sdp_api.c 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242
  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 SDP interface functions
  21. *
  22. ******************************************************************************/
  23. //#include <stdlib.h>
  24. #include <string.h>
  25. //#include <stdio.h>
  26. #include "common/bt_target.h"
  27. //#include "bt_utils.h"
  28. #include "stack/l2cdefs.h"
  29. #include "stack/hcidefs.h"
  30. #include "stack/hcimsgs.h"
  31. #include "common/bt_defs.h"
  32. #include "stack/sdp_api.h"
  33. #include "sdpint.h"
  34. #include "stack/btu.h"
  35. #if (SDP_INCLUDED == TRUE)
  36. /**********************************************************************
  37. ** C L I E N T F U N C T I O N P R O T O T Y P E S *
  38. ***********************************************************************/
  39. /*******************************************************************************
  40. **
  41. ** Function SDP_InitDiscoveryDb
  42. **
  43. ** Description This function is called to initialize a discovery database.
  44. **
  45. ** Parameters: p_db - (input) address of an area of memory where the
  46. ** discovery database is managed.
  47. ** len - (input) size (in bytes) of the memory
  48. ** NOTE: This must be larger than sizeof(tSDP_DISCOVERY_DB)
  49. ** num_uuid - (input) number of UUID filters applied
  50. ** p_uuid_list - (input) list of UUID filters
  51. ** num_attr - (input) number of attribute filters applied
  52. ** p_attr_list - (input) list of attribute filters
  53. **
  54. **
  55. ** Returns BOOLEAN
  56. ** TRUE if successful
  57. ** FALSE if one or more parameters are bad
  58. **
  59. *******************************************************************************/
  60. BOOLEAN SDP_InitDiscoveryDb (tSDP_DISCOVERY_DB *p_db, UINT32 len, UINT16 num_uuid,
  61. tSDP_UUID *p_uuid_list, UINT16 num_attr, UINT16 *p_attr_list)
  62. {
  63. #if SDP_CLIENT_ENABLED == TRUE
  64. UINT16 xx;
  65. /* verify the parameters */
  66. if (p_db == NULL || (sizeof (tSDP_DISCOVERY_DB) > len) ||
  67. num_attr > SDP_MAX_ATTR_FILTERS || num_uuid > SDP_MAX_UUID_FILTERS) {
  68. SDP_TRACE_ERROR("SDP_InitDiscoveryDb Illegal param: p_db 0x%x, len %d, num_uuid %d, num_attr %d",
  69. (UINT32)p_db, len, num_uuid, num_attr);
  70. return (FALSE);
  71. }
  72. memset (p_db, 0, (size_t)len);
  73. p_db->mem_size = len - sizeof (tSDP_DISCOVERY_DB);
  74. p_db->mem_free = p_db->mem_size;
  75. p_db->p_first_rec = NULL;
  76. p_db->p_free_mem = (UINT8 *)(p_db + 1);
  77. for (xx = 0; xx < num_uuid; xx++) {
  78. p_db->uuid_filters[xx] = *p_uuid_list++;
  79. }
  80. p_db->num_uuid_filters = num_uuid;
  81. for (xx = 0; xx < num_attr; xx++) {
  82. p_db->attr_filters[xx] = *p_attr_list++;
  83. }
  84. /* sort attributes */
  85. sdpu_sort_attr_list( num_attr, p_db );
  86. p_db->num_attr_filters = num_attr;
  87. #endif
  88. return (TRUE);
  89. }
  90. /*******************************************************************************
  91. **
  92. ** Function SDP_CancelServiceSearch
  93. **
  94. ** Description This function cancels an active query to an SDP server.
  95. **
  96. ** Returns TRUE if discovery cancelled, FALSE if a matching activity is not found.
  97. **
  98. *******************************************************************************/
  99. BOOLEAN SDP_CancelServiceSearch (tSDP_DISCOVERY_DB *p_db)
  100. {
  101. #if SDP_CLIENT_ENABLED == TRUE
  102. tCONN_CB *p_ccb = sdpu_find_ccb_by_db (p_db);
  103. if (!p_ccb) {
  104. return (FALSE);
  105. }
  106. sdp_disconnect (p_ccb, SDP_CANCEL);
  107. p_ccb->disc_state = SDP_DISC_WAIT_CANCEL;
  108. #endif
  109. return (TRUE);
  110. }
  111. /*******************************************************************************
  112. **
  113. ** Function SDP_ServiceSearchRequest
  114. **
  115. ** Description This function queries an SDP server for information.
  116. **
  117. ** Returns TRUE if discovery started, FALSE if failed.
  118. **
  119. *******************************************************************************/
  120. BOOLEAN SDP_ServiceSearchRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
  121. tSDP_DISC_CMPL_CB *p_cb)
  122. {
  123. #if SDP_CLIENT_ENABLED == TRUE
  124. tCONN_CB *p_ccb;
  125. /* Specific BD address */
  126. p_ccb = sdp_conn_originate (p_bd_addr);
  127. if (!p_ccb) {
  128. return (FALSE);
  129. }
  130. p_ccb->disc_state = SDP_DISC_WAIT_CONN;
  131. p_ccb->p_db = p_db;
  132. p_ccb->p_cb = p_cb;
  133. return (TRUE);
  134. #else
  135. return (FALSE);
  136. #endif
  137. }
  138. /*******************************************************************************
  139. **
  140. ** Function SDP_ServiceSearchAttributeRequest
  141. **
  142. ** Description This function queries an SDP server for information.
  143. **
  144. ** The difference between this API function and the function
  145. ** SDP_ServiceSearchRequest2 is that this one does a
  146. ** combined ServiceSearchAttributeRequest SDP function.
  147. **
  148. ** Returns TRUE if discovery started, FALSE if failed.
  149. **
  150. *******************************************************************************/
  151. BOOLEAN SDP_ServiceSearchAttributeRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
  152. tSDP_DISC_CMPL_CB *p_cb)
  153. {
  154. #if SDP_CLIENT_ENABLED == TRUE
  155. tCONN_CB *p_ccb;
  156. /* Specific BD address */
  157. p_ccb = sdp_conn_originate (p_bd_addr);
  158. if (!p_ccb) {
  159. return (FALSE);
  160. }
  161. p_ccb->disc_state = SDP_DISC_WAIT_CONN;
  162. p_ccb->p_db = p_db;
  163. p_ccb->p_cb = p_cb;
  164. p_ccb->is_attr_search = TRUE;
  165. return (TRUE);
  166. #else
  167. return (FALSE);
  168. #endif
  169. }
  170. /*******************************************************************************
  171. **
  172. ** Function SDP_ServiceSearchAttributeRequest2
  173. **
  174. ** Description This function queries an SDP server for information.
  175. **
  176. ** The difference between this API function and the function
  177. ** SDP_ServiceSearchRequest is that this one does a
  178. ** combined ServiceSearchAttributeRequest SDP function with the
  179. ** user data piggyback
  180. **
  181. ** Returns TRUE if discovery started, FALSE if failed.
  182. **
  183. *******************************************************************************/
  184. BOOLEAN SDP_ServiceSearchAttributeRequest2 (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
  185. tSDP_DISC_CMPL_CB2 *p_cb2, void *user_data)
  186. {
  187. #if SDP_CLIENT_ENABLED == TRUE
  188. tCONN_CB *p_ccb;
  189. /* Specific BD address */
  190. p_ccb = sdp_conn_originate (p_bd_addr);
  191. if (!p_ccb) {
  192. return (FALSE);
  193. }
  194. p_ccb->disc_state = SDP_DISC_WAIT_CONN;
  195. p_ccb->p_db = p_db;
  196. p_ccb->p_cb2 = p_cb2;
  197. p_ccb->is_attr_search = TRUE;
  198. p_ccb->user_data = user_data;
  199. return (TRUE);
  200. #else
  201. return (FALSE);
  202. #endif
  203. }
  204. #if SDP_CLIENT_ENABLED == TRUE
  205. void SDP_SetIdleTimeout (BD_ADDR addr, UINT16 timeout)
  206. {
  207. UNUSED(addr);
  208. UNUSED(timeout);
  209. }
  210. #endif
  211. /*******************************************************************************
  212. **
  213. ** Function SDP_FindAttributeInDb
  214. **
  215. ** Description This function queries an SDP database for a specific attribute.
  216. ** If the p_start_rec pointer is NULL, it looks from the beginning
  217. ** of the database, else it continues from the next record after
  218. ** p_start_rec.
  219. **
  220. ** Returns Pointer to matching record, or NULL
  221. **
  222. *******************************************************************************/
  223. tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db, UINT16 attr_id,
  224. tSDP_DISC_REC *p_start_rec)
  225. {
  226. #if SDP_CLIENT_ENABLED == TRUE
  227. tSDP_DISC_REC *p_rec;
  228. tSDP_DISC_ATTR *p_attr;
  229. /* Must have a valid database */
  230. if (p_db == NULL) {
  231. return (NULL);
  232. }
  233. if (!p_start_rec) {
  234. p_rec = p_db->p_first_rec;
  235. } else {
  236. p_rec = p_start_rec->p_next_rec;
  237. }
  238. while (p_rec) {
  239. p_attr = p_rec->p_first_attr;
  240. while (p_attr) {
  241. if (p_attr->attr_id == attr_id) {
  242. return (p_rec);
  243. }
  244. p_attr = p_attr->p_next_attr;
  245. }
  246. p_rec = p_rec->p_next_rec;
  247. }
  248. #endif
  249. /* If here, no matching attribute found */
  250. return (NULL);
  251. }
  252. /*******************************************************************************
  253. **
  254. ** Function SDP_FindAttributeInRec
  255. **
  256. ** Description This function searches an SDP discovery record for a specific
  257. ** attribute.
  258. **
  259. ** Returns Pointer to matching attribute entry, or NULL
  260. **
  261. *******************************************************************************/
  262. tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec, UINT16 attr_id)
  263. {
  264. #if SDP_CLIENT_ENABLED == TRUE
  265. tSDP_DISC_ATTR *p_attr;
  266. p_attr = p_rec->p_first_attr;
  267. while (p_attr) {
  268. if (p_attr->attr_id == attr_id) {
  269. return (p_attr);
  270. }
  271. p_attr = p_attr->p_next_attr;
  272. }
  273. #endif
  274. /* If here, no matching attribute found */
  275. return (NULL);
  276. }
  277. /*******************************************************************************
  278. **
  279. ** Function SDP_FindServiceUUIDInRec
  280. **
  281. ** Description This function is called to read the service UUID within a record
  282. ** if there is any.
  283. **
  284. ** Parameters: p_rec - pointer to a SDP record.
  285. ** p_uuid - output parameter to save the UUID found.
  286. **
  287. ** Returns TRUE if found, otherwise FALSE.
  288. **
  289. *******************************************************************************/
  290. BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID *p_uuid)
  291. {
  292. #if SDP_CLIENT_ENABLED == TRUE
  293. tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
  294. p_attr = p_rec->p_first_attr;
  295. while (p_attr) {
  296. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  297. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  298. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  299. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
  300. if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_16) {
  301. p_uuid->len = LEN_UUID_16;
  302. p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16;
  303. } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_128) {
  304. p_uuid->len = LEN_UUID_128;
  305. for (uint8_t i = 0; i != LEN_UUID_128; ++i) {
  306. p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128 - i - 1];
  307. }
  308. } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32) {
  309. p_uuid->len = LEN_UUID_32;
  310. p_uuid->uu.uuid32 = p_sattr->attr_value.v.u32;
  311. }
  312. return (TRUE);
  313. }
  314. /* Checking for Toyota G Block Car Kit:
  315. ** This car kit puts an extra data element sequence
  316. ** where the UUID is suppose to be!!!
  317. */
  318. else {
  319. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) {
  320. /* Look through data element sequence until no more UUIDs */
  321. for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) {
  322. /* Increment past this to see if the next attribut is UUID */
  323. if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
  324. /* only support 16 bits UUID for now */
  325. && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)) {
  326. p_uuid->len = 2;
  327. p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16;
  328. return (TRUE);
  329. }
  330. }
  331. }
  332. }
  333. }
  334. break;
  335. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  336. if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
  337. /* only support 16 bits UUID for now */
  338. && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)) {
  339. p_uuid->len = 2;
  340. p_uuid->uu.uuid16 = p_attr->attr_value.v.u16;
  341. return (TRUE);
  342. }
  343. }
  344. p_attr = p_attr->p_next_attr;
  345. }
  346. return FALSE;
  347. #else
  348. return FALSE;
  349. #endif
  350. }
  351. /*******************************************************************************
  352. **
  353. ** Function SDP_FindServiceUUIDInRec_128bit
  354. **
  355. ** Description This function is called to read the 128-bit service UUID within a record
  356. ** if there is any.
  357. **
  358. ** Parameters: p_rec - pointer to a SDP record.
  359. ** p_uuid - output parameter to save the UUID found.
  360. **
  361. ** Returns TRUE if found, otherwise FALSE.
  362. **
  363. *******************************************************************************/
  364. BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID *p_uuid)
  365. {
  366. #if SDP_CLIENT_ENABLED == TRUE
  367. tSDP_DISC_ATTR *p_attr, *p_sattr;
  368. p_attr = p_rec->p_first_attr;
  369. while (p_attr) {
  370. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  371. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  372. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  373. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
  374. /* only support 128 bits UUID for now */
  375. if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16) {
  376. p_uuid->len = LEN_UUID_128;
  377. for (uint8_t i = 0; i != LEN_UUID_128; ++i) {
  378. p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128 - i - 1];
  379. }
  380. }
  381. return (TRUE);
  382. }
  383. }
  384. break;
  385. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  386. if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
  387. /* only support 128 bits UUID for now */
  388. && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) {
  389. p_uuid->len = LEN_UUID_128;
  390. for (uint8_t i = 0; i != LEN_UUID_128; ++i) {
  391. p_uuid->uu.uuid128[i] = p_attr->attr_value.v.array[LEN_UUID_128 - i - 1];
  392. }
  393. return (TRUE);
  394. }
  395. }
  396. p_attr = p_attr->p_next_attr;
  397. }
  398. return FALSE;
  399. #else
  400. return FALSE;
  401. #endif
  402. }
  403. /*******************************************************************************
  404. **
  405. ** Function SDP_FindServiceInDb
  406. **
  407. ** Description This function queries an SDP database for a specific service.
  408. ** If the p_start_rec pointer is NULL, it looks from the beginning
  409. ** of the database, else it continues from the next record after
  410. ** p_start_rec.
  411. **
  412. ** Returns Pointer to record containing service class, or NULL
  413. **
  414. *******************************************************************************/
  415. tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, UINT16 service_uuid, tSDP_DISC_REC *p_start_rec)
  416. {
  417. #if SDP_CLIENT_ENABLED == TRUE
  418. tSDP_DISC_REC *p_rec;
  419. tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
  420. /* Must have a valid database */
  421. if (p_db == NULL) {
  422. return (NULL);
  423. }
  424. if (!p_start_rec) {
  425. p_rec = p_db->p_first_rec;
  426. } else {
  427. p_rec = p_start_rec->p_next_rec;
  428. }
  429. while (p_rec) {
  430. p_attr = p_rec->p_first_attr;
  431. while (p_attr) {
  432. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  433. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  434. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  435. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
  436. && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) ) {
  437. SDP_TRACE_DEBUG("SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x\r\n",
  438. p_sattr->attr_value.v.u16, service_uuid);
  439. if (service_uuid == UUID_SERVCLASS_HDP_PROFILE) {
  440. if ( (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE) || ( p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK)) {
  441. SDP_TRACE_DEBUG("SDP_FindServiceInDb found HDP source or sink\n" );
  442. return (p_rec);
  443. }
  444. }
  445. }
  446. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE && (service_uuid == 0
  447. || (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2
  448. && p_sattr->attr_value.v.u16 == service_uuid)))
  449. /* for a specific uuid, or any one */
  450. {
  451. return (p_rec);
  452. }
  453. /* Checking for Toyota G Block Car Kit:
  454. ** This car kit puts an extra data element sequence
  455. ** where the UUID is suppose to be!!!
  456. */
  457. else {
  458. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) {
  459. /* Look through data element sequence until no more UUIDs */
  460. for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) {
  461. /* Increment past this to see if the next attribut is UUID */
  462. if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
  463. && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)
  464. /* for a specific uuid, or any one */
  465. && ((p_extra_sattr->attr_value.v.u16 == service_uuid) || (service_uuid == 0))) {
  466. return (p_rec);
  467. }
  468. }
  469. }
  470. }
  471. }
  472. break;
  473. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  474. if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
  475. && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)
  476. /* find a specific UUID or anyone */
  477. && ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0)) {
  478. return (p_rec);
  479. }
  480. }
  481. p_attr = p_attr->p_next_attr;
  482. }
  483. p_rec = p_rec->p_next_rec;
  484. }
  485. #endif
  486. /* If here, no matching UUID found */
  487. return (NULL);
  488. }
  489. /*******************************************************************************
  490. **
  491. ** Function SDP_FindServiceInDb_128bit
  492. **
  493. ** Description This function queries an SDP database for a specific service.
  494. ** If the p_start_rec pointer is NULL, it looks from the beginning
  495. ** of the database, else it continues from the next record after
  496. ** p_start_rec.
  497. **
  498. ** This function is kept separate from SDP_FindServiceInDb since
  499. ** that API is expected to return only 16-bit UUIDs
  500. **
  501. ** Returns Pointer to record containing service class, or NULL
  502. **
  503. *******************************************************************************/
  504. tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_start_rec)
  505. {
  506. #if SDP_CLIENT_ENABLED == TRUE
  507. tSDP_DISC_REC *p_rec;
  508. tSDP_DISC_ATTR *p_attr, *p_sattr;
  509. /* Must have a valid database */
  510. if (p_db == NULL) {
  511. return (NULL);
  512. }
  513. if (!p_start_rec) {
  514. p_rec = p_db->p_first_rec;
  515. } else {
  516. p_rec = p_start_rec->p_next_rec;
  517. }
  518. while (p_rec) {
  519. p_attr = p_rec->p_first_attr;
  520. while (p_attr) {
  521. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  522. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  523. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  524. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
  525. && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)) {
  526. return (p_rec);
  527. }
  528. }
  529. break;
  530. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  531. if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
  532. && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) {
  533. return (p_rec);
  534. }
  535. }
  536. p_attr = p_attr->p_next_attr;
  537. }
  538. p_rec = p_rec->p_next_rec;
  539. }
  540. #endif
  541. /* If here, no matching UUID found */
  542. return (NULL);
  543. }
  544. /*******************************************************************************
  545. **
  546. ** Function SDP_FindServiceUUIDInDb
  547. **
  548. ** Description This function queries an SDP database for a specific service.
  549. ** If the p_start_rec pointer is NULL, it looks from the beginning
  550. ** of the database, else it continues from the next record after
  551. ** p_start_rec.
  552. **
  553. ** NOTE the only difference between this function and the previous function
  554. ** "SDP_FindServiceInDb()" is that this function takes a tBT_UUID input
  555. **
  556. ** Returns Pointer to record containing service class, or NULL
  557. **
  558. *******************************************************************************/
  559. tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, tBT_UUID *p_uuid, tSDP_DISC_REC *p_start_rec)
  560. {
  561. #if SDP_CLIENT_ENABLED == TRUE
  562. tSDP_DISC_REC *p_rec;
  563. tSDP_DISC_ATTR *p_attr, *p_sattr;
  564. /* Must have a valid database */
  565. if (p_db == NULL) {
  566. return (NULL);
  567. }
  568. if (!p_start_rec) {
  569. p_rec = p_db->p_first_rec;
  570. } else {
  571. p_rec = p_start_rec->p_next_rec;
  572. }
  573. while (p_rec) {
  574. p_attr = p_rec->p_first_attr;
  575. while (p_attr) {
  576. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  577. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  578. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  579. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
  580. if (sdpu_compare_uuid_with_attr (p_uuid, p_sattr)) {
  581. return (p_rec);
  582. }
  583. }
  584. }
  585. break;
  586. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  587. if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE ) {
  588. if (sdpu_compare_uuid_with_attr (p_uuid, p_attr)) {
  589. return (p_rec);
  590. }
  591. }
  592. }
  593. p_attr = p_attr->p_next_attr;
  594. }
  595. p_rec = p_rec->p_next_rec;
  596. }
  597. #endif /* CLIENT_ENABLED == TRUE */
  598. /* If here, no matching UUID found */
  599. return (NULL);
  600. }
  601. #if SDP_CLIENT_ENABLED == TRUE
  602. /*******************************************************************************
  603. **
  604. ** Function sdp_fill_proto_elem
  605. **
  606. ** Description This function retrieves the protocol element.
  607. **
  608. ** Returns TRUE if found, FALSE if not
  609. ** If found, the passed protocol list element is filled in.
  610. **
  611. *******************************************************************************/
  612. static BOOLEAN sdp_fill_proto_elem( tSDP_DISC_ATTR *p_attr, UINT16 layer_uuid,
  613. tSDP_PROTOCOL_ELEM *p_elem)
  614. {
  615. tSDP_DISC_ATTR *p_sattr;
  616. /* Walk through the protocol descriptor list */
  617. for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) {
  618. /* Safety check - each entry should itself be a sequence */
  619. if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
  620. return (FALSE);
  621. }
  622. /* Now, see if the entry contains the layer we are interested in */
  623. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  624. /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####",
  625. p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */
  626. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
  627. && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
  628. && (p_sattr->attr_value.v.u16 == layer_uuid)) {
  629. /* Bingo. Now fill in the passed element */
  630. p_elem->protocol_uuid = layer_uuid;
  631. p_elem->num_params = 0;
  632. /* Store the parameters, if any */
  633. for (p_sattr = p_sattr->p_next_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  634. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE) {
  635. break;
  636. }
  637. if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) {
  638. p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16;
  639. } else {
  640. p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8;
  641. }
  642. if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS) {
  643. break;
  644. }
  645. }
  646. return (TRUE);
  647. }
  648. }
  649. }
  650. return (FALSE);
  651. }
  652. #endif /* CLIENT_ENABLED == TRUE */
  653. /*******************************************************************************
  654. **
  655. ** Function SDP_FindProtocolListElemInRec
  656. **
  657. ** Description This function looks at a specific discovery record for a protocol
  658. ** list element.
  659. **
  660. ** Returns TRUE if found, FALSE if not
  661. ** If found, the passed protocol list element is filled in.
  662. **
  663. *******************************************************************************/
  664. BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
  665. {
  666. #if SDP_CLIENT_ENABLED == TRUE
  667. tSDP_DISC_ATTR *p_attr;
  668. p_attr = p_rec->p_first_attr;
  669. while (p_attr) {
  670. /* Find the protocol descriptor list */
  671. if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST)
  672. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  673. return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem);
  674. }
  675. p_attr = p_attr->p_next_attr;
  676. }
  677. #endif
  678. /* If here, no match found */
  679. return (FALSE);
  680. }
  681. /*******************************************************************************
  682. **
  683. ** Function SDP_FindAddProtoListsElemInRec
  684. **
  685. ** Description This function looks at a specific discovery record for a protocol
  686. ** list element.
  687. **
  688. ** Returns TRUE if found, FALSE if not
  689. ** If found, the passed protocol list element is filled in.
  690. **
  691. *******************************************************************************/
  692. BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
  693. {
  694. #if SDP_CLIENT_ENABLED == TRUE
  695. tSDP_DISC_ATTR *p_attr, *p_sattr;
  696. BOOLEAN ret = FALSE;
  697. p_attr = p_rec->p_first_attr;
  698. while (p_attr) {
  699. /* Find the additional protocol descriptor list attribute */
  700. if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
  701. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  702. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  703. /* Safety check - each entry should itself be a sequence */
  704. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) {
  705. if ( (ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem)) == TRUE) {
  706. break;
  707. }
  708. }
  709. }
  710. return ret;
  711. }
  712. p_attr = p_attr->p_next_attr;
  713. }
  714. #endif
  715. /* If here, no match found */
  716. return (FALSE);
  717. }
  718. /*******************************************************************************
  719. **
  720. ** Function SDP_FindProfileVersionInRec
  721. **
  722. ** Description This function looks at a specific discovery record for the
  723. ** Profile list descriptor, and pulls out the version number.
  724. ** The version number consists of an 8-bit major version and
  725. ** an 8-bit minor version.
  726. **
  727. ** Returns TRUE if found, FALSE if not
  728. ** If found, the major and minor version numbers that were passed
  729. ** in are filled in.
  730. **
  731. *******************************************************************************/
  732. BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, UINT16 profile_uuid, UINT16 *p_version)
  733. {
  734. #if SDP_CLIENT_ENABLED == TRUE
  735. tSDP_DISC_ATTR *p_attr, *p_sattr;
  736. p_attr = p_rec->p_first_attr;
  737. while (p_attr) {
  738. /* Find the profile descriptor list */
  739. if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST)
  740. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  741. /* Walk through the protocol descriptor list */
  742. for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) {
  743. /* Safety check - each entry should itself be a sequence */
  744. if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
  745. return (FALSE);
  746. }
  747. /* Now, see if the entry contains the profile UUID we are interested in */
  748. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  749. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
  750. && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) /* <- This is bytes, not size code! */
  751. && (p_sattr->attr_value.v.u16 == profile_uuid)) {
  752. /* Now fill in the major and minor numbers */
  753. /* if the attribute matches the description for version (type UINT, size 2 bytes) */
  754. p_sattr = p_sattr->p_next_attr;
  755. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) &&
  756. (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) {
  757. /* The high order 8 bits is the major number, low order is the minor number (big endian) */
  758. *p_version = p_sattr->attr_value.v.u16;
  759. return (TRUE);
  760. } else {
  761. return (FALSE); /* The type and/or size was not valid for the profile list version */
  762. }
  763. }
  764. }
  765. }
  766. return (FALSE);
  767. }
  768. p_attr = p_attr->p_next_attr;
  769. }
  770. #endif /* CLIENT_ENABLED == TRUE */
  771. /* If here, no match found */
  772. return (FALSE);
  773. }
  774. /*******************************************************************************
  775. ** Device Identification (DI) Client Functions
  776. *******************************************************************************/
  777. /*******************************************************************************
  778. **
  779. ** Function SDP_DiDiscover
  780. **
  781. ** Description This function queries a remote device for DI information.
  782. **
  783. ** Returns SDP_SUCCESS if query started successfully, else error
  784. **
  785. *******************************************************************************/
  786. UINT16 SDP_DiDiscover( BD_ADDR remote_device, tSDP_DISCOVERY_DB *p_db,
  787. UINT32 len, tSDP_DISC_CMPL_CB *p_cb )
  788. {
  789. #if SDP_CLIENT_ENABLED == TRUE
  790. UINT16 result = SDP_DI_DISC_FAILED;
  791. UINT16 num_uuids = 1;
  792. UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
  793. /* build uuid for db init */
  794. tSDP_UUID init_uuid;
  795. init_uuid.len = 2;
  796. init_uuid.uu.uuid16 = di_uuid;
  797. if ( SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL) ) {
  798. if ( SDP_ServiceSearchRequest(remote_device, p_db, p_cb) ) {
  799. result = SDP_SUCCESS;
  800. }
  801. }
  802. return result;
  803. #else
  804. return SDP_DI_DISC_FAILED;
  805. #endif
  806. }
  807. /*******************************************************************************
  808. **
  809. ** Function SDP_GetNumDiRecords
  810. **
  811. ** Description Searches specified database for DI records
  812. **
  813. ** Returns number of DI records found
  814. **
  815. *******************************************************************************/
  816. UINT8 SDP_GetNumDiRecords( tSDP_DISCOVERY_DB *p_db )
  817. {
  818. #if SDP_CLIENT_ENABLED == TRUE
  819. UINT8 num_records = 0;
  820. tSDP_DISC_REC *p_curr_record = NULL;
  821. do {
  822. p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
  823. p_curr_record );
  824. if ( p_curr_record ) {
  825. num_records++;
  826. }
  827. } while ( p_curr_record );
  828. return num_records;
  829. #else
  830. return 0;
  831. #endif
  832. }
  833. #if SDP_CLIENT_ENABLED == TRUE
  834. /*******************************************************************************
  835. **
  836. ** Function SDP_AttrStringCopy
  837. **
  838. ** Description This function copy given attribute to specified buffer as a string
  839. **
  840. ** Returns none
  841. **
  842. *******************************************************************************/
  843. static void SDP_AttrStringCopy(char *dst, tSDP_DISC_ATTR *p_attr, UINT16 dst_size)
  844. {
  845. if ( dst == NULL ) {
  846. return;
  847. }
  848. if ( p_attr ) {
  849. UINT16 len = SDP_DISC_ATTR_LEN(p_attr->attr_len_type);
  850. if ( len > dst_size - 1 ) {
  851. len = dst_size - 1;
  852. }
  853. memcpy(dst, (char *)p_attr->attr_value.v.array, len);
  854. dst[len] = '\0';
  855. } else {
  856. dst[0] = '\0';
  857. }
  858. }
  859. #endif
  860. /*******************************************************************************
  861. **
  862. ** Function SDP_GetDiRecord
  863. **
  864. ** Description This function retrieves a remote device's DI record from
  865. ** the specified database.
  866. **
  867. ** Returns SDP_SUCCESS if record retrieved, else error
  868. **
  869. *******************************************************************************/
  870. UINT16 SDP_GetDiRecord( UINT8 get_record_index, tSDP_DI_GET_RECORD *p_device_info,
  871. tSDP_DISCOVERY_DB *p_db )
  872. {
  873. #if SDP_CLIENT_ENABLED == TRUE
  874. UINT16 result = SDP_NO_DI_RECORD_FOUND;
  875. UINT8 curr_record_index = 1;
  876. tSDP_DISC_REC *p_curr_record = NULL;
  877. /* find the requested SDP record in the discovery database */
  878. do {
  879. p_curr_record = SDP_FindServiceInDb( p_db, UUID_SERVCLASS_PNP_INFORMATION,
  880. p_curr_record );
  881. if ( p_curr_record ) {
  882. if ( curr_record_index++ == get_record_index ) {
  883. result = SDP_SUCCESS;
  884. break;
  885. }
  886. }
  887. } while ( p_curr_record );
  888. if ( result == SDP_SUCCESS ) {
  889. /* copy the information from the SDP record to the DI record */
  890. tSDP_DISC_ATTR *p_curr_attr = NULL;
  891. /* ClientExecutableURL is optional */
  892. p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_CLIENT_EXE_URL );
  893. SDP_AttrStringCopy( p_device_info->rec.client_executable_url, p_curr_attr,
  894. SDP_MAX_ATTR_LEN );
  895. /* Service Description is optional */
  896. p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SERVICE_DESCRIPTION );
  897. SDP_AttrStringCopy( p_device_info->rec.service_description, p_curr_attr, SDP_MAX_ATTR_LEN );
  898. /* DocumentationURL is optional */
  899. p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_DOCUMENTATION_URL );
  900. SDP_AttrStringCopy( p_device_info->rec.documentation_url, p_curr_attr, SDP_MAX_ATTR_LEN );
  901. p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_SPECIFICATION_ID );
  902. if ( p_curr_attr ) {
  903. p_device_info->spec_id = p_curr_attr->attr_value.v.u16;
  904. } else {
  905. result = SDP_ERR_ATTR_NOT_PRESENT;
  906. }
  907. p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID );
  908. if ( p_curr_attr ) {
  909. p_device_info->rec.vendor = p_curr_attr->attr_value.v.u16;
  910. } else {
  911. result = SDP_ERR_ATTR_NOT_PRESENT;
  912. }
  913. p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_VENDOR_ID_SOURCE );
  914. if ( p_curr_attr ) {
  915. p_device_info->rec.vendor_id_source = p_curr_attr->attr_value.v.u16;
  916. } else {
  917. result = SDP_ERR_ATTR_NOT_PRESENT;
  918. }
  919. p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_ID );
  920. if ( p_curr_attr ) {
  921. p_device_info->rec.product = p_curr_attr->attr_value.v.u16;
  922. } else {
  923. result = SDP_ERR_ATTR_NOT_PRESENT;
  924. }
  925. p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRODUCT_VERSION );
  926. if ( p_curr_attr ) {
  927. p_device_info->rec.version = p_curr_attr->attr_value.v.u16;
  928. } else {
  929. result = SDP_ERR_ATTR_NOT_PRESENT;
  930. }
  931. p_curr_attr = SDP_FindAttributeInRec( p_curr_record, ATTR_ID_PRIMARY_RECORD );
  932. if ( p_curr_attr ) {
  933. p_device_info->rec.primary_record = (BOOLEAN)p_curr_attr->attr_value.v.u8;
  934. } else {
  935. result = SDP_ERR_ATTR_NOT_PRESENT;
  936. }
  937. }
  938. return result;
  939. #else /* SDP_CLIENT_ENABLED is FALSE */
  940. return SDP_NO_DI_RECORD_FOUND;
  941. #endif
  942. }
  943. /*******************************************************************************
  944. ** Device Identification (DI) Server Functions
  945. *******************************************************************************/
  946. /*******************************************************************************
  947. **
  948. ** Function SDP_SetLocalDiRecord
  949. **
  950. ** Description This function adds a DI record to the local SDP database.
  951. **
  952. **
  953. **
  954. ** Returns Returns SDP_SUCCESS if record added successfully, else error
  955. **
  956. *******************************************************************************/
  957. UINT16 SDP_SetLocalDiRecord( tSDP_DI_RECORD *p_device_info, UINT32 *p_handle )
  958. {
  959. #if SDP_SERVER_ENABLED == TRUE
  960. UINT16 result = SDP_SUCCESS;
  961. UINT32 handle;
  962. UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
  963. UINT16 di_specid = BLUETOOTH_DI_SPECIFICATION;
  964. UINT8 temp_u16[2];
  965. UINT8 *p_temp;
  966. UINT8 u8;
  967. *p_handle = 0;
  968. if ( p_device_info == NULL ) {
  969. return SDP_ILLEGAL_PARAMETER;
  970. }
  971. /* if record is to be primary record, get handle to replace old primary */
  972. if ( p_device_info->primary_record == TRUE && sdp_cb.server_db.di_primary_handle ) {
  973. handle = sdp_cb.server_db.di_primary_handle;
  974. } else {
  975. if ( (handle = SDP_CreateRecord()) == 0 ) {
  976. return SDP_NO_RESOURCES;
  977. }
  978. }
  979. *p_handle = handle;
  980. /* build the SDP entry */
  981. /* Add the UUID to the Service Class ID List */
  982. if ((SDP_AddServiceClassIdList(handle, 1, &di_uuid)) == FALSE) {
  983. result = SDP_DI_REG_FAILED;
  984. }
  985. /* mandatory */
  986. if ( result == SDP_SUCCESS) {
  987. p_temp = temp_u16;
  988. UINT16_TO_BE_STREAM(p_temp, di_specid);
  989. if ( !(SDP_AddAttribute(handle, ATTR_ID_SPECIFICATION_ID,
  990. UINT_DESC_TYPE, sizeof(di_specid),
  991. temp_u16)) ) {
  992. result = SDP_DI_REG_FAILED;
  993. }
  994. }
  995. /* optional - if string is null, do not add attribute */
  996. if ( result == SDP_SUCCESS ) {
  997. if ( p_device_info->client_executable_url[0] != '\0' ) {
  998. if ( !((strlen(p_device_info->client_executable_url) + 1 <= SDP_MAX_ATTR_LEN) &&
  999. SDP_AddAttribute(handle, ATTR_ID_CLIENT_EXE_URL, URL_DESC_TYPE,
  1000. (UINT32)(strlen(p_device_info->client_executable_url) + 1),
  1001. (UINT8 *)p_device_info->client_executable_url)) ) {
  1002. result = SDP_DI_REG_FAILED;
  1003. }
  1004. }
  1005. }
  1006. /* optional - if string is null, do not add attribute */
  1007. if ( result == SDP_SUCCESS ) {
  1008. if ( p_device_info->service_description[0] != '\0' ) {
  1009. if ( !((strlen(p_device_info->service_description) + 1 <= SDP_MAX_ATTR_LEN) &&
  1010. SDP_AddAttribute(handle, ATTR_ID_SERVICE_DESCRIPTION,
  1011. TEXT_STR_DESC_TYPE,
  1012. (UINT32)(strlen(p_device_info->service_description) + 1),
  1013. (UINT8 *)p_device_info->service_description)) ) {
  1014. result = SDP_DI_REG_FAILED;
  1015. }
  1016. }
  1017. }
  1018. /* optional - if string is null, do not add attribute */
  1019. if ( result == SDP_SUCCESS ) {
  1020. if ( p_device_info->documentation_url[0] != '\0' ) {
  1021. if ( !((strlen(p_device_info->documentation_url) + 1 <= SDP_MAX_ATTR_LEN) &&
  1022. SDP_AddAttribute(handle, ATTR_ID_DOCUMENTATION_URL, URL_DESC_TYPE,
  1023. (UINT32)(strlen(p_device_info->documentation_url) + 1),
  1024. (UINT8 *)p_device_info->documentation_url)) ) {
  1025. result = SDP_DI_REG_FAILED;
  1026. }
  1027. }
  1028. }
  1029. /* mandatory */
  1030. if ( result == SDP_SUCCESS) {
  1031. p_temp = temp_u16;
  1032. UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor);
  1033. if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID, UINT_DESC_TYPE,
  1034. sizeof(p_device_info->vendor), temp_u16)) ) {
  1035. result = SDP_DI_REG_FAILED;
  1036. }
  1037. }
  1038. /* mandatory */
  1039. if ( result == SDP_SUCCESS) {
  1040. p_temp = temp_u16;
  1041. UINT16_TO_BE_STREAM (p_temp, p_device_info->product);
  1042. if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_ID,
  1043. UINT_DESC_TYPE, sizeof(p_device_info->product), temp_u16)) ) {
  1044. result = SDP_DI_REG_FAILED;
  1045. }
  1046. }
  1047. /* mandatory */
  1048. if ( result == SDP_SUCCESS) {
  1049. p_temp = temp_u16;
  1050. UINT16_TO_BE_STREAM (p_temp, p_device_info->version);
  1051. if ( !(SDP_AddAttribute(handle, ATTR_ID_PRODUCT_VERSION, UINT_DESC_TYPE,
  1052. sizeof(p_device_info->version), temp_u16)) ) {
  1053. result = SDP_DI_REG_FAILED;
  1054. }
  1055. }
  1056. /* mandatory */
  1057. if ( result == SDP_SUCCESS) {
  1058. u8 = (UINT8)p_device_info->primary_record;
  1059. if ( !(SDP_AddAttribute(handle, ATTR_ID_PRIMARY_RECORD,
  1060. BOOLEAN_DESC_TYPE, 1, &u8)) ) {
  1061. result = SDP_DI_REG_FAILED;
  1062. }
  1063. }
  1064. /* mandatory */
  1065. if ( result == SDP_SUCCESS) {
  1066. p_temp = temp_u16;
  1067. UINT16_TO_BE_STREAM(p_temp, p_device_info->vendor_id_source);
  1068. if ( !(SDP_AddAttribute(handle, ATTR_ID_VENDOR_ID_SOURCE, UINT_DESC_TYPE,
  1069. sizeof(p_device_info->vendor_id_source), temp_u16)) ) {
  1070. result = SDP_DI_REG_FAILED;
  1071. }
  1072. }
  1073. if ( result != SDP_SUCCESS ) {
  1074. SDP_DeleteRecord( handle );
  1075. } else if (p_device_info->primary_record == TRUE) {
  1076. sdp_cb.server_db.di_primary_handle = handle;
  1077. }
  1078. return result;
  1079. #else /* SDP_SERVER_ENABLED is FALSE */
  1080. return SDP_DI_REG_FAILED;
  1081. #endif /* if SDP_SERVER_ENABLED */
  1082. }
  1083. /*******************************************************************************
  1084. **
  1085. ** Function SDP_SetTraceLevel
  1086. **
  1087. ** Description This function sets the trace level for SDP. If called with
  1088. ** a value of 0xFF, it simply reads the current trace level.
  1089. **
  1090. ** Returns the new (current) trace level
  1091. **
  1092. *******************************************************************************/
  1093. UINT8 SDP_SetTraceLevel (UINT8 new_level)
  1094. {
  1095. if (new_level != 0xFF) {
  1096. sdp_cb.trace_level = new_level;
  1097. }
  1098. return (sdp_cb.trace_level);
  1099. }
  1100. #endif ///SDP_INCLUDED == TRUE