sdp_server.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845
  1. /******************************************************************************
  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. * This file contains functions that handle the SDP server functions.
  21. * This is mainly dealing with client requests
  22. *
  23. ******************************************************************************/
  24. //#include <stdlib.h>
  25. #include <string.h>
  26. //#include <stdio.h>
  27. #include "gki.h"
  28. #include "bt_types.h"
  29. //#include "bt_utils.h"
  30. #include "btu.h"
  31. #include "bt_defs.h"
  32. #include "l2cdefs.h"
  33. #include "hcidefs.h"
  34. #include "hcimsgs.h"
  35. #include "sdp_api.h"
  36. #include "sdpint.h"
  37. #if SDP_SERVER_ENABLED == TRUE
  38. /* Maximum number of bytes to reserve out of SDP MTU for response data */
  39. #define SDP_MAX_SERVICE_RSPHDR_LEN 12
  40. #define SDP_MAX_SERVATTR_RSPHDR_LEN 10
  41. #define SDP_MAX_ATTR_RSPHDR_LEN 10
  42. /********************************************************************************/
  43. /* L O C A L F U N C T I O N P R O T O T Y P E S */
  44. /********************************************************************************/
  45. static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
  46. UINT16 param_len, UINT8 *p_req,
  47. UINT8 *p_req_end);
  48. static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
  49. UINT16 param_len, UINT8 *p_req,
  50. UINT8 *p_req_end);
  51. static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
  52. UINT16 param_len, UINT8 *p_req,
  53. UINT8 *p_req_end);
  54. /********************************************************************************/
  55. /* E R R O R T E X T S T R I N G S */
  56. /* */
  57. /* The default is to have no text string, but we allow the strings to be */
  58. /* configured in target.h if people want them. */
  59. /********************************************************************************/
  60. #ifndef SDP_TEXT_BAD_HEADER
  61. #define SDP_TEXT_BAD_HEADER NULL
  62. #endif
  63. #ifndef SDP_TEXT_BAD_PDU
  64. #define SDP_TEXT_BAD_PDU NULL
  65. #endif
  66. #ifndef SDP_TEXT_BAD_UUID_LIST
  67. #define SDP_TEXT_BAD_UUID_LIST NULL
  68. #endif
  69. #ifndef SDP_TEXT_BAD_HANDLE
  70. #define SDP_TEXT_BAD_HANDLE NULL
  71. #endif
  72. #ifndef SDP_TEXT_BAD_ATTR_LIST
  73. #define SDP_TEXT_BAD_ATTR_LIST NULL
  74. #endif
  75. #ifndef SDP_TEXT_BAD_CONT_LEN
  76. #define SDP_TEXT_BAD_CONT_LEN NULL
  77. #endif
  78. #ifndef SDP_TEXT_BAD_CONT_INX
  79. #define SDP_TEXT_BAD_CONT_INX NULL
  80. #endif
  81. #ifndef SDP_TEXT_BAD_MAX_RECORDS_LIST
  82. #define SDP_TEXT_BAD_MAX_RECORDS_LIST NULL
  83. #endif
  84. /*******************************************************************************
  85. **
  86. ** Function sdp_server_handle_client_req
  87. **
  88. ** Description This is the main dispatcher of the SDP server. It is called
  89. ** when any data is received from L2CAP, and dispatches the
  90. ** request to the appropriate handler.
  91. **
  92. ** Returns void
  93. **
  94. *******************************************************************************/
  95. void sdp_server_handle_client_req (tCONN_CB *p_ccb, BT_HDR *p_msg)
  96. {
  97. UINT8 *p_req = (UINT8 *) (p_msg + 1) + p_msg->offset;
  98. UINT8 *p_req_end = p_req + p_msg->len;
  99. UINT8 pdu_id;
  100. UINT16 trans_num, param_len;
  101. /* Start inactivity timer */
  102. btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_SDP, SDP_INACT_TIMEOUT);
  103. /* The first byte in the message is the pdu type */
  104. pdu_id = *p_req++;
  105. /* Extract the transaction number and parameter length */
  106. BE_STREAM_TO_UINT16 (trans_num, p_req);
  107. BE_STREAM_TO_UINT16 (param_len, p_req);
  108. if ((p_req + param_len) != p_req_end) {
  109. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_PDU_SIZE, SDP_TEXT_BAD_HEADER);
  110. return;
  111. }
  112. switch (pdu_id) {
  113. case SDP_PDU_SERVICE_SEARCH_REQ:
  114. process_service_search (p_ccb, trans_num, param_len, p_req, p_req_end);
  115. break;
  116. case SDP_PDU_SERVICE_ATTR_REQ:
  117. process_service_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
  118. break;
  119. case SDP_PDU_SERVICE_SEARCH_ATTR_REQ:
  120. process_service_search_attr_req (p_ccb, trans_num, param_len, p_req, p_req_end);
  121. break;
  122. default:
  123. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_PDU);
  124. SDP_TRACE_WARNING ("SDP - server got unknown PDU: 0x%x\n", pdu_id);
  125. break;
  126. }
  127. }
  128. /*******************************************************************************
  129. **
  130. ** Function process_service_search
  131. **
  132. ** Description This function handles a service search request from the
  133. ** client. It builds a reply message with info from the database,
  134. ** and sends the reply back to the client.
  135. **
  136. ** Returns void
  137. **
  138. *******************************************************************************/
  139. static void process_service_search (tCONN_CB *p_ccb, UINT16 trans_num,
  140. UINT16 param_len, UINT8 *p_req,
  141. UINT8 *p_req_end)
  142. {
  143. UINT16 max_replies, cur_handles, rem_handles, cont_offset;
  144. tSDP_UUID_SEQ uid_seq;
  145. UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
  146. UINT16 rsp_param_len, num_rsp_handles, xx;
  147. UINT32 rsp_handles[SDP_MAX_RECORDS] = {0};
  148. tSDP_RECORD *p_rec = NULL;
  149. BT_HDR *p_buf;
  150. BOOLEAN is_cont = FALSE;
  151. UNUSED(p_req_end);
  152. p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
  153. if ((!p_req) || (!uid_seq.num_uids)) {
  154. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
  155. return;
  156. }
  157. /* Get the max replies we can send. Cap it at our max anyways. */
  158. BE_STREAM_TO_UINT16 (max_replies, p_req);
  159. if (max_replies > SDP_MAX_RECORDS) {
  160. max_replies = SDP_MAX_RECORDS;
  161. }
  162. if ((!p_req) || (p_req > p_req_end)) {
  163. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_MAX_RECORDS_LIST);
  164. return;
  165. }
  166. /* Get a list of handles that match the UUIDs given to us */
  167. for (num_rsp_handles = 0; num_rsp_handles < max_replies; ) {
  168. p_rec = sdp_db_service_search (p_rec, &uid_seq);
  169. if (p_rec) {
  170. rsp_handles[num_rsp_handles++] = p_rec->record_handle;
  171. } else {
  172. break;
  173. }
  174. }
  175. /* Check if this is a continuation request */
  176. if (*p_req) {
  177. if (*p_req++ != SDP_CONTINUATION_LEN || (p_req >= p_req_end)) {
  178. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
  179. SDP_TEXT_BAD_CONT_LEN);
  180. return;
  181. }
  182. BE_STREAM_TO_UINT16 (cont_offset, p_req);
  183. if (cont_offset != p_ccb->cont_offset) {
  184. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE,
  185. SDP_TEXT_BAD_CONT_INX);
  186. return;
  187. }
  188. rem_handles = num_rsp_handles - cont_offset; /* extract the remaining handles */
  189. } else {
  190. rem_handles = num_rsp_handles;
  191. cont_offset = 0;
  192. p_ccb->cont_offset = 0;
  193. }
  194. /* Calculate how many handles will fit in one PDU */
  195. cur_handles = (UINT16)((p_ccb->rem_mtu_size - SDP_MAX_SERVICE_RSPHDR_LEN) / 4);
  196. if (rem_handles <= cur_handles) {
  197. cur_handles = rem_handles;
  198. } else { /* Continuation is set */
  199. p_ccb->cont_offset += cur_handles;
  200. is_cont = TRUE;
  201. }
  202. /* Get a buffer to use to build the response */
  203. if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL) {
  204. SDP_TRACE_ERROR ("SDP - no buf for search rsp\n");
  205. return;
  206. }
  207. p_buf->offset = L2CAP_MIN_OFFSET;
  208. p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  209. /* Start building a rsponse */
  210. UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_RSP);
  211. UINT16_TO_BE_STREAM (p_rsp, trans_num);
  212. /* Skip the length, we need to add it at the end */
  213. p_rsp_param_len = p_rsp;
  214. p_rsp += 2;
  215. /* Put in total and current number of handles, and handles themselves */
  216. UINT16_TO_BE_STREAM (p_rsp, num_rsp_handles);
  217. UINT16_TO_BE_STREAM (p_rsp, cur_handles);
  218. /* SDP_TRACE_DEBUG("SDP Service Rsp: tothdl %d, curhdlr %d, start %d, end %d, cont %d",
  219. num_rsp_handles, cur_handles, cont_offset,
  220. cont_offset + cur_handles-1, is_cont); */
  221. for (xx = cont_offset; xx < cont_offset + cur_handles; xx++) {
  222. UINT32_TO_BE_STREAM (p_rsp, rsp_handles[xx]);
  223. }
  224. if (is_cont) {
  225. UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
  226. UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
  227. } else {
  228. UINT8_TO_BE_STREAM (p_rsp, 0);
  229. }
  230. /* Go back and put the parameter length into the buffer */
  231. rsp_param_len = p_rsp - p_rsp_param_len - 2;
  232. UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
  233. /* Set the length of the SDP data in the buffer */
  234. p_buf->len = p_rsp - p_rsp_start;
  235. /* Send the buffer through L2CAP */
  236. L2CA_DataWrite (p_ccb->connection_id, p_buf);
  237. }
  238. /*******************************************************************************
  239. **
  240. ** Function process_service_attr_req
  241. **
  242. ** Description This function handles an attribute request from the client.
  243. ** It builds a reply message with info from the database,
  244. ** and sends the reply back to the client.
  245. **
  246. ** Returns void
  247. **
  248. *******************************************************************************/
  249. static void process_service_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
  250. UINT16 param_len, UINT8 *p_req,
  251. UINT8 *p_req_end)
  252. {
  253. UINT16 max_list_len, len_to_send, cont_offset;
  254. INT16 rem_len;
  255. tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
  256. UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
  257. UINT16 rsp_param_len, xx;
  258. UINT32 rec_handle;
  259. tSDP_RECORD *p_rec;
  260. tSDP_ATTRIBUTE *p_attr;
  261. BT_HDR *p_buf;
  262. BOOLEAN is_cont = FALSE;
  263. UINT16 attr_len;
  264. /* Extract the record handle */
  265. BE_STREAM_TO_UINT32 (rec_handle, p_req);
  266. if (p_req > p_req_end) {
  267. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
  268. return;
  269. }
  270. /* Get the max list length we can send. Cap it at MTU size minus overhead */
  271. BE_STREAM_TO_UINT16 (max_list_len, p_req);
  272. if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN)) {
  273. max_list_len = p_ccb->rem_mtu_size - SDP_MAX_ATTR_RSPHDR_LEN;
  274. }
  275. p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
  276. if ((!p_req) || (!attr_seq.num_attr) || (p_req > p_req_end)) {
  277. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
  278. return;
  279. }
  280. memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
  281. /* Find a record with the record handle */
  282. p_rec = sdp_db_find_record (rec_handle);
  283. if (!p_rec) {
  284. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_SERV_REC_HDL, SDP_TEXT_BAD_HANDLE);
  285. return;
  286. }
  287. /* Check if this is a continuation request */
  288. if (*p_req) {
  289. /* Free and reallocate buffer */
  290. if (p_ccb->rsp_list) {
  291. GKI_freebuf(p_ccb->rsp_list);
  292. }
  293. p_ccb->rsp_list = (UINT8 *)GKI_getbuf(max_list_len);
  294. if (p_ccb->rsp_list == NULL) {
  295. SDP_TRACE_ERROR("%s No scratch buf for attr rsp\n", __func__);
  296. return;
  297. }
  298. if (*p_req++ != SDP_CONTINUATION_LEN) {
  299. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN);
  300. return;
  301. }
  302. BE_STREAM_TO_UINT16 (cont_offset, p_req);
  303. if (cont_offset != p_ccb->cont_offset) {
  304. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX);
  305. return;
  306. }
  307. if (!p_ccb->rsp_list) {
  308. sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
  309. return;
  310. }
  311. is_cont = TRUE;
  312. /* Initialise for continuation response */
  313. p_rsp = &p_ccb->rsp_list[0];
  314. attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = p_ccb->cont_info.next_attr_start_id;
  315. } else {
  316. /* Get a scratch buffer to store response */
  317. if (!p_ccb->rsp_list || (GKI_get_buf_size(p_ccb->rsp_list) < max_list_len)) {
  318. /* Free and reallocate if the earlier allocated buffer is small */
  319. if (p_ccb->rsp_list) {
  320. GKI_freebuf (p_ccb->rsp_list);
  321. }
  322. p_ccb->rsp_list = (UINT8 *)GKI_getbuf (max_list_len);
  323. if (p_ccb->rsp_list == NULL) {
  324. SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp\n");
  325. return;
  326. }
  327. }
  328. p_ccb->cont_offset = 0;
  329. p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
  330. /* Reset continuation parameters in p_ccb */
  331. p_ccb->cont_info.prev_sdp_rec = NULL;
  332. p_ccb->cont_info.next_attr_index = 0;
  333. p_ccb->cont_info.attr_offset = 0;
  334. }
  335. /* Search for attributes that match the list given to us */
  336. for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) {
  337. p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
  338. if (p_attr) {
  339. /* Check if attribute fits. Assume 3-byte value type/length */
  340. rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
  341. /* just in case */
  342. if (rem_len <= 0) {
  343. p_ccb->cont_info.next_attr_index = xx;
  344. p_ccb->cont_info.next_attr_start_id = p_attr->id;
  345. break;
  346. }
  347. attr_len = sdpu_get_attrib_entry_len(p_attr);
  348. /* if there is a partial attribute pending to be sent */
  349. if (p_ccb->cont_info.attr_offset) {
  350. p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
  351. &p_ccb->cont_info.attr_offset);
  352. /* If the partial attrib could not been fully added yet */
  353. if (p_ccb->cont_info.attr_offset != attr_len) {
  354. break;
  355. } else { /* If the partial attrib has been added in full by now */
  356. p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
  357. }
  358. } else if (rem_len < attr_len) { /* Not enough space for attr... so add partially */
  359. if (attr_len >= SDP_MAX_ATTR_LEN) {
  360. SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d\n", max_list_len, attr_len);
  361. sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
  362. return;
  363. }
  364. /* add the partial attribute if possible */
  365. p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
  366. &p_ccb->cont_info.attr_offset);
  367. p_ccb->cont_info.next_attr_index = xx;
  368. p_ccb->cont_info.next_attr_start_id = p_attr->id;
  369. break;
  370. } else { /* build the whole attribute */
  371. p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
  372. }
  373. /* If doing a range, stick with this one till no more attributes found */
  374. if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) {
  375. /* Update for next time through */
  376. attr_seq.attr_entry[xx].start = p_attr->id + 1;
  377. xx--;
  378. }
  379. }
  380. }
  381. /* If all the attributes have been accomodated in p_rsp,
  382. reset next_attr_index */
  383. if (xx == attr_seq.num_attr) {
  384. p_ccb->cont_info.next_attr_index = 0;
  385. }
  386. len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
  387. cont_offset = 0;
  388. if (!is_cont) {
  389. p_ccb->list_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav) + 3;
  390. /* Put in the sequence header (2 or 3 bytes) */
  391. if (p_ccb->list_len > 255) {
  392. p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
  393. p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
  394. p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
  395. } else {
  396. cont_offset = 1;
  397. p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
  398. p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
  399. p_ccb->list_len--;
  400. len_to_send--;
  401. }
  402. }
  403. /* Get a buffer to use to build the response */
  404. if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL) {
  405. SDP_TRACE_ERROR ("SDP - no buf for search rsp\n");
  406. return;
  407. }
  408. p_buf->offset = L2CAP_MIN_OFFSET;
  409. p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  410. /* Start building a rsponse */
  411. UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_ATTR_RSP);
  412. UINT16_TO_BE_STREAM (p_rsp, trans_num);
  413. /* Skip the parameter length, add it when we know the length */
  414. p_rsp_param_len = p_rsp;
  415. p_rsp += 2;
  416. UINT16_TO_BE_STREAM (p_rsp, len_to_send);
  417. memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
  418. p_rsp += len_to_send;
  419. p_ccb->cont_offset += len_to_send;
  420. /* If anything left to send, continuation needed */
  421. if (p_ccb->cont_offset < p_ccb->list_len) {
  422. is_cont = TRUE;
  423. UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
  424. UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
  425. } else {
  426. UINT8_TO_BE_STREAM (p_rsp, 0);
  427. }
  428. /* Go back and put the parameter length into the buffer */
  429. rsp_param_len = p_rsp - p_rsp_param_len - 2;
  430. UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
  431. /* Set the length of the SDP data in the buffer */
  432. p_buf->len = p_rsp - p_rsp_start;
  433. /* Send the buffer through L2CAP */
  434. L2CA_DataWrite (p_ccb->connection_id, p_buf);
  435. }
  436. /*******************************************************************************
  437. **
  438. ** Function process_service_search_attr_req
  439. **
  440. ** Description This function handles a combined service search and attribute
  441. ** read request from the client. It builds a reply message with
  442. ** info from the database, and sends the reply back to the client.
  443. **
  444. ** Returns void
  445. **
  446. *******************************************************************************/
  447. static void process_service_search_attr_req (tCONN_CB *p_ccb, UINT16 trans_num,
  448. UINT16 param_len, UINT8 *p_req,
  449. UINT8 *p_req_end)
  450. {
  451. UINT16 max_list_len;
  452. INT16 rem_len;
  453. UINT16 len_to_send, cont_offset;
  454. tSDP_UUID_SEQ uid_seq;
  455. UINT8 *p_rsp, *p_rsp_start, *p_rsp_param_len;
  456. UINT16 rsp_param_len, xx;
  457. tSDP_RECORD *p_rec;
  458. tSDP_ATTR_SEQ attr_seq, attr_seq_sav;
  459. tSDP_ATTRIBUTE *p_attr;
  460. BT_HDR *p_buf;
  461. BOOLEAN maxxed_out = FALSE, is_cont = FALSE;
  462. UINT8 *p_seq_start;
  463. UINT16 seq_len, attr_len;
  464. UNUSED(p_req_end);
  465. /* Extract the UUID sequence to search for */
  466. p_req = sdpu_extract_uid_seq (p_req, param_len, &uid_seq);
  467. if ((!p_req) || (!uid_seq.num_uids)) {
  468. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_UUID_LIST);
  469. return;
  470. }
  471. /* Get the max list length we can send. Cap it at our max list length. */
  472. BE_STREAM_TO_UINT16 (max_list_len, p_req);
  473. if (max_list_len > (p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN)) {
  474. max_list_len = p_ccb->rem_mtu_size - SDP_MAX_SERVATTR_RSPHDR_LEN;
  475. }
  476. p_req = sdpu_extract_attr_seq (p_req, param_len, &attr_seq);
  477. if ((!p_req) || (!attr_seq.num_attr)) {
  478. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_REQ_SYNTAX, SDP_TEXT_BAD_ATTR_LIST);
  479. return;
  480. }
  481. memcpy(&attr_seq_sav, &attr_seq, sizeof(tSDP_ATTR_SEQ)) ;
  482. /* Check if this is a continuation request */
  483. if (*p_req) {
  484. /* Free and reallocate buffer */
  485. if (p_ccb->rsp_list) {
  486. GKI_freebuf (p_ccb->rsp_list);
  487. }
  488. p_ccb->rsp_list = (UINT8 *)GKI_getbuf (max_list_len);
  489. if (p_ccb->rsp_list == NULL) {
  490. SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp\n");
  491. return;
  492. }
  493. if (*p_req++ != SDP_CONTINUATION_LEN) {
  494. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_LEN);
  495. return;
  496. }
  497. BE_STREAM_TO_UINT16 (cont_offset, p_req);
  498. if (cont_offset != p_ccb->cont_offset) {
  499. sdpu_build_n_send_error (p_ccb, trans_num, SDP_INVALID_CONT_STATE, SDP_TEXT_BAD_CONT_INX);
  500. return;
  501. }
  502. if (!p_ccb->rsp_list) {
  503. sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
  504. return;
  505. }
  506. is_cont = TRUE;
  507. /* Initialise for continuation response */
  508. p_rsp = &p_ccb->rsp_list[0];
  509. attr_seq.attr_entry[p_ccb->cont_info.next_attr_index].start = p_ccb->cont_info.next_attr_start_id;
  510. } else {
  511. /* Get a scratch buffer to store response */
  512. if (!p_ccb->rsp_list || (GKI_get_buf_size(p_ccb->rsp_list) < max_list_len)) {
  513. /* Free and reallocate if the earlier allocated buffer is small */
  514. if (p_ccb->rsp_list) {
  515. GKI_freebuf (p_ccb->rsp_list);
  516. }
  517. p_ccb->rsp_list = (UINT8 *)GKI_getbuf (max_list_len);
  518. if (p_ccb->rsp_list == NULL) {
  519. SDP_TRACE_ERROR ("SDP - no scratch buf for search rsp\n");
  520. return;
  521. }
  522. }
  523. p_ccb->cont_offset = 0;
  524. p_rsp = &p_ccb->rsp_list[3]; /* Leave space for data elem descr */
  525. /* Reset continuation parameters in p_ccb */
  526. p_ccb->cont_info.prev_sdp_rec = NULL;
  527. p_ccb->cont_info.next_attr_index = 0;
  528. p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
  529. p_ccb->cont_info.attr_offset = 0;
  530. }
  531. /* Get a list of handles that match the UUIDs given to us */
  532. 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)) {
  533. /* Allow space for attribute sequence type and length */
  534. p_seq_start = p_rsp;
  535. if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE) {
  536. /* See if there is enough room to include a new service in the current response */
  537. rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
  538. if (rem_len < 3) {
  539. /* Not enough room. Update continuation info for next response */
  540. p_ccb->cont_info.next_attr_index = 0;
  541. p_ccb->cont_info.next_attr_start_id = attr_seq.attr_entry[0].start;
  542. break;
  543. }
  544. p_rsp += 3;
  545. }
  546. /* Get a list of handles that match the UUIDs given to us */
  547. for (xx = p_ccb->cont_info.next_attr_index; xx < attr_seq.num_attr; xx++) {
  548. p_attr = sdp_db_find_attr_in_rec (p_rec, attr_seq.attr_entry[xx].start, attr_seq.attr_entry[xx].end);
  549. if (p_attr) {
  550. /* Check if attribute fits. Assume 3-byte value type/length */
  551. rem_len = max_list_len - (INT16) (p_rsp - &p_ccb->rsp_list[0]);
  552. /* just in case */
  553. if (rem_len <= 0) {
  554. p_ccb->cont_info.next_attr_index = xx;
  555. p_ccb->cont_info.next_attr_start_id = p_attr->id;
  556. maxxed_out = TRUE;
  557. break;
  558. }
  559. attr_len = sdpu_get_attrib_entry_len(p_attr);
  560. /* if there is a partial attribute pending to be sent */
  561. if (p_ccb->cont_info.attr_offset) {
  562. p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, rem_len,
  563. &p_ccb->cont_info.attr_offset);
  564. /* If the partial attrib could not been fully added yet */
  565. if (p_ccb->cont_info.attr_offset != attr_len) {
  566. maxxed_out = TRUE;
  567. break;
  568. } else { /* If the partial attrib has been added in full by now */
  569. p_ccb->cont_info.attr_offset = 0; /* reset attr_offset */
  570. }
  571. } else if (rem_len < attr_len) { /* Not enough space for attr... so add partially */
  572. if (attr_len >= SDP_MAX_ATTR_LEN) {
  573. SDP_TRACE_ERROR("SDP attr too big: max_list_len=%d,attr_len=%d\n", max_list_len, attr_len);
  574. sdpu_build_n_send_error (p_ccb, trans_num, SDP_NO_RESOURCES, NULL);
  575. return;
  576. }
  577. /* add the partial attribute if possible */
  578. p_rsp = sdpu_build_partial_attrib_entry (p_rsp, p_attr, (UINT16)rem_len,
  579. &p_ccb->cont_info.attr_offset);
  580. p_ccb->cont_info.next_attr_index = xx;
  581. p_ccb->cont_info.next_attr_start_id = p_attr->id;
  582. maxxed_out = TRUE;
  583. break;
  584. } else { /* build the whole attribute */
  585. p_rsp = sdpu_build_attrib_entry (p_rsp, p_attr);
  586. }
  587. /* If doing a range, stick with this one till no more attributes found */
  588. if (attr_seq.attr_entry[xx].start != attr_seq.attr_entry[xx].end) {
  589. /* Update for next time through */
  590. attr_seq.attr_entry[xx].start = p_attr->id + 1;
  591. xx--;
  592. }
  593. }
  594. }
  595. /* Go back and put the type and length into the buffer */
  596. if (p_ccb->cont_info.last_attr_seq_desc_sent == FALSE) {
  597. seq_len = sdpu_get_attrib_seq_len(p_rec, &attr_seq_sav);
  598. if (seq_len != 0) {
  599. UINT8_TO_BE_STREAM (p_seq_start, (DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
  600. UINT16_TO_BE_STREAM (p_seq_start, seq_len);
  601. if (maxxed_out) {
  602. p_ccb->cont_info.last_attr_seq_desc_sent = TRUE;
  603. }
  604. } else {
  605. p_rsp = p_seq_start;
  606. }
  607. }
  608. if (maxxed_out) {
  609. break;
  610. }
  611. /* Restore the attr_seq to look for in the next sdp record */
  612. memcpy(&attr_seq, &attr_seq_sav, sizeof(tSDP_ATTR_SEQ)) ;
  613. /* Reset the next attr index */
  614. p_ccb->cont_info.next_attr_index = 0;
  615. p_ccb->cont_info.prev_sdp_rec = p_rec;
  616. p_ccb->cont_info.last_attr_seq_desc_sent = FALSE;
  617. }
  618. /* response length */
  619. len_to_send = (UINT16) (p_rsp - &p_ccb->rsp_list[0]);
  620. cont_offset = 0;
  621. // The current SDP server design has a critical flaw where it can run into an infinite
  622. // request/response loop with the client. Here's the scenario:
  623. // - client makes SDP request
  624. // - server returns the first fragment of the response with a continuation token
  625. // - an SDP record is deleted from the server
  626. // - client issues another request with previous continuation token
  627. // - server has nothing to send back because the record is unavailable but in the
  628. // first fragment, it had specified more response bytes than are now available
  629. // - server sends back no additional response bytes and returns the same continuation token
  630. // - client issues another request with the continuation token, and the process repeats
  631. //
  632. // We work around this design flaw here by checking if we will make forward progress
  633. // (i.e. we will send > 0 response bytes) on a continued request. If not, we must have
  634. // run into the above situation and we tell the peer an error occurred.
  635. //
  636. // TODO(sharvil): rewrite SDP server.
  637. if (is_cont && len_to_send == 0) {
  638. sdpu_build_n_send_error(p_ccb, trans_num, SDP_INVALID_CONT_STATE, NULL);
  639. return;
  640. }
  641. /* If first response, insert sequence header */
  642. if (!is_cont) {
  643. /* Get the total list length for requested uid and attribute sequence */
  644. p_ccb->list_len = sdpu_get_list_len(&uid_seq, &attr_seq_sav) + 3;
  645. /* Put in the sequence header (2 or 3 bytes) */
  646. if (p_ccb->list_len > 255) {
  647. p_ccb->rsp_list[0] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_WORD);
  648. p_ccb->rsp_list[1] = (UINT8) ((p_ccb->list_len - 3) >> 8);
  649. p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
  650. } else {
  651. cont_offset = 1;
  652. p_ccb->rsp_list[1] = (UINT8) ((DATA_ELE_SEQ_DESC_TYPE << 3) | SIZE_IN_NEXT_BYTE);
  653. p_ccb->rsp_list[2] = (UINT8) (p_ccb->list_len - 3);
  654. p_ccb->list_len--;
  655. len_to_send--;
  656. }
  657. }
  658. /* Get a buffer to use to build the response */
  659. if ((p_buf = (BT_HDR *)GKI_getpoolbuf (SDP_POOL_ID)) == NULL) {
  660. SDP_TRACE_ERROR ("SDP - no buf for search rsp\n");
  661. return;
  662. }
  663. p_buf->offset = L2CAP_MIN_OFFSET;
  664. p_rsp = p_rsp_start = (UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
  665. /* Start building a rsponse */
  666. UINT8_TO_BE_STREAM (p_rsp, SDP_PDU_SERVICE_SEARCH_ATTR_RSP);
  667. UINT16_TO_BE_STREAM (p_rsp, trans_num);
  668. /* Skip the parameter length, add it when we know the length */
  669. p_rsp_param_len = p_rsp;
  670. p_rsp += 2;
  671. /* Stream the list length to send */
  672. UINT16_TO_BE_STREAM (p_rsp, len_to_send);
  673. /* copy from rsp_list to the actual buffer to be sent */
  674. memcpy (p_rsp, &p_ccb->rsp_list[cont_offset], len_to_send);
  675. p_rsp += len_to_send;
  676. p_ccb->cont_offset += len_to_send;
  677. /* If anything left to send, continuation needed */
  678. if (p_ccb->cont_offset < p_ccb->list_len) {
  679. is_cont = TRUE;
  680. UINT8_TO_BE_STREAM (p_rsp, SDP_CONTINUATION_LEN);
  681. UINT16_TO_BE_STREAM (p_rsp, p_ccb->cont_offset);
  682. } else {
  683. UINT8_TO_BE_STREAM (p_rsp, 0);
  684. }
  685. /* Go back and put the parameter length into the buffer */
  686. rsp_param_len = p_rsp - p_rsp_param_len - 2;
  687. UINT16_TO_BE_STREAM (p_rsp_param_len, rsp_param_len);
  688. /* Set the length of the SDP data in the buffer */
  689. p_buf->len = p_rsp - p_rsp_start;
  690. /* Send the buffer through L2CAP */
  691. L2CA_DataWrite (p_ccb->connection_id, p_buf);
  692. }
  693. #endif /* SDP_SERVER_ENABLED == TRUE */