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-2010 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>
48 #include "src/sdp-xml.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)
55 #define N_ELEMENTS(x) (sizeof(x) / sizeof((x)[0]))
58 * Convert a string to a BDADDR, with a few "enhancements" - Jean II
60 static int estr2ba(char *str, bdaddr_t *ba)
62 /* Only trap "local", "any" is already dealt with */
63 if(!strcmp(str, "local")) {
64 bacpy(ba, BDADDR_LOCAL);
67 return str2ba(str, ba);
70 #define DEFAULT_VIEW 0 /* Display only known attribute */
71 #define TREE_VIEW 1 /* Display full attribute tree */
72 #define RAW_VIEW 2 /* Display raw tree */
73 #define XML_VIEW 3 /* Display xml tree */
75 /* Pass args to the inquiry/search handler */
76 struct search_context {
77 char *svc; /* Service */
78 uuid_t group; /* Browse group */
79 int view; /* View mode */
80 uint32_t handle; /* Service record handle */
83 typedef int (*handler_t)(bdaddr_t *bdaddr, struct search_context *arg);
85 static char UUID_str[MAX_LEN_UUID_STR];
86 static bdaddr_t interface;
88 /* Definition of attribute members */
93 /* Definition of an attribute */
95 int num; /* Numeric ID - 16 bits */
96 char *name; /* User readable name */
97 struct member_def *members; /* Definition of attribute args */
98 int member_max; /* Max of attribute arg definitions */
101 /* Definition of a service or protocol */
103 int num; /* Numeric ID - 16 bits */
104 char *name; /* User readable name */
105 struct attrib_def *attribs; /* Specific attribute definitions */
106 int attrib_max; /* Max of attribute definitions */
109 /* Context information about current attribute */
110 struct attrib_context {
111 struct uuid_def *service; /* Service UUID, if known */
112 struct attrib_def *attrib; /* Description of the attribute */
113 int member_index; /* Index of current attribute member */
116 /* Context information about the whole service */
117 struct service_context {
118 struct uuid_def *service; /* Service UUID, if known */
121 /* Allow us to do nice formatting of the lists */
122 static char *indent_spaces = " ";
124 /* ID of the service attribute.
125 * Most attributes after 0x200 are defined based on the service, so
126 * we need to find what is the service (which is messy) - Jean II */
127 #define SERVICE_ATTR 0x1
129 /* Definition of the optional arguments in protocol list */
130 static struct member_def protocol_members[] = {
136 /* Definition of the optional arguments in profile list */
137 static struct member_def profile_members[] = {
142 /* Definition of the optional arguments in Language list */
143 static struct member_def language_members[] = {
149 /* Name of the various common attributes. See BT assigned numbers */
150 static struct attrib_def attrib_names[] = {
151 { 0x0, "ServiceRecordHandle", NULL, 0 },
152 { 0x1, "ServiceClassIDList", NULL, 0 },
153 { 0x2, "ServiceRecordState", NULL, 0 },
154 { 0x3, "ServiceID", NULL, 0 },
155 { 0x4, "ProtocolDescriptorList",
156 protocol_members, N_ELEMENTS(protocol_members) },
157 { 0x5, "BrowseGroupList", NULL, 0 },
158 { 0x6, "LanguageBaseAttributeIDList",
159 language_members, N_ELEMENTS(language_members) },
160 { 0x7, "ServiceInfoTimeToLive", NULL, 0 },
161 { 0x8, "ServiceAvailability", NULL, 0 },
162 { 0x9, "BluetoothProfileDescriptorList",
163 profile_members, N_ELEMENTS(profile_members) },
164 { 0xA, "DocumentationURL", NULL, 0 },
165 { 0xB, "ClientExecutableURL", NULL, 0 },
166 { 0xC, "IconURL", NULL, 0 },
167 { 0xD, "AdditionalProtocolDescriptorLists", NULL, 0 },
168 /* Definitions after that are tricky (per profile or offset) */
171 const int attrib_max = N_ELEMENTS(attrib_names);
173 /* Name of the various SPD attributes. See BT assigned numbers */
174 static struct attrib_def sdp_attrib_names[] = {
175 { 0x200, "VersionNumberList", NULL, 0 },
176 { 0x201, "ServiceDatabaseState", NULL, 0 },
179 /* Name of the various SPD attributes. See BT assigned numbers */
180 static struct attrib_def browse_attrib_names[] = {
181 { 0x200, "GroupID", NULL, 0 },
184 /* Name of the various Device ID attributes. See Device Id spec. */
185 static struct attrib_def did_attrib_names[] = {
186 { 0x200, "SpecificationID", NULL, 0 },
187 { 0x201, "VendorID", NULL, 0 },
188 { 0x202, "ProductID", NULL, 0 },
189 { 0x203, "Version", NULL, 0 },
190 { 0x204, "PrimaryRecord", NULL, 0 },
191 { 0x205, "VendorIDSource", NULL, 0 },
194 /* Name of the various HID attributes. See HID spec. */
195 static struct attrib_def hid_attrib_names[] = {
196 { 0x200, "DeviceReleaseNum", NULL, 0 },
197 { 0x201, "ParserVersion", NULL, 0 },
198 { 0x202, "DeviceSubclass", NULL, 0 },
199 { 0x203, "CountryCode", NULL, 0 },
200 { 0x204, "VirtualCable", NULL, 0 },
201 { 0x205, "ReconnectInitiate", NULL, 0 },
202 { 0x206, "DescriptorList", NULL, 0 },
203 { 0x207, "LangIDBaseList", NULL, 0 },
204 { 0x208, "SDPDisable", NULL, 0 },
205 { 0x209, "BatteryPower", NULL, 0 },
206 { 0x20a, "RemoteWakeup", NULL, 0 },
207 { 0x20b, "ProfileVersion", NULL, 0 },
208 { 0x20c, "SupervisionTimeout", NULL, 0 },
209 { 0x20d, "NormallyConnectable", NULL, 0 },
210 { 0x20e, "BootDevice", NULL, 0 },
213 /* Name of the various PAN attributes. See BT assigned numbers */
214 /* Note : those need to be double checked - Jean II */
215 static struct attrib_def pan_attrib_names[] = {
216 { 0x200, "IpSubnet", NULL, 0 }, /* Obsolete ??? */
217 { 0x30A, "SecurityDescription", NULL, 0 },
218 { 0x30B, "NetAccessType", NULL, 0 },
219 { 0x30C, "MaxNetAccessrate", NULL, 0 },
220 { 0x30D, "IPv4Subnet", NULL, 0 },
221 { 0x30E, "IPv6Subnet", NULL, 0 },
224 /* Name of the various Generic-Audio attributes. See BT assigned numbers */
225 /* Note : totally untested - Jean II */
226 static struct attrib_def audio_attrib_names[] = {
227 { 0x302, "Remote audio volume control", NULL, 0 },
230 /* Name of the various GOEP attributes. See BT assigned numbers */
231 static struct attrib_def goep_attrib_names[] = {
232 { 0x200, "GoepL2capPsm", NULL, 0 },
235 /* Name of the various MAS attributes. See BT assigned numbers */
236 static struct attrib_def mas_attrib_names[] = {
237 { 0x0315, "MASInstanceID", NULL, 0 },
238 { 0x0316, "SupportedMessageTypes", NULL, 0 },
241 /* Same for the UUIDs. See BT assigned numbers */
242 static struct uuid_def uuid16_names[] = {
243 /* -- Protocols -- */
244 { 0x0001, "SDP", NULL, 0 },
245 { 0x0002, "UDP", NULL, 0 },
246 { 0x0003, "RFCOMM", NULL, 0 },
247 { 0x0004, "TCP", NULL, 0 },
248 { 0x0005, "TCS-BIN", NULL, 0 },
249 { 0x0006, "TCS-AT", NULL, 0 },
250 { 0x0008, "OBEX", NULL, 0 },
251 { 0x0009, "IP", NULL, 0 },
252 { 0x000a, "FTP", NULL, 0 },
253 { 0x000c, "HTTP", NULL, 0 },
254 { 0x000e, "WSP", NULL, 0 },
255 { 0x000f, "BNEP", NULL, 0 },
256 { 0x0010, "UPnP/ESDP", NULL, 0 },
257 { 0x0011, "HIDP", NULL, 0 },
258 { 0x0012, "HardcopyControlChannel", NULL, 0 },
259 { 0x0014, "HardcopyDataChannel", NULL, 0 },
260 { 0x0016, "HardcopyNotification", NULL, 0 },
261 { 0x0017, "AVCTP", NULL, 0 },
262 { 0x0019, "AVDTP", NULL, 0 },
263 { 0x001b, "CMTP", NULL, 0 },
264 { 0x001d, "UDI_C-Plane", NULL, 0 },
265 { 0x0100, "L2CAP", NULL, 0 },
267 { 0x1000, "ServiceDiscoveryServerServiceClassID",
268 sdp_attrib_names, N_ELEMENTS(sdp_attrib_names) },
269 { 0x1001, "BrowseGroupDescriptorServiceClassID",
270 browse_attrib_names, N_ELEMENTS(browse_attrib_names) },
271 { 0x1002, "PublicBrowseGroup", NULL, 0 },
272 { 0x1101, "SerialPort", NULL, 0 },
273 { 0x1102, "LANAccessUsingPPP", NULL, 0 },
274 { 0x1103, "DialupNetworking (DUN)", NULL, 0 },
275 { 0x1104, "IrMCSync", NULL, 0 },
276 { 0x1105, "OBEXObjectPush",
277 goep_attrib_names, N_ELEMENTS(goep_attrib_names) },
278 { 0x1106, "OBEXFileTransfer",
279 goep_attrib_names, N_ELEMENTS(goep_attrib_names) },
280 { 0x1107, "IrMCSyncCommand", NULL, 0 },
282 audio_attrib_names, N_ELEMENTS(audio_attrib_names) },
283 { 0x1109, "CordlessTelephony", NULL, 0 },
284 { 0x110a, "AudioSource", NULL, 0 },
285 { 0x110b, "AudioSink", NULL, 0 },
286 { 0x110c, "RemoteControlTarget", NULL, 0 },
287 { 0x110d, "AdvancedAudio", NULL, 0 },
288 { 0x110e, "RemoteControl", NULL, 0 },
289 { 0x110f, "RemoteControlController", NULL, 0 },
290 { 0x1110, "Intercom", NULL, 0 },
291 { 0x1111, "Fax", NULL, 0 },
292 { 0x1112, "HeadsetAudioGateway", NULL, 0 },
293 { 0x1113, "WAP", NULL, 0 },
294 { 0x1114, "WAP Client", NULL, 0 },
295 { 0x1115, "PANU (PAN/BNEP)",
296 pan_attrib_names, N_ELEMENTS(pan_attrib_names) },
297 { 0x1116, "NAP (PAN/BNEP)",
298 pan_attrib_names, N_ELEMENTS(pan_attrib_names) },
299 { 0x1117, "GN (PAN/BNEP)",
300 pan_attrib_names, N_ELEMENTS(pan_attrib_names) },
301 { 0x1118, "DirectPrinting (BPP)", NULL, 0 },
302 { 0x1119, "ReferencePrinting (BPP)", NULL, 0 },
303 { 0x111a, "Imaging (BIP)", NULL, 0 },
304 { 0x111b, "ImagingResponder (BIP)", NULL, 0 },
305 { 0x111c, "ImagingAutomaticArchive (BIP)", NULL, 0 },
306 { 0x111d, "ImagingReferencedObjects (BIP)", NULL, 0 },
307 { 0x111e, "Handsfree", NULL, 0 },
308 { 0x111f, "HandsfreeAudioGateway", NULL, 0 },
309 { 0x1120, "DirectPrintingReferenceObjectsService (BPP)", NULL, 0 },
310 { 0x1121, "ReflectedUI (BPP)", NULL, 0 },
311 { 0x1122, "BasicPrinting (BPP)", NULL, 0 },
312 { 0x1123, "PrintingStatus (BPP)", NULL, 0 },
313 { 0x1124, "HumanInterfaceDeviceService (HID)",
314 hid_attrib_names, N_ELEMENTS(hid_attrib_names) },
315 { 0x1125, "HardcopyCableReplacement (HCR)", NULL, 0 },
316 { 0x1126, "HCR_Print (HCR)", NULL, 0 },
317 { 0x1127, "HCR_Scan (HCR)", NULL, 0 },
318 { 0x1128, "Common ISDN Access (CIP)", NULL, 0 },
319 { 0x112a, "UDI-MT", NULL, 0 },
320 { 0x112b, "UDI-TA", NULL, 0 },
321 { 0x112c, "Audio/Video", NULL, 0 },
322 { 0x112d, "SIM Access (SAP)", NULL, 0 },
323 { 0x112e, "Phonebook Access (PBAP) - PCE", NULL, 0 },
324 { 0x112f, "Phonebook Access (PBAP) - PSE", NULL, 0 },
325 { 0x1130, "Phonebook Access (PBAP)", NULL, 0 },
326 { 0x1131, "Headset (HSP)", NULL, 0 },
327 { 0x1132, "Message Access (MAP) - MAS",
328 mas_attrib_names, N_ELEMENTS(mas_attrib_names) },
329 { 0x1133, "Message Access (MAP) - MNS", NULL, 0 },
330 { 0x1134, "Message Access (MAP)", NULL, 0 },
332 { 0x1200, "PnPInformation",
333 did_attrib_names, N_ELEMENTS(did_attrib_names) },
334 { 0x1201, "GenericNetworking", NULL, 0 },
335 { 0x1202, "GenericFileTransfer", NULL, 0 },
336 { 0x1203, "GenericAudio",
337 audio_attrib_names, N_ELEMENTS(audio_attrib_names) },
338 { 0x1204, "GenericTelephony", NULL, 0 },
340 { 0x1303, "VideoSource", NULL, 0 },
341 { 0x1304, "VideoSink", NULL, 0 },
342 { 0x1305, "VideoDistribution", NULL, 0 },
343 { 0x1400, "HDP", NULL, 0 },
344 { 0x1401, "HDPSource", NULL, 0 },
345 { 0x1402, "HDPSink", NULL, 0 },
346 { 0x2112, "AppleAgent", NULL, 0 },
349 static const int uuid16_max = N_ELEMENTS(uuid16_names);
351 static void sdp_data_printf(sdp_data_t *, struct attrib_context *, int);
355 * The BT assigned numbers only list UUID16, so I'm not sure the
356 * other types will ever get used...
358 static void sdp_uuid_printf(uuid_t *uuid, struct attrib_context *context, int indent)
361 if (uuid->type == SDP_UUID16) {
362 uint16_t uuidNum = uuid->value.uuid16;
363 struct uuid_def *uuidDef = NULL;
366 for (i = 0; i < uuid16_max; i++)
367 if (uuid16_names[i].num == uuidNum) {
368 uuidDef = &uuid16_names[i];
372 /* Check if it's the service attribute */
373 if (context->attrib && context->attrib->num == SERVICE_ATTR) {
374 /* We got the service ID !!! */
375 context->service = uuidDef;
379 printf("%.*sUUID16 : 0x%.4x - %s\n",
380 indent, indent_spaces, uuidNum, uuidDef->name);
382 printf("%.*sUUID16 : 0x%.4x\n",
383 indent, indent_spaces, uuidNum);
384 } else if (uuid->type == SDP_UUID32) {
385 struct uuid_def *uuidDef = NULL;
388 if (!(uuid->value.uuid32 & 0xffff0000)) {
389 uint16_t uuidNum = uuid->value.uuid32;
390 for (i = 0; i < uuid16_max; i++)
391 if (uuid16_names[i].num == uuidNum) {
392 uuidDef = &uuid16_names[i];
398 printf("%.*sUUID32 : 0x%.8x - %s\n",
399 indent, indent_spaces, uuid->value.uuid32, uuidDef->name);
401 printf("%.*sUUID32 : 0x%.8x\n",
402 indent, indent_spaces, uuid->value.uuid32);
403 } else if (uuid->type == SDP_UUID128) {
405 unsigned short data1;
406 unsigned short data2;
407 unsigned short data3;
409 unsigned short data5;
411 memcpy(&data0, &uuid->value.uuid128.data[0], 4);
412 memcpy(&data1, &uuid->value.uuid128.data[4], 2);
413 memcpy(&data2, &uuid->value.uuid128.data[6], 2);
414 memcpy(&data3, &uuid->value.uuid128.data[8], 2);
415 memcpy(&data4, &uuid->value.uuid128.data[10], 4);
416 memcpy(&data5, &uuid->value.uuid128.data[14], 2);
418 printf("%.*sUUID128 : 0x%.8x-%.4x-%.4x-%.4x-%.8x-%.4x\n",
419 indent, indent_spaces,
420 ntohl(data0), ntohs(data1), ntohs(data2),
421 ntohs(data3), ntohl(data4), ntohs(data5));
423 printf("%.*sEnum type of UUID not set\n",
424 indent, indent_spaces);
426 printf("%.*sNull passed to print UUID\n",
427 indent, indent_spaces);
431 * Parse a sequence of data elements (i.e. a list)
433 static void printf_dataseq(sdp_data_t * pData, struct attrib_context *context, int indent)
435 sdp_data_t *sdpdata = NULL;
439 context->member_index = 0;
441 sdp_data_printf(sdpdata, context, indent + 2);
442 sdpdata = sdpdata->next;
443 context->member_index++;
446 printf("%.*sBroken dataseq link\n", indent, indent_spaces);
451 * Parse a single data element (either in the attribute or in a data
454 static void sdp_data_printf(sdp_data_t *sdpdata, struct attrib_context *context, int indent)
456 char *member_name = NULL;
458 /* Find member name. Almost black magic ;-) */
459 if (context && context->attrib && context->attrib->members &&
460 context->member_index < context->attrib->member_max) {
461 member_name = context->attrib->members[context->member_index].name;
464 switch (sdpdata->dtd) {
466 printf("%.*sNil\n", indent, indent_spaces);
480 printf("%.*s%s (Integer) : 0x%x\n",
481 indent, indent_spaces, member_name, sdpdata->val.uint32);
483 printf("%.*sInteger : 0x%x\n", indent, indent_spaces,
484 sdpdata->val.uint32);
491 //printf("%.*sUUID\n", indent, indent_spaces);
492 sdp_uuid_printf(&sdpdata->val.uuid, context, indent);
498 if (sdpdata->unitSize > (int) strlen(sdpdata->val.str)) {
500 printf("%.*sData :", indent, indent_spaces);
501 for (i = 0; i < sdpdata->unitSize; i++)
502 printf(" %02x", (unsigned char) sdpdata->val.str[i]);
505 printf("%.*sText : \"%s\"\n", indent, indent_spaces, sdpdata->val.str);
510 printf("%.*sURL : %s\n", indent, indent_spaces, sdpdata->val.str);
516 printf("%.*sData Sequence\n", indent, indent_spaces);
517 printf_dataseq(sdpdata->val.dataseq, context, indent);
523 printf("%.*sData Sequence Alternates\n", indent, indent_spaces);
524 printf_dataseq(sdpdata->val.dataseq, context, indent);
530 * Parse a single attribute.
532 static void print_tree_attr_func(void *value, void *userData)
534 sdp_data_t *sdpdata = value;
536 struct service_context *service = (struct service_context *) userData;
537 struct attrib_context context;
538 struct attrib_def *attrDef = NULL;
544 attrId = sdpdata->attrId;
545 /* Search amongst the generic attributes */
546 for (i = 0; i < attrib_max; i++)
547 if (attrib_names[i].num == attrId) {
548 attrDef = &attrib_names[i];
551 /* Search amongst the specific attributes of this service */
552 if ((attrDef == NULL) && (service->service != NULL) &&
553 (service->service->attribs != NULL)) {
554 struct attrib_def *svc_attribs = service->service->attribs;
555 int svc_attrib_max = service->service->attrib_max;
556 for (i = 0; i < svc_attrib_max; i++)
557 if (svc_attribs[i].num == attrId) {
558 attrDef = &svc_attribs[i];
564 printf("Attribute Identifier : 0x%x - %s\n", attrId, attrDef->name);
566 printf("Attribute Identifier : 0x%x\n", attrId);
568 context.service = service->service;
569 context.attrib = attrDef;
570 context.member_index = 0;
571 /* Parse attribute members */
572 sdp_data_printf(sdpdata, &context, 2);
574 service->service = context.service;
578 * Main entry point of this library. Parse a SDP record.
579 * We assume the record has already been read, parsed and cached
582 static void print_tree_attr(sdp_record_t *rec)
584 if (rec && rec->attrlist) {
585 struct service_context service = { NULL };
586 sdp_list_foreach(rec->attrlist, print_tree_attr_func, &service);
590 static void print_raw_data(sdp_data_t *data, int indent)
592 struct uuid_def *def;
598 for (i = 0; i < indent; i++)
606 printf("Bool %s\n", data->val.uint8 ? "True" : "False");
609 printf("UINT8 0x%02x\n", data->val.uint8);
612 printf("UINT16 0x%04x\n", data->val.uint16);
615 printf("UINT32 0x%08x\n", data->val.uint32);
618 printf("UINT64 0x%016jx\n", data->val.uint64);
621 printf("UINT128 ...\n");
624 printf("INT8 %d\n", data->val.int8);
627 printf("INT16 %d\n", data->val.int16);
630 printf("INT32 %d\n", data->val.int32);
633 printf("INT64 %jd\n", data->val.int64);
636 printf("INT128 ...\n");
641 switch (data->val.uuid.type) {
644 for (i = 0; i < uuid16_max; i++)
645 if (uuid16_names[i].num == data->val.uuid.value.uuid16) {
646 def = &uuid16_names[i];
650 printf("UUID16 0x%04x - %s\n", data->val.uuid.value.uuid16, def->name);
652 printf("UUID16 0x%04x\n", data->val.uuid.value.uuid16);
656 if (!(data->val.uuid.value.uuid32 & 0xffff0000)) {
657 uint16_t value = data->val.uuid.value.uuid32;
658 for (i = 0; i < uuid16_max; i++)
659 if (uuid16_names[i].num == value) {
660 def = &uuid16_names[i];
665 printf("UUID32 0x%08x - %s\n", data->val.uuid.value.uuid32, def->name);
667 printf("UUID32 0x%08x\n", data->val.uuid.value.uuid32);
671 for (i = 0; i < 16; i++) {
680 printf("%02x", (unsigned char ) data->val.uuid.value.uuid128.data[i]);
685 printf("UUID type 0x%02x\n", data->val.uuid.type);
693 for (i = 0; i < data->unitSize; i++) {
694 if (i == (data->unitSize - 1) && data->val.str[i] == '\0')
696 if (!isprint(data->val.str[i])) {
703 for (i = 0; i < data->unitSize; i++)
704 printf(" %02x", (unsigned char) data->val.str[i]);
707 for (i = 0; i < data->unitSize; i++)
708 printf("%c", data->val.str[i]);
715 printf("URL %s\n", data->val.str);
720 printf("Sequence\n");
721 print_raw_data(data->val.dataseq, indent + 1);
726 printf("Alternate\n");
727 print_raw_data(data->val.dataseq, indent + 1);
730 printf("Unknown type 0x%02x\n", data->dtd);
734 print_raw_data(data->next, indent);
737 static void print_raw_attr_func(void *value, void *userData)
739 sdp_data_t *data = (sdp_data_t *) value;
740 struct attrib_def *def = NULL;
746 /* Search amongst the generic attributes */
747 for (i = 0; i < attrib_max; i++)
748 if (attrib_names[i].num == data->attrId) {
749 def = &attrib_names[i];
754 printf("\tAttribute 0x%04x - %s\n", data->attrId, def->name);
756 printf("\tAttribute 0x%04x\n", data->attrId);
758 print_raw_data(data, 2);
761 static void print_raw_attr(sdp_record_t *rec)
763 if (rec && rec->attrlist) {
764 printf("Sequence\n");
765 sdp_list_foreach(rec->attrlist, print_raw_attr_func, 0);
770 * Set attributes with single values in SDP record
773 static int set_attrib(sdp_session_t *sess, uint32_t handle, uint16_t attrib, char *value)
775 sdp_list_t *attrid_list;
776 uint32_t range = 0x0000ffff;
780 /* Get the old SDP record */
781 attrid_list = sdp_list_append(NULL, &range);
782 rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attrid_list);
783 sdp_list_free(attrid_list, NULL);
786 printf("Service get request failed.\n");
790 /* Check the type of attribute */
791 if (!strncasecmp(value, "u0x", 3)) {
793 uint16_t value_int = 0;
795 value_int = strtoul(value + 3, NULL, 16);
796 sdp_uuid16_create(&value_uuid, value_int);
797 printf("Adding attrib 0x%X uuid16 0x%X to record 0x%X\n",
798 attrib, value_int, handle);
800 sdp_attr_add_new(rec, attrib, SDP_UUID16, &value_uuid.value.uuid16);
801 } else if (!strncasecmp(value, "0x", 2)) {
804 value_int = strtoul(value + 2, NULL, 16);
805 printf("Adding attrib 0x%X int 0x%X to record 0x%X\n",
806 attrib, value_int, handle);
808 sdp_attr_add_new(rec, attrib, SDP_UINT32, &value_int);
811 printf("Adding attrib 0x%X string \"%s\" to record 0x%X\n",
812 attrib, value, handle);
814 /* Add/Update our attribute to the record */
815 sdp_attr_add_new(rec, attrib, SDP_TEXT_STR8, value);
818 /* Update on the server */
819 ret = sdp_device_record_update(sess, &interface, rec);
821 printf("Service Record update failed (%d).\n", errno);
822 sdp_record_free(rec);
826 static struct option set_options[] = {
827 { "help", 0, 0, 'h' },
831 static const char *set_help =
833 "\tget record_handle attrib_id attrib_value\n";
836 * Add an attribute to an existing SDP record on the local SDP server
838 static int cmd_setattr(int argc, char **argv)
845 for_each_opt(opt, set_options, NULL) {
848 printf("%s", set_help);
857 printf("%s", set_help);
861 /* Convert command line args */
862 handle = strtoul(argv[0], NULL, 16);
863 attrib = strtoul(argv[1], NULL, 16);
866 sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
870 status = set_attrib(sess, handle, attrib, argv[2]);
877 * We do only simple data sequences. Sequence of sequences is a pain ;-)
880 static int set_attribseq(sdp_session_t *session, uint32_t handle, uint16_t attrib, int argc, char **argv)
882 sdp_list_t *attrid_list;
883 uint32_t range = 0x0000ffff;
885 sdp_data_t *pSequenceHolder = NULL;
889 uint8_t uuid16 = SDP_UUID16;
890 uint8_t uint32 = SDP_UINT32;
891 uint8_t str8 = SDP_TEXT_STR8;
894 /* Get the old SDP record */
895 attrid_list = sdp_list_append(NULL, &range);
896 rec = sdp_service_attr_req(session, handle, SDP_ATTR_REQ_RANGE, attrid_list);
897 sdp_list_free(attrid_list, NULL);
900 printf("Service get request failed.\n");
905 dtdArray = (void **)malloc(argc * sizeof(void *));
906 valueArray = (void **)malloc(argc * sizeof(void *));
907 allocArray = (void **)malloc(argc * sizeof(void *));
909 /* Loop on all args, add them in arrays */
910 for (i = 0; i < argc; i++) {
911 /* Check the type of attribute */
912 if (!strncasecmp(argv[i], "u0x", 3)) {
914 uint16_t value_int = strtoul((argv[i]) + 3, NULL, 16);
915 uuid_t *value_uuid = (uuid_t *) malloc(sizeof(uuid_t));
916 allocArray[i] = value_uuid;
917 sdp_uuid16_create(value_uuid, value_int);
919 printf("Adding uuid16 0x%X to record 0x%X\n", value_int, handle);
920 dtdArray[i] = &uuid16;
921 valueArray[i] = &value_uuid->value.uuid16;
922 } else if (!strncasecmp(argv[i], "0x", 2)) {
924 uint32_t *value_int = (uint32_t *) malloc(sizeof(int));
925 allocArray[i] = value_int;
926 *value_int = strtoul((argv[i]) + 2, NULL, 16);
928 printf("Adding int 0x%X to record 0x%X\n", *value_int, handle);
929 dtdArray[i] = &uint32;
930 valueArray[i] = value_int;
933 printf("Adding string \"%s\" to record 0x%X\n", argv[i], handle);
935 valueArray[i] = argv[i];
939 /* Add this sequence to the attrib list */
940 pSequenceHolder = sdp_seq_alloc(dtdArray, valueArray, argc);
941 if (pSequenceHolder) {
942 sdp_attr_replace(rec, attrib, pSequenceHolder);
944 /* Update on the server */
945 ret = sdp_device_record_update(session, &interface, rec);
947 printf("Service Record update failed (%d).\n", errno);
949 printf("Failed to create pSequenceHolder\n");
952 for (i = 0; i < argc; i++)
959 sdp_record_free(rec);
964 static struct option seq_options[] = {
965 { "help", 0, 0, 'h' },
969 static const char *seq_help =
971 "\tget record_handle attrib_id attrib_values\n";
974 * Add an attribute sequence to an existing SDP record
975 * on the local SDP server
977 static int cmd_setseq(int argc, char **argv)
984 for_each_opt(opt, seq_options, NULL) {
987 printf("%s", seq_help);
996 printf("%s", seq_help);
1000 /* Convert command line args */
1001 handle = strtoul(argv[0], NULL, 16);
1002 attrib = strtoul(argv[1], NULL, 16);
1008 sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
1012 status = set_attribseq(sess, handle, attrib, argc, argv);
1018 static void print_service_class(void *value, void *userData)
1020 char ServiceClassUUID_str[MAX_LEN_SERVICECLASS_UUID_STR];
1021 uuid_t *uuid = (uuid_t *)value;
1023 sdp_uuid2strn(uuid, UUID_str, MAX_LEN_UUID_STR);
1024 sdp_svclass_uuid2strn(uuid, ServiceClassUUID_str, MAX_LEN_SERVICECLASS_UUID_STR);
1025 if (uuid->type != SDP_UUID128)
1026 printf(" \"%s\" (0x%s)\n", ServiceClassUUID_str, UUID_str);
1028 printf(" UUID 128: %s\n", UUID_str);
1031 static void print_service_desc(void *value, void *user)
1033 char str[MAX_LEN_PROTOCOL_UUID_STR];
1034 sdp_data_t *p = (sdp_data_t *)value, *s;
1035 int i = 0, proto = 0;
1037 for (; p; p = p->next, i++) {
1042 sdp_uuid2strn(&p->val.uuid, UUID_str, MAX_LEN_UUID_STR);
1043 sdp_proto_uuid2strn(&p->val.uuid, str, sizeof(str));
1044 proto = sdp_uuid_to_proto(&p->val.uuid);
1045 printf(" \"%s\" (0x%s)\n", str, UUID_str);
1048 if (proto == RFCOMM_UUID)
1049 printf(" Channel: %d\n", p->val.uint8);
1051 printf(" uint8: 0x%02x\n", p->val.uint8);
1054 if (proto == L2CAP_UUID) {
1056 printf(" PSM: %d\n", p->val.uint16);
1058 printf(" Version: 0x%04x\n", p->val.uint16);
1059 } else if (proto == BNEP_UUID)
1061 printf(" Version: 0x%04x\n", p->val.uint16);
1063 printf(" uint16: 0x%04x\n", p->val.uint16);
1065 printf(" uint16: 0x%04x\n", p->val.uint16);
1069 for (s = p->val.dataseq; s; s = s->next)
1070 printf(" %x", s->val.uint16);
1075 for (s = p->val.dataseq; s; s = s->next)
1076 printf(" %x", s->val.uint8);
1080 printf(" FIXME: dtd=0%x\n", p->dtd);
1086 static void print_lang_attr(void *value, void *user)
1088 sdp_lang_attr_t *lang = (sdp_lang_attr_t *)value;
1089 printf(" code_ISO639: 0x%02x\n", lang->code_ISO639);
1090 printf(" encoding: 0x%02x\n", lang->encoding);
1091 printf(" base_offset: 0x%02x\n", lang->base_offset);
1094 static void print_access_protos(void *value, void *userData)
1096 sdp_list_t *protDescSeq = (sdp_list_t *)value;
1097 sdp_list_foreach(protDescSeq, print_service_desc, 0);
1100 static void print_profile_desc(void *value, void *userData)
1102 sdp_profile_desc_t *desc = (sdp_profile_desc_t *)value;
1103 char str[MAX_LEN_PROFILEDESCRIPTOR_UUID_STR];
1105 sdp_uuid2strn(&desc->uuid, UUID_str, MAX_LEN_UUID_STR);
1106 sdp_profile_uuid2strn(&desc->uuid, str, MAX_LEN_PROFILEDESCRIPTOR_UUID_STR);
1108 printf(" \"%s\" (0x%s)\n", str, UUID_str);
1110 printf(" Version: 0x%04x\n", desc->version);
1114 * Parse a SDP record in user friendly form.
1116 static void print_service_attr(sdp_record_t *rec)
1118 sdp_list_t *list = 0, *proto = 0;
1120 sdp_record_print(rec);
1122 printf("Service RecHandle: 0x%x\n", rec->handle);
1124 if (sdp_get_service_classes(rec, &list) == 0) {
1125 printf("Service Class ID List:\n");
1126 sdp_list_foreach(list, print_service_class, 0);
1127 sdp_list_free(list, free);
1129 if (sdp_get_access_protos(rec, &proto) == 0) {
1130 printf("Protocol Descriptor List:\n");
1131 sdp_list_foreach(proto, print_access_protos, 0);
1132 sdp_list_foreach(proto, (sdp_list_func_t)sdp_list_free, 0);
1133 sdp_list_free(proto, 0);
1135 if (sdp_get_lang_attr(rec, &list) == 0) {
1136 printf("Language Base Attr List:\n");
1137 sdp_list_foreach(list, print_lang_attr, 0);
1138 sdp_list_free(list, free);
1140 if (sdp_get_profile_descs(rec, &list) == 0) {
1141 printf("Profile Descriptor List:\n");
1142 sdp_list_foreach(list, print_profile_desc, 0);
1143 sdp_list_free(list, free);
1148 * Support for Service (de)registration
1156 unsigned int profile;
1162 static int add_sp(sdp_session_t *session, svc_info_t *si)
1164 sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
1165 uuid_t root_uuid, sp_uuid, l2cap, rfcomm;
1166 sdp_profile_desc_t profile;
1167 sdp_record_t record;
1168 uint8_t u8 = si->channel ? si->channel : 1;
1169 sdp_data_t *channel;
1172 memset(&record, 0, sizeof(sdp_record_t));
1173 record.handle = si->handle;
1174 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1175 root = sdp_list_append(0, &root_uuid);
1176 sdp_set_browse_groups(&record, root);
1178 sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
1179 svclass_id = sdp_list_append(0, &sp_uuid);
1180 sdp_set_service_classes(&record, svclass_id);
1182 sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
1183 #ifdef __TIZEN_PATCH__
1184 profile.version = 0x0102;
1186 profile.version = 0x0100;
1188 profiles = sdp_list_append(0, &profile);
1189 sdp_set_profile_descs(&record, profiles);
1191 sdp_uuid16_create(&l2cap, L2CAP_UUID);
1192 proto[0] = sdp_list_append(0, &l2cap);
1193 apseq = sdp_list_append(0, proto[0]);
1195 sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
1196 proto[1] = sdp_list_append(0, &rfcomm);
1197 channel = sdp_data_alloc(SDP_UINT8, &u8);
1198 proto[1] = sdp_list_append(proto[1], channel);
1199 apseq = sdp_list_append(apseq, proto[1]);
1201 aproto = sdp_list_append(0, apseq);
1202 sdp_set_access_protos(&record, aproto);
1204 sdp_add_lang_attr(&record);
1206 sdp_set_info_attr(&record, "Serial Port", "BlueZ", "COM Port");
1208 sdp_set_url_attr(&record, "http://www.bluez.org/",
1209 "http://www.bluez.org/", "http://www.bluez.org/");
1211 sdp_set_service_id(&record, sp_uuid);
1212 sdp_set_service_ttl(&record, 0xffff);
1213 sdp_set_service_avail(&record, 0xff);
1214 sdp_set_record_state(&record, 0x00001234);
1216 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1217 printf("Service Record registration failed\n");
1222 printf("Serial Port service registered\n");
1225 sdp_data_free(channel);
1226 sdp_list_free(proto[0], 0);
1227 sdp_list_free(proto[1], 0);
1228 sdp_list_free(apseq, 0);
1229 sdp_list_free(aproto, 0);
1230 sdp_list_free(root, 0);
1231 sdp_list_free(svclass_id, 0);
1232 sdp_list_free(profiles, 0);
1237 static int add_dun(sdp_session_t *session, svc_info_t *si)
1239 sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto;
1240 uuid_t rootu, dun, gn, l2cap, rfcomm;
1241 sdp_profile_desc_t profile;
1242 sdp_list_t *proto[2];
1243 sdp_record_t record;
1244 uint8_t u8 = si->channel ? si->channel : 2;
1245 sdp_data_t *channel;
1248 memset(&record, 0, sizeof(sdp_record_t));
1249 record.handle = si->handle;
1251 sdp_uuid16_create(&rootu, PUBLIC_BROWSE_GROUP);
1252 root = sdp_list_append(0, &rootu);
1253 sdp_set_browse_groups(&record, root);
1255 sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
1256 svclass_id = sdp_list_append(0, &dun);
1257 sdp_uuid16_create(&gn, GENERIC_NETWORKING_SVCLASS_ID);
1258 svclass_id = sdp_list_append(svclass_id, &gn);
1259 sdp_set_service_classes(&record, svclass_id);
1261 sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID);
1262 profile.version = 0x0100;
1263 pfseq = sdp_list_append(0, &profile);
1264 sdp_set_profile_descs(&record, pfseq);
1266 sdp_uuid16_create(&l2cap, L2CAP_UUID);
1267 proto[0] = sdp_list_append(0, &l2cap);
1268 apseq = sdp_list_append(0, proto[0]);
1270 sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
1271 proto[1] = sdp_list_append(0, &rfcomm);
1272 channel = sdp_data_alloc(SDP_UINT8, &u8);
1273 proto[1] = sdp_list_append(proto[1], channel);
1274 apseq = sdp_list_append(apseq, proto[1]);
1276 aproto = sdp_list_append(0, apseq);
1277 sdp_set_access_protos(&record, aproto);
1279 sdp_set_info_attr(&record, "Dial-Up Networking", 0, 0);
1281 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1282 printf("Service Record registration failed\n");
1287 printf("Dial-Up Networking service registered\n");
1290 sdp_data_free(channel);
1291 sdp_list_free(proto[0], 0);
1292 sdp_list_free(proto[1], 0);
1293 sdp_list_free(apseq, 0);
1294 sdp_list_free(aproto, 0);
1299 static int add_fax(sdp_session_t *session, svc_info_t *si)
1301 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1302 uuid_t root_uuid, fax_uuid, tel_uuid, l2cap_uuid, rfcomm_uuid;
1303 sdp_profile_desc_t profile;
1304 sdp_list_t *aproto, *proto[2];
1305 sdp_record_t record;
1306 uint8_t u8 = si->channel? si->channel : 3;
1307 sdp_data_t *channel;
1310 memset(&record, 0, sizeof(sdp_record_t));
1311 record.handle = si->handle;
1313 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1314 root = sdp_list_append(0, &root_uuid);
1315 sdp_set_browse_groups(&record, root);
1317 sdp_uuid16_create(&fax_uuid, FAX_SVCLASS_ID);
1318 svclass_id = sdp_list_append(0, &fax_uuid);
1319 sdp_uuid16_create(&tel_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
1320 svclass_id = sdp_list_append(svclass_id, &tel_uuid);
1321 sdp_set_service_classes(&record, svclass_id);
1323 sdp_uuid16_create(&profile.uuid, FAX_PROFILE_ID);
1324 profile.version = 0x0100;
1325 pfseq = sdp_list_append(0, &profile);
1326 sdp_set_profile_descs(&record, pfseq);
1328 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1329 proto[0] = sdp_list_append(0, &l2cap_uuid);
1330 apseq = sdp_list_append(0, proto[0]);
1332 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1333 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1334 channel = sdp_data_alloc(SDP_UINT8, &u8);
1335 proto[1] = sdp_list_append(proto[1], channel);
1336 apseq = sdp_list_append(apseq, proto[1]);
1338 aproto = sdp_list_append(0, apseq);
1339 sdp_set_access_protos(&record, aproto);
1341 sdp_set_info_attr(&record, "Fax", 0, 0);
1343 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1344 printf("Service Record registration failed\n");
1348 printf("Fax service registered\n");
1350 sdp_data_free(channel);
1351 sdp_list_free(proto[0], 0);
1352 sdp_list_free(proto[1], 0);
1353 sdp_list_free(apseq, 0);
1354 sdp_list_free(aproto, 0);
1358 static int add_lan(sdp_session_t *session, svc_info_t *si)
1360 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1361 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
1362 sdp_profile_desc_t profile;
1363 sdp_list_t *aproto, *proto[2];
1364 sdp_record_t record;
1365 uint8_t u8 = si->channel ? si->channel : 4;
1366 sdp_data_t *channel;
1369 memset(&record, 0, sizeof(sdp_record_t));
1370 record.handle = si->handle;
1372 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1373 root = sdp_list_append(0, &root_uuid);
1374 sdp_set_browse_groups(&record, root);
1376 sdp_uuid16_create(&svclass_uuid, LAN_ACCESS_SVCLASS_ID);
1377 svclass_id = sdp_list_append(0, &svclass_uuid);
1378 sdp_set_service_classes(&record, svclass_id);
1380 sdp_uuid16_create(&profile.uuid, LAN_ACCESS_PROFILE_ID);
1381 profile.version = 0x0100;
1382 pfseq = sdp_list_append(0, &profile);
1383 sdp_set_profile_descs(&record, pfseq);
1385 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1386 proto[0] = sdp_list_append(0, &l2cap_uuid);
1387 apseq = sdp_list_append(0, proto[0]);
1389 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1390 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1391 channel = sdp_data_alloc(SDP_UINT8, &u8);
1392 proto[1] = sdp_list_append(proto[1], channel);
1393 apseq = sdp_list_append(apseq, proto[1]);
1395 aproto = sdp_list_append(0, apseq);
1396 sdp_set_access_protos(&record, aproto);
1398 sdp_set_info_attr(&record, "LAN Access over PPP", 0, 0);
1400 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1401 printf("Service Record registration failed\n");
1406 printf("LAN Access service registered\n");
1409 sdp_data_free(channel);
1410 sdp_list_free(proto[0], 0);
1411 sdp_list_free(proto[1], 0);
1412 sdp_list_free(apseq, 0);
1413 sdp_list_free(aproto, 0);
1418 static int add_headset(sdp_session_t *session, svc_info_t *si)
1420 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1421 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1422 sdp_profile_desc_t profile;
1423 sdp_list_t *aproto, *proto[2];
1424 sdp_record_t record;
1425 uint8_t u8 = si->channel ? si->channel : 5;
1426 sdp_data_t *channel;
1429 memset(&record, 0, sizeof(sdp_record_t));
1430 record.handle = si->handle;
1432 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1433 root = sdp_list_append(0, &root_uuid);
1434 sdp_set_browse_groups(&record, root);
1436 sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
1437 svclass_id = sdp_list_append(0, &svclass_uuid);
1438 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1439 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1440 sdp_set_service_classes(&record, svclass_id);
1442 sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
1443 profile.version = 0x0100;
1444 pfseq = sdp_list_append(0, &profile);
1445 sdp_set_profile_descs(&record, pfseq);
1447 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1448 proto[0] = sdp_list_append(0, &l2cap_uuid);
1449 apseq = sdp_list_append(0, proto[0]);
1451 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1452 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1453 channel = sdp_data_alloc(SDP_UINT8, &u8);
1454 proto[1] = sdp_list_append(proto[1], channel);
1455 apseq = sdp_list_append(apseq, proto[1]);
1457 aproto = sdp_list_append(0, apseq);
1458 sdp_set_access_protos(&record, aproto);
1460 sdp_set_info_attr(&record, "Headset", 0, 0);
1462 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1463 printf("Service Record registration failed\n");
1468 printf("Headset service registered\n");
1471 sdp_data_free(channel);
1472 sdp_list_free(proto[0], 0);
1473 sdp_list_free(proto[1], 0);
1474 sdp_list_free(apseq, 0);
1475 sdp_list_free(aproto, 0);
1480 static int add_headset_ag(sdp_session_t *session, svc_info_t *si)
1482 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1483 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1484 sdp_profile_desc_t profile;
1485 sdp_list_t *aproto, *proto[2];
1486 sdp_record_t record;
1487 uint8_t u8 = si->channel ? si->channel : 7;
1488 sdp_data_t *channel;
1489 uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
1490 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
1493 memset(&record, 0, sizeof(sdp_record_t));
1494 record.handle = si->handle;
1496 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1497 root = sdp_list_append(0, &root_uuid);
1498 sdp_set_browse_groups(&record, root);
1500 sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
1501 svclass_id = sdp_list_append(0, &svclass_uuid);
1502 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1503 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1504 sdp_set_service_classes(&record, svclass_id);
1506 sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
1507 profile.version = 0x0100;
1508 pfseq = sdp_list_append(0, &profile);
1509 sdp_set_profile_descs(&record, pfseq);
1511 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1512 proto[0] = sdp_list_append(0, &l2cap_uuid);
1513 apseq = sdp_list_append(0, proto[0]);
1515 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1516 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1517 channel = sdp_data_alloc(SDP_UINT8, &u8);
1518 proto[1] = sdp_list_append(proto[1], channel);
1519 apseq = sdp_list_append(apseq, proto[1]);
1521 aproto = sdp_list_append(0, apseq);
1522 sdp_set_access_protos(&record, aproto);
1524 sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
1526 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
1528 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
1529 printf("Service Record registration failed\n");
1534 printf("Headset AG service registered\n");
1537 sdp_data_free(channel);
1538 sdp_list_free(proto[0], 0);
1539 sdp_list_free(proto[1], 0);
1540 sdp_list_free(apseq, 0);
1541 sdp_list_free(aproto, 0);
1546 static int add_handsfree(sdp_session_t *session, svc_info_t *si)
1548 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1549 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1550 sdp_profile_desc_t profile;
1551 sdp_list_t *aproto, *proto[2];
1552 sdp_record_t record;
1553 uint8_t u8 = si->channel ? si->channel : 6;
1554 uint16_t u16 = 0x31;
1555 sdp_data_t *channel, *features;
1558 memset(&record, 0, sizeof(sdp_record_t));
1559 record.handle = si->handle;
1561 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1562 root = sdp_list_append(0, &root_uuid);
1563 sdp_set_browse_groups(&record, root);
1565 sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
1566 svclass_id = sdp_list_append(0, &svclass_uuid);
1567 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1568 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1569 sdp_set_service_classes(&record, svclass_id);
1571 sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
1572 profile.version = 0x0101;
1573 pfseq = sdp_list_append(0, &profile);
1574 sdp_set_profile_descs(&record, pfseq);
1576 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1577 proto[0] = sdp_list_append(0, &l2cap_uuid);
1578 apseq = sdp_list_append(0, proto[0]);
1580 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1581 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1582 channel = sdp_data_alloc(SDP_UINT8, &u8);
1583 proto[1] = sdp_list_append(proto[1], channel);
1584 apseq = sdp_list_append(apseq, proto[1]);
1586 features = sdp_data_alloc(SDP_UINT16, &u16);
1587 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1589 aproto = sdp_list_append(0, apseq);
1590 sdp_set_access_protos(&record, aproto);
1592 sdp_set_info_attr(&record, "Handsfree", 0, 0);
1594 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1595 printf("Service Record registration failed\n");
1600 printf("Handsfree service registered\n");
1603 sdp_data_free(channel);
1604 sdp_list_free(proto[0], 0);
1605 sdp_list_free(proto[1], 0);
1606 sdp_list_free(apseq, 0);
1607 sdp_list_free(aproto, 0);
1612 static int add_handsfree_ag(sdp_session_t *session, svc_info_t *si)
1614 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1615 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1616 sdp_profile_desc_t profile;
1617 sdp_list_t *aproto, *proto[2];
1618 sdp_record_t record;
1619 uint8_t u8 = si->channel ? si->channel : 7;
1620 uint16_t u16 = 0x17;
1621 sdp_data_t *channel, *features;
1622 uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
1623 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
1626 memset(&record, 0, sizeof(sdp_record_t));
1627 record.handle = si->handle;
1629 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1630 root = sdp_list_append(0, &root_uuid);
1631 sdp_set_browse_groups(&record, root);
1633 sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
1634 svclass_id = sdp_list_append(0, &svclass_uuid);
1635 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1636 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1637 sdp_set_service_classes(&record, svclass_id);
1639 sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
1640 profile.version = 0x0105;
1641 pfseq = sdp_list_append(0, &profile);
1642 sdp_set_profile_descs(&record, pfseq);
1644 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1645 proto[0] = sdp_list_append(0, &l2cap_uuid);
1646 apseq = sdp_list_append(0, proto[0]);
1648 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1649 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1650 channel = sdp_data_alloc(SDP_UINT8, &u8);
1651 proto[1] = sdp_list_append(proto[1], channel);
1652 apseq = sdp_list_append(apseq, proto[1]);
1654 features = sdp_data_alloc(SDP_UINT16, &u16);
1655 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1657 aproto = sdp_list_append(0, apseq);
1658 sdp_set_access_protos(&record, aproto);
1660 sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
1662 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
1664 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
1665 printf("Service Record registration failed\n");
1670 printf("Handsfree AG service registered\n");
1673 sdp_data_free(channel);
1674 sdp_list_free(proto[0], 0);
1675 sdp_list_free(proto[1], 0);
1676 sdp_list_free(apseq, 0);
1677 sdp_list_free(aproto, 0);
1682 static int add_simaccess(sdp_session_t *session, svc_info_t *si)
1684 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1685 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1686 sdp_profile_desc_t profile;
1687 sdp_list_t *aproto, *proto[2];
1688 sdp_record_t record;
1689 uint8_t u8 = si->channel? si->channel : 8;
1690 uint16_t u16 = 0x31;
1691 sdp_data_t *channel, *features;
1694 memset((void *)&record, 0, sizeof(sdp_record_t));
1695 record.handle = si->handle;
1697 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1698 root = sdp_list_append(0, &root_uuid);
1699 sdp_set_browse_groups(&record, root);
1701 sdp_uuid16_create(&svclass_uuid, SAP_SVCLASS_ID);
1702 svclass_id = sdp_list_append(0, &svclass_uuid);
1703 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
1704 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1705 sdp_set_service_classes(&record, svclass_id);
1707 sdp_uuid16_create(&profile.uuid, SAP_PROFILE_ID);
1708 profile.version = 0x0101;
1709 pfseq = sdp_list_append(0, &profile);
1710 sdp_set_profile_descs(&record, pfseq);
1712 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1713 proto[0] = sdp_list_append(0, &l2cap_uuid);
1714 apseq = sdp_list_append(0, proto[0]);
1716 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1717 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1718 channel = sdp_data_alloc(SDP_UINT8, &u8);
1719 proto[1] = sdp_list_append(proto[1], channel);
1720 apseq = sdp_list_append(apseq, proto[1]);
1722 features = sdp_data_alloc(SDP_UINT16, &u16);
1723 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1725 aproto = sdp_list_append(0, apseq);
1726 sdp_set_access_protos(&record, aproto);
1728 sdp_set_info_attr(&record, "SIM Access", 0, 0);
1730 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1731 printf("Service Record registration failed\n");
1736 printf("SIM Access service registered\n");
1739 sdp_data_free(channel);
1740 sdp_list_free(proto[0], 0);
1741 sdp_list_free(proto[1], 0);
1742 sdp_list_free(apseq, 0);
1743 sdp_list_free(aproto, 0);
1748 static int add_opush(sdp_session_t *session, svc_info_t *si)
1750 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1751 uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1752 sdp_profile_desc_t profile[1];
1753 sdp_list_t *aproto, *proto[3];
1754 sdp_record_t record;
1755 uint8_t chan = si->channel ? si->channel : 9;
1756 sdp_data_t *channel;
1757 uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
1758 void *dtds[sizeof(formats)], *values[sizeof(formats)];
1760 uint8_t dtd = SDP_UINT8;
1764 memset(&record, 0, sizeof(sdp_record_t));
1765 record.handle = si->handle;
1767 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1768 root = sdp_list_append(0, &root_uuid);
1769 sdp_set_browse_groups(&record, root);
1771 sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
1772 svclass_id = sdp_list_append(0, &opush_uuid);
1773 sdp_set_service_classes(&record, svclass_id);
1775 sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
1776 profile[0].version = 0x0100;
1777 pfseq = sdp_list_append(0, profile);
1778 sdp_set_profile_descs(&record, pfseq);
1780 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1781 proto[0] = sdp_list_append(0, &l2cap_uuid);
1782 apseq = sdp_list_append(0, proto[0]);
1784 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1785 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1786 channel = sdp_data_alloc(SDP_UINT8, &chan);
1787 proto[1] = sdp_list_append(proto[1], channel);
1788 apseq = sdp_list_append(apseq, proto[1]);
1790 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1791 proto[2] = sdp_list_append(0, &obex_uuid);
1792 apseq = sdp_list_append(apseq, proto[2]);
1794 aproto = sdp_list_append(0, apseq);
1795 sdp_set_access_protos(&record, aproto);
1797 for (i = 0; i < sizeof(formats); i++) {
1799 values[i] = &formats[i];
1801 sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
1802 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
1804 sdp_set_info_attr(&record, "OBEX Object Push", 0, 0);
1806 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1807 printf("Service Record registration failed\n");
1812 printf("OBEX Object Push service registered\n");
1815 sdp_data_free(channel);
1816 sdp_list_free(proto[0], 0);
1817 sdp_list_free(proto[1], 0);
1818 sdp_list_free(proto[2], 0);
1819 sdp_list_free(apseq, 0);
1820 sdp_list_free(pfseq, 0);
1821 sdp_list_free(aproto, 0);
1822 sdp_list_free(root, 0);
1823 sdp_list_free(svclass_id, NULL);
1828 static int add_pbap(sdp_session_t *session, svc_info_t *si)
1830 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1831 uuid_t root_uuid, pbap_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1832 sdp_profile_desc_t profile[1];
1833 sdp_list_t *aproto, *proto[3];
1834 sdp_record_t record;
1835 uint8_t chan = si->channel ? si->channel : 19;
1836 sdp_data_t *channel;
1837 uint8_t formats[] = {0x01};
1838 uint8_t dtd = SDP_UINT8;
1842 memset(&record, 0, sizeof(sdp_record_t));
1843 record.handle = si->handle;
1845 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1846 root = sdp_list_append(0, &root_uuid);
1847 sdp_set_browse_groups(&record, root);
1849 sdp_uuid16_create(&pbap_uuid, PBAP_PSE_SVCLASS_ID);
1850 svclass_id = sdp_list_append(0, &pbap_uuid);
1851 sdp_set_service_classes(&record, svclass_id);
1853 sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID);
1854 profile[0].version = 0x0100;
1855 pfseq = sdp_list_append(0, profile);
1856 sdp_set_profile_descs(&record, pfseq);
1858 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1859 proto[0] = sdp_list_append(0, &l2cap_uuid);
1860 apseq = sdp_list_append(0, proto[0]);
1862 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1863 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1864 channel = sdp_data_alloc(SDP_UINT8, &chan);
1865 proto[1] = sdp_list_append(proto[1], channel);
1866 apseq = sdp_list_append(apseq, proto[1]);
1868 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1869 proto[2] = sdp_list_append(0, &obex_uuid);
1870 apseq = sdp_list_append(apseq, proto[2]);
1872 aproto = sdp_list_append(0, apseq);
1873 sdp_set_access_protos(&record, aproto);
1875 sflist = sdp_data_alloc(dtd,formats);
1876 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_REPOSITORIES, sflist);
1878 sdp_set_info_attr(&record, "OBEX Phonebook Access Server", 0, 0);
1880 if (sdp_device_record_register(session, &interface, &record,
1881 SDP_RECORD_PERSIST) < 0) {
1882 printf("Service Record registration failed\n");
1887 printf("PBAP service registered\n");
1890 sdp_data_free(channel);
1891 sdp_list_free(proto[0], 0);
1892 sdp_list_free(proto[1], 0);
1893 sdp_list_free(proto[2], 0);
1894 sdp_list_free(apseq, 0);
1895 sdp_list_free(pfseq, 0);
1896 sdp_list_free(aproto, 0);
1897 sdp_list_free(root, 0);
1898 sdp_list_free(svclass_id, 0);
1903 static int add_ftp(sdp_session_t *session, svc_info_t *si)
1905 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1906 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1907 sdp_profile_desc_t profile[1];
1908 sdp_list_t *aproto, *proto[3];
1909 sdp_record_t record;
1910 uint8_t u8 = si->channel ? si->channel: 10;
1911 sdp_data_t *channel;
1914 memset(&record, 0, sizeof(sdp_record_t));
1915 record.handle = si->handle;
1917 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1918 root = sdp_list_append(0, &root_uuid);
1919 sdp_set_browse_groups(&record, root);
1921 sdp_uuid16_create(&ftrn_uuid, OBEX_FILETRANS_SVCLASS_ID);
1922 svclass_id = sdp_list_append(0, &ftrn_uuid);
1923 sdp_set_service_classes(&record, svclass_id);
1925 sdp_uuid16_create(&profile[0].uuid, OBEX_FILETRANS_PROFILE_ID);
1926 profile[0].version = 0x0100;
1927 pfseq = sdp_list_append(0, &profile[0]);
1928 sdp_set_profile_descs(&record, pfseq);
1930 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1931 proto[0] = sdp_list_append(0, &l2cap_uuid);
1932 apseq = sdp_list_append(0, proto[0]);
1934 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1935 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1936 channel = sdp_data_alloc(SDP_UINT8, &u8);
1937 proto[1] = sdp_list_append(proto[1], channel);
1938 apseq = sdp_list_append(apseq, proto[1]);
1940 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1941 proto[2] = sdp_list_append(0, &obex_uuid);
1942 apseq = sdp_list_append(apseq, proto[2]);
1944 aproto = sdp_list_append(0, apseq);
1945 sdp_set_access_protos(&record, aproto);
1947 sdp_set_info_attr(&record, "OBEX File Transfer", 0, 0);
1949 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1950 printf("Service Record registration failed\n");
1955 printf("OBEX File Transfer service registered\n");
1958 sdp_data_free(channel);
1959 sdp_list_free(proto[0], 0);
1960 sdp_list_free(proto[1], 0);
1961 sdp_list_free(proto[2], 0);
1962 sdp_list_free(apseq, 0);
1963 sdp_list_free(aproto, 0);
1968 static int add_directprint(sdp_session_t *session, svc_info_t *si)
1970 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1971 uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1972 sdp_profile_desc_t profile[1];
1973 sdp_list_t *aproto, *proto[3];
1974 sdp_record_t record;
1975 uint8_t chan = si->channel ? si->channel : 12;
1976 sdp_data_t *channel;
1979 memset(&record, 0, sizeof(sdp_record_t));
1980 record.handle = si->handle;
1982 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1983 root = sdp_list_append(0, &root_uuid);
1984 sdp_set_browse_groups(&record, root);
1986 sdp_uuid16_create(&opush_uuid, DIRECT_PRINTING_SVCLASS_ID);
1987 svclass_id = sdp_list_append(0, &opush_uuid);
1988 sdp_set_service_classes(&record, svclass_id);
1990 sdp_uuid16_create(&profile[0].uuid, BASIC_PRINTING_PROFILE_ID);
1991 profile[0].version = 0x0100;
1992 pfseq = sdp_list_append(0, profile);
1993 sdp_set_profile_descs(&record, pfseq);
1995 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1996 proto[0] = sdp_list_append(0, &l2cap_uuid);
1997 apseq = sdp_list_append(0, proto[0]);
1999 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
2000 proto[1] = sdp_list_append(0, &rfcomm_uuid);
2001 channel = sdp_data_alloc(SDP_UINT8, &chan);
2002 proto[1] = sdp_list_append(proto[1], channel);
2003 apseq = sdp_list_append(apseq, proto[1]);
2005 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
2006 proto[2] = sdp_list_append(0, &obex_uuid);
2007 apseq = sdp_list_append(apseq, proto[2]);
2009 aproto = sdp_list_append(0, apseq);
2010 sdp_set_access_protos(&record, aproto);
2012 sdp_set_info_attr(&record, "Direct Printing", 0, 0);
2014 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2015 printf("Service Record registration failed\n");
2020 printf("Direct Printing service registered\n");
2023 sdp_data_free(channel);
2024 sdp_list_free(proto[0], 0);
2025 sdp_list_free(proto[1], 0);
2026 sdp_list_free(proto[2], 0);
2027 sdp_list_free(apseq, 0);
2028 sdp_list_free(aproto, 0);
2033 static int add_nap(sdp_session_t *session, svc_info_t *si)
2035 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2036 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2037 sdp_profile_desc_t profile[1];
2038 sdp_list_t *aproto, *proto[2];
2039 sdp_record_t record;
2040 uint16_t lp = 0x000f, ver = 0x0100;
2041 sdp_data_t *psm, *version;
2044 memset(&record, 0, sizeof(sdp_record_t));
2045 record.handle = si->handle;
2047 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2048 root = sdp_list_append(0, &root_uuid);
2049 sdp_set_browse_groups(&record, root);
2051 sdp_uuid16_create(&ftrn_uuid, NAP_SVCLASS_ID);
2052 svclass_id = sdp_list_append(0, &ftrn_uuid);
2053 sdp_set_service_classes(&record, svclass_id);
2055 sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
2056 profile[0].version = 0x0100;
2057 pfseq = sdp_list_append(0, &profile[0]);
2058 sdp_set_profile_descs(&record, pfseq);
2060 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2061 proto[0] = sdp_list_append(0, &l2cap_uuid);
2062 psm = sdp_data_alloc(SDP_UINT16, &lp);
2063 proto[0] = sdp_list_append(proto[0], psm);
2064 apseq = sdp_list_append(0, proto[0]);
2066 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2067 proto[1] = sdp_list_append(0, &bnep_uuid);
2068 version = sdp_data_alloc(SDP_UINT16, &ver);
2069 proto[1] = sdp_list_append(proto[1], version);
2072 uint16_t ptype[4] = { 0x0010, 0x0020, 0x0030, 0x0040 };
2073 sdp_data_t *head, *pseq;
2076 for (p = 0, head = NULL; p < 4; p++) {
2077 sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
2078 head = sdp_seq_append(head, data);
2080 pseq = sdp_data_alloc(SDP_SEQ16, head);
2081 proto[1] = sdp_list_append(proto[1], pseq);
2084 apseq = sdp_list_append(apseq, proto[1]);
2086 aproto = sdp_list_append(0, apseq);
2087 sdp_set_access_protos(&record, aproto);
2089 sdp_set_info_attr(&record, "Network Access Point Service", 0, 0);
2091 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2092 printf("Service Record registration failed\n");
2097 printf("NAP service registered\n");
2100 sdp_data_free(version);
2102 sdp_list_free(proto[0], 0);
2103 sdp_list_free(proto[1], 0);
2104 sdp_list_free(apseq, 0);
2105 sdp_list_free(aproto, 0);
2110 static int add_gn(sdp_session_t *session, svc_info_t *si)
2112 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2113 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2114 sdp_profile_desc_t profile[1];
2115 sdp_list_t *aproto, *proto[2];
2116 sdp_record_t record;
2117 uint16_t lp = 0x000f, ver = 0x0100;
2118 sdp_data_t *psm, *version;
2121 memset(&record, 0, sizeof(sdp_record_t));
2122 record.handle = si->handle;
2124 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2125 root = sdp_list_append(0, &root_uuid);
2126 sdp_set_browse_groups(&record, root);
2128 sdp_uuid16_create(&ftrn_uuid, GN_SVCLASS_ID);
2129 svclass_id = sdp_list_append(0, &ftrn_uuid);
2130 sdp_set_service_classes(&record, svclass_id);
2132 sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
2133 profile[0].version = 0x0100;
2134 pfseq = sdp_list_append(0, &profile[0]);
2135 sdp_set_profile_descs(&record, pfseq);
2137 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2138 proto[0] = sdp_list_append(0, &l2cap_uuid);
2139 psm = sdp_data_alloc(SDP_UINT16, &lp);
2140 proto[0] = sdp_list_append(proto[0], psm);
2141 apseq = sdp_list_append(0, proto[0]);
2143 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2144 proto[1] = sdp_list_append(0, &bnep_uuid);
2145 version = sdp_data_alloc(SDP_UINT16, &ver);
2146 proto[1] = sdp_list_append(proto[1], version);
2147 apseq = sdp_list_append(apseq, proto[1]);
2149 aproto = sdp_list_append(0, apseq);
2150 sdp_set_access_protos(&record, aproto);
2152 sdp_set_info_attr(&record, "Group Network Service", 0, 0);
2154 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2155 printf("Service Record registration failed\n");
2160 printf("GN service registered\n");
2163 sdp_data_free(version);
2165 sdp_list_free(proto[0], 0);
2166 sdp_list_free(proto[1], 0);
2167 sdp_list_free(apseq, 0);
2168 sdp_list_free(aproto, 0);
2173 static int add_panu(sdp_session_t *session, svc_info_t *si)
2175 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2176 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2177 sdp_profile_desc_t profile[1];
2178 sdp_list_t *aproto, *proto[2];
2179 sdp_record_t record;
2180 uint16_t lp = 0x000f, ver = 0x0100;
2181 sdp_data_t *psm, *version;
2184 memset(&record, 0, sizeof(sdp_record_t));
2185 record.handle = si->handle;
2187 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2188 root = sdp_list_append(NULL, &root_uuid);
2189 sdp_set_browse_groups(&record, root);
2190 sdp_list_free(root, NULL);
2192 sdp_uuid16_create(&ftrn_uuid, PANU_SVCLASS_ID);
2193 svclass_id = sdp_list_append(NULL, &ftrn_uuid);
2194 sdp_set_service_classes(&record, svclass_id);
2195 sdp_list_free(svclass_id, NULL);
2197 sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
2198 profile[0].version = 0x0100;
2199 pfseq = sdp_list_append(NULL, &profile[0]);
2200 sdp_set_profile_descs(&record, pfseq);
2201 sdp_list_free(pfseq, NULL);
2203 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2204 proto[0] = sdp_list_append(NULL, &l2cap_uuid);
2205 psm = sdp_data_alloc(SDP_UINT16, &lp);
2206 proto[0] = sdp_list_append(proto[0], psm);
2207 apseq = sdp_list_append(NULL, proto[0]);
2209 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2210 proto[1] = sdp_list_append(NULL, &bnep_uuid);
2211 version = sdp_data_alloc(SDP_UINT16, &ver);
2212 proto[1] = sdp_list_append(proto[1], version);
2213 apseq = sdp_list_append(apseq, proto[1]);
2215 aproto = sdp_list_append(NULL, apseq);
2216 sdp_set_access_protos(&record, aproto);
2218 sdp_set_info_attr(&record, "PAN User", NULL, NULL);
2220 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2221 printf("Service Record registration failed\n");
2226 printf("PANU service registered\n");
2229 sdp_data_free(version);
2231 sdp_list_free(proto[0], 0);
2232 sdp_list_free(proto[1], 0);
2233 sdp_list_free(apseq, 0);
2234 sdp_list_free(aproto, 0);
2239 static int add_hid_keyb(sdp_session_t *session, svc_info_t *si)
2241 sdp_record_t record;
2242 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2243 uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
2244 sdp_profile_desc_t profile[1];
2245 sdp_list_t *aproto, *proto[3];
2246 sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
2248 uint8_t dtd = SDP_UINT16;
2249 uint8_t dtd2 = SDP_UINT8;
2250 uint8_t dtd_data = SDP_TEXT_STR8;
2256 uint8_t hid_spec_type = 0x22;
2257 uint16_t hid_attr_lang[] = { 0x409, 0x100 };
2258 static const uint16_t ctrl = 0x11;
2259 static const uint16_t intr = 0x13;
2260 static const uint16_t hid_attr[] = { 0x100, 0x111, 0x40, 0x0d, 0x01, 0x01 };
2261 static const uint16_t hid_attr2[] = { 0x0, 0x01, 0x100, 0x1f40, 0x01, 0x01 };
2262 const uint8_t hid_spec[] = {
2263 0x05, 0x01, // usage page
2264 0x09, 0x06, // keyboard
2265 0xa1, 0x01, // key codes
2266 0x85, 0x01, // minimum
2268 0x19, 0xe0, // logical min
2269 0x29, 0xe7, // logical max
2270 0x15, 0x00, // report size
2271 0x25, 0x01, // report count
2272 0x75, 0x01, // input data variable absolute
2273 0x95, 0x08, // report count
2274 0x81, 0x02, // report size
2315 memset(&record, 0, sizeof(sdp_record_t));
2316 record.handle = si->handle;
2318 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2319 root = sdp_list_append(0, &root_uuid);
2320 sdp_set_browse_groups(&record, root);
2322 sdp_add_lang_attr(&record);
2324 sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
2325 svclass_id = sdp_list_append(0, &hidkb_uuid);
2326 sdp_set_service_classes(&record, svclass_id);
2328 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
2329 profile[0].version = 0x0100;
2330 pfseq = sdp_list_append(0, profile);
2331 sdp_set_profile_descs(&record, pfseq);
2334 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2335 proto[1] = sdp_list_append(0, &l2cap_uuid);
2336 psm = sdp_data_alloc(SDP_UINT16, &ctrl);
2337 proto[1] = sdp_list_append(proto[1], psm);
2338 apseq = sdp_list_append(0, proto[1]);
2340 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2341 proto[2] = sdp_list_append(0, &hidp_uuid);
2342 apseq = sdp_list_append(apseq, proto[2]);
2344 aproto = sdp_list_append(0, apseq);
2345 sdp_set_access_protos(&record, aproto);
2347 /* additional protocols */
2348 proto[1] = sdp_list_append(0, &l2cap_uuid);
2349 psm = sdp_data_alloc(SDP_UINT16, &intr);
2350 proto[1] = sdp_list_append(proto[1], psm);
2351 apseq = sdp_list_append(0, proto[1]);
2353 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2354 proto[2] = sdp_list_append(0, &hidp_uuid);
2355 apseq = sdp_list_append(apseq, proto[2]);
2357 aproto = sdp_list_append(0, apseq);
2358 sdp_set_add_access_protos(&record, aproto);
2360 sdp_set_info_attr(&record, "HID Keyboard", NULL, NULL);
2362 for (i = 0; i < sizeof(hid_attr) / 2; i++)
2363 sdp_attr_add_new(&record,
2364 SDP_ATTR_HID_DEVICE_RELEASE_NUMBER + i,
2365 SDP_UINT16, &hid_attr[i]);
2368 values[0] = &hid_spec_type;
2369 dtds[1] = &dtd_data;
2370 values[1] = (uint8_t *) hid_spec;
2372 leng[1] = sizeof(hid_spec);
2373 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
2374 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
2375 sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
2377 for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
2379 values2[i] = &hid_attr_lang[i];
2382 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
2383 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
2384 sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
2386 sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE, SDP_UINT16, &hid_attr2[0]);
2388 for (i = 0; i < sizeof(hid_attr2) / 2 - 1; i++)
2389 sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP + i,
2390 SDP_UINT16, &hid_attr2[i + 1]);
2392 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
2393 printf("Service Record registration failed\n");
2397 printf("HID keyboard service registered\n");
2402 static int add_hid_wiimote(sdp_session_t *session, svc_info_t *si)
2404 sdp_record_t record;
2405 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2406 uuid_t root_uuid, hid_uuid, l2cap_uuid, hidp_uuid;
2407 sdp_profile_desc_t profile[1];
2408 sdp_list_t *aproto, *proto[3];
2409 sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
2411 uint8_t dtd = SDP_UINT16;
2412 uint8_t dtd2 = SDP_UINT8;
2413 uint8_t dtd_data = SDP_TEXT_STR8;
2419 uint8_t hid_spec_type = 0x22;
2420 uint16_t hid_attr_lang[] = { 0x409, 0x100 };
2421 uint16_t ctrl = 0x11, intr = 0x13;
2422 uint16_t hid_release = 0x0100, parser_version = 0x0111;
2423 uint8_t subclass = 0x04, country = 0x33;
2424 uint8_t virtual_cable = 0, reconnect = 1, sdp_disable = 0;
2425 uint8_t battery = 1, remote_wakeup = 1;
2426 uint16_t profile_version = 0x0100, superv_timeout = 0x0c80;
2427 uint8_t norm_connect = 0, boot_device = 0;
2428 const uint8_t hid_spec[] = {
2429 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10,
2430 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
2431 0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00,
2432 0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2433 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00,
2434 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2435 0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2436 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2437 0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
2438 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00,
2439 0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
2440 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2441 0x85, 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2442 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00,
2443 0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2444 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00,
2445 0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00,
2446 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00,
2447 0x85, 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00,
2448 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00,
2449 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2450 0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2451 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2452 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2453 0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2454 0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2455 0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2459 memset(&record, 0, sizeof(sdp_record_t));
2460 record.handle = si->handle;
2462 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2463 root = sdp_list_append(NULL, &root_uuid);
2464 sdp_set_browse_groups(&record, root);
2466 sdp_uuid16_create(&hid_uuid, HID_SVCLASS_ID);
2467 svclass_id = sdp_list_append(NULL, &hid_uuid);
2468 sdp_set_service_classes(&record, svclass_id);
2470 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
2471 profile[0].version = 0x0100;
2472 pfseq = sdp_list_append(NULL, profile);
2473 sdp_set_profile_descs(&record, pfseq);
2475 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2476 proto[1] = sdp_list_append(0, &l2cap_uuid);
2477 psm = sdp_data_alloc(SDP_UINT16, &ctrl);
2478 proto[1] = sdp_list_append(proto[1], psm);
2479 apseq = sdp_list_append(0, proto[1]);
2481 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2482 proto[2] = sdp_list_append(0, &hidp_uuid);
2483 apseq = sdp_list_append(apseq, proto[2]);
2485 aproto = sdp_list_append(0, apseq);
2486 sdp_set_access_protos(&record, aproto);
2488 proto[1] = sdp_list_append(0, &l2cap_uuid);
2489 psm = sdp_data_alloc(SDP_UINT16, &intr);
2490 proto[1] = sdp_list_append(proto[1], psm);
2491 apseq = sdp_list_append(0, proto[1]);
2493 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2494 proto[2] = sdp_list_append(0, &hidp_uuid);
2495 apseq = sdp_list_append(apseq, proto[2]);
2497 aproto = sdp_list_append(0, apseq);
2498 sdp_set_add_access_protos(&record, aproto);
2500 sdp_add_lang_attr(&record);
2502 sdp_set_info_attr(&record, "Nintendo RVL-CNT-01",
2503 "Nintendo", "Nintendo RVL-CNT-01");
2505 sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER,
2506 SDP_UINT16, &hid_release);
2508 sdp_attr_add_new(&record, SDP_ATTR_HID_PARSER_VERSION,
2509 SDP_UINT16, &parser_version);
2511 sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_SUBCLASS,
2512 SDP_UINT8, &subclass);
2514 sdp_attr_add_new(&record, SDP_ATTR_HID_COUNTRY_CODE,
2515 SDP_UINT8, &country);
2517 sdp_attr_add_new(&record, SDP_ATTR_HID_VIRTUAL_CABLE,
2518 SDP_BOOL, &virtual_cable);
2520 sdp_attr_add_new(&record, SDP_ATTR_HID_RECONNECT_INITIATE,
2521 SDP_BOOL, &reconnect);
2524 values[0] = &hid_spec_type;
2525 dtds[1] = &dtd_data;
2526 values[1] = (uint8_t *) hid_spec;
2528 leng[1] = sizeof(hid_spec);
2529 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
2530 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
2531 sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
2533 for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
2535 values2[i] = &hid_attr_lang[i];
2538 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
2539 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
2540 sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
2542 sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE,
2543 SDP_BOOL, &sdp_disable);
2545 sdp_attr_add_new(&record, SDP_ATTR_HID_BATTERY_POWER,
2546 SDP_BOOL, &battery);
2548 sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP,
2549 SDP_BOOL, &remote_wakeup);
2551 sdp_attr_add_new(&record, SDP_ATTR_HID_PROFILE_VERSION,
2552 SDP_UINT16, &profile_version);
2554 sdp_attr_add_new(&record, SDP_ATTR_HID_SUPERVISION_TIMEOUT,
2555 SDP_UINT16, &superv_timeout);
2557 sdp_attr_add_new(&record, SDP_ATTR_HID_NORMALLY_CONNECTABLE,
2558 SDP_BOOL, &norm_connect);
2560 sdp_attr_add_new(&record, SDP_ATTR_HID_BOOT_DEVICE,
2561 SDP_BOOL, &boot_device);
2563 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
2564 printf("Service Record registration failed\n");
2568 printf("Wii-Mote service registered\n");
2573 static int add_cip(sdp_session_t *session, svc_info_t *si)
2575 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2576 uuid_t root_uuid, l2cap, cmtp, cip;
2577 sdp_profile_desc_t profile[1];
2578 sdp_list_t *aproto, *proto[2];
2579 sdp_record_t record;
2580 uint16_t psm = si->psm ? si->psm : 0x1001;
2581 uint8_t netid = si->network ? si->network : 0x02; // 0x02 = ISDN, 0x03 = GSM
2582 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
2585 memset(&record, 0, sizeof(sdp_record_t));
2586 record.handle = si->handle;
2588 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2589 root = sdp_list_append(0, &root_uuid);
2590 sdp_set_browse_groups(&record, root);
2592 sdp_uuid16_create(&cip, CIP_SVCLASS_ID);
2593 svclass_id = sdp_list_append(0, &cip);
2594 sdp_set_service_classes(&record, svclass_id);
2596 sdp_uuid16_create(&profile[0].uuid, CIP_PROFILE_ID);
2597 profile[0].version = 0x0100;
2598 pfseq = sdp_list_append(0, &profile[0]);
2599 sdp_set_profile_descs(&record, pfseq);
2601 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2602 proto[0] = sdp_list_append(0, &l2cap);
2603 apseq = sdp_list_append(0, proto[0]);
2604 proto[0] = sdp_list_append(proto[0], sdp_data_alloc(SDP_UINT16, &psm));
2605 apseq = sdp_list_append(apseq, proto[0]);
2607 sdp_uuid16_create(&cmtp, CMTP_UUID);
2608 proto[1] = sdp_list_append(0, &cmtp);
2609 apseq = sdp_list_append(apseq, proto[1]);
2611 aproto = sdp_list_append(0, apseq);
2612 sdp_set_access_protos(&record, aproto);
2614 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
2616 sdp_set_info_attr(&record, "Common ISDN Access", 0, 0);
2618 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2619 printf("Service Record registration failed\n");
2624 printf("CIP service registered\n");
2627 sdp_list_free(proto[0], 0);
2628 sdp_list_free(proto[1], 0);
2629 sdp_list_free(apseq, 0);
2630 sdp_list_free(aproto, 0);
2631 sdp_data_free(network);
2636 static int add_ctp(sdp_session_t *session, svc_info_t *si)
2638 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2639 uuid_t root_uuid, l2cap, tcsbin, ctp;
2640 sdp_profile_desc_t profile[1];
2641 sdp_list_t *aproto, *proto[2];
2642 sdp_record_t record;
2643 uint8_t netid = si->network ? si->network : 0x02; // 0x01-0x07 cf. p120 profile document
2644 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
2647 memset(&record, 0, sizeof(sdp_record_t));
2648 record.handle = si->handle;
2650 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2651 root = sdp_list_append(0, &root_uuid);
2652 sdp_set_browse_groups(&record, root);
2654 sdp_uuid16_create(&ctp, CORDLESS_TELEPHONY_SVCLASS_ID);
2655 svclass_id = sdp_list_append(0, &ctp);
2656 sdp_set_service_classes(&record, svclass_id);
2658 sdp_uuid16_create(&profile[0].uuid, CORDLESS_TELEPHONY_PROFILE_ID);
2659 profile[0].version = 0x0100;
2660 pfseq = sdp_list_append(0, &profile[0]);
2661 sdp_set_profile_descs(&record, pfseq);
2663 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2664 proto[0] = sdp_list_append(0, &l2cap);
2665 apseq = sdp_list_append(0, proto[0]);
2667 sdp_uuid16_create(&tcsbin, TCS_BIN_UUID);
2668 proto[1] = sdp_list_append(0, &tcsbin);
2669 apseq = sdp_list_append(apseq, proto[1]);
2671 aproto = sdp_list_append(0, apseq);
2672 sdp_set_access_protos(&record, aproto);
2674 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
2676 sdp_set_info_attr(&record, "Cordless Telephony", 0, 0);
2678 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2679 printf("Service Record registration failed\n");
2684 printf("CTP service registered\n");
2687 sdp_list_free(proto[0], 0);
2688 sdp_list_free(proto[1], 0);
2689 sdp_list_free(apseq, 0);
2690 sdp_list_free(aproto, 0);
2691 sdp_data_free(network);
2696 static int add_a2source(sdp_session_t *session, svc_info_t *si)
2698 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2699 uuid_t root_uuid, l2cap, avdtp, a2src;
2700 sdp_profile_desc_t profile[1];
2701 sdp_list_t *aproto, *proto[2];
2702 sdp_record_t record;
2703 sdp_data_t *psm, *version;
2704 uint16_t lp = 0x0019, ver = 0x0100;
2707 memset(&record, 0, sizeof(sdp_record_t));
2708 record.handle = si->handle;
2710 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2711 root = sdp_list_append(0, &root_uuid);
2712 sdp_set_browse_groups(&record, root);
2714 sdp_uuid16_create(&a2src, AUDIO_SOURCE_SVCLASS_ID);
2715 svclass_id = sdp_list_append(0, &a2src);
2716 sdp_set_service_classes(&record, svclass_id);
2718 sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
2719 profile[0].version = 0x0100;
2720 pfseq = sdp_list_append(0, &profile[0]);
2721 sdp_set_profile_descs(&record, pfseq);
2723 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2724 proto[0] = sdp_list_append(0, &l2cap);
2725 psm = sdp_data_alloc(SDP_UINT16, &lp);
2726 proto[0] = sdp_list_append(proto[0], psm);
2727 apseq = sdp_list_append(0, proto[0]);
2729 sdp_uuid16_create(&avdtp, AVDTP_UUID);
2730 proto[1] = sdp_list_append(0, &avdtp);
2731 version = sdp_data_alloc(SDP_UINT16, &ver);
2732 proto[1] = sdp_list_append(proto[1], version);
2733 apseq = sdp_list_append(apseq, proto[1]);
2735 aproto = sdp_list_append(0, apseq);
2736 sdp_set_access_protos(&record, aproto);
2738 sdp_set_info_attr(&record, "Audio Source", 0, 0);
2740 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2741 printf("Service Record registration failed\n");
2746 printf("Audio source service registered\n");
2749 sdp_list_free(proto[0], 0);
2750 sdp_list_free(proto[1], 0);
2751 sdp_list_free(apseq, 0);
2752 sdp_list_free(aproto, 0);
2757 static int add_a2sink(sdp_session_t *session, svc_info_t *si)
2759 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2760 uuid_t root_uuid, l2cap, avdtp, a2snk;
2761 sdp_profile_desc_t profile[1];
2762 sdp_list_t *aproto, *proto[2];
2763 sdp_record_t record;
2764 sdp_data_t *psm, *version;
2765 uint16_t lp = 0x0019, ver = 0x0100;
2768 memset(&record, 0, sizeof(sdp_record_t));
2769 record.handle = si->handle;
2771 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2772 root = sdp_list_append(0, &root_uuid);
2773 sdp_set_browse_groups(&record, root);
2775 sdp_uuid16_create(&a2snk, AUDIO_SINK_SVCLASS_ID);
2776 svclass_id = sdp_list_append(0, &a2snk);
2777 sdp_set_service_classes(&record, svclass_id);
2779 sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
2780 profile[0].version = 0x0100;
2781 pfseq = sdp_list_append(0, &profile[0]);
2782 sdp_set_profile_descs(&record, pfseq);
2784 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2785 proto[0] = sdp_list_append(0, &l2cap);
2786 psm = sdp_data_alloc(SDP_UINT16, &lp);
2787 proto[0] = sdp_list_append(proto[0], psm);
2788 apseq = sdp_list_append(0, proto[0]);
2790 sdp_uuid16_create(&avdtp, AVDTP_UUID);
2791 proto[1] = sdp_list_append(0, &avdtp);
2792 version = sdp_data_alloc(SDP_UINT16, &ver);
2793 proto[1] = sdp_list_append(proto[1], version);
2794 apseq = sdp_list_append(apseq, proto[1]);
2796 aproto = sdp_list_append(0, apseq);
2797 sdp_set_access_protos(&record, aproto);
2799 sdp_set_info_attr(&record, "Audio Sink", 0, 0);
2801 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2802 printf("Service Record registration failed\n");
2807 printf("Audio sink service registered\n");
2810 sdp_list_free(proto[0], 0);
2811 sdp_list_free(proto[1], 0);
2812 sdp_list_free(apseq, 0);
2813 sdp_list_free(aproto, 0);
2818 static int add_avrct(sdp_session_t *session, svc_info_t *si)
2820 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2821 uuid_t root_uuid, l2cap, avctp, avrct;
2822 sdp_profile_desc_t profile[1];
2823 sdp_list_t *aproto, *proto[2];
2824 sdp_record_t record;
2825 sdp_data_t *psm, *version, *features;
2826 uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
2829 memset(&record, 0, sizeof(sdp_record_t));
2830 record.handle = si->handle;
2832 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2833 root = sdp_list_append(0, &root_uuid);
2834 sdp_set_browse_groups(&record, root);
2836 sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID);
2837 svclass_id = sdp_list_append(0, &avrct);
2838 sdp_set_service_classes(&record, svclass_id);
2840 sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
2841 profile[0].version = 0x0100;
2842 pfseq = sdp_list_append(0, &profile[0]);
2843 sdp_set_profile_descs(&record, pfseq);
2845 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2846 proto[0] = sdp_list_append(0, &l2cap);
2847 psm = sdp_data_alloc(SDP_UINT16, &lp);
2848 proto[0] = sdp_list_append(proto[0], psm);
2849 apseq = sdp_list_append(0, proto[0]);
2851 sdp_uuid16_create(&avctp, AVCTP_UUID);
2852 proto[1] = sdp_list_append(0, &avctp);
2853 version = sdp_data_alloc(SDP_UINT16, &ver);
2854 proto[1] = sdp_list_append(proto[1], version);
2855 apseq = sdp_list_append(apseq, proto[1]);
2857 aproto = sdp_list_append(0, apseq);
2858 sdp_set_access_protos(&record, aproto);
2860 features = sdp_data_alloc(SDP_UINT16, &feat);
2861 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
2863 sdp_set_info_attr(&record, "AVRCP CT", 0, 0);
2865 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2866 printf("Service Record registration failed\n");
2871 printf("Remote control service registered\n");
2874 sdp_list_free(proto[0], 0);
2875 sdp_list_free(proto[1], 0);
2876 sdp_list_free(apseq, 0);
2877 sdp_list_free(aproto, 0);
2882 static int add_avrtg(sdp_session_t *session, svc_info_t *si)
2884 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2885 uuid_t root_uuid, l2cap, avctp, avrtg;
2886 sdp_profile_desc_t profile[1];
2887 sdp_list_t *aproto, *proto[2];
2888 sdp_record_t record;
2889 sdp_data_t *psm, *version, *features;
2890 uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
2893 memset(&record, 0, sizeof(sdp_record_t));
2894 record.handle = si->handle;
2896 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2897 root = sdp_list_append(0, &root_uuid);
2898 sdp_set_browse_groups(&record, root);
2900 sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID);
2901 svclass_id = sdp_list_append(0, &avrtg);
2902 sdp_set_service_classes(&record, svclass_id);
2904 sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
2905 profile[0].version = 0x0100;
2906 pfseq = sdp_list_append(0, &profile[0]);
2907 sdp_set_profile_descs(&record, pfseq);
2909 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2910 proto[0] = sdp_list_append(0, &l2cap);
2911 psm = sdp_data_alloc(SDP_UINT16, &lp);
2912 proto[0] = sdp_list_append(proto[0], psm);
2913 apseq = sdp_list_append(0, proto[0]);
2915 sdp_uuid16_create(&avctp, AVCTP_UUID);
2916 proto[1] = sdp_list_append(0, &avctp);
2917 version = sdp_data_alloc(SDP_UINT16, &ver);
2918 proto[1] = sdp_list_append(proto[1], version);
2919 apseq = sdp_list_append(apseq, proto[1]);
2921 aproto = sdp_list_append(0, apseq);
2922 sdp_set_access_protos(&record, aproto);
2924 features = sdp_data_alloc(SDP_UINT16, &feat);
2925 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
2927 sdp_set_info_attr(&record, "AVRCP TG", 0, 0);
2929 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2930 printf("Service Record registration failed\n");
2935 printf("Remote target service registered\n");
2938 sdp_list_free(proto[0], 0);
2939 sdp_list_free(proto[1], 0);
2940 sdp_list_free(apseq, 0);
2941 sdp_list_free(aproto, 0);
2946 static int add_udi_ue(sdp_session_t *session, svc_info_t *si)
2948 sdp_record_t record;
2949 sdp_list_t *root, *svclass, *proto;
2950 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
2951 uint8_t channel = si->channel ? si->channel: 18;
2953 memset(&record, 0, sizeof(record));
2954 record.handle = si->handle;
2956 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2957 root = sdp_list_append(NULL, &root_uuid);
2958 sdp_set_browse_groups(&record, root);
2959 sdp_list_free(root, NULL);
2961 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2962 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
2964 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
2965 proto = sdp_list_append(proto, sdp_list_append(
2966 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
2968 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
2970 sdp_uuid16_create(&svclass_uuid, UDI_MT_SVCLASS_ID);
2971 svclass = sdp_list_append(NULL, &svclass_uuid);
2972 sdp_set_service_classes(&record, svclass);
2973 sdp_list_free(svclass, NULL);
2975 sdp_set_info_attr(&record, "UDI UE", NULL, NULL);
2977 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2978 printf("Service Record registration failed\n");
2982 printf("UDI UE service registered\n");
2987 static int add_udi_te(sdp_session_t *session, svc_info_t *si)
2989 sdp_record_t record;
2990 sdp_list_t *root, *svclass, *proto;
2991 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
2992 uint8_t channel = si->channel ? si->channel: 19;
2994 memset(&record, 0, sizeof(record));
2995 record.handle = si->handle;
2997 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2998 root = sdp_list_append(NULL, &root_uuid);
2999 sdp_set_browse_groups(&record, root);
3000 sdp_list_free(root, NULL);
3002 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3003 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3005 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3006 proto = sdp_list_append(proto, sdp_list_append(
3007 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3009 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3011 sdp_uuid16_create(&svclass_uuid, UDI_TA_SVCLASS_ID);
3012 svclass = sdp_list_append(NULL, &svclass_uuid);
3013 sdp_set_service_classes(&record, svclass);
3014 sdp_list_free(svclass, NULL);
3016 sdp_set_info_attr(&record, "UDI TE", NULL, NULL);
3018 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3019 printf("Service Record registration failed\n");
3023 printf("UDI TE service registered\n");
3028 static unsigned char sr1_uuid[] = { 0xbc, 0x19, 0x9c, 0x24, 0x95, 0x8b, 0x4c, 0xc0,
3029 0xa2, 0xcb, 0xfd, 0x8a, 0x30, 0xbf, 0x32, 0x06 };
3031 static int add_sr1(sdp_session_t *session, svc_info_t *si)
3033 sdp_record_t record;
3034 sdp_list_t *root, *svclass;
3035 uuid_t root_uuid, svclass_uuid;
3037 memset(&record, 0, sizeof(record));
3038 record.handle = si->handle;
3040 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3041 root = sdp_list_append(NULL, &root_uuid);
3042 sdp_set_browse_groups(&record, root);
3044 sdp_uuid128_create(&svclass_uuid, (void *) sr1_uuid);
3045 svclass = sdp_list_append(NULL, &svclass_uuid);
3046 sdp_set_service_classes(&record, svclass);
3048 sdp_set_info_attr(&record, "TOSHIBA SR-1", NULL, NULL);
3050 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3051 printf("Service Record registration failed\n");
3055 printf("Toshiba Speech Recognition SR-1 service record registered\n");
3060 static unsigned char syncmls_uuid[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
3061 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
3063 static unsigned char syncmlc_uuid[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
3064 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
3066 static int add_syncml(sdp_session_t *session, svc_info_t *si)
3068 sdp_record_t record;
3069 sdp_list_t *root, *svclass, *proto;
3070 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
3071 uint8_t channel = si->channel ? si->channel: 15;
3073 memset(&record, 0, sizeof(record));
3074 record.handle = si->handle;
3076 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3077 root = sdp_list_append(NULL, &root_uuid);
3078 sdp_set_browse_groups(&record, root);
3080 sdp_uuid128_create(&svclass_uuid, (void *) syncmlc_uuid);
3081 svclass = sdp_list_append(NULL, &svclass_uuid);
3082 sdp_set_service_classes(&record, svclass);
3084 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3085 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3087 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3088 proto = sdp_list_append(proto, sdp_list_append(
3089 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3091 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
3092 proto = sdp_list_append(proto, sdp_list_append(NULL, &obex_uuid));
3094 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3096 sdp_set_info_attr(&record, "SyncML Client", NULL, NULL);
3098 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3099 printf("Service Record registration failed\n");
3103 printf("SyncML Client service record registered\n");
3108 static unsigned char async_uuid[] = { 0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62,
3109 0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C };
3111 static int add_activesync(sdp_session_t *session, svc_info_t *si)
3113 sdp_record_t record;
3114 sdp_list_t *root, *svclass, *proto;
3115 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3116 uint8_t channel = si->channel ? si->channel: 21;
3118 memset(&record, 0, sizeof(record));
3119 record.handle = si->handle;
3121 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3122 root = sdp_list_append(NULL, &root_uuid);
3123 sdp_set_browse_groups(&record, root);
3125 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3126 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3128 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3129 proto = sdp_list_append(proto, sdp_list_append(
3130 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3132 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3134 sdp_uuid128_create(&svclass_uuid, (void *) async_uuid);
3135 svclass = sdp_list_append(NULL, &svclass_uuid);
3136 sdp_set_service_classes(&record, svclass);
3138 sdp_set_info_attr(&record, "Microsoft ActiveSync", NULL, NULL);
3140 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3141 printf("Service Record registration failed\n");
3145 printf("ActiveSync service record registered\n");
3150 static unsigned char hotsync_uuid[] = { 0xD8, 0x0C, 0xF9, 0xEA, 0x13, 0x4C, 0x11, 0xD5,
3151 0x83, 0xCE, 0x00, 0x30, 0x65, 0x7C, 0x54, 0x3C };
3153 static int add_hotsync(sdp_session_t *session, svc_info_t *si)
3155 sdp_record_t record;
3156 sdp_list_t *root, *svclass, *proto;
3157 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3158 uint8_t channel = si->channel ? si->channel: 22;
3160 memset(&record, 0, sizeof(record));
3161 record.handle = si->handle;
3163 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3164 root = sdp_list_append(NULL, &root_uuid);
3165 sdp_set_browse_groups(&record, root);
3167 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3168 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3170 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3171 proto = sdp_list_append(proto, sdp_list_append(
3172 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3174 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3176 sdp_uuid128_create(&svclass_uuid, (void *) hotsync_uuid);
3177 svclass = sdp_list_append(NULL, &svclass_uuid);
3178 sdp_set_service_classes(&record, svclass);
3180 sdp_set_info_attr(&record, "PalmOS HotSync", NULL, NULL);
3182 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3183 printf("Service Record registration failed\n");
3187 printf("HotSync service record registered\n");
3192 static unsigned char palmos_uuid[] = { 0xF5, 0xBE, 0xB6, 0x51, 0x41, 0x71, 0x40, 0x51,
3193 0xAC, 0xF5, 0x6C, 0xA7, 0x20, 0x22, 0x42, 0xF0 };
3195 static int add_palmos(sdp_session_t *session, svc_info_t *si)
3197 sdp_record_t record;
3198 sdp_list_t *root, *svclass;
3199 uuid_t root_uuid, svclass_uuid;
3201 memset(&record, 0, sizeof(record));
3202 record.handle = si->handle;
3204 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3205 root = sdp_list_append(NULL, &root_uuid);
3206 sdp_set_browse_groups(&record, root);
3208 sdp_uuid128_create(&svclass_uuid, (void *) palmos_uuid);
3209 svclass = sdp_list_append(NULL, &svclass_uuid);
3210 sdp_set_service_classes(&record, svclass);
3212 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3213 printf("Service Record registration failed\n");
3217 printf("PalmOS service record registered\n");
3222 static unsigned char nokid_uuid[] = { 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x10, 0x00,
3223 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3225 static int add_nokiaid(sdp_session_t *session, svc_info_t *si)
3227 sdp_record_t record;
3228 sdp_list_t *root, *svclass;
3229 uuid_t root_uuid, svclass_uuid;
3230 uint16_t verid = 0x005f;
3231 sdp_data_t *version = sdp_data_alloc(SDP_UINT16, &verid);
3233 memset(&record, 0, sizeof(record));
3234 record.handle = si->handle;
3236 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3237 root = sdp_list_append(NULL, &root_uuid);
3238 sdp_set_browse_groups(&record, root);
3240 sdp_uuid128_create(&svclass_uuid, (void *) nokid_uuid);
3241 svclass = sdp_list_append(NULL, &svclass_uuid);
3242 sdp_set_service_classes(&record, svclass);
3244 sdp_attr_add(&record, SDP_ATTR_SERVICE_VERSION, version);
3246 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3247 printf("Service Record registration failed\n");
3248 sdp_data_free(version);
3252 printf("Nokia ID service record registered\n");
3257 static unsigned char pcsuite_uuid[] = { 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x10, 0x00,
3258 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3260 static int add_pcsuite(sdp_session_t *session, svc_info_t *si)
3262 sdp_record_t record;
3263 sdp_list_t *root, *svclass, *proto;
3264 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3265 uint8_t channel = si->channel ? si->channel: 14;
3267 memset(&record, 0, sizeof(record));
3268 record.handle = si->handle;
3270 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3271 root = sdp_list_append(NULL, &root_uuid);
3272 sdp_set_browse_groups(&record, root);
3274 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3275 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3277 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3278 proto = sdp_list_append(proto, sdp_list_append(
3279 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3281 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3283 sdp_uuid128_create(&svclass_uuid, (void *) pcsuite_uuid);
3284 svclass = sdp_list_append(NULL, &svclass_uuid);
3285 sdp_set_service_classes(&record, svclass);
3287 sdp_set_info_attr(&record, "Nokia PC Suite", NULL, NULL);
3289 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3290 printf("Service Record registration failed\n");
3294 printf("Nokia PC Suite service registered\n");
3299 static unsigned char nftp_uuid[] = { 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x10, 0x00,
3300 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3302 static unsigned char nsyncml_uuid[] = { 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x10, 0x00,
3303 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3305 static unsigned char ngage_uuid[] = { 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x10, 0x00,
3306 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3308 static unsigned char apple_uuid[] = { 0xf0, 0x72, 0x2e, 0x20, 0x0f, 0x8b, 0x4e, 0x90,
3309 0x8c, 0xc2, 0x1b, 0x46, 0xf5, 0xf2, 0xef, 0xe2 };
3311 static unsigned char iap_uuid[] = { 0x00, 0x00, 0x00, 0x00, 0xde, 0xca, 0xfa, 0xde,
3312 0xde, 0xca, 0xde, 0xaf, 0xde, 0xca, 0xca, 0xfe };
3314 static int add_apple(sdp_session_t *session, svc_info_t *si)
3316 sdp_record_t record;
3319 uint32_t attr783 = 0x00000000;
3320 uint32_t attr785 = 0x00000002;
3321 uint16_t attr786 = 0x1234;
3323 memset(&record, 0, sizeof(record));
3324 record.handle = si->handle;
3326 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3327 root = sdp_list_append(NULL, &root_uuid);
3328 sdp_set_browse_groups(&record, root);
3330 sdp_attr_add_new(&record, 0x0780, SDP_UUID128, (void *) apple_uuid);
3331 sdp_attr_add_new(&record, 0x0781, SDP_TEXT_STR8, (void *) "Macmini");
3332 sdp_attr_add_new(&record, 0x0782, SDP_TEXT_STR8, (void *) "PowerMac10,1");
3333 sdp_attr_add_new(&record, 0x0783, SDP_UINT32, (void *) &attr783);
3334 sdp_attr_add_new(&record, 0x0784, SDP_TEXT_STR8, (void *) "1.6.6f22");
3335 sdp_attr_add_new(&record, 0x0785, SDP_UINT32, (void *) &attr785);
3336 sdp_attr_add_new(&record, 0x0786, SDP_UUID16, (void *) &attr786);
3338 sdp_set_info_attr(&record, "Apple Macintosh Attributes", NULL, NULL);
3340 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3341 printf("Service Record registration failed\n");
3345 printf("Apple attribute service registered\n");
3350 static int add_isync(sdp_session_t *session, svc_info_t *si)
3352 sdp_record_t record;
3353 sdp_list_t *root, *svclass, *proto;
3354 uuid_t root_uuid, svclass_uuid, serial_uuid, l2cap_uuid, rfcomm_uuid;
3355 uint8_t channel = si->channel ? si->channel : 16;
3357 memset(&record, 0, sizeof(record));
3358 record.handle = si->handle;
3360 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3361 root = sdp_list_append(NULL, &root_uuid);
3362 sdp_set_browse_groups(&record, root);
3364 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3365 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3367 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3368 proto = sdp_list_append(proto, sdp_list_append(
3369 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3371 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3373 sdp_uuid16_create(&serial_uuid, SERIAL_PORT_SVCLASS_ID);
3374 svclass = sdp_list_append(NULL, &serial_uuid);
3376 sdp_uuid16_create(&svclass_uuid, APPLE_AGENT_SVCLASS_ID);
3377 svclass = sdp_list_append(svclass, &svclass_uuid);
3379 sdp_set_service_classes(&record, svclass);
3381 sdp_set_info_attr(&record, "AppleAgent", "Bluetooth acceptor", "Apple Computer Ltd.");
3383 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3384 printf("Service Record registration failed\n");
3388 printf("Apple iSync service registered\n");
3393 static int add_semchla(sdp_session_t *session, svc_info_t *si)
3395 sdp_record_t record;
3396 sdp_profile_desc_t profile;
3397 sdp_list_t *root, *svclass, *proto, *profiles;
3398 uuid_t root_uuid, service_uuid, l2cap_uuid, semchla_uuid;
3399 uint16_t psm = 0xf0f9;
3401 memset(&record, 0, sizeof(record));
3402 record.handle = si->handle;
3404 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3405 root = sdp_list_append(NULL, &root_uuid);
3406 sdp_set_browse_groups(&record, root);
3408 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3409 proto = sdp_list_append(NULL, sdp_list_append(
3410 sdp_list_append(NULL, &l2cap_uuid), sdp_data_alloc(SDP_UINT16, &psm)));
3412 sdp_uuid32_create(&semchla_uuid, 0x8e770300);
3413 proto = sdp_list_append(proto, sdp_list_append(NULL, &semchla_uuid));
3415 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3417 sdp_uuid32_create(&service_uuid, 0x8e771301);
3418 svclass = sdp_list_append(NULL, &service_uuid);
3420 sdp_set_service_classes(&record, svclass);
3422 sdp_uuid32_create(&profile.uuid, 0x8e771302); // Headset
3423 //sdp_uuid32_create(&profile.uuid, 0x8e771303); // Phone
3424 profile.version = 0x0100;
3425 profiles = sdp_list_append(NULL, &profile);
3426 sdp_set_profile_descs(&record, profiles);
3428 sdp_set_info_attr(&record, "SEMC HLA", NULL, NULL);
3430 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3431 printf("Service Record registration failed\n");
3435 /* SEMC High Level Authentication */
3436 printf("SEMC HLA service registered\n");
3441 static int add_gatt(sdp_session_t *session, svc_info_t *si)
3443 sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
3444 uuid_t root_uuid, proto_uuid, gatt_uuid, l2cap;
3445 sdp_profile_desc_t profile;
3446 sdp_record_t record;
3447 sdp_data_t *psm, *sh, *eh;
3448 uint16_t att_psm = 27, start = 0x0001, end = 0x000f;
3451 memset(&record, 0, sizeof(sdp_record_t));
3452 record.handle = si->handle;
3453 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3454 root = sdp_list_append(NULL, &root_uuid);
3455 sdp_set_browse_groups(&record, root);
3456 sdp_list_free(root, NULL);
3458 sdp_uuid16_create(&gatt_uuid, GENERIC_ATTRIB_SVCLASS_ID);
3459 svclass_id = sdp_list_append(NULL, &gatt_uuid);
3460 sdp_set_service_classes(&record, svclass_id);
3461 sdp_list_free(svclass_id, NULL);
3463 sdp_uuid16_create(&profile.uuid, GENERIC_ATTRIB_PROFILE_ID);
3464 profile.version = 0x0100;
3465 profiles = sdp_list_append(NULL, &profile);
3466 sdp_set_profile_descs(&record, profiles);
3467 sdp_list_free(profiles, NULL);
3469 sdp_uuid16_create(&l2cap, L2CAP_UUID);
3470 proto[0] = sdp_list_append(NULL, &l2cap);
3471 psm = sdp_data_alloc(SDP_UINT16, &att_psm);
3472 proto[0] = sdp_list_append(proto[0], psm);
3473 apseq = sdp_list_append(NULL, proto[0]);
3475 sdp_uuid16_create(&proto_uuid, ATT_UUID);
3476 proto[1] = sdp_list_append(NULL, &proto_uuid);
3477 sh = sdp_data_alloc(SDP_UINT16, &start);
3478 proto[1] = sdp_list_append(proto[1], sh);
3479 eh = sdp_data_alloc(SDP_UINT16, &end);
3480 proto[1] = sdp_list_append(proto[1], eh);
3481 apseq = sdp_list_append(apseq, proto[1]);
3483 aproto = sdp_list_append(NULL, apseq);
3484 sdp_set_access_protos(&record, aproto);
3486 sdp_set_info_attr(&record, "Generic Attribute Profile", "BlueZ", NULL);
3488 sdp_set_url_attr(&record, "http://www.bluez.org/",
3489 "http://www.bluez.org/", "http://www.bluez.org/");
3491 sdp_set_service_id(&record, gatt_uuid);
3493 ret = sdp_device_record_register(session, &interface, &record,
3494 SDP_RECORD_PERSIST);
3496 printf("Service Record registration failed\n");
3498 printf("Generic Attribute Profile Service registered\n");
3503 sdp_list_free(proto[0], NULL);
3504 sdp_list_free(proto[1], NULL);
3505 sdp_list_free(apseq, NULL);
3506 sdp_list_free(aproto, NULL);
3514 int (*add)(sdp_session_t *sess, svc_info_t *si);
3515 unsigned char *uuid;
3517 { "DID", PNP_INFO_SVCLASS_ID, NULL, },
3519 { "SP", SERIAL_PORT_SVCLASS_ID, add_sp },
3520 { "DUN", DIALUP_NET_SVCLASS_ID, add_dun },
3521 { "LAN", LAN_ACCESS_SVCLASS_ID, add_lan },
3522 { "FAX", FAX_SVCLASS_ID, add_fax },
3523 { "OPUSH", OBEX_OBJPUSH_SVCLASS_ID, add_opush },
3524 { "FTP", OBEX_FILETRANS_SVCLASS_ID, add_ftp },
3525 { "PRINT", DIRECT_PRINTING_SVCLASS_ID, add_directprint },
3527 { "HS", HEADSET_SVCLASS_ID, add_headset },
3528 { "HSAG", HEADSET_AGW_SVCLASS_ID, add_headset_ag },
3529 { "HF", HANDSFREE_SVCLASS_ID, add_handsfree },
3530 { "HFAG", HANDSFREE_AGW_SVCLASS_ID, add_handsfree_ag},
3531 { "SAP", SAP_SVCLASS_ID, add_simaccess },
3532 { "PBAP", PBAP_SVCLASS_ID, add_pbap, },
3534 { "NAP", NAP_SVCLASS_ID, add_nap },
3535 { "GN", GN_SVCLASS_ID, add_gn },
3536 { "PANU", PANU_SVCLASS_ID, add_panu },
3538 { "HCRP", HCR_SVCLASS_ID, NULL },
3539 { "HID", HID_SVCLASS_ID, NULL },
3540 { "KEYB", HID_SVCLASS_ID, add_hid_keyb },
3541 { "WIIMOTE", HID_SVCLASS_ID, add_hid_wiimote },
3542 { "CIP", CIP_SVCLASS_ID, add_cip },
3543 { "CTP", CORDLESS_TELEPHONY_SVCLASS_ID, add_ctp },
3545 { "A2SRC", AUDIO_SOURCE_SVCLASS_ID, add_a2source },
3546 { "A2SNK", AUDIO_SINK_SVCLASS_ID, add_a2sink },
3547 { "AVRCT", AV_REMOTE_SVCLASS_ID, add_avrct },
3548 { "AVRTG", AV_REMOTE_TARGET_SVCLASS_ID, add_avrtg },
3550 { "UDIUE", UDI_MT_SVCLASS_ID, add_udi_ue },
3551 { "UDITE", UDI_TA_SVCLASS_ID, add_udi_te },
3553 { "SEMCHLA", 0x8e771301, add_semchla },
3555 { "SR1", 0, add_sr1, sr1_uuid },
3556 { "SYNCML", 0, add_syncml, syncmlc_uuid },
3557 { "SYNCMLSERV", 0, NULL, syncmls_uuid },
3558 { "ACTIVESYNC", 0, add_activesync, async_uuid },
3559 { "HOTSYNC", 0, add_hotsync, hotsync_uuid },
3560 { "PALMOS", 0, add_palmos, palmos_uuid },
3561 { "NOKID", 0, add_nokiaid, nokid_uuid },
3562 { "PCSUITE", 0, add_pcsuite, pcsuite_uuid },
3563 { "NFTP", 0, NULL, nftp_uuid },
3564 { "NSYNCML", 0, NULL, nsyncml_uuid },
3565 { "NGAGE", 0, NULL, ngage_uuid },
3566 { "APPLE", 0, add_apple, apple_uuid },
3567 { "IAP", 0, NULL, iap_uuid },
3569 { "ISYNC", APPLE_AGENT_SVCLASS_ID, add_isync, },
3570 { "GATT", GENERIC_ATTRIB_SVCLASS_ID, add_gatt, },
3575 /* Add local service */
3576 static int add_service(bdaddr_t *bdaddr, svc_info_t *si)
3578 sdp_session_t *sess;
3584 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
3588 for (i = 0; service[i].name; i++)
3589 if (!strcasecmp(service[i].name, si->name)) {
3591 ret = service[i].add(sess, si);
3595 printf("Unknown service name: %s\n", si->name);
3604 static struct option add_options[] = {
3605 { "help", 0, 0, 'h' },
3606 { "handle", 1, 0, 'r' },
3607 { "psm", 1, 0, 'p' },
3608 { "channel", 1, 0, 'c' },
3609 { "network", 1, 0, 'n' },
3613 static const char *add_help =
3615 "\tadd [--handle=RECORD_HANDLE --channel=CHANNEL] service\n";
3617 static int cmd_add(int argc, char **argv)
3622 memset(&si, 0, sizeof(si));
3623 si.handle = 0xffffffff;
3625 for_each_opt(opt, add_options, 0) {
3628 if (strncasecmp(optarg, "0x", 2))
3629 si.handle = atoi(optarg);
3631 si.handle = strtol(optarg + 2, NULL, 16);
3634 if (strncasecmp(optarg, "0x", 2))
3635 si.psm = atoi(optarg);
3637 si.psm = strtol(optarg + 2, NULL, 16);
3640 if (strncasecmp(optarg, "0x", 2))
3641 si.channel = atoi(optarg);
3643 si.channel = strtol(optarg + 2, NULL, 16);
3646 if (strncasecmp(optarg, "0x", 2))
3647 si.network = atoi(optarg);
3649 si.network = strtol(optarg + 2, NULL, 16);
3652 printf("%s", add_help);
3661 printf("%s", add_help);
3665 si.name = strdup(argv[0]);
3667 return add_service(0, &si);
3670 /* Delete local service */
3671 static int del_service(bdaddr_t *bdaddr, void *arg)
3673 uint32_t handle, range = 0x0000ffff;
3675 sdp_session_t *sess;
3679 printf("Record handle was not specified.\n");
3683 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
3685 printf("No local SDP server!\n");
3689 handle = strtoul((char *)arg, 0, 16);
3690 attr = sdp_list_append(0, &range);
3691 rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attr);
3692 sdp_list_free(attr, 0);
3695 printf("Service Record not found.\n");
3700 if (sdp_device_record_unregister(sess, &interface, rec)) {
3701 printf("Failed to unregister service record: %s\n", strerror(errno));
3706 printf("Service Record deleted.\n");
3712 static struct option del_options[] = {
3713 { "help", 0, 0, 'h' },
3717 static const char *del_help =
3719 "\tdel record_handle\n";
3721 static int cmd_del(int argc, char **argv)
3725 for_each_opt(opt, del_options, 0) {
3728 printf("%s", del_help);
3737 printf("%s", del_help);
3741 return del_service(NULL, argv[0]);
3745 * Perform an inquiry and search/browse all peer found.
3747 static void inquiry(handler_t handler, void *arg)
3749 inquiry_info ii[20];
3753 printf("Inquiring ...\n");
3754 if (sdp_general_inquiry(ii, 20, 8, &count) < 0) {
3755 printf("Inquiry failed\n");
3759 for (i = 0; i < count; i++)
3760 handler(&ii[i].bdaddr, arg);
3763 static void doprintf(void *data, const char *str)
3769 * Search for a specific SDP service
3771 static int do_search(bdaddr_t *bdaddr, struct search_context *context)
3773 sdp_list_t *attrid, *search, *seq, *next;
3774 uint32_t range = 0x0000ffff;
3776 sdp_session_t *sess;
3779 inquiry(do_search, context);
3783 sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
3784 ba2str(bdaddr, str);
3786 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
3790 if (context->view != RAW_VIEW) {
3792 printf("Searching for %s on %s ...\n", context->svc, str);
3794 printf("Browsing %s ...\n", str);
3797 attrid = sdp_list_append(0, &range);
3798 search = sdp_list_append(0, &context->group);
3799 if (sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq)) {
3800 printf("Service Search failed: %s\n", strerror(errno));
3801 sdp_list_free(attrid, 0);
3802 sdp_list_free(search, 0);
3806 sdp_list_free(attrid, 0);
3807 sdp_list_free(search, 0);
3809 for (; seq; seq = next) {
3810 sdp_record_t *rec = (sdp_record_t *) seq->data;
3811 struct search_context sub_context;
3813 switch (context->view) {
3815 /* Display user friendly form */
3816 print_service_attr(rec);
3820 /* Display full tree */
3821 print_tree_attr(rec);
3825 /* Display raw XML tree */
3826 convert_sdp_record_to_xml(rec, 0, doprintf);
3829 /* Display raw tree */
3830 print_raw_attr(rec);
3834 /* Set the subcontext for browsing the sub tree */
3835 memcpy(&sub_context, context, sizeof(struct search_context));
3837 if (sdp_get_group_id(rec, &sub_context.group) != -1) {
3838 /* Browse the next level down if not done */
3839 if (sub_context.group.value.uuid16 != context->group.value.uuid16)
3840 do_search(bdaddr, &sub_context);
3844 sdp_record_free(rec);
3851 static struct option browse_options[] = {
3852 { "help", 0, 0, 'h' },
3853 { "tree", 0, 0, 't' },
3854 { "raw", 0, 0, 'r' },
3855 { "xml", 0, 0, 'x' },
3856 { "uuid", 1, 0, 'u' },
3857 { "l2cap", 0, 0, 'l' },
3861 static const char *browse_help =
3863 "\tbrowse [--tree] [--raw] [--xml] [--uuid uuid] [--l2cap] [bdaddr]\n";
3866 * Browse the full SDP database (i.e. list all services starting from the
3869 static int cmd_browse(int argc, char **argv)
3871 struct search_context context;
3874 /* Initialise context */
3875 memset(&context, '\0', sizeof(struct search_context));
3876 /* We want to browse the top-level/root */
3877 sdp_uuid16_create(&context.group, PUBLIC_BROWSE_GROUP);
3879 for_each_opt(opt, browse_options, 0) {
3882 context.view = TREE_VIEW;
3885 context.view = RAW_VIEW;
3888 context.view = XML_VIEW;
3891 if (sscanf(optarg, "%i", &num) != 1 || num < 0 || num > 0xffff) {
3892 printf("Invalid uuid %s\n", optarg);
3895 sdp_uuid16_create(&context.group, num);
3898 sdp_uuid16_create(&context.group, L2CAP_UUID);
3901 printf("%s", browse_help);
3911 estr2ba(argv[0], &bdaddr);
3912 return do_search(&bdaddr, &context);
3915 return do_search(NULL, &context);
3918 static struct option search_options[] = {
3919 { "help", 0, 0, 'h' },
3920 { "bdaddr", 1, 0, 'b' },
3921 { "tree", 0, 0, 't' },
3922 { "raw", 0, 0, 'r' },
3923 { "xml", 0, 0, 'x' },
3927 static const char *search_help =
3929 "\tsearch [--bdaddr bdaddr] [--tree] [--raw] [--xml] SERVICE\n"
3930 "SERVICE is a name (string) or UUID (0x1002)\n";
3933 * Search for a specific SDP service
3935 * Note : we should support multiple services on the command line :
3936 * sdptool search 0x0100 0x000f 0x1002
3937 * (this would search a service supporting both L2CAP and BNEP directly in
3938 * the top level browse group)
3940 static int cmd_search(int argc, char **argv)
3942 struct search_context context;
3943 unsigned char *uuid = NULL;
3950 /* Initialise context */
3951 memset(&context, '\0', sizeof(struct search_context));
3953 for_each_opt(opt, search_options, 0) {
3956 estr2ba(optarg, &bdaddr);
3960 context.view = TREE_VIEW;
3963 context.view = RAW_VIEW;
3966 context.view = XML_VIEW;
3969 printf("%s", search_help);
3978 printf("%s", search_help);
3982 /* Note : we need to find a way to support search combining
3983 * multiple services */
3984 context.svc = strdup(argv[0]);
3985 if (!strncasecmp(context.svc, "0x", 2)) {
3987 /* This is a UUID16, just convert to int */
3988 sscanf(context.svc + 2, "%X", &num);
3990 printf("Class 0x%X\n", class);
3992 /* Convert class name to an UUID */
3994 for (i = 0; service[i].name; i++)
3995 if (strcasecmp(context.svc, service[i].name) == 0) {
3996 class = service[i].class;
3997 uuid = service[i].uuid;
4000 if (!class && !uuid) {
4001 printf("Unknown service %s\n", context.svc);
4007 if (class & 0xffff0000)
4008 sdp_uuid32_create(&context.group, class);
4010 uint16_t class16 = class & 0xffff;
4011 sdp_uuid16_create(&context.group, class16);
4014 sdp_uuid128_create(&context.group, uuid);
4017 return do_search(&bdaddr, &context);
4019 return do_search(NULL, &context);
4023 * Show how to get a specific SDP record by its handle.
4024 * Not really useful to the user, just show how it can be done...
4026 static int get_service(bdaddr_t *bdaddr, struct search_context *context, int quite)
4029 uint32_t range = 0x0000ffff;
4031 sdp_session_t *session = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
4035 ba2str(bdaddr, str);
4036 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
4040 attrid = sdp_list_append(0, &range);
4041 rec = sdp_service_attr_req(session, context->handle, SDP_ATTR_REQ_RANGE, attrid);
4042 sdp_list_free(attrid, 0);
4047 printf("Service get request failed.\n");
4053 switch (context->view) {
4055 /* Display user friendly form */
4056 print_service_attr(rec);
4060 /* Display full tree */
4061 print_tree_attr(rec);
4065 /* Display raw XML tree */
4066 convert_sdp_record_to_xml(rec, 0, doprintf);
4069 /* Display raw tree */
4070 print_raw_attr(rec);
4074 sdp_record_free(rec);
4078 static struct option records_options[] = {
4079 { "help", 0, 0, 'h' },
4080 { "tree", 0, 0, 't' },
4081 { "raw", 0, 0, 'r' },
4082 { "xml", 0, 0, 'x' },
4086 static const char *records_help =
4088 "\trecords [--tree] [--raw] [--xml] bdaddr\n";
4091 * Request possible SDP service records
4093 static int cmd_records(int argc, char **argv)
4095 struct search_context context;
4096 uint32_t base[] = { 0x10000, 0x10300, 0x10500,
4097 0x1002e, 0x110b, 0x90000, 0x2008000,
4098 0x4000000, 0x100000, 0x1000000,
4099 0x4f491100, 0x4f491200 };
4101 unsigned int i, n, num = 32;
4104 /* Initialise context */
4105 memset(&context, '\0', sizeof(struct search_context));
4107 for_each_opt(opt, records_options, 0) {
4110 context.view = TREE_VIEW;
4113 context.view = RAW_VIEW;
4116 context.view = XML_VIEW;
4119 printf("%s", records_help);
4128 printf("%s", records_help);
4132 /* Convert command line parameters */
4133 estr2ba(argv[0], &bdaddr);
4135 for (i = 0; i < sizeof(base) / sizeof(uint32_t); i++)
4136 for (n = 0; n < num; n++) {
4137 context.handle = base[i] + n;
4138 err = get_service(&bdaddr, &context, 1);
4146 static struct option get_options[] = {
4147 { "help", 0, 0, 'h' },
4148 { "bdaddr", 1, 0, 'b' },
4149 { "tree", 0, 0, 't' },
4150 { "raw", 0, 0, 'r' },
4151 { "xml", 0, 0, 'x' },
4155 static const char *get_help =
4157 "\tget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\n";
4160 * Get a specific SDP record on the local SDP server
4162 static int cmd_get(int argc, char **argv)
4164 struct search_context context;
4169 /* Initialise context */
4170 memset(&context, '\0', sizeof(struct search_context));
4172 for_each_opt(opt, get_options, 0) {
4175 estr2ba(optarg, &bdaddr);
4179 context.view = TREE_VIEW;
4182 context.view = RAW_VIEW;
4185 context.view = XML_VIEW;
4188 printf("%s", get_help);
4197 printf("%s", get_help);
4201 /* Convert command line parameters */
4202 context.handle = strtoul(argv[0], 0, 16);
4204 return get_service(has_addr ? &bdaddr : BDADDR_LOCAL, &context, 0);
4209 int (*func)(int argc, char **argv);
4212 { "search", cmd_search, "Search for a service" },
4213 { "browse", cmd_browse, "Browse all available services" },
4214 { "records", cmd_records, "Request all records" },
4215 { "add", cmd_add, "Add local service" },
4216 { "del", cmd_del, "Delete local service" },
4217 { "get", cmd_get, "Get local service" },
4218 { "setattr", cmd_setattr, "Set/Add attribute to a SDP record" },
4219 { "setseq", cmd_setseq, "Set/Add attribute sequence to a SDP record" },
4223 static void usage(void)
4227 printf("sdptool - SDP tool v%s\n", VERSION);
4229 "\tsdptool [options] <command> [command parameters]\n");
4231 "\t-h\t\tDisplay help\n"
4232 "\t-i\t\tSpecify source interface\n");
4234 printf("Commands:\n");
4235 for (i = 0; command[i].cmd; i++)
4236 printf("\t%-4s\t\t%s\n", command[i].cmd, command[i].doc);
4238 printf("\nServices:\n\t");
4239 for (i = 0; service[i].name; i++) {
4240 printf("%s ", service[i].name);
4241 pos += strlen(service[i].name) + 1;
4250 static struct option main_options[] = {
4251 { "help", 0, 0, 'h' },
4252 { "device", 1, 0, 'i' },
4256 int main(int argc, char *argv[])
4260 bacpy(&interface, BDADDR_ANY);
4262 while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
4265 if (!strncmp(optarg, "hci", 3))
4266 hci_devba(atoi(optarg + 3), &interface);
4268 str2ba(optarg, &interface);
4289 for (i = 0; command[i].cmd; i++)
4290 if (strncmp(command[i].cmd, argv[0], 4) == 0)
4291 return command[i].func(argc, argv);