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
50 typedef struct _sdp_cstate_list sdp_cstate_list_t;
51
52 struct _sdp_cstate_list {
53 sdp_cstate_list_t *next;
54 uint32_t timestamp;
55 sdp_buf_t buf;
56 };
57
58 static sdp_cstate_list_t *cstates;
59
60 // FIXME: should probably remove it when it's found
sdp_get_cached_rsp(sdp_cont_state_t * cstate)61 sdp_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
sdp_cstate_alloc_buf(sdp_buf_t * buf)71 static 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
91 struct 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 */
extract_des(uint8_t * buf,int len,sdp_list_t ** svcReqSeq,uint8_t * pDataType,uint8_t expectedType)105 static 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
237 failed:
238 sdp_list_free(pSeq, free);
239 return -1;
240 }
241
sdp_set_cstate_pdu(sdp_buf_t * buf,sdp_cont_state_t * cstate)242 static 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
sdp_cstate_get(uint8_t * buffer,size_t len,sdp_cont_state_t ** cstate)264 static 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 */
sdp_match_uuid(sdp_list_t * search,sdp_list_t * pattern)310 static 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 */
service_search_req(sdp_req_t * req,sdp_buf_t * buf)343 static 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_SYNTAX;
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
528 done:
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 */
extract_attrs(sdp_record_t * rec,sdp_list_t * seq,sdp_buf_t * buf)543 static 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 */
service_attr_req(sdp_req_t * req,sdp_buf_t * buf)618 static 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
746 done:
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 */
service_search_attr_req(sdp_req_t * req,sdp_buf_t * buf)762 static 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
929 done:
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 */
process_request(sdp_req_t * req)944 static 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
1007 send_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
handle_request(int sk,uint8_t * data,int len)1032 void 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