📄 sdptool.c
字号:
/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2001-2002 Nokia Corporation * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org> * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com> * Copyright (C) 2002-2003 Jean Tourrilhes <jt@hpl.hp.com> * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <ctype.h>#include <stdlib.h>#include <string.h>#include <getopt.h>#include <sys/socket.h>#include <bluetooth/bluetooth.h>#include <bluetooth/hci.h>#include <bluetooth/hci_lib.h>#include <bluetooth/sdp.h>#include <bluetooth/sdp_lib.h>#include <netinet/in.h>#include "sdp-xml.h"#ifndef APPLE_AGENT_SVCLASS_ID#define APPLE_AGENT_SVCLASS_ID 0x2112#endif#define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, 0)) != -1)/* * Convert a string to a BDADDR, with a few "enhancements" - Jean II */static int estr2ba(char *str, bdaddr_t *ba){ /* Only trap "local", "any" is already dealt with */ if(!strcmp(str, "local")) { bacpy(ba, BDADDR_LOCAL); return 0; } return str2ba(str, ba);}#define DEFAULT_VIEW 0 /* Display only known attribute */#define TREE_VIEW 1 /* Display full attribute tree */#define RAW_VIEW 2 /* Display raw tree */#define XML_VIEW 3 /* Display xml tree *//* Pass args to the inquiry/search handler */struct search_context { char *svc; /* Service */ uuid_t group; /* Browse group */ int view; /* View mode */ uint32_t handle; /* Service record handle */};typedef int (*handler_t)(bdaddr_t *bdaddr, struct search_context *arg);static char UUID_str[MAX_LEN_UUID_STR];static bdaddr_t interface;/* Definition of attribute members */struct member_def { char *name;};/* Definition of an attribute */struct attrib_def { int num; /* Numeric ID - 16 bits */ char *name; /* User readable name */ struct member_def *members; /* Definition of attribute args */ int member_max; /* Max of attribute arg definitions */};/* Definition of a service or protocol */struct uuid_def { int num; /* Numeric ID - 16 bits */ char *name; /* User readable name */ struct attrib_def *attribs; /* Specific attribute definitions */ int attrib_max; /* Max of attribute definitions */};/* Context information about current attribute */struct attrib_context { struct uuid_def *service; /* Service UUID, if known */ struct attrib_def *attrib; /* Description of the attribute */ int member_index; /* Index of current attribute member */};/* Context information about the whole service */struct service_context { struct uuid_def *service; /* Service UUID, if known */};/* Allow us to do nice formatting of the lists */static char *indent_spaces = " ";/* ID of the service attribute. * Most attributes after 0x200 are defined based on the service, so * we need to find what is the service (which is messy) - Jean II */#define SERVICE_ATTR 0x1/* Definition of the optional arguments in protocol list */static struct member_def protocol_members[] = { { "Protocol" }, { "Channel/Port" }, { "Version" },};/* Definition of the optional arguments in profile list */static struct member_def profile_members[] = { { "Profile" }, { "Version" },};/* Definition of the optional arguments in Language list */static struct member_def language_members[] = { { "Code ISO639" }, { "Encoding" }, { "Base Offset" },};/* Name of the various common attributes. See BT assigned numbers */static struct attrib_def attrib_names[] = { { 0x0, "ServiceRecordHandle", NULL, 0 }, { 0x1, "ServiceClassIDList", NULL, 0 }, { 0x2, "ServiceRecordState", NULL, 0 }, { 0x3, "ServiceID", NULL, 0 }, { 0x4, "ProtocolDescriptorList", protocol_members, sizeof(protocol_members)/sizeof(struct member_def) }, { 0x5, "BrowseGroupList", NULL, 0 }, { 0x6, "LanguageBaseAttributeIDList", language_members, sizeof(language_members)/sizeof(struct member_def) }, { 0x7, "ServiceInfoTimeToLive", NULL, 0 }, { 0x8, "ServiceAvailability", NULL, 0 }, { 0x9, "BluetoothProfileDescriptorList", profile_members, sizeof(profile_members)/sizeof(struct member_def) }, { 0xA, "DocumentationURL", NULL, 0 }, { 0xB, "ClientExecutableURL", NULL, 0 }, { 0xC, "IconURL", NULL, 0 }, { 0xD, "AdditionalProtocolDescriptorLists", NULL, 0 }, /* Definitions after that are tricky (per profile or offset) */};const int attrib_max = sizeof(attrib_names)/sizeof(struct attrib_def);/* Name of the various SPD attributes. See BT assigned numbers */static struct attrib_def sdp_attrib_names[] = { { 0x200, "VersionNumberList", NULL, 0 }, { 0x201, "ServiceDatabaseState", NULL, 0 },};/* Name of the various SPD attributes. See BT assigned numbers */static struct attrib_def browse_attrib_names[] = { { 0x200, "GroupID", NULL, 0 },};/* Name of the various Device ID attributes. See Device Id spec. */static struct attrib_def did_attrib_names[] = { { 0x200, "SpecificationID", NULL, 0 }, { 0x201, "VendorID", NULL, 0 }, { 0x202, "ProductID", NULL, 0 }, { 0x203, "Version", NULL, 0 }, { 0x204, "PrimaryRecord", NULL, 0 }, { 0x205, "VendorIDSource", NULL, 0 },};/* Name of the various HID attributes. See HID spec. */static struct attrib_def hid_attrib_names[] = { { 0x200, "DeviceReleaseNum", NULL, 0 }, { 0x201, "ParserVersion", NULL, 0 }, { 0x202, "DeviceSubclass", NULL, 0 }, { 0x203, "CountryCode", NULL, 0 }, { 0x204, "VirtualCable", NULL, 0 }, { 0x205, "ReconnectInitiate", NULL, 0 }, { 0x206, "DescriptorList", NULL, 0 }, { 0x207, "LangIDBaseList", NULL, 0 }, { 0x208, "SDPDisable", NULL, 0 }, { 0x209, "BatteryPower", NULL, 0 }, { 0x20a, "RemoteWakeup", NULL, 0 }, { 0x20b, "ProfileVersion", NULL, 0 }, { 0x20c, "SupervisionTimeout", NULL, 0 }, { 0x20d, "NormallyConnectable", NULL, 0 }, { 0x20e, "BootDevice", NULL, 0 },};/* Name of the various PAN attributes. See BT assigned numbers *//* Note : those need to be double checked - Jean II */static struct attrib_def pan_attrib_names[] = { { 0x200, "IpSubnet", NULL, 0 }, /* Obsolete ??? */ { 0x30A, "SecurityDescription", NULL, 0 }, { 0x30B, "NetAccessType", NULL, 0 }, { 0x30C, "MaxNetAccessrate", NULL, 0 }, { 0x30D, "IPv4Subnet", NULL, 0 }, { 0x30E, "IPv6Subnet", NULL, 0 },};/* Name of the various Generic-Audio attributes. See BT assigned numbers *//* Note : totally untested - Jean II */static struct attrib_def audio_attrib_names[] = { { 0x302, "Remote audio volume control", NULL, 0 },};/* Same for the UUIDs. See BT assigned numbers */static struct uuid_def uuid16_names[] = { /* -- Protocols -- */ { 0x0001, "SDP", NULL, 0 }, { 0x0002, "UDP", NULL, 0 }, { 0x0003, "RFCOMM", NULL, 0 }, { 0x0004, "TCP", NULL, 0 }, { 0x0005, "TCS-BIN", NULL, 0 }, { 0x0006, "TCS-AT", NULL, 0 }, { 0x0008, "OBEX", NULL, 0 }, { 0x0009, "IP", NULL, 0 }, { 0x000a, "FTP", NULL, 0 }, { 0x000c, "HTTP", NULL, 0 }, { 0x000e, "WSP", NULL, 0 }, { 0x000f, "BNEP", NULL, 0 }, { 0x0010, "UPnP/ESDP", NULL, 0 }, { 0x0011, "HIDP", NULL, 0 }, { 0x0012, "HardcopyControlChannel", NULL, 0 }, { 0x0014, "HardcopyDataChannel", NULL, 0 }, { 0x0016, "HardcopyNotification", NULL, 0 }, { 0x0017, "AVCTP", NULL, 0 }, { 0x0019, "AVDTP", NULL, 0 }, { 0x001b, "CMTP", NULL, 0 }, { 0x001d, "UDI_C-Plane", NULL, 0 }, { 0x0100, "L2CAP", NULL, 0 }, /* -- Services -- */ { 0x1000, "ServiceDiscoveryServerServiceClassID", sdp_attrib_names, sizeof(sdp_attrib_names)/sizeof(struct attrib_def) }, { 0x1001, "BrowseGroupDescriptorServiceClassID", browse_attrib_names, sizeof(browse_attrib_names)/sizeof(struct attrib_def) }, { 0x1002, "PublicBrowseGroup", NULL, 0 }, { 0x1101, "SerialPort", NULL, 0 }, { 0x1102, "LANAccessUsingPPP", NULL, 0 }, { 0x1103, "DialupNetworking (DUN)", NULL, 0 }, { 0x1104, "IrMCSync", NULL, 0 }, { 0x1105, "OBEXObjectPush", NULL, 0 }, { 0x1106, "OBEXFileTransfer", NULL, 0 }, { 0x1107, "IrMCSyncCommand", NULL, 0 }, { 0x1108, "Headset", audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) }, { 0x1109, "CordlessTelephony", NULL, 0 }, { 0x110a, "AudioSource", NULL, 0 }, { 0x110b, "AudioSink", NULL, 0 }, { 0x110c, "RemoteControlTarget", NULL, 0 }, { 0x110d, "AdvancedAudio", NULL, 0 }, { 0x110e, "RemoteControl", NULL, 0 }, { 0x110f, "VideoConferencing", NULL, 0 }, { 0x1110, "Intercom", NULL, 0 }, { 0x1111, "Fax", NULL, 0 }, { 0x1112, "HeadsetAudioGateway", NULL, 0 }, { 0x1113, "WAP", NULL, 0 }, { 0x1114, "WAP Client", NULL, 0 }, { 0x1115, "PANU (PAN/BNEP)", pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) }, { 0x1116, "NAP (PAN/BNEP)", pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) }, { 0x1117, "GN (PAN/BNEP)", pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) }, { 0x1118, "DirectPrinting (BPP)", NULL, 0 }, { 0x1119, "ReferencePrinting (BPP)", NULL, 0 }, { 0x111a, "Imaging (BIP)", NULL, 0 }, { 0x111b, "ImagingResponder (BIP)", NULL, 0 }, { 0x111c, "ImagingAutomaticArchive (BIP)", NULL, 0 }, { 0x111d, "ImagingReferencedObjects (BIP)", NULL, 0 }, { 0x111e, "Handsfree", NULL, 0 }, { 0x111f, "HandsfreeAudioGateway", NULL, 0 }, { 0x1120, "DirectPrintingReferenceObjectsService (BPP)", NULL, 0 }, { 0x1121, "ReflectedUI (BPP)", NULL, 0 }, { 0x1122, "BasicPrinting (BPP)", NULL, 0 }, { 0x1123, "PrintingStatus (BPP)", NULL, 0 }, { 0x1124, "HumanInterfaceDeviceService (HID)", hid_attrib_names, sizeof(hid_attrib_names)/sizeof(struct attrib_def) }, { 0x1125, "HardcopyCableReplacement (HCR)", NULL, 0 }, { 0x1126, "HCR_Print (HCR)", NULL, 0 }, { 0x1127, "HCR_Scan (HCR)", NULL, 0 }, { 0x1128, "Common ISDN Access (CIP)", NULL, 0 }, { 0x1129, "VideoConferencingGW (VCP)", NULL, 0 }, { 0x112a, "UDI-MT", NULL, 0 }, { 0x112b, "UDI-TA", NULL, 0 }, { 0x112c, "Audio/Video", NULL, 0 }, { 0x112d, "SIM Access (SAP)", NULL, 0 }, { 0x112e, "Phonebook Access (PBAP) - PCE", NULL, 0 }, { 0x112f, "Phonebook Access (PBAP) - PSE", NULL, 0 }, { 0x1130, "Phonebook Access (PBAP)", NULL, 0 }, /* ... */ { 0x1200, "PnPInformation", did_attrib_names, sizeof(did_attrib_names)/sizeof(struct attrib_def) }, { 0x1201, "GenericNetworking", NULL, 0 }, { 0x1202, "GenericFileTransfer", NULL, 0 }, { 0x1203, "GenericAudio", audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) }, { 0x1204, "GenericTelephony", NULL, 0 }, /* ... */ { 0x1303, "VideoSource", NULL, 0 }, { 0x1304, "VideoSink", NULL, 0 }, { 0x1305, "VideoDistribution", NULL, 0 }, { 0x1400, "MDP", NULL, 0 }, { 0x1401, "MDPSource", NULL, 0 }, { 0x1402, "MDPSink", NULL, 0 }, { 0x2112, "AppleAgent", NULL, 0 },};static const int uuid16_max = sizeof(uuid16_names)/sizeof(struct uuid_def);static void sdp_data_printf(sdp_data_t *, struct attrib_context *, int);/* * Parse a UUID. * The BT assigned numbers only list UUID16, so I'm not sure the * other types will ever get used... */static void sdp_uuid_printf(uuid_t *uuid, struct attrib_context *context, int indent){ if (uuid) { if (uuid->type == SDP_UUID16) { uint16_t uuidNum = uuid->value.uuid16; struct uuid_def *uuidDef = NULL; int i; for (i = 0; i < uuid16_max; i++) if (uuid16_names[i].num == uuidNum) { uuidDef = &uuid16_names[i]; break; } /* Check if it's the service attribute */ if (context->attrib && context->attrib->num == SERVICE_ATTR) { /* We got the service ID !!! */ context->service = uuidDef; } if (uuidDef) printf("%.*sUUID16 : 0x%.4x - %s\n", indent, indent_spaces, uuidNum, uuidDef->name); else printf("%.*sUUID16 : 0x%.4x\n", indent, indent_spaces, uuidNum); } else if (uuid->type == SDP_UUID32) { struct uuid_def *uuidDef = NULL; int i; if (!(uuid->value.uuid32 & 0xffff0000)) { uint16_t uuidNum = uuid->value.uuid32; for (i = 0; i < uuid16_max; i++) if (uuid16_names[i].num == uuidNum) { uuidDef = &uuid16_names[i]; break; } } if (uuidDef) printf("%.*sUUID32 : 0x%.8x - %s\n", indent, indent_spaces, uuid->value.uuid32, uuidDef->name); else printf("%.*sUUID32 : 0x%.8x\n", indent, indent_spaces, uuid->value.uuid32); } else if (uuid->type == SDP_UUID128) { unsigned int data0; unsigned short data1; unsigned short data2; unsigned short data3; unsigned int data4; unsigned short data5; memcpy(&data0, &uuid->value.uuid128.data[0], 4); memcpy(&data1, &uuid->value.uuid128.data[4], 2); memcpy(&data2, &uuid->value.uuid128.data[6], 2); memcpy(&data3, &uuid->value.uuid128.data[8], 2); memcpy(&data4, &uuid->value.uuid128.data[10], 4); memcpy(&data5, &uuid->value.uuid128.data[14], 2); printf("%.*sUUID128 : 0x%.8x-%.4x-%.4x-%.4x-%.8x-%.4x\n", indent, indent_spaces, ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3), ntohl(data4), ntohs(data5)); } else printf("%.*sEnum type of UUID not set\n", indent, indent_spaces); } else printf("%.*sNull passed to print UUID\n", indent, indent_spaces);}/* * Parse a sequence of data elements (i.e. a list) */static void printf_dataseq(sdp_data_t * pData, struct attrib_context *context, int indent){ sdp_data_t *sdpdata = NULL; sdpdata = pData; if (sdpdata) { context->member_index = 0; do { sdp_data_printf(sdpdata, context, indent + 2); sdpdata = sdpdata->next; context->member_index++; } while (sdpdata); } else { printf("%.*sBroken dataseq link\n", indent, indent_spaces); }}/* * Parse a single data element (either in the attribute or in a data * sequence). */static void sdp_data_printf(sdp_data_t *sdpdata, struct attrib_context *context, int indent){ char *member_name = NULL; /* Find member name. Almost black magic ;-) */ if (context && context->attrib && context->attrib->members && context->member_index < context->attrib->member_max) { member_name = context->attrib->members[context->member_index].name; } switch (sdpdata->dtd) { case SDP_DATA_NIL: printf("%.*sNil\n", indent, indent_spaces); break; case SDP_BOOL: case SDP_UINT8: case SDP_UINT16: case SDP_UINT32: case SDP_UINT64: case SDP_UINT128: case SDP_INT8: case SDP_INT16: case SDP_INT32: case SDP_INT64: case SDP_INT128:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -