1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2003-2010 Marcel Holtmann <marcel (at) holtmann.org> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include <stdio.h> 29 #include <errno.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <syslog.h> 33 #include <limits.h> 34 #include <sys/stat.h> 35 #include <sys/socket.h> 36 37 #include <bluetooth/bluetooth.h> 38 #include <bluetooth/l2cap.h> 39 #include <bluetooth/sdp.h> 40 #include <bluetooth/sdp_lib.h> 41 #include <bluetooth/hidp.h> 42 #include <bluetooth/bnep.h> 43 44 #include "textfile.h" 45 #include "sdp.h" 46 47 static sdp_record_t *record = NULL; 48 static sdp_session_t *session = NULL; 49 50 static void add_lang_attr(sdp_record_t *r) 51 { 52 sdp_lang_attr_t base_lang; 53 sdp_list_t *langs = 0; 54 55 /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */ 56 base_lang.code_ISO639 = (0x65 << 8) | 0x6e; 57 base_lang.encoding = 106; 58 base_lang.base_offset = SDP_PRIMARY_LANG_BASE; 59 langs = sdp_list_append(0, &base_lang); 60 sdp_set_lang_attr(r, langs); 61 sdp_list_free(langs, 0); 62 } 63 64 static void epox_endian_quirk(unsigned char *data, int size) 65 { 66 /* USAGE_PAGE (Keyboard) 05 07 67 * USAGE_MINIMUM (0) 19 00 68 * USAGE_MAXIMUM (65280) 2A 00 FF <= must be FF 00 69 * LOGICAL_MINIMUM (0) 15 00 70 * LOGICAL_MAXIMUM (65280) 26 00 FF <= must be FF 00 71 */ 72 unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff, 73 0x15, 0x00, 0x26, 0x00, 0xff }; 74 unsigned int i; 75 76 if (!data) 77 return; 78 79 for (i = 0; i < size - sizeof(pattern); i++) { 80 if (!memcmp(data + i, pattern, sizeof(pattern))) { 81 data[i + 5] = 0xff; 82 data[i + 6] = 0x00; 83 data[i + 10] = 0xff; 84 data[i + 11] = 0x00; 85 } 86 } 87 } 88 89 static int store_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req) 90 { 91 char filename[PATH_MAX + 1], addr[18], *str, *desc; 92 int i, err, size; 93 94 ba2str(src, addr); 95 create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); 96 97 size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; 98 str = malloc(size); 99 if (!str) 100 return -ENOMEM; 101 102 desc = malloc((req->rd_size * 2) + 1); 103 if (!desc) { 104 free(str); 105 return -ENOMEM; 106 } 107 108 memset(desc, 0, (req->rd_size * 2) + 1); 109 for (i = 0; i < req->rd_size; i++) 110 sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]); 111 112 snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %s %08X %s", 113 req->vendor, req->product, req->version, 114 req->subclass, req->country, req->parser, desc, 115 req->flags, req->name); 116 117 free(desc); 118 119 create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 120 121 ba2str(dst, addr); 122 err = textfile_put(filename, addr, str); 123 124 free(str); 125 126 return err; 127 } 128 129 int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req) 130 { 131 char filename[PATH_MAX + 1], addr[18], tmp[3], *str, *desc; 132 unsigned int vendor, product, version, subclass, country, parser, pos; 133 int i; 134 135 desc = malloc(4096); 136 if (!desc) 137 return -ENOMEM; 138 139 memset(desc, 0, 4096); 140 141 ba2str(src, addr); 142 create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); 143 144 ba2str(dst, addr); 145 str = textfile_get(filename, addr); 146 if (!str) { 147 free(desc); 148 return -EIO; 149 } 150 151 sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", 152 &vendor, &product, &version, &subclass, &country, 153 &parser, desc, &req->flags, &pos); 154 155 free(str); 156 157 req->vendor = vendor; 158 req->product = product; 159 req->version = version; 160 req->subclass = subclass; 161 req->country = country; 162 req->parser = parser; 163 164 snprintf(req->name, 128, "%s", str + pos); 165 166 req->rd_size = strlen(desc) / 2; 167 req->rd_data = malloc(req->rd_size); 168 if (!req->rd_data) { 169 free(desc); 170 return -ENOMEM; 171 } 172 173 memset(tmp, 0, sizeof(tmp)); 174 for (i = 0; i < req->rd_size; i++) { 175 memcpy(tmp, desc + (i * 2), 2); 176 req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); 177 } 178 179 free(desc); 180 181 return 0; 182 } 183 184 int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req) 185 { 186 struct sockaddr_l2 addr; 187 socklen_t addrlen; 188 bdaddr_t bdaddr; 189 uint32_t range = 0x0000ffff; 190 sdp_session_t *s; 191 sdp_list_t *search, *attrid, *pnp_rsp, *hid_rsp; 192 sdp_record_t *rec; 193 sdp_data_t *pdlist, *pdlist2; 194 uuid_t svclass; 195 int err; 196 197 s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE); 198 if (!s) 199 return -1; 200 201 sdp_uuid16_create(&svclass, PNP_INFO_SVCLASS_ID); 202 search = sdp_list_append(NULL, &svclass); 203 attrid = sdp_list_append(NULL, &range); 204 205 err = sdp_service_search_attr_req(s, search, 206 SDP_ATTR_REQ_RANGE, attrid, &pnp_rsp); 207 208 sdp_list_free(search, NULL); 209 sdp_list_free(attrid, NULL); 210 211 sdp_uuid16_create(&svclass, HID_SVCLASS_ID); 212 search = sdp_list_append(NULL, &svclass); 213 attrid = sdp_list_append(NULL, &range); 214 215 err = sdp_service_search_attr_req(s, search, 216 SDP_ATTR_REQ_RANGE, attrid, &hid_rsp); 217 218 sdp_list_free(search, NULL); 219 sdp_list_free(attrid, NULL); 220 221 memset(&addr, 0, sizeof(addr)); 222 addrlen = sizeof(addr); 223 224 if (getsockname(s->sock, (struct sockaddr *) &addr, &addrlen) < 0) 225 bacpy(&bdaddr, src); 226 else 227 bacpy(&bdaddr, &addr.l2_bdaddr); 228 229 sdp_close(s); 230 231 if (err || !hid_rsp) 232 return -1; 233 234 if (pnp_rsp) { 235 rec = (sdp_record_t *) pnp_rsp->data; 236 237 pdlist = sdp_data_get(rec, 0x0201); 238 req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; 239 240 pdlist = sdp_data_get(rec, 0x0202); 241 req->product = pdlist ? pdlist->val.uint16 : 0x0000; 242 243 pdlist = sdp_data_get(rec, 0x0203); 244 req->version = pdlist ? pdlist->val.uint16 : 0x0000; 245 246 sdp_record_free(rec); 247 } 248 249 rec = (sdp_record_t *) hid_rsp->data; 250 251 pdlist = sdp_data_get(rec, 0x0101); 252 pdlist2 = sdp_data_get(rec, 0x0102); 253 if (pdlist) { 254 if (pdlist2) { 255 if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) { 256 strncpy(req->name, pdlist2->val.str, sizeof(req->name) - 1); 257 strcat(req->name, " "); 258 } 259 strncat(req->name, pdlist->val.str, 260 sizeof(req->name) - strlen(req->name)); 261 } else 262 strncpy(req->name, pdlist->val.str, sizeof(req->name) - 1); 263 } else { 264 pdlist2 = sdp_data_get(rec, 0x0100); 265 if (pdlist2) 266 strncpy(req->name, pdlist2->val.str, sizeof(req->name) - 1); 267 } 268 269 pdlist = sdp_data_get(rec, 0x0201); 270 req->parser = pdlist ? pdlist->val.uint16 : 0x0100; 271 272 pdlist = sdp_data_get(rec, 0x0202); 273 req->subclass = pdlist ? pdlist->val.uint8 : 0; 274 275 pdlist = sdp_data_get(rec, 0x0203); 276 req->country = pdlist ? pdlist->val.uint8 : 0; 277 278 pdlist = sdp_data_get(rec, 0x0206); 279 if (pdlist) { 280 pdlist = pdlist->val.dataseq; 281 pdlist = pdlist->val.dataseq; 282 pdlist = pdlist->next; 283 284 req->rd_data = malloc(pdlist->unitSize); 285 if (req->rd_data) { 286 memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize); 287 req->rd_size = pdlist->unitSize; 288 epox_endian_quirk(req->rd_data, req->rd_size); 289 } 290 } 291 292 sdp_record_free(rec); 293 294 if (bacmp(&bdaddr, BDADDR_ANY)) 295 store_device_info(&bdaddr, dst, req); 296 297 return 0; 298 } 299 300 int get_alternate_device_info(const bdaddr_t *src, const bdaddr_t *dst, uint16_t *uuid, uint8_t *channel, char *name, size_t len) 301 { 302 uint16_t attr1 = SDP_ATTR_PROTO_DESC_LIST; 303 uint16_t attr2 = SDP_ATTR_SVCNAME_PRIMARY; 304 sdp_session_t *s; 305 sdp_list_t *search, *attrid, *rsp; 306 uuid_t svclass; 307 int err; 308 309 s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE); 310 if (!s) 311 return -1; 312 313 sdp_uuid16_create(&svclass, HEADSET_SVCLASS_ID); 314 search = sdp_list_append(NULL, &svclass); 315 attrid = sdp_list_append(NULL, &attr1); 316 attrid = sdp_list_append(attrid, &attr2); 317 318 err = sdp_service_search_attr_req(s, search, 319 SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp); 320 321 sdp_list_free(search, NULL); 322 sdp_list_free(attrid, NULL); 323 324 if (err <= 0) { 325 sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID); 326 search = sdp_list_append(NULL, &svclass); 327 attrid = sdp_list_append(NULL, &attr1); 328 attrid = sdp_list_append(attrid, &attr2); 329 330 err = sdp_service_search_attr_req(s, search, 331 SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp); 332 333 sdp_list_free(search, NULL); 334 sdp_list_free(attrid, NULL); 335 336 if (err < 0) { 337 sdp_close(s); 338 return err; 339 } 340 341 if (uuid) 342 *uuid = SERIAL_PORT_SVCLASS_ID; 343 } else { 344 if (uuid) 345 *uuid = HEADSET_SVCLASS_ID; 346 } 347 348 sdp_close(s); 349 350 for (; rsp; rsp = rsp->next) { 351 sdp_record_t *rec = (sdp_record_t *) rsp->data; 352 sdp_list_t *protos; 353 354 sdp_get_service_name(rec, name, len); 355 356 if (!sdp_get_access_protos(rec, &protos)) { 357 uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID); 358 if (ch > 0) { 359 if (channel) 360 *channel = ch; 361 return 0; 362 } 363 } 364 365 sdp_record_free(rec); 366 } 367 368 return -EIO; 369 } 370 371 void bnep_sdp_unregister(void) 372 { 373 if (record && sdp_record_unregister(session, record)) 374 syslog(LOG_ERR, "Service record unregistration failed."); 375 376 sdp_close(session); 377 } 378 379 int bnep_sdp_register(bdaddr_t *device, uint16_t role) 380 { 381 sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto; 382 uuid_t root_uuid, pan, l2cap, bnep; 383 sdp_profile_desc_t profile[1]; 384 sdp_list_t *proto[2]; 385 sdp_data_t *v, *p; 386 uint16_t psm = 15, version = 0x0100; 387 uint16_t security_desc = 0; 388 uint16_t net_access_type = 0xfffe; 389 uint32_t max_net_access_rate = 0; 390 char *name = "BlueZ PAN"; 391 char *desc = "BlueZ PAN Service"; 392 int status; 393 394 session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0); 395 if (!session) { 396 syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)", 397 strerror(errno), errno); 398 return -1; 399 } 400 401 record = sdp_record_alloc(); 402 if (!record) { 403 syslog(LOG_ERR, "Failed to allocate service record %s(%d)", 404 strerror(errno), errno); 405 sdp_close(session); 406 return -1; 407 } 408 409 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); 410 root = sdp_list_append(NULL, &root_uuid); 411 sdp_set_browse_groups(record, root); 412 sdp_list_free(root, 0); 413 414 sdp_uuid16_create(&l2cap, L2CAP_UUID); 415 proto[0] = sdp_list_append(NULL, &l2cap); 416 p = sdp_data_alloc(SDP_UINT16, &psm); 417 proto[0] = sdp_list_append(proto[0], p); 418 apseq = sdp_list_append(NULL, proto[0]); 419 420 sdp_uuid16_create(&bnep, BNEP_UUID); 421 proto[1] = sdp_list_append(NULL, &bnep); 422 v = sdp_data_alloc(SDP_UINT16, &version); 423 proto[1] = sdp_list_append(proto[1], v); 424 425 /* Supported protocols */ 426 { 427 uint16_t ptype[4] = { 428 0x0800, /* IPv4 */ 429 0x0806, /* ARP */ 430 }; 431 sdp_data_t *head, *pseq; 432 int p; 433 434 for (p = 0, head = NULL; p < 2; p++) { 435 sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]); 436 if (head) 437 sdp_seq_append(head, data); 438 else 439 head = data; 440 } 441 pseq = sdp_data_alloc(SDP_SEQ16, head); 442 proto[1] = sdp_list_append(proto[1], pseq); 443 } 444 445 apseq = sdp_list_append(apseq, proto[1]); 446 447 aproto = sdp_list_append(NULL, apseq); 448 sdp_set_access_protos(record, aproto); 449 450 add_lang_attr(record); 451 452 sdp_list_free(proto[0], NULL); 453 sdp_list_free(proto[1], NULL); 454 sdp_list_free(apseq, NULL); 455 sdp_list_free(aproto, NULL); 456 sdp_data_free(p); 457 sdp_data_free(v); 458 sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC, SDP_UINT16, &security_desc); 459 460 switch (role) { 461 case BNEP_SVC_NAP: 462 sdp_uuid16_create(&pan, NAP_SVCLASS_ID); 463 svclass = sdp_list_append(NULL, &pan); 464 sdp_set_service_classes(record, svclass); 465 466 sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID); 467 profile[0].version = 0x0100; 468 pfseq = sdp_list_append(NULL, &profile[0]); 469 sdp_set_profile_descs(record, pfseq); 470 471 sdp_set_info_attr(record, "Network Access Point", name, desc); 472 473 sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE, SDP_UINT16, &net_access_type); 474 sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE, SDP_UINT32, &max_net_access_rate); 475 break; 476 477 case BNEP_SVC_GN: 478 sdp_uuid16_create(&pan, GN_SVCLASS_ID); 479 svclass = sdp_list_append(NULL, &pan); 480 sdp_set_service_classes(record, svclass); 481 482 sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID); 483 profile[0].version = 0x0100; 484 pfseq = sdp_list_append(NULL, &profile[0]); 485 sdp_set_profile_descs(record, pfseq); 486 487 sdp_set_info_attr(record, "Group Network Service", name, desc); 488 break; 489 490 case BNEP_SVC_PANU: 491 sdp_uuid16_create(&pan, PANU_SVCLASS_ID); 492 svclass = sdp_list_append(NULL, &pan); 493 sdp_set_service_classes(record, svclass); 494 sdp_list_free(svclass, 0); 495 496 sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID); 497 profile[0].version = 0x0100; 498 pfseq = sdp_list_append(NULL, &profile[0]); 499 sdp_set_profile_descs(record, pfseq); 500 sdp_list_free(pfseq, 0); 501 502 sdp_set_info_attr(record, "PAN User", name, desc); 503 break; 504 } 505 506 status = sdp_device_record_register(session, device, record, 0); 507 if (status) { 508 syslog(LOG_ERR, "SDP registration failed."); 509 sdp_record_free(record); record = NULL; 510 sdp_close(session); 511 return -1; 512 } 513 514 return 0; 515 } 516 517 /* Search for PAN service. 518 * Returns 1 if service is found and 0 otherwise. */ 519 int bnep_sdp_search(bdaddr_t *src, bdaddr_t *dst, uint16_t service) 520 { 521 sdp_list_t *srch, *rsp = NULL; 522 sdp_session_t *s; 523 uuid_t svclass; 524 int err; 525 526 switch (service) { 527 case BNEP_SVC_PANU: 528 sdp_uuid16_create(&svclass, PANU_SVCLASS_ID); 529 break; 530 case BNEP_SVC_NAP: 531 sdp_uuid16_create(&svclass, NAP_SVCLASS_ID); 532 break; 533 case BNEP_SVC_GN: 534 sdp_uuid16_create(&svclass, GN_SVCLASS_ID); 535 break; 536 } 537 538 srch = sdp_list_append(NULL, &svclass); 539 540 s = sdp_connect(src, dst, 0); 541 if (!s) { 542 syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)", 543 strerror(errno), errno); 544 return 0; 545 } 546 547 err = sdp_service_search_req(s, srch, 1, &rsp); 548 sdp_close(s); 549 550 /* Assume that search is successeful 551 * if at least one record is found */ 552 if (!err && sdp_list_len(rsp)) 553 return 1; 554 555 return 0; 556 } 557 558 static unsigned char async_uuid[] = { 0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62, 559 0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C }; 560 561 void dun_sdp_unregister(void) 562 { 563 if (record && sdp_record_unregister(session, record)) 564 syslog(LOG_ERR, "Service record unregistration failed."); 565 sdp_close(session); 566 } 567 568 int dun_sdp_register(bdaddr_t *device, uint8_t channel, int type) 569 { 570 sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto; 571 uuid_t root_uuid, l2cap, rfcomm, dun; 572 sdp_profile_desc_t profile[1]; 573 sdp_list_t *proto[2]; 574 int status; 575 576 session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0); 577 if (!session) { 578 syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)", 579 strerror(errno), errno); 580 return -1; 581 } 582 583 record = sdp_record_alloc(); 584 if (!record) { 585 syslog(LOG_ERR, "Failed to alloc service record"); 586 return -1; 587 } 588 589 sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); 590 root = sdp_list_append(NULL, &root_uuid); 591 sdp_set_browse_groups(record, root); 592 593 sdp_uuid16_create(&l2cap, L2CAP_UUID); 594 proto[0] = sdp_list_append(NULL, &l2cap); 595 apseq = sdp_list_append(NULL, proto[0]); 596 597 sdp_uuid16_create(&rfcomm, RFCOMM_UUID); 598 proto[1] = sdp_list_append(NULL, &rfcomm); 599 proto[1] = sdp_list_append(proto[1], sdp_data_alloc(SDP_UINT8, &channel)); 600 apseq = sdp_list_append(apseq, proto[1]); 601 602 aproto = sdp_list_append(NULL, apseq); 603 sdp_set_access_protos(record, aproto); 604 605 switch (type) { 606 case MROUTER: 607 sdp_uuid16_create(&dun, SERIAL_PORT_SVCLASS_ID); 608 break; 609 case ACTIVESYNC: 610 sdp_uuid128_create(&dun, (void *) async_uuid); 611 break; 612 case DIALUP: 613 sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID); 614 break; 615 default: 616 sdp_uuid16_create(&dun, LAN_ACCESS_SVCLASS_ID); 617 break; 618 } 619 620 svclass = sdp_list_append(NULL, &dun); 621 sdp_set_service_classes(record, svclass); 622 623 switch (type) { 624 case LANACCESS: 625 sdp_uuid16_create(&profile[0].uuid, LAN_ACCESS_PROFILE_ID); 626 profile[0].version = 0x0100; 627 pfseq = sdp_list_append(NULL, &profile[0]); 628 sdp_set_profile_descs(record, pfseq); 629 break; 630 case DIALUP: 631 sdp_uuid16_create(&profile[0].uuid, DIALUP_NET_PROFILE_ID); 632 profile[0].version = 0x0100; 633 pfseq = sdp_list_append(NULL, &profile[0]); 634 sdp_set_profile_descs(record, pfseq); 635 break; 636 } 637 638 switch (type) { 639 case MROUTER: 640 sdp_set_info_attr(record, "mRouter", NULL, NULL); 641 break; 642 case ACTIVESYNC: 643 sdp_set_info_attr(record, "ActiveSync", NULL, NULL); 644 break; 645 case DIALUP: 646 sdp_set_info_attr(record, "Dialup Networking", NULL, NULL); 647 break; 648 default: 649 sdp_set_info_attr(record, "LAN Access Point", NULL, NULL); 650 break; 651 } 652 653 status = sdp_device_record_register(session, device, record, 0); 654 if (status) { 655 syslog(LOG_ERR, "SDP registration failed."); 656 sdp_record_free(record); 657 record = NULL; 658 return -1; 659 } 660 return 0; 661 } 662 663 int dun_sdp_search(bdaddr_t *src, bdaddr_t *dst, int *channel, int type) 664 { 665 sdp_session_t *s; 666 sdp_list_t *srch, *attrs, *rsp; 667 uuid_t svclass; 668 uint16_t attr; 669 int err; 670 671 s = sdp_connect(src, dst, 0); 672 if (!s) { 673 syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)", 674 strerror(errno), errno); 675 return -1; 676 } 677 678 switch (type) { 679 case MROUTER: 680 sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID); 681 break; 682 case ACTIVESYNC: 683 sdp_uuid128_create(&svclass, (void *) async_uuid); 684 break; 685 case DIALUP: 686 sdp_uuid16_create(&svclass, DIALUP_NET_SVCLASS_ID); 687 break; 688 default: 689 sdp_uuid16_create(&svclass, LAN_ACCESS_SVCLASS_ID); 690 break; 691 } 692 693 srch = sdp_list_append(NULL, &svclass); 694 695 attr = SDP_ATTR_PROTO_DESC_LIST; 696 attrs = sdp_list_append(NULL, &attr); 697 698 err = sdp_service_search_attr_req(s, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp); 699 700 sdp_close(s); 701 702 if (err) 703 return 0; 704 705 for(; rsp; rsp = rsp->next) { 706 sdp_record_t *rec = (sdp_record_t *) rsp->data; 707 sdp_list_t *protos; 708 709 if (!sdp_get_access_protos(rec, &protos)) { 710 int ch = sdp_get_proto_port(protos, RFCOMM_UUID); 711 if (ch > 0) { 712 *channel = ch; 713 return 1; 714 } 715 } 716 } 717 718 return 0; 719 } 720