3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2001-2002 Nokia Corporation
6 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
7 * Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
8 * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
9 * Copyright (C) 2002-2003 Jean Tourrilhes <jt@hpl.hp.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
38 #include <sys/socket.h>
40 #include <bluetooth/bluetooth.h>
41 #include <bluetooth/hci.h>
42 #include <bluetooth/hci_lib.h>
43 #include <bluetooth/sdp.h>
44 #include <bluetooth/sdp_lib.h>
46 #include <netinet/in.h>
50 #ifndef APPLE_AGENT_SVCLASS_ID
51 #define APPLE_AGENT_SVCLASS_ID 0x2112
54 #define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, 0)) != -1)
57 * Convert a string to a BDADDR, with a few "enhancements" - Jean II
59 static int estr2ba(char *str, bdaddr_t *ba)
61 /* Only trap "local", "any" is already dealt with */
62 if(!strcmp(str, "local")) {
63 bacpy(ba, BDADDR_LOCAL);
66 return str2ba(str, ba);
69 #define DEFAULT_VIEW 0 /* Display only known attribute */
70 #define TREE_VIEW 1 /* Display full attribute tree */
71 #define RAW_VIEW 2 /* Display raw tree */
72 #define XML_VIEW 3 /* Display xml tree */
74 /* Pass args to the inquiry/search handler */
75 struct search_context {
76 char *svc; /* Service */
77 uuid_t group; /* Browse group */
78 int view; /* View mode */
79 uint32_t handle; /* Service record handle */
82 typedef int (*handler_t)(bdaddr_t *bdaddr, struct search_context *arg);
84 static char UUID_str[MAX_LEN_UUID_STR];
85 static bdaddr_t interface;
87 /* Definition of attribute members */
92 /* Definition of an attribute */
94 int num; /* Numeric ID - 16 bits */
95 char *name; /* User readable name */
96 struct member_def *members; /* Definition of attribute args */
97 int member_max; /* Max of attribute arg definitions */
100 /* Definition of a service or protocol */
102 int num; /* Numeric ID - 16 bits */
103 char *name; /* User readable name */
104 struct attrib_def *attribs; /* Specific attribute definitions */
105 int attrib_max; /* Max of attribute definitions */
108 /* Context information about current attribute */
109 struct attrib_context {
110 struct uuid_def *service; /* Service UUID, if known */
111 struct attrib_def *attrib; /* Description of the attribute */
112 int member_index; /* Index of current attribute member */
115 /* Context information about the whole service */
116 struct service_context {
117 struct uuid_def *service; /* Service UUID, if known */
120 /* Allow us to do nice formatting of the lists */
121 static char *indent_spaces = " ";
123 /* ID of the service attribute.
124 * Most attributes after 0x200 are defined based on the service, so
125 * we need to find what is the service (which is messy) - Jean II */
126 #define SERVICE_ATTR 0x1
128 /* Definition of the optional arguments in protocol list */
129 static struct member_def protocol_members[] = {
135 /* Definition of the optional arguments in profile list */
136 static struct member_def profile_members[] = {
141 /* Definition of the optional arguments in Language list */
142 static struct member_def language_members[] = {
148 /* Name of the various common attributes. See BT assigned numbers */
149 static struct attrib_def attrib_names[] = {
150 { 0x0, "ServiceRecordHandle", NULL, 0 },
151 { 0x1, "ServiceClassIDList", NULL, 0 },
152 { 0x2, "ServiceRecordState", NULL, 0 },
153 { 0x3, "ServiceID", NULL, 0 },
154 { 0x4, "ProtocolDescriptorList",
155 protocol_members, sizeof(protocol_members)/sizeof(struct member_def) },
156 { 0x5, "BrowseGroupList", NULL, 0 },
157 { 0x6, "LanguageBaseAttributeIDList",
158 language_members, sizeof(language_members)/sizeof(struct member_def) },
159 { 0x7, "ServiceInfoTimeToLive", NULL, 0 },
160 { 0x8, "ServiceAvailability", NULL, 0 },
161 { 0x9, "BluetoothProfileDescriptorList",
162 profile_members, sizeof(profile_members)/sizeof(struct member_def) },
163 { 0xA, "DocumentationURL", NULL, 0 },
164 { 0xB, "ClientExecutableURL", NULL, 0 },
165 { 0xC, "IconURL", NULL, 0 },
166 { 0xD, "AdditionalProtocolDescriptorLists", NULL, 0 },
167 /* Definitions after that are tricky (per profile or offset) */
170 const int attrib_max = sizeof(attrib_names)/sizeof(struct attrib_def);
172 /* Name of the various SPD attributes. See BT assigned numbers */
173 static struct attrib_def sdp_attrib_names[] = {
174 { 0x200, "VersionNumberList", NULL, 0 },
175 { 0x201, "ServiceDatabaseState", NULL, 0 },
178 /* Name of the various SPD attributes. See BT assigned numbers */
179 static struct attrib_def browse_attrib_names[] = {
180 { 0x200, "GroupID", NULL, 0 },
183 /* Name of the various Device ID attributes. See Device Id spec. */
184 static struct attrib_def did_attrib_names[] = {
185 { 0x200, "SpecificationID", NULL, 0 },
186 { 0x201, "VendorID", NULL, 0 },
187 { 0x202, "ProductID", NULL, 0 },
188 { 0x203, "Version", NULL, 0 },
189 { 0x204, "PrimaryRecord", NULL, 0 },
190 { 0x205, "VendorIDSource", NULL, 0 },
193 /* Name of the various HID attributes. See HID spec. */
194 static struct attrib_def hid_attrib_names[] = {
195 { 0x200, "DeviceReleaseNum", NULL, 0 },
196 { 0x201, "ParserVersion", NULL, 0 },
197 { 0x202, "DeviceSubclass", NULL, 0 },
198 { 0x203, "CountryCode", NULL, 0 },
199 { 0x204, "VirtualCable", NULL, 0 },
200 { 0x205, "ReconnectInitiate", NULL, 0 },
201 { 0x206, "DescriptorList", NULL, 0 },
202 { 0x207, "LangIDBaseList", NULL, 0 },
203 { 0x208, "SDPDisable", NULL, 0 },
204 { 0x209, "BatteryPower", NULL, 0 },
205 { 0x20a, "RemoteWakeup", NULL, 0 },
206 { 0x20b, "ProfileVersion", NULL, 0 },
207 { 0x20c, "SupervisionTimeout", NULL, 0 },
208 { 0x20d, "NormallyConnectable", NULL, 0 },
209 { 0x20e, "BootDevice", NULL, 0 },
212 /* Name of the various PAN attributes. See BT assigned numbers */
213 /* Note : those need to be double checked - Jean II */
214 static struct attrib_def pan_attrib_names[] = {
215 { 0x200, "IpSubnet", NULL, 0 }, /* Obsolete ??? */
216 { 0x30A, "SecurityDescription", NULL, 0 },
217 { 0x30B, "NetAccessType", NULL, 0 },
218 { 0x30C, "MaxNetAccessrate", NULL, 0 },
219 { 0x30D, "IPv4Subnet", NULL, 0 },
220 { 0x30E, "IPv6Subnet", NULL, 0 },
223 /* Name of the various Generic-Audio attributes. See BT assigned numbers */
224 /* Note : totally untested - Jean II */
225 static struct attrib_def audio_attrib_names[] = {
226 { 0x302, "Remote audio volume control", NULL, 0 },
229 /* Same for the UUIDs. See BT assigned numbers */
230 static struct uuid_def uuid16_names[] = {
231 /* -- Protocols -- */
232 { 0x0001, "SDP", NULL, 0 },
233 { 0x0002, "UDP", NULL, 0 },
234 { 0x0003, "RFCOMM", NULL, 0 },
235 { 0x0004, "TCP", NULL, 0 },
236 { 0x0005, "TCS-BIN", NULL, 0 },
237 { 0x0006, "TCS-AT", NULL, 0 },
238 { 0x0008, "OBEX", NULL, 0 },
239 { 0x0009, "IP", NULL, 0 },
240 { 0x000a, "FTP", NULL, 0 },
241 { 0x000c, "HTTP", NULL, 0 },
242 { 0x000e, "WSP", NULL, 0 },
243 { 0x000f, "BNEP", NULL, 0 },
244 { 0x0010, "UPnP/ESDP", NULL, 0 },
245 { 0x0011, "HIDP", NULL, 0 },
246 { 0x0012, "HardcopyControlChannel", NULL, 0 },
247 { 0x0014, "HardcopyDataChannel", NULL, 0 },
248 { 0x0016, "HardcopyNotification", NULL, 0 },
249 { 0x0017, "AVCTP", NULL, 0 },
250 { 0x0019, "AVDTP", NULL, 0 },
251 { 0x001b, "CMTP", NULL, 0 },
252 { 0x001d, "UDI_C-Plane", NULL, 0 },
253 { 0x0100, "L2CAP", NULL, 0 },
255 { 0x1000, "ServiceDiscoveryServerServiceClassID",
256 sdp_attrib_names, sizeof(sdp_attrib_names)/sizeof(struct attrib_def) },
257 { 0x1001, "BrowseGroupDescriptorServiceClassID",
258 browse_attrib_names, sizeof(browse_attrib_names)/sizeof(struct attrib_def) },
259 { 0x1002, "PublicBrowseGroup", NULL, 0 },
260 { 0x1101, "SerialPort", NULL, 0 },
261 { 0x1102, "LANAccessUsingPPP", NULL, 0 },
262 { 0x1103, "DialupNetworking (DUN)", NULL, 0 },
263 { 0x1104, "IrMCSync", NULL, 0 },
264 { 0x1105, "OBEXObjectPush", NULL, 0 },
265 { 0x1106, "OBEXFileTransfer", NULL, 0 },
266 { 0x1107, "IrMCSyncCommand", NULL, 0 },
268 audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },
269 { 0x1109, "CordlessTelephony", NULL, 0 },
270 { 0x110a, "AudioSource", NULL, 0 },
271 { 0x110b, "AudioSink", NULL, 0 },
272 { 0x110c, "RemoteControlTarget", NULL, 0 },
273 { 0x110d, "AdvancedAudio", NULL, 0 },
274 { 0x110e, "RemoteControl", NULL, 0 },
275 { 0x110f, "VideoConferencing", NULL, 0 },
276 { 0x1110, "Intercom", NULL, 0 },
277 { 0x1111, "Fax", NULL, 0 },
278 { 0x1112, "HeadsetAudioGateway", NULL, 0 },
279 { 0x1113, "WAP", NULL, 0 },
280 { 0x1114, "WAP Client", NULL, 0 },
281 { 0x1115, "PANU (PAN/BNEP)",
282 pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
283 { 0x1116, "NAP (PAN/BNEP)",
284 pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
285 { 0x1117, "GN (PAN/BNEP)",
286 pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
287 { 0x1118, "DirectPrinting (BPP)", NULL, 0 },
288 { 0x1119, "ReferencePrinting (BPP)", NULL, 0 },
289 { 0x111a, "Imaging (BIP)", NULL, 0 },
290 { 0x111b, "ImagingResponder (BIP)", NULL, 0 },
291 { 0x111c, "ImagingAutomaticArchive (BIP)", NULL, 0 },
292 { 0x111d, "ImagingReferencedObjects (BIP)", NULL, 0 },
293 { 0x111e, "Handsfree", NULL, 0 },
294 { 0x111f, "HandsfreeAudioGateway", NULL, 0 },
295 { 0x1120, "DirectPrintingReferenceObjectsService (BPP)", NULL, 0 },
296 { 0x1121, "ReflectedUI (BPP)", NULL, 0 },
297 { 0x1122, "BasicPrinting (BPP)", NULL, 0 },
298 { 0x1123, "PrintingStatus (BPP)", NULL, 0 },
299 { 0x1124, "HumanInterfaceDeviceService (HID)",
300 hid_attrib_names, sizeof(hid_attrib_names)/sizeof(struct attrib_def) },
301 { 0x1125, "HardcopyCableReplacement (HCR)", NULL, 0 },
302 { 0x1126, "HCR_Print (HCR)", NULL, 0 },
303 { 0x1127, "HCR_Scan (HCR)", NULL, 0 },
304 { 0x1128, "Common ISDN Access (CIP)", NULL, 0 },
305 { 0x1129, "VideoConferencingGW (VCP)", NULL, 0 },
306 { 0x112a, "UDI-MT", NULL, 0 },
307 { 0x112b, "UDI-TA", NULL, 0 },
308 { 0x112c, "Audio/Video", NULL, 0 },
309 { 0x112d, "SIM Access (SAP)", NULL, 0 },
310 { 0x112e, "Phonebook Access (PBAP) - PCE", NULL, 0 },
311 { 0x112f, "Phonebook Access (PBAP) - PSE", NULL, 0 },
312 { 0x1130, "Phonebook Access (PBAP)", NULL, 0 },
314 { 0x1200, "PnPInformation",
315 did_attrib_names, sizeof(did_attrib_names)/sizeof(struct attrib_def) },
316 { 0x1201, "GenericNetworking", NULL, 0 },
317 { 0x1202, "GenericFileTransfer", NULL, 0 },
318 { 0x1203, "GenericAudio",
319 audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },
320 { 0x1204, "GenericTelephony", NULL, 0 },
322 { 0x1303, "VideoSource", NULL, 0 },
323 { 0x1304, "VideoSink", NULL, 0 },
324 { 0x1305, "VideoDistribution", NULL, 0 },
325 { 0x1400, "MDP", NULL, 0 },
326 { 0x1401, "MDPSource", NULL, 0 },
327 { 0x1402, "MDPSink", NULL, 0 },
328 { 0x2112, "AppleAgent", NULL, 0 },
331 static const int uuid16_max = sizeof(uuid16_names)/sizeof(struct uuid_def);
333 static void sdp_data_printf(sdp_data_t *, struct attrib_context *, int);
337 * The BT assigned numbers only list UUID16, so I'm not sure the
338 * other types will ever get used...
340 static void sdp_uuid_printf(uuid_t *uuid, struct attrib_context *context, int indent)
343 if (uuid->type == SDP_UUID16) {
344 uint16_t uuidNum = uuid->value.uuid16;
345 struct uuid_def *uuidDef = NULL;
348 for (i = 0; i < uuid16_max; i++)
349 if (uuid16_names[i].num == uuidNum) {
350 uuidDef = &uuid16_names[i];
354 /* Check if it's the service attribute */
355 if (context->attrib && context->attrib->num == SERVICE_ATTR) {
356 /* We got the service ID !!! */
357 context->service = uuidDef;
361 printf("%.*sUUID16 : 0x%.4x - %s\n",
362 indent, indent_spaces, uuidNum, uuidDef->name);
364 printf("%.*sUUID16 : 0x%.4x\n",
365 indent, indent_spaces, uuidNum);
366 } else if (uuid->type == SDP_UUID32) {
367 struct uuid_def *uuidDef = NULL;
370 if (!(uuid->value.uuid32 & 0xffff0000)) {
371 uint16_t uuidNum = uuid->value.uuid32;
372 for (i = 0; i < uuid16_max; i++)
373 if (uuid16_names[i].num == uuidNum) {
374 uuidDef = &uuid16_names[i];
380 printf("%.*sUUID32 : 0x%.8x - %s\n",
381 indent, indent_spaces, uuid->value.uuid32, uuidDef->name);
383 printf("%.*sUUID32 : 0x%.8x\n",
384 indent, indent_spaces, uuid->value.uuid32);
385 } else if (uuid->type == SDP_UUID128) {
387 unsigned short data1;
388 unsigned short data2;
389 unsigned short data3;
391 unsigned short data5;
393 memcpy(&data0, &uuid->value.uuid128.data[0], 4);
394 memcpy(&data1, &uuid->value.uuid128.data[4], 2);
395 memcpy(&data2, &uuid->value.uuid128.data[6], 2);
396 memcpy(&data3, &uuid->value.uuid128.data[8], 2);
397 memcpy(&data4, &uuid->value.uuid128.data[10], 4);
398 memcpy(&data5, &uuid->value.uuid128.data[14], 2);
400 printf("%.*sUUID128 : 0x%.8x-%.4x-%.4x-%.4x-%.8x-%.4x\n",
401 indent, indent_spaces,
402 ntohl(data0), ntohs(data1), ntohs(data2),
403 ntohs(data3), ntohl(data4), ntohs(data5));
405 printf("%.*sEnum type of UUID not set\n",
406 indent, indent_spaces);
408 printf("%.*sNull passed to print UUID\n",
409 indent, indent_spaces);
413 * Parse a sequence of data elements (i.e. a list)
415 static void printf_dataseq(sdp_data_t * pData, struct attrib_context *context, int indent)
417 sdp_data_t *sdpdata = NULL;
421 context->member_index = 0;
423 sdp_data_printf(sdpdata, context, indent + 2);
424 sdpdata = sdpdata->next;
425 context->member_index++;
428 printf("%.*sBroken dataseq link\n", indent, indent_spaces);
433 * Parse a single data element (either in the attribute or in a data
436 static void sdp_data_printf(sdp_data_t *sdpdata, struct attrib_context *context, int indent)
438 char *member_name = NULL;
440 /* Find member name. Almost black magic ;-) */
441 if (context && context->attrib && context->attrib->members &&
442 context->member_index < context->attrib->member_max) {
443 member_name = context->attrib->members[context->member_index].name;
446 switch (sdpdata->dtd) {
448 printf("%.*sNil\n", indent, indent_spaces);
462 printf("%.*s%s (Integer) : 0x%x\n",
463 indent, indent_spaces, member_name, sdpdata->val.uint32);
465 printf("%.*sInteger : 0x%x\n", indent, indent_spaces,
466 sdpdata->val.uint32);
473 //printf("%.*sUUID\n", indent, indent_spaces);
474 sdp_uuid_printf(&sdpdata->val.uuid, context, indent);
480 if (sdpdata->unitSize > strlen(sdpdata->val.str)) {
482 printf("%.*sData :", indent, indent_spaces);
483 for (i = 0; i < sdpdata->unitSize; i++)
484 printf(" %02x", (unsigned char) sdpdata->val.str[i]);
487 printf("%.*sText : \"%s\"\n", indent, indent_spaces, sdpdata->val.str);
492 printf("%.*sURL : %s\n", indent, indent_spaces, sdpdata->val.str);
498 printf("%.*sData Sequence\n", indent, indent_spaces);
499 printf_dataseq(sdpdata->val.dataseq, context, indent);
505 printf("%.*sData Sequence Alternates\n", indent, indent_spaces);
506 printf_dataseq(sdpdata->val.dataseq, context, indent);
512 * Parse a single attribute.
514 static void print_tree_attr_func(void *value, void *userData)
516 sdp_data_t *sdpdata = NULL;
518 struct service_context *service = (struct service_context *) userData;
519 struct attrib_context context;
520 struct attrib_def *attrDef = NULL;
523 sdpdata = (sdp_data_t *)value;
524 attrId = sdpdata->attrId;
525 /* Search amongst the generic attributes */
526 for (i = 0; i < attrib_max; i++)
527 if (attrib_names[i].num == attrId) {
528 attrDef = &attrib_names[i];
531 /* Search amongst the specific attributes of this service */
532 if ((attrDef == NULL) && (service->service != NULL) &&
533 (service->service->attribs != NULL)) {
534 struct attrib_def *svc_attribs = service->service->attribs;
535 int svc_attrib_max = service->service->attrib_max;
536 for (i = 0; i < svc_attrib_max; i++)
537 if (svc_attribs[i].num == attrId) {
538 attrDef = &svc_attribs[i];
544 printf("Attribute Identifier : 0x%x - %s\n", attrId, attrDef->name);
546 printf("Attribute Identifier : 0x%x\n", attrId);
548 context.service = service->service;
549 context.attrib = attrDef;
550 context.member_index = 0;
551 /* Parse attribute members */
553 sdp_data_printf(sdpdata, &context, 2);
555 printf(" NULL value\n");
557 service->service = context.service;
561 * Main entry point of this library. Parse a SDP record.
562 * We assume the record has already been read, parsed and cached
565 static void print_tree_attr(sdp_record_t *rec)
567 if (rec && rec->attrlist) {
568 struct service_context service = { NULL };
569 sdp_list_foreach(rec->attrlist, print_tree_attr_func, &service);
573 static void print_raw_data(sdp_data_t *data, int indent)
575 struct uuid_def *def;
581 for (i = 0; i < indent; i++)
589 printf("Bool %s\n", data->val.uint8 ? "True" : "False");
592 printf("UINT8 0x%02x\n", data->val.uint8);
595 printf("UINT16 0x%04x\n", data->val.uint16);
598 printf("UINT32 0x%08x\n", data->val.uint32);
601 printf("UINT64 0x%016jx\n", data->val.uint64);
604 printf("UINT128 ...\n");
607 printf("INT8 %d\n", data->val.int8);
610 printf("INT16 %d\n", data->val.int16);
613 printf("INT32 %d\n", data->val.int32);
616 printf("INT64 %jd\n", data->val.int64);
619 printf("INT128 ...\n");
624 switch (data->val.uuid.type) {
627 for (i = 0; i < uuid16_max; i++)
628 if (uuid16_names[i].num == data->val.uuid.value.uuid16) {
629 def = &uuid16_names[i];
633 printf("UUID16 0x%04x - %s\n", data->val.uuid.value.uuid16, def->name);
635 printf("UUID16 0x%04x\n", data->val.uuid.value.uuid16);
639 if (!(data->val.uuid.value.uuid32 & 0xffff0000)) {
640 uint16_t value = data->val.uuid.value.uuid32;
641 for (i = 0; i < uuid16_max; i++)
642 if (uuid16_names[i].num == value) {
643 def = &uuid16_names[i];
648 printf("UUID32 0x%08x - %s\n", data->val.uuid.value.uuid32, def->name);
650 printf("UUID32 0x%08x\n", data->val.uuid.value.uuid32);
654 for (i = 0; i < 16; i++) {
663 printf("%02x", (unsigned char ) data->val.uuid.value.uuid128.data[i]);
668 printf("UUID type 0x%02x\n", data->val.uuid.type);
676 for (i = 0; i < data->unitSize; i++) {
677 if (i == (data->unitSize - 1) && data->val.str[i] == '\0')
679 if (!isprint(data->val.str[i])) {
686 for (i = 0; i < data->unitSize; i++)
687 printf(" %02x", (unsigned char) data->val.str[i]);
690 for (i = 0; i < data->unitSize; i++)
691 printf("%c", data->val.str[i]);
698 printf("URL %s\n", data->val.str);
703 printf("Sequence\n");
704 print_raw_data(data->val.dataseq, indent + 1);
709 printf("Alternate\n");
710 print_raw_data(data->val.dataseq, indent + 1);
713 printf("Unknown type 0x%02x\n", data->dtd);
717 print_raw_data(data->next, indent);
720 static void print_raw_attr_func(void *value, void *userData)
722 sdp_data_t *data = (sdp_data_t *) value;
723 struct attrib_def *def = NULL;
726 /* Search amongst the generic attributes */
727 for (i = 0; i < attrib_max; i++)
728 if (attrib_names[i].num == data->attrId) {
729 def = &attrib_names[i];
734 printf("\tAttribute 0x%04x - %s\n", data->attrId, def->name);
736 printf("\tAttribute 0x%04x\n", data->attrId);
739 print_raw_data(data, 2);
741 printf(" NULL value\n");
744 static void print_raw_attr(sdp_record_t *rec)
746 if (rec && rec->attrlist) {
747 printf("Sequence\n");
748 sdp_list_foreach(rec->attrlist, print_raw_attr_func, 0);
753 * Set attributes with single values in SDP record
756 static int set_attrib(sdp_session_t *sess, uint32_t handle, uint16_t attrib, char *value)
758 sdp_list_t *attrid_list;
759 uint32_t range = 0x0000ffff;
763 /* Get the old SDP record */
764 attrid_list = sdp_list_append(NULL, &range);
765 rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attrid_list);
766 sdp_list_free(attrid_list, NULL);
769 printf("Service get request failed.\n");
773 /* Check the type of attribute */
774 if (!strncasecmp(value, "u0x", 3)) {
776 uint16_t value_int = 0;
778 value_int = strtoul(value + 3, NULL, 16);
779 sdp_uuid16_create(&value_uuid, value_int);
780 printf("Adding attrib 0x%X uuid16 0x%X to record 0x%X\n",
781 attrib, value_int, handle);
783 sdp_attr_add_new(rec, attrib, SDP_UUID16, &value_uuid.value.uuid16);
784 } else if (!strncasecmp(value, "0x", 2)) {
787 value_int = strtoul(value + 2, NULL, 16);
788 printf("Adding attrib 0x%X int 0x%X to record 0x%X\n",
789 attrib, value_int, handle);
791 sdp_attr_add_new(rec, attrib, SDP_UINT32, &value_int);
794 printf("Adding attrib 0x%X string \"%s\" to record 0x%X\n",
795 attrib, value, handle);
797 /* Add/Update our attribute to the record */
798 sdp_attr_add_new(rec, attrib, SDP_TEXT_STR8, value);
801 /* Update on the server */
802 ret = sdp_device_record_update(sess, &interface, rec);
804 printf("Service Record update failed (%d).\n", errno);
805 sdp_record_free(rec);
809 static struct option set_options[] = {
810 { "help", 0, 0, 'h' },
814 static char *set_help =
816 "\tget record_handle attrib_id attrib_value\n";
819 * Add an attribute to an existing SDP record on the local SDP server
821 static int cmd_setattr(int argc, char **argv)
828 for_each_opt(opt, set_options, NULL) {
844 /* Convert command line args */
845 handle = strtoul(argv[0], NULL, 16);
846 attrib = strtoul(argv[1], NULL, 16);
849 sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
853 status = set_attrib(sess, handle, attrib, argv[2]);
860 * We do only simple data sequences. Sequence of sequences is a pain ;-)
863 static int set_attribseq(sdp_session_t *session, uint32_t handle, uint16_t attrib, int argc, char **argv)
865 sdp_list_t *attrid_list;
866 uint32_t range = 0x0000ffff;
868 sdp_data_t *pSequenceHolder = NULL;
872 uint8_t uuid16 = SDP_UUID16;
873 uint8_t uint32 = SDP_UINT32;
874 uint8_t str8 = SDP_TEXT_STR8;
877 /* Get the old SDP record */
878 attrid_list = sdp_list_append(NULL, &range);
879 rec = sdp_service_attr_req(session, handle, SDP_ATTR_REQ_RANGE, attrid_list);
880 sdp_list_free(attrid_list, NULL);
883 printf("Service get request failed.\n");
888 dtdArray = (void **)malloc(argc * sizeof(void *));
889 valueArray = (void **)malloc(argc * sizeof(void *));
890 allocArray = (void **)malloc(argc * sizeof(void *));
892 /* Loop on all args, add them in arrays */
893 for (i = 0; i < argc; i++) {
894 /* Check the type of attribute */
895 if (!strncasecmp(argv[i], "u0x", 3)) {
897 uint16_t value_int = strtoul((argv[i]) + 3, NULL, 16);
898 uuid_t *value_uuid = (uuid_t *) malloc(sizeof(uuid_t));
899 allocArray[i] = value_uuid;
900 sdp_uuid16_create(value_uuid, value_int);
902 printf("Adding uuid16 0x%X to record 0x%X\n", value_int, handle);
903 dtdArray[i] = &uuid16;
904 valueArray[i] = &value_uuid->value.uuid16;
905 } else if (!strncasecmp(argv[i], "0x", 2)) {
907 uint32_t *value_int = (uint32_t *) malloc(sizeof(int));
908 allocArray[i] = value_int;
909 *value_int = strtoul((argv[i]) + 2, NULL, 16);
911 printf("Adding int 0x%X to record 0x%X\n", *value_int, handle);
912 dtdArray[i] = &uint32;
913 valueArray[i] = value_int;
916 printf("Adding string \"%s\" to record 0x%X\n", argv[i], handle);
918 valueArray[i] = argv[i];
922 /* Add this sequence to the attrib list */
923 pSequenceHolder = sdp_seq_alloc(dtdArray, valueArray, argc);
924 if (pSequenceHolder) {
925 sdp_attr_replace(rec, attrib, pSequenceHolder);
927 /* Update on the server */
928 ret = sdp_device_record_update(session, &interface, rec);
930 printf("Service Record update failed (%d).\n", errno);
932 printf("Failed to create pSequenceHolder\n");
935 for (i = 0; i < argc; i++)
942 sdp_record_free(rec);
947 static struct option seq_options[] = {
948 { "help", 0, 0, 'h' },
952 static char *seq_help =
954 "\tget record_handle attrib_id attrib_values\n";
957 * Add an attribute sequence to an existing SDP record
958 * on the local SDP server
960 static int cmd_setseq(int argc, char **argv)
967 for_each_opt(opt, seq_options, NULL) {
983 /* Convert command line args */
984 handle = strtoul(argv[0], NULL, 16);
985 attrib = strtoul(argv[1], NULL, 16);
991 sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
995 status = set_attribseq(sess, handle, attrib, argc, argv);
1001 static void print_service_class(void *value, void *userData)
1003 char ServiceClassUUID_str[MAX_LEN_SERVICECLASS_UUID_STR];
1004 uuid_t *uuid = (uuid_t *)value;
1006 sdp_uuid2strn(uuid, UUID_str, MAX_LEN_UUID_STR);
1007 sdp_svclass_uuid2strn(uuid, ServiceClassUUID_str, MAX_LEN_SERVICECLASS_UUID_STR);
1008 if (uuid->type != SDP_UUID128)
1009 printf(" \"%s\" (0x%s)\n", ServiceClassUUID_str, UUID_str);
1011 printf(" UUID 128: %s\n", UUID_str);
1014 static void print_service_desc(void *value, void *user)
1016 char str[MAX_LEN_PROTOCOL_UUID_STR];
1017 sdp_data_t *p = (sdp_data_t *)value, *s;
1018 int i = 0, proto = 0;
1020 for (; p; p = p->next, i++) {
1025 sdp_uuid2strn(&p->val.uuid, UUID_str, MAX_LEN_UUID_STR);
1026 sdp_proto_uuid2strn(&p->val.uuid, str, sizeof(str));
1027 proto = sdp_uuid_to_proto(&p->val.uuid);
1028 printf(" \"%s\" (0x%s)\n", str, UUID_str);
1031 if (proto == RFCOMM_UUID)
1032 printf(" Channel: %d\n", p->val.uint8);
1034 printf(" uint8: 0x%x\n", p->val.uint8);
1037 if (proto == L2CAP_UUID) {
1039 printf(" PSM: %d\n", p->val.uint16);
1041 printf(" Version: 0x%04x\n", p->val.uint16);
1042 } else if (proto == BNEP_UUID)
1044 printf(" Version: 0x%04x\n", p->val.uint16);
1046 printf(" uint16: 0x%x\n", p->val.uint16);
1048 printf(" uint16: 0x%x\n", p->val.uint16);
1052 for (s = p->val.dataseq; s; s = s->next)
1053 printf(" %x", s->val.uint16);
1058 for (s = p->val.dataseq; s; s = s->next)
1059 printf(" %x", s->val.uint8);
1063 printf(" FIXME: dtd=0%x\n", p->dtd);
1069 static void print_lang_attr(void *value, void *user)
1071 sdp_lang_attr_t *lang = (sdp_lang_attr_t *)value;
1072 printf(" code_ISO639: 0x%02x\n", lang->code_ISO639);
1073 printf(" encoding: 0x%02x\n", lang->encoding);
1074 printf(" base_offset: 0x%02x\n", lang->base_offset);
1077 static void print_access_protos(void *value, void *userData)
1079 sdp_list_t *protDescSeq = (sdp_list_t *)value;
1080 sdp_list_foreach(protDescSeq, print_service_desc, 0);
1083 static void print_profile_desc(void *value, void *userData)
1085 sdp_profile_desc_t *desc = (sdp_profile_desc_t *)value;
1086 char str[MAX_LEN_PROFILEDESCRIPTOR_UUID_STR];
1088 sdp_uuid2strn(&desc->uuid, UUID_str, MAX_LEN_UUID_STR);
1089 sdp_profile_uuid2strn(&desc->uuid, str, MAX_LEN_PROFILEDESCRIPTOR_UUID_STR);
1091 printf(" \"%s\" (0x%s)\n", str, UUID_str);
1093 printf(" Version: 0x%04x\n", desc->version);
1097 * Parse a SDP record in user friendly form.
1099 static void print_service_attr(sdp_record_t *rec)
1101 sdp_list_t *list = 0, *proto = 0;
1103 sdp_record_print(rec);
1105 printf("Service RecHandle: 0x%x\n", rec->handle);
1107 if (sdp_get_service_classes(rec, &list) == 0) {
1108 printf("Service Class ID List:\n");
1109 sdp_list_foreach(list, print_service_class, 0);
1110 sdp_list_free(list, free);
1112 if (sdp_get_access_protos(rec, &proto) == 0) {
1113 printf("Protocol Descriptor List:\n");
1114 sdp_list_foreach(proto, print_access_protos, 0);
1115 sdp_list_foreach(proto, (sdp_list_func_t)sdp_list_free, 0);
1116 sdp_list_free(proto, 0);
1118 if (sdp_get_lang_attr(rec, &list) == 0) {
1119 printf("Language Base Attr List:\n");
1120 sdp_list_foreach(list, print_lang_attr, 0);
1121 sdp_list_free(list, free);
1123 if (sdp_get_profile_descs(rec, &list) == 0) {
1124 printf("Profile Descriptor List:\n");
1125 sdp_list_foreach(list, print_profile_desc, 0);
1126 sdp_list_free(list, free);
1131 * Support for Service (de)registration
1139 unsigned int profile;
1145 static void add_lang_attr(sdp_record_t *r)
1147 sdp_lang_attr_t base_lang;
1148 sdp_list_t *langs = 0;
1150 /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
1151 base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
1152 base_lang.encoding = 106;
1153 base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
1154 langs = sdp_list_append(0, &base_lang);
1155 sdp_set_lang_attr(r, langs);
1156 sdp_list_free(langs, 0);
1159 static int add_sp(sdp_session_t *session, svc_info_t *si)
1161 sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
1162 uuid_t root_uuid, sp_uuid, l2cap, rfcomm;
1163 sdp_profile_desc_t profile;
1164 sdp_record_t record;
1165 uint8_t u8 = si->channel ? si->channel : 1;
1166 sdp_data_t *channel;
1169 memset(&record, 0, sizeof(sdp_record_t));
1170 record.handle = si->handle;
1171 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1172 root = sdp_list_append(0, &root_uuid);
1173 sdp_set_browse_groups(&record, root);
1174 sdp_list_free(root, 0);
1176 sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
1177 svclass_id = sdp_list_append(0, &sp_uuid);
1178 sdp_set_service_classes(&record, svclass_id);
1179 sdp_list_free(svclass_id, 0);
1181 sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
1182 profile.version = 0x0100;
1183 profiles = sdp_list_append(0, &profile);
1184 sdp_set_profile_descs(&record, profiles);
1185 sdp_list_free(profiles, 0);
1187 sdp_uuid16_create(&l2cap, L2CAP_UUID);
1188 proto[0] = sdp_list_append(0, &l2cap);
1189 apseq = sdp_list_append(0, proto[0]);
1191 sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
1192 proto[1] = sdp_list_append(0, &rfcomm);
1193 channel = sdp_data_alloc(SDP_UINT8, &u8);
1194 proto[1] = sdp_list_append(proto[1], channel);
1195 apseq = sdp_list_append(apseq, proto[1]);
1197 aproto = sdp_list_append(0, apseq);
1198 sdp_set_access_protos(&record, aproto);
1200 add_lang_attr(&record);
1202 sdp_set_info_attr(&record, "Serial Port", "BlueZ", "COM Port");
1204 sdp_set_url_attr(&record, "http://www.bluez.org/",
1205 "http://www.bluez.org/", "http://www.bluez.org/");
1207 sdp_set_service_id(&record, sp_uuid);
1208 sdp_set_service_ttl(&record, 0xffff);
1209 sdp_set_service_avail(&record, 0xff);
1210 sdp_set_record_state(&record, 0x00001234);
1212 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1213 printf("Service Record registration failed\n");
1218 printf("Serial Port service registered\n");
1221 sdp_data_free(channel);
1222 sdp_list_free(proto[0], 0);
1223 sdp_list_free(proto[1], 0);
1224 sdp_list_free(apseq, 0);
1225 sdp_list_free(aproto, 0);
1230 static int add_dun(sdp_session_t *session, svc_info_t *si)
1232 sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto;
1233 uuid_t rootu, dun, gn, l2cap, rfcomm;
1234 sdp_profile_desc_t profile;
1235 sdp_list_t *proto[2];
1236 sdp_record_t record;
1237 uint8_t u8 = si->channel ? si->channel : 2;
1238 sdp_data_t *channel;
1241 memset(&record, 0, sizeof(sdp_record_t));
1242 record.handle = si->handle;
1244 sdp_uuid16_create(&rootu, PUBLIC_BROWSE_GROUP);
1245 root = sdp_list_append(0, &rootu);
1246 sdp_set_browse_groups(&record, root);
1248 sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
1249 svclass_id = sdp_list_append(0, &dun);
1250 sdp_uuid16_create(&gn, GENERIC_NETWORKING_SVCLASS_ID);
1251 svclass_id = sdp_list_append(svclass_id, &gn);
1252 sdp_set_service_classes(&record, svclass_id);
1254 sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID);
1255 profile.version = 0x0100;
1256 pfseq = sdp_list_append(0, &profile);
1257 sdp_set_profile_descs(&record, pfseq);
1259 sdp_uuid16_create(&l2cap, L2CAP_UUID);
1260 proto[0] = sdp_list_append(0, &l2cap);
1261 apseq = sdp_list_append(0, proto[0]);
1263 sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
1264 proto[1] = sdp_list_append(0, &rfcomm);
1265 channel = sdp_data_alloc(SDP_UINT8, &u8);
1266 proto[1] = sdp_list_append(proto[1], channel);
1267 apseq = sdp_list_append(apseq, proto[1]);
1269 aproto = sdp_list_append(0, apseq);
1270 sdp_set_access_protos(&record, aproto);
1272 sdp_set_info_attr(&record, "Dial-Up Networking", 0, 0);
1274 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1275 printf("Service Record registration failed\n");
1280 printf("Dial-Up Networking service registered\n");
1283 sdp_data_free(channel);
1284 sdp_list_free(proto[0], 0);
1285 sdp_list_free(proto[1], 0);
1286 sdp_list_free(apseq, 0);
1287 sdp_list_free(aproto, 0);
1292 static int add_fax(sdp_session_t *session, svc_info_t *si)
1294 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1295 uuid_t root_uuid, fax_uuid, tel_uuid, l2cap_uuid, rfcomm_uuid;
1296 sdp_profile_desc_t profile;
1297 sdp_list_t *aproto, *proto[2];
1298 sdp_record_t record;
1299 uint8_t u8 = si->channel? si->channel : 3;
1300 sdp_data_t *channel;
1303 memset(&record, 0, sizeof(sdp_record_t));
1304 record.handle = si->handle;
1306 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1307 root = sdp_list_append(0, &root_uuid);
1308 sdp_set_browse_groups(&record, root);
1310 sdp_uuid16_create(&fax_uuid, FAX_SVCLASS_ID);
1311 svclass_id = sdp_list_append(0, &fax_uuid);
1312 sdp_uuid16_create(&tel_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
1313 svclass_id = sdp_list_append(svclass_id, &tel_uuid);
1314 sdp_set_service_classes(&record, svclass_id);
1316 sdp_uuid16_create(&profile.uuid, FAX_PROFILE_ID);
1317 profile.version = 0x0100;
1318 pfseq = sdp_list_append(0, &profile);
1319 sdp_set_profile_descs(&record, pfseq);
1321 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1322 proto[0] = sdp_list_append(0, &l2cap_uuid);
1323 apseq = sdp_list_append(0, proto[0]);
1325 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1326 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1327 channel = sdp_data_alloc(SDP_UINT8, &u8);
1328 proto[1] = sdp_list_append(proto[1], channel);
1329 apseq = sdp_list_append(apseq, proto[1]);
1331 aproto = sdp_list_append(0, apseq);
1332 sdp_set_access_protos(&record, aproto);
1334 sdp_set_info_attr(&record, "Fax", 0, 0);
1336 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1337 printf("Service Record registration failed\n");
1341 printf("Fax service registered\n");
1343 sdp_data_free(channel);
1344 sdp_list_free(proto[0], 0);
1345 sdp_list_free(proto[1], 0);
1346 sdp_list_free(apseq, 0);
1347 sdp_list_free(aproto, 0);
1351 static int add_lan(sdp_session_t *session, svc_info_t *si)
1353 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1354 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
1355 sdp_profile_desc_t profile;
1356 sdp_list_t *aproto, *proto[2];
1357 sdp_record_t record;
1358 uint8_t u8 = si->channel ? si->channel : 4;
1359 sdp_data_t *channel;
1362 memset(&record, 0, sizeof(sdp_record_t));
1363 record.handle = si->handle;
1365 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1366 root = sdp_list_append(0, &root_uuid);
1367 sdp_set_browse_groups(&record, root);
1369 sdp_uuid16_create(&svclass_uuid, LAN_ACCESS_SVCLASS_ID);
1370 svclass_id = sdp_list_append(0, &svclass_uuid);
1371 sdp_set_service_classes(&record, svclass_id);
1373 sdp_uuid16_create(&profile.uuid, LAN_ACCESS_PROFILE_ID);
1374 profile.version = 0x0100;
1375 pfseq = sdp_list_append(0, &profile);
1376 sdp_set_profile_descs(&record, pfseq);
1378 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1379 proto[0] = sdp_list_append(0, &l2cap_uuid);
1380 apseq = sdp_list_append(0, proto[0]);
1382 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1383 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1384 channel = sdp_data_alloc(SDP_UINT8, &u8);
1385 proto[1] = sdp_list_append(proto[1], channel);
1386 apseq = sdp_list_append(apseq, proto[1]);
1388 aproto = sdp_list_append(0, apseq);
1389 sdp_set_access_protos(&record, aproto);
1391 sdp_set_info_attr(&record, "LAN Access over PPP", 0, 0);
1393 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1394 printf("Service Record registration failed\n");
1399 printf("LAN Access service registered\n");
1402 sdp_data_free(channel);
1403 sdp_list_free(proto[0], 0);
1404 sdp_list_free(proto[1], 0);
1405 sdp_list_free(apseq, 0);
1406 sdp_list_free(aproto, 0);
1411 static int add_headset(sdp_session_t *session, svc_info_t *si)
1413 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1414 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1415 sdp_profile_desc_t profile;
1416 sdp_list_t *aproto, *proto[2];
1417 sdp_record_t record;
1418 uint8_t u8 = si->channel ? si->channel : 5;
1419 sdp_data_t *channel;
1422 memset(&record, 0, sizeof(sdp_record_t));
1423 record.handle = si->handle;
1425 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1426 root = sdp_list_append(0, &root_uuid);
1427 sdp_set_browse_groups(&record, root);
1429 sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
1430 svclass_id = sdp_list_append(0, &svclass_uuid);
1431 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1432 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1433 sdp_set_service_classes(&record, svclass_id);
1435 sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
1436 profile.version = 0x0100;
1437 pfseq = sdp_list_append(0, &profile);
1438 sdp_set_profile_descs(&record, pfseq);
1440 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1441 proto[0] = sdp_list_append(0, &l2cap_uuid);
1442 apseq = sdp_list_append(0, proto[0]);
1444 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1445 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1446 channel = sdp_data_alloc(SDP_UINT8, &u8);
1447 proto[1] = sdp_list_append(proto[1], channel);
1448 apseq = sdp_list_append(apseq, proto[1]);
1450 aproto = sdp_list_append(0, apseq);
1451 sdp_set_access_protos(&record, aproto);
1453 sdp_set_info_attr(&record, "Headset", 0, 0);
1455 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1456 printf("Service Record registration failed\n");
1461 printf("Headset service registered\n");
1464 sdp_data_free(channel);
1465 sdp_list_free(proto[0], 0);
1466 sdp_list_free(proto[1], 0);
1467 sdp_list_free(apseq, 0);
1468 sdp_list_free(aproto, 0);
1473 static int add_headset_ag(sdp_session_t *session, svc_info_t *si)
1475 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1476 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1477 sdp_profile_desc_t profile;
1478 sdp_list_t *aproto, *proto[2];
1479 sdp_record_t record;
1480 uint8_t u8 = si->channel ? si->channel : 7;
1481 uint16_t u16 = 0x17;
1482 sdp_data_t *channel, *features;
1483 uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
1484 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
1487 memset(&record, 0, sizeof(sdp_record_t));
1488 record.handle = si->handle;
1490 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1491 root = sdp_list_append(0, &root_uuid);
1492 sdp_set_browse_groups(&record, root);
1494 sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
1495 svclass_id = sdp_list_append(0, &svclass_uuid);
1496 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1497 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1498 sdp_set_service_classes(&record, svclass_id);
1500 sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
1501 profile.version = 0x0100;
1502 pfseq = sdp_list_append(0, &profile);
1503 sdp_set_profile_descs(&record, pfseq);
1505 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1506 proto[0] = sdp_list_append(0, &l2cap_uuid);
1507 apseq = sdp_list_append(0, proto[0]);
1509 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1510 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1511 channel = sdp_data_alloc(SDP_UINT8, &u8);
1512 proto[1] = sdp_list_append(proto[1], channel);
1513 apseq = sdp_list_append(apseq, proto[1]);
1515 features = sdp_data_alloc(SDP_UINT16, &u16);
1516 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1518 aproto = sdp_list_append(0, apseq);
1519 sdp_set_access_protos(&record, aproto);
1521 sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
1523 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
1525 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
1526 printf("Service Record registration failed\n");
1531 printf("Headset AG service registered\n");
1534 sdp_data_free(channel);
1535 sdp_list_free(proto[0], 0);
1536 sdp_list_free(proto[1], 0);
1537 sdp_list_free(apseq, 0);
1538 sdp_list_free(aproto, 0);
1543 static int add_handsfree(sdp_session_t *session, svc_info_t *si)
1545 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1546 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1547 sdp_profile_desc_t profile;
1548 sdp_list_t *aproto, *proto[2];
1549 sdp_record_t record;
1550 uint8_t u8 = si->channel ? si->channel : 6;
1551 uint16_t u16 = 0x31;
1552 sdp_data_t *channel, *features;
1555 memset(&record, 0, sizeof(sdp_record_t));
1556 record.handle = si->handle;
1558 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1559 root = sdp_list_append(0, &root_uuid);
1560 sdp_set_browse_groups(&record, root);
1562 sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
1563 svclass_id = sdp_list_append(0, &svclass_uuid);
1564 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1565 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1566 sdp_set_service_classes(&record, svclass_id);
1568 sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
1569 profile.version = 0x0101;
1570 pfseq = sdp_list_append(0, &profile);
1571 sdp_set_profile_descs(&record, pfseq);
1573 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1574 proto[0] = sdp_list_append(0, &l2cap_uuid);
1575 apseq = sdp_list_append(0, proto[0]);
1577 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1578 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1579 channel = sdp_data_alloc(SDP_UINT8, &u8);
1580 proto[1] = sdp_list_append(proto[1], channel);
1581 apseq = sdp_list_append(apseq, proto[1]);
1583 features = sdp_data_alloc(SDP_UINT16, &u16);
1584 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1586 aproto = sdp_list_append(0, apseq);
1587 sdp_set_access_protos(&record, aproto);
1589 sdp_set_info_attr(&record, "Handsfree", 0, 0);
1591 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1592 printf("Service Record registration failed\n");
1597 printf("Handsfree service registered\n");
1600 sdp_data_free(channel);
1601 sdp_list_free(proto[0], 0);
1602 sdp_list_free(proto[1], 0);
1603 sdp_list_free(apseq, 0);
1604 sdp_list_free(aproto, 0);
1609 static int add_handsfree_ag(sdp_session_t *session, svc_info_t *si)
1611 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1612 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1613 sdp_profile_desc_t profile;
1614 sdp_list_t *aproto, *proto[2];
1615 sdp_record_t record;
1616 uint8_t u8 = si->channel ? si->channel : 7;
1617 uint16_t u16 = 0x17;
1618 sdp_data_t *channel, *features;
1619 uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
1620 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
1623 memset(&record, 0, sizeof(sdp_record_t));
1624 record.handle = si->handle;
1626 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1627 root = sdp_list_append(0, &root_uuid);
1628 sdp_set_browse_groups(&record, root);
1630 sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
1631 svclass_id = sdp_list_append(0, &svclass_uuid);
1632 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1633 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1634 sdp_set_service_classes(&record, svclass_id);
1636 sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
1637 profile.version = 0x0105;
1638 pfseq = sdp_list_append(0, &profile);
1639 sdp_set_profile_descs(&record, pfseq);
1641 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1642 proto[0] = sdp_list_append(0, &l2cap_uuid);
1643 apseq = sdp_list_append(0, proto[0]);
1645 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1646 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1647 channel = sdp_data_alloc(SDP_UINT8, &u8);
1648 proto[1] = sdp_list_append(proto[1], channel);
1649 apseq = sdp_list_append(apseq, proto[1]);
1651 features = sdp_data_alloc(SDP_UINT16, &u16);
1652 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1654 aproto = sdp_list_append(0, apseq);
1655 sdp_set_access_protos(&record, aproto);
1657 sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
1659 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
1661 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
1662 printf("Service Record registration failed\n");
1667 printf("Handsfree AG service registered\n");
1670 sdp_data_free(channel);
1671 sdp_list_free(proto[0], 0);
1672 sdp_list_free(proto[1], 0);
1673 sdp_list_free(apseq, 0);
1674 sdp_list_free(aproto, 0);
1679 static int add_simaccess(sdp_session_t *session, svc_info_t *si)
1681 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1682 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1683 sdp_profile_desc_t profile;
1684 sdp_list_t *aproto, *proto[2];
1685 sdp_record_t record;
1686 uint8_t u8 = si->channel? si->channel : 8;
1687 uint16_t u16 = 0x31;
1688 sdp_data_t *channel, *features;
1691 memset((void *)&record, 0, sizeof(sdp_record_t));
1692 record.handle = si->handle;
1694 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1695 root = sdp_list_append(0, &root_uuid);
1696 sdp_set_browse_groups(&record, root);
1698 sdp_uuid16_create(&svclass_uuid, SAP_SVCLASS_ID);
1699 svclass_id = sdp_list_append(0, &svclass_uuid);
1700 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
1701 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1702 sdp_set_service_classes(&record, svclass_id);
1704 sdp_uuid16_create(&profile.uuid, SAP_PROFILE_ID);
1705 profile.version = 0x0101;
1706 pfseq = sdp_list_append(0, &profile);
1707 sdp_set_profile_descs(&record, pfseq);
1709 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1710 proto[0] = sdp_list_append(0, &l2cap_uuid);
1711 apseq = sdp_list_append(0, proto[0]);
1713 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1714 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1715 channel = sdp_data_alloc(SDP_UINT8, &u8);
1716 proto[1] = sdp_list_append(proto[1], channel);
1717 apseq = sdp_list_append(apseq, proto[1]);
1719 features = sdp_data_alloc(SDP_UINT16, &u16);
1720 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1722 aproto = sdp_list_append(0, apseq);
1723 sdp_set_access_protos(&record, aproto);
1725 sdp_set_info_attr(&record, "SIM Access", 0, 0);
1727 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1728 printf("Service Record registration failed\n");
1733 printf("SIM Access service registered\n");
1736 sdp_data_free(channel);
1737 sdp_list_free(proto[0], 0);
1738 sdp_list_free(proto[1], 0);
1739 sdp_list_free(apseq, 0);
1740 sdp_list_free(aproto, 0);
1745 static int add_opush(sdp_session_t *session, svc_info_t *si)
1747 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1748 uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1749 sdp_profile_desc_t profile[1];
1750 sdp_list_t *aproto, *proto[3];
1751 sdp_record_t record;
1752 uint8_t chan = si->channel ? si->channel : 9;
1753 sdp_data_t *channel;
1754 uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
1755 //uint8_t formats[] = { 0xff };
1756 void *dtds[sizeof(formats)], *values[sizeof(formats)];
1758 uint8_t dtd = SDP_UINT8;
1762 memset(&record, 0, sizeof(sdp_record_t));
1763 record.handle = si->handle;
1765 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1766 root = sdp_list_append(0, &root_uuid);
1767 sdp_set_browse_groups(&record, root);
1769 sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
1770 svclass_id = sdp_list_append(0, &opush_uuid);
1771 sdp_set_service_classes(&record, svclass_id);
1773 sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
1774 profile[0].version = 0x0100;
1775 pfseq = sdp_list_append(0, profile);
1776 sdp_set_profile_descs(&record, pfseq);
1778 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1779 proto[0] = sdp_list_append(0, &l2cap_uuid);
1780 apseq = sdp_list_append(0, proto[0]);
1782 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1783 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1784 channel = sdp_data_alloc(SDP_UINT8, &chan);
1785 proto[1] = sdp_list_append(proto[1], channel);
1786 apseq = sdp_list_append(apseq, proto[1]);
1788 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1789 proto[2] = sdp_list_append(0, &obex_uuid);
1790 apseq = sdp_list_append(apseq, proto[2]);
1792 aproto = sdp_list_append(0, apseq);
1793 sdp_set_access_protos(&record, aproto);
1795 for (i = 0; i < sizeof(formats); i++) {
1797 values[i] = &formats[i];
1799 sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
1800 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
1802 sdp_set_info_attr(&record, "OBEX Object Push", 0, 0);
1804 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1805 printf("Service Record registration failed\n");
1810 printf("OBEX Object Push service registered\n");
1813 sdp_data_free(channel);
1814 sdp_list_free(proto[0], 0);
1815 sdp_list_free(proto[1], 0);
1816 sdp_list_free(proto[2], 0);
1817 sdp_list_free(apseq, 0);
1818 sdp_list_free(aproto, 0);
1823 static int add_ftp(sdp_session_t *session, svc_info_t *si)
1825 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1826 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1827 sdp_profile_desc_t profile[1];
1828 sdp_list_t *aproto, *proto[3];
1829 sdp_record_t record;
1830 uint8_t u8 = si->channel ? si->channel: 10;
1831 sdp_data_t *channel;
1834 memset(&record, 0, sizeof(sdp_record_t));
1835 record.handle = si->handle;
1837 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1838 root = sdp_list_append(0, &root_uuid);
1839 sdp_set_browse_groups(&record, root);
1841 sdp_uuid16_create(&ftrn_uuid, OBEX_FILETRANS_SVCLASS_ID);
1842 svclass_id = sdp_list_append(0, &ftrn_uuid);
1843 sdp_set_service_classes(&record, svclass_id);
1845 sdp_uuid16_create(&profile[0].uuid, OBEX_FILETRANS_PROFILE_ID);
1846 profile[0].version = 0x0100;
1847 pfseq = sdp_list_append(0, &profile[0]);
1848 sdp_set_profile_descs(&record, pfseq);
1850 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1851 proto[0] = sdp_list_append(0, &l2cap_uuid);
1852 apseq = sdp_list_append(0, proto[0]);
1854 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1855 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1856 channel = sdp_data_alloc(SDP_UINT8, &u8);
1857 proto[1] = sdp_list_append(proto[1], channel);
1858 apseq = sdp_list_append(apseq, proto[1]);
1860 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1861 proto[2] = sdp_list_append(0, &obex_uuid);
1862 apseq = sdp_list_append(apseq, proto[2]);
1864 aproto = sdp_list_append(0, apseq);
1865 sdp_set_access_protos(&record, aproto);
1867 sdp_set_info_attr(&record, "OBEX File Transfer", 0, 0);
1869 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1870 printf("Service Record registration failed\n");
1875 printf("OBEX File Transfer service registered\n");
1878 sdp_data_free(channel);
1879 sdp_list_free(proto[0], 0);
1880 sdp_list_free(proto[1], 0);
1881 sdp_list_free(proto[2], 0);
1882 sdp_list_free(apseq, 0);
1883 sdp_list_free(aproto, 0);
1888 static int add_directprint(sdp_session_t *session, svc_info_t *si)
1890 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1891 uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1892 sdp_profile_desc_t profile[1];
1893 sdp_list_t *aproto, *proto[3];
1894 sdp_record_t record;
1895 uint8_t chan = si->channel ? si->channel : 12;
1896 sdp_data_t *channel;
1899 memset(&record, 0, sizeof(sdp_record_t));
1900 record.handle = si->handle;
1902 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1903 root = sdp_list_append(0, &root_uuid);
1904 sdp_set_browse_groups(&record, root);
1906 sdp_uuid16_create(&opush_uuid, DIRECT_PRINTING_SVCLASS_ID);
1907 svclass_id = sdp_list_append(0, &opush_uuid);
1908 sdp_set_service_classes(&record, svclass_id);
1910 sdp_uuid16_create(&profile[0].uuid, BASIC_PRINTING_PROFILE_ID);
1911 profile[0].version = 0x0100;
1912 pfseq = sdp_list_append(0, profile);
1913 sdp_set_profile_descs(&record, pfseq);
1915 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1916 proto[0] = sdp_list_append(0, &l2cap_uuid);
1917 apseq = sdp_list_append(0, proto[0]);
1919 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1920 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1921 channel = sdp_data_alloc(SDP_UINT8, &chan);
1922 proto[1] = sdp_list_append(proto[1], channel);
1923 apseq = sdp_list_append(apseq, proto[1]);
1925 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1926 proto[2] = sdp_list_append(0, &obex_uuid);
1927 apseq = sdp_list_append(apseq, proto[2]);
1929 aproto = sdp_list_append(0, apseq);
1930 sdp_set_access_protos(&record, aproto);
1932 sdp_set_info_attr(&record, "Direct Printing", 0, 0);
1934 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1935 printf("Service Record registration failed\n");
1940 printf("Direct Printing service registered\n");
1943 sdp_data_free(channel);
1944 sdp_list_free(proto[0], 0);
1945 sdp_list_free(proto[1], 0);
1946 sdp_list_free(proto[2], 0);
1947 sdp_list_free(apseq, 0);
1948 sdp_list_free(aproto, 0);
1953 static int add_nap(sdp_session_t *session, svc_info_t *si)
1955 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1956 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
1957 sdp_profile_desc_t profile[1];
1958 sdp_list_t *aproto, *proto[2];
1959 sdp_record_t record;
1960 uint16_t lp = 0x000f, ver = 0x0100;
1961 sdp_data_t *psm, *version;
1964 memset(&record, 0, sizeof(sdp_record_t));
1965 record.handle = si->handle;
1967 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1968 root = sdp_list_append(0, &root_uuid);
1969 sdp_set_browse_groups(&record, root);
1971 sdp_uuid16_create(&ftrn_uuid, NAP_SVCLASS_ID);
1972 svclass_id = sdp_list_append(0, &ftrn_uuid);
1973 sdp_set_service_classes(&record, svclass_id);
1975 sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
1976 profile[0].version = 0x0100;
1977 pfseq = sdp_list_append(0, &profile[0]);
1978 sdp_set_profile_descs(&record, pfseq);
1980 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1981 proto[0] = sdp_list_append(0, &l2cap_uuid);
1982 psm = sdp_data_alloc(SDP_UINT16, &lp);
1983 proto[0] = sdp_list_append(proto[0], psm);
1984 apseq = sdp_list_append(0, proto[0]);
1986 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
1987 proto[1] = sdp_list_append(0, &bnep_uuid);
1988 version = sdp_data_alloc(SDP_UINT16, &ver);
1989 proto[1] = sdp_list_append(proto[1], version);
1992 uint16_t ptype[4] = { 0x0010, 0x0020, 0x0030, 0x0040 };
1993 sdp_data_t *head, *pseq;
1996 for (p = 0, head = NULL; p < 4; p++) {
1997 sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
1998 head = sdp_seq_append(head, data);
2000 pseq = sdp_data_alloc(SDP_SEQ16, head);
2001 proto[1] = sdp_list_append(proto[1], pseq);
2004 apseq = sdp_list_append(apseq, proto[1]);
2006 aproto = sdp_list_append(0, apseq);
2007 sdp_set_access_protos(&record, aproto);
2009 sdp_set_info_attr(&record, "Network Access Point Service", 0, 0);
2011 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2012 printf("Service Record registration failed\n");
2017 printf("NAP service registered\n");
2020 sdp_data_free(version);
2022 sdp_list_free(proto[0], 0);
2023 sdp_list_free(proto[1], 0);
2024 sdp_list_free(apseq, 0);
2025 sdp_list_free(aproto, 0);
2030 static int add_gn(sdp_session_t *session, svc_info_t *si)
2032 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2033 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2034 sdp_profile_desc_t profile[1];
2035 sdp_list_t *aproto, *proto[2];
2036 sdp_record_t record;
2037 uint16_t lp = 0x000f, ver = 0x0100;
2038 sdp_data_t *psm, *version;
2041 memset(&record, 0, sizeof(sdp_record_t));
2042 record.handle = si->handle;
2044 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2045 root = sdp_list_append(0, &root_uuid);
2046 sdp_set_browse_groups(&record, root);
2048 sdp_uuid16_create(&ftrn_uuid, GN_SVCLASS_ID);
2049 svclass_id = sdp_list_append(0, &ftrn_uuid);
2050 sdp_set_service_classes(&record, svclass_id);
2052 sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
2053 profile[0].version = 0x0100;
2054 pfseq = sdp_list_append(0, &profile[0]);
2055 sdp_set_profile_descs(&record, pfseq);
2057 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2058 proto[0] = sdp_list_append(0, &l2cap_uuid);
2059 psm = sdp_data_alloc(SDP_UINT16, &lp);
2060 proto[0] = sdp_list_append(proto[0], psm);
2061 apseq = sdp_list_append(0, proto[0]);
2063 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2064 proto[1] = sdp_list_append(0, &bnep_uuid);
2065 version = sdp_data_alloc(SDP_UINT16, &ver);
2066 proto[1] = sdp_list_append(proto[1], version);
2067 apseq = sdp_list_append(apseq, proto[1]);
2069 aproto = sdp_list_append(0, apseq);
2070 sdp_set_access_protos(&record, aproto);
2072 sdp_set_info_attr(&record, "Group Network Service", 0, 0);
2074 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2075 printf("Service Record registration failed\n");
2080 printf("GN service registered\n");
2083 sdp_data_free(version);
2085 sdp_list_free(proto[0], 0);
2086 sdp_list_free(proto[1], 0);
2087 sdp_list_free(apseq, 0);
2088 sdp_list_free(aproto, 0);
2093 static int add_panu(sdp_session_t *session, svc_info_t *si)
2095 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2096 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2097 sdp_profile_desc_t profile[1];
2098 sdp_list_t *aproto, *proto[2];
2099 sdp_record_t record;
2100 uint16_t lp = 0x000f, ver = 0x0100;
2101 sdp_data_t *psm, *version;
2104 memset(&record, 0, sizeof(sdp_record_t));
2105 record.handle = si->handle;
2107 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2108 root = sdp_list_append(NULL, &root_uuid);
2109 sdp_set_browse_groups(&record, root);
2110 sdp_list_free(root, NULL);
2112 sdp_uuid16_create(&ftrn_uuid, PANU_SVCLASS_ID);
2113 svclass_id = sdp_list_append(NULL, &ftrn_uuid);
2114 sdp_set_service_classes(&record, svclass_id);
2115 sdp_list_free(svclass_id, NULL);
2117 sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
2118 profile[0].version = 0x0100;
2119 pfseq = sdp_list_append(NULL, &profile[0]);
2120 sdp_set_profile_descs(&record, pfseq);
2121 sdp_list_free(pfseq, NULL);
2123 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2124 proto[0] = sdp_list_append(NULL, &l2cap_uuid);
2125 psm = sdp_data_alloc(SDP_UINT16, &lp);
2126 proto[0] = sdp_list_append(proto[0], psm);
2127 apseq = sdp_list_append(NULL, proto[0]);
2129 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2130 proto[1] = sdp_list_append(NULL, &bnep_uuid);
2131 version = sdp_data_alloc(SDP_UINT16, &ver);
2132 proto[1] = sdp_list_append(proto[1], version);
2133 apseq = sdp_list_append(apseq, proto[1]);
2135 aproto = sdp_list_append(NULL, apseq);
2136 sdp_set_access_protos(&record, aproto);
2138 sdp_set_info_attr(&record, "PAN User", NULL, NULL);
2140 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2141 printf("Service Record registration failed\n");
2146 printf("PANU service registered\n");
2149 sdp_data_free(version);
2151 sdp_list_free(proto[0], 0);
2152 sdp_list_free(proto[1], 0);
2153 sdp_list_free(apseq, 0);
2154 sdp_list_free(aproto, 0);
2159 static int add_hid_keyb(sdp_session_t *session, svc_info_t *si)
2161 sdp_record_t record;
2162 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2163 uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
2164 sdp_profile_desc_t profile[1];
2165 sdp_list_t *aproto, *proto[3];
2166 sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
2168 uint8_t dtd = SDP_UINT16;
2169 uint8_t dtd2 = SDP_UINT8;
2170 uint8_t dtd_data = SDP_TEXT_STR8;
2176 uint8_t hid_spec_type = 0x22;
2177 uint16_t hid_attr_lang[] = { 0x409, 0x100 };
2178 static const uint16_t ctrl = 0x11;
2179 static const uint16_t intr = 0x13;
2180 static const uint16_t hid_attr[] = { 0x100, 0x111, 0x40, 0x0d, 0x01, 0x01 };
2181 static const uint16_t hid_attr2[] = { 0x0, 0x01, 0x100, 0x1f40, 0x01, 0x01 };
2182 const uint8_t hid_spec[] = {
2183 0x05, 0x01, // usage page
2184 0x09, 0x06, // keyboard
2185 0xa1, 0x01, // key codes
2186 0x85, 0x01, // minimum
2188 0x19, 0xe0, // logical min
2189 0x29, 0xe7, // logical max
2190 0x15, 0x00, // report size
2191 0x25, 0x01, // report count
2192 0x75, 0x01, // input data variable absolute
2193 0x95, 0x08, // report count
2194 0x81, 0x02, // report size
2235 memset(&record, 0, sizeof(sdp_record_t));
2236 record.handle = si->handle;
2238 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2239 root = sdp_list_append(0, &root_uuid);
2240 sdp_set_browse_groups(&record, root);
2242 add_lang_attr(&record);
2244 sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
2245 svclass_id = sdp_list_append(0, &hidkb_uuid);
2246 sdp_set_service_classes(&record, svclass_id);
2248 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
2249 profile[0].version = 0x0100;
2250 pfseq = sdp_list_append(0, profile);
2251 sdp_set_profile_descs(&record, pfseq);
2254 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2255 proto[1] = sdp_list_append(0, &l2cap_uuid);
2256 psm = sdp_data_alloc(SDP_UINT16, &ctrl);
2257 proto[1] = sdp_list_append(proto[1], psm);
2258 apseq = sdp_list_append(0, proto[1]);
2260 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2261 proto[2] = sdp_list_append(0, &hidp_uuid);
2262 apseq = sdp_list_append(apseq, proto[2]);
2264 aproto = sdp_list_append(0, apseq);
2265 sdp_set_access_protos(&record, aproto);
2267 /* additional protocols */
2268 proto[1] = sdp_list_append(0, &l2cap_uuid);
2269 psm = sdp_data_alloc(SDP_UINT16, &intr);
2270 proto[1] = sdp_list_append(proto[1], psm);
2271 apseq = sdp_list_append(0, proto[1]);
2273 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2274 proto[2] = sdp_list_append(0, &hidp_uuid);
2275 apseq = sdp_list_append(apseq, proto[2]);
2277 aproto = sdp_list_append(0, apseq);
2278 sdp_set_add_access_protos(&record, aproto);
2280 sdp_set_info_attr(&record, "HID Keyboard", NULL, NULL);
2282 for (i = 0; i < sizeof(hid_attr) / 2; i++)
2283 sdp_attr_add_new(&record,
2284 SDP_ATTR_HID_DEVICE_RELEASE_NUMBER + i,
2285 SDP_UINT16, &hid_attr[i]);
2288 values[0] = &hid_spec_type;
2289 dtds[1] = &dtd_data;
2290 values[1] = (uint8_t *) hid_spec;
2292 leng[1] = sizeof(hid_spec);
2293 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
2294 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
2295 sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
2297 for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
2299 values2[i] = &hid_attr_lang[i];
2302 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
2303 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
2304 sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
2306 sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE, SDP_UINT16, &hid_attr2[0]);
2308 for (i = 0; i < sizeof(hid_attr2) / 2 - 1; i++)
2309 sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP + i,
2310 SDP_UINT16, &hid_attr2[i + 1]);
2312 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
2313 printf("Service Record registration failed\n");
2317 printf("HID keyboard service registered\n");
2322 static int add_hid_wiimote(sdp_session_t *session, svc_info_t *si)
2324 sdp_record_t record;
2325 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2326 uuid_t root_uuid, hid_uuid, l2cap_uuid, hidp_uuid;
2327 sdp_profile_desc_t profile[1];
2328 sdp_list_t *aproto, *proto[3];
2329 sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
2331 uint8_t dtd = SDP_UINT16;
2332 uint8_t dtd2 = SDP_UINT8;
2333 uint8_t dtd_data = SDP_TEXT_STR8;
2339 uint8_t hid_spec_type = 0x22;
2340 uint16_t hid_attr_lang[] = { 0x409, 0x100 };
2341 uint16_t ctrl = 0x11, intr = 0x13;
2342 uint16_t hid_release = 0x0100, parser_version = 0x0111;
2343 uint8_t subclass = 0x04, country = 0x33;
2344 uint8_t virtual_cable = 0, reconnect = 1, sdp_disable = 0;
2345 uint8_t battery = 1, remote_wakeup = 1;
2346 uint16_t profile_version = 0x0100, superv_timeout = 0x0c80;
2347 uint8_t norm_connect = 0, boot_device = 0;
2348 const uint8_t hid_spec[] = {
2349 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10,
2350 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
2351 0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00,
2352 0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2353 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00,
2354 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2355 0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2356 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2357 0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
2358 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00,
2359 0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
2360 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2361 0x85, 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2362 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00,
2363 0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2364 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00,
2365 0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00,
2366 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00,
2367 0x85, 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00,
2368 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00,
2369 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2370 0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2371 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2372 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2373 0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2374 0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2375 0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2379 memset(&record, 0, sizeof(sdp_record_t));
2380 record.handle = si->handle;
2382 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2383 root = sdp_list_append(NULL, &root_uuid);
2384 sdp_set_browse_groups(&record, root);
2386 sdp_uuid16_create(&hid_uuid, HID_SVCLASS_ID);
2387 svclass_id = sdp_list_append(NULL, &hid_uuid);
2388 sdp_set_service_classes(&record, svclass_id);
2390 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
2391 profile[0].version = 0x0100;
2392 pfseq = sdp_list_append(NULL, profile);
2393 sdp_set_profile_descs(&record, pfseq);
2395 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2396 proto[1] = sdp_list_append(0, &l2cap_uuid);
2397 psm = sdp_data_alloc(SDP_UINT16, &ctrl);
2398 proto[1] = sdp_list_append(proto[1], psm);
2399 apseq = sdp_list_append(0, proto[1]);
2401 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2402 proto[2] = sdp_list_append(0, &hidp_uuid);
2403 apseq = sdp_list_append(apseq, proto[2]);
2405 aproto = sdp_list_append(0, apseq);
2406 sdp_set_access_protos(&record, aproto);
2408 proto[1] = sdp_list_append(0, &l2cap_uuid);
2409 psm = sdp_data_alloc(SDP_UINT16, &intr);
2410 proto[1] = sdp_list_append(proto[1], psm);
2411 apseq = sdp_list_append(0, proto[1]);
2413 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2414 proto[2] = sdp_list_append(0, &hidp_uuid);
2415 apseq = sdp_list_append(apseq, proto[2]);
2417 aproto = sdp_list_append(0, apseq);
2418 sdp_set_add_access_protos(&record, aproto);
2420 add_lang_attr(&record);
2422 sdp_set_info_attr(&record, "Nintendo RVL-CNT-01",
2423 "Nintendo", "Nintendo RVL-CNT-01");
2425 sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER,
2426 SDP_UINT16, &hid_release);
2428 sdp_attr_add_new(&record, SDP_ATTR_HID_PARSER_VERSION,
2429 SDP_UINT16, &parser_version);
2431 sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_SUBCLASS,
2432 SDP_UINT8, &subclass);
2434 sdp_attr_add_new(&record, SDP_ATTR_HID_COUNTRY_CODE,
2435 SDP_UINT8, &country);
2437 sdp_attr_add_new(&record, SDP_ATTR_HID_VIRTUAL_CABLE,
2438 SDP_BOOL, &virtual_cable);
2440 sdp_attr_add_new(&record, SDP_ATTR_HID_RECONNECT_INITIATE,
2441 SDP_BOOL, &reconnect);
2444 values[0] = &hid_spec_type;
2445 dtds[1] = &dtd_data;
2446 values[1] = (uint8_t *) hid_spec;
2448 leng[1] = sizeof(hid_spec);
2449 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
2450 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
2451 sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
2453 for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
2455 values2[i] = &hid_attr_lang[i];
2458 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
2459 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
2460 sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
2462 sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE,
2463 SDP_BOOL, &sdp_disable);
2465 sdp_attr_add_new(&record, SDP_ATTR_HID_BATTERY_POWER,
2466 SDP_BOOL, &battery);
2468 sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP,
2469 SDP_BOOL, &remote_wakeup);
2471 sdp_attr_add_new(&record, SDP_ATTR_HID_PROFILE_VERSION,
2472 SDP_UINT16, &profile_version);
2474 sdp_attr_add_new(&record, SDP_ATTR_HID_SUPERVISION_TIMEOUT,
2475 SDP_UINT16, &superv_timeout);
2477 sdp_attr_add_new(&record, SDP_ATTR_HID_NORMALLY_CONNECTABLE,
2478 SDP_BOOL, &norm_connect);
2480 sdp_attr_add_new(&record, SDP_ATTR_HID_BOOT_DEVICE,
2481 SDP_BOOL, &boot_device);
2483 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
2484 printf("Service Record registration failed\n");
2488 printf("Wii-Mote service registered\n");
2493 static int add_cip(sdp_session_t *session, svc_info_t *si)
2495 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2496 uuid_t root_uuid, l2cap, cmtp, cip;
2497 sdp_profile_desc_t profile[1];
2498 sdp_list_t *aproto, *proto[2];
2499 sdp_record_t record;
2500 uint16_t psm = si->psm ? si->psm : 0x1001;
2501 uint8_t netid = si->network ? si->network : 0x02; // 0x02 = ISDN, 0x03 = GSM
2502 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
2505 memset(&record, 0, sizeof(sdp_record_t));
2506 record.handle = si->handle;
2508 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2509 root = sdp_list_append(0, &root_uuid);
2510 sdp_set_browse_groups(&record, root);
2512 sdp_uuid16_create(&cip, CIP_SVCLASS_ID);
2513 svclass_id = sdp_list_append(0, &cip);
2514 sdp_set_service_classes(&record, svclass_id);
2516 sdp_uuid16_create(&profile[0].uuid, CIP_PROFILE_ID);
2517 profile[0].version = 0x0100;
2518 pfseq = sdp_list_append(0, &profile[0]);
2519 sdp_set_profile_descs(&record, pfseq);
2521 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2522 proto[0] = sdp_list_append(0, &l2cap);
2523 apseq = sdp_list_append(0, proto[0]);
2524 proto[0] = sdp_list_append(proto[0], sdp_data_alloc(SDP_UINT16, &psm));
2525 apseq = sdp_list_append(0, proto[0]);
2527 sdp_uuid16_create(&cmtp, CMTP_UUID);
2528 proto[1] = sdp_list_append(0, &cmtp);
2529 apseq = sdp_list_append(apseq, proto[1]);
2531 aproto = sdp_list_append(0, apseq);
2532 sdp_set_access_protos(&record, aproto);
2534 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
2536 sdp_set_info_attr(&record, "Common ISDN Access", 0, 0);
2538 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2539 printf("Service Record registration failed\n");
2544 printf("CIP service registered\n");
2547 sdp_list_free(proto[0], 0);
2548 sdp_list_free(proto[1], 0);
2549 sdp_list_free(apseq, 0);
2550 sdp_list_free(aproto, 0);
2551 sdp_data_free(network);
2556 static int add_ctp(sdp_session_t *session, svc_info_t *si)
2558 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2559 uuid_t root_uuid, l2cap, tcsbin, ctp;
2560 sdp_profile_desc_t profile[1];
2561 sdp_list_t *aproto, *proto[2];
2562 sdp_record_t record;
2563 uint8_t netid = si->network ? si->network : 0x02; // 0x01-0x07 cf. p120 profile document
2564 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
2567 memset(&record, 0, sizeof(sdp_record_t));
2568 record.handle = si->handle;
2570 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2571 root = sdp_list_append(0, &root_uuid);
2572 sdp_set_browse_groups(&record, root);
2574 sdp_uuid16_create(&ctp, CORDLESS_TELEPHONY_SVCLASS_ID);
2575 svclass_id = sdp_list_append(0, &ctp);
2576 sdp_set_service_classes(&record, svclass_id);
2578 sdp_uuid16_create(&profile[0].uuid, CORDLESS_TELEPHONY_PROFILE_ID);
2579 profile[0].version = 0x0100;
2580 pfseq = sdp_list_append(0, &profile[0]);
2581 sdp_set_profile_descs(&record, pfseq);
2583 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2584 proto[0] = sdp_list_append(0, &l2cap);
2585 apseq = sdp_list_append(0, proto[0]);
2587 sdp_uuid16_create(&tcsbin, TCS_BIN_UUID);
2588 proto[1] = sdp_list_append(0, &tcsbin);
2589 apseq = sdp_list_append(apseq, proto[1]);
2591 aproto = sdp_list_append(0, apseq);
2592 sdp_set_access_protos(&record, aproto);
2594 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
2596 sdp_set_info_attr(&record, "Cordless Telephony", 0, 0);
2598 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2599 printf("Service Record registration failed\n");
2604 printf("CTP service registered\n");
2607 sdp_list_free(proto[0], 0);
2608 sdp_list_free(proto[1], 0);
2609 sdp_list_free(apseq, 0);
2610 sdp_list_free(aproto, 0);
2611 sdp_data_free(network);
2616 static int add_a2source(sdp_session_t *session, svc_info_t *si)
2618 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2619 uuid_t root_uuid, l2cap, avdtp, a2src;
2620 sdp_profile_desc_t profile[1];
2621 sdp_list_t *aproto, *proto[2];
2622 sdp_record_t record;
2623 sdp_data_t *psm, *version;
2624 uint16_t lp = 0x0019, ver = 0x0100;
2627 memset(&record, 0, sizeof(sdp_record_t));
2628 record.handle = si->handle;
2630 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2631 root = sdp_list_append(0, &root_uuid);
2632 sdp_set_browse_groups(&record, root);
2634 sdp_uuid16_create(&a2src, AUDIO_SOURCE_SVCLASS_ID);
2635 svclass_id = sdp_list_append(0, &a2src);
2636 sdp_set_service_classes(&record, svclass_id);
2638 sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
2639 profile[0].version = 0x0100;
2640 pfseq = sdp_list_append(0, &profile[0]);
2641 sdp_set_profile_descs(&record, pfseq);
2643 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2644 proto[0] = sdp_list_append(0, &l2cap);
2645 psm = sdp_data_alloc(SDP_UINT16, &lp);
2646 proto[0] = sdp_list_append(proto[0], psm);
2647 apseq = sdp_list_append(0, proto[0]);
2649 sdp_uuid16_create(&avdtp, AVDTP_UUID);
2650 proto[1] = sdp_list_append(0, &avdtp);
2651 version = sdp_data_alloc(SDP_UINT16, &ver);
2652 proto[1] = sdp_list_append(proto[1], version);
2653 apseq = sdp_list_append(apseq, proto[1]);
2655 aproto = sdp_list_append(0, apseq);
2656 sdp_set_access_protos(&record, aproto);
2658 sdp_set_info_attr(&record, "Audio Source", 0, 0);
2660 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2661 printf("Service Record registration failed\n");
2666 printf("Audio source service registered\n");
2669 sdp_list_free(proto[0], 0);
2670 sdp_list_free(proto[1], 0);
2671 sdp_list_free(apseq, 0);
2672 sdp_list_free(aproto, 0);
2677 static int add_a2sink(sdp_session_t *session, svc_info_t *si)
2679 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2680 uuid_t root_uuid, l2cap, avdtp, a2snk;
2681 sdp_profile_desc_t profile[1];
2682 sdp_list_t *aproto, *proto[2];
2683 sdp_record_t record;
2684 sdp_data_t *psm, *version;
2685 uint16_t lp = 0x0019, ver = 0x0100;
2688 memset(&record, 0, sizeof(sdp_record_t));
2689 record.handle = si->handle;
2691 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2692 root = sdp_list_append(0, &root_uuid);
2693 sdp_set_browse_groups(&record, root);
2695 sdp_uuid16_create(&a2snk, AUDIO_SINK_SVCLASS_ID);
2696 svclass_id = sdp_list_append(0, &a2snk);
2697 sdp_set_service_classes(&record, svclass_id);
2699 sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
2700 profile[0].version = 0x0100;
2701 pfseq = sdp_list_append(0, &profile[0]);
2702 sdp_set_profile_descs(&record, pfseq);
2704 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2705 proto[0] = sdp_list_append(0, &l2cap);
2706 psm = sdp_data_alloc(SDP_UINT16, &lp);
2707 proto[0] = sdp_list_append(proto[0], psm);
2708 apseq = sdp_list_append(0, proto[0]);
2710 sdp_uuid16_create(&avdtp, AVDTP_UUID);
2711 proto[1] = sdp_list_append(0, &avdtp);
2712 version = sdp_data_alloc(SDP_UINT16, &ver);
2713 proto[1] = sdp_list_append(proto[1], version);
2714 apseq = sdp_list_append(apseq, proto[1]);
2716 aproto = sdp_list_append(0, apseq);
2717 sdp_set_access_protos(&record, aproto);
2719 sdp_set_info_attr(&record, "Audio Sink", 0, 0);
2721 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2722 printf("Service Record registration failed\n");
2727 printf("Audio sink service registered\n");
2730 sdp_list_free(proto[0], 0);
2731 sdp_list_free(proto[1], 0);
2732 sdp_list_free(apseq, 0);
2733 sdp_list_free(aproto, 0);
2738 static int add_avrct(sdp_session_t *session, svc_info_t *si)
2740 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2741 uuid_t root_uuid, l2cap, avctp, avrct;
2742 sdp_profile_desc_t profile[1];
2743 sdp_list_t *aproto, *proto[2];
2744 sdp_record_t record;
2745 sdp_data_t *psm, *version, *features;
2746 uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
2749 memset(&record, 0, sizeof(sdp_record_t));
2750 record.handle = si->handle;
2752 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2753 root = sdp_list_append(0, &root_uuid);
2754 sdp_set_browse_groups(&record, root);
2756 sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID);
2757 svclass_id = sdp_list_append(0, &avrct);
2758 sdp_set_service_classes(&record, svclass_id);
2760 sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
2761 profile[0].version = 0x0100;
2762 pfseq = sdp_list_append(0, &profile[0]);
2763 sdp_set_profile_descs(&record, pfseq);
2765 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2766 proto[0] = sdp_list_append(0, &l2cap);
2767 psm = sdp_data_alloc(SDP_UINT16, &lp);
2768 proto[0] = sdp_list_append(proto[0], psm);
2769 apseq = sdp_list_append(0, proto[0]);
2771 sdp_uuid16_create(&avctp, AVCTP_UUID);
2772 proto[1] = sdp_list_append(0, &avctp);
2773 version = sdp_data_alloc(SDP_UINT16, &ver);
2774 proto[1] = sdp_list_append(proto[1], version);
2775 apseq = sdp_list_append(apseq, proto[1]);
2777 aproto = sdp_list_append(0, apseq);
2778 sdp_set_access_protos(&record, aproto);
2780 features = sdp_data_alloc(SDP_UINT16, &feat);
2781 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
2783 sdp_set_info_attr(&record, "AVRCP CT", 0, 0);
2785 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2786 printf("Service Record registration failed\n");
2791 printf("Remote control service registered\n");
2794 sdp_list_free(proto[0], 0);
2795 sdp_list_free(proto[1], 0);
2796 sdp_list_free(apseq, 0);
2797 sdp_list_free(aproto, 0);
2802 static int add_avrtg(sdp_session_t *session, svc_info_t *si)
2804 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2805 uuid_t root_uuid, l2cap, avctp, avrtg;
2806 sdp_profile_desc_t profile[1];
2807 sdp_list_t *aproto, *proto[2];
2808 sdp_record_t record;
2809 sdp_data_t *psm, *version, *features;
2810 uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
2813 memset(&record, 0, sizeof(sdp_record_t));
2814 record.handle = si->handle;
2816 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2817 root = sdp_list_append(0, &root_uuid);
2818 sdp_set_browse_groups(&record, root);
2820 sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID);
2821 svclass_id = sdp_list_append(0, &avrtg);
2822 sdp_set_service_classes(&record, svclass_id);
2824 sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
2825 profile[0].version = 0x0100;
2826 pfseq = sdp_list_append(0, &profile[0]);
2827 sdp_set_profile_descs(&record, pfseq);
2829 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2830 proto[0] = sdp_list_append(0, &l2cap);
2831 psm = sdp_data_alloc(SDP_UINT16, &lp);
2832 proto[0] = sdp_list_append(proto[0], psm);
2833 apseq = sdp_list_append(0, proto[0]);
2835 sdp_uuid16_create(&avctp, AVCTP_UUID);
2836 proto[1] = sdp_list_append(0, &avctp);
2837 version = sdp_data_alloc(SDP_UINT16, &ver);
2838 proto[1] = sdp_list_append(proto[1], version);
2839 apseq = sdp_list_append(apseq, proto[1]);
2841 aproto = sdp_list_append(0, apseq);
2842 sdp_set_access_protos(&record, aproto);
2844 features = sdp_data_alloc(SDP_UINT16, &feat);
2845 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
2847 sdp_set_info_attr(&record, "AVRCP TG", 0, 0);
2849 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2850 printf("Service Record registration failed\n");
2855 printf("Remote target service registered\n");
2858 sdp_list_free(proto[0], 0);
2859 sdp_list_free(proto[1], 0);
2860 sdp_list_free(apseq, 0);
2861 sdp_list_free(aproto, 0);
2866 static int add_udi_ue(sdp_session_t *session, svc_info_t *si)
2868 sdp_record_t record;
2869 sdp_list_t *root, *svclass, *proto;
2870 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
2871 uint8_t channel = si->channel ? si->channel: 18;
2873 memset(&record, 0, sizeof(record));
2874 record.handle = si->handle;
2876 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2877 root = sdp_list_append(NULL, &root_uuid);
2878 sdp_set_browse_groups(&record, root);
2879 sdp_list_free(root, NULL);
2881 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2882 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
2884 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
2885 proto = sdp_list_append(proto, sdp_list_append(
2886 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
2888 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
2890 sdp_uuid16_create(&svclass_uuid, UDI_MT_SVCLASS_ID);
2891 svclass = sdp_list_append(NULL, &svclass_uuid);
2892 sdp_set_service_classes(&record, svclass);
2893 sdp_list_free(svclass, NULL);
2895 sdp_set_info_attr(&record, "UDI UE", NULL, NULL);
2897 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2898 printf("Service Record registration failed\n");
2902 printf("UDI UE service registered\n");
2907 static int add_udi_te(sdp_session_t *session, svc_info_t *si)
2909 sdp_record_t record;
2910 sdp_list_t *root, *svclass, *proto;
2911 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
2912 uint8_t channel = si->channel ? si->channel: 19;
2914 memset(&record, 0, sizeof(record));
2915 record.handle = si->handle;
2917 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2918 root = sdp_list_append(NULL, &root_uuid);
2919 sdp_set_browse_groups(&record, root);
2920 sdp_list_free(root, NULL);
2922 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2923 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
2925 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
2926 proto = sdp_list_append(proto, sdp_list_append(
2927 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
2929 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
2931 sdp_uuid16_create(&svclass_uuid, UDI_TA_SVCLASS_ID);
2932 svclass = sdp_list_append(NULL, &svclass_uuid);
2933 sdp_set_service_classes(&record, svclass);
2934 sdp_list_free(svclass, NULL);
2936 sdp_set_info_attr(&record, "UDI TE", NULL, NULL);
2938 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2939 printf("Service Record registration failed\n");
2943 printf("UDI TE service registered\n");
2948 static unsigned char sr1_uuid[] = { 0xbc, 0x19, 0x9c, 0x24, 0x95, 0x8b, 0x4c, 0xc0,
2949 0xa2, 0xcb, 0xfd, 0x8a, 0x30, 0xbf, 0x32, 0x06 };
2951 static int add_sr1(sdp_session_t *session, svc_info_t *si)
2953 sdp_record_t record;
2954 sdp_list_t *root, *svclass;
2955 uuid_t root_uuid, svclass_uuid;
2957 memset(&record, 0, sizeof(record));
2958 record.handle = si->handle;
2960 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2961 root = sdp_list_append(NULL, &root_uuid);
2962 sdp_set_browse_groups(&record, root);
2964 sdp_uuid128_create(&svclass_uuid, (void *) sr1_uuid);
2965 svclass = sdp_list_append(NULL, &svclass_uuid);
2966 sdp_set_service_classes(&record, svclass);
2968 sdp_set_info_attr(&record, "TOSHIBA SR-1", NULL, NULL);
2970 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2971 printf("Service Record registration failed\n");
2975 printf("Toshiba Speech Recognition SR-1 service record registered\n");
2980 static unsigned char syncmls_uuid[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
2981 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
2983 static unsigned char syncmlc_uuid[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
2984 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
2986 static int add_syncml(sdp_session_t *session, svc_info_t *si)
2988 sdp_record_t record;
2989 sdp_list_t *root, *svclass, *proto;
2990 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
2991 uint8_t channel = si->channel ? si->channel: 15;
2993 memset(&record, 0, sizeof(record));
2994 record.handle = si->handle;
2996 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2997 root = sdp_list_append(NULL, &root_uuid);
2998 sdp_set_browse_groups(&record, root);
3000 sdp_uuid128_create(&svclass_uuid, (void *) syncmlc_uuid);
3001 svclass = sdp_list_append(NULL, &svclass_uuid);
3002 sdp_set_service_classes(&record, svclass);
3004 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3005 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3007 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3008 proto = sdp_list_append(proto, sdp_list_append(
3009 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3011 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
3012 proto = sdp_list_append(proto, sdp_list_append(NULL, &obex_uuid));
3014 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3016 sdp_set_info_attr(&record, "SyncML Client", NULL, NULL);
3018 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3019 printf("Service Record registration failed\n");
3023 printf("SyncML Client service record registered\n");
3028 static unsigned char async_uuid[] = { 0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62,
3029 0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C };
3031 static int add_activesync(sdp_session_t *session, svc_info_t *si)
3033 sdp_record_t record;
3034 sdp_list_t *root, *svclass, *proto;
3035 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3036 uint8_t channel = si->channel ? si->channel: 21;
3038 memset(&record, 0, sizeof(record));
3039 record.handle = si->handle;
3041 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3042 root = sdp_list_append(NULL, &root_uuid);
3043 sdp_set_browse_groups(&record, root);
3045 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3046 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3048 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3049 proto = sdp_list_append(proto, sdp_list_append(
3050 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3052 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3054 sdp_uuid128_create(&svclass_uuid, (void *) async_uuid);
3055 svclass = sdp_list_append(NULL, &svclass_uuid);
3056 sdp_set_service_classes(&record, svclass);
3058 sdp_set_info_attr(&record, "Microsoft ActiveSync", NULL, NULL);
3060 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3061 printf("Service Record registration failed\n");
3065 printf("ActiveSync service record registered\n");
3070 static unsigned char hotsync_uuid[] = { 0xD8, 0x0C, 0xF9, 0xEA, 0x13, 0x4C, 0x11, 0xD5,
3071 0x83, 0xCE, 0x00, 0x30, 0x65, 0x7C, 0x54, 0x3C };
3073 static int add_hotsync(sdp_session_t *session, svc_info_t *si)
3075 sdp_record_t record;
3076 sdp_list_t *root, *svclass, *proto;
3077 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3078 uint8_t channel = si->channel ? si->channel: 22;
3080 memset(&record, 0, sizeof(record));
3081 record.handle = si->handle;
3083 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3084 root = sdp_list_append(NULL, &root_uuid);
3085 sdp_set_browse_groups(&record, root);
3087 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3088 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3090 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3091 proto = sdp_list_append(proto, sdp_list_append(
3092 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3094 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3096 sdp_uuid128_create(&svclass_uuid, (void *) hotsync_uuid);
3097 svclass = sdp_list_append(NULL, &svclass_uuid);
3098 sdp_set_service_classes(&record, svclass);
3100 sdp_set_info_attr(&record, "PalmOS HotSync", NULL, NULL);
3102 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3103 printf("Service Record registration failed\n");
3107 printf("HotSync service record registered\n");
3112 static unsigned char palmos_uuid[] = { 0xF5, 0xBE, 0xB6, 0x51, 0x41, 0x71, 0x40, 0x51,
3113 0xAC, 0xF5, 0x6C, 0xA7, 0x20, 0x22, 0x42, 0xF0 };
3115 static int add_palmos(sdp_session_t *session, svc_info_t *si)
3117 sdp_record_t record;
3118 sdp_list_t *root, *svclass;
3119 uuid_t root_uuid, svclass_uuid;
3121 memset(&record, 0, sizeof(record));
3122 record.handle = si->handle;
3124 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3125 root = sdp_list_append(NULL, &root_uuid);
3126 sdp_set_browse_groups(&record, root);
3128 sdp_uuid128_create(&svclass_uuid, (void *) palmos_uuid);
3129 svclass = sdp_list_append(NULL, &svclass_uuid);
3130 sdp_set_service_classes(&record, svclass);
3132 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3133 printf("Service Record registration failed\n");
3137 printf("PalmOS service record registered\n");
3142 static unsigned char nokid_uuid[] = { 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x10, 0x00,
3143 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3145 static int add_nokiaid(sdp_session_t *session, svc_info_t *si)
3147 sdp_record_t record;
3148 sdp_list_t *root, *svclass;
3149 uuid_t root_uuid, svclass_uuid;
3150 uint16_t verid = 0x005f;
3151 sdp_data_t *version = sdp_data_alloc(SDP_UINT16, &verid);
3153 memset(&record, 0, sizeof(record));
3154 record.handle = si->handle;
3156 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3157 root = sdp_list_append(NULL, &root_uuid);
3158 sdp_set_browse_groups(&record, root);
3160 sdp_uuid128_create(&svclass_uuid, (void *) nokid_uuid);
3161 svclass = sdp_list_append(NULL, &svclass_uuid);
3162 sdp_set_service_classes(&record, svclass);
3164 sdp_attr_add(&record, SDP_ATTR_SERVICE_VERSION, version);
3166 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3167 printf("Service Record registration failed\n");
3168 sdp_data_free(version);
3172 printf("Nokia ID service record registered\n");
3177 static unsigned char pcsuite_uuid[] = { 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x10, 0x00,
3178 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3180 static int add_pcsuite(sdp_session_t *session, svc_info_t *si)
3182 sdp_record_t record;
3183 sdp_list_t *root, *svclass, *proto;
3184 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3185 uint8_t channel = si->channel ? si->channel: 14;
3187 memset(&record, 0, sizeof(record));
3188 record.handle = si->handle;
3190 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3191 root = sdp_list_append(NULL, &root_uuid);
3192 sdp_set_browse_groups(&record, root);
3194 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3195 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3197 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3198 proto = sdp_list_append(proto, sdp_list_append(
3199 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3201 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3203 sdp_uuid128_create(&svclass_uuid, (void *) pcsuite_uuid);
3204 svclass = sdp_list_append(NULL, &svclass_uuid);
3205 sdp_set_service_classes(&record, svclass);
3207 sdp_set_info_attr(&record, "Nokia PC Suite", NULL, NULL);
3209 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3210 printf("Service Record registration failed\n");
3214 printf("Nokia PC Suite service registered\n");
3219 static unsigned char nftp_uuid[] = { 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x10, 0x00,
3220 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3222 static unsigned char nsyncml_uuid[] = { 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x10, 0x00,
3223 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3225 static unsigned char ngage_uuid[] = { 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x10, 0x00,
3226 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3228 static unsigned char apple_uuid[] = { 0xf0, 0x72, 0x2e, 0x20, 0x0f, 0x8b, 0x4e, 0x90,
3229 0x8c, 0xc2, 0x1b, 0x46, 0xf5, 0xf2, 0xef, 0xe2 };
3231 static int add_apple(sdp_session_t *session, svc_info_t *si)
3233 sdp_record_t record;
3236 uint32_t attr783 = 0x00000000;
3237 uint32_t attr785 = 0x00000002;
3238 uint16_t attr786 = 0x1234;
3240 memset(&record, 0, sizeof(record));
3241 record.handle = si->handle;
3243 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3244 root = sdp_list_append(NULL, &root_uuid);
3245 sdp_set_browse_groups(&record, root);
3247 sdp_attr_add_new(&record, 0x0780, SDP_UUID128, (void *) apple_uuid);
3248 sdp_attr_add_new(&record, 0x0781, SDP_TEXT_STR8, (void *) "Macmini");
3249 sdp_attr_add_new(&record, 0x0782, SDP_TEXT_STR8, (void *) "PowerMac10,1");
3250 sdp_attr_add_new(&record, 0x0783, SDP_UINT32, (void *) &attr783);
3251 sdp_attr_add_new(&record, 0x0784, SDP_TEXT_STR8, (void *) "1.6.6f22");
3252 sdp_attr_add_new(&record, 0x0785, SDP_UINT32, (void *) &attr785);
3253 sdp_attr_add_new(&record, 0x0786, SDP_UUID16, (void *) &attr786);
3255 sdp_set_info_attr(&record, "Apple Macintosh Attributes", NULL, NULL);
3257 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3258 printf("Service Record registration failed\n");
3262 printf("Apple attribute service registered\n");
3267 static int add_isync(sdp_session_t *session, svc_info_t *si)
3269 sdp_record_t record;
3270 sdp_list_t *root, *svclass, *proto;
3271 uuid_t root_uuid, svclass_uuid, serial_uuid, l2cap_uuid, rfcomm_uuid;
3272 uint8_t channel = si->channel ? si->channel : 16;
3274 memset(&record, 0, sizeof(record));
3275 record.handle = si->handle;
3277 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3278 root = sdp_list_append(NULL, &root_uuid);
3279 sdp_set_browse_groups(&record, root);
3281 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3282 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3284 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3285 proto = sdp_list_append(proto, sdp_list_append(
3286 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3288 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3290 sdp_uuid16_create(&serial_uuid, SERIAL_PORT_SVCLASS_ID);
3291 svclass = sdp_list_append(NULL, &serial_uuid);
3293 sdp_uuid16_create(&svclass_uuid, APPLE_AGENT_SVCLASS_ID);
3294 svclass = sdp_list_append(svclass, &svclass_uuid);
3296 sdp_set_service_classes(&record, svclass);
3298 sdp_set_info_attr(&record, "AppleAgent", "Bluetooth acceptor", "Apple Computer Ltd.");
3300 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3301 printf("Service Record registration failed\n");
3305 printf("Apple iSync service registered\n");
3310 static int add_semchla(sdp_session_t *session, svc_info_t *si)
3312 sdp_record_t record;
3313 sdp_profile_desc_t profile;
3314 sdp_list_t *root, *svclass, *proto, *profiles;
3315 uuid_t root_uuid, service_uuid, l2cap_uuid, semchla_uuid;
3316 uint16_t psm = 0xf0f9;
3318 memset(&record, 0, sizeof(record));
3319 record.handle = si->handle;
3321 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3322 root = sdp_list_append(NULL, &root_uuid);
3323 sdp_set_browse_groups(&record, root);
3325 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3326 proto = sdp_list_append(NULL, sdp_list_append(
3327 sdp_list_append(NULL, &l2cap_uuid), sdp_data_alloc(SDP_UINT16, &psm)));
3329 sdp_uuid32_create(&semchla_uuid, 0x8e770300);
3330 proto = sdp_list_append(proto, sdp_list_append(NULL, &semchla_uuid));
3332 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3334 sdp_uuid32_create(&service_uuid, 0x8e771301);
3335 svclass = sdp_list_append(NULL, &service_uuid);
3337 sdp_set_service_classes(&record, svclass);
3339 sdp_uuid32_create(&profile.uuid, 0x8e771302); // Headset
3340 //sdp_uuid32_create(&profile.uuid, 0x8e771303); // Phone
3341 profile.version = 0x0100;
3342 profiles = sdp_list_append(NULL, &profile);
3343 sdp_set_profile_descs(&record, profiles);
3345 sdp_set_info_attr(&record, "SEMC HLA", NULL, NULL);
3347 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3348 printf("Service Record registration failed\n");
3352 /* SEMC High Level Authentication */
3353 printf("SEMC HLA service registered\n");
3361 int (*add)(sdp_session_t *sess, svc_info_t *si);
3362 unsigned char *uuid;
3364 { "DID", PNP_INFO_SVCLASS_ID, NULL, },
3366 { "SP", SERIAL_PORT_SVCLASS_ID, add_sp },
3367 { "DUN", DIALUP_NET_SVCLASS_ID, add_dun },
3368 { "LAN", LAN_ACCESS_SVCLASS_ID, add_lan },
3369 { "FAX", FAX_SVCLASS_ID, add_fax },
3370 { "OPUSH", OBEX_OBJPUSH_SVCLASS_ID, add_opush },
3371 { "FTP", OBEX_FILETRANS_SVCLASS_ID, add_ftp },
3372 { "PRINT", DIRECT_PRINTING_SVCLASS_ID, add_directprint },
3374 { "HS", HEADSET_SVCLASS_ID, add_headset },
3375 { "HSAG", HEADSET_AGW_SVCLASS_ID, add_headset_ag},
3376 { "HF", HANDSFREE_SVCLASS_ID, add_handsfree },
3377 { "HFAG", HANDSFREE_AGW_SVCLASS_ID, add_handsfree_ag},
3378 { "SAP", SAP_SVCLASS_ID, add_simaccess },
3380 { "NAP", NAP_SVCLASS_ID, add_nap },
3381 { "GN", GN_SVCLASS_ID, add_gn },
3382 { "PANU", PANU_SVCLASS_ID, add_panu },
3384 { "HCRP", HCR_SVCLASS_ID, NULL },
3385 { "HID", HID_SVCLASS_ID, NULL },
3386 { "KEYB", HID_SVCLASS_ID, add_hid_keyb },
3387 { "WIIMOTE", HID_SVCLASS_ID, add_hid_wiimote },
3388 { "CIP", CIP_SVCLASS_ID, add_cip },
3389 { "CTP", CORDLESS_TELEPHONY_SVCLASS_ID, add_ctp },
3391 { "A2SRC", AUDIO_SOURCE_SVCLASS_ID, add_a2source },
3392 { "A2SNK", AUDIO_SINK_SVCLASS_ID, add_a2sink },
3393 { "AVRCT", AV_REMOTE_SVCLASS_ID, add_avrct },
3394 { "AVRTG", AV_REMOTE_TARGET_SVCLASS_ID, add_avrtg },
3396 { "UDIUE", UDI_MT_SVCLASS_ID, add_udi_ue },
3397 { "UDITE", UDI_TA_SVCLASS_ID, add_udi_te },
3399 { "SEMCHLA", 0x8e771301, add_semchla },
3401 { "SR1", 0, add_sr1, sr1_uuid },
3402 { "SYNCML", 0, add_syncml, syncmlc_uuid },
3403 { "SYNCMLSERV", 0, NULL, syncmls_uuid },
3404 { "ACTIVESYNC", 0, add_activesync, async_uuid },
3405 { "HOTSYNC", 0, add_hotsync, hotsync_uuid },
3406 { "PALMOS", 0, add_palmos, palmos_uuid },
3407 { "NOKID", 0, add_nokiaid, nokid_uuid },
3408 { "PCSUITE", 0, add_pcsuite, pcsuite_uuid },
3409 { "NFTP", 0, NULL, nftp_uuid },
3410 { "NSYNCML", 0, NULL, nsyncml_uuid },
3411 { "NGAGE", 0, NULL, ngage_uuid },
3412 { "APPLE", 0, add_apple, apple_uuid },
3414 { "ISYNC", APPLE_AGENT_SVCLASS_ID, add_isync, },
3419 /* Add local service */
3420 static int add_service(bdaddr_t *bdaddr, svc_info_t *si)
3422 sdp_session_t *sess;
3428 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
3432 for (i = 0; service[i].name; i++)
3433 if (!strcasecmp(service[i].name, si->name)) {
3435 ret = service[i].add(sess, si);
3439 printf("Unknown service name: %s\n", si->name);
3448 static struct option add_options[] = {
3449 { "help", 0, 0, 'h' },
3450 { "handle", 1, 0, 'r' },
3451 { "psm", 1, 0, 'p' },
3452 { "channel", 1, 0, 'c' },
3453 { "network", 1, 0, 'n' },
3457 static char *add_help =
3459 "\tadd [--handle=RECORD_HANDLE --channel=CHANNEL] service\n";
3461 static int cmd_add(int argc, char **argv)
3466 memset(&si, 0, sizeof(si));
3467 si.handle = 0xffffffff;
3469 for_each_opt(opt, add_options, 0) {
3472 if (strncasecmp(optarg, "0x", 2))
3473 si.handle = atoi(optarg);
3475 si.handle = strtol(optarg + 2, NULL, 16);
3478 if (strncasecmp(optarg, "0x", 2))
3479 si.psm = atoi(optarg);
3481 si.psm = strtol(optarg + 2, NULL, 16);
3484 if (strncasecmp(optarg, "0x", 2))
3485 si.channel = atoi(optarg);
3487 si.channel = strtol(optarg + 2, NULL, 16);
3490 if (strncasecmp(optarg, "0x", 2))
3491 si.network = atoi(optarg);
3493 si.network = strtol(optarg + 2, NULL, 16);
3509 si.name = strdup(argv[0]);
3511 return add_service(0, &si);
3514 /* Delete local service */
3515 static int del_service(bdaddr_t *bdaddr, void *arg)
3517 uint32_t handle, range = 0x0000ffff;
3519 sdp_session_t *sess;
3523 printf("Record handle was not specified.\n");
3527 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
3529 printf("No local SDP server!\n");
3533 handle = strtoul((char *)arg, 0, 16);
3534 attr = sdp_list_append(0, &range);
3535 rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attr);
3536 sdp_list_free(attr, 0);
3539 printf("Service Record not found.\n");
3544 if (sdp_device_record_unregister(sess, &interface, rec)) {
3545 printf("Failed to unregister service record: %s\n", strerror(errno));
3550 printf("Service Record deleted.\n");
3556 static struct option del_options[] = {
3557 { "help", 0, 0, 'h' },
3561 static char *del_help =
3563 "\tdel record_handle\n";
3565 static int cmd_del(int argc, char **argv)
3569 for_each_opt(opt, del_options, 0) {
3585 return del_service(NULL, argv[0]);
3589 * Perform an inquiry and search/browse all peer found.
3591 static void inquiry(handler_t handler, void *arg)
3593 inquiry_info ii[20];
3597 printf("Inquiring ...\n");
3598 if (sdp_general_inquiry(ii, 20, 8, &count) < 0) {
3599 printf("Inquiry failed\n");
3603 for (i = 0; i < count; i++)
3604 handler(&ii[i].bdaddr, arg);
3607 static void doprintf(void *data, const char *str)
3613 * Search for a specific SDP service
3615 static int do_search(bdaddr_t *bdaddr, struct search_context *context)
3617 sdp_list_t *attrid, *search, *seq, *next;
3618 uint32_t range = 0x0000ffff;
3620 sdp_session_t *sess;
3623 inquiry(do_search, context);
3627 sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
3628 ba2str(bdaddr, str);
3630 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
3634 if (context->view != RAW_VIEW) {
3636 printf("Searching for %s on %s ...\n", context->svc, str);
3638 printf("Browsing %s ...\n", str);
3641 attrid = sdp_list_append(0, &range);
3642 search = sdp_list_append(0, &context->group);
3643 if (sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq)) {
3644 printf("Service Search failed: %s\n", strerror(errno));
3648 sdp_list_free(attrid, 0);
3649 sdp_list_free(search, 0);
3651 for (; seq; seq = next) {
3652 sdp_record_t *rec = (sdp_record_t *) seq->data;
3653 struct search_context sub_context;
3655 switch (context->view) {
3657 /* Display user friendly form */
3658 print_service_attr(rec);
3662 /* Display full tree */
3663 print_tree_attr(rec);
3667 /* Display raw XML tree */
3668 convert_sdp_record_to_xml(rec, 0, doprintf);
3671 /* Display raw tree */
3672 print_raw_attr(rec);
3676 if (sdp_get_group_id(rec, &sub_context.group) != -1) {
3677 /* Set the subcontext for browsing the sub tree */
3678 memcpy(&sub_context, context, sizeof(struct search_context));
3679 /* Browse the next level down if not done */
3680 if (sub_context.group.value.uuid16 != context->group.value.uuid16)
3681 do_search(bdaddr, &sub_context);
3685 sdp_record_free(rec);
3692 static struct option browse_options[] = {
3693 { "help", 0, 0, 'h' },
3694 { "tree", 0, 0, 't' },
3695 { "raw", 0, 0, 'r' },
3696 { "xml", 0, 0, 'x' },
3697 { "uuid", 1, 0, 'u' },
3698 { "l2cap", 0, 0, 'l' },
3702 static char *browse_help =
3704 "\tbrowse [--tree] [--raw] [--xml] [--uuid uuid] [--l2cap] [bdaddr]\n";
3707 * Browse the full SDP database (i.e. list all services starting from the
3710 static int cmd_browse(int argc, char **argv)
3712 struct search_context context;
3715 /* Initialise context */
3716 memset(&context, '\0', sizeof(struct search_context));
3717 /* We want to browse the top-level/root */
3718 sdp_uuid16_create(&context.group, PUBLIC_BROWSE_GROUP);
3720 for_each_opt(opt, browse_options, 0) {
3723 context.view = TREE_VIEW;
3726 context.view = RAW_VIEW;
3729 context.view = XML_VIEW;
3732 if (sscanf(optarg, "%i", &num) != 1 || num < 0 || num > 0xffff) {
3733 printf("Invalid uuid %s\n", optarg);
3736 sdp_uuid16_create(&context.group, num);
3739 sdp_uuid16_create(&context.group, L2CAP_UUID);
3742 printf(browse_help);
3752 estr2ba(argv[0], &bdaddr);
3753 return do_search(&bdaddr, &context);
3756 return do_search(NULL, &context);
3759 static struct option search_options[] = {
3760 { "help", 0, 0, 'h' },
3761 { "bdaddr", 1, 0, 'b' },
3762 { "tree", 0, 0, 't' },
3763 { "raw", 0, 0, 'r' },
3764 { "xml", 0, 0, 'x' },
3768 static char *search_help =
3770 "\tsearch [--bdaddr bdaddr] [--tree] [--raw] [--xml] SERVICE\n"
3771 "SERVICE is a name (string) or UUID (0x1002)\n";
3774 * Search for a specific SDP service
3776 * Note : we should support multiple services on the command line :
3777 * sdptool search 0x0100 0x000f 0x1002
3778 * (this would search a service supporting both L2CAP and BNEP directly in
3779 * the top level browse group)
3781 static int cmd_search(int argc, char **argv)
3783 struct search_context context;
3784 unsigned char *uuid = NULL;
3791 /* Initialise context */
3792 memset(&context, '\0', sizeof(struct search_context));
3794 for_each_opt(opt, search_options, 0) {
3797 estr2ba(optarg, &bdaddr);
3801 context.view = TREE_VIEW;
3804 context.view = RAW_VIEW;
3807 context.view = XML_VIEW;
3810 printf(search_help);
3819 printf(search_help);
3823 /* Note : we need to find a way to support search combining
3824 * multiple services */
3825 context.svc = strdup(argv[0]);
3826 if (!strncasecmp(context.svc, "0x", 2)) {
3828 /* This is a UUID16, just convert to int */
3829 sscanf(context.svc + 2, "%X", &num);
3831 printf("Class 0x%X\n", class);
3833 /* Convert class name to an UUID */
3835 for (i = 0; service[i].name; i++)
3836 if (strcasecmp(context.svc, service[i].name) == 0) {
3837 class = service[i].class;
3838 uuid = service[i].uuid;
3841 if (!class && !uuid) {
3842 printf("Unknown service %s\n", context.svc);
3848 if (class & 0xffff0000)
3849 sdp_uuid32_create(&context.group, class);
3851 uint16_t class16 = class & 0xffff;
3852 sdp_uuid16_create(&context.group, class16);
3855 sdp_uuid128_create(&context.group, uuid);
3858 return do_search(&bdaddr, &context);
3860 return do_search(NULL, &context);
3864 * Show how to get a specific SDP record by its handle.
3865 * Not really useful to the user, just show how it can be done...
3867 static int get_service(bdaddr_t *bdaddr, struct search_context *context, int quite)
3870 uint32_t range = 0x0000ffff;
3872 sdp_session_t *session = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
3876 ba2str(bdaddr, str);
3877 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
3881 attrid = sdp_list_append(0, &range);
3882 rec = sdp_service_attr_req(session, context->handle, SDP_ATTR_REQ_RANGE, attrid);
3883 sdp_list_free(attrid, 0);
3888 printf("Service get request failed.\n");
3894 switch (context->view) {
3896 /* Display user friendly form */
3897 print_service_attr(rec);
3901 /* Display full tree */
3902 print_tree_attr(rec);
3906 /* Display raw XML tree */
3907 convert_sdp_record_to_xml(rec, 0, doprintf);
3910 /* Display raw tree */
3911 print_raw_attr(rec);
3915 sdp_record_free(rec);
3919 static struct option records_options[] = {
3920 { "help", 0, 0, 'h' },
3921 { "tree", 0, 0, 't' },
3922 { "raw", 0, 0, 'r' },
3923 { "xml", 0, 0, 'x' },
3927 static char *records_help =
3929 "\trecords [--tree] [--raw] [--xml] bdaddr\n";
3932 * Request possible SDP service records
3934 static int cmd_records(int argc, char **argv)
3936 struct search_context context;
3937 uint32_t base[] = { 0x10000, 0x10300, 0x10500,
3938 0x1002e, 0x110b, 0x90000, 0x2008000,
3939 0x4000000, 0x100000, 0x1000000, 0x4f491100 };
3941 int i, n, opt, err = 0, num = 32;
3943 /* Initialise context */
3944 memset(&context, '\0', sizeof(struct search_context));
3946 for_each_opt(opt, records_options, 0) {
3949 context.view = TREE_VIEW;
3952 context.view = RAW_VIEW;
3955 context.view = XML_VIEW;
3958 printf(records_help);
3967 printf(records_help);
3971 /* Convert command line parameters */
3972 estr2ba(argv[0], &bdaddr);
3974 for (i = 0; i < sizeof(base) / sizeof(uint32_t); i++)
3975 for (n = 0; n < num; n++) {
3976 context.handle = base[i] + n;
3977 err = get_service(&bdaddr, &context, 1);
3986 static struct option get_options[] = {
3987 { "help", 0, 0, 'h' },
3988 { "bdaddr", 1, 0, 'b' },
3989 { "tree", 0, 0, 't' },
3990 { "raw", 0, 0, 'r' },
3991 { "xml", 0, 0, 'x' },
3995 static char *get_help =
3997 "\tget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\n";
4000 * Get a specific SDP record on the local SDP server
4002 static int cmd_get(int argc, char **argv)
4004 struct search_context context;
4009 /* Initialise context */
4010 memset(&context, '\0', sizeof(struct search_context));
4012 for_each_opt(opt, get_options, 0) {
4015 estr2ba(optarg, &bdaddr);
4019 context.view = TREE_VIEW;
4022 context.view = RAW_VIEW;
4025 context.view = XML_VIEW;
4041 /* Convert command line parameters */
4042 context.handle = strtoul(argv[0], 0, 16);
4044 return get_service(has_addr ? &bdaddr : BDADDR_LOCAL, &context, 0);
4049 int (*func)(int argc, char **argv);
4052 { "search", cmd_search, "Search for a service" },
4053 { "browse", cmd_browse, "Browse all available services" },
4054 { "records", cmd_records, "Request all records" },
4055 { "add", cmd_add, "Add local service" },
4056 { "del", cmd_del, "Delete local service" },
4057 { "get", cmd_get, "Get local service" },
4058 { "setattr", cmd_setattr, "Set/Add attribute to a SDP record" },
4059 { "setseq", cmd_setseq, "Set/Add attribute sequence to a SDP record" },
4063 static void usage(void)
4067 printf("sdptool - SDP tool v%s\n", VERSION);
4069 "\tsdptool [options] <command> [command parameters]\n");
4071 "\t-h\t\tDisplay help\n"
4072 "\t-i\t\tSpecify source interface\n");
4074 printf("Commands:\n");
4075 for (i = 0; command[i].cmd; i++)
4076 printf("\t%-4s\t\t%s\n", command[i].cmd, command[i].doc);
4078 printf("\nServices:\n\t");
4079 for (i = 0; service[i].name; i++) {
4080 printf("%s ", service[i].name);
4081 pos += strlen(service[i].name) + 1;
4090 static struct option main_options[] = {
4091 { "help", 0, 0, 'h' },
4092 { "device", 1, 0, 'i' },
4096 int main(int argc, char *argv[])
4100 bacpy(&interface, BDADDR_ANY);
4102 while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
4105 if (!strncmp(optarg, "hci", 3))
4106 hci_devba(atoi(optarg + 3), &interface);
4108 str2ba(optarg, &interface);
4129 for (i = 0; command[i].cmd; i++)
4130 if (strncmp(command[i].cmd, argv[0], 4) == 0)
4131 return command[i].func(argc, argv);