blob: 100d35b6370aacfe1ab2977f072fafd2e2684265 [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
Hansong Zhang968df7a2018-01-09 19:43:20 -080026#include <cutils/log.h>
27
The Android Open Source Project5738f832012-12-12 16:00:35 -080028#include <stdlib.h>
29#include <string.h>
30#include <stdio.h>
31
Pavlin Radoslavov258c2532015-09-27 20:59:05 -070032#include "bt_common.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080033#include "bt_types.h"
Mike J. Chen5cd8bff2014-01-31 18:16:59 -080034#include "bt_utils.h"
The Android Open Source Project5738f832012-12-12 16:00:35 -080035#include "btu.h"
36
37#include "l2cdefs.h"
38#include "hcidefs.h"
39#include "hcimsgs.h"
40
41#include "sdp_api.h"
42#include "sdpint.h"
43
44
45#if SDP_SERVER_ENABLED == TRUE
46
Pavlin Radoslavov78bcff72015-12-04 17:36:34 -080047extern fixed_queue_t *btu_general_alarm_queue;
48
The Android Open Source Project5738f832012-12-12 16:00:35 -080049/* Maximum number of bytes to reserve out of SDP MTU for response data */
50#define SDP_MAX_SERVICE_RSPHDR_LEN 12
51#define SDP_MAX_SERVATTR_RSPHDR_LEN 10
52#define SDP_MAX_ATTR_RSPHDR_LEN 10
53
54/********************************************************************************/
55/* L O C A L F U N C T I O N P R O T O T Y P E S */
56/********************************************************************************/
57static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
58 UINT16 param_len, UINT8 *p_req,
59 UINT8 *p_req_end);
60
61static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
62 UINT16 param_len, UINT8 *p_req,
63 UINT8 *p_req_end);
64
65static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
66 UINT16 param_len, UINT8 *p_req,
67 UINT8 *p_req_end);
68
69
70/********************************************************************************/
71/* E R R O R T E X T S T R I N G S */
72/* */
73/* The default is to have no text string, but we allow the strings to be */
74/* configured in target.h if people want them. */
75/********************************************************************************/
76#ifndef SDP_TEXT_BAD_HEADER
77#define SDP_TEXT_BAD_HEADER NULL
78#endif
79
80#ifndef SDP_TEXT_BAD_PDU
81#define SDP_TEXT_BAD_PDU NULL
82#endif
83
84#ifndef SDP_TEXT_BAD_UUID_LIST
85#define SDP_TEXT_BAD_UUID_LIST NULL
86#endif
87
88#ifndef SDP_TEXT_BAD_HANDLE
89#define SDP_TEXT_BAD_HANDLE NULL
90#endif
91
92#ifndef SDP_TEXT_BAD_ATTR_LIST
93#define SDP_TEXT_BAD_ATTR_LIST NULL
94#endif
95
96#ifndef SDP_TEXT_BAD_CONT_LEN
97#define SDP_TEXT_BAD_CONT_LEN NULL
98#endif
99
100#ifndef SDP_TEXT_BAD_CONT_INX
101#define SDP_TEXT_BAD_CONT_INX NULL
102#endif
103
Hemant Gupta86225e42014-01-23 18:38:44 +0530104#ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
105#define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL
106#endif
107
The Android Open Source Project5738f832012-12-12 16:00:35 -0800108/*******************************************************************************
109**
110** Function sdp_server_handle_client_req
111**
112** Description This is the main dispatcher of the SDP server. It is called
113** when any data is received from L2CAP, and dispatches the
114** request to the appropriate handler.
115**
116** Returns void
117**
118*******************************************************************************/
119void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
120{
121 UINT8 *p_req = (UINT8 *) (p_msg + 1) + p_msg->offset;
122 UINT8 *p_req_end = p_req + p_msg->len;
123 UINT8 pdu_id;
124 UINT16 trans_num, param_len;
125
126
127 /* Start inactivity timer */
Pavlin Radoslavov78bcff72015-12-04 17:36:34 -0800128 alarm_set_on_queue(p_ccb->sdp_conn_timer, SDP_INACT_TIMEOUT_MS,
129 sdp_conn_timer_timeout, p_ccb, btu_general_alarm_queue);
Myles Watsond321b132018-01-11 17:43:40 -0800130 if (p_req + sizeof(pdu_id) + sizeof(trans_num) > p_req_end) {
131 android_errorWriteLog(0x534e4554, "69384124");
132 trans_num = 0;
133 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
134 SDP_TEXT_BAD_HEADER);
135 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800136
137 /* The first byte in the message is the pdu type */
138 pdu_id = *p_req++;
139
140 /* Extract the transaction number and parameter length */
141 BE_STREAM_TO_UINT16 (trans_num, p_req);
Myles Watsond321b132018-01-11 17:43:40 -0800142
143 if (p_req + sizeof(param_len) > p_req_end) {
144 android_errorWriteLog(0x534e4554, "69384124");
145 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX,
146 SDP_TEXT_BAD_HEADER);
147 }
148
The Android Open Source Project5738f832012-12-12 16:00:35 -0800149 BE_STREAM_TO_UINT16 (param_len, p_req);
150
Kim Schulz107660f2013-09-24 09:52:52 +0200151 if ((p_req + param_len) != p_req_end)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800152 {
153 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
154 return;
155 }
156
157 switch (pdu_id)
158 {
159 case SDP_PDU_SERVICE_SEARCH_REQ:
160 process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end);
161 break;
162
163 case SDP_PDU_SERVICE_ATTR_REQ:
164 process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
165 break;
166
167 case SDP_PDU_SERVICE_SEARCH_ATTR_REQ:
168 process_service_search_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
169 break;
170
171 default:
172 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_PDU);
Sharvil Nanavatia51c9d92014-05-04 01:08:21 -0700173 SDP_TRACE_WARNING ("SDP - server got unknown PDU: 0x%x", pdu_id);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800174 break;
175 }
176}
177
178
179
180/*******************************************************************************
181**
182** Function process_service_search
183**
184** Description This function handles a service search request from the
185** client. It builds a reply message with info from the database,
186** and sends the reply back to the client.
187**
188** Returns void
189**
190*******************************************************************************/
191static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
192 UINT16 param_len, UINT8 *p_req,
193 UINT8 *p_req_end)
194{
195 UINT16 max_replies, cur_handles, rem_handles, cont_offset;
196 tSDP_UUID_SEQ uid_seq;
197 UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
198 UINT16 rsp_param_len, num_rsp_handles, xx;
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800199 UINT32 rsp_handles[SDP_MAX_RECORDS] = {0};
The Android Open Source Project5738f832012-12-12 16:00:35 -0800200 tSDP_RECORD *p_rec = NULL;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800201 BOOLEAN is_cont = FALSE;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800202 UNUSED(p_req_end);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800203
204 p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
205
206 if ((!p_req) || (!uid_seq.num_uids))
207 {
208 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
209 return;
210 }
211
212 /* Get the max replies we can send. Cap it at our max anyways. */
Myles Watsond321b132018-01-11 17:43:40 -0800213 if (p_req + sizeof(max_replies) + sizeof(uint8_t) > p_req_end) {
214 android_errorWriteLog(0x534e4554, "69384124");
215 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
216 return;
217 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800218 BE_STREAM_TO_UINT16 (max_replies, p_req);
219
220 if (max_replies > SDP_MAX_RECORDS)
221 max_replies = SDP_MAX_RECORDS;
222
Hemant Gupta86225e42014-01-23 18:38:44 +0530223
Hemant Gupta86225e42014-01-23 18:38:44 +0530224
225
The Android Open Source Project5738f832012-12-12 16:00:35 -0800226 /* Get a list of handles that match the UUIDs given to us */
227 for (num_rsp_handles = 0; num_rsp_handles < max_replies; )
228 {
229 p_rec = sdp_db_service_search (p_rec, &uid_seq);
230
231 if (p_rec)
232 rsp_handles[num_rsp_handles++] = p_rec->record_handle;
233 else
234 break;
235 }
236
237 /* Check if this is a continuation request */
238 if (*p_req)
239 {
Myles Watsond321b132018-01-11 17:43:40 -0800240 if (*p_req++ != SDP_CONTINUATION_LEN ||
241 (p_req + sizeof(cont_offset) > p_req_end)) {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800242 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
243 SDP_TEXT_BAD_CONT_LEN);
244 return;
245 }
246 BE_STREAM_TO_UINT16 (cont_offset, p_req);
247
Pavlin Radoslavov34883642017-07-12 18:56:03 -0700248 if (cont_offset != p_ccb->cont_offset || num_rsp_handles < cont_offset)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800249 {
250 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
251 SDP_TEXT_BAD_CONT_INX);
252 return;
253 }
254
255 rem_handles = num_rsp_handles - cont_offset; /* extract the remaining handles */
256 }
257 else
258 {
259 rem_handles = num_rsp_handles;
260 cont_offset = 0;
Simon Wilsondc69e2d2015-04-02 15:17:08 -0700261 p_ccb->cont_offset = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800262 }
263
264 /* Calculate how many handles will fit in one PDU */
265 cur_handles = (UINT16)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);
266
267 if (rem_handles <= cur_handles)
268 cur_handles = rem_handles;
269 else /* Continuation is set */
270 {
271 p_ccb->cont_offset += cur_handles;
272 is_cont = TRUE;
273 }
274
275 /* Get a buffer to use to build the response */
Pavlin Radoslavov5fe6f0c2016-02-06 08:36:06 -0800276 BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800277 p_buf->offset = L2CAP_MIN_OFFSET;
278 p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
279
280 /* Start building a rsponse */
281 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_RSP);
282 UINT16_TO_BE_STREAM (p_rsp, trans_num);
283
284 /* Skip the length, we need to add it at the end */
285 p_rsp_param_len = p_rsp;
286 p_rsp += 2;
287
288 /* Put in total and current number of handles, and handles themselves */
289 UINT16_TO_BE_STREAM (p_rsp, num_rsp_handles);
290 UINT16_TO_BE_STREAM (p_rsp, cur_handles);
291
Sharvil Nanavatia51c9d92014-05-04 01:08:21 -0700292/* 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 -0800293 num_rsp_handles, cur_handles, cont_offset,
294 cont_offset + cur_handles-1, is_cont); */
295 for (xx = cont_offset; xx < cont_offset + cur_handles; xx++)
296 UINT32_TO_BE_STREAM (p_rsp, rsp_handles[xx]);
297
298 if (is_cont)
299 {
300 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
301 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
302 }
303 else
304 UINT8_TO_BE_STREAM (p_rsp, 0);
305
306 /* Go back and put the parameter length into the buffer */
307 rsp_param_len = p_rsp - p_rsp_param_len - 2;
308 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
309
310 /* Set the length of the SDP data in the buffer */
311 p_buf->len = p_rsp - p_rsp_start;
312
313
314 /* Send the buffer through L2CAP */
315 L2CA_DataWrite (p_ccb->connection_id, p_buf);
316}
317
318
319/*******************************************************************************
320**
321** Function process_service_attr_req
322**
323** Description This function handles an attribute request from the client.
324** It builds a reply message with info from the database,
325** and sends the reply back to the client.
326**
327** Returns void
328**
329*******************************************************************************/
330static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
331 UINT16 param_len, UINT8 *p_req,
332 UINT8 *p_req_end)
333{
334 UINT16 max_list_len, len_to_send, cont_offset;
335 INT16 rem_len;
336 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
337 UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
338 UINT16 rsp_param_len, xx;
339 UINT32 rec_handle;
340 tSDP_RECORD *p_rec;
341 tSDP_ATTRIBUTE *p_attr;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800342 BOOLEAN is_cont = FALSE;
343 UINT16 attr_len;
344
Myles Watsond321b132018-01-11 17:43:40 -0800345 if (p_req + sizeof(rec_handle) + sizeof(max_list_len) > p_req_end) {
346 android_errorWriteLog(0x534e4554, "69384124");
347 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL,
348 SDP_TEXT_BAD_HANDLE);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800349 return;
350 }
351
Myles Watsond321b132018-01-11 17:43:40 -0800352 /* Extract the record handle */
353 BE_STREAM_TO_UINT32 (rec_handle, p_req);
Jakub Pawlowski76e96282018-05-29 16:25:56 -0700354 param_len -= sizeof(rec_handle);
Myles Watsond321b132018-01-11 17:43:40 -0800355
The Android Open Source Project5738f832012-12-12 16:00:35 -0800356 /* Get the max list length we can send. Cap it at MTU size minus overhead */
357 BE_STREAM_TO_UINT16 (max_list_len, p_req);
Jakub Pawlowski76e96282018-05-29 16:25:56 -0700358 param_len -= sizeof(max_list_len);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800359
360 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN))
361 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
362
Myles Watsonca8a83b2018-05-29 16:55:58 -0700363 param_len = (UINT16)(p_req_end - p_req);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800364 p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
365
Myles Watsond321b132018-01-11 17:43:40 -0800366 if ((!p_req) || (!attr_seq.num_attr) ||
367 (p_req + sizeof(uint8_t) > p_req_end)) {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800368 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
369 return;
370 }
371
372 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
373
374 /* Find a record with the record handle */
375 p_rec = sdp_db_find_record (rec_handle);
376 if (!p_rec)
377 {
378 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
379 return;
380 }
381
Hansong Zhang968df7a2018-01-09 19:43:20 -0800382 if (max_list_len < 4) {
383 sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
384 android_errorWriteLog(0x534e4554, "68776054");
385 return;
386 }
387
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800388 /* Free and reallocate buffer */
Pavlin Radoslavovabd70ab2016-02-05 13:54:43 -0800389 osi_free(p_ccb->rsp_list);
390 p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800391
The Android Open Source Project5738f832012-12-12 16:00:35 -0800392 /* Check if this is a continuation request */
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800393 if (*p_req) {
Myles Watsond321b132018-01-11 17:43:40 -0800394 if (*p_req++ != SDP_CONTINUATION_LEN ||
395 (p_req + sizeof(cont_offset) > p_req_end)) {
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800396 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
397 SDP_TEXT_BAD_CONT_LEN);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800398 return;
399 }
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800400 BE_STREAM_TO_UINT16(cont_offset, p_req);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800401
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800402 if (cont_offset != p_ccb->cont_offset) {
403 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
404 SDP_TEXT_BAD_CONT_INX);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800405 return;
406 }
407 is_cont = TRUE;
408
409 /* Initialise for continuation response */
410 p_rsp = &p_ccb->rsp_list[0];
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800411 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
412 p_ccb->cont_info.next_attr_start_id;
413 } else {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800414 p_ccb->cont_offset = 0;
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800415 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800416
417 /* Reset continuation parameters in p_ccb */
418 p_ccb->cont_info.prev_sdp_rec = NULL;
419 p_ccb->cont_info.next_attr_index = 0;
420 p_ccb->cont_info.attr_offset = 0;
421 }
422
423 /* Search for attributes that match the list given to us */
424 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
425 {
426 p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
427
428 if (p_attr)
429 {
430 /* Check if attribute fits. Assume 3-byte value type/length */
431 rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
432
433 /* just in case */
434 if (rem_len <= 0)
435 {
436 p_ccb->cont_info.next_attr_index = xx;
437 p_ccb->cont_info.next_attr_start_id = p_attr->id;
438 break;
439 }
440
441 attr_len = sdpu_get_attrib_entry_len(p_attr);
442 /* if there is a partial attribute pending to be sent */
443 if (p_ccb->cont_info.attr_offset)
444 {
445 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
446 &p_ccb->cont_info.attr_offset);
447
448 /* If the partial attrib could not been fully added yet */
449 if (p_ccb->cont_info.attr_offset != attr_len)
450 break;
451 else /* If the partial attrib has been added in full by now */
452 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
453 }
454 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
455 {
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800456 if (attr_len >= SDP_MAX_ATTR_LEN)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800457 {
Sharvil Nanavatia51c9d92014-05-04 01:08:21 -0700458 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 -0800459 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
460 return;
461 }
462
463 /* add the partial attribute if possible */
464 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
465 &p_ccb->cont_info.attr_offset);
466
467 p_ccb->cont_info.next_attr_index = xx;
468 p_ccb->cont_info.next_attr_start_id = p_attr->id;
469 break;
470 }
471 else /* build the whole attribute */
472 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
473
474 /* If doing a range, stick with this one till no more attributes found */
475 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
476 {
477 /* Update for next time through */
478 attr_seq.attr_entry[xx].start = p_attr->id + 1;
479
480 xx--;
481 }
482 }
483 }
484 /* If all the attributes have been accomodated in p_rsp,
485 reset next_attr_index */
486 if (xx == attr_seq.num_attr)
487 p_ccb->cont_info.next_attr_index = 0;
488
489 len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
490 cont_offset = 0;
491
492 if (!is_cont)
493 {
494 p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3;
495 /* Put in the sequence header (2 or 3 bytes) */
496 if (p_ccb->list_len > 255)
497 {
498 p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
499 p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
500 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
501 }
502 else
503 {
504 cont_offset = 1;
505
506 p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
507 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
508
509 p_ccb->list_len--;
510 len_to_send--;
511 }
512 }
513
514 /* Get a buffer to use to build the response */
Pavlin Radoslavov5fe6f0c2016-02-06 08:36:06 -0800515 BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800516 p_buf->offset = L2CAP_MIN_OFFSET;
517 p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
518
519 /* Start building a rsponse */
520 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
521 UINT16_TO_BE_STREAM (p_rsp, trans_num);
522
523 /* Skip the parameter length, add it when we know the length */
524 p_rsp_param_len = p_rsp;
525 p_rsp += 2;
526
527 UINT16_TO_BE_STREAM (p_rsp, len_to_send);
528
529 memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
530 p_rsp += len_to_send;
531
532 p_ccb->cont_offset += len_to_send;
533
534 /* If anything left to send, continuation needed */
535 if (p_ccb->cont_offset < p_ccb->list_len)
536 {
537 is_cont = TRUE;
538
539 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
540 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
541 }
542 else
543 UINT8_TO_BE_STREAM (p_rsp, 0);
544
545 /* Go back and put the parameter length into the buffer */
546 rsp_param_len = p_rsp - p_rsp_param_len - 2;
547 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
548
549 /* Set the length of the SDP data in the buffer */
550 p_buf->len = p_rsp - p_rsp_start;
551
552
553 /* Send the buffer through L2CAP */
554 L2CA_DataWrite (p_ccb->connection_id, p_buf);
555}
556
557
558
559/*******************************************************************************
560**
561** Function process_service_search_attr_req
562**
563** Description This function handles a combined service search and attribute
564** read request from the client. It builds a reply message with
565** info from the database, and sends the reply back to the client.
566**
567** Returns void
568**
569*******************************************************************************/
570static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
571 UINT16 param_len, UINT8 *p_req,
572 UINT8 *p_req_end)
573{
574 UINT16 max_list_len;
575 INT16 rem_len;
576 UINT16 len_to_send, cont_offset;
577 tSDP_UUID_SEQ uid_seq;
578 UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
579 UINT16 rsp_param_len, xx;
580 tSDP_RECORD *p_rec;
581 tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
582 tSDP_ATTRIBUTE *p_attr;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800583 BOOLEAN maxxed_out = FALSE, is_cont = FALSE;
584 UINT8 *p_seq_start;
585 UINT16 seq_len, attr_len;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800586 UNUSED(p_req_end);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800587
588 /* Extract the UUID sequence to search for */
589 p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
590
Myles Watsond321b132018-01-11 17:43:40 -0800591 if ((!p_req) || (!uid_seq.num_uids) ||
592 (p_req + sizeof(uint16_t) > p_req_end)) {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800593 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
594 return;
595 }
596
597 /* Get the max list length we can send. Cap it at our max list length. */
598 BE_STREAM_TO_UINT16 (max_list_len, p_req);
599
600 if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN))
601 max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
602
603 p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
604
Myles Watsond321b132018-01-11 17:43:40 -0800605 if ((!p_req) || (!attr_seq.num_attr) ||
606 (p_req + sizeof(uint8_t) > p_req_end)) {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800607 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
608 return;
609 }
610
611 memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
612
Hansong Zhang968df7a2018-01-09 19:43:20 -0800613 if (max_list_len < 4) {
614 sdpu_build_n_send_error(p_ccb, trans_num, SDP_ILLEGAL_PARAMETER, NULL);
615 android_errorWriteLog(0x534e4554, "68817966");
616 return;
617 }
618
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800619 /* Free and reallocate buffer */
Pavlin Radoslavovabd70ab2016-02-05 13:54:43 -0800620 osi_free(p_ccb->rsp_list);
621 p_ccb->rsp_list = (UINT8 *)osi_malloc(max_list_len);
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800622
The Android Open Source Project5738f832012-12-12 16:00:35 -0800623 /* Check if this is a continuation request */
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800624 if (*p_req) {
Myles Watsond321b132018-01-11 17:43:40 -0800625 if (*p_req++ != SDP_CONTINUATION_LEN ||
626 (p_req + sizeof(uint16_t) > p_req_end)) {
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800627 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE,
628 SDP_TEXT_BAD_CONT_LEN);
Srinu Jellac0532302014-12-22 19:46:28 +0530629 return;
630 }
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800631 BE_STREAM_TO_UINT16(cont_offset, p_req);
Srinu Jellac0532302014-12-22 19:46:28 +0530632
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800633 if (cont_offset != p_ccb->cont_offset) {
634 sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
635 SDP_TEXT_BAD_CONT_INX);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800636 return;
637 }
638 is_cont = TRUE;
639
640 /* Initialise for continuation response */
641 p_rsp = &p_ccb->rsp_list[0];
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800642 attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start =
643 p_ccb->cont_info.next_attr_start_id;
644 } else {
The Android Open Source Project5738f832012-12-12 16:00:35 -0800645 p_ccb->cont_offset = 0;
Pavlin Radoslavovca57b252016-02-04 18:20:06 -0800646 p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
The Android Open Source Project5738f832012-12-12 16:00:35 -0800647
648 /* Reset continuation parameters in p_ccb */
649 p_ccb->cont_info.prev_sdp_rec = NULL;
650 p_ccb->cont_info.next_attr_index = 0;
651 p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
652 p_ccb->cont_info.attr_offset = 0;
653 }
654
655 /* Get a list of handles that match the UUIDs given to us */
656 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))
657 {
658 /* Allow space for attribute sequence type and length */
659 p_seq_start = p_rsp;
660 if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
661 {
662 /* See if there is enough room to include a new service in the current response */
663 rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
664 if (rem_len < 3)
665 {
666 /* Not enough room. Update continuation info for next response */
667 p_ccb->cont_info.next_attr_index = 0;
668 p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
669 break;
670 }
671 p_rsp += 3;
672 }
673
674 /* Get a list of handles that match the UUIDs given to us */
675 for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++)
676 {
677 p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
678
679 if (p_attr)
680 {
681 /* Check if attribute fits. Assume 3-byte value type/length */
682 rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
683
684 /* just in case */
685 if (rem_len <= 0)
686 {
687 p_ccb->cont_info.next_attr_index = xx;
688 p_ccb->cont_info.next_attr_start_id = p_attr->id;
689 maxxed_out = TRUE;
690 break;
691 }
692
693 attr_len = sdpu_get_attrib_entry_len(p_attr);
694 /* if there is a partial attribute pending to be sent */
695 if (p_ccb->cont_info.attr_offset)
696 {
697 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
698 &p_ccb->cont_info.attr_offset);
699
700 /* If the partial attrib could not been fully added yet */
701 if (p_ccb->cont_info.attr_offset != attr_len)
702 {
703 maxxed_out = TRUE;
704 break;
705 }
706 else /* If the partial attrib has been added in full by now */
707 p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
708 }
709 else if (rem_len < attr_len) /* Not enough space for attr... so add partially */
710 {
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800711 if (attr_len >= SDP_MAX_ATTR_LEN)
The Android Open Source Project5738f832012-12-12 16:00:35 -0800712 {
Sharvil Nanavatia51c9d92014-05-04 01:08:21 -0700713 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 -0800714 sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
715 return;
716 }
717
718 /* add the partial attribute if possible */
719 p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
720 &p_ccb->cont_info.attr_offset);
721
722 p_ccb->cont_info.next_attr_index = xx;
723 p_ccb->cont_info.next_attr_start_id = p_attr->id;
724 maxxed_out = TRUE;
725 break;
726 }
727 else /* build the whole attribute */
728 p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
729
730 /* If doing a range, stick with this one till no more attributes found */
731 if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end)
732 {
733 /* Update for next time through */
734 attr_seq.attr_entry[xx].start = p_attr->id + 1;
735
736 xx--;
737 }
738 }
739 }
740
741 /* Go back and put the type and length into the buffer */
742 if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE)
743 {
744 seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
745 if (seq_len != 0)
746 {
747 UINT8_TO_BE_STREAM (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
748 UINT16_TO_BE_STREAM (p_seq_start, seq_len);
749
750 if (maxxed_out)
751 p_ccb->cont_info.last_attr_seq_desc_sent = TRUE;
752 }
753 else
754 p_rsp = p_seq_start;
755 }
756
757 if (maxxed_out)
758 break;
759
760 /* Restore the attr_seq to look for in the next sdp record */
761 memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ;
762
763 /* Reset the next attr index */
764 p_ccb->cont_info.next_attr_index = 0;
765 p_ccb->cont_info.prev_sdp_rec = p_rec;
766 p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
767 }
768
769 /* response length */
770 len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
771 cont_offset = 0;
772
Sharvil Nanavati54966dc2014-11-15 00:17:35 -0800773 // The current SDP server design has a critical flaw where it can run into an infinite
774 // request/response loop with the client. Here's the scenario:
775 // - client makes SDP request
776 // - server returns the first fragment of the response with a continuation token
777 // - an SDP record is deleted from the server
778 // - client issues another request with previous continuation token
779 // - server has nothing to send back because the record is unavailable but in the
780 // first fragment, it had specified more response bytes than are now available
781 // - server sends back no additional response bytes and returns the same continuation token
782 // - client issues another request with the continuation token, and the process repeats
783 //
784 // We work around this design flaw here by checking if we will make forward progress
785 // (i.e. we will send > 0 response bytes) on a continued request. If not, we must have
786 // run into the above situation and we tell the peer an error occurred.
787 //
788 // TODO(sharvil): rewrite SDP server.
789 if (is_cont && len_to_send == 0) {
790 sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL);
791 return;
792 }
793
The Android Open Source Project5738f832012-12-12 16:00:35 -0800794 /* If first response, insert sequence header */
795 if (!is_cont)
796 {
797 /* Get the total list length for requested uid and attribute sequence */
798 p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
799 /* Put in the sequence header (2 or 3 bytes) */
800 if (p_ccb->list_len > 255)
801 {
802 p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
803 p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
804 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
805 }
806 else
807 {
808 cont_offset = 1;
809
810 p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
811 p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
812
813 p_ccb->list_len--;
814 len_to_send--;
815 }
816 }
817
818 /* Get a buffer to use to build the response */
Pavlin Radoslavov5fe6f0c2016-02-06 08:36:06 -0800819 BT_HDR *p_buf = (BT_HDR *)osi_malloc(SDP_DATA_BUF_SIZE);
The Android Open Source Project5738f832012-12-12 16:00:35 -0800820 p_buf->offset = L2CAP_MIN_OFFSET;
821 p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
822
823 /* Start building a rsponse */
824 UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
825 UINT16_TO_BE_STREAM (p_rsp, trans_num);
826
827 /* Skip the parameter length, add it when we know the length */
828 p_rsp_param_len = p_rsp;
829 p_rsp += 2;
830
831 /* Stream the list length to send */
832 UINT16_TO_BE_STREAM (p_rsp, len_to_send);
833
834 /* copy from rsp_list to the actual buffer to be sent */
835 memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
836 p_rsp += len_to_send;
837
838 p_ccb->cont_offset += len_to_send;
839
840 /* If anything left to send, continuation needed */
841 if (p_ccb->cont_offset < p_ccb->list_len)
842 {
843 is_cont = TRUE;
844
845 UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
846 UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
847 }
848 else
849 UINT8_TO_BE_STREAM (p_rsp, 0);
850
851 /* Go back and put the parameter length into the buffer */
852 rsp_param_len = p_rsp - p_rsp_param_len - 2;
853 UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
854
855 /* Set the length of the SDP data in the buffer */
856 p_buf->len = p_rsp - p_rsp_start;
857
858
859 /* Send the buffer through L2CAP */
860 L2CA_DataWrite (p_ccb->connection_id, p_buf);
861}
862
863#endif /* SDP_SERVER_ENABLED == TRUE */