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-2009 Marcel Holtmann <marcel@holtmann.org>
8 * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
9 * Copyright (C) 2002-2003 Jean Tourrilhes <jt@hpl.hp.com>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
38 #include <sys/socket.h>
40 #include <bluetooth/bluetooth.h>
41 #include <bluetooth/hci.h>
42 #include <bluetooth/hci_lib.h>
43 #include <bluetooth/sdp.h>
44 #include <bluetooth/sdp_lib.h>
46 #include <netinet/in.h>
50 #ifndef APPLE_AGENT_SVCLASS_ID
51 #define APPLE_AGENT_SVCLASS_ID 0x2112
54 #define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, 0)) != -1)
57 * Convert a string to a BDADDR, with a few "enhancements" - Jean II
59 static int estr2ba(char *str, bdaddr_t *ba)
61 /* Only trap "local", "any" is already dealt with */
62 if(!strcmp(str, "local")) {
63 bacpy(ba, BDADDR_LOCAL);
66 return str2ba(str, ba);
69 #define DEFAULT_VIEW 0 /* Display only known attribute */
70 #define TREE_VIEW 1 /* Display full attribute tree */
71 #define RAW_VIEW 2 /* Display raw tree */
72 #define XML_VIEW 3 /* Display xml tree */
74 /* Pass args to the inquiry/search handler */
75 struct search_context {
76 char *svc; /* Service */
77 uuid_t group; /* Browse group */
78 int view; /* View mode */
79 uint32_t handle; /* Service record handle */
82 typedef int (*handler_t)(bdaddr_t *bdaddr, struct search_context *arg);
84 static char UUID_str[MAX_LEN_UUID_STR];
85 static bdaddr_t interface;
87 /* Definition of attribute members */
92 /* Definition of an attribute */
94 int num; /* Numeric ID - 16 bits */
95 char *name; /* User readable name */
96 struct member_def *members; /* Definition of attribute args */
97 int member_max; /* Max of attribute arg definitions */
100 /* Definition of a service or protocol */
102 int num; /* Numeric ID - 16 bits */
103 char *name; /* User readable name */
104 struct attrib_def *attribs; /* Specific attribute definitions */
105 int attrib_max; /* Max of attribute definitions */
108 /* Context information about current attribute */
109 struct attrib_context {
110 struct uuid_def *service; /* Service UUID, if known */
111 struct attrib_def *attrib; /* Description of the attribute */
112 int member_index; /* Index of current attribute member */
115 /* Context information about the whole service */
116 struct service_context {
117 struct uuid_def *service; /* Service UUID, if known */
120 /* Allow us to do nice formatting of the lists */
121 static char *indent_spaces = " ";
123 /* ID of the service attribute.
124 * Most attributes after 0x200 are defined based on the service, so
125 * we need to find what is the service (which is messy) - Jean II */
126 #define SERVICE_ATTR 0x1
128 /* Definition of the optional arguments in protocol list */
129 static struct member_def protocol_members[] = {
135 /* Definition of the optional arguments in profile list */
136 static struct member_def profile_members[] = {
141 /* Definition of the optional arguments in Language list */
142 static struct member_def language_members[] = {
148 /* Name of the various common attributes. See BT assigned numbers */
149 static struct attrib_def attrib_names[] = {
150 { 0x0, "ServiceRecordHandle", NULL, 0 },
151 { 0x1, "ServiceClassIDList", NULL, 0 },
152 { 0x2, "ServiceRecordState", NULL, 0 },
153 { 0x3, "ServiceID", NULL, 0 },
154 { 0x4, "ProtocolDescriptorList",
155 protocol_members, sizeof(protocol_members)/sizeof(struct member_def) },
156 { 0x5, "BrowseGroupList", NULL, 0 },
157 { 0x6, "LanguageBaseAttributeIDList",
158 language_members, sizeof(language_members)/sizeof(struct member_def) },
159 { 0x7, "ServiceInfoTimeToLive", NULL, 0 },
160 { 0x8, "ServiceAvailability", NULL, 0 },
161 { 0x9, "BluetoothProfileDescriptorList",
162 profile_members, sizeof(profile_members)/sizeof(struct member_def) },
163 { 0xA, "DocumentationURL", NULL, 0 },
164 { 0xB, "ClientExecutableURL", NULL, 0 },
165 { 0xC, "IconURL", NULL, 0 },
166 { 0xD, "AdditionalProtocolDescriptorLists", NULL, 0 },
167 /* Definitions after that are tricky (per profile or offset) */
170 const int attrib_max = sizeof(attrib_names)/sizeof(struct attrib_def);
172 /* Name of the various SPD attributes. See BT assigned numbers */
173 static struct attrib_def sdp_attrib_names[] = {
174 { 0x200, "VersionNumberList", NULL, 0 },
175 { 0x201, "ServiceDatabaseState", NULL, 0 },
178 /* Name of the various SPD attributes. See BT assigned numbers */
179 static struct attrib_def browse_attrib_names[] = {
180 { 0x200, "GroupID", NULL, 0 },
183 /* Name of the various Device ID attributes. See Device Id spec. */
184 static struct attrib_def did_attrib_names[] = {
185 { 0x200, "SpecificationID", NULL, 0 },
186 { 0x201, "VendorID", NULL, 0 },
187 { 0x202, "ProductID", NULL, 0 },
188 { 0x203, "Version", NULL, 0 },
189 { 0x204, "PrimaryRecord", NULL, 0 },
190 { 0x205, "VendorIDSource", NULL, 0 },
193 /* Name of the various HID attributes. See HID spec. */
194 static struct attrib_def hid_attrib_names[] = {
195 { 0x200, "DeviceReleaseNum", NULL, 0 },
196 { 0x201, "ParserVersion", NULL, 0 },
197 { 0x202, "DeviceSubclass", NULL, 0 },
198 { 0x203, "CountryCode", NULL, 0 },
199 { 0x204, "VirtualCable", NULL, 0 },
200 { 0x205, "ReconnectInitiate", NULL, 0 },
201 { 0x206, "DescriptorList", NULL, 0 },
202 { 0x207, "LangIDBaseList", NULL, 0 },
203 { 0x208, "SDPDisable", NULL, 0 },
204 { 0x209, "BatteryPower", NULL, 0 },
205 { 0x20a, "RemoteWakeup", NULL, 0 },
206 { 0x20b, "ProfileVersion", NULL, 0 },
207 { 0x20c, "SupervisionTimeout", NULL, 0 },
208 { 0x20d, "NormallyConnectable", NULL, 0 },
209 { 0x20e, "BootDevice", NULL, 0 },
212 /* Name of the various PAN attributes. See BT assigned numbers */
213 /* Note : those need to be double checked - Jean II */
214 static struct attrib_def pan_attrib_names[] = {
215 { 0x200, "IpSubnet", NULL, 0 }, /* Obsolete ??? */
216 { 0x30A, "SecurityDescription", NULL, 0 },
217 { 0x30B, "NetAccessType", NULL, 0 },
218 { 0x30C, "MaxNetAccessrate", NULL, 0 },
219 { 0x30D, "IPv4Subnet", NULL, 0 },
220 { 0x30E, "IPv6Subnet", NULL, 0 },
223 /* Name of the various Generic-Audio attributes. See BT assigned numbers */
224 /* Note : totally untested - Jean II */
225 static struct attrib_def audio_attrib_names[] = {
226 { 0x302, "Remote audio volume control", NULL, 0 },
229 /* Same for the UUIDs. See BT assigned numbers */
230 static struct uuid_def uuid16_names[] = {
231 /* -- Protocols -- */
232 { 0x0001, "SDP", NULL, 0 },
233 { 0x0002, "UDP", NULL, 0 },
234 { 0x0003, "RFCOMM", NULL, 0 },
235 { 0x0004, "TCP", NULL, 0 },
236 { 0x0005, "TCS-BIN", NULL, 0 },
237 { 0x0006, "TCS-AT", NULL, 0 },
238 { 0x0008, "OBEX", NULL, 0 },
239 { 0x0009, "IP", NULL, 0 },
240 { 0x000a, "FTP", NULL, 0 },
241 { 0x000c, "HTTP", NULL, 0 },
242 { 0x000e, "WSP", NULL, 0 },
243 { 0x000f, "BNEP", NULL, 0 },
244 { 0x0010, "UPnP/ESDP", NULL, 0 },
245 { 0x0011, "HIDP", NULL, 0 },
246 { 0x0012, "HardcopyControlChannel", NULL, 0 },
247 { 0x0014, "HardcopyDataChannel", NULL, 0 },
248 { 0x0016, "HardcopyNotification", NULL, 0 },
249 { 0x0017, "AVCTP", NULL, 0 },
250 { 0x0019, "AVDTP", NULL, 0 },
251 { 0x001b, "CMTP", NULL, 0 },
252 { 0x001d, "UDI_C-Plane", NULL, 0 },
253 { 0x0100, "L2CAP", NULL, 0 },
255 { 0x1000, "ServiceDiscoveryServerServiceClassID",
256 sdp_attrib_names, sizeof(sdp_attrib_names)/sizeof(struct attrib_def) },
257 { 0x1001, "BrowseGroupDescriptorServiceClassID",
258 browse_attrib_names, sizeof(browse_attrib_names)/sizeof(struct attrib_def) },
259 { 0x1002, "PublicBrowseGroup", NULL, 0 },
260 { 0x1101, "SerialPort", NULL, 0 },
261 { 0x1102, "LANAccessUsingPPP", NULL, 0 },
262 { 0x1103, "DialupNetworking (DUN)", NULL, 0 },
263 { 0x1104, "IrMCSync", NULL, 0 },
264 { 0x1105, "OBEXObjectPush", NULL, 0 },
265 { 0x1106, "OBEXFileTransfer", NULL, 0 },
266 { 0x1107, "IrMCSyncCommand", NULL, 0 },
268 audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },
269 { 0x1109, "CordlessTelephony", NULL, 0 },
270 { 0x110a, "AudioSource", NULL, 0 },
271 { 0x110b, "AudioSink", NULL, 0 },
272 { 0x110c, "RemoteControlTarget", NULL, 0 },
273 { 0x110d, "AdvancedAudio", NULL, 0 },
274 { 0x110e, "RemoteControl", NULL, 0 },
275 { 0x110f, "VideoConferencing", NULL, 0 },
276 { 0x1110, "Intercom", NULL, 0 },
277 { 0x1111, "Fax", NULL, 0 },
278 { 0x1112, "HeadsetAudioGateway", NULL, 0 },
279 { 0x1113, "WAP", NULL, 0 },
280 { 0x1114, "WAP Client", NULL, 0 },
281 { 0x1115, "PANU (PAN/BNEP)",
282 pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
283 { 0x1116, "NAP (PAN/BNEP)",
284 pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
285 { 0x1117, "GN (PAN/BNEP)",
286 pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
287 { 0x1118, "DirectPrinting (BPP)", NULL, 0 },
288 { 0x1119, "ReferencePrinting (BPP)", NULL, 0 },
289 { 0x111a, "Imaging (BIP)", NULL, 0 },
290 { 0x111b, "ImagingResponder (BIP)", NULL, 0 },
291 { 0x111c, "ImagingAutomaticArchive (BIP)", NULL, 0 },
292 { 0x111d, "ImagingReferencedObjects (BIP)", NULL, 0 },
293 { 0x111e, "Handsfree", NULL, 0 },
294 { 0x111f, "HandsfreeAudioGateway", NULL, 0 },
295 { 0x1120, "DirectPrintingReferenceObjectsService (BPP)", NULL, 0 },
296 { 0x1121, "ReflectedUI (BPP)", NULL, 0 },
297 { 0x1122, "BasicPrinting (BPP)", NULL, 0 },
298 { 0x1123, "PrintingStatus (BPP)", NULL, 0 },
299 { 0x1124, "HumanInterfaceDeviceService (HID)",
300 hid_attrib_names, sizeof(hid_attrib_names)/sizeof(struct attrib_def) },
301 { 0x1125, "HardcopyCableReplacement (HCR)", NULL, 0 },
302 { 0x1126, "HCR_Print (HCR)", NULL, 0 },
303 { 0x1127, "HCR_Scan (HCR)", NULL, 0 },
304 { 0x1128, "Common ISDN Access (CIP)", NULL, 0 },
305 { 0x1129, "VideoConferencingGW (VCP)", NULL, 0 },
306 { 0x112a, "UDI-MT", NULL, 0 },
307 { 0x112b, "UDI-TA", NULL, 0 },
308 { 0x112c, "Audio/Video", NULL, 0 },
309 { 0x112d, "SIM Access (SAP)", NULL, 0 },
310 { 0x112e, "Phonebook Access (PBAP) - PCE", NULL, 0 },
311 { 0x112f, "Phonebook Access (PBAP) - PSE", NULL, 0 },
312 { 0x1130, "Phonebook Access (PBAP)", NULL, 0 },
314 { 0x1200, "PnPInformation",
315 did_attrib_names, sizeof(did_attrib_names)/sizeof(struct attrib_def) },
316 { 0x1201, "GenericNetworking", NULL, 0 },
317 { 0x1202, "GenericFileTransfer", NULL, 0 },
318 { 0x1203, "GenericAudio",
319 audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },
320 { 0x1204, "GenericTelephony", NULL, 0 },
322 { 0x1303, "VideoSource", NULL, 0 },
323 { 0x1304, "VideoSink", NULL, 0 },
324 { 0x1305, "VideoDistribution", NULL, 0 },
325 { 0x1400, "MDP", NULL, 0 },
326 { 0x1401, "MDPSource", NULL, 0 },
327 { 0x1402, "MDPSink", NULL, 0 },
328 { 0x2112, "AppleAgent", NULL, 0 },
331 static const int uuid16_max = sizeof(uuid16_names)/sizeof(struct uuid_def);
333 static void sdp_data_printf(sdp_data_t *, struct attrib_context *, int);
337 * The BT assigned numbers only list UUID16, so I'm not sure the
338 * other types will ever get used...
340 static void sdp_uuid_printf(uuid_t *uuid, struct attrib_context *context, int indent)
343 if (uuid->type == SDP_UUID16) {
344 uint16_t uuidNum = uuid->value.uuid16;
345 struct uuid_def *uuidDef = NULL;
348 for (i = 0; i < uuid16_max; i++)
349 if (uuid16_names[i].num == uuidNum) {
350 uuidDef = &uuid16_names[i];
354 /* Check if it's the service attribute */
355 if (context->attrib && context->attrib->num == SERVICE_ATTR) {
356 /* We got the service ID !!! */
357 context->service = uuidDef;
361 printf("%.*sUUID16 : 0x%.4x - %s\n",
362 indent, indent_spaces, uuidNum, uuidDef->name);
364 printf("%.*sUUID16 : 0x%.4x\n",
365 indent, indent_spaces, uuidNum);
366 } else if (uuid->type == SDP_UUID32) {
367 struct uuid_def *uuidDef = NULL;
370 if (!(uuid->value.uuid32 & 0xffff0000)) {
371 uint16_t uuidNum = uuid->value.uuid32;
372 for (i = 0; i < uuid16_max; i++)
373 if (uuid16_names[i].num == uuidNum) {
374 uuidDef = &uuid16_names[i];
380 printf("%.*sUUID32 : 0x%.8x - %s\n",
381 indent, indent_spaces, uuid->value.uuid32, uuidDef->name);
383 printf("%.*sUUID32 : 0x%.8x\n",
384 indent, indent_spaces, uuid->value.uuid32);
385 } else if (uuid->type == SDP_UUID128) {
387 unsigned short data1;
388 unsigned short data2;
389 unsigned short data3;
391 unsigned short data5;
393 memcpy(&data0, &uuid->value.uuid128.data[0], 4);
394 memcpy(&data1, &uuid->value.uuid128.data[4], 2);
395 memcpy(&data2, &uuid->value.uuid128.data[6], 2);
396 memcpy(&data3, &uuid->value.uuid128.data[8], 2);
397 memcpy(&data4, &uuid->value.uuid128.data[10], 4);
398 memcpy(&data5, &uuid->value.uuid128.data[14], 2);
400 printf("%.*sUUID128 : 0x%.8x-%.4x-%.4x-%.4x-%.8x-%.4x\n",
401 indent, indent_spaces,
402 ntohl(data0), ntohs(data1), ntohs(data2),
403 ntohs(data3), ntohl(data4), ntohs(data5));
405 printf("%.*sEnum type of UUID not set\n",
406 indent, indent_spaces);
408 printf("%.*sNull passed to print UUID\n",
409 indent, indent_spaces);
413 * Parse a sequence of data elements (i.e. a list)
415 static void printf_dataseq(sdp_data_t * pData, struct attrib_context *context, int indent)
417 sdp_data_t *sdpdata = NULL;
421 context->member_index = 0;
423 sdp_data_printf(sdpdata, context, indent + 2);
424 sdpdata = sdpdata->next;
425 context->member_index++;
428 printf("%.*sBroken dataseq link\n", indent, indent_spaces);
433 * Parse a single data element (either in the attribute or in a data
436 static void sdp_data_printf(sdp_data_t *sdpdata, struct attrib_context *context, int indent)
438 char *member_name = NULL;
440 /* Find member name. Almost black magic ;-) */
441 if (context && context->attrib && context->attrib->members &&
442 context->member_index < context->attrib->member_max) {
443 member_name = context->attrib->members[context->member_index].name;
446 switch (sdpdata->dtd) {
448 printf("%.*sNil\n", indent, indent_spaces);
462 printf("%.*s%s (Integer) : 0x%x\n",
463 indent, indent_spaces, member_name, sdpdata->val.uint32);
465 printf("%.*sInteger : 0x%x\n", indent, indent_spaces,
466 sdpdata->val.uint32);
473 //printf("%.*sUUID\n", indent, indent_spaces);
474 sdp_uuid_printf(&sdpdata->val.uuid, context, indent);
480 if (sdpdata->unitSize > (int) strlen(sdpdata->val.str)) {
482 printf("%.*sData :", indent, indent_spaces);
483 for (i = 0; i < sdpdata->unitSize; i++)
484 printf(" %02x", (unsigned char) sdpdata->val.str[i]);
487 printf("%.*sText : \"%s\"\n", indent, indent_spaces, sdpdata->val.str);
492 printf("%.*sURL : %s\n", indent, indent_spaces, sdpdata->val.str);
498 printf("%.*sData Sequence\n", indent, indent_spaces);
499 printf_dataseq(sdpdata->val.dataseq, context, indent);
505 printf("%.*sData Sequence Alternates\n", indent, indent_spaces);
506 printf_dataseq(sdpdata->val.dataseq, context, indent);
512 * Parse a single attribute.
514 static void print_tree_attr_func(void *value, void *userData)
516 sdp_data_t *sdpdata = NULL;
518 struct service_context *service = (struct service_context *) userData;
519 struct attrib_context context;
520 struct attrib_def *attrDef = NULL;
523 sdpdata = (sdp_data_t *)value;
524 attrId = sdpdata->attrId;
525 /* Search amongst the generic attributes */
526 for (i = 0; i < attrib_max; i++)
527 if (attrib_names[i].num == attrId) {
528 attrDef = &attrib_names[i];
531 /* Search amongst the specific attributes of this service */
532 if ((attrDef == NULL) && (service->service != NULL) &&
533 (service->service->attribs != NULL)) {
534 struct attrib_def *svc_attribs = service->service->attribs;
535 int svc_attrib_max = service->service->attrib_max;
536 for (i = 0; i < svc_attrib_max; i++)
537 if (svc_attribs[i].num == attrId) {
538 attrDef = &svc_attribs[i];
544 printf("Attribute Identifier : 0x%x - %s\n", attrId, attrDef->name);
546 printf("Attribute Identifier : 0x%x\n", attrId);
548 context.service = service->service;
549 context.attrib = attrDef;
550 context.member_index = 0;
551 /* Parse attribute members */
553 sdp_data_printf(sdpdata, &context, 2);
555 printf(" NULL value\n");
557 service->service = context.service;
561 * Main entry point of this library. Parse a SDP record.
562 * We assume the record has already been read, parsed and cached
565 static void print_tree_attr(sdp_record_t *rec)
567 if (rec && rec->attrlist) {
568 struct service_context service = { NULL };
569 sdp_list_foreach(rec->attrlist, print_tree_attr_func, &service);
573 static void print_raw_data(sdp_data_t *data, int indent)
575 struct uuid_def *def;
581 for (i = 0; i < indent; i++)
589 printf("Bool %s\n", data->val.uint8 ? "True" : "False");
592 printf("UINT8 0x%02x\n", data->val.uint8);
595 printf("UINT16 0x%04x\n", data->val.uint16);
598 printf("UINT32 0x%08x\n", data->val.uint32);
601 printf("UINT64 0x%016jx\n", data->val.uint64);
604 printf("UINT128 ...\n");
607 printf("INT8 %d\n", data->val.int8);
610 printf("INT16 %d\n", data->val.int16);
613 printf("INT32 %d\n", data->val.int32);
616 printf("INT64 %jd\n", data->val.int64);
619 printf("INT128 ...\n");
624 switch (data->val.uuid.type) {
627 for (i = 0; i < uuid16_max; i++)
628 if (uuid16_names[i].num == data->val.uuid.value.uuid16) {
629 def = &uuid16_names[i];
633 printf("UUID16 0x%04x - %s\n", data->val.uuid.value.uuid16, def->name);
635 printf("UUID16 0x%04x\n", data->val.uuid.value.uuid16);
639 if (!(data->val.uuid.value.uuid32 & 0xffff0000)) {
640 uint16_t value = data->val.uuid.value.uuid32;
641 for (i = 0; i < uuid16_max; i++)
642 if (uuid16_names[i].num == value) {
643 def = &uuid16_names[i];
648 printf("UUID32 0x%08x - %s\n", data->val.uuid.value.uuid32, def->name);
650 printf("UUID32 0x%08x\n", data->val.uuid.value.uuid32);
654 for (i = 0; i < 16; i++) {
663 printf("%02x", (unsigned char ) data->val.uuid.value.uuid128.data[i]);
668 printf("UUID type 0x%02x\n", data->val.uuid.type);
676 for (i = 0; i < data->unitSize; i++) {
677 if (i == (data->unitSize - 1) && data->val.str[i] == '\0')
679 if (!isprint(data->val.str[i])) {
686 for (i = 0; i < data->unitSize; i++)
687 printf(" %02x", (unsigned char) data->val.str[i]);
690 for (i = 0; i < data->unitSize; i++)
691 printf("%c", data->val.str[i]);
698 printf("URL %s\n", data->val.str);
703 printf("Sequence\n");
704 print_raw_data(data->val.dataseq, indent + 1);
709 printf("Alternate\n");
710 print_raw_data(data->val.dataseq, indent + 1);
713 printf("Unknown type 0x%02x\n", data->dtd);
717 print_raw_data(data->next, indent);
720 static void print_raw_attr_func(void *value, void *userData)
722 sdp_data_t *data = (sdp_data_t *) value;
723 struct attrib_def *def = NULL;
726 /* Search amongst the generic attributes */
727 for (i = 0; i < attrib_max; i++)
728 if (attrib_names[i].num == data->attrId) {
729 def = &attrib_names[i];
734 printf("\tAttribute 0x%04x - %s\n", data->attrId, def->name);
736 printf("\tAttribute 0x%04x\n", data->attrId);
739 print_raw_data(data, 2);
741 printf(" NULL value\n");
744 static void print_raw_attr(sdp_record_t *rec)
746 if (rec && rec->attrlist) {
747 printf("Sequence\n");
748 sdp_list_foreach(rec->attrlist, print_raw_attr_func, 0);
753 * Set attributes with single values in SDP record
756 static int set_attrib(sdp_session_t *sess, uint32_t handle, uint16_t attrib, char *value)
758 sdp_list_t *attrid_list;
759 uint32_t range = 0x0000ffff;
763 /* Get the old SDP record */
764 attrid_list = sdp_list_append(NULL, &range);
765 rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attrid_list);
766 sdp_list_free(attrid_list, NULL);
769 printf("Service get request failed.\n");
773 /* Check the type of attribute */
774 if (!strncasecmp(value, "u0x", 3)) {
776 uint16_t value_int = 0;
778 value_int = strtoul(value + 3, NULL, 16);
779 sdp_uuid16_create(&value_uuid, value_int);
780 printf("Adding attrib 0x%X uuid16 0x%X to record 0x%X\n",
781 attrib, value_int, handle);
783 sdp_attr_add_new(rec, attrib, SDP_UUID16, &value_uuid.value.uuid16);
784 } else if (!strncasecmp(value, "0x", 2)) {
787 value_int = strtoul(value + 2, NULL, 16);
788 printf("Adding attrib 0x%X int 0x%X to record 0x%X\n",
789 attrib, value_int, handle);
791 sdp_attr_add_new(rec, attrib, SDP_UINT32, &value_int);
794 printf("Adding attrib 0x%X string \"%s\" to record 0x%X\n",
795 attrib, value, handle);
797 /* Add/Update our attribute to the record */
798 sdp_attr_add_new(rec, attrib, SDP_TEXT_STR8, value);
801 /* Update on the server */
802 ret = sdp_device_record_update(sess, &interface, rec);
804 printf("Service Record update failed (%d).\n", errno);
805 sdp_record_free(rec);
809 static struct option set_options[] = {
810 { "help", 0, 0, 'h' },
814 static const char *set_help =
816 "\tget record_handle attrib_id attrib_value\n";
819 * Add an attribute to an existing SDP record on the local SDP server
821 static int cmd_setattr(int argc, char **argv)
828 for_each_opt(opt, set_options, NULL) {
831 printf("%s", set_help);
840 printf("%s", set_help);
844 /* Convert command line args */
845 handle = strtoul(argv[0], NULL, 16);
846 attrib = strtoul(argv[1], NULL, 16);
849 sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
853 status = set_attrib(sess, handle, attrib, argv[2]);
860 * We do only simple data sequences. Sequence of sequences is a pain ;-)
863 static int set_attribseq(sdp_session_t *session, uint32_t handle, uint16_t attrib, int argc, char **argv)
865 sdp_list_t *attrid_list;
866 uint32_t range = 0x0000ffff;
868 sdp_data_t *pSequenceHolder = NULL;
872 uint8_t uuid16 = SDP_UUID16;
873 uint8_t uint32 = SDP_UINT32;
874 uint8_t str8 = SDP_TEXT_STR8;
877 /* Get the old SDP record */
878 attrid_list = sdp_list_append(NULL, &range);
879 rec = sdp_service_attr_req(session, handle, SDP_ATTR_REQ_RANGE, attrid_list);
880 sdp_list_free(attrid_list, NULL);
883 printf("Service get request failed.\n");
888 dtdArray = (void **)malloc(argc * sizeof(void *));
889 valueArray = (void **)malloc(argc * sizeof(void *));
890 allocArray = (void **)malloc(argc * sizeof(void *));
892 /* Loop on all args, add them in arrays */
893 for (i = 0; i < argc; i++) {
894 /* Check the type of attribute */
895 if (!strncasecmp(argv[i], "u0x", 3)) {
897 uint16_t value_int = strtoul((argv[i]) + 3, NULL, 16);
898 uuid_t *value_uuid = (uuid_t *) malloc(sizeof(uuid_t));
899 allocArray[i] = value_uuid;
900 sdp_uuid16_create(value_uuid, value_int);
902 printf("Adding uuid16 0x%X to record 0x%X\n", value_int, handle);
903 dtdArray[i] = &uuid16;
904 valueArray[i] = &value_uuid->value.uuid16;
905 } else if (!strncasecmp(argv[i], "0x", 2)) {
907 uint32_t *value_int = (uint32_t *) malloc(sizeof(int));
908 allocArray[i] = value_int;
909 *value_int = strtoul((argv[i]) + 2, NULL, 16);
911 printf("Adding int 0x%X to record 0x%X\n", *value_int, handle);
912 dtdArray[i] = &uint32;
913 valueArray[i] = value_int;
916 printf("Adding string \"%s\" to record 0x%X\n", argv[i], handle);
918 valueArray[i] = argv[i];
922 /* Add this sequence to the attrib list */
923 pSequenceHolder = sdp_seq_alloc(dtdArray, valueArray, argc);
924 if (pSequenceHolder) {
925 sdp_attr_replace(rec, attrib, pSequenceHolder);
927 /* Update on the server */
928 ret = sdp_device_record_update(session, &interface, rec);
930 printf("Service Record update failed (%d).\n", errno);
932 printf("Failed to create pSequenceHolder\n");
935 for (i = 0; i < argc; i++)
942 sdp_record_free(rec);
947 static struct option seq_options[] = {
948 { "help", 0, 0, 'h' },
952 static const char *seq_help =
954 "\tget record_handle attrib_id attrib_values\n";
957 * Add an attribute sequence to an existing SDP record
958 * on the local SDP server
960 static int cmd_setseq(int argc, char **argv)
967 for_each_opt(opt, seq_options, NULL) {
970 printf("%s", seq_help);
979 printf("%s", seq_help);
983 /* Convert command line args */
984 handle = strtoul(argv[0], NULL, 16);
985 attrib = strtoul(argv[1], NULL, 16);
991 sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
995 status = set_attribseq(sess, handle, attrib, argc, argv);
1001 static void print_service_class(void *value, void *userData)
1003 char ServiceClassUUID_str[MAX_LEN_SERVICECLASS_UUID_STR];
1004 uuid_t *uuid = (uuid_t *)value;
1006 sdp_uuid2strn(uuid, UUID_str, MAX_LEN_UUID_STR);
1007 sdp_svclass_uuid2strn(uuid, ServiceClassUUID_str, MAX_LEN_SERVICECLASS_UUID_STR);
1008 if (uuid->type != SDP_UUID128)
1009 printf(" \"%s\" (0x%s)\n", ServiceClassUUID_str, UUID_str);
1011 printf(" UUID 128: %s\n", UUID_str);
1014 static void print_service_desc(void *value, void *user)
1016 char str[MAX_LEN_PROTOCOL_UUID_STR];
1017 sdp_data_t *p = (sdp_data_t *)value, *s;
1018 int i = 0, proto = 0;
1020 for (; p; p = p->next, i++) {
1025 sdp_uuid2strn(&p->val.uuid, UUID_str, MAX_LEN_UUID_STR);
1026 sdp_proto_uuid2strn(&p->val.uuid, str, sizeof(str));
1027 proto = sdp_uuid_to_proto(&p->val.uuid);
1028 printf(" \"%s\" (0x%s)\n", str, UUID_str);
1031 if (proto == RFCOMM_UUID)
1032 printf(" Channel: %d\n", p->val.uint8);
1034 printf(" uint8: 0x%x\n", p->val.uint8);
1037 if (proto == L2CAP_UUID) {
1039 printf(" PSM: %d\n", p->val.uint16);
1041 printf(" Version: 0x%04x\n", p->val.uint16);
1042 } else if (proto == BNEP_UUID)
1044 printf(" Version: 0x%04x\n", p->val.uint16);
1046 printf(" uint16: 0x%x\n", p->val.uint16);
1048 printf(" uint16: 0x%x\n", p->val.uint16);
1052 for (s = p->val.dataseq; s; s = s->next)
1053 printf(" %x", s->val.uint16);
1058 for (s = p->val.dataseq; s; s = s->next)
1059 printf(" %x", s->val.uint8);
1063 printf(" FIXME: dtd=0%x\n", p->dtd);
1069 static void print_lang_attr(void *value, void *user)
1071 sdp_lang_attr_t *lang = (sdp_lang_attr_t *)value;
1072 printf(" code_ISO639: 0x%02x\n", lang->code_ISO639);
1073 printf(" encoding: 0x%02x\n", lang->encoding);
1074 printf(" base_offset: 0x%02x\n", lang->base_offset);
1077 static void print_access_protos(void *value, void *userData)
1079 sdp_list_t *protDescSeq = (sdp_list_t *)value;
1080 sdp_list_foreach(protDescSeq, print_service_desc, 0);
1083 static void print_profile_desc(void *value, void *userData)
1085 sdp_profile_desc_t *desc = (sdp_profile_desc_t *)value;
1086 char str[MAX_LEN_PROFILEDESCRIPTOR_UUID_STR];
1088 sdp_uuid2strn(&desc->uuid, UUID_str, MAX_LEN_UUID_STR);
1089 sdp_profile_uuid2strn(&desc->uuid, str, MAX_LEN_PROFILEDESCRIPTOR_UUID_STR);
1091 printf(" \"%s\" (0x%s)\n", str, UUID_str);
1093 printf(" Version: 0x%04x\n", desc->version);
1097 * Parse a SDP record in user friendly form.
1099 static void print_service_attr(sdp_record_t *rec)
1101 sdp_list_t *list = 0, *proto = 0;
1103 sdp_record_print(rec);
1105 printf("Service RecHandle: 0x%x\n", rec->handle);
1107 if (sdp_get_service_classes(rec, &list) == 0) {
1108 printf("Service Class ID List:\n");
1109 sdp_list_foreach(list, print_service_class, 0);
1110 sdp_list_free(list, free);
1112 if (sdp_get_access_protos(rec, &proto) == 0) {
1113 printf("Protocol Descriptor List:\n");
1114 sdp_list_foreach(proto, print_access_protos, 0);
1115 sdp_list_foreach(proto, (sdp_list_func_t)sdp_list_free, 0);
1116 sdp_list_free(proto, 0);
1118 if (sdp_get_lang_attr(rec, &list) == 0) {
1119 printf("Language Base Attr List:\n");
1120 sdp_list_foreach(list, print_lang_attr, 0);
1121 sdp_list_free(list, free);
1123 if (sdp_get_profile_descs(rec, &list) == 0) {
1124 printf("Profile Descriptor List:\n");
1125 sdp_list_foreach(list, print_profile_desc, 0);
1126 sdp_list_free(list, free);
1131 * Support for Service (de)registration
1139 unsigned int profile;
1145 static void add_lang_attr(sdp_record_t *r)
1147 sdp_lang_attr_t base_lang;
1148 sdp_list_t *langs = 0;
1150 /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
1151 base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
1152 base_lang.encoding = 106;
1153 base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
1154 langs = sdp_list_append(0, &base_lang);
1155 sdp_set_lang_attr(r, langs);
1156 sdp_list_free(langs, 0);
1159 static int add_sp(sdp_session_t *session, svc_info_t *si)
1161 sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
1162 uuid_t root_uuid, sp_uuid, l2cap, rfcomm;
1163 sdp_profile_desc_t profile;
1164 sdp_record_t record;
1165 uint8_t u8 = si->channel ? si->channel : 1;
1166 sdp_data_t *channel;
1169 memset(&record, 0, sizeof(sdp_record_t));
1170 record.handle = si->handle;
1171 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1172 root = sdp_list_append(0, &root_uuid);
1173 sdp_set_browse_groups(&record, root);
1174 sdp_list_free(root, 0);
1176 sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
1177 svclass_id = sdp_list_append(0, &sp_uuid);
1178 sdp_set_service_classes(&record, svclass_id);
1179 sdp_list_free(svclass_id, 0);
1181 sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
1182 profile.version = 0x0100;
1183 profiles = sdp_list_append(0, &profile);
1184 sdp_set_profile_descs(&record, profiles);
1185 sdp_list_free(profiles, 0);
1187 sdp_uuid16_create(&l2cap, L2CAP_UUID);
1188 proto[0] = sdp_list_append(0, &l2cap);
1189 apseq = sdp_list_append(0, proto[0]);
1191 sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
1192 proto[1] = sdp_list_append(0, &rfcomm);
1193 channel = sdp_data_alloc(SDP_UINT8, &u8);
1194 proto[1] = sdp_list_append(proto[1], channel);
1195 apseq = sdp_list_append(apseq, proto[1]);
1197 aproto = sdp_list_append(0, apseq);
1198 sdp_set_access_protos(&record, aproto);
1200 add_lang_attr(&record);
1202 sdp_set_info_attr(&record, "Serial Port", "BlueZ", "COM Port");
1204 sdp_set_url_attr(&record, "http://www.bluez.org/",
1205 "http://www.bluez.org/", "http://www.bluez.org/");
1207 sdp_set_service_id(&record, sp_uuid);
1208 sdp_set_service_ttl(&record, 0xffff);
1209 sdp_set_service_avail(&record, 0xff);
1210 sdp_set_record_state(&record, 0x00001234);
1212 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1213 printf("Service Record registration failed\n");
1218 printf("Serial Port service registered\n");
1221 sdp_data_free(channel);
1222 sdp_list_free(proto[0], 0);
1223 sdp_list_free(proto[1], 0);
1224 sdp_list_free(apseq, 0);
1225 sdp_list_free(aproto, 0);
1230 static int add_dun(sdp_session_t *session, svc_info_t *si)
1232 sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto;
1233 uuid_t rootu, dun, gn, l2cap, rfcomm;
1234 sdp_profile_desc_t profile;
1235 sdp_list_t *proto[2];
1236 sdp_record_t record;
1237 uint8_t u8 = si->channel ? si->channel : 2;
1238 sdp_data_t *channel;
1241 memset(&record, 0, sizeof(sdp_record_t));
1242 record.handle = si->handle;
1244 sdp_uuid16_create(&rootu, PUBLIC_BROWSE_GROUP);
1245 root = sdp_list_append(0, &rootu);
1246 sdp_set_browse_groups(&record, root);
1248 sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
1249 svclass_id = sdp_list_append(0, &dun);
1250 sdp_uuid16_create(&gn, GENERIC_NETWORKING_SVCLASS_ID);
1251 svclass_id = sdp_list_append(svclass_id, &gn);
1252 sdp_set_service_classes(&record, svclass_id);
1254 sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID);
1255 profile.version = 0x0100;
1256 pfseq = sdp_list_append(0, &profile);
1257 sdp_set_profile_descs(&record, pfseq);
1259 sdp_uuid16_create(&l2cap, L2CAP_UUID);
1260 proto[0] = sdp_list_append(0, &l2cap);
1261 apseq = sdp_list_append(0, proto[0]);
1263 sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
1264 proto[1] = sdp_list_append(0, &rfcomm);
1265 channel = sdp_data_alloc(SDP_UINT8, &u8);
1266 proto[1] = sdp_list_append(proto[1], channel);
1267 apseq = sdp_list_append(apseq, proto[1]);
1269 aproto = sdp_list_append(0, apseq);
1270 sdp_set_access_protos(&record, aproto);
1272 sdp_set_info_attr(&record, "Dial-Up Networking", 0, 0);
1274 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1275 printf("Service Record registration failed\n");
1280 printf("Dial-Up Networking service registered\n");
1283 sdp_data_free(channel);
1284 sdp_list_free(proto[0], 0);
1285 sdp_list_free(proto[1], 0);
1286 sdp_list_free(apseq, 0);
1287 sdp_list_free(aproto, 0);
1292 static int add_fax(sdp_session_t *session, svc_info_t *si)
1294 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1295 uuid_t root_uuid, fax_uuid, tel_uuid, l2cap_uuid, rfcomm_uuid;
1296 sdp_profile_desc_t profile;
1297 sdp_list_t *aproto, *proto[2];
1298 sdp_record_t record;
1299 uint8_t u8 = si->channel? si->channel : 3;
1300 sdp_data_t *channel;
1303 memset(&record, 0, sizeof(sdp_record_t));
1304 record.handle = si->handle;
1306 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1307 root = sdp_list_append(0, &root_uuid);
1308 sdp_set_browse_groups(&record, root);
1310 sdp_uuid16_create(&fax_uuid, FAX_SVCLASS_ID);
1311 svclass_id = sdp_list_append(0, &fax_uuid);
1312 sdp_uuid16_create(&tel_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
1313 svclass_id = sdp_list_append(svclass_id, &tel_uuid);
1314 sdp_set_service_classes(&record, svclass_id);
1316 sdp_uuid16_create(&profile.uuid, FAX_PROFILE_ID);
1317 profile.version = 0x0100;
1318 pfseq = sdp_list_append(0, &profile);
1319 sdp_set_profile_descs(&record, pfseq);
1321 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1322 proto[0] = sdp_list_append(0, &l2cap_uuid);
1323 apseq = sdp_list_append(0, proto[0]);
1325 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1326 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1327 channel = sdp_data_alloc(SDP_UINT8, &u8);
1328 proto[1] = sdp_list_append(proto[1], channel);
1329 apseq = sdp_list_append(apseq, proto[1]);
1331 aproto = sdp_list_append(0, apseq);
1332 sdp_set_access_protos(&record, aproto);
1334 sdp_set_info_attr(&record, "Fax", 0, 0);
1336 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1337 printf("Service Record registration failed\n");
1341 printf("Fax service registered\n");
1343 sdp_data_free(channel);
1344 sdp_list_free(proto[0], 0);
1345 sdp_list_free(proto[1], 0);
1346 sdp_list_free(apseq, 0);
1347 sdp_list_free(aproto, 0);
1351 static int add_lan(sdp_session_t *session, svc_info_t *si)
1353 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1354 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
1355 sdp_profile_desc_t profile;
1356 sdp_list_t *aproto, *proto[2];
1357 sdp_record_t record;
1358 uint8_t u8 = si->channel ? si->channel : 4;
1359 sdp_data_t *channel;
1362 memset(&record, 0, sizeof(sdp_record_t));
1363 record.handle = si->handle;
1365 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1366 root = sdp_list_append(0, &root_uuid);
1367 sdp_set_browse_groups(&record, root);
1369 sdp_uuid16_create(&svclass_uuid, LAN_ACCESS_SVCLASS_ID);
1370 svclass_id = sdp_list_append(0, &svclass_uuid);
1371 sdp_set_service_classes(&record, svclass_id);
1373 sdp_uuid16_create(&profile.uuid, LAN_ACCESS_PROFILE_ID);
1374 profile.version = 0x0100;
1375 pfseq = sdp_list_append(0, &profile);
1376 sdp_set_profile_descs(&record, pfseq);
1378 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1379 proto[0] = sdp_list_append(0, &l2cap_uuid);
1380 apseq = sdp_list_append(0, proto[0]);
1382 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1383 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1384 channel = sdp_data_alloc(SDP_UINT8, &u8);
1385 proto[1] = sdp_list_append(proto[1], channel);
1386 apseq = sdp_list_append(apseq, proto[1]);
1388 aproto = sdp_list_append(0, apseq);
1389 sdp_set_access_protos(&record, aproto);
1391 sdp_set_info_attr(&record, "LAN Access over PPP", 0, 0);
1393 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1394 printf("Service Record registration failed\n");
1399 printf("LAN Access service registered\n");
1402 sdp_data_free(channel);
1403 sdp_list_free(proto[0], 0);
1404 sdp_list_free(proto[1], 0);
1405 sdp_list_free(apseq, 0);
1406 sdp_list_free(aproto, 0);
1411 static int add_headset(sdp_session_t *session, svc_info_t *si)
1413 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1414 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1415 sdp_profile_desc_t profile;
1416 sdp_list_t *aproto, *proto[2];
1417 sdp_record_t record;
1418 uint8_t u8 = si->channel ? si->channel : 5;
1419 sdp_data_t *channel;
1422 memset(&record, 0, sizeof(sdp_record_t));
1423 record.handle = si->handle;
1425 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1426 root = sdp_list_append(0, &root_uuid);
1427 sdp_set_browse_groups(&record, root);
1429 sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
1430 svclass_id = sdp_list_append(0, &svclass_uuid);
1431 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1432 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1433 sdp_set_service_classes(&record, svclass_id);
1435 sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
1436 profile.version = 0x0100;
1437 pfseq = sdp_list_append(0, &profile);
1438 sdp_set_profile_descs(&record, pfseq);
1440 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1441 proto[0] = sdp_list_append(0, &l2cap_uuid);
1442 apseq = sdp_list_append(0, proto[0]);
1444 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1445 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1446 channel = sdp_data_alloc(SDP_UINT8, &u8);
1447 proto[1] = sdp_list_append(proto[1], channel);
1448 apseq = sdp_list_append(apseq, proto[1]);
1450 aproto = sdp_list_append(0, apseq);
1451 sdp_set_access_protos(&record, aproto);
1453 sdp_set_info_attr(&record, "Headset", 0, 0);
1455 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1456 printf("Service Record registration failed\n");
1461 printf("Headset service registered\n");
1464 sdp_data_free(channel);
1465 sdp_list_free(proto[0], 0);
1466 sdp_list_free(proto[1], 0);
1467 sdp_list_free(apseq, 0);
1468 sdp_list_free(aproto, 0);
1473 static int add_headset_ag(sdp_session_t *session, svc_info_t *si)
1475 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1476 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1477 sdp_profile_desc_t profile;
1478 sdp_list_t *aproto, *proto[2];
1479 sdp_record_t record;
1480 uint8_t u8 = si->channel ? si->channel : 7;
1481 uint16_t u16 = 0x17;
1482 sdp_data_t *channel, *features;
1483 uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
1484 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
1487 memset(&record, 0, sizeof(sdp_record_t));
1488 record.handle = si->handle;
1490 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1491 root = sdp_list_append(0, &root_uuid);
1492 sdp_set_browse_groups(&record, root);
1494 sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
1495 svclass_id = sdp_list_append(0, &svclass_uuid);
1496 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1497 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1498 sdp_set_service_classes(&record, svclass_id);
1500 sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
1501 profile.version = 0x0100;
1502 pfseq = sdp_list_append(0, &profile);
1503 sdp_set_profile_descs(&record, pfseq);
1505 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1506 proto[0] = sdp_list_append(0, &l2cap_uuid);
1507 apseq = sdp_list_append(0, proto[0]);
1509 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1510 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1511 channel = sdp_data_alloc(SDP_UINT8, &u8);
1512 proto[1] = sdp_list_append(proto[1], channel);
1513 apseq = sdp_list_append(apseq, proto[1]);
1515 features = sdp_data_alloc(SDP_UINT16, &u16);
1516 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1518 aproto = sdp_list_append(0, apseq);
1519 sdp_set_access_protos(&record, aproto);
1521 sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
1523 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
1525 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
1526 printf("Service Record registration failed\n");
1531 printf("Headset AG service registered\n");
1534 sdp_data_free(channel);
1535 sdp_list_free(proto[0], 0);
1536 sdp_list_free(proto[1], 0);
1537 sdp_list_free(apseq, 0);
1538 sdp_list_free(aproto, 0);
1543 static int add_handsfree(sdp_session_t *session, svc_info_t *si)
1545 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1546 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1547 sdp_profile_desc_t profile;
1548 sdp_list_t *aproto, *proto[2];
1549 sdp_record_t record;
1550 uint8_t u8 = si->channel ? si->channel : 6;
1551 uint16_t u16 = 0x31;
1552 sdp_data_t *channel, *features;
1555 memset(&record, 0, sizeof(sdp_record_t));
1556 record.handle = si->handle;
1558 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1559 root = sdp_list_append(0, &root_uuid);
1560 sdp_set_browse_groups(&record, root);
1562 sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
1563 svclass_id = sdp_list_append(0, &svclass_uuid);
1564 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1565 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1566 sdp_set_service_classes(&record, svclass_id);
1568 sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
1569 profile.version = 0x0101;
1570 pfseq = sdp_list_append(0, &profile);
1571 sdp_set_profile_descs(&record, pfseq);
1573 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1574 proto[0] = sdp_list_append(0, &l2cap_uuid);
1575 apseq = sdp_list_append(0, proto[0]);
1577 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1578 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1579 channel = sdp_data_alloc(SDP_UINT8, &u8);
1580 proto[1] = sdp_list_append(proto[1], channel);
1581 apseq = sdp_list_append(apseq, proto[1]);
1583 features = sdp_data_alloc(SDP_UINT16, &u16);
1584 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1586 aproto = sdp_list_append(0, apseq);
1587 sdp_set_access_protos(&record, aproto);
1589 sdp_set_info_attr(&record, "Handsfree", 0, 0);
1591 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1592 printf("Service Record registration failed\n");
1597 printf("Handsfree service registered\n");
1600 sdp_data_free(channel);
1601 sdp_list_free(proto[0], 0);
1602 sdp_list_free(proto[1], 0);
1603 sdp_list_free(apseq, 0);
1604 sdp_list_free(aproto, 0);
1609 static int add_handsfree_ag(sdp_session_t *session, svc_info_t *si)
1611 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1612 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1613 sdp_profile_desc_t profile;
1614 sdp_list_t *aproto, *proto[2];
1615 sdp_record_t record;
1616 uint8_t u8 = si->channel ? si->channel : 7;
1617 uint16_t u16 = 0x17;
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 };
1758 //uint8_t formats[] = { 0xff };
1759 void *dtds[sizeof(formats)], *values[sizeof(formats)];
1761 uint8_t dtd = SDP_UINT8;
1765 memset(&record, 0, sizeof(sdp_record_t));
1766 record.handle = si->handle;
1768 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1769 root = sdp_list_append(0, &root_uuid);
1770 sdp_set_browse_groups(&record, root);
1772 sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
1773 svclass_id = sdp_list_append(0, &opush_uuid);
1774 sdp_set_service_classes(&record, svclass_id);
1776 sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
1777 profile[0].version = 0x0100;
1778 pfseq = sdp_list_append(0, profile);
1779 sdp_set_profile_descs(&record, pfseq);
1781 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1782 proto[0] = sdp_list_append(0, &l2cap_uuid);
1783 apseq = sdp_list_append(0, proto[0]);
1785 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1786 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1787 channel = sdp_data_alloc(SDP_UINT8, &chan);
1788 proto[1] = sdp_list_append(proto[1], channel);
1789 apseq = sdp_list_append(apseq, proto[1]);
1791 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1792 proto[2] = sdp_list_append(0, &obex_uuid);
1793 apseq = sdp_list_append(apseq, proto[2]);
1795 aproto = sdp_list_append(0, apseq);
1796 sdp_set_access_protos(&record, aproto);
1798 for (i = 0; i < sizeof(formats); i++) {
1800 values[i] = &formats[i];
1802 sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
1803 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
1805 sdp_set_info_attr(&record, "OBEX Object Push", 0, 0);
1807 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1808 printf("Service Record registration failed\n");
1813 printf("OBEX Object Push service registered\n");
1816 sdp_data_free(channel);
1817 sdp_list_free(proto[0], 0);
1818 sdp_list_free(proto[1], 0);
1819 sdp_list_free(proto[2], 0);
1820 sdp_list_free(apseq, 0);
1821 sdp_list_free(aproto, 0);
1826 static int add_pbap(sdp_session_t *session, svc_info_t *si)
1828 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1829 uuid_t root_uuid, pbap_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1830 sdp_profile_desc_t profile[1];
1831 sdp_list_t *aproto, *proto[3];
1832 sdp_record_t record;
1833 uint8_t chan = si->channel ? si->channel : 19;
1834 sdp_data_t *channel;
1835 uint8_t formats[] = {0x01};
1836 void *dtds[sizeof(formats)], *values[sizeof(formats)];
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(aproto, 0);
1900 static int add_ftp(sdp_session_t *session, svc_info_t *si)
1902 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1903 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1904 sdp_profile_desc_t profile[1];
1905 sdp_list_t *aproto, *proto[3];
1906 sdp_record_t record;
1907 uint8_t u8 = si->channel ? si->channel: 10;
1908 sdp_data_t *channel;
1911 memset(&record, 0, sizeof(sdp_record_t));
1912 record.handle = si->handle;
1914 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1915 root = sdp_list_append(0, &root_uuid);
1916 sdp_set_browse_groups(&record, root);
1918 sdp_uuid16_create(&ftrn_uuid, OBEX_FILETRANS_SVCLASS_ID);
1919 svclass_id = sdp_list_append(0, &ftrn_uuid);
1920 sdp_set_service_classes(&record, svclass_id);
1922 sdp_uuid16_create(&profile[0].uuid, OBEX_FILETRANS_PROFILE_ID);
1923 profile[0].version = 0x0100;
1924 pfseq = sdp_list_append(0, &profile[0]);
1925 sdp_set_profile_descs(&record, pfseq);
1927 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1928 proto[0] = sdp_list_append(0, &l2cap_uuid);
1929 apseq = sdp_list_append(0, proto[0]);
1931 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1932 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1933 channel = sdp_data_alloc(SDP_UINT8, &u8);
1934 proto[1] = sdp_list_append(proto[1], channel);
1935 apseq = sdp_list_append(apseq, proto[1]);
1937 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1938 proto[2] = sdp_list_append(0, &obex_uuid);
1939 apseq = sdp_list_append(apseq, proto[2]);
1941 aproto = sdp_list_append(0, apseq);
1942 sdp_set_access_protos(&record, aproto);
1944 sdp_set_info_attr(&record, "OBEX File Transfer", 0, 0);
1946 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1947 printf("Service Record registration failed\n");
1952 printf("OBEX File Transfer service registered\n");
1955 sdp_data_free(channel);
1956 sdp_list_free(proto[0], 0);
1957 sdp_list_free(proto[1], 0);
1958 sdp_list_free(proto[2], 0);
1959 sdp_list_free(apseq, 0);
1960 sdp_list_free(aproto, 0);
1965 static int add_directprint(sdp_session_t *session, svc_info_t *si)
1967 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1968 uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1969 sdp_profile_desc_t profile[1];
1970 sdp_list_t *aproto, *proto[3];
1971 sdp_record_t record;
1972 uint8_t chan = si->channel ? si->channel : 12;
1973 sdp_data_t *channel;
1976 memset(&record, 0, sizeof(sdp_record_t));
1977 record.handle = si->handle;
1979 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1980 root = sdp_list_append(0, &root_uuid);
1981 sdp_set_browse_groups(&record, root);
1983 sdp_uuid16_create(&opush_uuid, DIRECT_PRINTING_SVCLASS_ID);
1984 svclass_id = sdp_list_append(0, &opush_uuid);
1985 sdp_set_service_classes(&record, svclass_id);
1987 sdp_uuid16_create(&profile[0].uuid, BASIC_PRINTING_PROFILE_ID);
1988 profile[0].version = 0x0100;
1989 pfseq = sdp_list_append(0, profile);
1990 sdp_set_profile_descs(&record, pfseq);
1992 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1993 proto[0] = sdp_list_append(0, &l2cap_uuid);
1994 apseq = sdp_list_append(0, proto[0]);
1996 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1997 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1998 channel = sdp_data_alloc(SDP_UINT8, &chan);
1999 proto[1] = sdp_list_append(proto[1], channel);
2000 apseq = sdp_list_append(apseq, proto[1]);
2002 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
2003 proto[2] = sdp_list_append(0, &obex_uuid);
2004 apseq = sdp_list_append(apseq, proto[2]);
2006 aproto = sdp_list_append(0, apseq);
2007 sdp_set_access_protos(&record, aproto);
2009 sdp_set_info_attr(&record, "Direct Printing", 0, 0);
2011 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2012 printf("Service Record registration failed\n");
2017 printf("Direct Printing service registered\n");
2020 sdp_data_free(channel);
2021 sdp_list_free(proto[0], 0);
2022 sdp_list_free(proto[1], 0);
2023 sdp_list_free(proto[2], 0);
2024 sdp_list_free(apseq, 0);
2025 sdp_list_free(aproto, 0);
2030 static int add_nap(sdp_session_t *session, svc_info_t *si)
2032 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2033 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2034 sdp_profile_desc_t profile[1];
2035 sdp_list_t *aproto, *proto[2];
2036 sdp_record_t record;
2037 uint16_t lp = 0x000f, ver = 0x0100;
2038 sdp_data_t *psm, *version;
2041 memset(&record, 0, sizeof(sdp_record_t));
2042 record.handle = si->handle;
2044 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2045 root = sdp_list_append(0, &root_uuid);
2046 sdp_set_browse_groups(&record, root);
2048 sdp_uuid16_create(&ftrn_uuid, NAP_SVCLASS_ID);
2049 svclass_id = sdp_list_append(0, &ftrn_uuid);
2050 sdp_set_service_classes(&record, svclass_id);
2052 sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
2053 profile[0].version = 0x0100;
2054 pfseq = sdp_list_append(0, &profile[0]);
2055 sdp_set_profile_descs(&record, pfseq);
2057 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2058 proto[0] = sdp_list_append(0, &l2cap_uuid);
2059 psm = sdp_data_alloc(SDP_UINT16, &lp);
2060 proto[0] = sdp_list_append(proto[0], psm);
2061 apseq = sdp_list_append(0, proto[0]);
2063 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2064 proto[1] = sdp_list_append(0, &bnep_uuid);
2065 version = sdp_data_alloc(SDP_UINT16, &ver);
2066 proto[1] = sdp_list_append(proto[1], version);
2069 uint16_t ptype[4] = { 0x0010, 0x0020, 0x0030, 0x0040 };
2070 sdp_data_t *head, *pseq;
2073 for (p = 0, head = NULL; p < 4; p++) {
2074 sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
2075 head = sdp_seq_append(head, data);
2077 pseq = sdp_data_alloc(SDP_SEQ16, head);
2078 proto[1] = sdp_list_append(proto[1], pseq);
2081 apseq = sdp_list_append(apseq, proto[1]);
2083 aproto = sdp_list_append(0, apseq);
2084 sdp_set_access_protos(&record, aproto);
2086 sdp_set_info_attr(&record, "Network Access Point Service", 0, 0);
2088 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2089 printf("Service Record registration failed\n");
2094 printf("NAP service registered\n");
2097 sdp_data_free(version);
2099 sdp_list_free(proto[0], 0);
2100 sdp_list_free(proto[1], 0);
2101 sdp_list_free(apseq, 0);
2102 sdp_list_free(aproto, 0);
2107 static int add_gn(sdp_session_t *session, svc_info_t *si)
2109 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2110 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2111 sdp_profile_desc_t profile[1];
2112 sdp_list_t *aproto, *proto[2];
2113 sdp_record_t record;
2114 uint16_t lp = 0x000f, ver = 0x0100;
2115 sdp_data_t *psm, *version;
2118 memset(&record, 0, sizeof(sdp_record_t));
2119 record.handle = si->handle;
2121 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2122 root = sdp_list_append(0, &root_uuid);
2123 sdp_set_browse_groups(&record, root);
2125 sdp_uuid16_create(&ftrn_uuid, GN_SVCLASS_ID);
2126 svclass_id = sdp_list_append(0, &ftrn_uuid);
2127 sdp_set_service_classes(&record, svclass_id);
2129 sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
2130 profile[0].version = 0x0100;
2131 pfseq = sdp_list_append(0, &profile[0]);
2132 sdp_set_profile_descs(&record, pfseq);
2134 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2135 proto[0] = sdp_list_append(0, &l2cap_uuid);
2136 psm = sdp_data_alloc(SDP_UINT16, &lp);
2137 proto[0] = sdp_list_append(proto[0], psm);
2138 apseq = sdp_list_append(0, proto[0]);
2140 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2141 proto[1] = sdp_list_append(0, &bnep_uuid);
2142 version = sdp_data_alloc(SDP_UINT16, &ver);
2143 proto[1] = sdp_list_append(proto[1], version);
2144 apseq = sdp_list_append(apseq, proto[1]);
2146 aproto = sdp_list_append(0, apseq);
2147 sdp_set_access_protos(&record, aproto);
2149 sdp_set_info_attr(&record, "Group Network Service", 0, 0);
2151 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2152 printf("Service Record registration failed\n");
2157 printf("GN service registered\n");
2160 sdp_data_free(version);
2162 sdp_list_free(proto[0], 0);
2163 sdp_list_free(proto[1], 0);
2164 sdp_list_free(apseq, 0);
2165 sdp_list_free(aproto, 0);
2170 static int add_panu(sdp_session_t *session, svc_info_t *si)
2172 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2173 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2174 sdp_profile_desc_t profile[1];
2175 sdp_list_t *aproto, *proto[2];
2176 sdp_record_t record;
2177 uint16_t lp = 0x000f, ver = 0x0100;
2178 sdp_data_t *psm, *version;
2181 memset(&record, 0, sizeof(sdp_record_t));
2182 record.handle = si->handle;
2184 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2185 root = sdp_list_append(NULL, &root_uuid);
2186 sdp_set_browse_groups(&record, root);
2187 sdp_list_free(root, NULL);
2189 sdp_uuid16_create(&ftrn_uuid, PANU_SVCLASS_ID);
2190 svclass_id = sdp_list_append(NULL, &ftrn_uuid);
2191 sdp_set_service_classes(&record, svclass_id);
2192 sdp_list_free(svclass_id, NULL);
2194 sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
2195 profile[0].version = 0x0100;
2196 pfseq = sdp_list_append(NULL, &profile[0]);
2197 sdp_set_profile_descs(&record, pfseq);
2198 sdp_list_free(pfseq, NULL);
2200 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2201 proto[0] = sdp_list_append(NULL, &l2cap_uuid);
2202 psm = sdp_data_alloc(SDP_UINT16, &lp);
2203 proto[0] = sdp_list_append(proto[0], psm);
2204 apseq = sdp_list_append(NULL, proto[0]);
2206 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2207 proto[1] = sdp_list_append(NULL, &bnep_uuid);
2208 version = sdp_data_alloc(SDP_UINT16, &ver);
2209 proto[1] = sdp_list_append(proto[1], version);
2210 apseq = sdp_list_append(apseq, proto[1]);
2212 aproto = sdp_list_append(NULL, apseq);
2213 sdp_set_access_protos(&record, aproto);
2215 sdp_set_info_attr(&record, "PAN User", NULL, NULL);
2217 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2218 printf("Service Record registration failed\n");
2223 printf("PANU service registered\n");
2226 sdp_data_free(version);
2228 sdp_list_free(proto[0], 0);
2229 sdp_list_free(proto[1], 0);
2230 sdp_list_free(apseq, 0);
2231 sdp_list_free(aproto, 0);
2236 static int add_hid_keyb(sdp_session_t *session, svc_info_t *si)
2238 sdp_record_t record;
2239 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2240 uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
2241 sdp_profile_desc_t profile[1];
2242 sdp_list_t *aproto, *proto[3];
2243 sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
2245 uint8_t dtd = SDP_UINT16;
2246 uint8_t dtd2 = SDP_UINT8;
2247 uint8_t dtd_data = SDP_TEXT_STR8;
2253 uint8_t hid_spec_type = 0x22;
2254 uint16_t hid_attr_lang[] = { 0x409, 0x100 };
2255 static const uint16_t ctrl = 0x11;
2256 static const uint16_t intr = 0x13;
2257 static const uint16_t hid_attr[] = { 0x100, 0x111, 0x40, 0x0d, 0x01, 0x01 };
2258 static const uint16_t hid_attr2[] = { 0x0, 0x01, 0x100, 0x1f40, 0x01, 0x01 };
2259 const uint8_t hid_spec[] = {
2260 0x05, 0x01, // usage page
2261 0x09, 0x06, // keyboard
2262 0xa1, 0x01, // key codes
2263 0x85, 0x01, // minimum
2265 0x19, 0xe0, // logical min
2266 0x29, 0xe7, // logical max
2267 0x15, 0x00, // report size
2268 0x25, 0x01, // report count
2269 0x75, 0x01, // input data variable absolute
2270 0x95, 0x08, // report count
2271 0x81, 0x02, // report size
2312 memset(&record, 0, sizeof(sdp_record_t));
2313 record.handle = si->handle;
2315 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2316 root = sdp_list_append(0, &root_uuid);
2317 sdp_set_browse_groups(&record, root);
2319 add_lang_attr(&record);
2321 sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
2322 svclass_id = sdp_list_append(0, &hidkb_uuid);
2323 sdp_set_service_classes(&record, svclass_id);
2325 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
2326 profile[0].version = 0x0100;
2327 pfseq = sdp_list_append(0, profile);
2328 sdp_set_profile_descs(&record, pfseq);
2331 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2332 proto[1] = sdp_list_append(0, &l2cap_uuid);
2333 psm = sdp_data_alloc(SDP_UINT16, &ctrl);
2334 proto[1] = sdp_list_append(proto[1], psm);
2335 apseq = sdp_list_append(0, proto[1]);
2337 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2338 proto[2] = sdp_list_append(0, &hidp_uuid);
2339 apseq = sdp_list_append(apseq, proto[2]);
2341 aproto = sdp_list_append(0, apseq);
2342 sdp_set_access_protos(&record, aproto);
2344 /* additional protocols */
2345 proto[1] = sdp_list_append(0, &l2cap_uuid);
2346 psm = sdp_data_alloc(SDP_UINT16, &intr);
2347 proto[1] = sdp_list_append(proto[1], psm);
2348 apseq = sdp_list_append(0, proto[1]);
2350 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2351 proto[2] = sdp_list_append(0, &hidp_uuid);
2352 apseq = sdp_list_append(apseq, proto[2]);
2354 aproto = sdp_list_append(0, apseq);
2355 sdp_set_add_access_protos(&record, aproto);
2357 sdp_set_info_attr(&record, "HID Keyboard", NULL, NULL);
2359 for (i = 0; i < sizeof(hid_attr) / 2; i++)
2360 sdp_attr_add_new(&record,
2361 SDP_ATTR_HID_DEVICE_RELEASE_NUMBER + i,
2362 SDP_UINT16, &hid_attr[i]);
2365 values[0] = &hid_spec_type;
2366 dtds[1] = &dtd_data;
2367 values[1] = (uint8_t *) hid_spec;
2369 leng[1] = sizeof(hid_spec);
2370 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
2371 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
2372 sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
2374 for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
2376 values2[i] = &hid_attr_lang[i];
2379 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
2380 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
2381 sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
2383 sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE, SDP_UINT16, &hid_attr2[0]);
2385 for (i = 0; i < sizeof(hid_attr2) / 2 - 1; i++)
2386 sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP + i,
2387 SDP_UINT16, &hid_attr2[i + 1]);
2389 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
2390 printf("Service Record registration failed\n");
2394 printf("HID keyboard service registered\n");
2399 static int add_hid_wiimote(sdp_session_t *session, svc_info_t *si)
2401 sdp_record_t record;
2402 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2403 uuid_t root_uuid, hid_uuid, l2cap_uuid, hidp_uuid;
2404 sdp_profile_desc_t profile[1];
2405 sdp_list_t *aproto, *proto[3];
2406 sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
2408 uint8_t dtd = SDP_UINT16;
2409 uint8_t dtd2 = SDP_UINT8;
2410 uint8_t dtd_data = SDP_TEXT_STR8;
2416 uint8_t hid_spec_type = 0x22;
2417 uint16_t hid_attr_lang[] = { 0x409, 0x100 };
2418 uint16_t ctrl = 0x11, intr = 0x13;
2419 uint16_t hid_release = 0x0100, parser_version = 0x0111;
2420 uint8_t subclass = 0x04, country = 0x33;
2421 uint8_t virtual_cable = 0, reconnect = 1, sdp_disable = 0;
2422 uint8_t battery = 1, remote_wakeup = 1;
2423 uint16_t profile_version = 0x0100, superv_timeout = 0x0c80;
2424 uint8_t norm_connect = 0, boot_device = 0;
2425 const uint8_t hid_spec[] = {
2426 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10,
2427 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
2428 0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00,
2429 0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2430 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00,
2431 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2432 0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2433 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2434 0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
2435 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00,
2436 0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
2437 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2438 0x85, 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2439 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00,
2440 0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2441 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00,
2442 0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00,
2443 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00,
2444 0x85, 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00,
2445 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00,
2446 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2447 0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2448 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2449 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2450 0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2451 0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2452 0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2456 memset(&record, 0, sizeof(sdp_record_t));
2457 record.handle = si->handle;
2459 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2460 root = sdp_list_append(NULL, &root_uuid);
2461 sdp_set_browse_groups(&record, root);
2463 sdp_uuid16_create(&hid_uuid, HID_SVCLASS_ID);
2464 svclass_id = sdp_list_append(NULL, &hid_uuid);
2465 sdp_set_service_classes(&record, svclass_id);
2467 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
2468 profile[0].version = 0x0100;
2469 pfseq = sdp_list_append(NULL, profile);
2470 sdp_set_profile_descs(&record, pfseq);
2472 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2473 proto[1] = sdp_list_append(0, &l2cap_uuid);
2474 psm = sdp_data_alloc(SDP_UINT16, &ctrl);
2475 proto[1] = sdp_list_append(proto[1], psm);
2476 apseq = sdp_list_append(0, proto[1]);
2478 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2479 proto[2] = sdp_list_append(0, &hidp_uuid);
2480 apseq = sdp_list_append(apseq, proto[2]);
2482 aproto = sdp_list_append(0, apseq);
2483 sdp_set_access_protos(&record, aproto);
2485 proto[1] = sdp_list_append(0, &l2cap_uuid);
2486 psm = sdp_data_alloc(SDP_UINT16, &intr);
2487 proto[1] = sdp_list_append(proto[1], psm);
2488 apseq = sdp_list_append(0, proto[1]);
2490 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2491 proto[2] = sdp_list_append(0, &hidp_uuid);
2492 apseq = sdp_list_append(apseq, proto[2]);
2494 aproto = sdp_list_append(0, apseq);
2495 sdp_set_add_access_protos(&record, aproto);
2497 add_lang_attr(&record);
2499 sdp_set_info_attr(&record, "Nintendo RVL-CNT-01",
2500 "Nintendo", "Nintendo RVL-CNT-01");
2502 sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER,
2503 SDP_UINT16, &hid_release);
2505 sdp_attr_add_new(&record, SDP_ATTR_HID_PARSER_VERSION,
2506 SDP_UINT16, &parser_version);
2508 sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_SUBCLASS,
2509 SDP_UINT8, &subclass);
2511 sdp_attr_add_new(&record, SDP_ATTR_HID_COUNTRY_CODE,
2512 SDP_UINT8, &country);
2514 sdp_attr_add_new(&record, SDP_ATTR_HID_VIRTUAL_CABLE,
2515 SDP_BOOL, &virtual_cable);
2517 sdp_attr_add_new(&record, SDP_ATTR_HID_RECONNECT_INITIATE,
2518 SDP_BOOL, &reconnect);
2521 values[0] = &hid_spec_type;
2522 dtds[1] = &dtd_data;
2523 values[1] = (uint8_t *) hid_spec;
2525 leng[1] = sizeof(hid_spec);
2526 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
2527 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
2528 sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
2530 for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
2532 values2[i] = &hid_attr_lang[i];
2535 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
2536 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
2537 sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
2539 sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE,
2540 SDP_BOOL, &sdp_disable);
2542 sdp_attr_add_new(&record, SDP_ATTR_HID_BATTERY_POWER,
2543 SDP_BOOL, &battery);
2545 sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP,
2546 SDP_BOOL, &remote_wakeup);
2548 sdp_attr_add_new(&record, SDP_ATTR_HID_PROFILE_VERSION,
2549 SDP_UINT16, &profile_version);
2551 sdp_attr_add_new(&record, SDP_ATTR_HID_SUPERVISION_TIMEOUT,
2552 SDP_UINT16, &superv_timeout);
2554 sdp_attr_add_new(&record, SDP_ATTR_HID_NORMALLY_CONNECTABLE,
2555 SDP_BOOL, &norm_connect);
2557 sdp_attr_add_new(&record, SDP_ATTR_HID_BOOT_DEVICE,
2558 SDP_BOOL, &boot_device);
2560 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
2561 printf("Service Record registration failed\n");
2565 printf("Wii-Mote service registered\n");
2570 static int add_cip(sdp_session_t *session, svc_info_t *si)
2572 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2573 uuid_t root_uuid, l2cap, cmtp, cip;
2574 sdp_profile_desc_t profile[1];
2575 sdp_list_t *aproto, *proto[2];
2576 sdp_record_t record;
2577 uint16_t psm = si->psm ? si->psm : 0x1001;
2578 uint8_t netid = si->network ? si->network : 0x02; // 0x02 = ISDN, 0x03 = GSM
2579 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
2582 memset(&record, 0, sizeof(sdp_record_t));
2583 record.handle = si->handle;
2585 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2586 root = sdp_list_append(0, &root_uuid);
2587 sdp_set_browse_groups(&record, root);
2589 sdp_uuid16_create(&cip, CIP_SVCLASS_ID);
2590 svclass_id = sdp_list_append(0, &cip);
2591 sdp_set_service_classes(&record, svclass_id);
2593 sdp_uuid16_create(&profile[0].uuid, CIP_PROFILE_ID);
2594 profile[0].version = 0x0100;
2595 pfseq = sdp_list_append(0, &profile[0]);
2596 sdp_set_profile_descs(&record, pfseq);
2598 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2599 proto[0] = sdp_list_append(0, &l2cap);
2600 apseq = sdp_list_append(0, proto[0]);
2601 proto[0] = sdp_list_append(proto[0], sdp_data_alloc(SDP_UINT16, &psm));
2602 apseq = sdp_list_append(0, proto[0]);
2604 sdp_uuid16_create(&cmtp, CMTP_UUID);
2605 proto[1] = sdp_list_append(0, &cmtp);
2606 apseq = sdp_list_append(apseq, proto[1]);
2608 aproto = sdp_list_append(0, apseq);
2609 sdp_set_access_protos(&record, aproto);
2611 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
2613 sdp_set_info_attr(&record, "Common ISDN Access", 0, 0);
2615 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2616 printf("Service Record registration failed\n");
2621 printf("CIP service registered\n");
2624 sdp_list_free(proto[0], 0);
2625 sdp_list_free(proto[1], 0);
2626 sdp_list_free(apseq, 0);
2627 sdp_list_free(aproto, 0);
2628 sdp_data_free(network);
2633 static int add_ctp(sdp_session_t *session, svc_info_t *si)
2635 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2636 uuid_t root_uuid, l2cap, tcsbin, ctp;
2637 sdp_profile_desc_t profile[1];
2638 sdp_list_t *aproto, *proto[2];
2639 sdp_record_t record;
2640 uint8_t netid = si->network ? si->network : 0x02; // 0x01-0x07 cf. p120 profile document
2641 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
2644 memset(&record, 0, sizeof(sdp_record_t));
2645 record.handle = si->handle;
2647 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2648 root = sdp_list_append(0, &root_uuid);
2649 sdp_set_browse_groups(&record, root);
2651 sdp_uuid16_create(&ctp, CORDLESS_TELEPHONY_SVCLASS_ID);
2652 svclass_id = sdp_list_append(0, &ctp);
2653 sdp_set_service_classes(&record, svclass_id);
2655 sdp_uuid16_create(&profile[0].uuid, CORDLESS_TELEPHONY_PROFILE_ID);
2656 profile[0].version = 0x0100;
2657 pfseq = sdp_list_append(0, &profile[0]);
2658 sdp_set_profile_descs(&record, pfseq);
2660 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2661 proto[0] = sdp_list_append(0, &l2cap);
2662 apseq = sdp_list_append(0, proto[0]);
2664 sdp_uuid16_create(&tcsbin, TCS_BIN_UUID);
2665 proto[1] = sdp_list_append(0, &tcsbin);
2666 apseq = sdp_list_append(apseq, proto[1]);
2668 aproto = sdp_list_append(0, apseq);
2669 sdp_set_access_protos(&record, aproto);
2671 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
2673 sdp_set_info_attr(&record, "Cordless Telephony", 0, 0);
2675 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2676 printf("Service Record registration failed\n");
2681 printf("CTP service registered\n");
2684 sdp_list_free(proto[0], 0);
2685 sdp_list_free(proto[1], 0);
2686 sdp_list_free(apseq, 0);
2687 sdp_list_free(aproto, 0);
2688 sdp_data_free(network);
2693 static int add_a2source(sdp_session_t *session, svc_info_t *si)
2695 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2696 uuid_t root_uuid, l2cap, avdtp, a2src;
2697 sdp_profile_desc_t profile[1];
2698 sdp_list_t *aproto, *proto[2];
2699 sdp_record_t record;
2700 sdp_data_t *psm, *version;
2701 uint16_t lp = 0x0019, ver = 0x0100;
2704 memset(&record, 0, sizeof(sdp_record_t));
2705 record.handle = si->handle;
2707 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2708 root = sdp_list_append(0, &root_uuid);
2709 sdp_set_browse_groups(&record, root);
2711 sdp_uuid16_create(&a2src, AUDIO_SOURCE_SVCLASS_ID);
2712 svclass_id = sdp_list_append(0, &a2src);
2713 sdp_set_service_classes(&record, svclass_id);
2715 sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
2716 profile[0].version = 0x0100;
2717 pfseq = sdp_list_append(0, &profile[0]);
2718 sdp_set_profile_descs(&record, pfseq);
2720 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2721 proto[0] = sdp_list_append(0, &l2cap);
2722 psm = sdp_data_alloc(SDP_UINT16, &lp);
2723 proto[0] = sdp_list_append(proto[0], psm);
2724 apseq = sdp_list_append(0, proto[0]);
2726 sdp_uuid16_create(&avdtp, AVDTP_UUID);
2727 proto[1] = sdp_list_append(0, &avdtp);
2728 version = sdp_data_alloc(SDP_UINT16, &ver);
2729 proto[1] = sdp_list_append(proto[1], version);
2730 apseq = sdp_list_append(apseq, proto[1]);
2732 aproto = sdp_list_append(0, apseq);
2733 sdp_set_access_protos(&record, aproto);
2735 sdp_set_info_attr(&record, "Audio Source", 0, 0);
2737 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2738 printf("Service Record registration failed\n");
2743 printf("Audio source service registered\n");
2746 sdp_list_free(proto[0], 0);
2747 sdp_list_free(proto[1], 0);
2748 sdp_list_free(apseq, 0);
2749 sdp_list_free(aproto, 0);
2754 static int add_a2sink(sdp_session_t *session, svc_info_t *si)
2756 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2757 uuid_t root_uuid, l2cap, avdtp, a2snk;
2758 sdp_profile_desc_t profile[1];
2759 sdp_list_t *aproto, *proto[2];
2760 sdp_record_t record;
2761 sdp_data_t *psm, *version;
2762 uint16_t lp = 0x0019, ver = 0x0100;
2765 memset(&record, 0, sizeof(sdp_record_t));
2766 record.handle = si->handle;
2768 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2769 root = sdp_list_append(0, &root_uuid);
2770 sdp_set_browse_groups(&record, root);
2772 sdp_uuid16_create(&a2snk, AUDIO_SINK_SVCLASS_ID);
2773 svclass_id = sdp_list_append(0, &a2snk);
2774 sdp_set_service_classes(&record, svclass_id);
2776 sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
2777 profile[0].version = 0x0100;
2778 pfseq = sdp_list_append(0, &profile[0]);
2779 sdp_set_profile_descs(&record, pfseq);
2781 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2782 proto[0] = sdp_list_append(0, &l2cap);
2783 psm = sdp_data_alloc(SDP_UINT16, &lp);
2784 proto[0] = sdp_list_append(proto[0], psm);
2785 apseq = sdp_list_append(0, proto[0]);
2787 sdp_uuid16_create(&avdtp, AVDTP_UUID);
2788 proto[1] = sdp_list_append(0, &avdtp);
2789 version = sdp_data_alloc(SDP_UINT16, &ver);
2790 proto[1] = sdp_list_append(proto[1], version);
2791 apseq = sdp_list_append(apseq, proto[1]);
2793 aproto = sdp_list_append(0, apseq);
2794 sdp_set_access_protos(&record, aproto);
2796 sdp_set_info_attr(&record, "Audio Sink", 0, 0);
2798 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2799 printf("Service Record registration failed\n");
2804 printf("Audio sink service registered\n");
2807 sdp_list_free(proto[0], 0);
2808 sdp_list_free(proto[1], 0);
2809 sdp_list_free(apseq, 0);
2810 sdp_list_free(aproto, 0);
2815 static int add_avrct(sdp_session_t *session, svc_info_t *si)
2817 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2818 uuid_t root_uuid, l2cap, avctp, avrct;
2819 sdp_profile_desc_t profile[1];
2820 sdp_list_t *aproto, *proto[2];
2821 sdp_record_t record;
2822 sdp_data_t *psm, *version, *features;
2823 uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
2826 memset(&record, 0, sizeof(sdp_record_t));
2827 record.handle = si->handle;
2829 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2830 root = sdp_list_append(0, &root_uuid);
2831 sdp_set_browse_groups(&record, root);
2833 sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID);
2834 svclass_id = sdp_list_append(0, &avrct);
2835 sdp_set_service_classes(&record, svclass_id);
2837 sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
2838 profile[0].version = 0x0100;
2839 pfseq = sdp_list_append(0, &profile[0]);
2840 sdp_set_profile_descs(&record, pfseq);
2842 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2843 proto[0] = sdp_list_append(0, &l2cap);
2844 psm = sdp_data_alloc(SDP_UINT16, &lp);
2845 proto[0] = sdp_list_append(proto[0], psm);
2846 apseq = sdp_list_append(0, proto[0]);
2848 sdp_uuid16_create(&avctp, AVCTP_UUID);
2849 proto[1] = sdp_list_append(0, &avctp);
2850 version = sdp_data_alloc(SDP_UINT16, &ver);
2851 proto[1] = sdp_list_append(proto[1], version);
2852 apseq = sdp_list_append(apseq, proto[1]);
2854 aproto = sdp_list_append(0, apseq);
2855 sdp_set_access_protos(&record, aproto);
2857 features = sdp_data_alloc(SDP_UINT16, &feat);
2858 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
2860 sdp_set_info_attr(&record, "AVRCP CT", 0, 0);
2862 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2863 printf("Service Record registration failed\n");
2868 printf("Remote control service registered\n");
2871 sdp_list_free(proto[0], 0);
2872 sdp_list_free(proto[1], 0);
2873 sdp_list_free(apseq, 0);
2874 sdp_list_free(aproto, 0);
2879 static int add_avrtg(sdp_session_t *session, svc_info_t *si)
2881 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2882 uuid_t root_uuid, l2cap, avctp, avrtg;
2883 sdp_profile_desc_t profile[1];
2884 sdp_list_t *aproto, *proto[2];
2885 sdp_record_t record;
2886 sdp_data_t *psm, *version, *features;
2887 uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
2890 memset(&record, 0, sizeof(sdp_record_t));
2891 record.handle = si->handle;
2893 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2894 root = sdp_list_append(0, &root_uuid);
2895 sdp_set_browse_groups(&record, root);
2897 sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID);
2898 svclass_id = sdp_list_append(0, &avrtg);
2899 sdp_set_service_classes(&record, svclass_id);
2901 sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
2902 profile[0].version = 0x0100;
2903 pfseq = sdp_list_append(0, &profile[0]);
2904 sdp_set_profile_descs(&record, pfseq);
2906 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2907 proto[0] = sdp_list_append(0, &l2cap);
2908 psm = sdp_data_alloc(SDP_UINT16, &lp);
2909 proto[0] = sdp_list_append(proto[0], psm);
2910 apseq = sdp_list_append(0, proto[0]);
2912 sdp_uuid16_create(&avctp, AVCTP_UUID);
2913 proto[1] = sdp_list_append(0, &avctp);
2914 version = sdp_data_alloc(SDP_UINT16, &ver);
2915 proto[1] = sdp_list_append(proto[1], version);
2916 apseq = sdp_list_append(apseq, proto[1]);
2918 aproto = sdp_list_append(0, apseq);
2919 sdp_set_access_protos(&record, aproto);
2921 features = sdp_data_alloc(SDP_UINT16, &feat);
2922 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
2924 sdp_set_info_attr(&record, "AVRCP TG", 0, 0);
2926 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2927 printf("Service Record registration failed\n");
2932 printf("Remote target service registered\n");
2935 sdp_list_free(proto[0], 0);
2936 sdp_list_free(proto[1], 0);
2937 sdp_list_free(apseq, 0);
2938 sdp_list_free(aproto, 0);
2943 static int add_udi_ue(sdp_session_t *session, svc_info_t *si)
2945 sdp_record_t record;
2946 sdp_list_t *root, *svclass, *proto;
2947 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
2948 uint8_t channel = si->channel ? si->channel: 18;
2950 memset(&record, 0, sizeof(record));
2951 record.handle = si->handle;
2953 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2954 root = sdp_list_append(NULL, &root_uuid);
2955 sdp_set_browse_groups(&record, root);
2956 sdp_list_free(root, NULL);
2958 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2959 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
2961 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
2962 proto = sdp_list_append(proto, sdp_list_append(
2963 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
2965 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
2967 sdp_uuid16_create(&svclass_uuid, UDI_MT_SVCLASS_ID);
2968 svclass = sdp_list_append(NULL, &svclass_uuid);
2969 sdp_set_service_classes(&record, svclass);
2970 sdp_list_free(svclass, NULL);
2972 sdp_set_info_attr(&record, "UDI UE", NULL, NULL);
2974 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2975 printf("Service Record registration failed\n");
2979 printf("UDI UE service registered\n");
2984 static int add_udi_te(sdp_session_t *session, svc_info_t *si)
2986 sdp_record_t record;
2987 sdp_list_t *root, *svclass, *proto;
2988 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
2989 uint8_t channel = si->channel ? si->channel: 19;
2991 memset(&record, 0, sizeof(record));
2992 record.handle = si->handle;
2994 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2995 root = sdp_list_append(NULL, &root_uuid);
2996 sdp_set_browse_groups(&record, root);
2997 sdp_list_free(root, NULL);
2999 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3000 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3002 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3003 proto = sdp_list_append(proto, sdp_list_append(
3004 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3006 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3008 sdp_uuid16_create(&svclass_uuid, UDI_TA_SVCLASS_ID);
3009 svclass = sdp_list_append(NULL, &svclass_uuid);
3010 sdp_set_service_classes(&record, svclass);
3011 sdp_list_free(svclass, NULL);
3013 sdp_set_info_attr(&record, "UDI TE", NULL, NULL);
3015 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3016 printf("Service Record registration failed\n");
3020 printf("UDI TE service registered\n");
3025 static unsigned char sr1_uuid[] = { 0xbc, 0x19, 0x9c, 0x24, 0x95, 0x8b, 0x4c, 0xc0,
3026 0xa2, 0xcb, 0xfd, 0x8a, 0x30, 0xbf, 0x32, 0x06 };
3028 static int add_sr1(sdp_session_t *session, svc_info_t *si)
3030 sdp_record_t record;
3031 sdp_list_t *root, *svclass;
3032 uuid_t root_uuid, svclass_uuid;
3034 memset(&record, 0, sizeof(record));
3035 record.handle = si->handle;
3037 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3038 root = sdp_list_append(NULL, &root_uuid);
3039 sdp_set_browse_groups(&record, root);
3041 sdp_uuid128_create(&svclass_uuid, (void *) sr1_uuid);
3042 svclass = sdp_list_append(NULL, &svclass_uuid);
3043 sdp_set_service_classes(&record, svclass);
3045 sdp_set_info_attr(&record, "TOSHIBA SR-1", NULL, NULL);
3047 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3048 printf("Service Record registration failed\n");
3052 printf("Toshiba Speech Recognition SR-1 service record registered\n");
3057 static unsigned char syncmls_uuid[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
3058 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
3060 static unsigned char syncmlc_uuid[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
3061 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
3063 static int add_syncml(sdp_session_t *session, svc_info_t *si)
3065 sdp_record_t record;
3066 sdp_list_t *root, *svclass, *proto;
3067 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
3068 uint8_t channel = si->channel ? si->channel: 15;
3070 memset(&record, 0, sizeof(record));
3071 record.handle = si->handle;
3073 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3074 root = sdp_list_append(NULL, &root_uuid);
3075 sdp_set_browse_groups(&record, root);
3077 sdp_uuid128_create(&svclass_uuid, (void *) syncmlc_uuid);
3078 svclass = sdp_list_append(NULL, &svclass_uuid);
3079 sdp_set_service_classes(&record, svclass);
3081 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3082 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3084 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3085 proto = sdp_list_append(proto, sdp_list_append(
3086 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3088 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
3089 proto = sdp_list_append(proto, sdp_list_append(NULL, &obex_uuid));
3091 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3093 sdp_set_info_attr(&record, "SyncML Client", NULL, NULL);
3095 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3096 printf("Service Record registration failed\n");
3100 printf("SyncML Client service record registered\n");
3105 static unsigned char async_uuid[] = { 0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62,
3106 0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C };
3108 static int add_activesync(sdp_session_t *session, svc_info_t *si)
3110 sdp_record_t record;
3111 sdp_list_t *root, *svclass, *proto;
3112 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3113 uint8_t channel = si->channel ? si->channel: 21;
3115 memset(&record, 0, sizeof(record));
3116 record.handle = si->handle;
3118 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3119 root = sdp_list_append(NULL, &root_uuid);
3120 sdp_set_browse_groups(&record, root);
3122 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3123 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3125 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3126 proto = sdp_list_append(proto, sdp_list_append(
3127 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3129 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3131 sdp_uuid128_create(&svclass_uuid, (void *) async_uuid);
3132 svclass = sdp_list_append(NULL, &svclass_uuid);
3133 sdp_set_service_classes(&record, svclass);
3135 sdp_set_info_attr(&record, "Microsoft ActiveSync", NULL, NULL);
3137 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3138 printf("Service Record registration failed\n");
3142 printf("ActiveSync service record registered\n");
3147 static unsigned char hotsync_uuid[] = { 0xD8, 0x0C, 0xF9, 0xEA, 0x13, 0x4C, 0x11, 0xD5,
3148 0x83, 0xCE, 0x00, 0x30, 0x65, 0x7C, 0x54, 0x3C };
3150 static int add_hotsync(sdp_session_t *session, svc_info_t *si)
3152 sdp_record_t record;
3153 sdp_list_t *root, *svclass, *proto;
3154 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3155 uint8_t channel = si->channel ? si->channel: 22;
3157 memset(&record, 0, sizeof(record));
3158 record.handle = si->handle;
3160 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3161 root = sdp_list_append(NULL, &root_uuid);
3162 sdp_set_browse_groups(&record, root);
3164 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3165 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3167 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3168 proto = sdp_list_append(proto, sdp_list_append(
3169 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3171 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3173 sdp_uuid128_create(&svclass_uuid, (void *) hotsync_uuid);
3174 svclass = sdp_list_append(NULL, &svclass_uuid);
3175 sdp_set_service_classes(&record, svclass);
3177 sdp_set_info_attr(&record, "PalmOS HotSync", NULL, NULL);
3179 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3180 printf("Service Record registration failed\n");
3184 printf("HotSync service record registered\n");
3189 static unsigned char palmos_uuid[] = { 0xF5, 0xBE, 0xB6, 0x51, 0x41, 0x71, 0x40, 0x51,
3190 0xAC, 0xF5, 0x6C, 0xA7, 0x20, 0x22, 0x42, 0xF0 };
3192 static int add_palmos(sdp_session_t *session, svc_info_t *si)
3194 sdp_record_t record;
3195 sdp_list_t *root, *svclass;
3196 uuid_t root_uuid, svclass_uuid;
3198 memset(&record, 0, sizeof(record));
3199 record.handle = si->handle;
3201 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3202 root = sdp_list_append(NULL, &root_uuid);
3203 sdp_set_browse_groups(&record, root);
3205 sdp_uuid128_create(&svclass_uuid, (void *) palmos_uuid);
3206 svclass = sdp_list_append(NULL, &svclass_uuid);
3207 sdp_set_service_classes(&record, svclass);
3209 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3210 printf("Service Record registration failed\n");
3214 printf("PalmOS service record registered\n");
3219 static unsigned char nokid_uuid[] = { 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x10, 0x00,
3220 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3222 static int add_nokiaid(sdp_session_t *session, svc_info_t *si)
3224 sdp_record_t record;
3225 sdp_list_t *root, *svclass;
3226 uuid_t root_uuid, svclass_uuid;
3227 uint16_t verid = 0x005f;
3228 sdp_data_t *version = sdp_data_alloc(SDP_UINT16, &verid);
3230 memset(&record, 0, sizeof(record));
3231 record.handle = si->handle;
3233 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3234 root = sdp_list_append(NULL, &root_uuid);
3235 sdp_set_browse_groups(&record, root);
3237 sdp_uuid128_create(&svclass_uuid, (void *) nokid_uuid);
3238 svclass = sdp_list_append(NULL, &svclass_uuid);
3239 sdp_set_service_classes(&record, svclass);
3241 sdp_attr_add(&record, SDP_ATTR_SERVICE_VERSION, version);
3243 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3244 printf("Service Record registration failed\n");
3245 sdp_data_free(version);
3249 printf("Nokia ID service record registered\n");
3254 static unsigned char pcsuite_uuid[] = { 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x10, 0x00,
3255 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3257 static int add_pcsuite(sdp_session_t *session, svc_info_t *si)
3259 sdp_record_t record;
3260 sdp_list_t *root, *svclass, *proto;
3261 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3262 uint8_t channel = si->channel ? si->channel: 14;
3264 memset(&record, 0, sizeof(record));
3265 record.handle = si->handle;
3267 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3268 root = sdp_list_append(NULL, &root_uuid);
3269 sdp_set_browse_groups(&record, root);
3271 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3272 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3274 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3275 proto = sdp_list_append(proto, sdp_list_append(
3276 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3278 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3280 sdp_uuid128_create(&svclass_uuid, (void *) pcsuite_uuid);
3281 svclass = sdp_list_append(NULL, &svclass_uuid);
3282 sdp_set_service_classes(&record, svclass);
3284 sdp_set_info_attr(&record, "Nokia PC Suite", NULL, NULL);
3286 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3287 printf("Service Record registration failed\n");
3291 printf("Nokia PC Suite service registered\n");
3296 static unsigned char nftp_uuid[] = { 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x10, 0x00,
3297 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3299 static unsigned char nsyncml_uuid[] = { 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x10, 0x00,
3300 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3302 static unsigned char ngage_uuid[] = { 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x10, 0x00,
3303 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3305 static unsigned char apple_uuid[] = { 0xf0, 0x72, 0x2e, 0x20, 0x0f, 0x8b, 0x4e, 0x90,
3306 0x8c, 0xc2, 0x1b, 0x46, 0xf5, 0xf2, 0xef, 0xe2 };
3308 static int add_apple(sdp_session_t *session, svc_info_t *si)
3310 sdp_record_t record;
3313 uint32_t attr783 = 0x00000000;
3314 uint32_t attr785 = 0x00000002;
3315 uint16_t attr786 = 0x1234;
3317 memset(&record, 0, sizeof(record));
3318 record.handle = si->handle;
3320 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3321 root = sdp_list_append(NULL, &root_uuid);
3322 sdp_set_browse_groups(&record, root);
3324 sdp_attr_add_new(&record, 0x0780, SDP_UUID128, (void *) apple_uuid);
3325 sdp_attr_add_new(&record, 0x0781, SDP_TEXT_STR8, (void *) "Macmini");
3326 sdp_attr_add_new(&record, 0x0782, SDP_TEXT_STR8, (void *) "PowerMac10,1");
3327 sdp_attr_add_new(&record, 0x0783, SDP_UINT32, (void *) &attr783);
3328 sdp_attr_add_new(&record, 0x0784, SDP_TEXT_STR8, (void *) "1.6.6f22");
3329 sdp_attr_add_new(&record, 0x0785, SDP_UINT32, (void *) &attr785);
3330 sdp_attr_add_new(&record, 0x0786, SDP_UUID16, (void *) &attr786);
3332 sdp_set_info_attr(&record, "Apple Macintosh Attributes", NULL, NULL);
3334 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3335 printf("Service Record registration failed\n");
3339 printf("Apple attribute service registered\n");
3344 static int add_isync(sdp_session_t *session, svc_info_t *si)
3346 sdp_record_t record;
3347 sdp_list_t *root, *svclass, *proto;
3348 uuid_t root_uuid, svclass_uuid, serial_uuid, l2cap_uuid, rfcomm_uuid;
3349 uint8_t channel = si->channel ? si->channel : 16;
3351 memset(&record, 0, sizeof(record));
3352 record.handle = si->handle;
3354 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3355 root = sdp_list_append(NULL, &root_uuid);
3356 sdp_set_browse_groups(&record, root);
3358 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3359 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3361 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3362 proto = sdp_list_append(proto, sdp_list_append(
3363 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3365 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3367 sdp_uuid16_create(&serial_uuid, SERIAL_PORT_SVCLASS_ID);
3368 svclass = sdp_list_append(NULL, &serial_uuid);
3370 sdp_uuid16_create(&svclass_uuid, APPLE_AGENT_SVCLASS_ID);
3371 svclass = sdp_list_append(svclass, &svclass_uuid);
3373 sdp_set_service_classes(&record, svclass);
3375 sdp_set_info_attr(&record, "AppleAgent", "Bluetooth acceptor", "Apple Computer Ltd.");
3377 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3378 printf("Service Record registration failed\n");
3382 printf("Apple iSync service registered\n");
3387 static int add_semchla(sdp_session_t *session, svc_info_t *si)
3389 sdp_record_t record;
3390 sdp_profile_desc_t profile;
3391 sdp_list_t *root, *svclass, *proto, *profiles;
3392 uuid_t root_uuid, service_uuid, l2cap_uuid, semchla_uuid;
3393 uint16_t psm = 0xf0f9;
3395 memset(&record, 0, sizeof(record));
3396 record.handle = si->handle;
3398 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3399 root = sdp_list_append(NULL, &root_uuid);
3400 sdp_set_browse_groups(&record, root);
3402 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3403 proto = sdp_list_append(NULL, sdp_list_append(
3404 sdp_list_append(NULL, &l2cap_uuid), sdp_data_alloc(SDP_UINT16, &psm)));
3406 sdp_uuid32_create(&semchla_uuid, 0x8e770300);
3407 proto = sdp_list_append(proto, sdp_list_append(NULL, &semchla_uuid));
3409 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3411 sdp_uuid32_create(&service_uuid, 0x8e771301);
3412 svclass = sdp_list_append(NULL, &service_uuid);
3414 sdp_set_service_classes(&record, svclass);
3416 sdp_uuid32_create(&profile.uuid, 0x8e771302); // Headset
3417 //sdp_uuid32_create(&profile.uuid, 0x8e771303); // Phone
3418 profile.version = 0x0100;
3419 profiles = sdp_list_append(NULL, &profile);
3420 sdp_set_profile_descs(&record, profiles);
3422 sdp_set_info_attr(&record, "SEMC HLA", NULL, NULL);
3424 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3425 printf("Service Record registration failed\n");
3429 /* SEMC High Level Authentication */
3430 printf("SEMC HLA service registered\n");
3438 int (*add)(sdp_session_t *sess, svc_info_t *si);
3439 unsigned char *uuid;
3441 { "DID", PNP_INFO_SVCLASS_ID, NULL, },
3443 { "SP", SERIAL_PORT_SVCLASS_ID, add_sp },
3444 { "DUN", DIALUP_NET_SVCLASS_ID, add_dun },
3445 { "LAN", LAN_ACCESS_SVCLASS_ID, add_lan },
3446 { "FAX", FAX_SVCLASS_ID, add_fax },
3447 { "OPUSH", OBEX_OBJPUSH_SVCLASS_ID, add_opush },
3448 { "FTP", OBEX_FILETRANS_SVCLASS_ID, add_ftp },
3449 { "PRINT", DIRECT_PRINTING_SVCLASS_ID, add_directprint },
3451 { "HS", HEADSET_SVCLASS_ID, add_headset },
3452 { "HSAG", HEADSET_AGW_SVCLASS_ID, add_headset_ag },
3453 { "HF", HANDSFREE_SVCLASS_ID, add_handsfree },
3454 { "HFAG", HANDSFREE_AGW_SVCLASS_ID, add_handsfree_ag},
3455 { "SAP", SAP_SVCLASS_ID, add_simaccess },
3456 { "PBAP", PBAP_SVCLASS_ID, add_pbap, },
3458 { "NAP", NAP_SVCLASS_ID, add_nap },
3459 { "GN", GN_SVCLASS_ID, add_gn },
3460 { "PANU", PANU_SVCLASS_ID, add_panu },
3462 { "HCRP", HCR_SVCLASS_ID, NULL },
3463 { "HID", HID_SVCLASS_ID, NULL },
3464 { "KEYB", HID_SVCLASS_ID, add_hid_keyb },
3465 { "WIIMOTE", HID_SVCLASS_ID, add_hid_wiimote },
3466 { "CIP", CIP_SVCLASS_ID, add_cip },
3467 { "CTP", CORDLESS_TELEPHONY_SVCLASS_ID, add_ctp },
3469 { "A2SRC", AUDIO_SOURCE_SVCLASS_ID, add_a2source },
3470 { "A2SNK", AUDIO_SINK_SVCLASS_ID, add_a2sink },
3471 { "AVRCT", AV_REMOTE_SVCLASS_ID, add_avrct },
3472 { "AVRTG", AV_REMOTE_TARGET_SVCLASS_ID, add_avrtg },
3474 { "UDIUE", UDI_MT_SVCLASS_ID, add_udi_ue },
3475 { "UDITE", UDI_TA_SVCLASS_ID, add_udi_te },
3477 { "SEMCHLA", 0x8e771301, add_semchla },
3479 { "SR1", 0, add_sr1, sr1_uuid },
3480 { "SYNCML", 0, add_syncml, syncmlc_uuid },
3481 { "SYNCMLSERV", 0, NULL, syncmls_uuid },
3482 { "ACTIVESYNC", 0, add_activesync, async_uuid },
3483 { "HOTSYNC", 0, add_hotsync, hotsync_uuid },
3484 { "PALMOS", 0, add_palmos, palmos_uuid },
3485 { "NOKID", 0, add_nokiaid, nokid_uuid },
3486 { "PCSUITE", 0, add_pcsuite, pcsuite_uuid },
3487 { "NFTP", 0, NULL, nftp_uuid },
3488 { "NSYNCML", 0, NULL, nsyncml_uuid },
3489 { "NGAGE", 0, NULL, ngage_uuid },
3490 { "APPLE", 0, add_apple, apple_uuid },
3492 { "ISYNC", APPLE_AGENT_SVCLASS_ID, add_isync, },
3497 /* Add local service */
3498 static int add_service(bdaddr_t *bdaddr, svc_info_t *si)
3500 sdp_session_t *sess;
3506 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
3510 for (i = 0; service[i].name; i++)
3511 if (!strcasecmp(service[i].name, si->name)) {
3513 ret = service[i].add(sess, si);
3517 printf("Unknown service name: %s\n", si->name);
3526 static struct option add_options[] = {
3527 { "help", 0, 0, 'h' },
3528 { "handle", 1, 0, 'r' },
3529 { "psm", 1, 0, 'p' },
3530 { "channel", 1, 0, 'c' },
3531 { "network", 1, 0, 'n' },
3535 static const char *add_help =
3537 "\tadd [--handle=RECORD_HANDLE --channel=CHANNEL] service\n";
3539 static int cmd_add(int argc, char **argv)
3544 memset(&si, 0, sizeof(si));
3545 si.handle = 0xffffffff;
3547 for_each_opt(opt, add_options, 0) {
3550 if (strncasecmp(optarg, "0x", 2))
3551 si.handle = atoi(optarg);
3553 si.handle = strtol(optarg + 2, NULL, 16);
3556 if (strncasecmp(optarg, "0x", 2))
3557 si.psm = atoi(optarg);
3559 si.psm = strtol(optarg + 2, NULL, 16);
3562 if (strncasecmp(optarg, "0x", 2))
3563 si.channel = atoi(optarg);
3565 si.channel = strtol(optarg + 2, NULL, 16);
3568 if (strncasecmp(optarg, "0x", 2))
3569 si.network = atoi(optarg);
3571 si.network = strtol(optarg + 2, NULL, 16);
3574 printf("%s", add_help);
3583 printf("%s", add_help);
3587 si.name = strdup(argv[0]);
3589 return add_service(0, &si);
3592 /* Delete local service */
3593 static int del_service(bdaddr_t *bdaddr, void *arg)
3595 uint32_t handle, range = 0x0000ffff;
3597 sdp_session_t *sess;
3601 printf("Record handle was not specified.\n");
3605 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
3607 printf("No local SDP server!\n");
3611 handle = strtoul((char *)arg, 0, 16);
3612 attr = sdp_list_append(0, &range);
3613 rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attr);
3614 sdp_list_free(attr, 0);
3617 printf("Service Record not found.\n");
3622 if (sdp_device_record_unregister(sess, &interface, rec)) {
3623 printf("Failed to unregister service record: %s\n", strerror(errno));
3628 printf("Service Record deleted.\n");
3634 static struct option del_options[] = {
3635 { "help", 0, 0, 'h' },
3639 static const char *del_help =
3641 "\tdel record_handle\n";
3643 static int cmd_del(int argc, char **argv)
3647 for_each_opt(opt, del_options, 0) {
3650 printf("%s", del_help);
3659 printf("%s", del_help);
3663 return del_service(NULL, argv[0]);
3667 * Perform an inquiry and search/browse all peer found.
3669 static void inquiry(handler_t handler, void *arg)
3671 inquiry_info ii[20];
3675 printf("Inquiring ...\n");
3676 if (sdp_general_inquiry(ii, 20, 8, &count) < 0) {
3677 printf("Inquiry failed\n");
3681 for (i = 0; i < count; i++)
3682 handler(&ii[i].bdaddr, arg);
3685 static void doprintf(void *data, const char *str)
3691 * Search for a specific SDP service
3693 static int do_search(bdaddr_t *bdaddr, struct search_context *context)
3695 sdp_list_t *attrid, *search, *seq, *next;
3696 uint32_t range = 0x0000ffff;
3698 sdp_session_t *sess;
3701 inquiry(do_search, context);
3705 sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
3706 ba2str(bdaddr, str);
3708 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
3712 if (context->view != RAW_VIEW) {
3714 printf("Searching for %s on %s ...\n", context->svc, str);
3716 printf("Browsing %s ...\n", str);
3719 attrid = sdp_list_append(0, &range);
3720 search = sdp_list_append(0, &context->group);
3721 if (sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq)) {
3722 printf("Service Search failed: %s\n", strerror(errno));
3726 sdp_list_free(attrid, 0);
3727 sdp_list_free(search, 0);
3729 for (; seq; seq = next) {
3730 sdp_record_t *rec = (sdp_record_t *) seq->data;
3731 struct search_context sub_context;
3733 switch (context->view) {
3735 /* Display user friendly form */
3736 print_service_attr(rec);
3740 /* Display full tree */
3741 print_tree_attr(rec);
3745 /* Display raw XML tree */
3746 convert_sdp_record_to_xml(rec, 0, doprintf);
3749 /* Display raw tree */
3750 print_raw_attr(rec);
3754 if (sdp_get_group_id(rec, &sub_context.group) != -1) {
3755 /* Set the subcontext for browsing the sub tree */
3756 memcpy(&sub_context, context, sizeof(struct search_context));
3757 /* Browse the next level down if not done */
3758 if (sub_context.group.value.uuid16 != context->group.value.uuid16)
3759 do_search(bdaddr, &sub_context);
3763 sdp_record_free(rec);
3770 static struct option browse_options[] = {
3771 { "help", 0, 0, 'h' },
3772 { "tree", 0, 0, 't' },
3773 { "raw", 0, 0, 'r' },
3774 { "xml", 0, 0, 'x' },
3775 { "uuid", 1, 0, 'u' },
3776 { "l2cap", 0, 0, 'l' },
3780 static const char *browse_help =
3782 "\tbrowse [--tree] [--raw] [--xml] [--uuid uuid] [--l2cap] [bdaddr]\n";
3785 * Browse the full SDP database (i.e. list all services starting from the
3788 static int cmd_browse(int argc, char **argv)
3790 struct search_context context;
3793 /* Initialise context */
3794 memset(&context, '\0', sizeof(struct search_context));
3795 /* We want to browse the top-level/root */
3796 sdp_uuid16_create(&context.group, PUBLIC_BROWSE_GROUP);
3798 for_each_opt(opt, browse_options, 0) {
3801 context.view = TREE_VIEW;
3804 context.view = RAW_VIEW;
3807 context.view = XML_VIEW;
3810 if (sscanf(optarg, "%i", &num) != 1 || num < 0 || num > 0xffff) {
3811 printf("Invalid uuid %s\n", optarg);
3814 sdp_uuid16_create(&context.group, num);
3817 sdp_uuid16_create(&context.group, L2CAP_UUID);
3820 printf("%s", browse_help);
3830 estr2ba(argv[0], &bdaddr);
3831 return do_search(&bdaddr, &context);
3834 return do_search(NULL, &context);
3837 static struct option search_options[] = {
3838 { "help", 0, 0, 'h' },
3839 { "bdaddr", 1, 0, 'b' },
3840 { "tree", 0, 0, 't' },
3841 { "raw", 0, 0, 'r' },
3842 { "xml", 0, 0, 'x' },
3846 static const char *search_help =
3848 "\tsearch [--bdaddr bdaddr] [--tree] [--raw] [--xml] SERVICE\n"
3849 "SERVICE is a name (string) or UUID (0x1002)\n";
3852 * Search for a specific SDP service
3854 * Note : we should support multiple services on the command line :
3855 * sdptool search 0x0100 0x000f 0x1002
3856 * (this would search a service supporting both L2CAP and BNEP directly in
3857 * the top level browse group)
3859 static int cmd_search(int argc, char **argv)
3861 struct search_context context;
3862 unsigned char *uuid = NULL;
3869 /* Initialise context */
3870 memset(&context, '\0', sizeof(struct search_context));
3872 for_each_opt(opt, search_options, 0) {
3875 estr2ba(optarg, &bdaddr);
3879 context.view = TREE_VIEW;
3882 context.view = RAW_VIEW;
3885 context.view = XML_VIEW;
3888 printf("%s", search_help);
3897 printf("%s", search_help);
3901 /* Note : we need to find a way to support search combining
3902 * multiple services */
3903 context.svc = strdup(argv[0]);
3904 if (!strncasecmp(context.svc, "0x", 2)) {
3906 /* This is a UUID16, just convert to int */
3907 sscanf(context.svc + 2, "%X", &num);
3909 printf("Class 0x%X\n", class);
3911 /* Convert class name to an UUID */
3913 for (i = 0; service[i].name; i++)
3914 if (strcasecmp(context.svc, service[i].name) == 0) {
3915 class = service[i].class;
3916 uuid = service[i].uuid;
3919 if (!class && !uuid) {
3920 printf("Unknown service %s\n", context.svc);
3926 if (class & 0xffff0000)
3927 sdp_uuid32_create(&context.group, class);
3929 uint16_t class16 = class & 0xffff;
3930 sdp_uuid16_create(&context.group, class16);
3933 sdp_uuid128_create(&context.group, uuid);
3936 return do_search(&bdaddr, &context);
3938 return do_search(NULL, &context);
3942 * Show how to get a specific SDP record by its handle.
3943 * Not really useful to the user, just show how it can be done...
3945 static int get_service(bdaddr_t *bdaddr, struct search_context *context, int quite)
3948 uint32_t range = 0x0000ffff;
3950 sdp_session_t *session = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
3954 ba2str(bdaddr, str);
3955 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
3959 attrid = sdp_list_append(0, &range);
3960 rec = sdp_service_attr_req(session, context->handle, SDP_ATTR_REQ_RANGE, attrid);
3961 sdp_list_free(attrid, 0);
3966 printf("Service get request failed.\n");
3972 switch (context->view) {
3974 /* Display user friendly form */
3975 print_service_attr(rec);
3979 /* Display full tree */
3980 print_tree_attr(rec);
3984 /* Display raw XML tree */
3985 convert_sdp_record_to_xml(rec, 0, doprintf);
3988 /* Display raw tree */
3989 print_raw_attr(rec);
3993 sdp_record_free(rec);
3997 static struct option records_options[] = {
3998 { "help", 0, 0, 'h' },
3999 { "tree", 0, 0, 't' },
4000 { "raw", 0, 0, 'r' },
4001 { "xml", 0, 0, 'x' },
4005 static const char *records_help =
4007 "\trecords [--tree] [--raw] [--xml] bdaddr\n";
4010 * Request possible SDP service records
4012 static int cmd_records(int argc, char **argv)
4014 struct search_context context;
4015 uint32_t base[] = { 0x10000, 0x10300, 0x10500,
4016 0x1002e, 0x110b, 0x90000, 0x2008000,
4017 0x4000000, 0x100000, 0x1000000,
4018 0x4f491100, 0x4f491200 };
4020 unsigned int i, n, num = 32;
4023 /* Initialise context */
4024 memset(&context, '\0', sizeof(struct search_context));
4026 for_each_opt(opt, records_options, 0) {
4029 context.view = TREE_VIEW;
4032 context.view = RAW_VIEW;
4035 context.view = XML_VIEW;
4038 printf("%s", records_help);
4047 printf("%s", records_help);
4051 /* Convert command line parameters */
4052 estr2ba(argv[0], &bdaddr);
4054 for (i = 0; i < sizeof(base) / sizeof(uint32_t); i++)
4055 for (n = 0; n < num; n++) {
4056 context.handle = base[i] + n;
4057 err = get_service(&bdaddr, &context, 1);
4066 static struct option get_options[] = {
4067 { "help", 0, 0, 'h' },
4068 { "bdaddr", 1, 0, 'b' },
4069 { "tree", 0, 0, 't' },
4070 { "raw", 0, 0, 'r' },
4071 { "xml", 0, 0, 'x' },
4075 static const char *get_help =
4077 "\tget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\n";
4080 * Get a specific SDP record on the local SDP server
4082 static int cmd_get(int argc, char **argv)
4084 struct search_context context;
4089 /* Initialise context */
4090 memset(&context, '\0', sizeof(struct search_context));
4092 for_each_opt(opt, get_options, 0) {
4095 estr2ba(optarg, &bdaddr);
4099 context.view = TREE_VIEW;
4102 context.view = RAW_VIEW;
4105 context.view = XML_VIEW;
4108 printf("%s", get_help);
4117 printf("%s", get_help);
4121 /* Convert command line parameters */
4122 context.handle = strtoul(argv[0], 0, 16);
4124 return get_service(has_addr ? &bdaddr : BDADDR_LOCAL, &context, 0);
4129 int (*func)(int argc, char **argv);
4132 { "search", cmd_search, "Search for a service" },
4133 { "browse", cmd_browse, "Browse all available services" },
4134 { "records", cmd_records, "Request all records" },
4135 { "add", cmd_add, "Add local service" },
4136 { "del", cmd_del, "Delete local service" },
4137 { "get", cmd_get, "Get local service" },
4138 { "setattr", cmd_setattr, "Set/Add attribute to a SDP record" },
4139 { "setseq", cmd_setseq, "Set/Add attribute sequence to a SDP record" },
4143 static void usage(void)
4147 printf("sdptool - SDP tool v%s\n", VERSION);
4149 "\tsdptool [options] <command> [command parameters]\n");
4151 "\t-h\t\tDisplay help\n"
4152 "\t-i\t\tSpecify source interface\n");
4154 printf("Commands:\n");
4155 for (i = 0; command[i].cmd; i++)
4156 printf("\t%-4s\t\t%s\n", command[i].cmd, command[i].doc);
4158 printf("\nServices:\n\t");
4159 for (i = 0; service[i].name; i++) {
4160 printf("%s ", service[i].name);
4161 pos += strlen(service[i].name) + 1;
4170 static struct option main_options[] = {
4171 { "help", 0, 0, 'h' },
4172 { "device", 1, 0, 'i' },
4176 int main(int argc, char *argv[])
4180 bacpy(&interface, BDADDR_ANY);
4182 while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
4185 if (!strncmp(optarg, "hci", 3))
4186 hci_devba(atoi(optarg + 3), &interface);
4188 str2ba(optarg, &interface);
4209 for (i = 0; command[i].cmd; i++)
4210 if (strncmp(command[i].cmd, argv[0], 4) == 0)
4211 return command[i].func(argc, argv);