3
* BlueZ - Bluetooth protocol stack for Linux
5
* Copyright (C) 2001-2002 Nokia Corporation
6
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
7
* Copyright (C) 2002-2008 Marcel Holtmann <marcel@holtmann.org>
8
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
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.
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.
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
36
#include <sys/socket.h>
38
#include <bluetooth/bluetooth.h>
39
#include <bluetooth/l2cap.h>
40
#include <bluetooth/sdp.h>
41
#include <bluetooth/sdp_lib.h>
43
#include <netinet/in.h>
48
#define MIN(x, y) ((x) < (y)) ? (x): (y)
50
typedef struct _sdp_cstate_list sdp_cstate_list_t;
52
struct _sdp_cstate_list {
53
sdp_cstate_list_t *next;
58
static sdp_cstate_list_t *cstates;
60
// FIXME: should probably remove it when it's found
61
sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate)
65
for (p = cstates; p; p = p->next)
66
if (p->timestamp == cstate->timestamp)
71
static uint32_t sdp_cstate_alloc_buf(sdp_buf_t *buf)
73
sdp_cstate_list_t *cstate = malloc(sizeof(sdp_cstate_list_t));
74
uint8_t *data = malloc(buf->data_size);
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;
84
return cstate->timestamp;
87
/* Additional values for checking datatype (not in spec) */
88
#define SDP_TYPE_UUID 0xfe
89
#define SDP_TYPE_ANY 0xff
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
97
static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType)
100
int scanned, data_size = 0;
101
short numberOfElements = 0;
103
sdp_list_t *pSeq = NULL;
109
scanned = sdp_extract_seqtype(buf, len, &seqType, &data_size);
111
SDPDBG("Seq type : %d", seqType);
112
if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) {
113
error("Unknown seq type");
117
bufsize = len - scanned;
119
SDPDBG("Data size : %d", data_size);
123
int localSeqLength = 0;
125
if (bufsize < sizeof(uint8_t)) {
126
SDPDBG("->Unexpected end of buffer");
130
dataType = *(uint8_t *)p;
131
SDPDBG("Data type: 0x%02x", dataType);
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)");
138
} else if (expectedType != SDP_TYPE_ANY && dataType != expectedType) {
139
SDPDBG("->Unexpected Data type (expected 0x%02x)", expectedType);
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");
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);
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");
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);
177
pElem = malloc(sizeof(uuid_t));
178
status = sdp_uuid_extract(p, bufsize, (uuid_t *) pElem, &localSeqLength);
180
seqlen += localSeqLength;
182
bufsize -= localSeqLength;
189
pSeq = sdp_list_append(pSeq, pElem);
191
SDPDBG("No of elements : %d", numberOfElements);
193
if (seqlen == data_size)
195
else if (seqlen > data_size || seqlen > len)
202
*pDataType = dataType;
206
static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate)
208
uint8_t *pdata = buf->data + buf->data_size;
212
SDPDBG("Non null sdp_cstate_t id : 0x%lx", cstate->timestamp);
213
*(uint8_t *)pdata = sizeof(sdp_cont_state_t);
214
pdata += sizeof(uint8_t);
215
length += sizeof(uint8_t);
216
memcpy(pdata, cstate, sizeof(sdp_cont_state_t));
217
length += sizeof(sdp_cont_state_t);
219
// set "null" continuation state
220
*(uint8_t *)pdata = 0;
221
pdata += sizeof(uint8_t);
222
length += sizeof(uint8_t);
224
buf->data_size += length;
228
static sdp_cont_state_t *sdp_cstate_get(uint8_t *buffer)
230
uint8_t *pdata = buffer;
231
uint8_t cStateSize = *(uint8_t *)pdata;
234
* Check if continuation state exists, if yes attempt
235
* to get response remainder from cache, else send error
237
SDPDBG("Continuation State size : %d", cStateSize);
239
pdata += sizeof(uint8_t);
240
if (cStateSize != 0) {
241
sdp_cont_state_t *cstate = malloc(sizeof(sdp_cont_state_t));
244
memcpy(cstate, (sdp_cont_state_t *)pdata, sizeof(sdp_cont_state_t));
245
SDPDBG("Cstate TS : 0x%lx", cstate->timestamp);
246
SDPDBG("Bytes sent : %d", cstate->cStateValue.maxBytesSent);
253
* The matching process is defined as "each and every UUID
254
* specified in the "search pattern" must be present in the
255
* "target pattern". Here "search pattern" is the set of UUIDs
256
* specified by the service discovery client and "target pattern"
257
* is the set of UUIDs present in a service record.
259
* Return 1 if each and every UUID in the search
260
* pattern exists in the target pattern, 0 if the
261
* match succeeds and -1 on error.
263
static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern)
266
* The target is a sorted list, so we need not look
267
* at all elements to confirm existence of an element
268
* from the search pattern
270
int patlen = sdp_list_len(pattern);
272
if (patlen < sdp_list_len(search))
274
for (; search; search = search->next) {
276
void *data = search->data;
281
// create 128-bit form of the search UUID
282
uuid128 = sdp_uuid_to_uuid128((uuid_t *)data);
283
list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp);
292
* Service search request PDU. This method extracts the search pattern
293
* (a sequence of UUIDs) and calls the matching function
294
* to find matching services
296
static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
298
int status = 0, i, plen, mlen, mtu, scanned;
299
sdp_list_t *pattern = NULL;
300
uint16_t expected, actual, rsp_count = 0;
302
sdp_cont_state_t *cstate = NULL;
303
uint8_t *pCacheBuffer = NULL;
305
uint32_t cStateId = 0;
306
short *pTotalRecordCount, *pCurrentRecordCount;
307
uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
309
scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
310
&pattern, &dtd, SDP_TYPE_UUID);
313
status = SDP_INVALID_SYNTAX;
318
plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
319
mlen = scanned + sizeof(uint16_t) + 1;
320
// ensure we don't read past buffer
321
if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) {
322
status = SDP_INVALID_SYNTAX;
326
expected = ntohs(bt_get_unaligned((uint16_t *)pdata));
328
SDPDBG("Expected count: %d", expected);
329
SDPDBG("Bytes scanned : %d", scanned);
331
pdata += sizeof(uint16_t);
334
* Check if continuation state exists, if yes attempt
335
* to get rsp remainder from cache, else send error
337
cstate = sdp_cstate_get(pdata);
339
mtu = req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - SDP_CONT_STATE_SIZE;
340
actual = MIN(expected, mtu >> 2);
342
/* make space in the rsp buffer for total and current record counts */
345
/* total service record count = 0 */
346
pTotalRecordCount = (short *)pdata;
347
bt_put_unaligned(0, (uint16_t *)pdata);
348
pdata += sizeof(uint16_t);
349
buf->data_size += sizeof(uint16_t);
351
/* current service record count = 0 */
352
pCurrentRecordCount = (short *)pdata;
353
bt_put_unaligned(0, (uint16_t *)pdata);
354
pdata += sizeof(uint16_t);
355
buf->data_size += sizeof(uint16_t);
357
if (cstate == NULL) {
358
/* for every record in the DB, do a pattern search */
359
sdp_list_t *list = sdp_get_record_list();
362
for (; list && rsp_count < expected; list = list->next) {
363
sdp_record_t *rec = (sdp_record_t *) list->data;
365
SDPDBG("Checking svcRec : 0x%x", rec->handle);
367
if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
368
sdp_check_access(rec->handle, &req->device)) {
370
bt_put_unaligned(htonl(rec->handle), (uint32_t *)pdata);
371
pdata += sizeof(uint32_t);
372
handleSize += sizeof(uint32_t);
376
SDPDBG("Match count: %d", rsp_count);
378
buf->data_size += handleSize;
379
bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
380
bt_put_unaligned(htons(rsp_count), (uint16_t *)pCurrentRecordCount);
382
if (rsp_count > actual) {
383
/* cache the rsp and generate a continuation state */
384
cStateId = sdp_cstate_alloc_buf(buf);
386
* subtract handleSize since we now send only
387
* a subset of handles
389
buf->data_size -= handleSize;
391
/* NULL continuation state */
392
sdp_set_cstate_pdu(buf, NULL);
396
/* under both the conditions below, the rsp buffer is not built yet */
397
if (cstate || cStateId > 0) {
402
* Get the previous sdp_cont_state_t and obtain
405
sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
407
pCacheBuffer = pCache->data;
408
/* get the rsp_count from the cached buffer */
409
rsp_count = ntohs(bt_get_unaligned((uint16_t *)pCacheBuffer));
411
/* get index of the last sdp_record_t sent */
412
lastIndex = cstate->cStateValue.lastIndexSent;
414
status = SDP_INVALID_CSTATE;
418
pCacheBuffer = buf->data;
423
* Set the local buffer pointer to after the
424
* current record count and increment the cached
425
* buffer pointer to beyond the counters
427
pdata = (uint8_t *) pCurrentRecordCount + sizeof(uint16_t);
429
/* increment beyond the totalCount and the currentCount */
430
pCacheBuffer += 2 * sizeof(uint16_t);
434
for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) {
435
bt_put_unaligned(bt_get_unaligned((uint32_t *)(pCacheBuffer + i * sizeof(uint32_t))), (uint32_t *)pdata);
436
pdata += sizeof(uint32_t);
437
handleSize += sizeof(uint32_t);
440
handleSize = actual << 2;
444
buf->data_size += handleSize;
445
bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
446
bt_put_unaligned(htons(i - lastIndex), (uint16_t *)pCurrentRecordCount);
448
if (i == rsp_count) {
449
/* set "null" continuationState */
450
sdp_set_cstate_pdu(buf, NULL);
453
* there's more: set lastIndexSent to
454
* the new value and move on
456
sdp_cont_state_t newState;
458
SDPDBG("Setting non-NULL sdp_cstate_t");
461
memcpy((char *)&newState, cstate, sizeof(sdp_cont_state_t));
463
memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
464
newState.timestamp = cStateId;
466
newState.cStateValue.lastIndexSent = i;
467
sdp_set_cstate_pdu(buf, &newState);
475
sdp_list_free(pattern, free);
481
* Extract attribute identifiers from the request PDU.
482
* Clients could request a subset of attributes (by id)
483
* from a service record, instead of the whole set. The
484
* requested identifiers are present in the PDU form of
487
static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, uint8_t dtd, sdp_buf_t *buf)
490
return SDP_INVALID_RECORD_HANDLE;
493
SDPDBG("Entries in attr seq : %d", sdp_list_len(seq));
495
SDPDBG("NULL attribute descriptor");
497
SDPDBG("AttrDataType : %d", dtd);
500
SDPDBG("Attribute sequence is NULL");
503
if (dtd == SDP_UINT16)
504
for (; seq; seq = seq->next) {
505
uint16_t attr = bt_get_unaligned((uint16_t *)seq->data);
506
sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr);
508
sdp_append_to_pdu(buf, a);
510
else if (dtd == SDP_UINT32) {
512
sdp_gen_record_pdu(rec, &pdu);
513
for (; seq; seq = seq->next) {
514
uint32_t range = bt_get_unaligned((uint32_t *)seq->data);
516
uint16_t low = (0xffff0000 & range) >> 16;
517
uint16_t high = 0x0000ffff & range;
520
SDPDBG("attr range : 0x%x", range);
521
SDPDBG("Low id : 0x%x", low);
522
SDPDBG("High id : 0x%x", high);
524
if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) {
526
memcpy(buf->data, pdu.data, pdu.data_size);
527
buf->data_size = pdu.data_size;
530
/* (else) sub-range of attributes */
531
for (attr = low; attr < high; attr++) {
532
data = sdp_data_get(rec, attr);
534
sdp_append_to_pdu(buf, data);
536
data = sdp_data_get(rec, high);
538
sdp_append_to_pdu(buf, data);
542
error("Unexpected data type : 0x%x", dtd);
543
error("Expect uint16_t or uint32_t");
544
return SDP_INVALID_SYNTAX;
550
* A request for the attributes of a service record.
551
* First check if the service record (specified by
552
* service record handle) exists, then call the attribute
555
static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
557
sdp_cont_state_t *cstate = NULL;
558
uint8_t *pResponse = NULL;
559
short cstate_size = 0;
560
sdp_list_t *seq = NULL;
564
int status = 0, plen, mlen;
565
uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
566
uint32_t handle = ntohl(bt_get_unaligned((uint32_t *)pdata));
568
pdata += sizeof(uint32_t);
569
max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata));
570
pdata += sizeof(uint16_t);
572
/* extract the attribute list */
573
scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
574
&seq, &dtd, SDP_TYPE_ANY);
576
status = SDP_INVALID_SYNTAX;
581
plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
582
mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1;
583
// ensure we don't read past buffer
584
if (plen < mlen || plen != mlen + *(uint8_t *)pdata) {
585
status = SDP_INVALID_SYNTAX;
590
* if continuation state exists, attempt
591
* to get rsp remainder from cache, else send error
593
cstate = sdp_cstate_get(pdata);
595
SDPDBG("SvcRecHandle : 0x%x", handle);
596
SDPDBG("max_rsp_size : %d", max_rsp_size);
599
* Calculate Attribute size acording to MTU
600
* We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
602
max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) -
603
sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
605
/* pull header for AttributeList byte count */
606
buf->data += sizeof(uint16_t);
607
buf->buf_size -= sizeof(uint16_t);
610
sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
612
SDPDBG("Obtained cached rsp : %p", pCache);
615
short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent);
616
pResponse = pCache->data;
617
memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
618
buf->data_size += sent;
619
cstate->cStateValue.maxBytesSent += sent;
621
SDPDBG("Response size : %d sending now : %d bytes sent so far : %d",
622
pCache->data_size, sent, cstate->cStateValue.maxBytesSent);
623
if (cstate->cStateValue.maxBytesSent == pCache->data_size)
624
cstate_size = sdp_set_cstate_pdu(buf, NULL);
626
cstate_size = sdp_set_cstate_pdu(buf, cstate);
628
status = SDP_INVALID_CSTATE;
629
error("NULL cache buffer and non-NULL continuation state");
632
sdp_record_t *rec = sdp_record_find(handle);
633
status = extract_attrs(rec, seq, dtd, buf);
634
if (buf->data_size > max_rsp_size) {
635
sdp_cont_state_t newState;
637
memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
638
newState.timestamp = sdp_cstate_alloc_buf(buf);
640
* Reset the buffer size to the maximum expected and
641
* set the sdp_cont_state_t
643
SDPDBG("Creating continuation state of size : %d", buf->data_size);
644
buf->data_size = max_rsp_size;
645
newState.cStateValue.maxBytesSent = max_rsp_size;
646
cstate_size = sdp_set_cstate_pdu(buf, &newState);
648
if (buf->data_size == 0)
649
sdp_append_to_buf(buf, 0, 0);
650
cstate_size = sdp_set_cstate_pdu(buf, NULL);
655
buf->data -= sizeof(uint16_t);
656
buf->buf_size += sizeof(uint16_t);
662
sdp_list_free(seq, free);
666
/* set attribute list byte count */
667
bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
668
buf->data_size += sizeof(uint16_t);
673
* combined service search and attribute extraction
675
static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
677
int status = 0, plen, totscanned;
678
uint8_t *pdata, *pResponse = NULL;
679
int scanned, max, rsp_count = 0;
680
sdp_list_t *pattern = NULL, *seq = NULL, *svcList;
681
sdp_cont_state_t *cstate = NULL;
682
short cstate_size = 0;
687
pdata = req->buf + sizeof(sdp_pdu_hdr_t);
688
scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
689
&pattern, &dtd, SDP_TYPE_UUID);
691
status = SDP_INVALID_SYNTAX;
694
totscanned = scanned;
696
SDPDBG("Bytes scanned: %d", scanned);
699
max = ntohs(bt_get_unaligned((uint16_t *)pdata));
700
pdata += sizeof(uint16_t);
702
SDPDBG("Max Attr expected: %d", max);
704
/* extract the attribute list */
705
scanned = extract_des(pdata, req->len - sizeof(sdp_pdu_hdr_t),
706
&seq, &dtd, SDP_TYPE_ANY);
708
status = SDP_INVALID_SYNTAX;
712
totscanned += scanned + sizeof(uint16_t) + 1;
714
plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen);
715
if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) {
716
status = SDP_INVALID_SYNTAX;
721
* if continuation state exists attempt
722
* to get rsp remainder from cache, else send error
724
cstate = sdp_cstate_get(pdata); // continuation information
726
svcList = sdp_get_record_list();
728
tmpbuf.data = malloc(USHRT_MAX);
729
tmpbuf.data_size = 0;
730
tmpbuf.buf_size = USHRT_MAX;
731
memset(tmpbuf.data, 0, USHRT_MAX);
734
* Calculate Attribute size acording to MTU
735
* We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t))
737
max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t));
739
/* pull header for AttributeList byte count */
740
buf->data += sizeof(uint16_t);
741
buf->buf_size -= sizeof(uint16_t);
743
if (cstate == NULL) {
744
/* no continuation state -> create new response */
746
for (p = svcList; p; p = p->next) {
747
sdp_record_t *rec = (sdp_record_t *) p->data;
748
if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
749
sdp_check_access(rec->handle, &req->device)) {
751
status = extract_attrs(rec, seq, dtd, &tmpbuf);
753
SDPDBG("Response count : %d", rsp_count);
754
SDPDBG("Local PDU size : %d", tmpbuf.data_size);
756
SDPDBG("Extract attr from record returns err");
759
if (buf->data_size + tmpbuf.data_size < buf->buf_size) {
760
// to be sure no relocations
761
sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
762
tmpbuf.data_size = 0;
763
memset(tmpbuf.data, 0, USHRT_MAX);
765
error("Relocation needed");
768
SDPDBG("Net PDU size : %d", buf->data_size);
771
if (buf->data_size > max) {
772
sdp_cont_state_t newState;
774
memset((char *)&newState, 0, sizeof(sdp_cont_state_t));
775
newState.timestamp = sdp_cstate_alloc_buf(buf);
777
* Reset the buffer size to the maximum expected and
778
* set the sdp_cont_state_t
780
buf->data_size = max;
781
newState.cStateValue.maxBytesSent = max;
782
cstate_size = sdp_set_cstate_pdu(buf, &newState);
784
cstate_size = sdp_set_cstate_pdu(buf, NULL);
786
/* continuation State exists -> get from cache */
787
sdp_buf_t *pCache = sdp_get_cached_rsp(cstate);
789
uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent);
790
pResponse = pCache->data;
791
memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent);
792
buf->data_size += sent;
793
cstate->cStateValue.maxBytesSent += sent;
794
if (cstate->cStateValue.maxBytesSent == pCache->data_size)
795
cstate_size = sdp_set_cstate_pdu(buf, NULL);
797
cstate_size = sdp_set_cstate_pdu(buf, cstate);
799
status = SDP_INVALID_CSTATE;
800
SDPDBG("Non-null continuation state, but null cache buffer");
804
if (!rsp_count && !cstate) {
807
sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size);
808
sdp_set_cstate_pdu(buf, NULL);
812
buf->data -= sizeof(uint16_t);
813
buf->buf_size += sizeof(uint16_t);
816
/* set attribute list byte count */
817
bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
818
buf->data_size += sizeof(uint16_t);
827
sdp_list_free(pattern, free);
829
sdp_list_free(seq, free);
834
* Top level request processor. Calls the appropriate processing
835
* function based on request type. Handles service registration
836
* client requests also.
838
static void process_request(sdp_req_t *req)
840
sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf;
841
sdp_pdu_hdr_t *rsphdr;
843
uint8_t *buf = malloc(USHRT_MAX);
845
int status = SDP_INVALID_SYNTAX;
847
memset(buf, 0, USHRT_MAX);
848
rsp.data = buf + sizeof(sdp_pdu_hdr_t);
850
rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t);
851
rsphdr = (sdp_pdu_hdr_t *)buf;
853
if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) {
854
status = SDP_INVALID_PDU_SIZE;
857
switch (reqhdr->pdu_id) {
858
case SDP_SVC_SEARCH_REQ:
859
SDPDBG("Got a svc srch req");
860
status = service_search_req(req, &rsp);
861
rsphdr->pdu_id = SDP_SVC_SEARCH_RSP;
863
case SDP_SVC_ATTR_REQ:
864
SDPDBG("Got a svc attr req");
865
status = service_attr_req(req, &rsp);
866
rsphdr->pdu_id = SDP_SVC_ATTR_RSP;
868
case SDP_SVC_SEARCH_ATTR_REQ:
869
SDPDBG("Got a svc srch attr req");
870
status = service_search_attr_req(req, &rsp);
871
rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP;
873
/* Following requests are allowed only for local connections */
874
case SDP_SVC_REGISTER_REQ:
875
SDPDBG("Service register request");
877
status = service_register_req(req, &rsp);
878
rsphdr->pdu_id = SDP_SVC_REGISTER_RSP;
881
case SDP_SVC_UPDATE_REQ:
882
SDPDBG("Service update request");
884
status = service_update_req(req, &rsp);
885
rsphdr->pdu_id = SDP_SVC_UPDATE_RSP;
888
case SDP_SVC_REMOVE_REQ:
889
SDPDBG("Service removal request");
891
status = service_remove_req(req, &rsp);
892
rsphdr->pdu_id = SDP_SVC_REMOVE_RSP;
896
error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id);
897
status = SDP_INVALID_SYNTAX;
903
rsphdr->pdu_id = SDP_ERROR_RSP;
904
bt_put_unaligned(htons(status), (uint16_t *)rsp.data);
905
rsp.data_size = sizeof(uint16_t);
908
SDPDBG("Sending rsp. status %d", status);
910
rsphdr->tid = reqhdr->tid;
911
rsphdr->plen = htons(rsp.data_size);
913
/* point back to the real buffer start and set the real rsp length */
914
rsp.data_size += sizeof(sdp_pdu_hdr_t);
917
/* stream the rsp PDU */
918
sent = send(req->sock, rsp.data, rsp.data_size, 0);
920
SDPDBG("Bytes Sent : %d", sent);
926
void handle_request(int sk, uint8_t *data, int len)
928
struct sockaddr_l2 sa;
933
if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0)
936
if (sa.l2_family == AF_BLUETOOTH) {
937
struct l2cap_options lo;
938
memset(&lo, 0, sizeof(lo));
940
getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size);
941
bacpy(&req.bdaddr, &sa.l2_bdaddr);
944
memset(&sa, 0, sizeof(sa));
946
getsockname(sk, (struct sockaddr *) &sa, &size);
947
bacpy(&req.device, &sa.l2_bdaddr);
949
bacpy(&req.device, BDADDR_ANY);
950
bacpy(&req.bdaddr, BDADDR_LOCAL);
959
process_request(&req);