1 /*
2 *
3 * BlueZ - Bluetooth protocol stack for Linux
4 *
5 * Copyright (C) 2001-2002 Nokia Corporation
6 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
7 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
8 * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
9 * Copyright (C) 2002-2003 Jean Tourrilhes <jt@hpl.hp.com>
10 *
11 *
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.
16 *
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.
21 *
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
25 *
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #include <stdio.h>
33 #include <errno.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <getopt.h>
38 #include <sys/socket.h>
39
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>
45
46 #include <netinet/in.h>
47
48 #include "sdp-xml.h"
49
50 #ifndef APPLE_AGENT_SVCLASS_ID
51 #define APPLE_AGENT_SVCLASS_ID 0x2112
52 #endif
53
54 #define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, 0)) != -1)
55
56 /*
57 * Convert a string to a BDADDR, with a few "enhancements" - Jean II
58 */
estr2ba(char * str,bdaddr_t * ba)59 static int estr2ba(char *str, bdaddr_t *ba)
60 {
61 /* Only trap "local", "any" is already dealt with */
62 if(!strcmp(str, "local")) {
63 bacpy(ba, BDADDR_LOCAL);
64 return 0;
65 }
66 return str2ba(str, ba);
67 }
68
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 */
73
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 */
80 };
81
82 typedef int (*handler_t)(bdaddr_t *bdaddr, struct search_context *arg);
83
84 static char UUID_str[MAX_LEN_UUID_STR];
85 static bdaddr_t interface;
86
87 /* Definition of attribute members */
88 struct member_def {
89 char *name;
90 };
91
92 /* Definition of an attribute */
93 struct attrib_def {
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 */
98 };
99
100 /* Definition of a service or protocol */
101 struct uuid_def {
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 */
106 };
107
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 */
113 };
114
115 /* Context information about the whole service */
116 struct service_context {
117 struct uuid_def *service; /* Service UUID, if known */
118 };
119
120 /* Allow us to do nice formatting of the lists */
121 static char *indent_spaces = " ";
122
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
127
128 /* Definition of the optional arguments in protocol list */
129 static struct member_def protocol_members[] = {
130 { "Protocol" },
131 { "Channel/Port" },
132 { "Version" },
133 };
134
135 /* Definition of the optional arguments in profile list */
136 static struct member_def profile_members[] = {
137 { "Profile" },
138 { "Version" },
139 };
140
141 /* Definition of the optional arguments in Language list */
142 static struct member_def language_members[] = {
143 { "Code ISO639" },
144 { "Encoding" },
145 { "Base Offset" },
146 };
147
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) */
168 };
169
170 const int attrib_max = sizeof(attrib_names)/sizeof(struct attrib_def);
171
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 },
176 };
177
178 /* Name of the various SPD attributes. See BT assigned numbers */
179 static struct attrib_def browse_attrib_names[] = {
180 { 0x200, "GroupID", NULL, 0 },
181 };
182
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 },
191 };
192
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 },
210 };
211
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 },
221 };
222
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 },
227 };
228
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 },
254 /* -- Services -- */
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 },
267 { 0x1108, "Headset",
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 },
313 /* ... */
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 },
321 /* ... */
322 { 0x1303, "VideoSource", NULL, 0 },
323 { 0x1304, "VideoSink", NULL, 0 },
324 { 0x1305, "VideoDistribution", NULL, 0 },
325 { 0x1400, "HDP", NULL, 0 },
326 { 0x1401, "HDPSource", NULL, 0 },
327 { 0x1402, "HDPSink", NULL, 0 },
328 { 0x2112, "AppleAgent", NULL, 0 },
329 };
330
331 static const int uuid16_max = sizeof(uuid16_names)/sizeof(struct uuid_def);
332
333 static void sdp_data_printf(sdp_data_t *, struct attrib_context *, int);
334
335 /*
336 * Parse a UUID.
337 * The BT assigned numbers only list UUID16, so I'm not sure the
338 * other types will ever get used...
339 */
sdp_uuid_printf(uuid_t * uuid,struct attrib_context * context,int indent)340 static void sdp_uuid_printf(uuid_t *uuid, struct attrib_context *context, int indent)
341 {
342 if (uuid) {
343 if (uuid->type == SDP_UUID16) {
344 uint16_t uuidNum = uuid->value.uuid16;
345 struct uuid_def *uuidDef = NULL;
346 int i;
347
348 for (i = 0; i < uuid16_max; i++)
349 if (uuid16_names[i].num == uuidNum) {
350 uuidDef = &uuid16_names[i];
351 break;
352 }
353
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;
358 }
359
360 if (uuidDef)
361 printf("%.*sUUID16 : 0x%.4x - %s\n",
362 indent, indent_spaces, uuidNum, uuidDef->name);
363 else
364 printf("%.*sUUID16 : 0x%.4x\n",
365 indent, indent_spaces, uuidNum);
366 } else if (uuid->type == SDP_UUID32) {
367 struct uuid_def *uuidDef = NULL;
368 int i;
369
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];
375 break;
376 }
377 }
378
379 if (uuidDef)
380 printf("%.*sUUID32 : 0x%.8x - %s\n",
381 indent, indent_spaces, uuid->value.uuid32, uuidDef->name);
382 else
383 printf("%.*sUUID32 : 0x%.8x\n",
384 indent, indent_spaces, uuid->value.uuid32);
385 } else if (uuid->type == SDP_UUID128) {
386 unsigned int data0;
387 unsigned short data1;
388 unsigned short data2;
389 unsigned short data3;
390 unsigned int data4;
391 unsigned short data5;
392
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);
399
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));
404 } else
405 printf("%.*sEnum type of UUID not set\n",
406 indent, indent_spaces);
407 } else
408 printf("%.*sNull passed to print UUID\n",
409 indent, indent_spaces);
410 }
411
412 /*
413 * Parse a sequence of data elements (i.e. a list)
414 */
printf_dataseq(sdp_data_t * pData,struct attrib_context * context,int indent)415 static void printf_dataseq(sdp_data_t * pData, struct attrib_context *context, int indent)
416 {
417 sdp_data_t *sdpdata = NULL;
418
419 sdpdata = pData;
420 if (sdpdata) {
421 context->member_index = 0;
422 do {
423 sdp_data_printf(sdpdata, context, indent + 2);
424 sdpdata = sdpdata->next;
425 context->member_index++;
426 } while (sdpdata);
427 } else {
428 printf("%.*sBroken dataseq link\n", indent, indent_spaces);
429 }
430 }
431
432 /*
433 * Parse a single data element (either in the attribute or in a data
434 * sequence).
435 */
sdp_data_printf(sdp_data_t * sdpdata,struct attrib_context * context,int indent)436 static void sdp_data_printf(sdp_data_t *sdpdata, struct attrib_context *context, int indent)
437 {
438 char *member_name = NULL;
439
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;
444 }
445
446 switch (sdpdata->dtd) {
447 case SDP_DATA_NIL:
448 printf("%.*sNil\n", indent, indent_spaces);
449 break;
450 case SDP_BOOL:
451 case SDP_UINT8:
452 case SDP_UINT16:
453 case SDP_UINT32:
454 case SDP_UINT64:
455 case SDP_UINT128:
456 case SDP_INT8:
457 case SDP_INT16:
458 case SDP_INT32:
459 case SDP_INT64:
460 case SDP_INT128:
461 if (member_name) {
462 printf("%.*s%s (Integer) : 0x%x\n",
463 indent, indent_spaces, member_name, sdpdata->val.uint32);
464 } else {
465 printf("%.*sInteger : 0x%x\n", indent, indent_spaces,
466 sdpdata->val.uint32);
467 }
468 break;
469
470 case SDP_UUID16:
471 case SDP_UUID32:
472 case SDP_UUID128:
473 //printf("%.*sUUID\n", indent, indent_spaces);
474 sdp_uuid_printf(&sdpdata->val.uuid, context, indent);
475 break;
476
477 case SDP_TEXT_STR8:
478 case SDP_TEXT_STR16:
479 case SDP_TEXT_STR32:
480 if (sdpdata->unitSize > (int) strlen(sdpdata->val.str)) {
481 int i;
482 printf("%.*sData :", indent, indent_spaces);
483 for (i = 0; i < sdpdata->unitSize; i++)
484 printf(" %02x", (unsigned char) sdpdata->val.str[i]);
485 printf("\n");
486 } else
487 printf("%.*sText : \"%s\"\n", indent, indent_spaces, sdpdata->val.str);
488 break;
489 case SDP_URL_STR8:
490 case SDP_URL_STR16:
491 case SDP_URL_STR32:
492 printf("%.*sURL : %s\n", indent, indent_spaces, sdpdata->val.str);
493 break;
494
495 case SDP_SEQ8:
496 case SDP_SEQ16:
497 case SDP_SEQ32:
498 printf("%.*sData Sequence\n", indent, indent_spaces);
499 printf_dataseq(sdpdata->val.dataseq, context, indent);
500 break;
501
502 case SDP_ALT8:
503 case SDP_ALT16:
504 case SDP_ALT32:
505 printf("%.*sData Sequence Alternates\n", indent, indent_spaces);
506 printf_dataseq(sdpdata->val.dataseq, context, indent);
507 break;
508 }
509 }
510
511 /*
512 * Parse a single attribute.
513 */
print_tree_attr_func(void * value,void * userData)514 static void print_tree_attr_func(void *value, void *userData)
515 {
516 sdp_data_t *sdpdata = value;
517 uint16_t attrId;
518 struct service_context *service = (struct service_context *) userData;
519 struct attrib_context context;
520 struct attrib_def *attrDef = NULL;
521 int i;
522
523 if (!sdpdata)
524 return;
525
526 attrId = sdpdata->attrId;
527 /* Search amongst the generic attributes */
528 for (i = 0; i < attrib_max; i++)
529 if (attrib_names[i].num == attrId) {
530 attrDef = &attrib_names[i];
531 break;
532 }
533 /* Search amongst the specific attributes of this service */
534 if ((attrDef == NULL) && (service->service != NULL) &&
535 (service->service->attribs != NULL)) {
536 struct attrib_def *svc_attribs = service->service->attribs;
537 int svc_attrib_max = service->service->attrib_max;
538 for (i = 0; i < svc_attrib_max; i++)
539 if (svc_attribs[i].num == attrId) {
540 attrDef = &svc_attribs[i];
541 break;
542 }
543 }
544
545 if (attrDef)
546 printf("Attribute Identifier : 0x%x - %s\n", attrId, attrDef->name);
547 else
548 printf("Attribute Identifier : 0x%x\n", attrId);
549 /* Build context */
550 context.service = service->service;
551 context.attrib = attrDef;
552 context.member_index = 0;
553 /* Parse attribute members */
554 sdp_data_printf(sdpdata, &context, 2);
555 /* Update service */
556 service->service = context.service;
557 }
558
559 /*
560 * Main entry point of this library. Parse a SDP record.
561 * We assume the record has already been read, parsed and cached
562 * locally. Jean II
563 */
print_tree_attr(sdp_record_t * rec)564 static void print_tree_attr(sdp_record_t *rec)
565 {
566 if (rec && rec->attrlist) {
567 struct service_context service = { NULL };
568 sdp_list_foreach(rec->attrlist, print_tree_attr_func, &service);
569 }
570 }
571
print_raw_data(sdp_data_t * data,int indent)572 static void print_raw_data(sdp_data_t *data, int indent)
573 {
574 struct uuid_def *def;
575 int i, hex;
576
577 if (!data)
578 return;
579
580 for (i = 0; i < indent; i++)
581 printf("\t");
582
583 switch (data->dtd) {
584 case SDP_DATA_NIL:
585 printf("NIL\n");
586 break;
587 case SDP_BOOL:
588 printf("Bool %s\n", data->val.uint8 ? "True" : "False");
589 break;
590 case SDP_UINT8:
591 printf("UINT8 0x%02x\n", data->val.uint8);
592 break;
593 case SDP_UINT16:
594 printf("UINT16 0x%04x\n", data->val.uint16);
595 break;
596 case SDP_UINT32:
597 printf("UINT32 0x%08x\n", data->val.uint32);
598 break;
599 case SDP_UINT64:
600 printf("UINT64 0x%016jx\n", data->val.uint64);
601 break;
602 case SDP_UINT128:
603 printf("UINT128 ...\n");
604 break;
605 case SDP_INT8:
606 printf("INT8 %d\n", data->val.int8);
607 break;
608 case SDP_INT16:
609 printf("INT16 %d\n", data->val.int16);
610 break;
611 case SDP_INT32:
612 printf("INT32 %d\n", data->val.int32);
613 break;
614 case SDP_INT64:
615 printf("INT64 %jd\n", data->val.int64);
616 break;
617 case SDP_INT128:
618 printf("INT128 ...\n");
619 break;
620 case SDP_UUID16:
621 case SDP_UUID32:
622 case SDP_UUID128:
623 switch (data->val.uuid.type) {
624 case SDP_UUID16:
625 def = NULL;
626 for (i = 0; i < uuid16_max; i++)
627 if (uuid16_names[i].num == data->val.uuid.value.uuid16) {
628 def = &uuid16_names[i];
629 break;
630 }
631 if (def)
632 printf("UUID16 0x%04x - %s\n", data->val.uuid.value.uuid16, def->name);
633 else
634 printf("UUID16 0x%04x\n", data->val.uuid.value.uuid16);
635 break;
636 case SDP_UUID32:
637 def = NULL;
638 if (!(data->val.uuid.value.uuid32 & 0xffff0000)) {
639 uint16_t value = data->val.uuid.value.uuid32;
640 for (i = 0; i < uuid16_max; i++)
641 if (uuid16_names[i].num == value) {
642 def = &uuid16_names[i];
643 break;
644 }
645 }
646 if (def)
647 printf("UUID32 0x%08x - %s\n", data->val.uuid.value.uuid32, def->name);
648 else
649 printf("UUID32 0x%08x\n", data->val.uuid.value.uuid32);
650 break;
651 case SDP_UUID128:
652 printf("UUID128 ");
653 for (i = 0; i < 16; i++) {
654 switch (i) {
655 case 4:
656 case 6:
657 case 8:
658 case 10:
659 printf("-");
660 break;
661 }
662 printf("%02x", (unsigned char ) data->val.uuid.value.uuid128.data[i]);
663 }
664 printf("\n");
665 break;
666 default:
667 printf("UUID type 0x%02x\n", data->val.uuid.type);
668 break;
669 }
670 break;
671 case SDP_TEXT_STR8:
672 case SDP_TEXT_STR16:
673 case SDP_TEXT_STR32:
674 hex = 0;
675 for (i = 0; i < data->unitSize; i++) {
676 if (i == (data->unitSize - 1) && data->val.str[i] == '\0')
677 break;
678 if (!isprint(data->val.str[i])) {
679 hex = 1;
680 break;
681 }
682 }
683 if (hex) {
684 printf("Data");
685 for (i = 0; i < data->unitSize; i++)
686 printf(" %02x", (unsigned char) data->val.str[i]);
687 } else {
688 printf("String ");
689 for (i = 0; i < data->unitSize; i++)
690 printf("%c", data->val.str[i]);
691 }
692 printf("\n");
693 break;
694 case SDP_URL_STR8:
695 case SDP_URL_STR16:
696 case SDP_URL_STR32:
697 printf("URL %s\n", data->val.str);
698 break;
699 case SDP_SEQ8:
700 case SDP_SEQ16:
701 case SDP_SEQ32:
702 printf("Sequence\n");
703 print_raw_data(data->val.dataseq, indent + 1);
704 break;
705 case SDP_ALT8:
706 case SDP_ALT16:
707 case SDP_ALT32:
708 printf("Alternate\n");
709 print_raw_data(data->val.dataseq, indent + 1);
710 break;
711 default:
712 printf("Unknown type 0x%02x\n", data->dtd);
713 break;
714 }
715
716 print_raw_data(data->next, indent);
717 }
718
print_raw_attr_func(void * value,void * userData)719 static void print_raw_attr_func(void *value, void *userData)
720 {
721 sdp_data_t *data = (sdp_data_t *) value;
722 struct attrib_def *def = NULL;
723 int i;
724
725 if (!data)
726 return;
727
728 /* Search amongst the generic attributes */
729 for (i = 0; i < attrib_max; i++)
730 if (attrib_names[i].num == data->attrId) {
731 def = &attrib_names[i];
732 break;
733 }
734
735 if (def)
736 printf("\tAttribute 0x%04x - %s\n", data->attrId, def->name);
737 else
738 printf("\tAttribute 0x%04x\n", data->attrId);
739
740 print_raw_data(data, 2);
741 }
742
print_raw_attr(sdp_record_t * rec)743 static void print_raw_attr(sdp_record_t *rec)
744 {
745 if (rec && rec->attrlist) {
746 printf("Sequence\n");
747 sdp_list_foreach(rec->attrlist, print_raw_attr_func, 0);
748 }
749 }
750
751 /*
752 * Set attributes with single values in SDP record
753 * Jean II
754 */
set_attrib(sdp_session_t * sess,uint32_t handle,uint16_t attrib,char * value)755 static int set_attrib(sdp_session_t *sess, uint32_t handle, uint16_t attrib, char *value)
756 {
757 sdp_list_t *attrid_list;
758 uint32_t range = 0x0000ffff;
759 sdp_record_t *rec;
760 int ret;
761
762 /* Get the old SDP record */
763 attrid_list = sdp_list_append(NULL, &range);
764 rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attrid_list);
765 sdp_list_free(attrid_list, NULL);
766
767 if (!rec) {
768 printf("Service get request failed.\n");
769 return -1;
770 }
771
772 /* Check the type of attribute */
773 if (!strncasecmp(value, "u0x", 3)) {
774 /* UUID16 */
775 uint16_t value_int = 0;
776 uuid_t value_uuid;
777 value_int = strtoul(value + 3, NULL, 16);
778 sdp_uuid16_create(&value_uuid, value_int);
779 printf("Adding attrib 0x%X uuid16 0x%X to record 0x%X\n",
780 attrib, value_int, handle);
781
782 sdp_attr_add_new(rec, attrib, SDP_UUID16, &value_uuid.value.uuid16);
783 } else if (!strncasecmp(value, "0x", 2)) {
784 /* Int */
785 uint32_t value_int;
786 value_int = strtoul(value + 2, NULL, 16);
787 printf("Adding attrib 0x%X int 0x%X to record 0x%X\n",
788 attrib, value_int, handle);
789
790 sdp_attr_add_new(rec, attrib, SDP_UINT32, &value_int);
791 } else {
792 /* String */
793 printf("Adding attrib 0x%X string \"%s\" to record 0x%X\n",
794 attrib, value, handle);
795
796 /* Add/Update our attribute to the record */
797 sdp_attr_add_new(rec, attrib, SDP_TEXT_STR8, value);
798 }
799
800 /* Update on the server */
801 ret = sdp_device_record_update(sess, &interface, rec);
802 if (ret < 0)
803 printf("Service Record update failed (%d).\n", errno);
804 sdp_record_free(rec);
805 return ret;
806 }
807
808 static struct option set_options[] = {
809 { "help", 0, 0, 'h' },
810 { 0, 0, 0, 0 }
811 };
812
813 static const char *set_help =
814 "Usage:\n"
815 "\tget record_handle attrib_id attrib_value\n";
816
817 /*
818 * Add an attribute to an existing SDP record on the local SDP server
819 */
cmd_setattr(int argc,char ** argv)820 static int cmd_setattr(int argc, char **argv)
821 {
822 int opt, status;
823 uint32_t handle;
824 uint16_t attrib;
825 sdp_session_t *sess;
826
827 for_each_opt(opt, set_options, NULL) {
828 switch(opt) {
829 default:
830 printf("%s", set_help);
831 return -1;
832 }
833 }
834
835 argc -= optind;
836 argv += optind;
837
838 if (argc < 3) {
839 printf("%s", set_help);
840 return -1;
841 }
842
843 /* Convert command line args */
844 handle = strtoul(argv[0], NULL, 16);
845 attrib = strtoul(argv[1], NULL, 16);
846
847 /* Do it */
848 sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
849 if (!sess)
850 return -1;
851
852 status = set_attrib(sess, handle, attrib, argv[2]);
853 sdp_close(sess);
854
855 return status;
856 }
857
858 /*
859 * We do only simple data sequences. Sequence of sequences is a pain ;-)
860 * Jean II
861 */
set_attribseq(sdp_session_t * session,uint32_t handle,uint16_t attrib,int argc,char ** argv)862 static int set_attribseq(sdp_session_t *session, uint32_t handle, uint16_t attrib, int argc, char **argv)
863 {
864 sdp_list_t *attrid_list;
865 uint32_t range = 0x0000ffff;
866 sdp_record_t *rec;
867 sdp_data_t *pSequenceHolder = NULL;
868 void **dtdArray;
869 void **valueArray;
870 void **allocArray;
871 uint8_t uuid16 = SDP_UUID16;
872 uint8_t uint32 = SDP_UINT32;
873 uint8_t str8 = SDP_TEXT_STR8;
874 int i, ret = 0;
875
876 /* Get the old SDP record */
877 attrid_list = sdp_list_append(NULL, &range);
878 rec = sdp_service_attr_req(session, handle, SDP_ATTR_REQ_RANGE, attrid_list);
879 sdp_list_free(attrid_list, NULL);
880
881 if (!rec) {
882 printf("Service get request failed.\n");
883 return -1;
884 }
885
886 /* Create arrays */
887 dtdArray = (void **)malloc(argc * sizeof(void *));
888 valueArray = (void **)malloc(argc * sizeof(void *));
889 allocArray = (void **)malloc(argc * sizeof(void *));
890
891 /* Loop on all args, add them in arrays */
892 for (i = 0; i < argc; i++) {
893 /* Check the type of attribute */
894 if (!strncasecmp(argv[i], "u0x", 3)) {
895 /* UUID16 */
896 uint16_t value_int = strtoul((argv[i]) + 3, NULL, 16);
897 uuid_t *value_uuid = (uuid_t *) malloc(sizeof(uuid_t));
898 allocArray[i] = value_uuid;
899 sdp_uuid16_create(value_uuid, value_int);
900
901 printf("Adding uuid16 0x%X to record 0x%X\n", value_int, handle);
902 dtdArray[i] = &uuid16;
903 valueArray[i] = &value_uuid->value.uuid16;
904 } else if (!strncasecmp(argv[i], "0x", 2)) {
905 /* Int */
906 uint32_t *value_int = (uint32_t *) malloc(sizeof(int));
907 allocArray[i] = value_int;
908 *value_int = strtoul((argv[i]) + 2, NULL, 16);
909
910 printf("Adding int 0x%X to record 0x%X\n", *value_int, handle);
911 dtdArray[i] = &uint32;
912 valueArray[i] = value_int;
913 } else {
914 /* String */
915 printf("Adding string \"%s\" to record 0x%X\n", argv[i], handle);
916 dtdArray[i] = &str8;
917 valueArray[i] = argv[i];
918 }
919 }
920
921 /* Add this sequence to the attrib list */
922 pSequenceHolder = sdp_seq_alloc(dtdArray, valueArray, argc);
923 if (pSequenceHolder) {
924 sdp_attr_replace(rec, attrib, pSequenceHolder);
925
926 /* Update on the server */
927 ret = sdp_device_record_update(session, &interface, rec);
928 if (ret < 0)
929 printf("Service Record update failed (%d).\n", errno);
930 } else
931 printf("Failed to create pSequenceHolder\n");
932
933 /* Cleanup */
934 for (i = 0; i < argc; i++)
935 free(allocArray[i]);
936
937 free(dtdArray);
938 free(valueArray);
939 free(allocArray);
940
941 sdp_record_free(rec);
942
943 return ret;
944 }
945
946 static struct option seq_options[] = {
947 { "help", 0, 0, 'h' },
948 { 0, 0, 0, 0 }
949 };
950
951 static const char *seq_help =
952 "Usage:\n"
953 "\tget record_handle attrib_id attrib_values\n";
954
955 /*
956 * Add an attribute sequence to an existing SDP record
957 * on the local SDP server
958 */
cmd_setseq(int argc,char ** argv)959 static int cmd_setseq(int argc, char **argv)
960 {
961 int opt, status;
962 uint32_t handle;
963 uint16_t attrib;
964 sdp_session_t *sess;
965
966 for_each_opt(opt, seq_options, NULL) {
967 switch(opt) {
968 default:
969 printf("%s", seq_help);
970 return -1;
971 }
972 }
973
974 argc -= optind;
975 argv += optind;
976
977 if (argc < 3) {
978 printf("%s", seq_help);
979 return -1;
980 }
981
982 /* Convert command line args */
983 handle = strtoul(argv[0], NULL, 16);
984 attrib = strtoul(argv[1], NULL, 16);
985
986 argc -= 2;
987 argv += 2;
988
989 /* Do it */
990 sess = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
991 if (!sess)
992 return -1;
993
994 status = set_attribseq(sess, handle, attrib, argc, argv);
995 sdp_close(sess);
996
997 return status;
998 }
999
print_service_class(void * value,void * userData)1000 static void print_service_class(void *value, void *userData)
1001 {
1002 char ServiceClassUUID_str[MAX_LEN_SERVICECLASS_UUID_STR];
1003 uuid_t *uuid = (uuid_t *)value;
1004
1005 sdp_uuid2strn(uuid, UUID_str, MAX_LEN_UUID_STR);
1006 sdp_svclass_uuid2strn(uuid, ServiceClassUUID_str, MAX_LEN_SERVICECLASS_UUID_STR);
1007 if (uuid->type != SDP_UUID128)
1008 printf(" \"%s\" (0x%s)\n", ServiceClassUUID_str, UUID_str);
1009 else
1010 printf(" UUID 128: %s\n", UUID_str);
1011 }
1012
print_service_desc(void * value,void * user)1013 static void print_service_desc(void *value, void *user)
1014 {
1015 char str[MAX_LEN_PROTOCOL_UUID_STR];
1016 sdp_data_t *p = (sdp_data_t *)value, *s;
1017 int i = 0, proto = 0;
1018
1019 for (; p; p = p->next, i++) {
1020 switch (p->dtd) {
1021 case SDP_UUID16:
1022 case SDP_UUID32:
1023 case SDP_UUID128:
1024 sdp_uuid2strn(&p->val.uuid, UUID_str, MAX_LEN_UUID_STR);
1025 sdp_proto_uuid2strn(&p->val.uuid, str, sizeof(str));
1026 proto = sdp_uuid_to_proto(&p->val.uuid);
1027 printf(" \"%s\" (0x%s)\n", str, UUID_str);
1028 break;
1029 case SDP_UINT8:
1030 if (proto == RFCOMM_UUID)
1031 printf(" Channel: %d\n", p->val.uint8);
1032 else
1033 printf(" uint8: 0x%x\n", p->val.uint8);
1034 break;
1035 case SDP_UINT16:
1036 if (proto == L2CAP_UUID) {
1037 if (i == 1)
1038 printf(" PSM: %d\n", p->val.uint16);
1039 else
1040 printf(" Version: 0x%04x\n", p->val.uint16);
1041 } else if (proto == BNEP_UUID)
1042 if (i == 1)
1043 printf(" Version: 0x%04x\n", p->val.uint16);
1044 else
1045 printf(" uint16: 0x%x\n", p->val.uint16);
1046 else
1047 printf(" uint16: 0x%x\n", p->val.uint16);
1048 break;
1049 case SDP_SEQ16:
1050 printf(" SEQ16:");
1051 for (s = p->val.dataseq; s; s = s->next)
1052 printf(" %x", s->val.uint16);
1053 printf("\n");
1054 break;
1055 case SDP_SEQ8:
1056 printf(" SEQ8:");
1057 for (s = p->val.dataseq; s; s = s->next)
1058 printf(" %x", s->val.uint8);
1059 printf("\n");
1060 break;
1061 default:
1062 printf(" FIXME: dtd=0%x\n", p->dtd);
1063 break;
1064 }
1065 }
1066 }
1067
print_lang_attr(void * value,void * user)1068 static void print_lang_attr(void *value, void *user)
1069 {
1070 sdp_lang_attr_t *lang = (sdp_lang_attr_t *)value;
1071 printf(" code_ISO639: 0x%02x\n", lang->code_ISO639);
1072 printf(" encoding: 0x%02x\n", lang->encoding);
1073 printf(" base_offset: 0x%02x\n", lang->base_offset);
1074 }
1075
print_access_protos(void * value,void * userData)1076 static void print_access_protos(void *value, void *userData)
1077 {
1078 sdp_list_t *protDescSeq = (sdp_list_t *)value;
1079 sdp_list_foreach(protDescSeq, print_service_desc, 0);
1080 }
1081
print_profile_desc(void * value,void * userData)1082 static void print_profile_desc(void *value, void *userData)
1083 {
1084 sdp_profile_desc_t *desc = (sdp_profile_desc_t *)value;
1085 char str[MAX_LEN_PROFILEDESCRIPTOR_UUID_STR];
1086
1087 sdp_uuid2strn(&desc->uuid, UUID_str, MAX_LEN_UUID_STR);
1088 sdp_profile_uuid2strn(&desc->uuid, str, MAX_LEN_PROFILEDESCRIPTOR_UUID_STR);
1089
1090 printf(" \"%s\" (0x%s)\n", str, UUID_str);
1091 if (desc->version)
1092 printf(" Version: 0x%04x\n", desc->version);
1093 }
1094
1095 /*
1096 * Parse a SDP record in user friendly form.
1097 */
print_service_attr(sdp_record_t * rec)1098 static void print_service_attr(sdp_record_t *rec)
1099 {
1100 sdp_list_t *list = 0, *proto = 0;
1101
1102 sdp_record_print(rec);
1103
1104 printf("Service RecHandle: 0x%x\n", rec->handle);
1105
1106 if (sdp_get_service_classes(rec, &list) == 0) {
1107 printf("Service Class ID List:\n");
1108 sdp_list_foreach(list, print_service_class, 0);
1109 sdp_list_free(list, free);
1110 }
1111 if (sdp_get_access_protos(rec, &proto) == 0) {
1112 printf("Protocol Descriptor List:\n");
1113 sdp_list_foreach(proto, print_access_protos, 0);
1114 sdp_list_foreach(proto, (sdp_list_func_t)sdp_list_free, 0);
1115 sdp_list_free(proto, 0);
1116 }
1117 if (sdp_get_lang_attr(rec, &list) == 0) {
1118 printf("Language Base Attr List:\n");
1119 sdp_list_foreach(list, print_lang_attr, 0);
1120 sdp_list_free(list, free);
1121 }
1122 if (sdp_get_profile_descs(rec, &list) == 0) {
1123 printf("Profile Descriptor List:\n");
1124 sdp_list_foreach(list, print_profile_desc, 0);
1125 sdp_list_free(list, free);
1126 }
1127 }
1128
1129 /*
1130 * Support for Service (de)registration
1131 */
1132 typedef struct {
1133 uint32_t handle;
1134 char *name;
1135 char *provider;
1136 char *desc;
1137 unsigned int class;
1138 unsigned int profile;
1139 uint16_t psm;
1140 uint8_t channel;
1141 uint8_t network;
1142 } svc_info_t;
1143
add_lang_attr(sdp_record_t * r)1144 static void add_lang_attr(sdp_record_t *r)
1145 {
1146 sdp_lang_attr_t base_lang;
1147 sdp_list_t *langs = 0;
1148
1149 /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
1150 base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
1151 base_lang.encoding = 106;
1152 base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
1153 langs = sdp_list_append(0, &base_lang);
1154 sdp_set_lang_attr(r, langs);
1155 sdp_list_free(langs, 0);
1156 }
1157
add_sp(sdp_session_t * session,svc_info_t * si)1158 static int add_sp(sdp_session_t *session, svc_info_t *si)
1159 {
1160 sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
1161 uuid_t root_uuid, sp_uuid, l2cap, rfcomm;
1162 sdp_profile_desc_t profile;
1163 sdp_record_t record;
1164 uint8_t u8 = si->channel ? si->channel : 1;
1165 sdp_data_t *channel;
1166 int ret = 0;
1167
1168 memset(&record, 0, sizeof(sdp_record_t));
1169 record.handle = si->handle;
1170 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1171 root = sdp_list_append(0, &root_uuid);
1172 sdp_set_browse_groups(&record, root);
1173 sdp_list_free(root, 0);
1174
1175 sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
1176 svclass_id = sdp_list_append(0, &sp_uuid);
1177 sdp_set_service_classes(&record, svclass_id);
1178 sdp_list_free(svclass_id, 0);
1179
1180 sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
1181 profile.version = 0x0100;
1182 profiles = sdp_list_append(0, &profile);
1183 sdp_set_profile_descs(&record, profiles);
1184 sdp_list_free(profiles, 0);
1185
1186 sdp_uuid16_create(&l2cap, L2CAP_UUID);
1187 proto[0] = sdp_list_append(0, &l2cap);
1188 apseq = sdp_list_append(0, proto[0]);
1189
1190 sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
1191 proto[1] = sdp_list_append(0, &rfcomm);
1192 channel = sdp_data_alloc(SDP_UINT8, &u8);
1193 proto[1] = sdp_list_append(proto[1], channel);
1194 apseq = sdp_list_append(apseq, proto[1]);
1195
1196 aproto = sdp_list_append(0, apseq);
1197 sdp_set_access_protos(&record, aproto);
1198
1199 add_lang_attr(&record);
1200
1201 sdp_set_info_attr(&record, "Serial Port", "BlueZ", "COM Port");
1202
1203 sdp_set_url_attr(&record, "http://www.bluez.org/",
1204 "http://www.bluez.org/", "http://www.bluez.org/");
1205
1206 sdp_set_service_id(&record, sp_uuid);
1207 sdp_set_service_ttl(&record, 0xffff);
1208 sdp_set_service_avail(&record, 0xff);
1209 sdp_set_record_state(&record, 0x00001234);
1210
1211 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1212 printf("Service Record registration failed\n");
1213 ret = -1;
1214 goto end;
1215 }
1216
1217 printf("Serial Port service registered\n");
1218
1219 end:
1220 sdp_data_free(channel);
1221 sdp_list_free(proto[0], 0);
1222 sdp_list_free(proto[1], 0);
1223 sdp_list_free(apseq, 0);
1224 sdp_list_free(aproto, 0);
1225
1226 return ret;
1227 }
1228
add_dun(sdp_session_t * session,svc_info_t * si)1229 static int add_dun(sdp_session_t *session, svc_info_t *si)
1230 {
1231 sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto;
1232 uuid_t rootu, dun, gn, l2cap, rfcomm;
1233 sdp_profile_desc_t profile;
1234 sdp_list_t *proto[2];
1235 sdp_record_t record;
1236 uint8_t u8 = si->channel ? si->channel : 2;
1237 sdp_data_t *channel;
1238 int ret = 0;
1239
1240 memset(&record, 0, sizeof(sdp_record_t));
1241 record.handle = si->handle;
1242
1243 sdp_uuid16_create(&rootu, PUBLIC_BROWSE_GROUP);
1244 root = sdp_list_append(0, &rootu);
1245 sdp_set_browse_groups(&record, root);
1246
1247 sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
1248 svclass_id = sdp_list_append(0, &dun);
1249 sdp_uuid16_create(&gn, GENERIC_NETWORKING_SVCLASS_ID);
1250 svclass_id = sdp_list_append(svclass_id, &gn);
1251 sdp_set_service_classes(&record, svclass_id);
1252
1253 sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID);
1254 profile.version = 0x0100;
1255 pfseq = sdp_list_append(0, &profile);
1256 sdp_set_profile_descs(&record, pfseq);
1257
1258 sdp_uuid16_create(&l2cap, L2CAP_UUID);
1259 proto[0] = sdp_list_append(0, &l2cap);
1260 apseq = sdp_list_append(0, proto[0]);
1261
1262 sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
1263 proto[1] = sdp_list_append(0, &rfcomm);
1264 channel = sdp_data_alloc(SDP_UINT8, &u8);
1265 proto[1] = sdp_list_append(proto[1], channel);
1266 apseq = sdp_list_append(apseq, proto[1]);
1267
1268 aproto = sdp_list_append(0, apseq);
1269 sdp_set_access_protos(&record, aproto);
1270
1271 sdp_set_info_attr(&record, "Dial-Up Networking", 0, 0);
1272
1273 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1274 printf("Service Record registration failed\n");
1275 ret = -1;
1276 goto end;
1277 }
1278
1279 printf("Dial-Up Networking service registered\n");
1280
1281 end:
1282 sdp_data_free(channel);
1283 sdp_list_free(proto[0], 0);
1284 sdp_list_free(proto[1], 0);
1285 sdp_list_free(apseq, 0);
1286 sdp_list_free(aproto, 0);
1287
1288 return ret;
1289 }
1290
add_fax(sdp_session_t * session,svc_info_t * si)1291 static int add_fax(sdp_session_t *session, svc_info_t *si)
1292 {
1293 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1294 uuid_t root_uuid, fax_uuid, tel_uuid, l2cap_uuid, rfcomm_uuid;
1295 sdp_profile_desc_t profile;
1296 sdp_list_t *aproto, *proto[2];
1297 sdp_record_t record;
1298 uint8_t u8 = si->channel? si->channel : 3;
1299 sdp_data_t *channel;
1300 int ret = 0;
1301
1302 memset(&record, 0, sizeof(sdp_record_t));
1303 record.handle = si->handle;
1304
1305 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1306 root = sdp_list_append(0, &root_uuid);
1307 sdp_set_browse_groups(&record, root);
1308
1309 sdp_uuid16_create(&fax_uuid, FAX_SVCLASS_ID);
1310 svclass_id = sdp_list_append(0, &fax_uuid);
1311 sdp_uuid16_create(&tel_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
1312 svclass_id = sdp_list_append(svclass_id, &tel_uuid);
1313 sdp_set_service_classes(&record, svclass_id);
1314
1315 sdp_uuid16_create(&profile.uuid, FAX_PROFILE_ID);
1316 profile.version = 0x0100;
1317 pfseq = sdp_list_append(0, &profile);
1318 sdp_set_profile_descs(&record, pfseq);
1319
1320 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1321 proto[0] = sdp_list_append(0, &l2cap_uuid);
1322 apseq = sdp_list_append(0, proto[0]);
1323
1324 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1325 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1326 channel = sdp_data_alloc(SDP_UINT8, &u8);
1327 proto[1] = sdp_list_append(proto[1], channel);
1328 apseq = sdp_list_append(apseq, proto[1]);
1329
1330 aproto = sdp_list_append(0, apseq);
1331 sdp_set_access_protos(&record, aproto);
1332
1333 sdp_set_info_attr(&record, "Fax", 0, 0);
1334
1335 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1336 printf("Service Record registration failed\n");
1337 ret = -1;
1338 goto end;
1339 }
1340 printf("Fax service registered\n");
1341 end:
1342 sdp_data_free(channel);
1343 sdp_list_free(proto[0], 0);
1344 sdp_list_free(proto[1], 0);
1345 sdp_list_free(apseq, 0);
1346 sdp_list_free(aproto, 0);
1347 return ret;
1348 }
1349
add_lan(sdp_session_t * session,svc_info_t * si)1350 static int add_lan(sdp_session_t *session, svc_info_t *si)
1351 {
1352 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1353 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
1354 sdp_profile_desc_t profile;
1355 sdp_list_t *aproto, *proto[2];
1356 sdp_record_t record;
1357 uint8_t u8 = si->channel ? si->channel : 4;
1358 sdp_data_t *channel;
1359 int ret = 0;
1360
1361 memset(&record, 0, sizeof(sdp_record_t));
1362 record.handle = si->handle;
1363
1364 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1365 root = sdp_list_append(0, &root_uuid);
1366 sdp_set_browse_groups(&record, root);
1367
1368 sdp_uuid16_create(&svclass_uuid, LAN_ACCESS_SVCLASS_ID);
1369 svclass_id = sdp_list_append(0, &svclass_uuid);
1370 sdp_set_service_classes(&record, svclass_id);
1371
1372 sdp_uuid16_create(&profile.uuid, LAN_ACCESS_PROFILE_ID);
1373 profile.version = 0x0100;
1374 pfseq = sdp_list_append(0, &profile);
1375 sdp_set_profile_descs(&record, pfseq);
1376
1377 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1378 proto[0] = sdp_list_append(0, &l2cap_uuid);
1379 apseq = sdp_list_append(0, proto[0]);
1380
1381 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1382 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1383 channel = sdp_data_alloc(SDP_UINT8, &u8);
1384 proto[1] = sdp_list_append(proto[1], channel);
1385 apseq = sdp_list_append(apseq, proto[1]);
1386
1387 aproto = sdp_list_append(0, apseq);
1388 sdp_set_access_protos(&record, aproto);
1389
1390 sdp_set_info_attr(&record, "LAN Access over PPP", 0, 0);
1391
1392 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1393 printf("Service Record registration failed\n");
1394 ret = -1;
1395 goto end;
1396 }
1397
1398 printf("LAN Access service registered\n");
1399
1400 end:
1401 sdp_data_free(channel);
1402 sdp_list_free(proto[0], 0);
1403 sdp_list_free(proto[1], 0);
1404 sdp_list_free(apseq, 0);
1405 sdp_list_free(aproto, 0);
1406
1407 return ret;
1408 }
1409
add_headset(sdp_session_t * session,svc_info_t * si)1410 static int add_headset(sdp_session_t *session, svc_info_t *si)
1411 {
1412 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1413 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1414 sdp_profile_desc_t profile;
1415 sdp_list_t *aproto, *proto[2];
1416 sdp_record_t record;
1417 uint8_t u8 = si->channel ? si->channel : 5;
1418 sdp_data_t *channel;
1419 int ret = 0;
1420
1421 memset(&record, 0, sizeof(sdp_record_t));
1422 record.handle = si->handle;
1423
1424 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1425 root = sdp_list_append(0, &root_uuid);
1426 sdp_set_browse_groups(&record, root);
1427
1428 sdp_uuid16_create(&svclass_uuid, HEADSET_SVCLASS_ID);
1429 svclass_id = sdp_list_append(0, &svclass_uuid);
1430 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1431 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1432 sdp_set_service_classes(&record, svclass_id);
1433
1434 sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
1435 profile.version = 0x0100;
1436 pfseq = sdp_list_append(0, &profile);
1437 sdp_set_profile_descs(&record, pfseq);
1438
1439 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1440 proto[0] = sdp_list_append(0, &l2cap_uuid);
1441 apseq = sdp_list_append(0, proto[0]);
1442
1443 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1444 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1445 channel = sdp_data_alloc(SDP_UINT8, &u8);
1446 proto[1] = sdp_list_append(proto[1], channel);
1447 apseq = sdp_list_append(apseq, proto[1]);
1448
1449 aproto = sdp_list_append(0, apseq);
1450 sdp_set_access_protos(&record, aproto);
1451
1452 sdp_set_info_attr(&record, "Headset", 0, 0);
1453
1454 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1455 printf("Service Record registration failed\n");
1456 ret = -1;
1457 goto end;
1458 }
1459
1460 printf("Headset service registered\n");
1461
1462 end:
1463 sdp_data_free(channel);
1464 sdp_list_free(proto[0], 0);
1465 sdp_list_free(proto[1], 0);
1466 sdp_list_free(apseq, 0);
1467 sdp_list_free(aproto, 0);
1468
1469 return ret;
1470 }
1471
add_headset_ag(sdp_session_t * session,svc_info_t * si)1472 static int add_headset_ag(sdp_session_t *session, svc_info_t *si)
1473 {
1474 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1475 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1476 sdp_profile_desc_t profile;
1477 sdp_list_t *aproto, *proto[2];
1478 sdp_record_t record;
1479 uint8_t u8 = si->channel ? si->channel : 7;
1480 sdp_data_t *channel;
1481 uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
1482 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
1483 int ret = 0;
1484
1485 memset(&record, 0, sizeof(sdp_record_t));
1486 record.handle = si->handle;
1487
1488 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1489 root = sdp_list_append(0, &root_uuid);
1490 sdp_set_browse_groups(&record, root);
1491
1492 sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
1493 svclass_id = sdp_list_append(0, &svclass_uuid);
1494 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1495 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1496 sdp_set_service_classes(&record, svclass_id);
1497
1498 sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
1499 profile.version = 0x0100;
1500 pfseq = sdp_list_append(0, &profile);
1501 sdp_set_profile_descs(&record, pfseq);
1502
1503 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1504 proto[0] = sdp_list_append(0, &l2cap_uuid);
1505 apseq = sdp_list_append(0, proto[0]);
1506
1507 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1508 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1509 channel = sdp_data_alloc(SDP_UINT8, &u8);
1510 proto[1] = sdp_list_append(proto[1], channel);
1511 apseq = sdp_list_append(apseq, proto[1]);
1512
1513 aproto = sdp_list_append(0, apseq);
1514 sdp_set_access_protos(&record, aproto);
1515
1516 sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
1517
1518 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
1519
1520 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
1521 printf("Service Record registration failed\n");
1522 ret = -1;
1523 goto end;
1524 }
1525
1526 printf("Headset AG service registered\n");
1527
1528 end:
1529 sdp_data_free(channel);
1530 sdp_list_free(proto[0], 0);
1531 sdp_list_free(proto[1], 0);
1532 sdp_list_free(apseq, 0);
1533 sdp_list_free(aproto, 0);
1534
1535 return ret;
1536 }
1537
add_handsfree(sdp_session_t * session,svc_info_t * si)1538 static int add_handsfree(sdp_session_t *session, svc_info_t *si)
1539 {
1540 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1541 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1542 sdp_profile_desc_t profile;
1543 sdp_list_t *aproto, *proto[2];
1544 sdp_record_t record;
1545 uint8_t u8 = si->channel ? si->channel : 6;
1546 uint16_t u16 = 0x31;
1547 sdp_data_t *channel, *features;
1548 int ret = 0;
1549
1550 memset(&record, 0, sizeof(sdp_record_t));
1551 record.handle = si->handle;
1552
1553 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1554 root = sdp_list_append(0, &root_uuid);
1555 sdp_set_browse_groups(&record, root);
1556
1557 sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
1558 svclass_id = sdp_list_append(0, &svclass_uuid);
1559 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1560 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1561 sdp_set_service_classes(&record, svclass_id);
1562
1563 sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
1564 profile.version = 0x0101;
1565 pfseq = sdp_list_append(0, &profile);
1566 sdp_set_profile_descs(&record, pfseq);
1567
1568 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1569 proto[0] = sdp_list_append(0, &l2cap_uuid);
1570 apseq = sdp_list_append(0, proto[0]);
1571
1572 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1573 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1574 channel = sdp_data_alloc(SDP_UINT8, &u8);
1575 proto[1] = sdp_list_append(proto[1], channel);
1576 apseq = sdp_list_append(apseq, proto[1]);
1577
1578 features = sdp_data_alloc(SDP_UINT16, &u16);
1579 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1580
1581 aproto = sdp_list_append(0, apseq);
1582 sdp_set_access_protos(&record, aproto);
1583
1584 sdp_set_info_attr(&record, "Handsfree", 0, 0);
1585
1586 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1587 printf("Service Record registration failed\n");
1588 ret = -1;
1589 goto end;
1590 }
1591
1592 printf("Handsfree service registered\n");
1593
1594 end:
1595 sdp_data_free(channel);
1596 sdp_list_free(proto[0], 0);
1597 sdp_list_free(proto[1], 0);
1598 sdp_list_free(apseq, 0);
1599 sdp_list_free(aproto, 0);
1600
1601 return ret;
1602 }
1603
add_handsfree_ag(sdp_session_t * session,svc_info_t * si)1604 static int add_handsfree_ag(sdp_session_t *session, svc_info_t *si)
1605 {
1606 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1607 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1608 sdp_profile_desc_t profile;
1609 sdp_list_t *aproto, *proto[2];
1610 sdp_record_t record;
1611 uint8_t u8 = si->channel ? si->channel : 7;
1612 uint16_t u16 = 0x17;
1613 #ifdef ANDROID
1614 u16 = 0x07;
1615 #endif
1616 sdp_data_t *channel, *features;
1617 uint8_t netid = si->network ? si->network : 0x01; // ???? profile document
1618 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
1619 int ret = 0;
1620
1621 memset(&record, 0, sizeof(sdp_record_t));
1622 record.handle = si->handle;
1623
1624 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1625 root = sdp_list_append(0, &root_uuid);
1626 sdp_set_browse_groups(&record, root);
1627
1628 sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
1629 svclass_id = sdp_list_append(0, &svclass_uuid);
1630 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
1631 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1632 sdp_set_service_classes(&record, svclass_id);
1633
1634 sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
1635 profile.version = 0x0105;
1636 pfseq = sdp_list_append(0, &profile);
1637 sdp_set_profile_descs(&record, pfseq);
1638
1639 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1640 proto[0] = sdp_list_append(0, &l2cap_uuid);
1641 apseq = sdp_list_append(0, proto[0]);
1642
1643 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1644 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1645 channel = sdp_data_alloc(SDP_UINT8, &u8);
1646 proto[1] = sdp_list_append(proto[1], channel);
1647 apseq = sdp_list_append(apseq, proto[1]);
1648
1649 features = sdp_data_alloc(SDP_UINT16, &u16);
1650 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1651
1652 aproto = sdp_list_append(0, apseq);
1653 sdp_set_access_protos(&record, aproto);
1654
1655 sdp_set_info_attr(&record, "Voice Gateway", 0, 0);
1656
1657 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
1658
1659 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
1660 printf("Service Record registration failed\n");
1661 ret = -1;
1662 goto end;
1663 }
1664
1665 printf("Handsfree AG service registered\n");
1666
1667 end:
1668 sdp_data_free(channel);
1669 sdp_list_free(proto[0], 0);
1670 sdp_list_free(proto[1], 0);
1671 sdp_list_free(apseq, 0);
1672 sdp_list_free(aproto, 0);
1673
1674 return ret;
1675 }
1676
add_simaccess(sdp_session_t * session,svc_info_t * si)1677 static int add_simaccess(sdp_session_t *session, svc_info_t *si)
1678 {
1679 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1680 uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
1681 sdp_profile_desc_t profile;
1682 sdp_list_t *aproto, *proto[2];
1683 sdp_record_t record;
1684 uint8_t u8 = si->channel? si->channel : 8;
1685 uint16_t u16 = 0x31;
1686 sdp_data_t *channel, *features;
1687 int ret = 0;
1688
1689 memset((void *)&record, 0, sizeof(sdp_record_t));
1690 record.handle = si->handle;
1691
1692 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1693 root = sdp_list_append(0, &root_uuid);
1694 sdp_set_browse_groups(&record, root);
1695
1696 sdp_uuid16_create(&svclass_uuid, SAP_SVCLASS_ID);
1697 svclass_id = sdp_list_append(0, &svclass_uuid);
1698 sdp_uuid16_create(&ga_svclass_uuid, GENERIC_TELEPHONY_SVCLASS_ID);
1699 svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
1700 sdp_set_service_classes(&record, svclass_id);
1701
1702 sdp_uuid16_create(&profile.uuid, SAP_PROFILE_ID);
1703 profile.version = 0x0101;
1704 pfseq = sdp_list_append(0, &profile);
1705 sdp_set_profile_descs(&record, pfseq);
1706
1707 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1708 proto[0] = sdp_list_append(0, &l2cap_uuid);
1709 apseq = sdp_list_append(0, proto[0]);
1710
1711 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1712 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1713 channel = sdp_data_alloc(SDP_UINT8, &u8);
1714 proto[1] = sdp_list_append(proto[1], channel);
1715 apseq = sdp_list_append(apseq, proto[1]);
1716
1717 features = sdp_data_alloc(SDP_UINT16, &u16);
1718 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
1719
1720 aproto = sdp_list_append(0, apseq);
1721 sdp_set_access_protos(&record, aproto);
1722
1723 sdp_set_info_attr(&record, "SIM Access", 0, 0);
1724
1725 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1726 printf("Service Record registration failed\n");
1727 ret = -1;
1728 goto end;
1729 }
1730
1731 printf("SIM Access service registered\n");
1732
1733 end:
1734 sdp_data_free(channel);
1735 sdp_list_free(proto[0], 0);
1736 sdp_list_free(proto[1], 0);
1737 sdp_list_free(apseq, 0);
1738 sdp_list_free(aproto, 0);
1739
1740 return ret;
1741 }
1742
add_opush(sdp_session_t * session,svc_info_t * si)1743 static int add_opush(sdp_session_t *session, svc_info_t *si)
1744 {
1745 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1746 uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1747 sdp_profile_desc_t profile[1];
1748 sdp_list_t *aproto, *proto[3];
1749 sdp_record_t record;
1750 uint8_t chan = si->channel ? si->channel : 9;
1751 sdp_data_t *channel;
1752 #ifdef ANDROID
1753 uint8_t formats[] = { 0x01, 0x02, 0xff };
1754 #else
1755 uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
1756 #endif
1757 void *dtds[sizeof(formats)], *values[sizeof(formats)];
1758 unsigned int i;
1759 uint8_t dtd = SDP_UINT8;
1760 sdp_data_t *sflist;
1761 int ret = 0;
1762
1763 memset(&record, 0, sizeof(sdp_record_t));
1764 record.handle = si->handle;
1765
1766 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1767 root = sdp_list_append(0, &root_uuid);
1768 sdp_set_browse_groups(&record, root);
1769
1770 sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
1771 svclass_id = sdp_list_append(0, &opush_uuid);
1772 sdp_set_service_classes(&record, svclass_id);
1773
1774 sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
1775 profile[0].version = 0x0100;
1776 pfseq = sdp_list_append(0, profile);
1777 sdp_set_profile_descs(&record, pfseq);
1778
1779 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1780 proto[0] = sdp_list_append(0, &l2cap_uuid);
1781 apseq = sdp_list_append(0, proto[0]);
1782
1783 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1784 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1785 channel = sdp_data_alloc(SDP_UINT8, &chan);
1786 proto[1] = sdp_list_append(proto[1], channel);
1787 apseq = sdp_list_append(apseq, proto[1]);
1788
1789 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1790 proto[2] = sdp_list_append(0, &obex_uuid);
1791 apseq = sdp_list_append(apseq, proto[2]);
1792
1793 aproto = sdp_list_append(0, apseq);
1794 sdp_set_access_protos(&record, aproto);
1795
1796 for (i = 0; i < sizeof(formats); i++) {
1797 dtds[i] = &dtd;
1798 values[i] = &formats[i];
1799 }
1800 sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
1801 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
1802
1803 sdp_set_info_attr(&record, "OBEX Object Push", 0, 0);
1804
1805 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1806 printf("Service Record registration failed\n");
1807 ret = -1;
1808 goto end;
1809 }
1810
1811 printf("OBEX Object Push service registered\n");
1812
1813 end:
1814 sdp_data_free(channel);
1815 sdp_list_free(proto[0], 0);
1816 sdp_list_free(proto[1], 0);
1817 sdp_list_free(proto[2], 0);
1818 sdp_list_free(apseq, 0);
1819 sdp_list_free(aproto, 0);
1820
1821 return ret;
1822 }
1823
add_pbap(sdp_session_t * session,svc_info_t * si)1824 static int add_pbap(sdp_session_t *session, svc_info_t *si)
1825 {
1826 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1827 uuid_t root_uuid, pbap_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1828 sdp_profile_desc_t profile[1];
1829 sdp_list_t *aproto, *proto[3];
1830 sdp_record_t record;
1831 uint8_t chan = si->channel ? si->channel : 19;
1832 sdp_data_t *channel;
1833 uint8_t formats[] = {0x01};
1834 uint8_t dtd = SDP_UINT8;
1835 sdp_data_t *sflist;
1836 int ret = 0;
1837
1838 memset(&record, 0, sizeof(sdp_record_t));
1839 record.handle = si->handle;
1840
1841 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1842 root = sdp_list_append(0, &root_uuid);
1843 sdp_set_browse_groups(&record, root);
1844
1845 sdp_uuid16_create(&pbap_uuid, PBAP_PSE_SVCLASS_ID);
1846 svclass_id = sdp_list_append(0, &pbap_uuid);
1847 sdp_set_service_classes(&record, svclass_id);
1848
1849 sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID);
1850 profile[0].version = 0x0100;
1851 pfseq = sdp_list_append(0, profile);
1852 sdp_set_profile_descs(&record, pfseq);
1853
1854 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1855 proto[0] = sdp_list_append(0, &l2cap_uuid);
1856 apseq = sdp_list_append(0, proto[0]);
1857
1858 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1859 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1860 channel = sdp_data_alloc(SDP_UINT8, &chan);
1861 proto[1] = sdp_list_append(proto[1], channel);
1862 apseq = sdp_list_append(apseq, proto[1]);
1863
1864 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1865 proto[2] = sdp_list_append(0, &obex_uuid);
1866 apseq = sdp_list_append(apseq, proto[2]);
1867
1868 aproto = sdp_list_append(0, apseq);
1869 sdp_set_access_protos(&record, aproto);
1870
1871 sflist = sdp_data_alloc(dtd,formats);
1872 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_REPOSITORIES, sflist);
1873
1874 sdp_set_info_attr(&record, "OBEX Phonebook Access Server", 0, 0);
1875
1876 if (sdp_device_record_register(session, &interface, &record,
1877 SDP_RECORD_PERSIST) < 0) {
1878 printf("Service Record registration failed\n");
1879 ret = -1;
1880 goto end;
1881 }
1882
1883 printf("PBAP service registered\n");
1884
1885 end:
1886 sdp_data_free(channel);
1887 sdp_list_free(proto[0], 0);
1888 sdp_list_free(proto[1], 0);
1889 sdp_list_free(proto[2], 0);
1890 sdp_list_free(apseq, 0);
1891 sdp_list_free(aproto, 0);
1892
1893 return ret;
1894 }
1895
add_ftp(sdp_session_t * session,svc_info_t * si)1896 static int add_ftp(sdp_session_t *session, svc_info_t *si)
1897 {
1898 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1899 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1900 sdp_profile_desc_t profile[1];
1901 sdp_list_t *aproto, *proto[3];
1902 sdp_record_t record;
1903 uint8_t u8 = si->channel ? si->channel: 10;
1904 sdp_data_t *channel;
1905 int ret = 0;
1906
1907 memset(&record, 0, sizeof(sdp_record_t));
1908 record.handle = si->handle;
1909
1910 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1911 root = sdp_list_append(0, &root_uuid);
1912 sdp_set_browse_groups(&record, root);
1913
1914 sdp_uuid16_create(&ftrn_uuid, OBEX_FILETRANS_SVCLASS_ID);
1915 svclass_id = sdp_list_append(0, &ftrn_uuid);
1916 sdp_set_service_classes(&record, svclass_id);
1917
1918 sdp_uuid16_create(&profile[0].uuid, OBEX_FILETRANS_PROFILE_ID);
1919 profile[0].version = 0x0100;
1920 pfseq = sdp_list_append(0, &profile[0]);
1921 sdp_set_profile_descs(&record, pfseq);
1922
1923 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1924 proto[0] = sdp_list_append(0, &l2cap_uuid);
1925 apseq = sdp_list_append(0, proto[0]);
1926
1927 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1928 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1929 channel = sdp_data_alloc(SDP_UINT8, &u8);
1930 proto[1] = sdp_list_append(proto[1], channel);
1931 apseq = sdp_list_append(apseq, proto[1]);
1932
1933 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1934 proto[2] = sdp_list_append(0, &obex_uuid);
1935 apseq = sdp_list_append(apseq, proto[2]);
1936
1937 aproto = sdp_list_append(0, apseq);
1938 sdp_set_access_protos(&record, aproto);
1939
1940 sdp_set_info_attr(&record, "OBEX File Transfer", 0, 0);
1941
1942 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
1943 printf("Service Record registration failed\n");
1944 ret = -1;
1945 goto end;
1946 }
1947
1948 printf("OBEX File Transfer service registered\n");
1949
1950 end:
1951 sdp_data_free(channel);
1952 sdp_list_free(proto[0], 0);
1953 sdp_list_free(proto[1], 0);
1954 sdp_list_free(proto[2], 0);
1955 sdp_list_free(apseq, 0);
1956 sdp_list_free(aproto, 0);
1957
1958 return ret;
1959 }
1960
add_directprint(sdp_session_t * session,svc_info_t * si)1961 static int add_directprint(sdp_session_t *session, svc_info_t *si)
1962 {
1963 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
1964 uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
1965 sdp_profile_desc_t profile[1];
1966 sdp_list_t *aproto, *proto[3];
1967 sdp_record_t record;
1968 uint8_t chan = si->channel ? si->channel : 12;
1969 sdp_data_t *channel;
1970 int ret = 0;
1971
1972 memset(&record, 0, sizeof(sdp_record_t));
1973 record.handle = si->handle;
1974
1975 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
1976 root = sdp_list_append(0, &root_uuid);
1977 sdp_set_browse_groups(&record, root);
1978
1979 sdp_uuid16_create(&opush_uuid, DIRECT_PRINTING_SVCLASS_ID);
1980 svclass_id = sdp_list_append(0, &opush_uuid);
1981 sdp_set_service_classes(&record, svclass_id);
1982
1983 sdp_uuid16_create(&profile[0].uuid, BASIC_PRINTING_PROFILE_ID);
1984 profile[0].version = 0x0100;
1985 pfseq = sdp_list_append(0, profile);
1986 sdp_set_profile_descs(&record, pfseq);
1987
1988 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
1989 proto[0] = sdp_list_append(0, &l2cap_uuid);
1990 apseq = sdp_list_append(0, proto[0]);
1991
1992 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
1993 proto[1] = sdp_list_append(0, &rfcomm_uuid);
1994 channel = sdp_data_alloc(SDP_UINT8, &chan);
1995 proto[1] = sdp_list_append(proto[1], channel);
1996 apseq = sdp_list_append(apseq, proto[1]);
1997
1998 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
1999 proto[2] = sdp_list_append(0, &obex_uuid);
2000 apseq = sdp_list_append(apseq, proto[2]);
2001
2002 aproto = sdp_list_append(0, apseq);
2003 sdp_set_access_protos(&record, aproto);
2004
2005 sdp_set_info_attr(&record, "Direct Printing", 0, 0);
2006
2007 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2008 printf("Service Record registration failed\n");
2009 ret = -1;
2010 goto end;
2011 }
2012
2013 printf("Direct Printing service registered\n");
2014
2015 end:
2016 sdp_data_free(channel);
2017 sdp_list_free(proto[0], 0);
2018 sdp_list_free(proto[1], 0);
2019 sdp_list_free(proto[2], 0);
2020 sdp_list_free(apseq, 0);
2021 sdp_list_free(aproto, 0);
2022
2023 return ret;
2024 }
2025
add_nap(sdp_session_t * session,svc_info_t * si)2026 static int add_nap(sdp_session_t *session, svc_info_t *si)
2027 {
2028 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2029 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2030 sdp_profile_desc_t profile[1];
2031 sdp_list_t *aproto, *proto[2];
2032 sdp_record_t record;
2033 uint16_t lp = 0x000f, ver = 0x0100;
2034 sdp_data_t *psm, *version;
2035 int ret = 0;
2036
2037 memset(&record, 0, sizeof(sdp_record_t));
2038 record.handle = si->handle;
2039
2040 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2041 root = sdp_list_append(0, &root_uuid);
2042 sdp_set_browse_groups(&record, root);
2043
2044 sdp_uuid16_create(&ftrn_uuid, NAP_SVCLASS_ID);
2045 svclass_id = sdp_list_append(0, &ftrn_uuid);
2046 sdp_set_service_classes(&record, svclass_id);
2047
2048 sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
2049 profile[0].version = 0x0100;
2050 pfseq = sdp_list_append(0, &profile[0]);
2051 sdp_set_profile_descs(&record, pfseq);
2052
2053 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2054 proto[0] = sdp_list_append(0, &l2cap_uuid);
2055 psm = sdp_data_alloc(SDP_UINT16, &lp);
2056 proto[0] = sdp_list_append(proto[0], psm);
2057 apseq = sdp_list_append(0, proto[0]);
2058
2059 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2060 proto[1] = sdp_list_append(0, &bnep_uuid);
2061 version = sdp_data_alloc(SDP_UINT16, &ver);
2062 proto[1] = sdp_list_append(proto[1], version);
2063
2064 {
2065 uint16_t ptype[4] = { 0x0010, 0x0020, 0x0030, 0x0040 };
2066 sdp_data_t *head, *pseq;
2067 int p;
2068
2069 for (p = 0, head = NULL; p < 4; p++) {
2070 sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
2071 head = sdp_seq_append(head, data);
2072 }
2073 pseq = sdp_data_alloc(SDP_SEQ16, head);
2074 proto[1] = sdp_list_append(proto[1], pseq);
2075 }
2076
2077 apseq = sdp_list_append(apseq, proto[1]);
2078
2079 aproto = sdp_list_append(0, apseq);
2080 sdp_set_access_protos(&record, aproto);
2081
2082 sdp_set_info_attr(&record, "Network Access Point Service", 0, 0);
2083
2084 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2085 printf("Service Record registration failed\n");
2086 ret = -1;
2087 goto end;
2088 }
2089
2090 printf("NAP service registered\n");
2091
2092 end:
2093 sdp_data_free(version);
2094 sdp_data_free(psm);
2095 sdp_list_free(proto[0], 0);
2096 sdp_list_free(proto[1], 0);
2097 sdp_list_free(apseq, 0);
2098 sdp_list_free(aproto, 0);
2099
2100 return ret;
2101 }
2102
add_gn(sdp_session_t * session,svc_info_t * si)2103 static int add_gn(sdp_session_t *session, svc_info_t *si)
2104 {
2105 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2106 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2107 sdp_profile_desc_t profile[1];
2108 sdp_list_t *aproto, *proto[2];
2109 sdp_record_t record;
2110 uint16_t lp = 0x000f, ver = 0x0100;
2111 sdp_data_t *psm, *version;
2112 int ret = 0;
2113
2114 memset(&record, 0, sizeof(sdp_record_t));
2115 record.handle = si->handle;
2116
2117 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2118 root = sdp_list_append(0, &root_uuid);
2119 sdp_set_browse_groups(&record, root);
2120
2121 sdp_uuid16_create(&ftrn_uuid, GN_SVCLASS_ID);
2122 svclass_id = sdp_list_append(0, &ftrn_uuid);
2123 sdp_set_service_classes(&record, svclass_id);
2124
2125 sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
2126 profile[0].version = 0x0100;
2127 pfseq = sdp_list_append(0, &profile[0]);
2128 sdp_set_profile_descs(&record, pfseq);
2129
2130 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2131 proto[0] = sdp_list_append(0, &l2cap_uuid);
2132 psm = sdp_data_alloc(SDP_UINT16, &lp);
2133 proto[0] = sdp_list_append(proto[0], psm);
2134 apseq = sdp_list_append(0, proto[0]);
2135
2136 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2137 proto[1] = sdp_list_append(0, &bnep_uuid);
2138 version = sdp_data_alloc(SDP_UINT16, &ver);
2139 proto[1] = sdp_list_append(proto[1], version);
2140 apseq = sdp_list_append(apseq, proto[1]);
2141
2142 aproto = sdp_list_append(0, apseq);
2143 sdp_set_access_protos(&record, aproto);
2144
2145 sdp_set_info_attr(&record, "Group Network Service", 0, 0);
2146
2147 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2148 printf("Service Record registration failed\n");
2149 ret = -1;
2150 goto end;
2151 }
2152
2153 printf("GN service registered\n");
2154
2155 end:
2156 sdp_data_free(version);
2157 sdp_data_free(psm);
2158 sdp_list_free(proto[0], 0);
2159 sdp_list_free(proto[1], 0);
2160 sdp_list_free(apseq, 0);
2161 sdp_list_free(aproto, 0);
2162
2163 return ret;
2164 }
2165
add_panu(sdp_session_t * session,svc_info_t * si)2166 static int add_panu(sdp_session_t *session, svc_info_t *si)
2167 {
2168 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2169 uuid_t root_uuid, ftrn_uuid, l2cap_uuid, bnep_uuid;
2170 sdp_profile_desc_t profile[1];
2171 sdp_list_t *aproto, *proto[2];
2172 sdp_record_t record;
2173 uint16_t lp = 0x000f, ver = 0x0100;
2174 sdp_data_t *psm, *version;
2175 int ret = 0;
2176
2177 memset(&record, 0, sizeof(sdp_record_t));
2178 record.handle = si->handle;
2179
2180 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2181 root = sdp_list_append(NULL, &root_uuid);
2182 sdp_set_browse_groups(&record, root);
2183 sdp_list_free(root, NULL);
2184
2185 sdp_uuid16_create(&ftrn_uuid, PANU_SVCLASS_ID);
2186 svclass_id = sdp_list_append(NULL, &ftrn_uuid);
2187 sdp_set_service_classes(&record, svclass_id);
2188 sdp_list_free(svclass_id, NULL);
2189
2190 sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
2191 profile[0].version = 0x0100;
2192 pfseq = sdp_list_append(NULL, &profile[0]);
2193 sdp_set_profile_descs(&record, pfseq);
2194 sdp_list_free(pfseq, NULL);
2195
2196 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2197 proto[0] = sdp_list_append(NULL, &l2cap_uuid);
2198 psm = sdp_data_alloc(SDP_UINT16, &lp);
2199 proto[0] = sdp_list_append(proto[0], psm);
2200 apseq = sdp_list_append(NULL, proto[0]);
2201
2202 sdp_uuid16_create(&bnep_uuid, BNEP_UUID);
2203 proto[1] = sdp_list_append(NULL, &bnep_uuid);
2204 version = sdp_data_alloc(SDP_UINT16, &ver);
2205 proto[1] = sdp_list_append(proto[1], version);
2206 apseq = sdp_list_append(apseq, proto[1]);
2207
2208 aproto = sdp_list_append(NULL, apseq);
2209 sdp_set_access_protos(&record, aproto);
2210
2211 sdp_set_info_attr(&record, "PAN User", NULL, NULL);
2212
2213 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2214 printf("Service Record registration failed\n");
2215 ret = -1;
2216 goto end;
2217 }
2218
2219 printf("PANU service registered\n");
2220
2221 end:
2222 sdp_data_free(version);
2223 sdp_data_free(psm);
2224 sdp_list_free(proto[0], 0);
2225 sdp_list_free(proto[1], 0);
2226 sdp_list_free(apseq, 0);
2227 sdp_list_free(aproto, 0);
2228
2229 return ret;
2230 }
2231
add_hid_keyb(sdp_session_t * session,svc_info_t * si)2232 static int add_hid_keyb(sdp_session_t *session, svc_info_t *si)
2233 {
2234 sdp_record_t record;
2235 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2236 uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
2237 sdp_profile_desc_t profile[1];
2238 sdp_list_t *aproto, *proto[3];
2239 sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
2240 unsigned int i;
2241 uint8_t dtd = SDP_UINT16;
2242 uint8_t dtd2 = SDP_UINT8;
2243 uint8_t dtd_data = SDP_TEXT_STR8;
2244 void *dtds[2];
2245 void *values[2];
2246 void *dtds2[2];
2247 void *values2[2];
2248 int leng[2];
2249 uint8_t hid_spec_type = 0x22;
2250 uint16_t hid_attr_lang[] = { 0x409, 0x100 };
2251 static const uint16_t ctrl = 0x11;
2252 static const uint16_t intr = 0x13;
2253 static const uint16_t hid_attr[] = { 0x100, 0x111, 0x40, 0x0d, 0x01, 0x01 };
2254 static const uint16_t hid_attr2[] = { 0x0, 0x01, 0x100, 0x1f40, 0x01, 0x01 };
2255 const uint8_t hid_spec[] = {
2256 0x05, 0x01, // usage page
2257 0x09, 0x06, // keyboard
2258 0xa1, 0x01, // key codes
2259 0x85, 0x01, // minimum
2260 0x05, 0x07, // max
2261 0x19, 0xe0, // logical min
2262 0x29, 0xe7, // logical max
2263 0x15, 0x00, // report size
2264 0x25, 0x01, // report count
2265 0x75, 0x01, // input data variable absolute
2266 0x95, 0x08, // report count
2267 0x81, 0x02, // report size
2268 0x75, 0x08,
2269 0x95, 0x01,
2270 0x81, 0x01,
2271 0x75, 0x01,
2272 0x95, 0x05,
2273 0x05, 0x08,
2274 0x19, 0x01,
2275 0x29, 0x05,
2276 0x91, 0x02,
2277 0x75, 0x03,
2278 0x95, 0x01,
2279 0x91, 0x01,
2280 0x75, 0x08,
2281 0x95, 0x06,
2282 0x15, 0x00,
2283 0x26, 0xff,
2284 0x00, 0x05,
2285 0x07, 0x19,
2286 0x00, 0x2a,
2287 0xff, 0x00,
2288 0x81, 0x00,
2289 0x75, 0x01,
2290 0x95, 0x01,
2291 0x15, 0x00,
2292 0x25, 0x01,
2293 0x05, 0x0c,
2294 0x09, 0xb8,
2295 0x81, 0x06,
2296 0x09, 0xe2,
2297 0x81, 0x06,
2298 0x09, 0xe9,
2299 0x81, 0x02,
2300 0x09, 0xea,
2301 0x81, 0x02,
2302 0x75, 0x01,
2303 0x95, 0x04,
2304 0x81, 0x01,
2305 0xc0 // end tag
2306 };
2307
2308 memset(&record, 0, sizeof(sdp_record_t));
2309 record.handle = si->handle;
2310
2311 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2312 root = sdp_list_append(0, &root_uuid);
2313 sdp_set_browse_groups(&record, root);
2314
2315 add_lang_attr(&record);
2316
2317 sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
2318 svclass_id = sdp_list_append(0, &hidkb_uuid);
2319 sdp_set_service_classes(&record, svclass_id);
2320
2321 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
2322 profile[0].version = 0x0100;
2323 pfseq = sdp_list_append(0, profile);
2324 sdp_set_profile_descs(&record, pfseq);
2325
2326 /* protocols */
2327 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2328 proto[1] = sdp_list_append(0, &l2cap_uuid);
2329 psm = sdp_data_alloc(SDP_UINT16, &ctrl);
2330 proto[1] = sdp_list_append(proto[1], psm);
2331 apseq = sdp_list_append(0, proto[1]);
2332
2333 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2334 proto[2] = sdp_list_append(0, &hidp_uuid);
2335 apseq = sdp_list_append(apseq, proto[2]);
2336
2337 aproto = sdp_list_append(0, apseq);
2338 sdp_set_access_protos(&record, aproto);
2339
2340 /* additional protocols */
2341 proto[1] = sdp_list_append(0, &l2cap_uuid);
2342 psm = sdp_data_alloc(SDP_UINT16, &intr);
2343 proto[1] = sdp_list_append(proto[1], psm);
2344 apseq = sdp_list_append(0, proto[1]);
2345
2346 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2347 proto[2] = sdp_list_append(0, &hidp_uuid);
2348 apseq = sdp_list_append(apseq, proto[2]);
2349
2350 aproto = sdp_list_append(0, apseq);
2351 sdp_set_add_access_protos(&record, aproto);
2352
2353 sdp_set_info_attr(&record, "HID Keyboard", NULL, NULL);
2354
2355 for (i = 0; i < sizeof(hid_attr) / 2; i++)
2356 sdp_attr_add_new(&record,
2357 SDP_ATTR_HID_DEVICE_RELEASE_NUMBER + i,
2358 SDP_UINT16, &hid_attr[i]);
2359
2360 dtds[0] = &dtd2;
2361 values[0] = &hid_spec_type;
2362 dtds[1] = &dtd_data;
2363 values[1] = (uint8_t *) hid_spec;
2364 leng[0] = 0;
2365 leng[1] = sizeof(hid_spec);
2366 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
2367 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
2368 sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
2369
2370 for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
2371 dtds2[i] = &dtd;
2372 values2[i] = &hid_attr_lang[i];
2373 }
2374
2375 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
2376 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
2377 sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
2378
2379 sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE, SDP_UINT16, &hid_attr2[0]);
2380
2381 for (i = 0; i < sizeof(hid_attr2) / 2 - 1; i++)
2382 sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP + i,
2383 SDP_UINT16, &hid_attr2[i + 1]);
2384
2385 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
2386 printf("Service Record registration failed\n");
2387 return -1;
2388 }
2389
2390 printf("HID keyboard service registered\n");
2391
2392 return 0;
2393 }
2394
add_hid_wiimote(sdp_session_t * session,svc_info_t * si)2395 static int add_hid_wiimote(sdp_session_t *session, svc_info_t *si)
2396 {
2397 sdp_record_t record;
2398 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2399 uuid_t root_uuid, hid_uuid, l2cap_uuid, hidp_uuid;
2400 sdp_profile_desc_t profile[1];
2401 sdp_list_t *aproto, *proto[3];
2402 sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
2403 unsigned int i;
2404 uint8_t dtd = SDP_UINT16;
2405 uint8_t dtd2 = SDP_UINT8;
2406 uint8_t dtd_data = SDP_TEXT_STR8;
2407 void *dtds[2];
2408 void *values[2];
2409 void *dtds2[2];
2410 void *values2[2];
2411 int leng[2];
2412 uint8_t hid_spec_type = 0x22;
2413 uint16_t hid_attr_lang[] = { 0x409, 0x100 };
2414 uint16_t ctrl = 0x11, intr = 0x13;
2415 uint16_t hid_release = 0x0100, parser_version = 0x0111;
2416 uint8_t subclass = 0x04, country = 0x33;
2417 uint8_t virtual_cable = 0, reconnect = 1, sdp_disable = 0;
2418 uint8_t battery = 1, remote_wakeup = 1;
2419 uint16_t profile_version = 0x0100, superv_timeout = 0x0c80;
2420 uint8_t norm_connect = 0, boot_device = 0;
2421 const uint8_t hid_spec[] = {
2422 0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x10,
2423 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95,
2424 0x01, 0x06, 0x00, 0xff, 0x09, 0x01, 0x91, 0x00,
2425 0x85, 0x11, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2426 0x85, 0x12, 0x95, 0x02, 0x09, 0x01, 0x91, 0x00,
2427 0x85, 0x13, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2428 0x85, 0x14, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2429 0x85, 0x15, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2430 0x85, 0x16, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
2431 0x85, 0x17, 0x95, 0x06, 0x09, 0x01, 0x91, 0x00,
2432 0x85, 0x18, 0x95, 0x15, 0x09, 0x01, 0x91, 0x00,
2433 0x85, 0x19, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2434 0x85, 0x1a, 0x95, 0x01, 0x09, 0x01, 0x91, 0x00,
2435 0x85, 0x20, 0x95, 0x06, 0x09, 0x01, 0x81, 0x00,
2436 0x85, 0x21, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2437 0x85, 0x22, 0x95, 0x04, 0x09, 0x01, 0x81, 0x00,
2438 0x85, 0x30, 0x95, 0x02, 0x09, 0x01, 0x81, 0x00,
2439 0x85, 0x31, 0x95, 0x05, 0x09, 0x01, 0x81, 0x00,
2440 0x85, 0x32, 0x95, 0x0a, 0x09, 0x01, 0x81, 0x00,
2441 0x85, 0x33, 0x95, 0x11, 0x09, 0x01, 0x81, 0x00,
2442 0x85, 0x34, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2443 0x85, 0x35, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2444 0x85, 0x36, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2445 0x85, 0x37, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2446 0x85, 0x3d, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2447 0x85, 0x3e, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2448 0x85, 0x3f, 0x95, 0x15, 0x09, 0x01, 0x81, 0x00,
2449 0xc0, 0x00
2450 };
2451
2452 memset(&record, 0, sizeof(sdp_record_t));
2453 record.handle = si->handle;
2454
2455 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2456 root = sdp_list_append(NULL, &root_uuid);
2457 sdp_set_browse_groups(&record, root);
2458
2459 sdp_uuid16_create(&hid_uuid, HID_SVCLASS_ID);
2460 svclass_id = sdp_list_append(NULL, &hid_uuid);
2461 sdp_set_service_classes(&record, svclass_id);
2462
2463 sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
2464 profile[0].version = 0x0100;
2465 pfseq = sdp_list_append(NULL, profile);
2466 sdp_set_profile_descs(&record, pfseq);
2467
2468 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2469 proto[1] = sdp_list_append(0, &l2cap_uuid);
2470 psm = sdp_data_alloc(SDP_UINT16, &ctrl);
2471 proto[1] = sdp_list_append(proto[1], psm);
2472 apseq = sdp_list_append(0, proto[1]);
2473
2474 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2475 proto[2] = sdp_list_append(0, &hidp_uuid);
2476 apseq = sdp_list_append(apseq, proto[2]);
2477
2478 aproto = sdp_list_append(0, apseq);
2479 sdp_set_access_protos(&record, aproto);
2480
2481 proto[1] = sdp_list_append(0, &l2cap_uuid);
2482 psm = sdp_data_alloc(SDP_UINT16, &intr);
2483 proto[1] = sdp_list_append(proto[1], psm);
2484 apseq = sdp_list_append(0, proto[1]);
2485
2486 sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
2487 proto[2] = sdp_list_append(0, &hidp_uuid);
2488 apseq = sdp_list_append(apseq, proto[2]);
2489
2490 aproto = sdp_list_append(0, apseq);
2491 sdp_set_add_access_protos(&record, aproto);
2492
2493 add_lang_attr(&record);
2494
2495 sdp_set_info_attr(&record, "Nintendo RVL-CNT-01",
2496 "Nintendo", "Nintendo RVL-CNT-01");
2497
2498 sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_RELEASE_NUMBER,
2499 SDP_UINT16, &hid_release);
2500
2501 sdp_attr_add_new(&record, SDP_ATTR_HID_PARSER_VERSION,
2502 SDP_UINT16, &parser_version);
2503
2504 sdp_attr_add_new(&record, SDP_ATTR_HID_DEVICE_SUBCLASS,
2505 SDP_UINT8, &subclass);
2506
2507 sdp_attr_add_new(&record, SDP_ATTR_HID_COUNTRY_CODE,
2508 SDP_UINT8, &country);
2509
2510 sdp_attr_add_new(&record, SDP_ATTR_HID_VIRTUAL_CABLE,
2511 SDP_BOOL, &virtual_cable);
2512
2513 sdp_attr_add_new(&record, SDP_ATTR_HID_RECONNECT_INITIATE,
2514 SDP_BOOL, &reconnect);
2515
2516 dtds[0] = &dtd2;
2517 values[0] = &hid_spec_type;
2518 dtds[1] = &dtd_data;
2519 values[1] = (uint8_t *) hid_spec;
2520 leng[0] = 0;
2521 leng[1] = sizeof(hid_spec);
2522 hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
2523 hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
2524 sdp_attr_add(&record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
2525
2526 for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
2527 dtds2[i] = &dtd;
2528 values2[i] = &hid_attr_lang[i];
2529 }
2530
2531 lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
2532 lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
2533 sdp_attr_add(&record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
2534
2535 sdp_attr_add_new(&record, SDP_ATTR_HID_SDP_DISABLE,
2536 SDP_BOOL, &sdp_disable);
2537
2538 sdp_attr_add_new(&record, SDP_ATTR_HID_BATTERY_POWER,
2539 SDP_BOOL, &battery);
2540
2541 sdp_attr_add_new(&record, SDP_ATTR_HID_REMOTE_WAKEUP,
2542 SDP_BOOL, &remote_wakeup);
2543
2544 sdp_attr_add_new(&record, SDP_ATTR_HID_PROFILE_VERSION,
2545 SDP_UINT16, &profile_version);
2546
2547 sdp_attr_add_new(&record, SDP_ATTR_HID_SUPERVISION_TIMEOUT,
2548 SDP_UINT16, &superv_timeout);
2549
2550 sdp_attr_add_new(&record, SDP_ATTR_HID_NORMALLY_CONNECTABLE,
2551 SDP_BOOL, &norm_connect);
2552
2553 sdp_attr_add_new(&record, SDP_ATTR_HID_BOOT_DEVICE,
2554 SDP_BOOL, &boot_device);
2555
2556 if (sdp_record_register(session, &record, SDP_RECORD_PERSIST) < 0) {
2557 printf("Service Record registration failed\n");
2558 return -1;
2559 }
2560
2561 printf("Wii-Mote service registered\n");
2562
2563 return 0;
2564 }
2565
add_cip(sdp_session_t * session,svc_info_t * si)2566 static int add_cip(sdp_session_t *session, svc_info_t *si)
2567 {
2568 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2569 uuid_t root_uuid, l2cap, cmtp, cip;
2570 sdp_profile_desc_t profile[1];
2571 sdp_list_t *aproto, *proto[2];
2572 sdp_record_t record;
2573 uint16_t psm = si->psm ? si->psm : 0x1001;
2574 uint8_t netid = si->network ? si->network : 0x02; // 0x02 = ISDN, 0x03 = GSM
2575 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
2576 int ret = 0;
2577
2578 memset(&record, 0, sizeof(sdp_record_t));
2579 record.handle = si->handle;
2580
2581 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2582 root = sdp_list_append(0, &root_uuid);
2583 sdp_set_browse_groups(&record, root);
2584
2585 sdp_uuid16_create(&cip, CIP_SVCLASS_ID);
2586 svclass_id = sdp_list_append(0, &cip);
2587 sdp_set_service_classes(&record, svclass_id);
2588
2589 sdp_uuid16_create(&profile[0].uuid, CIP_PROFILE_ID);
2590 profile[0].version = 0x0100;
2591 pfseq = sdp_list_append(0, &profile[0]);
2592 sdp_set_profile_descs(&record, pfseq);
2593
2594 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2595 proto[0] = sdp_list_append(0, &l2cap);
2596 apseq = sdp_list_append(0, proto[0]);
2597 proto[0] = sdp_list_append(proto[0], sdp_data_alloc(SDP_UINT16, &psm));
2598 apseq = sdp_list_append(0, proto[0]);
2599
2600 sdp_uuid16_create(&cmtp, CMTP_UUID);
2601 proto[1] = sdp_list_append(0, &cmtp);
2602 apseq = sdp_list_append(apseq, proto[1]);
2603
2604 aproto = sdp_list_append(0, apseq);
2605 sdp_set_access_protos(&record, aproto);
2606
2607 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
2608
2609 sdp_set_info_attr(&record, "Common ISDN Access", 0, 0);
2610
2611 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2612 printf("Service Record registration failed\n");
2613 ret = -1;
2614 goto end;
2615 }
2616
2617 printf("CIP service registered\n");
2618
2619 end:
2620 sdp_list_free(proto[0], 0);
2621 sdp_list_free(proto[1], 0);
2622 sdp_list_free(apseq, 0);
2623 sdp_list_free(aproto, 0);
2624 sdp_data_free(network);
2625
2626 return ret;
2627 }
2628
add_ctp(sdp_session_t * session,svc_info_t * si)2629 static int add_ctp(sdp_session_t *session, svc_info_t *si)
2630 {
2631 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2632 uuid_t root_uuid, l2cap, tcsbin, ctp;
2633 sdp_profile_desc_t profile[1];
2634 sdp_list_t *aproto, *proto[2];
2635 sdp_record_t record;
2636 uint8_t netid = si->network ? si->network : 0x02; // 0x01-0x07 cf. p120 profile document
2637 sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
2638 int ret = 0;
2639
2640 memset(&record, 0, sizeof(sdp_record_t));
2641 record.handle = si->handle;
2642
2643 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2644 root = sdp_list_append(0, &root_uuid);
2645 sdp_set_browse_groups(&record, root);
2646
2647 sdp_uuid16_create(&ctp, CORDLESS_TELEPHONY_SVCLASS_ID);
2648 svclass_id = sdp_list_append(0, &ctp);
2649 sdp_set_service_classes(&record, svclass_id);
2650
2651 sdp_uuid16_create(&profile[0].uuid, CORDLESS_TELEPHONY_PROFILE_ID);
2652 profile[0].version = 0x0100;
2653 pfseq = sdp_list_append(0, &profile[0]);
2654 sdp_set_profile_descs(&record, pfseq);
2655
2656 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2657 proto[0] = sdp_list_append(0, &l2cap);
2658 apseq = sdp_list_append(0, proto[0]);
2659
2660 sdp_uuid16_create(&tcsbin, TCS_BIN_UUID);
2661 proto[1] = sdp_list_append(0, &tcsbin);
2662 apseq = sdp_list_append(apseq, proto[1]);
2663
2664 aproto = sdp_list_append(0, apseq);
2665 sdp_set_access_protos(&record, aproto);
2666
2667 sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
2668
2669 sdp_set_info_attr(&record, "Cordless Telephony", 0, 0);
2670
2671 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2672 printf("Service Record registration failed\n");
2673 ret = -1;
2674 goto end;
2675 }
2676
2677 printf("CTP service registered\n");
2678
2679 end:
2680 sdp_list_free(proto[0], 0);
2681 sdp_list_free(proto[1], 0);
2682 sdp_list_free(apseq, 0);
2683 sdp_list_free(aproto, 0);
2684 sdp_data_free(network);
2685
2686 return ret;
2687 }
2688
add_a2source(sdp_session_t * session,svc_info_t * si)2689 static int add_a2source(sdp_session_t *session, svc_info_t *si)
2690 {
2691 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2692 uuid_t root_uuid, l2cap, avdtp, a2src;
2693 sdp_profile_desc_t profile[1];
2694 sdp_list_t *aproto, *proto[2];
2695 sdp_record_t record;
2696 sdp_data_t *psm, *version;
2697 uint16_t lp = 0x0019, ver = 0x0100;
2698 int ret = 0;
2699
2700 memset(&record, 0, sizeof(sdp_record_t));
2701 record.handle = si->handle;
2702
2703 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2704 root = sdp_list_append(0, &root_uuid);
2705 sdp_set_browse_groups(&record, root);
2706
2707 sdp_uuid16_create(&a2src, AUDIO_SOURCE_SVCLASS_ID);
2708 svclass_id = sdp_list_append(0, &a2src);
2709 sdp_set_service_classes(&record, svclass_id);
2710
2711 sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
2712 profile[0].version = 0x0100;
2713 pfseq = sdp_list_append(0, &profile[0]);
2714 sdp_set_profile_descs(&record, pfseq);
2715
2716 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2717 proto[0] = sdp_list_append(0, &l2cap);
2718 psm = sdp_data_alloc(SDP_UINT16, &lp);
2719 proto[0] = sdp_list_append(proto[0], psm);
2720 apseq = sdp_list_append(0, proto[0]);
2721
2722 sdp_uuid16_create(&avdtp, AVDTP_UUID);
2723 proto[1] = sdp_list_append(0, &avdtp);
2724 version = sdp_data_alloc(SDP_UINT16, &ver);
2725 proto[1] = sdp_list_append(proto[1], version);
2726 apseq = sdp_list_append(apseq, proto[1]);
2727
2728 aproto = sdp_list_append(0, apseq);
2729 sdp_set_access_protos(&record, aproto);
2730
2731 sdp_set_info_attr(&record, "Audio Source", 0, 0);
2732
2733 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2734 printf("Service Record registration failed\n");
2735 ret = -1;
2736 goto done;
2737 }
2738
2739 printf("Audio source service registered\n");
2740
2741 done:
2742 sdp_list_free(proto[0], 0);
2743 sdp_list_free(proto[1], 0);
2744 sdp_list_free(apseq, 0);
2745 sdp_list_free(aproto, 0);
2746
2747 return ret;
2748 }
2749
add_a2sink(sdp_session_t * session,svc_info_t * si)2750 static int add_a2sink(sdp_session_t *session, svc_info_t *si)
2751 {
2752 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2753 uuid_t root_uuid, l2cap, avdtp, a2snk;
2754 sdp_profile_desc_t profile[1];
2755 sdp_list_t *aproto, *proto[2];
2756 sdp_record_t record;
2757 sdp_data_t *psm, *version;
2758 uint16_t lp = 0x0019, ver = 0x0100;
2759 int ret = 0;
2760
2761 memset(&record, 0, sizeof(sdp_record_t));
2762 record.handle = si->handle;
2763
2764 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2765 root = sdp_list_append(0, &root_uuid);
2766 sdp_set_browse_groups(&record, root);
2767
2768 sdp_uuid16_create(&a2snk, AUDIO_SINK_SVCLASS_ID);
2769 svclass_id = sdp_list_append(0, &a2snk);
2770 sdp_set_service_classes(&record, svclass_id);
2771
2772 sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID);
2773 profile[0].version = 0x0100;
2774 pfseq = sdp_list_append(0, &profile[0]);
2775 sdp_set_profile_descs(&record, pfseq);
2776
2777 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2778 proto[0] = sdp_list_append(0, &l2cap);
2779 psm = sdp_data_alloc(SDP_UINT16, &lp);
2780 proto[0] = sdp_list_append(proto[0], psm);
2781 apseq = sdp_list_append(0, proto[0]);
2782
2783 sdp_uuid16_create(&avdtp, AVDTP_UUID);
2784 proto[1] = sdp_list_append(0, &avdtp);
2785 version = sdp_data_alloc(SDP_UINT16, &ver);
2786 proto[1] = sdp_list_append(proto[1], version);
2787 apseq = sdp_list_append(apseq, proto[1]);
2788
2789 aproto = sdp_list_append(0, apseq);
2790 sdp_set_access_protos(&record, aproto);
2791
2792 sdp_set_info_attr(&record, "Audio Sink", 0, 0);
2793
2794 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2795 printf("Service Record registration failed\n");
2796 ret = -1;
2797 goto done;
2798 }
2799
2800 printf("Audio sink service registered\n");
2801
2802 done:
2803 sdp_list_free(proto[0], 0);
2804 sdp_list_free(proto[1], 0);
2805 sdp_list_free(apseq, 0);
2806 sdp_list_free(aproto, 0);
2807
2808 return ret;
2809 }
2810
add_avrct(sdp_session_t * session,svc_info_t * si)2811 static int add_avrct(sdp_session_t *session, svc_info_t *si)
2812 {
2813 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2814 uuid_t root_uuid, l2cap, avctp, avrct;
2815 sdp_profile_desc_t profile[1];
2816 sdp_list_t *aproto, *proto[2];
2817 sdp_record_t record;
2818 sdp_data_t *psm, *version, *features;
2819 uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
2820 int ret = 0;
2821
2822 memset(&record, 0, sizeof(sdp_record_t));
2823 record.handle = si->handle;
2824
2825 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2826 root = sdp_list_append(0, &root_uuid);
2827 sdp_set_browse_groups(&record, root);
2828
2829 sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID);
2830 svclass_id = sdp_list_append(0, &avrct);
2831 sdp_set_service_classes(&record, svclass_id);
2832
2833 sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
2834 profile[0].version = 0x0100;
2835 pfseq = sdp_list_append(0, &profile[0]);
2836 sdp_set_profile_descs(&record, pfseq);
2837
2838 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2839 proto[0] = sdp_list_append(0, &l2cap);
2840 psm = sdp_data_alloc(SDP_UINT16, &lp);
2841 proto[0] = sdp_list_append(proto[0], psm);
2842 apseq = sdp_list_append(0, proto[0]);
2843
2844 sdp_uuid16_create(&avctp, AVCTP_UUID);
2845 proto[1] = sdp_list_append(0, &avctp);
2846 version = sdp_data_alloc(SDP_UINT16, &ver);
2847 proto[1] = sdp_list_append(proto[1], version);
2848 apseq = sdp_list_append(apseq, proto[1]);
2849
2850 aproto = sdp_list_append(0, apseq);
2851 sdp_set_access_protos(&record, aproto);
2852
2853 features = sdp_data_alloc(SDP_UINT16, &feat);
2854 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
2855
2856 sdp_set_info_attr(&record, "AVRCP CT", 0, 0);
2857
2858 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2859 printf("Service Record registration failed\n");
2860 ret = -1;
2861 goto done;
2862 }
2863
2864 printf("Remote control service registered\n");
2865
2866 done:
2867 sdp_list_free(proto[0], 0);
2868 sdp_list_free(proto[1], 0);
2869 sdp_list_free(apseq, 0);
2870 sdp_list_free(aproto, 0);
2871
2872 return ret;
2873 }
2874
add_avrtg(sdp_session_t * session,svc_info_t * si)2875 static int add_avrtg(sdp_session_t *session, svc_info_t *si)
2876 {
2877 sdp_list_t *svclass_id, *pfseq, *apseq, *root;
2878 uuid_t root_uuid, l2cap, avctp, avrtg;
2879 sdp_profile_desc_t profile[1];
2880 sdp_list_t *aproto, *proto[2];
2881 sdp_record_t record;
2882 sdp_data_t *psm, *version, *features;
2883 uint16_t lp = 0x0017, ver = 0x0100, feat = 0x000f;
2884 int ret = 0;
2885
2886 memset(&record, 0, sizeof(sdp_record_t));
2887 record.handle = si->handle;
2888
2889 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2890 root = sdp_list_append(0, &root_uuid);
2891 sdp_set_browse_groups(&record, root);
2892
2893 sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID);
2894 svclass_id = sdp_list_append(0, &avrtg);
2895 sdp_set_service_classes(&record, svclass_id);
2896
2897 sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
2898 profile[0].version = 0x0100;
2899 pfseq = sdp_list_append(0, &profile[0]);
2900 sdp_set_profile_descs(&record, pfseq);
2901
2902 sdp_uuid16_create(&l2cap, L2CAP_UUID);
2903 proto[0] = sdp_list_append(0, &l2cap);
2904 psm = sdp_data_alloc(SDP_UINT16, &lp);
2905 proto[0] = sdp_list_append(proto[0], psm);
2906 apseq = sdp_list_append(0, proto[0]);
2907
2908 sdp_uuid16_create(&avctp, AVCTP_UUID);
2909 proto[1] = sdp_list_append(0, &avctp);
2910 version = sdp_data_alloc(SDP_UINT16, &ver);
2911 proto[1] = sdp_list_append(proto[1], version);
2912 apseq = sdp_list_append(apseq, proto[1]);
2913
2914 aproto = sdp_list_append(0, apseq);
2915 sdp_set_access_protos(&record, aproto);
2916
2917 features = sdp_data_alloc(SDP_UINT16, &feat);
2918 sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
2919
2920 sdp_set_info_attr(&record, "AVRCP TG", 0, 0);
2921
2922 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2923 printf("Service Record registration failed\n");
2924 ret = -1;
2925 goto done;
2926 }
2927
2928 printf("Remote target service registered\n");
2929
2930 done:
2931 sdp_list_free(proto[0], 0);
2932 sdp_list_free(proto[1], 0);
2933 sdp_list_free(apseq, 0);
2934 sdp_list_free(aproto, 0);
2935
2936 return ret;
2937 }
2938
add_udi_ue(sdp_session_t * session,svc_info_t * si)2939 static int add_udi_ue(sdp_session_t *session, svc_info_t *si)
2940 {
2941 sdp_record_t record;
2942 sdp_list_t *root, *svclass, *proto;
2943 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
2944 uint8_t channel = si->channel ? si->channel: 18;
2945
2946 memset(&record, 0, sizeof(record));
2947 record.handle = si->handle;
2948
2949 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2950 root = sdp_list_append(NULL, &root_uuid);
2951 sdp_set_browse_groups(&record, root);
2952 sdp_list_free(root, NULL);
2953
2954 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2955 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
2956
2957 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
2958 proto = sdp_list_append(proto, sdp_list_append(
2959 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
2960
2961 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
2962
2963 sdp_uuid16_create(&svclass_uuid, UDI_MT_SVCLASS_ID);
2964 svclass = sdp_list_append(NULL, &svclass_uuid);
2965 sdp_set_service_classes(&record, svclass);
2966 sdp_list_free(svclass, NULL);
2967
2968 sdp_set_info_attr(&record, "UDI UE", NULL, NULL);
2969
2970 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
2971 printf("Service Record registration failed\n");
2972 return -1;
2973 }
2974
2975 printf("UDI UE service registered\n");
2976
2977 return 0;
2978 }
2979
add_udi_te(sdp_session_t * session,svc_info_t * si)2980 static int add_udi_te(sdp_session_t *session, svc_info_t *si)
2981 {
2982 sdp_record_t record;
2983 sdp_list_t *root, *svclass, *proto;
2984 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
2985 uint8_t channel = si->channel ? si->channel: 19;
2986
2987 memset(&record, 0, sizeof(record));
2988 record.handle = si->handle;
2989
2990 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
2991 root = sdp_list_append(NULL, &root_uuid);
2992 sdp_set_browse_groups(&record, root);
2993 sdp_list_free(root, NULL);
2994
2995 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
2996 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
2997
2998 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
2999 proto = sdp_list_append(proto, sdp_list_append(
3000 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3001
3002 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3003
3004 sdp_uuid16_create(&svclass_uuid, UDI_TA_SVCLASS_ID);
3005 svclass = sdp_list_append(NULL, &svclass_uuid);
3006 sdp_set_service_classes(&record, svclass);
3007 sdp_list_free(svclass, NULL);
3008
3009 sdp_set_info_attr(&record, "UDI TE", NULL, NULL);
3010
3011 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3012 printf("Service Record registration failed\n");
3013 return -1;
3014 }
3015
3016 printf("UDI TE service registered\n");
3017
3018 return 0;
3019 }
3020
3021 static unsigned char sr1_uuid[] = { 0xbc, 0x19, 0x9c, 0x24, 0x95, 0x8b, 0x4c, 0xc0,
3022 0xa2, 0xcb, 0xfd, 0x8a, 0x30, 0xbf, 0x32, 0x06 };
3023
add_sr1(sdp_session_t * session,svc_info_t * si)3024 static int add_sr1(sdp_session_t *session, svc_info_t *si)
3025 {
3026 sdp_record_t record;
3027 sdp_list_t *root, *svclass;
3028 uuid_t root_uuid, svclass_uuid;
3029
3030 memset(&record, 0, sizeof(record));
3031 record.handle = si->handle;
3032
3033 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3034 root = sdp_list_append(NULL, &root_uuid);
3035 sdp_set_browse_groups(&record, root);
3036
3037 sdp_uuid128_create(&svclass_uuid, (void *) sr1_uuid);
3038 svclass = sdp_list_append(NULL, &svclass_uuid);
3039 sdp_set_service_classes(&record, svclass);
3040
3041 sdp_set_info_attr(&record, "TOSHIBA SR-1", NULL, NULL);
3042
3043 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3044 printf("Service Record registration failed\n");
3045 return -1;
3046 }
3047
3048 printf("Toshiba Speech Recognition SR-1 service record registered\n");
3049
3050 return 0;
3051 }
3052
3053 static unsigned char syncmls_uuid[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00,
3054 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
3055
3056 static unsigned char syncmlc_uuid[] = { 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x00,
3057 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x02 };
3058
add_syncml(sdp_session_t * session,svc_info_t * si)3059 static int add_syncml(sdp_session_t *session, svc_info_t *si)
3060 {
3061 sdp_record_t record;
3062 sdp_list_t *root, *svclass, *proto;
3063 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
3064 uint8_t channel = si->channel ? si->channel: 15;
3065
3066 memset(&record, 0, sizeof(record));
3067 record.handle = si->handle;
3068
3069 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3070 root = sdp_list_append(NULL, &root_uuid);
3071 sdp_set_browse_groups(&record, root);
3072
3073 sdp_uuid128_create(&svclass_uuid, (void *) syncmlc_uuid);
3074 svclass = sdp_list_append(NULL, &svclass_uuid);
3075 sdp_set_service_classes(&record, svclass);
3076
3077 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3078 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3079
3080 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3081 proto = sdp_list_append(proto, sdp_list_append(
3082 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3083
3084 sdp_uuid16_create(&obex_uuid, OBEX_UUID);
3085 proto = sdp_list_append(proto, sdp_list_append(NULL, &obex_uuid));
3086
3087 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3088
3089 sdp_set_info_attr(&record, "SyncML Client", NULL, NULL);
3090
3091 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3092 printf("Service Record registration failed\n");
3093 return -1;
3094 }
3095
3096 printf("SyncML Client service record registered\n");
3097
3098 return 0;
3099 }
3100
3101 static unsigned char async_uuid[] = { 0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62,
3102 0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C };
3103
add_activesync(sdp_session_t * session,svc_info_t * si)3104 static int add_activesync(sdp_session_t *session, svc_info_t *si)
3105 {
3106 sdp_record_t record;
3107 sdp_list_t *root, *svclass, *proto;
3108 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3109 uint8_t channel = si->channel ? si->channel: 21;
3110
3111 memset(&record, 0, sizeof(record));
3112 record.handle = si->handle;
3113
3114 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3115 root = sdp_list_append(NULL, &root_uuid);
3116 sdp_set_browse_groups(&record, root);
3117
3118 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3119 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3120
3121 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3122 proto = sdp_list_append(proto, sdp_list_append(
3123 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3124
3125 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3126
3127 sdp_uuid128_create(&svclass_uuid, (void *) async_uuid);
3128 svclass = sdp_list_append(NULL, &svclass_uuid);
3129 sdp_set_service_classes(&record, svclass);
3130
3131 sdp_set_info_attr(&record, "Microsoft ActiveSync", NULL, NULL);
3132
3133 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3134 printf("Service Record registration failed\n");
3135 return -1;
3136 }
3137
3138 printf("ActiveSync service record registered\n");
3139
3140 return 0;
3141 }
3142
3143 static unsigned char hotsync_uuid[] = { 0xD8, 0x0C, 0xF9, 0xEA, 0x13, 0x4C, 0x11, 0xD5,
3144 0x83, 0xCE, 0x00, 0x30, 0x65, 0x7C, 0x54, 0x3C };
3145
add_hotsync(sdp_session_t * session,svc_info_t * si)3146 static int add_hotsync(sdp_session_t *session, svc_info_t *si)
3147 {
3148 sdp_record_t record;
3149 sdp_list_t *root, *svclass, *proto;
3150 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3151 uint8_t channel = si->channel ? si->channel: 22;
3152
3153 memset(&record, 0, sizeof(record));
3154 record.handle = si->handle;
3155
3156 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3157 root = sdp_list_append(NULL, &root_uuid);
3158 sdp_set_browse_groups(&record, root);
3159
3160 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3161 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3162
3163 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3164 proto = sdp_list_append(proto, sdp_list_append(
3165 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3166
3167 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3168
3169 sdp_uuid128_create(&svclass_uuid, (void *) hotsync_uuid);
3170 svclass = sdp_list_append(NULL, &svclass_uuid);
3171 sdp_set_service_classes(&record, svclass);
3172
3173 sdp_set_info_attr(&record, "PalmOS HotSync", NULL, NULL);
3174
3175 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3176 printf("Service Record registration failed\n");
3177 return -1;
3178 }
3179
3180 printf("HotSync service record registered\n");
3181
3182 return 0;
3183 }
3184
3185 static unsigned char palmos_uuid[] = { 0xF5, 0xBE, 0xB6, 0x51, 0x41, 0x71, 0x40, 0x51,
3186 0xAC, 0xF5, 0x6C, 0xA7, 0x20, 0x22, 0x42, 0xF0 };
3187
add_palmos(sdp_session_t * session,svc_info_t * si)3188 static int add_palmos(sdp_session_t *session, svc_info_t *si)
3189 {
3190 sdp_record_t record;
3191 sdp_list_t *root, *svclass;
3192 uuid_t root_uuid, svclass_uuid;
3193
3194 memset(&record, 0, sizeof(record));
3195 record.handle = si->handle;
3196
3197 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3198 root = sdp_list_append(NULL, &root_uuid);
3199 sdp_set_browse_groups(&record, root);
3200
3201 sdp_uuid128_create(&svclass_uuid, (void *) palmos_uuid);
3202 svclass = sdp_list_append(NULL, &svclass_uuid);
3203 sdp_set_service_classes(&record, svclass);
3204
3205 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3206 printf("Service Record registration failed\n");
3207 return -1;
3208 }
3209
3210 printf("PalmOS service record registered\n");
3211
3212 return 0;
3213 }
3214
3215 static unsigned char nokid_uuid[] = { 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x10, 0x00,
3216 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3217
add_nokiaid(sdp_session_t * session,svc_info_t * si)3218 static int add_nokiaid(sdp_session_t *session, svc_info_t *si)
3219 {
3220 sdp_record_t record;
3221 sdp_list_t *root, *svclass;
3222 uuid_t root_uuid, svclass_uuid;
3223 uint16_t verid = 0x005f;
3224 sdp_data_t *version = sdp_data_alloc(SDP_UINT16, &verid);
3225
3226 memset(&record, 0, sizeof(record));
3227 record.handle = si->handle;
3228
3229 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3230 root = sdp_list_append(NULL, &root_uuid);
3231 sdp_set_browse_groups(&record, root);
3232
3233 sdp_uuid128_create(&svclass_uuid, (void *) nokid_uuid);
3234 svclass = sdp_list_append(NULL, &svclass_uuid);
3235 sdp_set_service_classes(&record, svclass);
3236
3237 sdp_attr_add(&record, SDP_ATTR_SERVICE_VERSION, version);
3238
3239 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3240 printf("Service Record registration failed\n");
3241 sdp_data_free(version);
3242 return -1;
3243 }
3244
3245 printf("Nokia ID service record registered\n");
3246
3247 return 0;
3248 }
3249
3250 static unsigned char pcsuite_uuid[] = { 0x00, 0x00, 0x50, 0x02, 0x00, 0x00, 0x10, 0x00,
3251 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3252
add_pcsuite(sdp_session_t * session,svc_info_t * si)3253 static int add_pcsuite(sdp_session_t *session, svc_info_t *si)
3254 {
3255 sdp_record_t record;
3256 sdp_list_t *root, *svclass, *proto;
3257 uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid;
3258 uint8_t channel = si->channel ? si->channel: 14;
3259
3260 memset(&record, 0, sizeof(record));
3261 record.handle = si->handle;
3262
3263 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3264 root = sdp_list_append(NULL, &root_uuid);
3265 sdp_set_browse_groups(&record, root);
3266
3267 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3268 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3269
3270 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3271 proto = sdp_list_append(proto, sdp_list_append(
3272 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3273
3274 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3275
3276 sdp_uuid128_create(&svclass_uuid, (void *) pcsuite_uuid);
3277 svclass = sdp_list_append(NULL, &svclass_uuid);
3278 sdp_set_service_classes(&record, svclass);
3279
3280 sdp_set_info_attr(&record, "Nokia PC Suite", NULL, NULL);
3281
3282 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3283 printf("Service Record registration failed\n");
3284 return -1;
3285 }
3286
3287 printf("Nokia PC Suite service registered\n");
3288
3289 return 0;
3290 }
3291
3292 static unsigned char nftp_uuid[] = { 0x00, 0x00, 0x50, 0x05, 0x00, 0x00, 0x10, 0x00,
3293 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3294
3295 static unsigned char nsyncml_uuid[] = { 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x10, 0x00,
3296 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3297
3298 static unsigned char ngage_uuid[] = { 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x10, 0x00,
3299 0x80, 0x00, 0x00, 0x02, 0xEE, 0x00, 0x00, 0x01 };
3300
3301 static unsigned char apple_uuid[] = { 0xf0, 0x72, 0x2e, 0x20, 0x0f, 0x8b, 0x4e, 0x90,
3302 0x8c, 0xc2, 0x1b, 0x46, 0xf5, 0xf2, 0xef, 0xe2 };
3303
add_apple(sdp_session_t * session,svc_info_t * si)3304 static int add_apple(sdp_session_t *session, svc_info_t *si)
3305 {
3306 sdp_record_t record;
3307 sdp_list_t *root;
3308 uuid_t root_uuid;
3309 uint32_t attr783 = 0x00000000;
3310 uint32_t attr785 = 0x00000002;
3311 uint16_t attr786 = 0x1234;
3312
3313 memset(&record, 0, sizeof(record));
3314 record.handle = si->handle;
3315
3316 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3317 root = sdp_list_append(NULL, &root_uuid);
3318 sdp_set_browse_groups(&record, root);
3319
3320 sdp_attr_add_new(&record, 0x0780, SDP_UUID128, (void *) apple_uuid);
3321 sdp_attr_add_new(&record, 0x0781, SDP_TEXT_STR8, (void *) "Macmini");
3322 sdp_attr_add_new(&record, 0x0782, SDP_TEXT_STR8, (void *) "PowerMac10,1");
3323 sdp_attr_add_new(&record, 0x0783, SDP_UINT32, (void *) &attr783);
3324 sdp_attr_add_new(&record, 0x0784, SDP_TEXT_STR8, (void *) "1.6.6f22");
3325 sdp_attr_add_new(&record, 0x0785, SDP_UINT32, (void *) &attr785);
3326 sdp_attr_add_new(&record, 0x0786, SDP_UUID16, (void *) &attr786);
3327
3328 sdp_set_info_attr(&record, "Apple Macintosh Attributes", NULL, NULL);
3329
3330 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3331 printf("Service Record registration failed\n");
3332 return -1;
3333 }
3334
3335 printf("Apple attribute service registered\n");
3336
3337 return 0;
3338 }
3339
add_isync(sdp_session_t * session,svc_info_t * si)3340 static int add_isync(sdp_session_t *session, svc_info_t *si)
3341 {
3342 sdp_record_t record;
3343 sdp_list_t *root, *svclass, *proto;
3344 uuid_t root_uuid, svclass_uuid, serial_uuid, l2cap_uuid, rfcomm_uuid;
3345 uint8_t channel = si->channel ? si->channel : 16;
3346
3347 memset(&record, 0, sizeof(record));
3348 record.handle = si->handle;
3349
3350 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3351 root = sdp_list_append(NULL, &root_uuid);
3352 sdp_set_browse_groups(&record, root);
3353
3354 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3355 proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid));
3356
3357 sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
3358 proto = sdp_list_append(proto, sdp_list_append(
3359 sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel)));
3360
3361 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3362
3363 sdp_uuid16_create(&serial_uuid, SERIAL_PORT_SVCLASS_ID);
3364 svclass = sdp_list_append(NULL, &serial_uuid);
3365
3366 sdp_uuid16_create(&svclass_uuid, APPLE_AGENT_SVCLASS_ID);
3367 svclass = sdp_list_append(svclass, &svclass_uuid);
3368
3369 sdp_set_service_classes(&record, svclass);
3370
3371 sdp_set_info_attr(&record, "AppleAgent", "Bluetooth acceptor", "Apple Computer Ltd.");
3372
3373 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3374 printf("Service Record registration failed\n");
3375 return -1;
3376 }
3377
3378 printf("Apple iSync service registered\n");
3379
3380 return 0;
3381 }
3382
add_semchla(sdp_session_t * session,svc_info_t * si)3383 static int add_semchla(sdp_session_t *session, svc_info_t *si)
3384 {
3385 sdp_record_t record;
3386 sdp_profile_desc_t profile;
3387 sdp_list_t *root, *svclass, *proto, *profiles;
3388 uuid_t root_uuid, service_uuid, l2cap_uuid, semchla_uuid;
3389 uint16_t psm = 0xf0f9;
3390
3391 memset(&record, 0, sizeof(record));
3392 record.handle = si->handle;
3393
3394 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3395 root = sdp_list_append(NULL, &root_uuid);
3396 sdp_set_browse_groups(&record, root);
3397
3398 sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
3399 proto = sdp_list_append(NULL, sdp_list_append(
3400 sdp_list_append(NULL, &l2cap_uuid), sdp_data_alloc(SDP_UINT16, &psm)));
3401
3402 sdp_uuid32_create(&semchla_uuid, 0x8e770300);
3403 proto = sdp_list_append(proto, sdp_list_append(NULL, &semchla_uuid));
3404
3405 sdp_set_access_protos(&record, sdp_list_append(NULL, proto));
3406
3407 sdp_uuid32_create(&service_uuid, 0x8e771301);
3408 svclass = sdp_list_append(NULL, &service_uuid);
3409
3410 sdp_set_service_classes(&record, svclass);
3411
3412 sdp_uuid32_create(&profile.uuid, 0x8e771302); // Headset
3413 //sdp_uuid32_create(&profile.uuid, 0x8e771303); // Phone
3414 profile.version = 0x0100;
3415 profiles = sdp_list_append(NULL, &profile);
3416 sdp_set_profile_descs(&record, profiles);
3417
3418 sdp_set_info_attr(&record, "SEMC HLA", NULL, NULL);
3419
3420 if (sdp_device_record_register(session, &interface, &record, SDP_RECORD_PERSIST) < 0) {
3421 printf("Service Record registration failed\n");
3422 return -1;
3423 }
3424
3425 /* SEMC High Level Authentication */
3426 printf("SEMC HLA service registered\n");
3427
3428 return 0;
3429 }
3430
add_gatt(sdp_session_t * session,svc_info_t * si)3431 static int add_gatt(sdp_session_t *session, svc_info_t *si)
3432 {
3433 sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
3434 uuid_t root_uuid, proto_uuid, gatt_uuid, l2cap;
3435 sdp_profile_desc_t profile;
3436 sdp_record_t record;
3437 sdp_data_t *psm, *sh, *eh;
3438 uint16_t att_psm = 27, start = 0x0001, end = 0x000f;
3439 int ret;
3440
3441 memset(&record, 0, sizeof(sdp_record_t));
3442 record.handle = si->handle;
3443 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3444 root = sdp_list_append(NULL, &root_uuid);
3445 sdp_set_browse_groups(&record, root);
3446 sdp_list_free(root, NULL);
3447
3448 sdp_uuid16_create(&gatt_uuid, GENERIC_ATTRIB_SVCLASS_ID);
3449 svclass_id = sdp_list_append(NULL, &gatt_uuid);
3450 sdp_set_service_classes(&record, svclass_id);
3451 sdp_list_free(svclass_id, NULL);
3452
3453 sdp_uuid16_create(&profile.uuid, GENERIC_ATTRIB_PROFILE_ID);
3454 profile.version = 0x0100;
3455 profiles = sdp_list_append(NULL, &profile);
3456 sdp_set_profile_descs(&record, profiles);
3457 sdp_list_free(profiles, NULL);
3458
3459 sdp_uuid16_create(&l2cap, L2CAP_UUID);
3460 proto[0] = sdp_list_append(NULL, &l2cap);
3461 psm = sdp_data_alloc(SDP_UINT16, &att_psm);
3462 proto[0] = sdp_list_append(proto[0], psm);
3463 apseq = sdp_list_append(NULL, proto[0]);
3464
3465 sdp_uuid16_create(&proto_uuid, ATT_UUID);
3466 proto[1] = sdp_list_append(NULL, &proto_uuid);
3467 sh = sdp_data_alloc(SDP_UINT16, &start);
3468 proto[1] = sdp_list_append(proto[1], sh);
3469 eh = sdp_data_alloc(SDP_UINT16, &end);
3470 proto[1] = sdp_list_append(proto[1], eh);
3471 apseq = sdp_list_append(apseq, proto[1]);
3472
3473 aproto = sdp_list_append(NULL, apseq);
3474 sdp_set_access_protos(&record, aproto);
3475
3476 sdp_set_info_attr(&record, "Generic Attribute Profile", "BlueZ", NULL);
3477
3478 sdp_set_url_attr(&record, "http://www.bluez.org/",
3479 "http://www.bluez.org/", "http://www.bluez.org/");
3480
3481 sdp_set_service_id(&record, gatt_uuid);
3482
3483 ret = sdp_device_record_register(session, &interface, &record,
3484 SDP_RECORD_PERSIST);
3485 if (ret < 0)
3486 printf("Service Record registration failed\n");
3487 else
3488 printf("Generic Attribute Profile Service registered\n");
3489
3490 sdp_data_free(psm);
3491 sdp_data_free(sh);
3492 sdp_data_free(eh);
3493 sdp_list_free(proto[0], NULL);
3494 sdp_list_free(proto[1], NULL);
3495 sdp_list_free(apseq, NULL);
3496 sdp_list_free(aproto, NULL);
3497
3498 return ret;
3499 }
3500
3501 struct {
3502 char *name;
3503 uint32_t class;
3504 int (*add)(sdp_session_t *sess, svc_info_t *si);
3505 unsigned char *uuid;
3506 } service[] = {
3507 { "DID", PNP_INFO_SVCLASS_ID, NULL, },
3508
3509 { "SP", SERIAL_PORT_SVCLASS_ID, add_sp },
3510 { "DUN", DIALUP_NET_SVCLASS_ID, add_dun },
3511 { "LAN", LAN_ACCESS_SVCLASS_ID, add_lan },
3512 { "FAX", FAX_SVCLASS_ID, add_fax },
3513 { "OPUSH", OBEX_OBJPUSH_SVCLASS_ID, add_opush },
3514 { "FTP", OBEX_FILETRANS_SVCLASS_ID, add_ftp },
3515 { "PRINT", DIRECT_PRINTING_SVCLASS_ID, add_directprint },
3516
3517 { "HS", HEADSET_SVCLASS_ID, add_headset },
3518 { "HSAG", HEADSET_AGW_SVCLASS_ID, add_headset_ag },
3519 { "HF", HANDSFREE_SVCLASS_ID, add_handsfree },
3520 { "HFAG", HANDSFREE_AGW_SVCLASS_ID, add_handsfree_ag},
3521 { "SAP", SAP_SVCLASS_ID, add_simaccess },
3522 { "PBAP", PBAP_SVCLASS_ID, add_pbap, },
3523
3524 { "NAP", NAP_SVCLASS_ID, add_nap },
3525 { "GN", GN_SVCLASS_ID, add_gn },
3526 { "PANU", PANU_SVCLASS_ID, add_panu },
3527
3528 { "HCRP", HCR_SVCLASS_ID, NULL },
3529 { "HID", HID_SVCLASS_ID, NULL },
3530 { "KEYB", HID_SVCLASS_ID, add_hid_keyb },
3531 { "WIIMOTE", HID_SVCLASS_ID, add_hid_wiimote },
3532 { "CIP", CIP_SVCLASS_ID, add_cip },
3533 { "CTP", CORDLESS_TELEPHONY_SVCLASS_ID, add_ctp },
3534
3535 { "A2SRC", AUDIO_SOURCE_SVCLASS_ID, add_a2source },
3536 { "A2SNK", AUDIO_SINK_SVCLASS_ID, add_a2sink },
3537 { "AVRCT", AV_REMOTE_SVCLASS_ID, add_avrct },
3538 { "AVRTG", AV_REMOTE_TARGET_SVCLASS_ID, add_avrtg },
3539
3540 { "UDIUE", UDI_MT_SVCLASS_ID, add_udi_ue },
3541 { "UDITE", UDI_TA_SVCLASS_ID, add_udi_te },
3542
3543 { "SEMCHLA", 0x8e771301, add_semchla },
3544
3545 { "SR1", 0, add_sr1, sr1_uuid },
3546 { "SYNCML", 0, add_syncml, syncmlc_uuid },
3547 { "SYNCMLSERV", 0, NULL, syncmls_uuid },
3548 { "ACTIVESYNC", 0, add_activesync, async_uuid },
3549 { "HOTSYNC", 0, add_hotsync, hotsync_uuid },
3550 { "PALMOS", 0, add_palmos, palmos_uuid },
3551 { "NOKID", 0, add_nokiaid, nokid_uuid },
3552 { "PCSUITE", 0, add_pcsuite, pcsuite_uuid },
3553 { "NFTP", 0, NULL, nftp_uuid },
3554 { "NSYNCML", 0, NULL, nsyncml_uuid },
3555 { "NGAGE", 0, NULL, ngage_uuid },
3556 { "APPLE", 0, add_apple, apple_uuid },
3557
3558 { "ISYNC", APPLE_AGENT_SVCLASS_ID, add_isync, },
3559 { "GATT", GENERIC_ATTRIB_SVCLASS_ID, add_gatt, },
3560
3561 { 0 }
3562 };
3563
3564 /* Add local service */
add_service(bdaddr_t * bdaddr,svc_info_t * si)3565 static int add_service(bdaddr_t *bdaddr, svc_info_t *si)
3566 {
3567 sdp_session_t *sess;
3568 int i, ret = -1;
3569
3570 if (!si->name)
3571 return -1;
3572
3573 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
3574 if (!sess)
3575 return -1;
3576
3577 for (i = 0; service[i].name; i++)
3578 if (!strcasecmp(service[i].name, si->name)) {
3579 if (service[i].add)
3580 ret = service[i].add(sess, si);
3581 goto done;
3582 }
3583
3584 printf("Unknown service name: %s\n", si->name);
3585
3586 done:
3587 free(si->name);
3588 sdp_close(sess);
3589
3590 return ret;
3591 }
3592
3593 static struct option add_options[] = {
3594 { "help", 0, 0, 'h' },
3595 { "handle", 1, 0, 'r' },
3596 { "psm", 1, 0, 'p' },
3597 { "channel", 1, 0, 'c' },
3598 { "network", 1, 0, 'n' },
3599 { 0, 0, 0, 0 }
3600 };
3601
3602 static const char *add_help =
3603 "Usage:\n"
3604 "\tadd [--handle=RECORD_HANDLE --channel=CHANNEL] service\n";
3605
cmd_add(int argc,char ** argv)3606 static int cmd_add(int argc, char **argv)
3607 {
3608 svc_info_t si;
3609 int opt;
3610
3611 memset(&si, 0, sizeof(si));
3612 si.handle = 0xffffffff;
3613
3614 for_each_opt(opt, add_options, 0) {
3615 switch (opt) {
3616 case 'r':
3617 if (strncasecmp(optarg, "0x", 2))
3618 si.handle = atoi(optarg);
3619 else
3620 si.handle = strtol(optarg + 2, NULL, 16);
3621 break;
3622 case 'p':
3623 if (strncasecmp(optarg, "0x", 2))
3624 si.psm = atoi(optarg);
3625 else
3626 si.psm = strtol(optarg + 2, NULL, 16);
3627 break;
3628 case 'c':
3629 if (strncasecmp(optarg, "0x", 2))
3630 si.channel = atoi(optarg);
3631 else
3632 si.channel = strtol(optarg + 2, NULL, 16);
3633 break;
3634 case 'n':
3635 if (strncasecmp(optarg, "0x", 2))
3636 si.network = atoi(optarg);
3637 else
3638 si.network = strtol(optarg + 2, NULL, 16);
3639 break;
3640 default:
3641 printf("%s", add_help);
3642 return -1;
3643 }
3644 }
3645
3646 argc -= optind;
3647 argv += optind;
3648
3649 if (argc < 1) {
3650 printf("%s", add_help);
3651 return -1;
3652 }
3653
3654 si.name = strdup(argv[0]);
3655
3656 return add_service(0, &si);
3657 }
3658
3659 /* Delete local service */
del_service(bdaddr_t * bdaddr,void * arg)3660 static int del_service(bdaddr_t *bdaddr, void *arg)
3661 {
3662 uint32_t handle, range = 0x0000ffff;
3663 sdp_list_t *attr;
3664 sdp_session_t *sess;
3665 sdp_record_t *rec;
3666
3667 if (!arg) {
3668 printf("Record handle was not specified.\n");
3669 return -1;
3670 }
3671
3672 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
3673 if (!sess) {
3674 printf("No local SDP server!\n");
3675 return -1;
3676 }
3677
3678 handle = strtoul((char *)arg, 0, 16);
3679 attr = sdp_list_append(0, &range);
3680 rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attr);
3681 sdp_list_free(attr, 0);
3682
3683 if (!rec) {
3684 printf("Service Record not found.\n");
3685 sdp_close(sess);
3686 return -1;
3687 }
3688
3689 if (sdp_device_record_unregister(sess, &interface, rec)) {
3690 printf("Failed to unregister service record: %s\n", strerror(errno));
3691 sdp_close(sess);
3692 return -1;
3693 }
3694
3695 printf("Service Record deleted.\n");
3696 sdp_close(sess);
3697
3698 return 0;
3699 }
3700
3701 static struct option del_options[] = {
3702 { "help", 0, 0, 'h' },
3703 { 0, 0, 0, 0 }
3704 };
3705
3706 static const char *del_help =
3707 "Usage:\n"
3708 "\tdel record_handle\n";
3709
cmd_del(int argc,char ** argv)3710 static int cmd_del(int argc, char **argv)
3711 {
3712 int opt;
3713
3714 for_each_opt(opt, del_options, 0) {
3715 switch (opt) {
3716 default:
3717 printf("%s", del_help);
3718 return -1;
3719 }
3720 }
3721
3722 argc -= optind;
3723 argv += optind;
3724
3725 if (argc < 1) {
3726 printf("%s", del_help);
3727 return -1;
3728 }
3729
3730 return del_service(NULL, argv[0]);
3731 }
3732
3733 /*
3734 * Perform an inquiry and search/browse all peer found.
3735 */
inquiry(handler_t handler,void * arg)3736 static void inquiry(handler_t handler, void *arg)
3737 {
3738 inquiry_info ii[20];
3739 uint8_t count = 0;
3740 int i;
3741
3742 printf("Inquiring ...\n");
3743 if (sdp_general_inquiry(ii, 20, 8, &count) < 0) {
3744 printf("Inquiry failed\n");
3745 return;
3746 }
3747
3748 for (i = 0; i < count; i++)
3749 handler(&ii[i].bdaddr, arg);
3750 }
3751
doprintf(void * data,const char * str)3752 static void doprintf(void *data, const char *str)
3753 {
3754 printf("%s", str);
3755 }
3756
3757 /*
3758 * Search for a specific SDP service
3759 */
do_search(bdaddr_t * bdaddr,struct search_context * context)3760 static int do_search(bdaddr_t *bdaddr, struct search_context *context)
3761 {
3762 sdp_list_t *attrid, *search, *seq, *next;
3763 uint32_t range = 0x0000ffff;
3764 char str[20];
3765 sdp_session_t *sess;
3766
3767 if (!bdaddr) {
3768 inquiry(do_search, context);
3769 return 0;
3770 }
3771
3772 sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
3773 ba2str(bdaddr, str);
3774 if (!sess) {
3775 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
3776 return -1;
3777 }
3778
3779 if (context->view != RAW_VIEW) {
3780 if (context->svc)
3781 printf("Searching for %s on %s ...\n", context->svc, str);
3782 else
3783 printf("Browsing %s ...\n", str);
3784 }
3785
3786 attrid = sdp_list_append(0, &range);
3787 search = sdp_list_append(0, &context->group);
3788 if (sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq)) {
3789 printf("Service Search failed: %s\n", strerror(errno));
3790 sdp_close(sess);
3791 return -1;
3792 }
3793 sdp_list_free(attrid, 0);
3794 sdp_list_free(search, 0);
3795
3796 for (; seq; seq = next) {
3797 sdp_record_t *rec = (sdp_record_t *) seq->data;
3798 struct search_context sub_context;
3799
3800 switch (context->view) {
3801 case DEFAULT_VIEW:
3802 /* Display user friendly form */
3803 print_service_attr(rec);
3804 printf("\n");
3805 break;
3806 case TREE_VIEW:
3807 /* Display full tree */
3808 print_tree_attr(rec);
3809 printf("\n");
3810 break;
3811 case XML_VIEW:
3812 /* Display raw XML tree */
3813 convert_sdp_record_to_xml(rec, 0, doprintf);
3814 break;
3815 default:
3816 /* Display raw tree */
3817 print_raw_attr(rec);
3818 break;
3819 }
3820
3821 if (sdp_get_group_id(rec, &sub_context.group) != -1) {
3822 /* Set the subcontext for browsing the sub tree */
3823 memcpy(&sub_context, context, sizeof(struct search_context));
3824 /* Browse the next level down if not done */
3825 if (sub_context.group.value.uuid16 != context->group.value.uuid16)
3826 do_search(bdaddr, &sub_context);
3827 }
3828 next = seq->next;
3829 free(seq);
3830 sdp_record_free(rec);
3831 }
3832
3833 sdp_close(sess);
3834 return 0;
3835 }
3836
3837 static struct option browse_options[] = {
3838 { "help", 0, 0, 'h' },
3839 { "tree", 0, 0, 't' },
3840 { "raw", 0, 0, 'r' },
3841 { "xml", 0, 0, 'x' },
3842 { "uuid", 1, 0, 'u' },
3843 { "l2cap", 0, 0, 'l' },
3844 { 0, 0, 0, 0 }
3845 };
3846
3847 static const char *browse_help =
3848 "Usage:\n"
3849 "\tbrowse [--tree] [--raw] [--xml] [--uuid uuid] [--l2cap] [bdaddr]\n";
3850
3851 /*
3852 * Browse the full SDP database (i.e. list all services starting from the
3853 * root/top-level).
3854 */
cmd_browse(int argc,char ** argv)3855 static int cmd_browse(int argc, char **argv)
3856 {
3857 struct search_context context;
3858 int opt, num;
3859
3860 /* Initialise context */
3861 memset(&context, '\0', sizeof(struct search_context));
3862 /* We want to browse the top-level/root */
3863 sdp_uuid16_create(&context.group, PUBLIC_BROWSE_GROUP);
3864
3865 for_each_opt(opt, browse_options, 0) {
3866 switch (opt) {
3867 case 't':
3868 context.view = TREE_VIEW;
3869 break;
3870 case 'r':
3871 context.view = RAW_VIEW;
3872 break;
3873 case 'x':
3874 context.view = XML_VIEW;
3875 break;
3876 case 'u':
3877 if (sscanf(optarg, "%i", &num) != 1 || num < 0 || num > 0xffff) {
3878 printf("Invalid uuid %s\n", optarg);
3879 return -1;
3880 }
3881 sdp_uuid16_create(&context.group, num);
3882 break;
3883 case 'l':
3884 sdp_uuid16_create(&context.group, L2CAP_UUID);
3885 break;
3886 default:
3887 printf("%s", browse_help);
3888 return -1;
3889 }
3890 }
3891
3892 argc -= optind;
3893 argv += optind;
3894
3895 if (argc >= 1) {
3896 bdaddr_t bdaddr;
3897 estr2ba(argv[0], &bdaddr);
3898 return do_search(&bdaddr, &context);
3899 }
3900
3901 return do_search(NULL, &context);
3902 }
3903
3904 static struct option search_options[] = {
3905 { "help", 0, 0, 'h' },
3906 { "bdaddr", 1, 0, 'b' },
3907 { "tree", 0, 0, 't' },
3908 { "raw", 0, 0, 'r' },
3909 { "xml", 0, 0, 'x' },
3910 { 0, 0, 0, 0}
3911 };
3912
3913 static const char *search_help =
3914 "Usage:\n"
3915 "\tsearch [--bdaddr bdaddr] [--tree] [--raw] [--xml] SERVICE\n"
3916 "SERVICE is a name (string) or UUID (0x1002)\n";
3917
3918 /*
3919 * Search for a specific SDP service
3920 *
3921 * Note : we should support multiple services on the command line :
3922 * sdptool search 0x0100 0x000f 0x1002
3923 * (this would search a service supporting both L2CAP and BNEP directly in
3924 * the top level browse group)
3925 */
cmd_search(int argc,char ** argv)3926 static int cmd_search(int argc, char **argv)
3927 {
3928 struct search_context context;
3929 unsigned char *uuid = NULL;
3930 uint32_t class = 0;
3931 bdaddr_t bdaddr;
3932 int has_addr = 0;
3933 int i;
3934 int opt;
3935
3936 /* Initialise context */
3937 memset(&context, '\0', sizeof(struct search_context));
3938
3939 for_each_opt(opt, search_options, 0) {
3940 switch (opt) {
3941 case 'b':
3942 estr2ba(optarg, &bdaddr);
3943 has_addr = 1;
3944 break;
3945 case 't':
3946 context.view = TREE_VIEW;
3947 break;
3948 case 'r':
3949 context.view = RAW_VIEW;
3950 break;
3951 case 'x':
3952 context.view = XML_VIEW;
3953 break;
3954 default:
3955 printf("%s", search_help);
3956 return -1;
3957 }
3958 }
3959
3960 argc -= optind;
3961 argv += optind;
3962
3963 if (argc < 1) {
3964 printf("%s", search_help);
3965 return -1;
3966 }
3967
3968 /* Note : we need to find a way to support search combining
3969 * multiple services */
3970 context.svc = strdup(argv[0]);
3971 if (!strncasecmp(context.svc, "0x", 2)) {
3972 int num;
3973 /* This is a UUID16, just convert to int */
3974 sscanf(context.svc + 2, "%X", &num);
3975 class = num;
3976 printf("Class 0x%X\n", class);
3977 } else {
3978 /* Convert class name to an UUID */
3979
3980 for (i = 0; service[i].name; i++)
3981 if (strcasecmp(context.svc, service[i].name) == 0) {
3982 class = service[i].class;
3983 uuid = service[i].uuid;
3984 break;
3985 }
3986 if (!class && !uuid) {
3987 printf("Unknown service %s\n", context.svc);
3988 return -1;
3989 }
3990 }
3991
3992 if (class) {
3993 if (class & 0xffff0000)
3994 sdp_uuid32_create(&context.group, class);
3995 else {
3996 uint16_t class16 = class & 0xffff;
3997 sdp_uuid16_create(&context.group, class16);
3998 }
3999 } else
4000 sdp_uuid128_create(&context.group, uuid);
4001
4002 if (has_addr)
4003 return do_search(&bdaddr, &context);
4004
4005 return do_search(NULL, &context);
4006 }
4007
4008 /*
4009 * Show how to get a specific SDP record by its handle.
4010 * Not really useful to the user, just show how it can be done...
4011 */
get_service(bdaddr_t * bdaddr,struct search_context * context,int quite)4012 static int get_service(bdaddr_t *bdaddr, struct search_context *context, int quite)
4013 {
4014 sdp_list_t *attrid;
4015 uint32_t range = 0x0000ffff;
4016 sdp_record_t *rec;
4017 sdp_session_t *session = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY);
4018
4019 if (!session) {
4020 char str[20];
4021 ba2str(bdaddr, str);
4022 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno));
4023 return -1;
4024 }
4025
4026 attrid = sdp_list_append(0, &range);
4027 rec = sdp_service_attr_req(session, context->handle, SDP_ATTR_REQ_RANGE, attrid);
4028 sdp_list_free(attrid, 0);
4029 sdp_close(session);
4030
4031 if (!rec) {
4032 if (!quite) {
4033 printf("Service get request failed.\n");
4034 return -1;
4035 } else
4036 return 0;
4037 }
4038
4039 switch (context->view) {
4040 case DEFAULT_VIEW:
4041 /* Display user friendly form */
4042 print_service_attr(rec);
4043 printf("\n");
4044 break;
4045 case TREE_VIEW:
4046 /* Display full tree */
4047 print_tree_attr(rec);
4048 printf("\n");
4049 break;
4050 case XML_VIEW:
4051 /* Display raw XML tree */
4052 convert_sdp_record_to_xml(rec, 0, doprintf);
4053 break;
4054 default:
4055 /* Display raw tree */
4056 print_raw_attr(rec);
4057 break;
4058 }
4059
4060 sdp_record_free(rec);
4061 return 0;
4062 }
4063
4064 static struct option records_options[] = {
4065 { "help", 0, 0, 'h' },
4066 { "tree", 0, 0, 't' },
4067 { "raw", 0, 0, 'r' },
4068 { "xml", 0, 0, 'x' },
4069 { 0, 0, 0, 0 }
4070 };
4071
4072 static const char *records_help =
4073 "Usage:\n"
4074 "\trecords [--tree] [--raw] [--xml] bdaddr\n";
4075
4076 /*
4077 * Request possible SDP service records
4078 */
cmd_records(int argc,char ** argv)4079 static int cmd_records(int argc, char **argv)
4080 {
4081 struct search_context context;
4082 uint32_t base[] = { 0x10000, 0x10300, 0x10500,
4083 0x1002e, 0x110b, 0x90000, 0x2008000,
4084 0x4000000, 0x100000, 0x1000000,
4085 0x4f491100, 0x4f491200 };
4086 bdaddr_t bdaddr;
4087 unsigned int i, n, num = 32;
4088 int opt, err = 0;
4089
4090 /* Initialise context */
4091 memset(&context, '\0', sizeof(struct search_context));
4092
4093 for_each_opt(opt, records_options, 0) {
4094 switch (opt) {
4095 case 't':
4096 context.view = TREE_VIEW;
4097 break;
4098 case 'r':
4099 context.view = RAW_VIEW;
4100 break;
4101 case 'x':
4102 context.view = XML_VIEW;
4103 break;
4104 default:
4105 printf("%s", records_help);
4106 return -1;
4107 }
4108 }
4109
4110 argc -= optind;
4111 argv += optind;
4112
4113 if (argc < 1) {
4114 printf("%s", records_help);
4115 return -1;
4116 }
4117
4118 /* Convert command line parameters */
4119 estr2ba(argv[0], &bdaddr);
4120
4121 for (i = 0; i < sizeof(base) / sizeof(uint32_t); i++)
4122 for (n = 0; n < num; n++) {
4123 context.handle = base[i] + n;
4124 err = get_service(&bdaddr, &context, 1);
4125 if (err < 0)
4126 goto done;
4127 }
4128
4129 done:
4130 return 0;
4131 }
4132
4133 static struct option get_options[] = {
4134 { "help", 0, 0, 'h' },
4135 { "bdaddr", 1, 0, 'b' },
4136 { "tree", 0, 0, 't' },
4137 { "raw", 0, 0, 'r' },
4138 { "xml", 0, 0, 'x' },
4139 { 0, 0, 0, 0 }
4140 };
4141
4142 static const char *get_help =
4143 "Usage:\n"
4144 "\tget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\n";
4145
4146 /*
4147 * Get a specific SDP record on the local SDP server
4148 */
cmd_get(int argc,char ** argv)4149 static int cmd_get(int argc, char **argv)
4150 {
4151 struct search_context context;
4152 bdaddr_t bdaddr;
4153 int has_addr = 0;
4154 int opt;
4155
4156 /* Initialise context */
4157 memset(&context, '\0', sizeof(struct search_context));
4158
4159 for_each_opt(opt, get_options, 0) {
4160 switch (opt) {
4161 case 'b':
4162 estr2ba(optarg, &bdaddr);
4163 has_addr = 1;
4164 break;
4165 case 't':
4166 context.view = TREE_VIEW;
4167 break;
4168 case 'r':
4169 context.view = RAW_VIEW;
4170 break;
4171 case 'x':
4172 context.view = XML_VIEW;
4173 break;
4174 default:
4175 printf("%s", get_help);
4176 return -1;
4177 }
4178 }
4179
4180 argc -= optind;
4181 argv += optind;
4182
4183 if (argc < 1) {
4184 printf("%s", get_help);
4185 return -1;
4186 }
4187
4188 /* Convert command line parameters */
4189 context.handle = strtoul(argv[0], 0, 16);
4190
4191 return get_service(has_addr ? &bdaddr : BDADDR_LOCAL, &context, 0);
4192 }
4193
4194 static struct {
4195 char *cmd;
4196 int (*func)(int argc, char **argv);
4197 char *doc;
4198 } command[] = {
4199 { "search", cmd_search, "Search for a service" },
4200 { "browse", cmd_browse, "Browse all available services" },
4201 { "records", cmd_records, "Request all records" },
4202 { "add", cmd_add, "Add local service" },
4203 { "del", cmd_del, "Delete local service" },
4204 { "get", cmd_get, "Get local service" },
4205 { "setattr", cmd_setattr, "Set/Add attribute to a SDP record" },
4206 { "setseq", cmd_setseq, "Set/Add attribute sequence to a SDP record" },
4207 { 0, 0, 0 }
4208 };
4209
usage(void)4210 static void usage(void)
4211 {
4212 int i, pos = 0;
4213
4214 printf("sdptool - SDP tool v%s\n", VERSION);
4215 printf("Usage:\n"
4216 "\tsdptool [options] <command> [command parameters]\n");
4217 printf("Options:\n"
4218 "\t-h\t\tDisplay help\n"
4219 "\t-i\t\tSpecify source interface\n");
4220
4221 printf("Commands:\n");
4222 for (i = 0; command[i].cmd; i++)
4223 printf("\t%-4s\t\t%s\n", command[i].cmd, command[i].doc);
4224
4225 printf("\nServices:\n\t");
4226 for (i = 0; service[i].name; i++) {
4227 printf("%s ", service[i].name);
4228 pos += strlen(service[i].name) + 1;
4229 if (pos > 60) {
4230 printf("\n\t");
4231 pos = 0;
4232 }
4233 }
4234 printf("\n");
4235 }
4236
4237 static struct option main_options[] = {
4238 { "help", 0, 0, 'h' },
4239 { "device", 1, 0, 'i' },
4240 { 0, 0, 0, 0 }
4241 };
4242
main(int argc,char * argv[])4243 int main(int argc, char *argv[])
4244 {
4245 int i, opt;
4246
4247 bacpy(&interface, BDADDR_ANY);
4248
4249 while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
4250 switch(opt) {
4251 case 'i':
4252 if (!strncmp(optarg, "hci", 3))
4253 hci_devba(atoi(optarg + 3), &interface);
4254 else
4255 str2ba(optarg, &interface);
4256 break;
4257
4258 case 'h':
4259 usage();
4260 exit(0);
4261
4262 default:
4263 exit(1);
4264 }
4265 }
4266
4267 argc -= optind;
4268 argv += optind;
4269 optind = 0;
4270
4271 if (argc < 1) {
4272 usage();
4273 exit(1);
4274 }
4275
4276 for (i = 0; command[i].cmd; i++)
4277 if (strncmp(command[i].cmd, argv[0], 4) == 0)
4278 return command[i].func(argc, argv);
4279
4280 return 1;
4281 }
4282