sdpd-request.c revision b5fe14e46c4351fe582f009de2f0b6d6834566e5
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-2009 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 "logging.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_ANY 0xff 90 91/* 92 * Generic data element sequence extractor. Builds 93 * a list whose elements are those found in the 94 * sequence. The data type of elements found in the 95 * sequence is returned in the reference pDataType 96 */ 97static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType) 98{ 99 uint8_t seqType; 100 int scanned, data_size = 0; 101 short numberOfElements = 0; 102 int seqlen = 0; 103 sdp_list_t *pSeq = NULL; 104 uint8_t dataType; 105 int status = 0; 106 const uint8_t *p; 107 int bufsize; 108 109 scanned = sdp_extract_seqtype(buf, len, &seqType, &data_size); 110 111 SDPDBG("Seq type : %d", seqType); 112 if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) { 113 error("Unknown seq type"); 114 return -1; 115 } 116 p = buf + scanned; 117 bufsize = len - scanned; 118 119 SDPDBG("Data size : %d", data_size); 120 121 for (;;) { 122 char *pElem = NULL; 123 int localSeqLength = 0; 124 125 if (bufsize < sizeof(uint8_t)) { 126 SDPDBG("->Unexpected end of buffer"); 127 return -1; 128 } 129 130 dataType = *(uint8_t *)p; 131 SDPDBG("Data type: 0x%02x", dataType); 132 133 if (expectedType == SDP_TYPE_UUID) { 134 if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) { 135 SDPDBG("->Unexpected Data type (expected UUID_ANY)"); 136 return -1; 137 } 138 } else if (expectedType != SDP_TYPE_ANY && dataType != expectedType) { 139 SDPDBG("->Unexpected Data type (expected 0x%02x)", expectedType); 140 return -1; 141 } 142 143 switch (dataType) { 144 case SDP_UINT16: 145 p += sizeof(uint8_t); 146 seqlen += sizeof(uint8_t); 147 bufsize -= sizeof(uint8_t); 148 if (bufsize < sizeof(uint16_t)) { 149 SDPDBG("->Unexpected end of buffer"); 150 return -1; 151 } 152 153 pElem = malloc(sizeof(uint16_t)); 154 bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem); 155 p += sizeof(uint16_t); 156 seqlen += sizeof(uint16_t); 157 bufsize -= sizeof(uint16_t); 158 break; 159 case SDP_UINT32: 160 p += sizeof(uint8_t); 161 seqlen += sizeof(uint8_t); 162 bufsize -= sizeof(uint8_t); 163 if (bufsize < (int)sizeof(uint32_t)) { 164 SDPDBG("->Unexpected end of buffer"); 165 return -1; 166 } 167 168 pElem = malloc(sizeof(uint32_t)); 169 bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem); 170 p += sizeof(uint32_t); 171 seqlen += sizeof(uint32_t); 172 bufsize -= sizeof(uint32_t); 173 break; 174 case SDP_UUID16: 175 case SDP_UUID32: 176 case SDP_UUID128: 177 pElem = malloc(sizeof(uuid_t)); 178 status = sdp_uuid_extract(p, bufsize, (uuid_t *) pElem, &localSeqLength); 179 if (status < 0) { 180 free(pElem); 181 return -1; 182 } 183 seqlen += localSeqLength; 184 p += localSeqLength; 185 bufsize -= localSeqLength; 186 break; 187 default: 188 return -1; 189 } 190 if (status == 0) { 191 pSeq = sdp_list_append(pSeq, pElem); 192 numberOfElements++; 193 SDPDBG("No of elements : %d", numberOfElements); 194 195 if (seqlen == data_size) 196 break; 197 else if (seqlen > data_size || seqlen > len) 198 return -1; 199 } else 200 free(pElem); 201 } 202 *svcReqSeq = pSeq; 203 scanned += seqlen; 204 *pDataType = dataType; 205 return scanned; 206} 207 208static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate) 209{ 210 uint8_t *pdata = buf->data + buf->data_size; 211 int length = 0; 212 213 if (cstate) { 214 SDPDBG("Non null sdp_cstate_t id : 0x%x", cstate->timestamp); 215 *(uint8_t *)pdata = sizeof(sdp_cont_state_t); 216 pdata += sizeof(uint8_t); 217 length += sizeof(uint8_t); 218 memcpy(pdata, cstate, sizeof(sdp_cont_state_t)); 219 length += sizeof(sdp_cont_state_t); 220 } else { 221 // set "null" continuation state 222 *(uint8_t *)pdata = 0; 223 pdata += sizeof(uint8_t); 224 length += sizeof(uint8_t); 225 } 226 buf->data_size += length; 227 return length; 228} 229 230static sdp_cont_state_t *sdp_cstate_get(uint8_t *buffer) 231{ 232 uint8_t *pdata = buffer; 233 uint8_t cStateSize = *(uint8_t *)pdata; 234 235 /* 236 * Check if continuation state exists, if yes attempt 237 * to get response remainder from cache, else send error 238 */ 239 SDPDBG("Continuation State size : %d", cStateSize); 240 241 pdata += sizeof(uint8_t); 242 if (cStateSize != 0) { 243 sdp_cont_state_t *cstate = malloc(sizeof(sdp_cont_state_t)); 244 if (!cstate) 245 return NULL; 246 memcpy(cstate, (sdp_cont_state_t *)pdata, sizeof(sdp_cont_state_t)); 247 SDPDBG("Cstate TS : 0x%x", cstate->timestamp); 248 SDPDBG("Bytes sent : %d", cstate->cStateValue.maxBytesSent); 249 return cstate; 250 } 251 return NULL; 252} 253 254/* 255 * The matching process is defined as "each and every UUID 256 * specified in the "search pattern" must be present in the 257 * "target pattern". Here "search pattern" is the set of UUIDs 258 * specified by the service discovery client and "target pattern" 259 * is the set of UUIDs present in a service record. 260 * 261 * Return 1 if each and every UUID in the search 262 * pattern exists in the target pattern, 0 if the 263 * match succeeds and -1 on error. 264 */ 265static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern) 266{ 267 /* 268 * The target is a sorted list, so we need not look 269 * at all elements to confirm existence of an element 270 * from the search pattern 271 */ 272 int patlen = sdp_list_len(pattern); 273 274 if (patlen < sdp_list_len(search)) 275 return -1; 276 for (; search; search = search->next) { 277 uuid_t *uuid128; 278 void *data = search->data; 279 sdp_list_t *list; 280 if (data == NULL) 281 return -1; 282 283 // create 128-bit form of the search UUID 284 uuid128 = sdp_uuid_to_uuid128((uuid_t *)data); 285 list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp); 286 bt_free(uuid128); 287 if (!list) 288 return 0; 289 } 290 return 1; 291} 292 293/* 294 * Service search request PDU. This method extracts the search pattern 295 * (a sequence of UUIDs) and calls the matching function 296 * to find matching services 297 */ 298static int service_search_req(sdp_req_t *req, sdp_buf_t *buf) 299{ 300 int status = 0, i, plen, mlen, mtu, scanned; 301 sdp_list_t *pattern = NULL; 302 uint16_t expected, actual, rsp_count = 0; 303 uint8_t dtd; 304 sdp_cont_state_t *cstate = NULL; 305 uint8_t *pCacheBuffer = NULL; 306 int handleSize = 0; 307 uint32_t cStateId = 0; 308 short *pTotalRecordCount, *pCurrentRecordCount; 309 uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t); 310 311 scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t), 312 &pattern, &dtd, SDP_TYPE_UUID); 313 314 if (scanned == -1) { 315 status = SDP_INVALID_SYNTAX; 316 goto done; 317 } 318 pdata += scanned; 319 320 plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); 321 mlen = scanned + sizeof(uint16_t) + 1; 322 // ensure we don't read past buffer 323 if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) { 324 status = SDP_INVALID_SYNTAX; 325 goto done; 326 } 327 328 expected = ntohs(bt_get_unaligned((uint16_t *)pdata)); 329 330 SDPDBG("Expected count: %d", expected); 331 SDPDBG("Bytes scanned : %d", scanned); 332 333 pdata += sizeof(uint16_t); 334 335 /* 336 * Check if continuation state exists, if yes attempt 337 * to get rsp remainder from cache, else send error 338 */ 339 cstate = sdp_cstate_get(pdata); 340 341 mtu = req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - SDP_CONT_STATE_SIZE; 342 actual = MIN(expected, mtu >> 2); 343 344 /* make space in the rsp buffer for total and current record counts */ 345 pdata = buf->data; 346 347 /* total service record count = 0 */ 348 pTotalRecordCount = (short *)pdata; 349 bt_put_unaligned(0, (uint16_t *)pdata); 350 pdata += sizeof(uint16_t); 351 buf->data_size += sizeof(uint16_t); 352 353 /* current service record count = 0 */ 354 pCurrentRecordCount = (short *)pdata; 355 bt_put_unaligned(0, (uint16_t *)pdata); 356 pdata += sizeof(uint16_t); 357 buf->data_size += sizeof(uint16_t); 358 359 if (cstate == NULL) { 360 /* for every record in the DB, do a pattern search */ 361 sdp_list_t *list = sdp_get_record_list(); 362 363 handleSize = 0; 364 for (; list && rsp_count < expected; list = list->next) { 365 sdp_record_t *rec = (sdp_record_t *) list->data; 366 367 SDPDBG("Checking svcRec : 0x%x", rec->handle); 368 369 if (sdp_match_uuid(pattern, rec->pattern) > 0 && 370 sdp_check_access(rec->handle, &req->device)) { 371 rsp_count++; 372 bt_put_unaligned(htonl(rec->handle), (uint32_t *)pdata); 373 pdata += sizeof(uint32_t); 374 handleSize += sizeof(uint32_t); 375 } 376 } 377 378 SDPDBG("Match count: %d", rsp_count); 379 380 buf->data_size += handleSize; 381 bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount); 382 bt_put_unaligned(htons(rsp_count), (uint16_t *)pCurrentRecordCount); 383 384 if (rsp_count > actual) { 385 /* cache the rsp and generate a continuation state */ 386 cStateId = sdp_cstate_alloc_buf(buf); 387 /* 388 * subtract handleSize since we now send only 389 * a subset of handles 390 */ 391 buf->data_size -= handleSize; 392 } else { 393 /* NULL continuation state */ 394 sdp_set_cstate_pdu(buf, NULL); 395 } 396 } 397 398 /* under both the conditions below, the rsp buffer is not built yet */ 399 if (cstate || cStateId > 0) { 400 short lastIndex = 0; 401 402 if (cstate) { 403 /* 404 * Get the previous sdp_cont_state_t and obtain 405 * the cached rsp 406 */ 407 sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); 408 if (pCache) { 409 pCacheBuffer = pCache->data; 410 /* get the rsp_count from the cached buffer */ 411 rsp_count = ntohs(bt_get_unaligned((uint16_t *)pCacheBuffer)); 412 413 /* get index of the last sdp_record_t sent */ 414 lastIndex = cstate->cStateValue.lastIndexSent; 415 } else { 416 status = SDP_INVALID_CSTATE; 417 goto done; 418 } 419 } else { 420 pCacheBuffer = buf->data; 421 lastIndex = 0; 422 } 423 424 /* 425 * Set the local buffer pointer to after the 426 * current record count and increment the cached 427 * buffer pointer to beyond the counters 428 */ 429 pdata = (uint8_t *) pCurrentRecordCount + sizeof(uint16_t); 430 431 /* increment beyond the totalCount and the currentCount */ 432 pCacheBuffer += 2 * sizeof(uint16_t); 433 434 if (cstate) { 435 handleSize = 0; 436 for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) { 437 bt_put_unaligned(bt_get_unaligned((uint32_t *)(pCacheBuffer + i * sizeof(uint32_t))), (uint32_t *)pdata); 438 pdata += sizeof(uint32_t); 439 handleSize += sizeof(uint32_t); 440 } 441 } else { 442 handleSize = actual << 2; 443 i = actual; 444 } 445 446 buf->data_size += handleSize; 447 bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount); 448 bt_put_unaligned(htons(i - lastIndex), (uint16_t *)pCurrentRecordCount); 449 450 if (i == rsp_count) { 451 /* set "null" continuationState */ 452 sdp_set_cstate_pdu(buf, NULL); 453 } else { 454 /* 455 * there's more: set lastIndexSent to 456 * the new value and move on 457 */ 458 sdp_cont_state_t newState; 459 460 SDPDBG("Setting non-NULL sdp_cstate_t"); 461 462 if (cstate) 463 memcpy((char *)&newState, cstate, sizeof(sdp_cont_state_t)); 464 else { 465 memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); 466 newState.timestamp = cStateId; 467 } 468 newState.cStateValue.lastIndexSent = i; 469 sdp_set_cstate_pdu(buf, &newState); 470 } 471 } 472 473done: 474 if (cstate) 475 free(cstate); 476 if (pattern) 477 sdp_list_free(pattern, free); 478 479 return status; 480} 481 482/* 483 * Extract attribute identifiers from the request PDU. 484 * Clients could request a subset of attributes (by id) 485 * from a service record, instead of the whole set. The 486 * requested identifiers are present in the PDU form of 487 * the request 488 */ 489static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, uint8_t dtd, sdp_buf_t *buf) 490{ 491 if (!rec) 492 return SDP_INVALID_RECORD_HANDLE; 493 494 if (seq) { 495 SDPDBG("Entries in attr seq : %d", sdp_list_len(seq)); 496 } else { 497 SDPDBG("NULL attribute descriptor"); 498 } 499 500 SDPDBG("AttrDataType : %d", dtd); 501 502 if (seq == NULL) { 503 SDPDBG("Attribute sequence is NULL"); 504 return 0; 505 } 506 if (dtd == SDP_UINT16) 507 for (; seq; seq = seq->next) { 508 uint16_t attr = bt_get_unaligned((uint16_t *)seq->data); 509 sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr); 510 if (a) 511 sdp_append_to_pdu(buf, a); 512 } 513 else if (dtd == SDP_UINT32) { 514 sdp_buf_t pdu; 515 sdp_gen_record_pdu(rec, &pdu); 516 for (; seq; seq = seq->next) { 517 uint32_t range = bt_get_unaligned((uint32_t *)seq->data); 518 uint16_t attr; 519 uint16_t low = (0xffff0000 & range) >> 16; 520 uint16_t high = 0x0000ffff & range; 521 sdp_data_t *data; 522 523 SDPDBG("attr range : 0x%x", range); 524 SDPDBG("Low id : 0x%x", low); 525 SDPDBG("High id : 0x%x", high); 526 527 if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) { 528 /* copy it */ 529 memcpy(buf->data, pdu.data, pdu.data_size); 530 buf->data_size = pdu.data_size; 531 break; 532 } 533 /* (else) sub-range of attributes */ 534 for (attr = low; attr < high; attr++) { 535 data = sdp_data_get(rec, attr); 536 if (data) 537 sdp_append_to_pdu(buf, data); 538 } 539 data = sdp_data_get(rec, high); 540 if (data) 541 sdp_append_to_pdu(buf, data); 542 } 543 free(pdu.data); 544 } else { 545 error("Unexpected data type : 0x%x", dtd); 546 error("Expect uint16_t or uint32_t"); 547 return SDP_INVALID_SYNTAX; 548 } 549 return 0; 550} 551 552/* 553 * A request for the attributes of a service record. 554 * First check if the service record (specified by 555 * service record handle) exists, then call the attribute 556 * streaming function 557 */ 558static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf) 559{ 560 sdp_cont_state_t *cstate = NULL; 561 uint8_t *pResponse = NULL; 562 short cstate_size = 0; 563 sdp_list_t *seq = NULL; 564 uint8_t dtd = 0; 565 int scanned = 0; 566 int max_rsp_size; 567 int status = 0, plen, mlen; 568 uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t); 569 uint32_t handle = ntohl(bt_get_unaligned((uint32_t *)pdata)); 570 571 pdata += sizeof(uint32_t); 572 max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata)); 573 pdata += sizeof(uint16_t); 574 575 /* extract the attribute list */ 576 scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t), 577 &seq, &dtd, SDP_TYPE_ANY); 578 if (scanned == -1) { 579 status = SDP_INVALID_SYNTAX; 580 goto done; 581 } 582 pdata += scanned; 583 584 plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); 585 mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1; 586 // ensure we don't read past buffer 587 if (plen < mlen || plen != mlen + *(uint8_t *)pdata) { 588 status = SDP_INVALID_SYNTAX; 589 goto done; 590 } 591 592 /* 593 * if continuation state exists, attempt 594 * to get rsp remainder from cache, else send error 595 */ 596 cstate = sdp_cstate_get(pdata); 597 598 SDPDBG("SvcRecHandle : 0x%x", handle); 599 SDPDBG("max_rsp_size : %d", max_rsp_size); 600 601 /* 602 * Calculate Attribute size acording to MTU 603 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t)) 604 */ 605 max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) - 606 sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t)); 607 608 /* pull header for AttributeList byte count */ 609 buf->data += sizeof(uint16_t); 610 buf->buf_size -= sizeof(uint16_t); 611 612 if (cstate) { 613 sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); 614 615 SDPDBG("Obtained cached rsp : %p", pCache); 616 617 if (pCache) { 618 short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent); 619 pResponse = pCache->data; 620 memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent); 621 buf->data_size += sent; 622 cstate->cStateValue.maxBytesSent += sent; 623 624 SDPDBG("Response size : %d sending now : %d bytes sent so far : %d", 625 pCache->data_size, sent, cstate->cStateValue.maxBytesSent); 626 if (cstate->cStateValue.maxBytesSent == pCache->data_size) 627 cstate_size = sdp_set_cstate_pdu(buf, NULL); 628 else 629 cstate_size = sdp_set_cstate_pdu(buf, cstate); 630 } else { 631 status = SDP_INVALID_CSTATE; 632 error("NULL cache buffer and non-NULL continuation state"); 633 } 634 } else { 635 sdp_record_t *rec = sdp_record_find(handle); 636 status = extract_attrs(rec, seq, dtd, buf); 637 if (buf->data_size > max_rsp_size) { 638 sdp_cont_state_t newState; 639 640 memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); 641 newState.timestamp = sdp_cstate_alloc_buf(buf); 642 /* 643 * Reset the buffer size to the maximum expected and 644 * set the sdp_cont_state_t 645 */ 646 SDPDBG("Creating continuation state of size : %d", buf->data_size); 647 buf->data_size = max_rsp_size; 648 newState.cStateValue.maxBytesSent = max_rsp_size; 649 cstate_size = sdp_set_cstate_pdu(buf, &newState); 650 } else { 651 if (buf->data_size == 0) 652 sdp_append_to_buf(buf, 0, 0); 653 cstate_size = sdp_set_cstate_pdu(buf, NULL); 654 } 655 } 656 657 // push header 658 buf->data -= sizeof(uint16_t); 659 buf->buf_size += sizeof(uint16_t); 660 661done: 662 if (cstate) 663 free(cstate); 664 if (seq) 665 sdp_list_free(seq, free); 666 if (status) 667 return status; 668 669 /* set attribute list byte count */ 670 bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data); 671 buf->data_size += sizeof(uint16_t); 672 return 0; 673} 674 675/* 676 * combined service search and attribute extraction 677 */ 678static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf) 679{ 680 int status = 0, plen, totscanned; 681 uint8_t *pdata, *pResponse = NULL; 682 int scanned, max, rsp_count = 0; 683 sdp_list_t *pattern = NULL, *seq = NULL, *svcList; 684 sdp_cont_state_t *cstate = NULL; 685 short cstate_size = 0; 686 uint8_t dtd = 0; 687 sdp_buf_t tmpbuf; 688 689 tmpbuf.data = NULL; 690 pdata = req->buf + sizeof(sdp_pdu_hdr_t); 691 scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t), 692 &pattern, &dtd, SDP_TYPE_UUID); 693 if (scanned == -1) { 694 status = SDP_INVALID_SYNTAX; 695 goto done; 696 } 697 totscanned = scanned; 698 699 SDPDBG("Bytes scanned: %d", scanned); 700 701 pdata += scanned; 702 max = ntohs(bt_get_unaligned((uint16_t *)pdata)); 703 pdata += sizeof(uint16_t); 704 705 SDPDBG("Max Attr expected: %d", max); 706 707 /* extract the attribute list */ 708 scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t), 709 &seq, &dtd, SDP_TYPE_ANY); 710 if (scanned == -1) { 711 status = SDP_INVALID_SYNTAX; 712 goto done; 713 } 714 pdata += scanned; 715 totscanned += scanned + sizeof(uint16_t) + 1; 716 717 plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); 718 if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) { 719 status = SDP_INVALID_SYNTAX; 720 goto done; 721 } 722 723 /* 724 * if continuation state exists attempt 725 * to get rsp remainder from cache, else send error 726 */ 727 cstate = sdp_cstate_get(pdata); // continuation information 728 729 svcList = sdp_get_record_list(); 730 731 tmpbuf.data = malloc(USHRT_MAX); 732 tmpbuf.data_size = 0; 733 tmpbuf.buf_size = USHRT_MAX; 734 memset(tmpbuf.data, 0, USHRT_MAX); 735 736 /* 737 * Calculate Attribute size acording to MTU 738 * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t)) 739 */ 740 max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t)); 741 742 /* pull header for AttributeList byte count */ 743 buf->data += sizeof(uint16_t); 744 buf->buf_size -= sizeof(uint16_t); 745 746 if (cstate == NULL) { 747 /* no continuation state -> create new response */ 748 sdp_list_t *p; 749 for (p = svcList; p; p = p->next) { 750 sdp_record_t *rec = (sdp_record_t *) p->data; 751 if (sdp_match_uuid(pattern, rec->pattern) > 0 && 752 sdp_check_access(rec->handle, &req->device)) { 753 rsp_count++; 754 status = extract_attrs(rec, seq, dtd, &tmpbuf); 755 756 SDPDBG("Response count : %d", rsp_count); 757 SDPDBG("Local PDU size : %d", tmpbuf.data_size); 758 if (status) { 759 SDPDBG("Extract attr from record returns err"); 760 break; 761 } 762 if (buf->data_size + tmpbuf.data_size < buf->buf_size) { 763 // to be sure no relocations 764 sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size); 765 tmpbuf.data_size = 0; 766 memset(tmpbuf.data, 0, USHRT_MAX); 767 } else { 768 error("Relocation needed"); 769 break; 770 } 771 SDPDBG("Net PDU size : %d", buf->data_size); 772 } 773 } 774 if (buf->data_size > max) { 775 sdp_cont_state_t newState; 776 777 memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); 778 newState.timestamp = sdp_cstate_alloc_buf(buf); 779 /* 780 * Reset the buffer size to the maximum expected and 781 * set the sdp_cont_state_t 782 */ 783 buf->data_size = max; 784 newState.cStateValue.maxBytesSent = max; 785 cstate_size = sdp_set_cstate_pdu(buf, &newState); 786 } else 787 cstate_size = sdp_set_cstate_pdu(buf, NULL); 788 } else { 789 /* continuation State exists -> get from cache */ 790 sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); 791 if (pCache) { 792 uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent); 793 pResponse = pCache->data; 794 memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent); 795 buf->data_size += sent; 796 cstate->cStateValue.maxBytesSent += sent; 797 if (cstate->cStateValue.maxBytesSent == pCache->data_size) 798 cstate_size = sdp_set_cstate_pdu(buf, NULL); 799 else 800 cstate_size = sdp_set_cstate_pdu(buf, cstate); 801 } else { 802 status = SDP_INVALID_CSTATE; 803 SDPDBG("Non-null continuation state, but null cache buffer"); 804 } 805 } 806 807 if (!rsp_count && !cstate) { 808 // found nothing 809 buf->data_size = 0; 810 sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size); 811 sdp_set_cstate_pdu(buf, NULL); 812 } 813 814 // push header 815 buf->data -= sizeof(uint16_t); 816 buf->buf_size += sizeof(uint16_t); 817 818 if (!status) { 819 /* set attribute list byte count */ 820 bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data); 821 buf->data_size += sizeof(uint16_t); 822 } 823 824done: 825 if (cstate) 826 free(cstate); 827 if (tmpbuf.data) 828 free(tmpbuf.data); 829 if (pattern) 830 sdp_list_free(pattern, free); 831 if (seq) 832 sdp_list_free(seq, free); 833 return status; 834} 835 836/* 837 * Top level request processor. Calls the appropriate processing 838 * function based on request type. Handles service registration 839 * client requests also. 840 */ 841static void process_request(sdp_req_t *req) 842{ 843 sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf; 844 sdp_pdu_hdr_t *rsphdr; 845 sdp_buf_t rsp; 846 uint8_t *buf = malloc(USHRT_MAX); 847 int sent = 0; 848 int status = SDP_INVALID_SYNTAX; 849 850 memset(buf, 0, USHRT_MAX); 851 rsp.data = buf + sizeof(sdp_pdu_hdr_t); 852 rsp.data_size = 0; 853 rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t); 854 rsphdr = (sdp_pdu_hdr_t *)buf; 855 856 if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) { 857 status = SDP_INVALID_PDU_SIZE; 858 goto send_rsp; 859 } 860 switch (reqhdr->pdu_id) { 861 case SDP_SVC_SEARCH_REQ: 862 SDPDBG("Got a svc srch req"); 863 status = service_search_req(req, &rsp); 864 rsphdr->pdu_id = SDP_SVC_SEARCH_RSP; 865 break; 866 case SDP_SVC_ATTR_REQ: 867 SDPDBG("Got a svc attr req"); 868 status = service_attr_req(req, &rsp); 869 rsphdr->pdu_id = SDP_SVC_ATTR_RSP; 870 break; 871 case SDP_SVC_SEARCH_ATTR_REQ: 872 SDPDBG("Got a svc srch attr req"); 873 status = service_search_attr_req(req, &rsp); 874 rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP; 875 break; 876 /* Following requests are allowed only for local connections */ 877 case SDP_SVC_REGISTER_REQ: 878 SDPDBG("Service register request"); 879 if (req->local) { 880 status = service_register_req(req, &rsp); 881 rsphdr->pdu_id = SDP_SVC_REGISTER_RSP; 882 } 883 break; 884 case SDP_SVC_UPDATE_REQ: 885 SDPDBG("Service update request"); 886 if (req->local) { 887 status = service_update_req(req, &rsp); 888 rsphdr->pdu_id = SDP_SVC_UPDATE_RSP; 889 } 890 break; 891 case SDP_SVC_REMOVE_REQ: 892 SDPDBG("Service removal request"); 893 if (req->local) { 894 status = service_remove_req(req, &rsp); 895 rsphdr->pdu_id = SDP_SVC_REMOVE_RSP; 896 } 897 break; 898 default: 899 error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id); 900 status = SDP_INVALID_SYNTAX; 901 break; 902 } 903 904send_rsp: 905 if (status) { 906 rsphdr->pdu_id = SDP_ERROR_RSP; 907 bt_put_unaligned(htons(status), (uint16_t *)rsp.data); 908 rsp.data_size = sizeof(uint16_t); 909 } 910 911 SDPDBG("Sending rsp. status %d", status); 912 913 rsphdr->tid = reqhdr->tid; 914 rsphdr->plen = htons(rsp.data_size); 915 916 /* point back to the real buffer start and set the real rsp length */ 917 rsp.data_size += sizeof(sdp_pdu_hdr_t); 918 rsp.data = buf; 919 920 /* stream the rsp PDU */ 921 sent = send(req->sock, rsp.data, rsp.data_size, 0); 922 923 SDPDBG("Bytes Sent : %d", sent); 924 925 free(rsp.data); 926 free(req->buf); 927} 928 929void handle_request(int sk, uint8_t *data, int len) 930{ 931 struct sockaddr_l2 sa; 932 socklen_t size; 933 sdp_req_t req; 934 935 size = sizeof(sa); 936 if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) 937 return; 938 939 if (sa.l2_family == AF_BLUETOOTH) { 940 struct l2cap_options lo; 941 memset(&lo, 0, sizeof(lo)); 942 size = sizeof(lo); 943 getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size); 944 bacpy(&req.bdaddr, &sa.l2_bdaddr); 945 req.mtu = lo.omtu; 946 req.local = 0; 947 memset(&sa, 0, sizeof(sa)); 948 size = sizeof(sa); 949 getsockname(sk, (struct sockaddr *) &sa, &size); 950 bacpy(&req.device, &sa.l2_bdaddr); 951 } else { 952 bacpy(&req.device, BDADDR_ANY); 953 bacpy(&req.bdaddr, BDADDR_LOCAL); 954 req.mtu = 2048; 955 req.local = 1; 956 } 957 958 req.sock = sk; 959 req.buf = data; 960 req.len = len; 961 962 process_request(&req); 963} 964