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 (at) qualcomm.com> 7 * Copyright (C) 2002-2010 Marcel Holtmann <marcel (at) holtmann.org> 8 * Copyright (C) 2002-2003 Stephen Crane <steve.crane (at) rococosoft.com> 9 * Copyright (C) 2002-2003 Jean Tourrilhes <jt (at) 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 3431 struct { 3432 char *name; 3433 uint32_t class; 3434 int (*add)(sdp_session_t *sess, svc_info_t *si); 3435 unsigned char *uuid; 3436 } service[] = { 3437 { "DID", PNP_INFO_SVCLASS_ID, NULL, }, 3438 3439 { "SP", SERIAL_PORT_SVCLASS_ID, add_sp }, 3440 { "DUN", DIALUP_NET_SVCLASS_ID, add_dun }, 3441 { "LAN", LAN_ACCESS_SVCLASS_ID, add_lan }, 3442 { "FAX", FAX_SVCLASS_ID, add_fax }, 3443 { "OPUSH", OBEX_OBJPUSH_SVCLASS_ID, add_opush }, 3444 { "FTP", OBEX_FILETRANS_SVCLASS_ID, add_ftp }, 3445 { "PRINT", DIRECT_PRINTING_SVCLASS_ID, add_directprint }, 3446 3447 { "HS", HEADSET_SVCLASS_ID, add_headset }, 3448 { "HSAG", HEADSET_AGW_SVCLASS_ID, add_headset_ag }, 3449 { "HF", HANDSFREE_SVCLASS_ID, add_handsfree }, 3450 { "HFAG", HANDSFREE_AGW_SVCLASS_ID, add_handsfree_ag}, 3451 { "SAP", SAP_SVCLASS_ID, add_simaccess }, 3452 { "PBAP", PBAP_SVCLASS_ID, add_pbap, }, 3453 3454 { "NAP", NAP_SVCLASS_ID, add_nap }, 3455 { "GN", GN_SVCLASS_ID, add_gn }, 3456 { "PANU", PANU_SVCLASS_ID, add_panu }, 3457 3458 { "HCRP", HCR_SVCLASS_ID, NULL }, 3459 { "HID", HID_SVCLASS_ID, NULL }, 3460 { "KEYB", HID_SVCLASS_ID, add_hid_keyb }, 3461 { "WIIMOTE", HID_SVCLASS_ID, add_hid_wiimote }, 3462 { "CIP", CIP_SVCLASS_ID, add_cip }, 3463 { "CTP", CORDLESS_TELEPHONY_SVCLASS_ID, add_ctp }, 3464 3465 { "A2SRC", AUDIO_SOURCE_SVCLASS_ID, add_a2source }, 3466 { "A2SNK", AUDIO_SINK_SVCLASS_ID, add_a2sink }, 3467 { "AVRCT", AV_REMOTE_SVCLASS_ID, add_avrct }, 3468 { "AVRTG", AV_REMOTE_TARGET_SVCLASS_ID, add_avrtg }, 3469 3470 { "UDIUE", UDI_MT_SVCLASS_ID, add_udi_ue }, 3471 { "UDITE", UDI_TA_SVCLASS_ID, add_udi_te }, 3472 3473 { "SEMCHLA", 0x8e771301, add_semchla }, 3474 3475 { "SR1", 0, add_sr1, sr1_uuid }, 3476 { "SYNCML", 0, add_syncml, syncmlc_uuid }, 3477 { "SYNCMLSERV", 0, NULL, syncmls_uuid }, 3478 { "ACTIVESYNC", 0, add_activesync, async_uuid }, 3479 { "HOTSYNC", 0, add_hotsync, hotsync_uuid }, 3480 { "PALMOS", 0, add_palmos, palmos_uuid }, 3481 { "NOKID", 0, add_nokiaid, nokid_uuid }, 3482 { "PCSUITE", 0, add_pcsuite, pcsuite_uuid }, 3483 { "NFTP", 0, NULL, nftp_uuid }, 3484 { "NSYNCML", 0, NULL, nsyncml_uuid }, 3485 { "NGAGE", 0, NULL, ngage_uuid }, 3486 { "APPLE", 0, add_apple, apple_uuid }, 3487 3488 { "ISYNC", APPLE_AGENT_SVCLASS_ID, add_isync, }, 3489 3490 { 0 } 3491 }; 3492 3493 /* Add local service */ 3494 static int add_service(bdaddr_t *bdaddr, svc_info_t *si) 3495 { 3496 sdp_session_t *sess; 3497 int i, ret = -1; 3498 3499 if (!si->name) 3500 return -1; 3501 3502 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); 3503 if (!sess) 3504 return -1; 3505 3506 for (i = 0; service[i].name; i++) 3507 if (!strcasecmp(service[i].name, si->name)) { 3508 if (service[i].add) 3509 ret = service[i].add(sess, si); 3510 goto done; 3511 } 3512 3513 printf("Unknown service name: %s\n", si->name); 3514 3515 done: 3516 free(si->name); 3517 sdp_close(sess); 3518 3519 return ret; 3520 } 3521 3522 static struct option add_options[] = { 3523 { "help", 0, 0, 'h' }, 3524 { "handle", 1, 0, 'r' }, 3525 { "psm", 1, 0, 'p' }, 3526 { "channel", 1, 0, 'c' }, 3527 { "network", 1, 0, 'n' }, 3528 { 0, 0, 0, 0 } 3529 }; 3530 3531 static const char *add_help = 3532 "Usage:\n" 3533 "\tadd [--handle=RECORD_HANDLE --channel=CHANNEL] service\n"; 3534 3535 static int cmd_add(int argc, char **argv) 3536 { 3537 svc_info_t si; 3538 int opt; 3539 3540 memset(&si, 0, sizeof(si)); 3541 si.handle = 0xffffffff; 3542 3543 for_each_opt(opt, add_options, 0) { 3544 switch (opt) { 3545 case 'r': 3546 if (strncasecmp(optarg, "0x", 2)) 3547 si.handle = atoi(optarg); 3548 else 3549 si.handle = strtol(optarg + 2, NULL, 16); 3550 break; 3551 case 'p': 3552 if (strncasecmp(optarg, "0x", 2)) 3553 si.psm = atoi(optarg); 3554 else 3555 si.psm = strtol(optarg + 2, NULL, 16); 3556 break; 3557 case 'c': 3558 if (strncasecmp(optarg, "0x", 2)) 3559 si.channel = atoi(optarg); 3560 else 3561 si.channel = strtol(optarg + 2, NULL, 16); 3562 break; 3563 case 'n': 3564 if (strncasecmp(optarg, "0x", 2)) 3565 si.network = atoi(optarg); 3566 else 3567 si.network = strtol(optarg + 2, NULL, 16); 3568 break; 3569 default: 3570 printf("%s", add_help); 3571 return -1; 3572 } 3573 } 3574 3575 argc -= optind; 3576 argv += optind; 3577 3578 if (argc < 1) { 3579 printf("%s", add_help); 3580 return -1; 3581 } 3582 3583 si.name = strdup(argv[0]); 3584 3585 return add_service(0, &si); 3586 } 3587 3588 /* Delete local service */ 3589 static int del_service(bdaddr_t *bdaddr, void *arg) 3590 { 3591 uint32_t handle, range = 0x0000ffff; 3592 sdp_list_t *attr; 3593 sdp_session_t *sess; 3594 sdp_record_t *rec; 3595 3596 if (!arg) { 3597 printf("Record handle was not specified.\n"); 3598 return -1; 3599 } 3600 3601 sess = sdp_connect(&interface, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); 3602 if (!sess) { 3603 printf("No local SDP server!\n"); 3604 return -1; 3605 } 3606 3607 handle = strtoul((char *)arg, 0, 16); 3608 attr = sdp_list_append(0, &range); 3609 rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attr); 3610 sdp_list_free(attr, 0); 3611 3612 if (!rec) { 3613 printf("Service Record not found.\n"); 3614 sdp_close(sess); 3615 return -1; 3616 } 3617 3618 if (sdp_device_record_unregister(sess, &interface, rec)) { 3619 printf("Failed to unregister service record: %s\n", strerror(errno)); 3620 sdp_close(sess); 3621 return -1; 3622 } 3623 3624 printf("Service Record deleted.\n"); 3625 sdp_close(sess); 3626 3627 return 0; 3628 } 3629 3630 static struct option del_options[] = { 3631 { "help", 0, 0, 'h' }, 3632 { 0, 0, 0, 0 } 3633 }; 3634 3635 static const char *del_help = 3636 "Usage:\n" 3637 "\tdel record_handle\n"; 3638 3639 static int cmd_del(int argc, char **argv) 3640 { 3641 int opt; 3642 3643 for_each_opt(opt, del_options, 0) { 3644 switch (opt) { 3645 default: 3646 printf("%s", del_help); 3647 return -1; 3648 } 3649 } 3650 3651 argc -= optind; 3652 argv += optind; 3653 3654 if (argc < 1) { 3655 printf("%s", del_help); 3656 return -1; 3657 } 3658 3659 return del_service(NULL, argv[0]); 3660 } 3661 3662 /* 3663 * Perform an inquiry and search/browse all peer found. 3664 */ 3665 static void inquiry(handler_t handler, void *arg) 3666 { 3667 inquiry_info ii[20]; 3668 uint8_t count = 0; 3669 int i; 3670 3671 printf("Inquiring ...\n"); 3672 if (sdp_general_inquiry(ii, 20, 8, &count) < 0) { 3673 printf("Inquiry failed\n"); 3674 return; 3675 } 3676 3677 for (i = 0; i < count; i++) 3678 handler(&ii[i].bdaddr, arg); 3679 } 3680 3681 static void doprintf(void *data, const char *str) 3682 { 3683 printf("%s", str); 3684 } 3685 3686 /* 3687 * Search for a specific SDP service 3688 */ 3689 static int do_search(bdaddr_t *bdaddr, struct search_context *context) 3690 { 3691 sdp_list_t *attrid, *search, *seq, *next; 3692 uint32_t range = 0x0000ffff; 3693 char str[20]; 3694 sdp_session_t *sess; 3695 3696 if (!bdaddr) { 3697 inquiry(do_search, context); 3698 return 0; 3699 } 3700 3701 sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY); 3702 ba2str(bdaddr, str); 3703 if (!sess) { 3704 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno)); 3705 return -1; 3706 } 3707 3708 if (context->view != RAW_VIEW) { 3709 if (context->svc) 3710 printf("Searching for %s on %s ...\n", context->svc, str); 3711 else 3712 printf("Browsing %s ...\n", str); 3713 } 3714 3715 attrid = sdp_list_append(0, &range); 3716 search = sdp_list_append(0, &context->group); 3717 if (sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq)) { 3718 printf("Service Search failed: %s\n", strerror(errno)); 3719 sdp_close(sess); 3720 return -1; 3721 } 3722 sdp_list_free(attrid, 0); 3723 sdp_list_free(search, 0); 3724 3725 for (; seq; seq = next) { 3726 sdp_record_t *rec = (sdp_record_t *) seq->data; 3727 struct search_context sub_context; 3728 3729 switch (context->view) { 3730 case DEFAULT_VIEW: 3731 /* Display user friendly form */ 3732 print_service_attr(rec); 3733 printf("\n"); 3734 break; 3735 case TREE_VIEW: 3736 /* Display full tree */ 3737 print_tree_attr(rec); 3738 printf("\n"); 3739 break; 3740 case XML_VIEW: 3741 /* Display raw XML tree */ 3742 convert_sdp_record_to_xml(rec, 0, doprintf); 3743 break; 3744 default: 3745 /* Display raw tree */ 3746 print_raw_attr(rec); 3747 break; 3748 } 3749 3750 if (sdp_get_group_id(rec, &sub_context.group) != -1) { 3751 /* Set the subcontext for browsing the sub tree */ 3752 memcpy(&sub_context, context, sizeof(struct search_context)); 3753 /* Browse the next level down if not done */ 3754 if (sub_context.group.value.uuid16 != context->group.value.uuid16) 3755 do_search(bdaddr, &sub_context); 3756 } 3757 next = seq->next; 3758 free(seq); 3759 sdp_record_free(rec); 3760 } 3761 3762 sdp_close(sess); 3763 return 0; 3764 } 3765 3766 static struct option browse_options[] = { 3767 { "help", 0, 0, 'h' }, 3768 { "tree", 0, 0, 't' }, 3769 { "raw", 0, 0, 'r' }, 3770 { "xml", 0, 0, 'x' }, 3771 { "uuid", 1, 0, 'u' }, 3772 { "l2cap", 0, 0, 'l' }, 3773 { 0, 0, 0, 0 } 3774 }; 3775 3776 static const char *browse_help = 3777 "Usage:\n" 3778 "\tbrowse [--tree] [--raw] [--xml] [--uuid uuid] [--l2cap] [bdaddr]\n"; 3779 3780 /* 3781 * Browse the full SDP database (i.e. list all services starting from the 3782 * root/top-level). 3783 */ 3784 static int cmd_browse(int argc, char **argv) 3785 { 3786 struct search_context context; 3787 int opt, num; 3788 3789 /* Initialise context */ 3790 memset(&context, '\0', sizeof(struct search_context)); 3791 /* We want to browse the top-level/root */ 3792 sdp_uuid16_create(&context.group, PUBLIC_BROWSE_GROUP); 3793 3794 for_each_opt(opt, browse_options, 0) { 3795 switch (opt) { 3796 case 't': 3797 context.view = TREE_VIEW; 3798 break; 3799 case 'r': 3800 context.view = RAW_VIEW; 3801 break; 3802 case 'x': 3803 context.view = XML_VIEW; 3804 break; 3805 case 'u': 3806 if (sscanf(optarg, "%i", &num) != 1 || num < 0 || num > 0xffff) { 3807 printf("Invalid uuid %s\n", optarg); 3808 return -1; 3809 } 3810 sdp_uuid16_create(&context.group, num); 3811 break; 3812 case 'l': 3813 sdp_uuid16_create(&context.group, L2CAP_UUID); 3814 break; 3815 default: 3816 printf("%s", browse_help); 3817 return -1; 3818 } 3819 } 3820 3821 argc -= optind; 3822 argv += optind; 3823 3824 if (argc >= 1) { 3825 bdaddr_t bdaddr; 3826 estr2ba(argv[0], &bdaddr); 3827 return do_search(&bdaddr, &context); 3828 } 3829 3830 return do_search(NULL, &context); 3831 } 3832 3833 static struct option search_options[] = { 3834 { "help", 0, 0, 'h' }, 3835 { "bdaddr", 1, 0, 'b' }, 3836 { "tree", 0, 0, 't' }, 3837 { "raw", 0, 0, 'r' }, 3838 { "xml", 0, 0, 'x' }, 3839 { 0, 0, 0, 0} 3840 }; 3841 3842 static const char *search_help = 3843 "Usage:\n" 3844 "\tsearch [--bdaddr bdaddr] [--tree] [--raw] [--xml] SERVICE\n" 3845 "SERVICE is a name (string) or UUID (0x1002)\n"; 3846 3847 /* 3848 * Search for a specific SDP service 3849 * 3850 * Note : we should support multiple services on the command line : 3851 * sdptool search 0x0100 0x000f 0x1002 3852 * (this would search a service supporting both L2CAP and BNEP directly in 3853 * the top level browse group) 3854 */ 3855 static int cmd_search(int argc, char **argv) 3856 { 3857 struct search_context context; 3858 unsigned char *uuid = NULL; 3859 uint32_t class = 0; 3860 bdaddr_t bdaddr; 3861 int has_addr = 0; 3862 int i; 3863 int opt; 3864 3865 /* Initialise context */ 3866 memset(&context, '\0', sizeof(struct search_context)); 3867 3868 for_each_opt(opt, search_options, 0) { 3869 switch (opt) { 3870 case 'b': 3871 estr2ba(optarg, &bdaddr); 3872 has_addr = 1; 3873 break; 3874 case 't': 3875 context.view = TREE_VIEW; 3876 break; 3877 case 'r': 3878 context.view = RAW_VIEW; 3879 break; 3880 case 'x': 3881 context.view = XML_VIEW; 3882 break; 3883 default: 3884 printf("%s", search_help); 3885 return -1; 3886 } 3887 } 3888 3889 argc -= optind; 3890 argv += optind; 3891 3892 if (argc < 1) { 3893 printf("%s", search_help); 3894 return -1; 3895 } 3896 3897 /* Note : we need to find a way to support search combining 3898 * multiple services */ 3899 context.svc = strdup(argv[0]); 3900 if (!strncasecmp(context.svc, "0x", 2)) { 3901 int num; 3902 /* This is a UUID16, just convert to int */ 3903 sscanf(context.svc + 2, "%X", &num); 3904 class = num; 3905 printf("Class 0x%X\n", class); 3906 } else { 3907 /* Convert class name to an UUID */ 3908 3909 for (i = 0; service[i].name; i++) 3910 if (strcasecmp(context.svc, service[i].name) == 0) { 3911 class = service[i].class; 3912 uuid = service[i].uuid; 3913 break; 3914 } 3915 if (!class && !uuid) { 3916 printf("Unknown service %s\n", context.svc); 3917 return -1; 3918 } 3919 } 3920 3921 if (class) { 3922 if (class & 0xffff0000) 3923 sdp_uuid32_create(&context.group, class); 3924 else { 3925 uint16_t class16 = class & 0xffff; 3926 sdp_uuid16_create(&context.group, class16); 3927 } 3928 } else 3929 sdp_uuid128_create(&context.group, uuid); 3930 3931 if (has_addr) 3932 return do_search(&bdaddr, &context); 3933 3934 return do_search(NULL, &context); 3935 } 3936 3937 /* 3938 * Show how to get a specific SDP record by its handle. 3939 * Not really useful to the user, just show how it can be done... 3940 */ 3941 static int get_service(bdaddr_t *bdaddr, struct search_context *context, int quite) 3942 { 3943 sdp_list_t *attrid; 3944 uint32_t range = 0x0000ffff; 3945 sdp_record_t *rec; 3946 sdp_session_t *session = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY); 3947 3948 if (!session) { 3949 char str[20]; 3950 ba2str(bdaddr, str); 3951 printf("Failed to connect to SDP server on %s: %s\n", str, strerror(errno)); 3952 return -1; 3953 } 3954 3955 attrid = sdp_list_append(0, &range); 3956 rec = sdp_service_attr_req(session, context->handle, SDP_ATTR_REQ_RANGE, attrid); 3957 sdp_list_free(attrid, 0); 3958 sdp_close(session); 3959 3960 if (!rec) { 3961 if (!quite) { 3962 printf("Service get request failed.\n"); 3963 return -1; 3964 } else 3965 return 0; 3966 } 3967 3968 switch (context->view) { 3969 case DEFAULT_VIEW: 3970 /* Display user friendly form */ 3971 print_service_attr(rec); 3972 printf("\n"); 3973 break; 3974 case TREE_VIEW: 3975 /* Display full tree */ 3976 print_tree_attr(rec); 3977 printf("\n"); 3978 break; 3979 case XML_VIEW: 3980 /* Display raw XML tree */ 3981 convert_sdp_record_to_xml(rec, 0, doprintf); 3982 break; 3983 default: 3984 /* Display raw tree */ 3985 print_raw_attr(rec); 3986 break; 3987 } 3988 3989 sdp_record_free(rec); 3990 return 0; 3991 } 3992 3993 static struct option records_options[] = { 3994 { "help", 0, 0, 'h' }, 3995 { "tree", 0, 0, 't' }, 3996 { "raw", 0, 0, 'r' }, 3997 { "xml", 0, 0, 'x' }, 3998 { 0, 0, 0, 0 } 3999 }; 4000 4001 static const char *records_help = 4002 "Usage:\n" 4003 "\trecords [--tree] [--raw] [--xml] bdaddr\n"; 4004 4005 /* 4006 * Request possible SDP service records 4007 */ 4008 static int cmd_records(int argc, char **argv) 4009 { 4010 struct search_context context; 4011 uint32_t base[] = { 0x10000, 0x10300, 0x10500, 4012 0x1002e, 0x110b, 0x90000, 0x2008000, 4013 0x4000000, 0x100000, 0x1000000, 4014 0x4f491100, 0x4f491200 }; 4015 bdaddr_t bdaddr; 4016 unsigned int i, n, num = 32; 4017 int opt, err = 0; 4018 4019 /* Initialise context */ 4020 memset(&context, '\0', sizeof(struct search_context)); 4021 4022 for_each_opt(opt, records_options, 0) { 4023 switch (opt) { 4024 case 't': 4025 context.view = TREE_VIEW; 4026 break; 4027 case 'r': 4028 context.view = RAW_VIEW; 4029 break; 4030 case 'x': 4031 context.view = XML_VIEW; 4032 break; 4033 default: 4034 printf("%s", records_help); 4035 return -1; 4036 } 4037 } 4038 4039 argc -= optind; 4040 argv += optind; 4041 4042 if (argc < 1) { 4043 printf("%s", records_help); 4044 return -1; 4045 } 4046 4047 /* Convert command line parameters */ 4048 estr2ba(argv[0], &bdaddr); 4049 4050 for (i = 0; i < sizeof(base) / sizeof(uint32_t); i++) 4051 for (n = 0; n < num; n++) { 4052 context.handle = base[i] + n; 4053 err = get_service(&bdaddr, &context, 1); 4054 if (err < 0) 4055 goto done; 4056 } 4057 4058 done: 4059 return 0; 4060 } 4061 4062 static struct option get_options[] = { 4063 { "help", 0, 0, 'h' }, 4064 { "bdaddr", 1, 0, 'b' }, 4065 { "tree", 0, 0, 't' }, 4066 { "raw", 0, 0, 'r' }, 4067 { "xml", 0, 0, 'x' }, 4068 { 0, 0, 0, 0 } 4069 }; 4070 4071 static const char *get_help = 4072 "Usage:\n" 4073 "\tget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\n"; 4074 4075 /* 4076 * Get a specific SDP record on the local SDP server 4077 */ 4078 static int cmd_get(int argc, char **argv) 4079 { 4080 struct search_context context; 4081 bdaddr_t bdaddr; 4082 int has_addr = 0; 4083 int opt; 4084 4085 /* Initialise context */ 4086 memset(&context, '\0', sizeof(struct search_context)); 4087 4088 for_each_opt(opt, get_options, 0) { 4089 switch (opt) { 4090 case 'b': 4091 estr2ba(optarg, &bdaddr); 4092 has_addr = 1; 4093 break; 4094 case 't': 4095 context.view = TREE_VIEW; 4096 break; 4097 case 'r': 4098 context.view = RAW_VIEW; 4099 break; 4100 case 'x': 4101 context.view = XML_VIEW; 4102 break; 4103 default: 4104 printf("%s", get_help); 4105 return -1; 4106 } 4107 } 4108 4109 argc -= optind; 4110 argv += optind; 4111 4112 if (argc < 1) { 4113 printf("%s", get_help); 4114 return -1; 4115 } 4116 4117 /* Convert command line parameters */ 4118 context.handle = strtoul(argv[0], 0, 16); 4119 4120 return get_service(has_addr ? &bdaddr : BDADDR_LOCAL, &context, 0); 4121 } 4122 4123 static struct { 4124 char *cmd; 4125 int (*func)(int argc, char **argv); 4126 char *doc; 4127 } command[] = { 4128 { "search", cmd_search, "Search for a service" }, 4129 { "browse", cmd_browse, "Browse all available services" }, 4130 { "records", cmd_records, "Request all records" }, 4131 { "add", cmd_add, "Add local service" }, 4132 { "del", cmd_del, "Delete local service" }, 4133 { "get", cmd_get, "Get local service" }, 4134 { "setattr", cmd_setattr, "Set/Add attribute to a SDP record" }, 4135 { "setseq", cmd_setseq, "Set/Add attribute sequence to a SDP record" }, 4136 { 0, 0, 0 } 4137 }; 4138 4139 static void usage(void) 4140 { 4141 int i, pos = 0; 4142 4143 printf("sdptool - SDP tool v%s\n", VERSION); 4144 printf("Usage:\n" 4145 "\tsdptool [options] <command> [command parameters]\n"); 4146 printf("Options:\n" 4147 "\t-h\t\tDisplay help\n" 4148 "\t-i\t\tSpecify source interface\n"); 4149 4150 printf("Commands:\n"); 4151 for (i = 0; command[i].cmd; i++) 4152 printf("\t%-4s\t\t%s\n", command[i].cmd, command[i].doc); 4153 4154 printf("\nServices:\n\t"); 4155 for (i = 0; service[i].name; i++) { 4156 printf("%s ", service[i].name); 4157 pos += strlen(service[i].name) + 1; 4158 if (pos > 60) { 4159 printf("\n\t"); 4160 pos = 0; 4161 } 4162 } 4163 printf("\n"); 4164 } 4165 4166 static struct option main_options[] = { 4167 { "help", 0, 0, 'h' }, 4168 { "device", 1, 0, 'i' }, 4169 { 0, 0, 0, 0 } 4170 }; 4171 4172 int main(int argc, char *argv[]) 4173 { 4174 int i, opt; 4175 4176 bacpy(&interface, BDADDR_ANY); 4177 4178 while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) { 4179 switch(opt) { 4180 case 'i': 4181 if (!strncmp(optarg, "hci", 3)) 4182 hci_devba(atoi(optarg + 3), &interface); 4183 else 4184 str2ba(optarg, &interface); 4185 break; 4186 4187 case 'h': 4188 usage(); 4189 exit(0); 4190 4191 default: 4192 exit(1); 4193 } 4194 } 4195 4196 argc -= optind; 4197 argv += optind; 4198 optind = 0; 4199 4200 if (argc < 1) { 4201 usage(); 4202 exit(1); 4203 } 4204 4205 for (i = 0; command[i].cmd; i++) 4206 if (strncmp(command[i].cmd, argv[0], 4) == 0) 4207 return command[i].func(argc, argv); 4208 4209 return 1; 4210 } 4211