sdpd-request.c revision 3094ec7008735c80d35bd255ffc41e7bea2d3a3c
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2001-2002 Nokia Corporation 6 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> 7 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org> 8 * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com> 9 * 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 * 25 */ 26 27#ifdef HAVE_CONFIG_H 28#include <config.h> 29#endif 30 31#include <stdio.h> 32#include <errno.h> 33#include <stdlib.h> 34#include <string.h> 35#include <limits.h> 36#include <sys/socket.h> 37 38#include <bluetooth/bluetooth.h> 39#include <bluetooth/l2cap.h> 40#include <bluetooth/sdp.h> 41#include <bluetooth/sdp_lib.h> 42 43#include <netinet/in.h> 44 45#include "sdpd.h" 46#include "log.h" 47 48#define MIN(x, y) ((x) < (y)) ? (x): (y) 49 50typedef struct _sdp_cstate_list sdp_cstate_list_t; 51 52struct _sdp_cstate_list { 53 sdp_cstate_list_t *next; 54 uint32_t timestamp; 55 sdp_buf_t buf; 56}; 57 58static sdp_cstate_list_t *cstates; 59 60// FIXME: should probably remove it when it's found 61sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate) 62{ 63 sdp_cstate_list_t *p; 64 65 for (p = cstates; p; p = p->next) 66 if (p->timestamp == cstate->timestamp) 67 return &p->buf; 68 return 0; 69} 70 71static uint32_t sdp_cstate_alloc_buf(sdp_buf_t *buf) 72{ 73 sdp_cstate_list_t *cstate = malloc(sizeof(sdp_cstate_list_t)); 74 uint8_t *data = malloc(buf->data_size); 75 76 memcpy(data, buf->data, buf->data_size); 77 memset((char *)cstate, 0, sizeof(sdp_cstate_list_t)); 78 cstate->buf.data = data; 79 cstate->buf.data_size = buf->data_size; 80 cstate->buf.buf_size = buf->data_size; 81 cstate->timestamp = sdp_get_time(); 82 cstate->next = cstates; 83 cstates = cstate; 84 return cstate->timestamp; 85} 86 87/* Additional values for checking datatype (not in spec) */ 88#define SDP_TYPE_UUID 0xfe 89#define SDP_TYPE_ATTRID 0xff 90 91struct attrid { 92 uint8_t dtd; 93 union { 94 uint16_t uint16; 95 uint32_t uint32; 96 }; 97}; 98 99/* 100 * Generic data element sequence extractor. Builds 101 * a list whose elements are those found in the 102 * sequence. The data type of elements found in the 103 * sequence is returned in the reference pDataType 104 */ 105static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType) 106{ 107 uint8_t seqType; 108 int scanned, data_size = 0; 109 short numberOfElements = 0; 110 int seqlen = 0; 111 sdp_list_t *pSeq = NULL; 112 uint8_t dataType; 113 int status = 0; 114 const uint8_t *p; 115 size_t bufsize; 116 117 scanned = sdp_extract_seqtype(buf, len, &seqType, &data_size); 118 119 SDPDBG("Seq type : %d", seqType); 120 if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) { 121 error("Unknown seq type"); 122 return -1; 123 } 124 p = buf + scanned; 125 bufsize = len - scanned; 126 127 SDPDBG("Data size : %d", data_size); 128 129 for (;;) { 130 char *pElem = NULL; 131 int localSeqLength = 0; 132 133 if (bufsize < sizeof(uint8_t)) { 134 SDPDBG("->Unexpected end of buffer"); 135 goto failed; 136 } 137 138 dataType = *p; 139 140 SDPDBG("Data type: 0x%02x", dataType); 141 142 if (expectedType == SDP_TYPE_UUID) { 143 if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) { 144 SDPDBG("->Unexpected Data type (expected UUID_ANY)"); 145 goto failed; 146 } 147 } else if (expectedType == SDP_TYPE_ATTRID && 148 (dataType != SDP_UINT16 && dataType != SDP_UINT32)) { 149 SDPDBG("->Unexpected Data type (expected 0x%02x or 0x%02x)", 150 SDP_UINT16, SDP_UINT32); 151 goto failed; 152 } else if (expectedType != SDP_TYPE_ATTRID && dataType != expectedType) { 153 SDPDBG("->Unexpected Data type (expected 0x%02x)", expectedType); 154 goto failed; 155 } 156 157 switch (dataType) { 158 case SDP_UINT16: 159 p += sizeof(uint8_t); 160 seqlen += sizeof(uint8_t); 161 bufsize -= sizeof(uint8_t); 162 if (bufsize < sizeof(uint16_t)) { 163 SDPDBG("->Unexpected end of buffer"); 164 goto failed; 165 } 166 167 if (expectedType == SDP_TYPE_ATTRID) { 168 struct attrid *aid; 169 aid = malloc(sizeof(struct attrid)); 170 aid->dtd = dataType; 171 bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)&aid->uint16); 172 pElem = (char *) aid; 173 } else { 174 pElem = malloc(sizeof(uint16_t)); 175 bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem); 176 } 177 p += sizeof(uint16_t); 178 seqlen += sizeof(uint16_t); 179 bufsize -= sizeof(uint16_t); 180 break; 181 case SDP_UINT32: 182 p += sizeof(uint8_t); 183 seqlen += sizeof(uint8_t); 184 bufsize -= sizeof(uint8_t); 185 if (bufsize < (int)sizeof(uint32_t)) { 186 SDPDBG("->Unexpected end of buffer"); 187 goto failed; 188 } 189 190 if (expectedType == SDP_TYPE_ATTRID) { 191 struct attrid *aid; 192 aid = malloc(sizeof(struct attrid)); 193 aid->dtd = dataType; 194 bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)&aid->uint32); 195 pElem = (char *) aid; 196 } else { 197 pElem = malloc(sizeof(uint32_t)); 198 bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem); 199 } 200 p += sizeof(uint32_t); 201 seqlen += sizeof(uint32_t); 202 bufsize -= sizeof(uint32_t); 203 break; 204 case SDP_UUID16: 205 case SDP_UUID32: 206 case SDP_UUID128: 207 pElem = malloc(sizeof(uuid_t)); 208 status = sdp_uuid_extract(p, bufsize, (uuid_t *) pElem, &localSeqLength); 209 if (status < 0) { 210 free(pElem); 211 goto failed; 212 } 213 seqlen += localSeqLength; 214 p += localSeqLength; 215 bufsize -= localSeqLength; 216 break; 217 default: 218 return -1; 219 } 220 if (status == 0) { 221 pSeq = sdp_list_append(pSeq, pElem); 222 numberOfElements++; 223 SDPDBG("No of elements : %d", numberOfElements); 224 225 if (seqlen == data_size) 226 break; 227 else if (seqlen > data_size || seqlen > len) 228 goto failed; 229 } else 230 free(pElem); 231 } 232 *svcReqSeq = pSeq; 233 scanned += seqlen; 234 *pDataType = dataType; 235 return scanned; 236 237failed: 238 sdp_list_free(pSeq, free); 239 return -1; 240} 241 242static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate) 243{ 244 uint8_t *pdata = buf->data + buf->data_size; 245 int length = 0; 246 247 if (cstate) { 248 SDPDBG("Non null sdp_cstate_t id : 0x%x", cstate->timestamp); 249 *(uint8_t *)pdata = sizeof(sdp_cont_state_t); 250 pdata += sizeof(uint8_t); 251 length += sizeof(uint8_t); 252 memcpy(pdata, cstate, sizeof(sdp_cont_state_t)); 253 length += sizeof(sdp_cont_state_t); 254 } else { 255 // set "null" continuation state 256 *(uint8_t *)pdata = 0; 257 pdata += sizeof(uint8_t); 258 length += sizeof(uint8_t); 259 } 260 buf->data_size += length; 261 return length; 262} 263 264static int sdp_cstate_get(uint8_t *buffer, size_t len, 265 sdp_cont_state_t **cstate) 266{ 267 uint8_t cStateSize = *buffer; 268 269 SDPDBG("Continuation State size : %d", cStateSize); 270 271 if (cStateSize == 0) { 272 *cstate = NULL; 273 return 0; 274 } 275 276 buffer++; 277 len--; 278 279 if (len < sizeof(sdp_cont_state_t)) 280 return -EINVAL; 281 282 /* 283 * Check if continuation state exists, if yes attempt 284 * to get response remainder from cache, else send error 285 */ 286 287 *cstate = malloc(sizeof(sdp_cont_state_t)); 288 if (!(*cstate)) 289 return -ENOMEM; 290 291 memcpy(*cstate, buffer, sizeof(sdp_cont_state_t)); 292 293 SDPDBG("Cstate TS : 0x%x", (*cstate)->timestamp); 294 SDPDBG("Bytes sent : %d", (*cstate)->cStateValue.maxBytesSent); 295 296 return 0; 297} 298 299/* 300 * The matching process is defined as "each and every UUID 301 * specified in the "search pattern" must be present in the 302 * "target pattern". Here "search pattern" is the set of UUIDs 303 * specified by the service discovery client and "target pattern" 304 * is the set of UUIDs present in a service record. 305 * 306 * Return 1 if each and every UUID in the search 307 * pattern exists in the target pattern, 0 if the 308 * match succeeds and -1 on error. 309 */ 310static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern) 311{ 312 /* 313 * The target is a sorted list, so we need not look 314 * at all elements to confirm existence of an element 315 * from the search pattern 316 */ 317 int patlen = sdp_list_len(pattern); 318 319 if (patlen < sdp_list_len(search)) 320 return -1; 321 for (; search; search = search->next) { 322 uuid_t *uuid128; 323 void *data = search->data; 324 sdp_list_t *list; 325 if (data == NULL) 326 return -1; 327 328 // create 128-bit form of the search UUID 329 uuid128 = sdp_uuid_to_uuid128((uuid_t *)data); 330 list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp); 331 bt_free(uuid128); 332 if (!list) 333 return 0; 334 } 335 return 1; 336} 337 338/* 339 * Service search request PDU. This method extracts the search pattern 340 * (a sequence of UUIDs) and calls the matching function 341 * to find matching services 342 */ 343static int service_search_req(sdp_req_t *req, sdp_buf_t *buf) 344{ 345 int status = 0, i, plen, mlen, mtu, scanned; 346 sdp_list_t *pattern = NULL; 347 uint16_t expected, actual, rsp_count = 0; 348 uint8_t dtd; 349 sdp_cont_state_t *cstate = NULL; 350 uint8_t *pCacheBuffer = NULL; 351 int handleSize = 0; 352 uint32_t cStateId = 0; 353 short *pTotalRecordCount, *pCurrentRecordCount; 354 uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t); 355 size_t data_left = req->len - sizeof(sdp_pdu_hdr_t); 356 357 scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID); 358 359 if (scanned == -1) { 360 status = SDP_INVALID_SYNTAX; 361 goto done; 362 } 363 pdata += scanned; 364 data_left -= scanned; 365 366 plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); 367 mlen = scanned + sizeof(uint16_t) + 1; 368 // ensure we don't read past buffer 369 if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) { 370 status = SDP_INVALID_PDU_SIZE; 371 goto done; 372 } 373 374 if (data_left < sizeof(uint16_t)) { 375 status = SDP_INVALID_SYNTAX; 376 goto done; 377 } 378 379 expected = ntohs(bt_get_unaligned((uint16_t *)pdata)); 380 381 SDPDBG("Expected count: %d", expected); 382 SDPDBG("Bytes scanned : %d", scanned); 383 384 pdata += sizeof(uint16_t); 385 data_left -= sizeof(uint16_t); 386 387 /* 388 * Check if continuation state exists, if yes attempt 389 * to get rsp remainder from cache, else send error 390 */ 391 if (sdp_cstate_get(pdata, data_left, &cstate) < 0) { 392 status = SDP_INVALID_SYNTAX; 393 goto done; 394 } 395 396 mtu = req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - SDP_CONT_STATE_SIZE; 397 actual = MIN(expected, mtu >> 2); 398 399 /* make space in the rsp buffer for total and current record counts */ 400 pdata = buf->data; 401 402 /* total service record count = 0 */ 403 pTotalRecordCount = (short *)pdata; 404 bt_put_unaligned(0, (uint16_t *)pdata); 405 pdata += sizeof(uint16_t); 406 buf->data_size += sizeof(uint16_t); 407 408 /* current service record count = 0 */ 409 pCurrentRecordCount = (short *)pdata; 410 bt_put_unaligned(0, (uint16_t *)pdata); 411 pdata += sizeof(uint16_t); 412 buf->data_size += sizeof(uint16_t); 413 414 if (cstate == NULL) { 415 /* for every record in the DB, do a pattern search */ 416 sdp_list_t *list = sdp_get_record_list(); 417 418 handleSize = 0; 419 for (; list && rsp_count < expected; list = list->next) { 420 sdp_record_t *rec = (sdp_record_t *) list->data; 421 422 SDPDBG("Checking svcRec : 0x%x", rec->handle); 423 424 if (sdp_match_uuid(pattern, rec->pattern) > 0 && 425 sdp_check_access(rec->handle, &req->device)) { 426 rsp_count++; 427 bt_put_unaligned(htonl(rec->handle), (uint32_t *)pdata); 428 pdata += sizeof(uint32_t); 429 handleSize += sizeof(uint32_t); 430 } 431 } 432 433 SDPDBG("Match count: %d", rsp_count); 434 435 buf->data_size += handleSize; 436 bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount); 437 bt_put_unaligned(htons(rsp_count), (uint16_t *)pCurrentRecordCount); 438 439 if (rsp_count > actual) { 440 /* cache the rsp and generate a continuation state */ 441 cStateId = sdp_cstate_alloc_buf(buf); 442 /* 443 * subtract handleSize since we now send only 444 * a subset of handles 445 */ 446 buf->data_size -= handleSize; 447 } else { 448 /* NULL continuation state */ 449 sdp_set_cstate_pdu(buf, NULL); 450 } 451 } 452 453 /* under both the conditions below, the rsp buffer is not built yet */ 454 if (cstate || cStateId > 0) { 455 short lastIndex = 0; 456 457 if (cstate) { 458 /* 459 * Get the previous sdp_cont_state_t and obtain 460 * the cached rsp 461 */ 462 sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); 463 if (pCache) { 464 pCacheBuffer = pCache->data; 465 /* get the rsp_count from the cached buffer */ 466 rsp_count = ntohs(bt_get_unaligned((uint16_t *)pCacheBuffer)); 467 468 /* get index of the last sdp_record_t sent */ 469 lastIndex = cstate->cStateValue.lastIndexSent; 470 } else { 471 status = SDP_INVALID_CSTATE; 472 goto done; 473 } 474 } else { 475 pCacheBuffer = buf->data; 476 lastIndex = 0; 477 } 478 479 /* 480 * Set the local buffer pointer to after the 481 * current record count and increment the cached 482 * buffer pointer to beyond the counters 483 */ 484 pdata = (uint8_t *) pCurrentRecordCount + sizeof(uint16_t); 485 486 /* increment beyond the totalCount and the currentCount */ 487 pCacheBuffer += 2 * sizeof(uint16_t); 488 489 if (cstate) { 490 handleSize = 0; 491 for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) { 492 bt_put_unaligned(bt_get_unaligned((uint32_t *)(pCacheBuffer + i * sizeof(uint32_t))), (uint32_t *)pdata); 493 pdata += sizeof(uint32_t); 494 handleSize += sizeof(uint32_t); 495 } 496 } else { 497 handleSize = actual << 2; 498 i = actual; 499 } 500 501 buf->data_size += handleSize; 502 bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount); 503 bt_put_unaligned(htons(i - lastIndex), (uint16_t *)pCurrentRecordCount); 504 505 if (i == rsp_count) { 506 /* set "null" continuationState */ 507 sdp_set_cstate_pdu(buf, NULL); 508 } else { 509 /* 510 * there's more: set lastIndexSent to 511 * the new value and move on 512 */ 513 sdp_cont_state_t newState; 514 515 SDPDBG("Setting non-NULL sdp_cstate_t"); 516 517 if (cstate) 518 memcpy(&newState, cstate, sizeof(sdp_cont_state_t)); 519 else { 520 memset(&newState, 0, sizeof(sdp_cont_state_t)); 521 newState.timestamp = cStateId; 522 } 523 newState.cStateValue.lastIndexSent = i; 524 sdp_set_cstate_pdu(buf, &newState); 525 } 526 } 527 528done: 529 free(cstate); 530 if (pattern) 531 sdp_list_free(pattern, free); 532 533 return status; 534} 535 536/* 537 * Extract attribute identifiers from the request PDU. 538 * Clients could request a subset of attributes (by id) 539 * from a service record, instead of the whole set. The 540 * requested identifiers are present in the PDU form of 541 * the request 542 */ 543static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, sdp_buf_t *buf) 544{ 545 sdp_buf_t pdu; 546 547 if (!rec) 548 return SDP_INVALID_RECORD_HANDLE; 549 550 if (seq) { 551 SDPDBG("Entries in attr seq : %d", sdp_list_len(seq)); 552 } else { 553 SDPDBG("NULL attribute descriptor"); 554 } 555 556 if (seq == NULL) { 557 SDPDBG("Attribute sequence is NULL"); 558 return 0; 559 } 560 561 sdp_gen_record_pdu(rec, &pdu); 562 563 for (; seq; seq = seq->next) { 564 struct attrid *aid = seq->data; 565 566 SDPDBG("AttrDataType : %d", aid->dtd); 567 568 if (aid->dtd == SDP_UINT16) { 569 uint16_t attr = bt_get_unaligned((uint16_t *)&aid->uint16); 570 sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr); 571 if (a) 572 sdp_append_to_pdu(buf, a); 573 } else if (aid->dtd == SDP_UINT32) { 574 uint32_t range = bt_get_unaligned((uint32_t *)&aid->uint32); 575 uint16_t attr; 576 uint16_t low = (0xffff0000 & range) >> 16; 577 uint16_t high = 0x0000ffff & range; 578 sdp_data_t *data; 579 580 SDPDBG("attr range : 0x%x", range); 581 SDPDBG("Low id : 0x%x", low); 582 SDPDBG("High id : 0x%x", high); 583 584 if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) { 585 /* copy it */ 586 memcpy(buf->data, pdu.data, pdu.data_size); 587 buf->data_size = pdu.data_size; 588 break; 589 } 590 /* (else) sub-range of attributes */ 591 for (attr = low; attr < high; attr++) { 592 data = sdp_data_get(rec, attr); 593 if (data) 594 sdp_append_to_pdu(buf, data); 595 } 596 data = sdp_data_get(rec, high); 597 if (data) 598 sdp_append_to_pdu(buf, data); 599 } else { 600 error("Unexpected data type : 0x%x", aid->dtd); 601 error("Expect uint16_t or uint32_t"); 602 free(pdu.data); 603 return SDP_INVALID_SYNTAX; 604 } 605 } 606 607 free(pdu.data); 608 609 return 0; 610} 611 612/* 613 * A request for the attributes of a service record. 614 * First check if the service record (specified by 615 * service record handle) exists, then call the attribute 616 * streaming function 617 */ 618static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf) 619{ 620 sdp_cont_state_t *cstate = NULL; 621 uint8_t *pResponse = NULL; 622 short cstate_size = 0; 623 sdp_list_t *seq = NULL; 624 uint8_t dtd = 0; 625 int scanned = 0; 626 unsigned int max_rsp_size; 627 int status = 0, plen, mlen; 628 uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t); 629 size_t data_left = req->len - sizeof(sdp_pdu_hdr_t); 630 uint32_t handle; 631 632 if (data_left < sizeof(uint32_t)) { 633 status = SDP_INVALID_SYNTAX; 634 goto done; 635 } 636 637 handle = ntohl(bt_get_unaligned((uint32_t *)pdata)); 638 639 pdata += sizeof(uint32_t); 640 data_left -= sizeof(uint32_t); 641 642 if (data_left < sizeof(uint16_t)) { 643 status = SDP_INVALID_SYNTAX; 644 goto done; 645 } 646 647 max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata)); 648 649 pdata += sizeof(uint16_t); 650 data_left -= sizeof(uint16_t); 651 652 if (data_left < sizeof(sdp_pdu_hdr_t)) { 653 status = SDP_INVALID_SYNTAX; 654 goto done; 655 } 656 657 /* extract the attribute list */ 658 scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID); 659 if (scanned == -1) { 660 status = SDP_INVALID_SYNTAX; 661 goto done; 662 } 663 pdata += scanned; 664 data_left -= scanned; 665 666 plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); 667 mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1; 668 // ensure we don't read past buffer 669 if (plen < mlen || plen != mlen + *(uint8_t *)pdata) { 670 status = SDP_INVALID_SYNTAX; 671 goto done; 672 } 673 674 /* 675 * if continuation state exists, attempt 676 * to get rsp remainder from cache, else send error 677 */ 678 if (sdp_cstate_get(pdata, data_left, &cstate) < 0) { 679 status = SDP_INVALID_SYNTAX; 680 goto done; 681 } 682 683 SDPDBG("SvcRecHandle : 0x%x", handle); 684 SDPDBG("max_rsp_size : %d", max_rsp_size); 685 686 /* 687 * Calculate Attribute size acording to MTU 688 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t)) 689 */ 690 max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) - 691 sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t)); 692 693 /* pull header for AttributeList byte count */ 694 buf->data += sizeof(uint16_t); 695 buf->buf_size -= sizeof(uint16_t); 696 697 if (cstate) { 698 sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); 699 700 SDPDBG("Obtained cached rsp : %p", pCache); 701 702 if (pCache) { 703 short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent); 704 pResponse = pCache->data; 705 memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent); 706 buf->data_size += sent; 707 cstate->cStateValue.maxBytesSent += sent; 708 709 SDPDBG("Response size : %d sending now : %d bytes sent so far : %d", 710 pCache->data_size, sent, cstate->cStateValue.maxBytesSent); 711 if (cstate->cStateValue.maxBytesSent == pCache->data_size) 712 cstate_size = sdp_set_cstate_pdu(buf, NULL); 713 else 714 cstate_size = sdp_set_cstate_pdu(buf, cstate); 715 } else { 716 status = SDP_INVALID_CSTATE; 717 error("NULL cache buffer and non-NULL continuation state"); 718 } 719 } else { 720 sdp_record_t *rec = sdp_record_find(handle); 721 status = extract_attrs(rec, seq, buf); 722 if (buf->data_size > max_rsp_size) { 723 sdp_cont_state_t newState; 724 725 memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); 726 newState.timestamp = sdp_cstate_alloc_buf(buf); 727 /* 728 * Reset the buffer size to the maximum expected and 729 * set the sdp_cont_state_t 730 */ 731 SDPDBG("Creating continuation state of size : %d", buf->data_size); 732 buf->data_size = max_rsp_size; 733 newState.cStateValue.maxBytesSent = max_rsp_size; 734 cstate_size = sdp_set_cstate_pdu(buf, &newState); 735 } else { 736 if (buf->data_size == 0) 737 sdp_append_to_buf(buf, 0, 0); 738 cstate_size = sdp_set_cstate_pdu(buf, NULL); 739 } 740 } 741 742 // push header 743 buf->data -= sizeof(uint16_t); 744 buf->buf_size += sizeof(uint16_t); 745 746done: 747 free(cstate); 748 if (seq) 749 sdp_list_free(seq, free); 750 if (status) 751 return status; 752 753 /* set attribute list byte count */ 754 bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data); 755 buf->data_size += sizeof(uint16_t); 756 return 0; 757} 758 759/* 760 * combined service search and attribute extraction 761 */ 762static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf) 763{ 764 int status = 0, plen, totscanned; 765 uint8_t *pdata, *pResponse = NULL; 766 unsigned int max; 767 int scanned, rsp_count = 0; 768 sdp_list_t *pattern = NULL, *seq = NULL, *svcList; 769 sdp_cont_state_t *cstate = NULL; 770 short cstate_size = 0; 771 uint8_t dtd = 0; 772 sdp_buf_t tmpbuf; 773 size_t data_left = req->len; 774 775 tmpbuf.data = NULL; 776 pdata = req->buf + sizeof(sdp_pdu_hdr_t); 777 data_left = req->len - sizeof(sdp_pdu_hdr_t); 778 scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID); 779 if (scanned == -1) { 780 status = SDP_INVALID_SYNTAX; 781 goto done; 782 } 783 totscanned = scanned; 784 785 SDPDBG("Bytes scanned: %d", scanned); 786 787 pdata += scanned; 788 data_left -= scanned; 789 790 if (data_left < sizeof(uint16_t)) { 791 status = SDP_INVALID_SYNTAX; 792 goto done; 793 } 794 795 max = ntohs(bt_get_unaligned((uint16_t *)pdata)); 796 797 pdata += sizeof(uint16_t); 798 data_left -= sizeof(uint16_t); 799 800 SDPDBG("Max Attr expected: %d", max); 801 802 if (data_left < sizeof(sdp_pdu_hdr_t)) { 803 status = SDP_INVALID_SYNTAX; 804 goto done; 805 } 806 807 /* extract the attribute list */ 808 scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID); 809 if (scanned == -1) { 810 status = SDP_INVALID_SYNTAX; 811 goto done; 812 } 813 814 pdata += scanned; 815 data_left -= scanned; 816 817 totscanned += scanned + sizeof(uint16_t) + 1; 818 819 plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); 820 if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) { 821 status = SDP_INVALID_SYNTAX; 822 goto done; 823 } 824 825 /* 826 * if continuation state exists attempt 827 * to get rsp remainder from cache, else send error 828 */ 829 if (sdp_cstate_get(pdata, data_left, &cstate) < 0) { 830 status = SDP_INVALID_SYNTAX; 831 goto done; 832 } 833 834 svcList = sdp_get_record_list(); 835 836 tmpbuf.data = malloc(USHRT_MAX); 837 tmpbuf.data_size = 0; 838 tmpbuf.buf_size = USHRT_MAX; 839 memset(tmpbuf.data, 0, USHRT_MAX); 840 841 /* 842 * Calculate Attribute size acording to MTU 843 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t)) 844 */ 845 max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t)); 846 847 /* pull header for AttributeList byte count */ 848 buf->data += sizeof(uint16_t); 849 buf->buf_size -= sizeof(uint16_t); 850 851 if (cstate == NULL) { 852 /* no continuation state -> create new response */ 853 sdp_list_t *p; 854 for (p = svcList; p; p = p->next) { 855 sdp_record_t *rec = (sdp_record_t *) p->data; 856 if (sdp_match_uuid(pattern, rec->pattern) > 0 && 857 sdp_check_access(rec->handle, &req->device)) { 858 rsp_count++; 859 status = extract_attrs(rec, seq, &tmpbuf); 860 861 SDPDBG("Response count : %d", rsp_count); 862 SDPDBG("Local PDU size : %d", tmpbuf.data_size); 863 if (status) { 864 SDPDBG("Extract attr from record returns err"); 865 break; 866 } 867 if (buf->data_size + tmpbuf.data_size < buf->buf_size) { 868 // to be sure no relocations 869 sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size); 870 tmpbuf.data_size = 0; 871 memset(tmpbuf.data, 0, USHRT_MAX); 872 } else { 873 error("Relocation needed"); 874 break; 875 } 876 SDPDBG("Net PDU size : %d", buf->data_size); 877 } 878 } 879 if (buf->data_size > max) { 880 sdp_cont_state_t newState; 881 882 memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); 883 newState.timestamp = sdp_cstate_alloc_buf(buf); 884 /* 885 * Reset the buffer size to the maximum expected and 886 * set the sdp_cont_state_t 887 */ 888 buf->data_size = max; 889 newState.cStateValue.maxBytesSent = max; 890 cstate_size = sdp_set_cstate_pdu(buf, &newState); 891 } else 892 cstate_size = sdp_set_cstate_pdu(buf, NULL); 893 } else { 894 /* continuation State exists -> get from cache */ 895 sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); 896 if (pCache) { 897 uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent); 898 pResponse = pCache->data; 899 memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent); 900 buf->data_size += sent; 901 cstate->cStateValue.maxBytesSent += sent; 902 if (cstate->cStateValue.maxBytesSent == pCache->data_size) 903 cstate_size = sdp_set_cstate_pdu(buf, NULL); 904 else 905 cstate_size = sdp_set_cstate_pdu(buf, cstate); 906 } else { 907 status = SDP_INVALID_CSTATE; 908 SDPDBG("Non-null continuation state, but null cache buffer"); 909 } 910 } 911 912 if (!rsp_count && !cstate) { 913 // found nothing 914 buf->data_size = 0; 915 sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size); 916 sdp_set_cstate_pdu(buf, NULL); 917 } 918 919 // push header 920 buf->data -= sizeof(uint16_t); 921 buf->buf_size += sizeof(uint16_t); 922 923 if (!status) { 924 /* set attribute list byte count */ 925 bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data); 926 buf->data_size += sizeof(uint16_t); 927 } 928 929done: 930 free(cstate); 931 free(tmpbuf.data); 932 if (pattern) 933 sdp_list_free(pattern, free); 934 if (seq) 935 sdp_list_free(seq, free); 936 return status; 937} 938 939/* 940 * Top level request processor. Calls the appropriate processing 941 * function based on request type. Handles service registration 942 * client requests also. 943 */ 944static void process_request(sdp_req_t *req) 945{ 946 sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf; 947 sdp_pdu_hdr_t *rsphdr; 948 sdp_buf_t rsp; 949 uint8_t *buf = malloc(USHRT_MAX); 950 int sent = 0; 951 int status = SDP_INVALID_SYNTAX; 952 953 memset(buf, 0, USHRT_MAX); 954 rsp.data = buf + sizeof(sdp_pdu_hdr_t); 955 rsp.data_size = 0; 956 rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t); 957 rsphdr = (sdp_pdu_hdr_t *)buf; 958 959 if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) { 960 status = SDP_INVALID_PDU_SIZE; 961 goto send_rsp; 962 } 963 switch (reqhdr->pdu_id) { 964 case SDP_SVC_SEARCH_REQ: 965 SDPDBG("Got a svc srch req"); 966 status = service_search_req(req, &rsp); 967 rsphdr->pdu_id = SDP_SVC_SEARCH_RSP; 968 break; 969 case SDP_SVC_ATTR_REQ: 970 SDPDBG("Got a svc attr req"); 971 status = service_attr_req(req, &rsp); 972 rsphdr->pdu_id = SDP_SVC_ATTR_RSP; 973 break; 974 case SDP_SVC_SEARCH_ATTR_REQ: 975 SDPDBG("Got a svc srch attr req"); 976 status = service_search_attr_req(req, &rsp); 977 rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP; 978 break; 979 /* Following requests are allowed only for local connections */ 980 case SDP_SVC_REGISTER_REQ: 981 SDPDBG("Service register request"); 982 if (req->local) { 983 status = service_register_req(req, &rsp); 984 rsphdr->pdu_id = SDP_SVC_REGISTER_RSP; 985 } 986 break; 987 case SDP_SVC_UPDATE_REQ: 988 SDPDBG("Service update request"); 989 if (req->local) { 990 status = service_update_req(req, &rsp); 991 rsphdr->pdu_id = SDP_SVC_UPDATE_RSP; 992 } 993 break; 994 case SDP_SVC_REMOVE_REQ: 995 SDPDBG("Service removal request"); 996 if (req->local) { 997 status = service_remove_req(req, &rsp); 998 rsphdr->pdu_id = SDP_SVC_REMOVE_RSP; 999 } 1000 break; 1001 default: 1002 error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id); 1003 status = SDP_INVALID_SYNTAX; 1004 break; 1005 } 1006 1007send_rsp: 1008 if (status) { 1009 rsphdr->pdu_id = SDP_ERROR_RSP; 1010 bt_put_unaligned(htons(status), (uint16_t *)rsp.data); 1011 rsp.data_size = sizeof(uint16_t); 1012 } 1013 1014 SDPDBG("Sending rsp. status %d", status); 1015 1016 rsphdr->tid = reqhdr->tid; 1017 rsphdr->plen = htons(rsp.data_size); 1018 1019 /* point back to the real buffer start and set the real rsp length */ 1020 rsp.data_size += sizeof(sdp_pdu_hdr_t); 1021 rsp.data = buf; 1022 1023 /* stream the rsp PDU */ 1024 sent = send(req->sock, rsp.data, rsp.data_size, 0); 1025 1026 SDPDBG("Bytes Sent : %d", sent); 1027 1028 free(rsp.data); 1029 free(req->buf); 1030} 1031 1032void handle_request(int sk, uint8_t *data, int len) 1033{ 1034 struct sockaddr_l2 sa; 1035 socklen_t size; 1036 sdp_req_t req; 1037 1038 size = sizeof(sa); 1039 if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) { 1040 error("getpeername: %s", strerror(errno)); 1041 return; 1042 } 1043 1044 if (sa.l2_family == AF_BLUETOOTH) { 1045 struct l2cap_options lo; 1046 1047 memset(&lo, 0, sizeof(lo)); 1048 size = sizeof(lo); 1049 1050 if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size) < 0) { 1051 error("getsockopt: %s", strerror(errno)); 1052 return; 1053 } 1054 1055 bacpy(&req.bdaddr, &sa.l2_bdaddr); 1056 req.mtu = lo.omtu; 1057 req.local = 0; 1058 memset(&sa, 0, sizeof(sa)); 1059 size = sizeof(sa); 1060 1061 if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) { 1062 error("getsockname: %s", strerror(errno)); 1063 return; 1064 } 1065 1066 bacpy(&req.device, &sa.l2_bdaddr); 1067 } else { 1068 bacpy(&req.device, BDADDR_ANY); 1069 bacpy(&req.bdaddr, BDADDR_LOCAL); 1070 req.mtu = 2048; 1071 req.local = 1; 1072 } 1073 1074 req.sock = sk; 1075 req.buf = data; 1076 req.len = len; 1077 1078 process_request(&req); 1079} 1080