diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2005-05-06 16:10:26 +0000 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2005-05-06 16:10:26 +0000 |
commit | e7b5f3c69c6a7303b951e7a1398c87a568a16761 (patch) | |
tree | c9450ea29d7ab5ccabbcbc2fa127b727662d83c3 /tools | |
parent | 18cb95673231d41455528a782b168ee05f32fe2b (diff) |
Include a raw mode for showing the original record tree
Diffstat (limited to 'tools')
-rw-r--r-- | tools/sdptool.1 | 21 | ||||
-rw-r--r-- | tools/sdptool.c | 326 |
2 files changed, 289 insertions, 58 deletions
diff --git a/tools/sdptool.1 b/tools/sdptool.1 index c4f248eb..5ed9e33e 100644 --- a/tools/sdptool.1 +++ b/tools/sdptool.1 @@ -65,15 +65,16 @@ local \fBsdpd\fR. .SH "COMMANDS" .PP The following commands are available. -.IP "\fBsearch [--bdaddr bdaddr] [--tree] service\fP" 10 +.IP "\fBsearch [--bdaddr bdaddr] [--tree] [--raw] service\fP" 10 Search for services.. .IP "" 10 -Known service names are SP< DUN, LAN, FAX, OPUSH, -FTRN, NAP, GN, HID, CIP. -.IP "\fBbrowse [--tree] [bdaddr]\fP" 10 +Known service names are DID, SP, DUN, LAN, FAX, OPUSH, +FTP, HS, HF, SAP, NAP, GN, PANU, HID, CIP, CTP, A2SRC, A2SNK +and SYNCML. +.IP "\fBbrowse [--tree] [--raw] [bdaddr]\fP" 10 Browse all available services on the device specified by a Bluetooth address as a parameter. -.IP "\fBrecords [--tree] bdaddr\fP" 10 +.IP "\fBrecords [--tree] [--raw] bdaddr\fP" 10 Retrieve all possible service records. .IP "\fBadd [ --channel=N ]\fP" 10 Add a service to the local @@ -84,7 +85,7 @@ using the \fB--channel\fP option. .IP "\fBdel record_handle\fP" 10 Remove a service from the local \fBsdpd\fR. -.IP "\fBget [--tree] [--bdaddr bdaddr] record_handle\fP" 10 +.IP "\fBget [--tree] [--raw] [--bdaddr bdaddr] record_handle\fP" 10 Retrieve a service from the local \fBsdpd\fR. .IP "\fBsetattr record_handle attrib_id attrib_value\fP" 10 @@ -99,13 +100,13 @@ Displays help on using sdptool. .SH "EXAMPLES" .PP -sdptool browse 00:80:98:24:15:6D +sdptool browse 00:80:98:24:15:6D .PP -sdptool browse local +sdptool browse local .PP -sdptool add DUN +sdptool add DUN .PP -sdptool del LAN +sdptool del 0x10000 .SH "BUGS" .PP Documentation needs improving. diff --git a/tools/sdptool.c b/tools/sdptool.c index 64e3a464..d015f12f 100644 --- a/tools/sdptool.c +++ b/tools/sdptool.c @@ -36,9 +36,11 @@ #include <stdio.h> #include <errno.h> +#include <ctype.h> #include <stdlib.h> +#include <string.h> #include <getopt.h> -#include <netinet/in.h> +#include <sys/socket.h> #include <bluetooth/bluetooth.h> #include <bluetooth/hci.h> @@ -46,6 +48,8 @@ #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> +#include <netinet/in.h> + #define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, 0)) != -1) /* @@ -61,11 +65,15 @@ static int estr2ba(char *str, bdaddr_t *ba) 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 */ + /* Pass args to the inquiry/search handler */ struct search_context { char *svc; /* Service */ uuid_t group; /* Browse group */ - int tree; /* Display full attribute tree */ + int view; /* View mode */ uint32_t handle; /* Service record handle */ }; @@ -219,7 +227,7 @@ static struct attrib_def audio_attrib_names[] = { /* Same for the UUIDs. See BT assigned numbers */ static struct uuid_def uuid16_names[] = { /* -- Protocols -- */ - { 0x0001, "SDP (Service Discovery Protocol)", NULL, 0 }, + { 0x0001, "SDP", NULL, 0 }, { 0x0002, "UDP", NULL, 0 }, { 0x0003, "RFCOMM", NULL, 0 }, { 0x0004, "TCP", NULL, 0 }, @@ -230,7 +238,7 @@ static struct uuid_def uuid16_names[] = { { 0x000a, "FTP", NULL, 0 }, { 0x000c, "HTTP", NULL, 0 }, { 0x000e, "WSP", NULL, 0 }, - { 0x000f, "BNEP (PAN/BNEP)", NULL, 0 }, + { 0x000f, "BNEP", NULL, 0 }, { 0x0010, "UPnP/ESDP", NULL, 0 }, { 0x0011, "HIDP", NULL, 0 }, { 0x0012, "HardcopyControlChannel", NULL, 0 }, @@ -242,11 +250,11 @@ static struct uuid_def uuid16_names[] = { { 0x001d, "UDI_C-Plane", NULL, 0 }, { 0x0100, "L2CAP", NULL, 0 }, /* -- Services -- */ - { 0x1000, "ServiceDiscoveryServerServiceClassID (SDP)", + { 0x1000, "ServiceDiscoveryServerServiceClassID", sdp_attrib_names, sizeof(sdp_attrib_names)/sizeof(struct attrib_def) }, - { 0x1001, "BrowseGroupDescriptorServiceClassID (SDP)", + { 0x1001, "BrowseGroupDescriptorServiceClassID", browse_attrib_names, sizeof(browse_attrib_names)/sizeof(struct attrib_def) }, - { 0x1002, "PublicBrowseGroup (SDP)", NULL, 0 }, + { 0x1002, "PublicBrowseGroup", NULL, 0 }, { 0x1101, "SerialPort", NULL, 0 }, { 0x1102, "LANAccessUsingPPP", NULL, 0 }, { 0x1103, "DialupNetworking (DUN)", NULL, 0 }, @@ -276,7 +284,10 @@ static struct uuid_def uuid16_names[] = { 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 }, @@ -411,9 +422,9 @@ static void sdp_data_printf(sdp_data_t *sdpdata, struct attrib_context *context, char *member_name = NULL; /* Find member name. Almost black magic ;-) */ - if (context->attrib && context->attrib->members && - context->member_index < context->attrib->member_max) { - member_name = context->attrib->members[context->member_index].name; + 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) { @@ -484,7 +495,7 @@ static void sdp_data_printf(sdp_data_t *sdpdata, struct attrib_context *context, /* * Parse a single attribute. */ -static void sdp_attr_printf_func(void *value, void *userData) +static void print_tree_attr_func(void *value, void *userData) { sdp_data_t *sdpdata = NULL; uint16_t attrId; @@ -535,11 +546,191 @@ static void sdp_attr_printf_func(void *value, void *userData) * We assume the record has already been read, parsed and cached * locally. Jean II */ -static void sdp_printf_service_attr(sdp_record_t *rec) +static void print_tree_attr(sdp_record_t *rec) { if (rec && rec->attrlist) { struct service_context service = { NULL }; - sdp_list_foreach(rec->attrlist, sdp_attr_printf_func, &service); + sdp_list_foreach(rec->attrlist, print_tree_attr_func, &service); + } +} + +static void print_raw_data(sdp_data_t *data, int indent) +{ + struct uuid_def *def; + char *str; + int i, hex; + + if (!data) + return; + + for (i = 0; i < indent; i++) + printf("\t"); + + switch (data->dtd) { + case SDP_DATA_NIL: + printf("NIL\n"); + break; + case SDP_BOOL: + printf("Bool %s\n", data->val.uint8 ? "True" : "False"); + break; + case SDP_UINT8: + printf("UINT8 0x%02x\n", data->val.uint8); + break; + case SDP_UINT16: + printf("UINT16 0x%04x\n", data->val.uint16); + break; + case SDP_UINT32: + printf("UINT32 0x%08x\n", data->val.uint32); + break; + case SDP_UINT64: + printf("UINT64 0x%016llx\n", data->val.uint64); + break; + case SDP_UINT128: + printf("UINT128 ...\n"); + break; + case SDP_INT8: + printf("INT8 %d\n", data->val.int8); + break; + case SDP_INT16: + printf("INT16 %d\n", data->val.int16); + break; + case SDP_INT32: + printf("INT32 %d\n", data->val.int32); + break; + case SDP_INT64: + printf("INT64 %lld\n", data->val.int64); + break; + case SDP_INT128: + printf("INT128 ...\n"); + break; + case SDP_UUID16: + case SDP_UUID32: + case SDP_UUID128: + switch (data->val.uuid.type) { + case SDP_UUID16: + def = NULL; + for (i = 0; i < uuid16_max; i++) + if (uuid16_names[i].num == data->val.uuid.value.uuid16) { + def = &uuid16_names[i]; + break; + } + if (def) + printf("UUID16 0x%04x - %s\n", data->val.uuid.value.uuid16, def->name); + else + printf("UUID16 0x%04x\n", data->val.uuid.value.uuid16); + break; + case SDP_UUID32: + def = NULL; + if (!(data->val.uuid.value.uuid32 & 0xffff0000)) { + uint16_t value = data->val.uuid.value.uuid32; + for (i = 0; i < uuid16_max; i++) + if (uuid16_names[i].num == value) { + def = &uuid16_names[i]; + break; + } + } + if (def) + printf("UUID32 0x%08x - %s\n", data->val.uuid.value.uuid32, def->name); + else + printf("UUID32 0x%08x\n", data->val.uuid.value.uuid32); + break; + case SDP_UUID128: + printf("UUID128 "); + for (i = 0; i < 16; i++) { + switch (i) { + case 4: + case 6: + case 8: + case 10: + printf("-"); + break; + } + printf("%02x", (unsigned char ) data->val.uuid.value.uuid128.data[i]); + } + printf("\n"); + break; + default: + printf("UUID type 0x%02x\n", data->val.uuid.type); + break; + } + break; + case SDP_TEXT_STR8: + case SDP_TEXT_STR16: + case SDP_TEXT_STR32: + str = data->val.str; + if (data->unitSize > strlen(str) + 1) { + hex = 0; + for (i = 0; i < data->unitSize - 1; i++) + if (!isprint(str[i])) { + hex = 1; + break; + } + if (str[data->unitSize - 1] != '\0') + hex = 1; + } else + hex = 0; + if (hex) { + printf("String"); + for (i = 0; i < data->unitSize; i++) + printf(" %02x", (unsigned char) str[i]); + printf("\n"); + } else + printf("String %s\n", str); + break; + case SDP_URL_STR8: + case SDP_URL_STR16: + case SDP_URL_STR32: + printf("URL %s\n", data->val.str); + break; + case SDP_SEQ8: + case SDP_SEQ16: + case SDP_SEQ32: + printf("Sequence\n"); + print_raw_data(data->val.dataseq, indent + 1); + break; + case SDP_ALT8: + case SDP_ALT16: + case SDP_ALT32: + printf("Alternate\n"); + print_raw_data(data->val.dataseq, indent + 1); + break; + default: + printf("Unknown type 0x%02x\n", data->dtd); + break; + } + + print_raw_data(data->next, indent); +} + +static void print_raw_attr_func(void *value, void *userData) +{ + sdp_data_t *data = (sdp_data_t *) value; + struct attrib_def *def = NULL; + int i; + + /* Search amongst the generic attributes */ + for (i = 0; i < attrib_max; i++) + if (attrib_names[i].num == data->attrId) { + def = &attrib_names[i]; + break; + } + + if (def) + printf("\tAttribute 0x%04x - %s\n", data->attrId, def->name); + else + printf("\tAttribute 0x%04x\n", data->attrId); + + if (data) + print_raw_data(data, 2); + else + printf(" NULL value\n"); +} + +static void print_raw_attr(sdp_record_t *rec) +{ + if (rec && rec->attrlist) { + printf("Sequence\n"); + sdp_list_foreach(rec->attrlist, print_raw_attr_func, 0); } } @@ -2219,10 +2410,12 @@ static int do_search(bdaddr_t *bdaddr, struct search_context *context) return -1; } - if (context->svc) - printf("Searching for %s on %s ...\n", context->svc, str); - else - printf("Browsing %s ...\n", str); + if (context->view != RAW_VIEW) { + if (context->svc) + printf("Searching for %s on %s ...\n", context->svc, str); + else + printf("Browsing %s ...\n", str); + } attrid = sdp_list_append(0, &range); search = sdp_list_append(0, &context->group); @@ -2238,15 +2431,23 @@ static int do_search(bdaddr_t *bdaddr, struct search_context *context) sdp_record_t *rec = (sdp_record_t *) seq->data; struct search_context sub_context; - if (context->tree) { - /* Display full tree */ - sdp_printf_service_attr(rec); - } else { + switch (context->view) { + case DEFAULT_VIEW: /* Display user friendly form */ print_service_attr(rec); + printf("\n"); + break; + case TREE_VIEW: + /* Display full tree */ + print_tree_attr(rec); + printf("\n"); + break; + default: + /* Display raw tree */ + print_raw_attr(rec); + break; } - printf("\n"); - + if (sdp_get_group_id(rec, &sub_context.group) != -1) { /* Set the subcontext for browsing the sub tree */ memcpy(&sub_context, context, sizeof(struct search_context)); @@ -2266,6 +2467,7 @@ static int do_search(bdaddr_t *bdaddr, struct search_context *context) static struct option browse_options[] = { { "help", 0, 0, 'h' }, { "tree", 0, 0, 't' }, + { "raw", 0, 0, 'r' }, { "uuid", 1, 0, 'u' }, { "l2cap", 0, 0, 'l' }, { 0, 0, 0, 0 } @@ -2273,7 +2475,7 @@ static struct option browse_options[] = { static char *browse_help = "Usage:\n" - "\tbrowse [--tree] [--uuid uuid] [--l2cap] [bdaddr]\n"; + "\tbrowse [--tree] [--raw] [--uuid uuid] [--l2cap] [bdaddr]\n"; /* * Browse the full SDP database (i.e. list all services starting from the @@ -2292,7 +2494,10 @@ static int cmd_browse(int argc, char **argv) for_each_opt(opt, browse_options, 0) { switch (opt) { case 't': - context.tree = 1; + context.view = TREE_VIEW; + break; + case 'r': + context.view = RAW_VIEW; break; case 'u': if (sscanf(optarg, "%i", &num) != 1 || num < 0 || num > 0xffff) { @@ -2322,15 +2527,16 @@ static int cmd_browse(int argc, char **argv) } static struct option search_options[] = { - { "help", 0,0, 'h' }, - { "bdaddr", 1,0, 'b' }, - { "tree", 0,0, 't' }, + { "help", 0,0, 'h' }, + { "bdaddr", 1,0, 'b' }, + { "tree", 0,0, 't' }, + { "raw", 0, 0, 'r' }, { 0, 0, 0, 0} }; static char *search_help = "Usage:\n" - "\tsearch [--bdaddr bdaddr] [--tree] SERVICE\n" + "\tsearch [--bdaddr bdaddr] [--tree] [--raw] SERVICE\n" "SERVICE is a name (string) or UUID (0x1002)\n"; /* @@ -2361,7 +2567,10 @@ static int cmd_search(int argc, char **argv) has_addr = 1; break; case 't': - context.tree = 1; + context.view = TREE_VIEW; + break; + case 'r': + context.view = RAW_VIEW; break; default: printf(search_help); @@ -2435,19 +2644,29 @@ static int get_service(bdaddr_t *bdaddr, struct search_context *context, int qui sdp_list_free(attrid, 0); sdp_close(session); if (!rec) { - if (!quite) + if (!quite) { printf("Service get request failed.\n"); - return -1; + return -1; + } else + return 0; } - if (context->tree) { - /* Display full tree */ - sdp_printf_service_attr(rec); - } else { + switch (context->view) { + case DEFAULT_VIEW: /* Display user friendly form */ print_service_attr(rec); + printf("\n"); + break; + case TREE_VIEW: + /* Display full tree */ + print_tree_attr(rec); + printf("\n"); + break; + default: + /* Display raw tree */ + print_raw_attr(rec); + break; } - printf("\n"); sdp_record_free(rec); return 0; @@ -2456,12 +2675,13 @@ static int get_service(bdaddr_t *bdaddr, struct search_context *context, int qui static struct option records_options[] = { { "help", 0, 0, 'h' }, { "tree", 0, 0, 't' }, + { "raw", 0, 0, 'r' }, { 0, 0, 0, 0 } }; static char *records_help = "Usage:\n" - "\trecords [--tree] bdaddr\n"; + "\trecords [--tree] [--raw] bdaddr\n"; /* * Request possible SDP service records @@ -2469,9 +2689,9 @@ static char *records_help = static int cmd_records(int argc, char **argv) { struct search_context context; - uint32_t base[] = { 0x10000, 0x1002e }; + uint32_t base[] = { 0x10000, 0x1002e, 0x110b }; bdaddr_t bdaddr; - int i, n, opt, num = 32; + int i, n, opt, err = 0, num = 32; /* Initialise context */ memset(&context, '\0', sizeof(struct search_context)); @@ -2479,7 +2699,10 @@ static int cmd_records(int argc, char **argv) for_each_opt(opt, records_options, 0) { switch (opt) { case 't': - context.tree = 1; + context.view = TREE_VIEW; + break; + case 'r': + context.view = RAW_VIEW; break; default: printf(records_help); @@ -2500,22 +2723,26 @@ static int cmd_records(int argc, char **argv) for (i = 0; i < sizeof(base) / sizeof(uint32_t); i++) for (n = 0; n < num; n++) { context.handle = base[i] + n; - get_service(&bdaddr, &context, 1); + err = get_service(&bdaddr, &context, 1); + if (err < 0) + goto done; } +done: return 0; } static struct option get_options[] = { - { "help", 0,0, 'h' }, - { "bdaddr", 1,0, 'b' }, - { "tree", 0,0, 't' }, + { "help", 0, 0, 'h' }, + { "bdaddr", 1, 0, 'b' }, + { "tree", 0, 0, 't' }, + { "raw", 0, 0, 'r' }, { 0, 0, 0, 0 } }; static char *get_help = "Usage:\n" - "\tget [--tree] [--bdaddr bdaddr] record_handle\n"; + "\tget [--tree] [--raw] [--bdaddr bdaddr] record_handle\n"; /* * Get a specific SDP record on the local SDP server @@ -2537,7 +2764,10 @@ static int cmd_get(int argc, char **argv) has_addr = 1; break; case 't': - context.tree = 1; + context.view = TREE_VIEW; + break; + case 'r': + context.view = RAW_VIEW; break; default: printf(get_help); |