blob: 40a2abfa83bf6d66fc8b55079d74c9d000fe5940 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
2 *
3 * Copyright (C) 1999-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19/******************************************************************************
20 *
21 * This file contains functions that handle the SDP server functions.
22 * This is mainly dealing with client requests
23 *
24 ******************************************************************************/
25
26#include <stdlib.h>
27#include <string.h>
28#include <stdio.h>
29
Pavlin Radoslavov258c2532015-09-27 20:59:05 -070030#include "bt_common.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080031#include "bt_types.h"
Mike J. Chen5cd8bff2014-01-31 18:16:59 -080032#include "bt_utils.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080033#include "btu.h"
34
35#include "l2cdefs.h"
36#include "hcidefs.h"
37#include "hcimsgs.h"
38
39#include "sdp_api.h"
40#include "sdpint.h"
41
42
Marie Janssend19e0782016-07-15 12:48:27 -070043#if (SDP_SERVER_ENABLED == TRUE)
The Android Open Source Project5738f832012-12-12 16:00:35 -080044
Pavlin Radoslavov78bcff72015-12-04 17:36:34 -080045extern fixed_queue_t *btu_general_alarm_queue;
46
The Android Open Source Project5738f832012-12-12 16:00:35 -080047/* Maximum number of bytes to reserve out of SDP MTU for response data */
48#define SDP_MAX_SERVICE_RSPHDR_LEN 12
49#define SDP_MAX_SERVATTR_RSPHDR_LEN 10
50#define SDP_MAX_ATTR_RSPHDR_LEN 10
51
52/********************************************************************************/
53/* L O C A L F U N C T I O N P R O T O T Y P E S */
54/********************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -070055static void process_service_search (tCONN_CB *p_ccb, uint16_t trans_num,
56 uint16_t param_len, uint8_t *p_req,
57 uint8_t *p_req_end);
The Android Open Source Project5738f832012-12-12 16:00:35 -080058
Marie Janssend19e0782016-07-15 12:48:27 -070059static void process_service_attr_req (tCONN_CB *p_ccb, uint16_t trans_num,
60 uint16_t param_len, uint8_t *p_req,
61 uint8_t *p_req_end);
The Android Open Source Project5738f832012-12-12 16:00:35 -080062
Marie Janssend19e0782016-07-15 12:48:27 -070063static void process_service_search_attr_req (tCONN_CB *p_ccb, uint16_t trans_num,
64 uint16_t param_len, uint8_t *p_req,
65 uint8_t *p_req_end);
The Android Open Source Project5738f832012-12-12 16:00:35 -080066
67
68/********************************************************************************/
69/* E R R O R T E X T S T R I N G S */
70/* */
71/* The default is to have no text string, but we allow the strings to be */
72/* configured in target.h if people want them. */
73/********************************************************************************/
74#ifndef SDP_TEXT_BAD_HEADER
75#define SDP_TEXT_BAD_HEADER NULL
76#endif
77
78#ifndef SDP_TEXT_BAD_PDU
79#define SDP_TEXT_BAD_PDU NULL
80#endif
81
82#ifndef SDP_TEXT_BAD_UUID_LIST
83#define SDP_TEXT_BAD_UUID_LIST NULL
84#endif
85
86#ifndef SDP_TEXT_BAD_HANDLE
87#define SDP_TEXT_BAD_HANDLE NULL
88#endif
89
90#ifndef SDP_TEXT_BAD_ATTR_LIST
91#define SDP_TEXT_BAD_ATTR_LIST NULL
92#endif
93
94#ifndef SDP_TEXT_BAD_CONT_LEN
95#define SDP_TEXT_BAD_CONT_LEN NULL
96#endif
97
98#ifndef SDP_TEXT_BAD_CONT_INX
99#define SDP_TEXT_BAD_CONT_INX NULL
100#endif
101
Hemant Gupta86225e42014-01-23 18:38:44 +0530102#ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
103#define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL
104#endif
105
The Android Open Source Project5738f832012-12-12 16:00:35 -0800106/*******************************************************************************
107**
108** Function sdp_server_handle_client_req
109**
110** Description This is the main dispatcher of the SDP server. It is called
111** when any data is received from L2CAP, and dispatches the
112** request to the appropriate handler.
113**
114** Returns void
115**
116*******************************************************************************/
117void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
118{
Marie Janssend19e0782016-07-15 12:48:27 -0700119 uint8_t *p_req = (uint8_t *) (p_msg + 1) + p_msg->offset;
120 uint8_t *p_req_end = p_req + p_msg->len;
121 uint8_t pdu_id;
122 uint16_t trans_num, param_len;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800123
124
125 /* Start inactivity timer */
Pavlin Radoslavov78bcff72015-12-04 17:36:34 -0800126 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
127 sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800128
129 /* The first byte in the message is the pdu type */
130 pdu_id = *p_req++;
131
132 /* Extract the transaction number and parameter length */
133 BE_STREAM_TO_UINT16 (trans_num, p_req);
134 BE_STREAM_TO_UINT16 (param_len, p_req);
135
Kim Schulz107660f2013-09-24 09:52:52 +0200136 if ((p_req + param_len) != p_req_end)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800137 {
138 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
139 return;
140 }
141
142 switch (pdu_id)
143 {
144 case SDP_PDU_SERVICE_SEARCH_REQ:
145 process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end);
146 break;
147
148 case SDP_PDU_SERVICE_ATTR_REQ:
149 process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
150 break;
151
152 case SDP_PDU_SERVICE_SEARCH_ATTR_REQ:
153 process_service_search_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
154 break;
155
156 default:
157 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_PDU);
Sharvil Nanavatia51c9d92014-05-04 01:08:21 -0700158 SDP_TRACE_WARNING ("SDP - server got unknown PDU: 0x%x", pdu_id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800159 break;
160 }
161}
162
163
164
165/*******************************************************************************
166**
167** Function process_service_search
168**
169** Description This function handles a service search request from the
170** client. It builds a reply message with info from the database,
171** and sends the reply back to the client.
172**
173** Returns void
174**
175*******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -0700176static void process_service_search (tCONN_CB *p_ccb, uint16_t trans_num,
177 uint16_t param_len, uint8_t *p_req,
178 uint8_t *p_req_end)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800179{
Marie Janssend19e0782016-07-15 12:48:27 -0700180 uint16_t max_replies, cur_handles, rem_handles, cont_offset;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800181 tSDP_UUID_SEQ uid_seq;
Marie Janssend19e0782016-07-15 12:48:27 -0700182 uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
183 uint16_t rsp_param_len, num_rsp_handles, xx;
184 uint32_t rsp_handles[SDP_MAX_RECORDS] = {0};
The Android Open Source Project5738f832012-12-12 16:00:35 -0800185 tSDP_RECORD *p_rec = NULL;
Marie Janssend19e0782016-07-15 12:48:27 -0700186 bool is_cont = false;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800187 UNUSED(p_req_end);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800188
189 p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
190
191 if ((!p_req) || (!uid_seq.num_uids))
192 {
193 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
194 return;
195 }
196
197 /* Get the max replies we can send. Cap it at our max anyways. */
198 BE_STREAM_TO_UINT16 (max_replies, p_req);
199
200 if (max_replies > SDP_MAX_RECORDS)
201 max_replies = SDP_MAX_RECORDS;
202
Hemant Gupta86225e42014-01-23 18:38:44 +0530203
204 if ((!p_req) || (p_req > p_req_end))
205 {
206 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
207 return;
208 }
209
210
The Android Open Source Project5738f832012-12-12 16:00:35 -0800211 /* Get a list of handles that match the UUIDs given to us */
212 for (num_rsp_handles = 0; num_rsp_handles < max_replies; )
213 {
214 p_rec = sdp_db_service_search (p_rec, &uid_seq);
215
216 if (p_rec)
217 rsp_handles[num_rsp_handles++] = p_rec->record_handle;
218 else
219 break;
220 }
221
222 /* Check if this is a continuation request */
223 if (*p_req)
224 {
Kim Schulz107660f2013-09-24 09:52:52 +0200225 if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800226 {
227 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
228 SDP_TEXT_BAD_CONT_LEN);
229 return;
230 }
231 BE_STREAM_TO_UINT16 (cont_offset, p_req);
232
233 if (cont_offset != p_ccb->cont_offset)
234 {
235 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
236 SDP_TEXT_BAD_CONT_INX);
237 return;
238 }
239
240 rem_handles = num_rsp_handles - cont_offset; /* extract the remaining handles */
241 }
242 else
243 {
244 rem_handles = num_rsp_handles;
245 cont_offset = 0;
Simon Wilsondc69e2d2015-04-02 15:17:08 -0700246 p_ccb->cont_offset = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800247 }
248
249 /* Calculate how many handles will fit in one PDU */
Marie Janssend19e0782016-07-15 12:48:27 -0700250 cur_handles = (uint16_t)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800251
252 if (rem_handles <= cur_handles)
253 cur_handles = rem_handles;
254 else /* Continuation is set */
255 {
256 p_ccb->cont_offset += cur_handles;
Marie Janssend19e0782016-07-15 12:48:27 -0700257 is_cont = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800258 }
259
260 /* Get a buffer to use to build the response */
Pavlin Radoslavov717a4a92016-02-06 08:36:06 -0800261 BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800262 p_buf->offset = L2CAP_MIN_OFFSET;
Marie Janssend19e0782016-07-15 12:48:27 -0700263 p_rsp = p_rsp_start = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800264
265 /* Start building a rsponse */
266 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_RSP);
267 UINT16_TO_BE_STREAM (p_rsp, trans_num);
268
269 /* Skip the length, we need to add it at the end */
270 p_rsp_param_len = p_rsp;
271 p_rsp += 2;
272
273 /* Put in total and current number of handles, and handles themselves */
274 UINT16_TO_BE_STREAM (p_rsp, num_rsp_handles);
275 UINT16_TO_BE_STREAM (p_rsp, cur_handles);
276
Sharvil Nanavatia51c9d92014-05-04 01:08:21 -0700277/* SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, cont %d",
The Android Open Source Project5738f832012-12-12 16:00:35 -0800278 num_rsp_handles, cur_handles, cont_offset,
279 cont_offset + cur_handles-1, is_cont); */
280 for (xx = cont_offset; xx < cont_offset + cur_handles; xx++)
281 UINT32_TO_BE_STREAM (p_rsp, rsp_handles[xx]);
282
283 if (is_cont)
284 {
285 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
286 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
287 }
288 else
289 UINT8_TO_BE_STREAM (p_rsp, 0);
290
291 /* Go back and put the parameter length into the buffer */
292 rsp_param_len = p_rsp - p_rsp_param_len - 2;
293 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
294
295 /* Set the length of the SDP data in the buffer */
296 p_buf->len = p_rsp - p_rsp_start;
297
298
299 /* Send the buffer through L2CAP */
300 L2CA_DataWrite (p_ccb->connection_id, p_buf);
301}
302
303
304/*******************************************************************************
305**
306** Function process_service_attr_req
307**
308** Description This function handles an attribute request from the client.
309** It builds a reply message with info from the database,
310** and sends the reply back to the client.
311**
312** Returns void
313**
314*******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -0700315static void process_service_attr_req (tCONN_CB *p_ccb, uint16_t trans_num,
316 uint16_t param_len, uint8_t *p_req,
317 uint8_t *p_req_end)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800318{
Marie Janssend19e0782016-07-15 12:48:27 -0700319 uint16_t max_list_len, len_to_send, cont_offset;
320 int16_t rem_len;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800321 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
Marie Janssend19e0782016-07-15 12:48:27 -0700322 uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
323 uint16_t rsp_param_len, xx;
324 uint32_t rec_handle;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800325 tSDP_RECORD *p_rec;
326 tSDP_ATTRIBUTE *p_attr;
Marie Janssend19e0782016-07-15 12:48:27 -0700327 bool is_cont = false;
328 uint16_t attr_len;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800329
330 /* Extract the record handle */
331 BE_STREAM_TO_UINT32 (rec_handle, p_req);
332
333 if (p_req > p_req_end)
334 {
335 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
336 return;
337 }
338
339 /* Get the max list length we can send. Cap it at MTU size minus overhead */
340 BE_STREAM_TO_UINT16 (max_list_len, p_req);
341
342 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
343 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
344
345 p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
346
347 if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end))
348 {
349 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
350 return;
351 }
352
353 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
354
355 /* Find a record with the record handle */
356 p_rec = sdp_db_find_record (rec_handle);
357 if (!p_rec)
358 {
359 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
360 return;
361 }
362
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800363 /* Free and reallocate buffer */
Pavlin Radoslavovcceb4302016-02-05 13:54:43 -0800364 osi_free(p_ccb->rsp_list);
Marie Janssend19e0782016-07-15 12:48:27 -0700365 p_ccb->rsp_list = (uint8_t *)osi_malloc(max_list_len);
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800366
The Android Open Source Project5738f832012-12-12 16:00:35 -0800367 /* Check if this is a continuation request */
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800368 if (*p_req) {
369 if (*p_req++ != SDP_CONTINUATION_LEN) {
370 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
371 SDP_TEXT_BAD_CONT_LEN);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800372 return;
373 }
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800374 BE_STREAM_TO_UINT16(cont_offset, p_req);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800375
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800376 if (cont_offset != p_ccb->cont_offset) {
377 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
378 SDP_TEXT_BAD_CONT_INX);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800379 return;
380 }
Marie Janssend19e0782016-07-15 12:48:27 -0700381 is_cont = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800382
383 /* Initialise for continuation response */
384 p_rsp = &p_ccb->rsp_list[0];
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800385 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
386 p_ccb->cont_info.next_attr_start_id;
387 } else {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800388 p_ccb->cont_offset = 0;
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800389 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800390
391 /* Reset continuation parameters in p_ccb */
392 p_ccb->cont_info.prev_sdp_rec = NULL;
393 p_ccb->cont_info.next_attr_index = 0;
394 p_ccb->cont_info.attr_offset = 0;
395 }
396
397 /* Search for attributes that match the list given to us */
398 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
399 {
400 p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
401
402 if (p_attr)
403 {
404 /* Check if attribute fits. Assume 3-byte value type/length */
Marie Janssend19e0782016-07-15 12:48:27 -0700405 rem_len = max_list_len - (int16_t) (p_rsp - &p_ccb->rsp_list[0]);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800406
407 /* just in case */
408 if (rem_len <= 0)
409 {
410 p_ccb->cont_info.next_attr_index = xx;
411 p_ccb->cont_info.next_attr_start_id = p_attr->id;
412 break;
413 }
414
415 attr_len = sdpu_get_attrib_entry_len(p_attr);
416 /* if there is a partial attribute pending to be sent */
417 if (p_ccb->cont_info.attr_offset)
418 {
419 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
420 &p_ccb->cont_info.attr_offset);
421
422 /* If the partial attrib could not been fully added yet */
423 if (p_ccb->cont_info.attr_offset != attr_len)
424 break;
425 else /* If the partial attrib has been added in full by now */
426 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
427 }
428 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
429 {
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800430 if (attr_len >= SDP_MAX_ATTR_LEN)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800431 {
Sharvil Nanavatia51c9d92014-05-04 01:08:21 -0700432 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800433 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
434 return;
435 }
436
437 /* add the partial attribute if possible */
Marie Janssend19e0782016-07-15 12:48:27 -0700438 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (uint16_t)rem_len,
The Android Open Source Project5738f832012-12-12 16:00:35 -0800439 &p_ccb->cont_info.attr_offset);
440
441 p_ccb->cont_info.next_attr_index = xx;
442 p_ccb->cont_info.next_attr_start_id = p_attr->id;
443 break;
444 }
445 else /* build the whole attribute */
446 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
447
448 /* If doing a range, stick with this one till no more attributes found */
449 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
450 {
451 /* Update for next time through */
452 attr_seq.attr_entry[xx].start = p_attr->id + 1;
453
454 xx--;
455 }
456 }
457 }
458 /* If all the attributes have been accomodated in p_rsp,
459 reset next_attr_index */
460 if (xx == attr_seq.num_attr)
461 p_ccb->cont_info.next_attr_index = 0;
462
Marie Janssend19e0782016-07-15 12:48:27 -0700463 len_to_send = (uint16_t) (p_rsp - &p_ccb->rsp_list[0]);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800464 cont_offset = 0;
465
466 if (!is_cont)
467 {
468 p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3;
469 /* Put in the sequence header (2 or 3 bytes) */
470 if (p_ccb->list_len > 255)
471 {
Marie Janssend19e0782016-07-15 12:48:27 -0700472 p_ccb->rsp_list[0] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
473 p_ccb->rsp_list[1] = (uint8_t) ((p_ccb->list_len - 3) >> 8);
474 p_ccb->rsp_list[2] = (uint8_t) (p_ccb->list_len - 3);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800475 }
476 else
477 {
478 cont_offset = 1;
479
Marie Janssend19e0782016-07-15 12:48:27 -0700480 p_ccb->rsp_list[1] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
481 p_ccb->rsp_list[2] = (uint8_t) (p_ccb->list_len - 3);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800482
483 p_ccb->list_len--;
484 len_to_send--;
485 }
486 }
487
488 /* Get a buffer to use to build the response */
Pavlin Radoslavov717a4a92016-02-06 08:36:06 -0800489 BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800490 p_buf->offset = L2CAP_MIN_OFFSET;
Marie Janssend19e0782016-07-15 12:48:27 -0700491 p_rsp = p_rsp_start = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800492
493 /* Start building a rsponse */
494 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
495 UINT16_TO_BE_STREAM (p_rsp, trans_num);
496
497 /* Skip the parameter length, add it when we know the length */
498 p_rsp_param_len = p_rsp;
499 p_rsp += 2;
500
501 UINT16_TO_BE_STREAM (p_rsp, len_to_send);
502
503 memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
504 p_rsp += len_to_send;
505
506 p_ccb->cont_offset += len_to_send;
507
508 /* If anything left to send, continuation needed */
509 if (p_ccb->cont_offset < p_ccb->list_len)
510 {
Marie Janssend19e0782016-07-15 12:48:27 -0700511 is_cont = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800512
513 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
514 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
515 }
516 else
517 UINT8_TO_BE_STREAM (p_rsp, 0);
518
519 /* Go back and put the parameter length into the buffer */
520 rsp_param_len = p_rsp - p_rsp_param_len - 2;
521 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
522
523 /* Set the length of the SDP data in the buffer */
524 p_buf->len = p_rsp - p_rsp_start;
525
526
527 /* Send the buffer through L2CAP */
528 L2CA_DataWrite (p_ccb->connection_id, p_buf);
529}
530
531
532
533/*******************************************************************************
534**
535** Function process_service_search_attr_req
536**
537** Description This function handles a combined service search and attribute
538** read request from the client. It builds a reply message with
539** info from the database, and sends the reply back to the client.
540**
541** Returns void
542**
543*******************************************************************************/
Marie Janssend19e0782016-07-15 12:48:27 -0700544static void process_service_search_attr_req (tCONN_CB *p_ccb, uint16_t trans_num,
545 uint16_t param_len, uint8_t *p_req,
546 uint8_t *p_req_end)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800547{
Marie Janssend19e0782016-07-15 12:48:27 -0700548 uint16_t max_list_len;
549 int16_t rem_len;
550 uint16_t len_to_send, cont_offset;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800551 tSDP_UUID_SEQ uid_seq;
Marie Janssend19e0782016-07-15 12:48:27 -0700552 uint8_t *p_rsp, *p_rsp_start, *p_rsp_param_len;
553 uint16_t rsp_param_len, xx;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800554 tSDP_RECORD *p_rec;
555 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
556 tSDP_ATTRIBUTE *p_attr;
Marie Janssend19e0782016-07-15 12:48:27 -0700557 bool maxxed_out = false, is_cont = false;
558 uint8_t *p_seq_start;
559 uint16_t seq_len, attr_len;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800560 UNUSED(p_req_end);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800561
562 /* Extract the UUID sequence to search for */
563 p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
564
565 if ((!p_req) || (!uid_seq.num_uids))
566 {
567 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
568 return;
569 }
570
571 /* Get the max list length we can send. Cap it at our max list length. */
572 BE_STREAM_TO_UINT16 (max_list_len, p_req);
573
574 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
575 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
576
577 p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
578
579 if ((!p_req) || (!attr_seq.num_attr))
580 {
581 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
582 return;
583 }
584
585 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
586
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800587 /* Free and reallocate buffer */
Pavlin Radoslavovcceb4302016-02-05 13:54:43 -0800588 osi_free(p_ccb->rsp_list);
Marie Janssend19e0782016-07-15 12:48:27 -0700589 p_ccb->rsp_list = (uint8_t *)osi_malloc(max_list_len);
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800590
The Android Open Source Project5738f832012-12-12 16:00:35 -0800591 /* Check if this is a continuation request */
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800592 if (*p_req) {
593 if (*p_req++ != SDP_CONTINUATION_LEN) {
594 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
595 SDP_TEXT_BAD_CONT_LEN);
Srinu Jellac0532302014-12-22 19:46:28 +0530596 return;
597 }
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800598 BE_STREAM_TO_UINT16(cont_offset, p_req);
Srinu Jellac0532302014-12-22 19:46:28 +0530599
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800600 if (cont_offset != p_ccb->cont_offset) {
601 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
602 SDP_TEXT_BAD_CONT_INX);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800603 return;
604 }
Marie Janssend19e0782016-07-15 12:48:27 -0700605 is_cont = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800606
607 /* Initialise for continuation response */
608 p_rsp = &p_ccb->rsp_list[0];
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800609 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
610 p_ccb->cont_info.next_attr_start_id;
611 } else {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800612 p_ccb->cont_offset = 0;
Pavlin Radoslavov0a20dd42016-02-04 18:20:06 -0800613 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800614
615 /* Reset continuation parameters in p_ccb */
616 p_ccb->cont_info.prev_sdp_rec = NULL;
617 p_ccb->cont_info.next_attr_index = 0;
Marie Janssend19e0782016-07-15 12:48:27 -0700618 p_ccb->cont_info.last_attr_seq_desc_sent = false;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800619 p_ccb->cont_info.attr_offset = 0;
620 }
621
622 /* Get a list of handles that match the UUIDs given to us */
623 for (p_rec = sdp_db_service_search (p_ccb->cont_info.prev_sdp_rec, &uid_seq); p_rec; p_rec = sdp_db_service_search (p_rec, &uid_seq))
624 {
625 /* Allow space for attribute sequence type and length */
626 p_seq_start = p_rsp;
Marie Janssend19e0782016-07-15 12:48:27 -0700627 if (p_ccb->cont_info.last_attr_seq_desc_sent == false)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800628 {
629 /* See if there is enough room to include a new service in the current response */
Marie Janssend19e0782016-07-15 12:48:27 -0700630 rem_len = max_list_len - (int16_t) (p_rsp - &p_ccb->rsp_list[0]);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800631 if (rem_len < 3)
632 {
633 /* Not enough room. Update continuation info for next response */
634 p_ccb->cont_info.next_attr_index = 0;
635 p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
636 break;
637 }
638 p_rsp += 3;
639 }
640
641 /* Get a list of handles that match the UUIDs given to us */
642 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
643 {
644 p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
645
646 if (p_attr)
647 {
648 /* Check if attribute fits. Assume 3-byte value type/length */
Marie Janssend19e0782016-07-15 12:48:27 -0700649 rem_len = max_list_len - (int16_t) (p_rsp - &p_ccb->rsp_list[0]);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800650
651 /* just in case */
652 if (rem_len <= 0)
653 {
654 p_ccb->cont_info.next_attr_index = xx;
655 p_ccb->cont_info.next_attr_start_id = p_attr->id;
Marie Janssend19e0782016-07-15 12:48:27 -0700656 maxxed_out = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800657 break;
658 }
659
660 attr_len = sdpu_get_attrib_entry_len(p_attr);
661 /* if there is a partial attribute pending to be sent */
662 if (p_ccb->cont_info.attr_offset)
663 {
664 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
665 &p_ccb->cont_info.attr_offset);
666
667 /* If the partial attrib could not been fully added yet */
668 if (p_ccb->cont_info.attr_offset != attr_len)
669 {
Marie Janssend19e0782016-07-15 12:48:27 -0700670 maxxed_out = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800671 break;
672 }
673 else /* If the partial attrib has been added in full by now */
674 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
675 }
676 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
677 {
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800678 if (attr_len >= SDP_MAX_ATTR_LEN)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800679 {
Sharvil Nanavatia51c9d92014-05-04 01:08:21 -0700680 SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d", max_list_len, attr_len);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800681 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
682 return;
683 }
684
685 /* add the partial attribute if possible */
Marie Janssend19e0782016-07-15 12:48:27 -0700686 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (uint16_t)rem_len,
The Android Open Source Project5738f832012-12-12 16:00:35 -0800687 &p_ccb->cont_info.attr_offset);
688
689 p_ccb->cont_info.next_attr_index = xx;
690 p_ccb->cont_info.next_attr_start_id = p_attr->id;
Marie Janssend19e0782016-07-15 12:48:27 -0700691 maxxed_out = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800692 break;
693 }
694 else /* build the whole attribute */
695 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
696
697 /* If doing a range, stick with this one till no more attributes found */
698 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
699 {
700 /* Update for next time through */
701 attr_seq.attr_entry[xx].start = p_attr->id + 1;
702
703 xx--;
704 }
705 }
706 }
707
708 /* Go back and put the type and length into the buffer */
Marie Janssend19e0782016-07-15 12:48:27 -0700709 if (p_ccb->cont_info.last_attr_seq_desc_sent == false)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800710 {
711 seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
712 if (seq_len != 0)
713 {
714 UINT8_TO_BE_STREAM (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
715 UINT16_TO_BE_STREAM (p_seq_start, seq_len);
716
717 if (maxxed_out)
Marie Janssend19e0782016-07-15 12:48:27 -0700718 p_ccb->cont_info.last_attr_seq_desc_sent = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800719 }
720 else
721 p_rsp = p_seq_start;
722 }
723
724 if (maxxed_out)
725 break;
726
727 /* Restore the attr_seq to look for in the next sdp record */
728 memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ;
729
730 /* Reset the next attr index */
731 p_ccb->cont_info.next_attr_index = 0;
732 p_ccb->cont_info.prev_sdp_rec = p_rec;
Marie Janssend19e0782016-07-15 12:48:27 -0700733 p_ccb->cont_info.last_attr_seq_desc_sent = false;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800734 }
735
736 /* response length */
Marie Janssend19e0782016-07-15 12:48:27 -0700737 len_to_send = (uint16_t) (p_rsp - &p_ccb->rsp_list[0]);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800738 cont_offset = 0;
739
Sharvil Nanavati54966dc2014-11-15 00:17:35 -0800740 // The current SDP server design has a critical flaw where it can run into an infinite
741 // request/response loop with the client. Here's the scenario:
742 // - client makes SDP request
743 // - server returns the first fragment of the response with a continuation token
744 // - an SDP record is deleted from the server
745 // - client issues another request with previous continuation token
746 // - server has nothing to send back because the record is unavailable but in the
747 // first fragment, it had specified more response bytes than are now available
748 // - server sends back no additional response bytes and returns the same continuation token
749 // - client issues another request with the continuation token, and the process repeats
750 //
751 // We work around this design flaw here by checking if we will make forward progress
752 // (i.e. we will send > 0 response bytes) on a continued request. If not, we must have
753 // run into the above situation and we tell the peer an error occurred.
754 //
755 // TODO(sharvil): rewrite SDP server.
756 if (is_cont && len_to_send == 0) {
757 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL);
758 return;
759 }
760
The Android Open Source Project5738f832012-12-12 16:00:35 -0800761 /* If first response, insert sequence header */
762 if (!is_cont)
763 {
764 /* Get the total list length for requested uid and attribute sequence */
765 p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
766 /* Put in the sequence header (2 or 3 bytes) */
767 if (p_ccb->list_len > 255)
768 {
Marie Janssend19e0782016-07-15 12:48:27 -0700769 p_ccb->rsp_list[0] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
770 p_ccb->rsp_list[1] = (uint8_t) ((p_ccb->list_len - 3) >> 8);
771 p_ccb->rsp_list[2] = (uint8_t) (p_ccb->list_len - 3);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800772 }
773 else
774 {
775 cont_offset = 1;
776
Marie Janssend19e0782016-07-15 12:48:27 -0700777 p_ccb->rsp_list[1] = (uint8_t) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
778 p_ccb->rsp_list[2] = (uint8_t) (p_ccb->list_len - 3);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800779
780 p_ccb->list_len--;
781 len_to_send--;
782 }
783 }
784
785 /* Get a buffer to use to build the response */
Pavlin Radoslavov717a4a92016-02-06 08:36:06 -0800786 BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800787 p_buf->offset = L2CAP_MIN_OFFSET;
Marie Janssend19e0782016-07-15 12:48:27 -0700788 p_rsp = p_rsp_start = (uint8_t *)(p_buf + 1) + L2CAP_MIN_OFFSET;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800789
790 /* Start building a rsponse */
791 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
792 UINT16_TO_BE_STREAM (p_rsp, trans_num);
793
794 /* Skip the parameter length, add it when we know the length */
795 p_rsp_param_len = p_rsp;
796 p_rsp += 2;
797
798 /* Stream the list length to send */
799 UINT16_TO_BE_STREAM (p_rsp, len_to_send);
800
801 /* copy from rsp_list to the actual buffer to be sent */
802 memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
803 p_rsp += len_to_send;
804
805 p_ccb->cont_offset += len_to_send;
806
807 /* If anything left to send, continuation needed */
808 if (p_ccb->cont_offset < p_ccb->list_len)
809 {
Marie Janssend19e0782016-07-15 12:48:27 -0700810 is_cont = true;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800811
812 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
813 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
814 }
815 else
816 UINT8_TO_BE_STREAM (p_rsp, 0);
817
818 /* Go back and put the parameter length into the buffer */
819 rsp_param_len = p_rsp - p_rsp_param_len - 2;
820 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
821
822 /* Set the length of the SDP data in the buffer */
823 p_buf->len = p_rsp - p_rsp_start;
824
825
826 /* Send the buffer through L2CAP */
827 L2CA_DataWrite (p_ccb->connection_id, p_buf);
828}
829
830#endif /* SDP_SERVER_ENABLED == TRUE */