sdp_api.c 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241
  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 "bt_target.h"
  27. //#include "bt_utils.h"
  28. #include "gki.h"
  29. #include "l2cdefs.h"
  30. #include "hcidefs.h"
  31. #include "hcimsgs.h"
  32. #include "bt_defs.h"
  33. #include "sdp_api.h"
  34. #include "sdpint.h"
  35. #include "btu.h"
  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_ServiceSearchRequest is that this one does a
  146. ** combined ServiceSearchAttributeRequest SDP function.
  147. ** (This is for Unplug Testing)
  148. **
  149. ** Returns TRUE if discovery started, FALSE if failed.
  150. **
  151. *******************************************************************************/
  152. BOOLEAN SDP_ServiceSearchAttributeRequest (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
  153. tSDP_DISC_CMPL_CB *p_cb)
  154. {
  155. #if SDP_CLIENT_ENABLED == TRUE
  156. tCONN_CB *p_ccb;
  157. /* Specific BD address */
  158. p_ccb = sdp_conn_originate (p_bd_addr);
  159. if (!p_ccb) {
  160. return (FALSE);
  161. }
  162. p_ccb->disc_state = SDP_DISC_WAIT_CONN;
  163. p_ccb->p_db = p_db;
  164. p_ccb->p_cb = p_cb;
  165. p_ccb->is_attr_search = TRUE;
  166. return (TRUE);
  167. #else
  168. return (FALSE);
  169. #endif
  170. }
  171. /*******************************************************************************
  172. **
  173. ** Function SDP_ServiceSearchAttributeRequest2
  174. **
  175. ** Description This function queries an SDP server for information.
  176. **
  177. ** The difference between this API function and the function
  178. ** SDP_ServiceSearchRequest is that this one does a
  179. ** combined ServiceSearchAttributeRequest SDP function.
  180. ** (This is for Unplug Testing)
  181. **
  182. ** Returns TRUE if discovery started, FALSE if failed.
  183. **
  184. *******************************************************************************/
  185. BOOLEAN SDP_ServiceSearchAttributeRequest2 (UINT8 *p_bd_addr, tSDP_DISCOVERY_DB *p_db,
  186. tSDP_DISC_CMPL_CB2 *p_cb2, void *user_data)
  187. {
  188. #if SDP_CLIENT_ENABLED == TRUE
  189. tCONN_CB *p_ccb;
  190. /* Specific BD address */
  191. p_ccb = sdp_conn_originate (p_bd_addr);
  192. if (!p_ccb) {
  193. return (FALSE);
  194. }
  195. p_ccb->disc_state = SDP_DISC_WAIT_CONN;
  196. p_ccb->p_db = p_db;
  197. p_ccb->p_cb2 = p_cb2;
  198. p_ccb->is_attr_search = TRUE;
  199. p_ccb->user_data = user_data;
  200. return (TRUE);
  201. #else
  202. return (FALSE);
  203. #endif
  204. }
  205. #if SDP_CLIENT_ENABLED == TRUE
  206. void SDP_SetIdleTimeout (BD_ADDR addr, UINT16 timeout)
  207. {
  208. UNUSED(addr);
  209. UNUSED(timeout);
  210. }
  211. #endif
  212. /*******************************************************************************
  213. **
  214. ** Function SDP_FindAttributeInDb
  215. **
  216. ** Description This function queries an SDP database for a specific attribute.
  217. ** If the p_start_rec pointer is NULL, it looks from the beginning
  218. ** of the database, else it continues from the next record after
  219. ** p_start_rec.
  220. **
  221. ** Returns Pointer to matching record, or NULL
  222. **
  223. *******************************************************************************/
  224. tSDP_DISC_REC *SDP_FindAttributeInDb (tSDP_DISCOVERY_DB *p_db, UINT16 attr_id,
  225. tSDP_DISC_REC *p_start_rec)
  226. {
  227. #if SDP_CLIENT_ENABLED == TRUE
  228. tSDP_DISC_REC *p_rec;
  229. tSDP_DISC_ATTR *p_attr;
  230. /* Must have a valid database */
  231. if (p_db == NULL) {
  232. return (NULL);
  233. }
  234. if (!p_start_rec) {
  235. p_rec = p_db->p_first_rec;
  236. } else {
  237. p_rec = p_start_rec->p_next_rec;
  238. }
  239. while (p_rec) {
  240. p_attr = p_rec->p_first_attr;
  241. while (p_attr) {
  242. if (p_attr->attr_id == attr_id) {
  243. return (p_rec);
  244. }
  245. p_attr = p_attr->p_next_attr;
  246. }
  247. p_rec = p_rec->p_next_rec;
  248. }
  249. #endif
  250. /* If here, no matching attribute found */
  251. return (NULL);
  252. }
  253. /*******************************************************************************
  254. **
  255. ** Function SDP_FindAttributeInRec
  256. **
  257. ** Description This function searches an SDP discovery record for a specific
  258. ** attribute.
  259. **
  260. ** Returns Pointer to matching attribute entry, or NULL
  261. **
  262. *******************************************************************************/
  263. tSDP_DISC_ATTR *SDP_FindAttributeInRec (tSDP_DISC_REC *p_rec, UINT16 attr_id)
  264. {
  265. #if SDP_CLIENT_ENABLED == TRUE
  266. tSDP_DISC_ATTR *p_attr;
  267. p_attr = p_rec->p_first_attr;
  268. while (p_attr) {
  269. if (p_attr->attr_id == attr_id) {
  270. return (p_attr);
  271. }
  272. p_attr = p_attr->p_next_attr;
  273. }
  274. #endif
  275. /* If here, no matching attribute found */
  276. return (NULL);
  277. }
  278. /*******************************************************************************
  279. **
  280. ** Function SDP_FindServiceUUIDInRec
  281. **
  282. ** Description This function is called to read the service UUID within a record
  283. ** if there is any.
  284. **
  285. ** Parameters: p_rec - pointer to a SDP record.
  286. ** p_uuid - output parameter to save the UUID found.
  287. **
  288. ** Returns TRUE if found, otherwise FALSE.
  289. **
  290. *******************************************************************************/
  291. BOOLEAN SDP_FindServiceUUIDInRec(tSDP_DISC_REC *p_rec, tBT_UUID *p_uuid)
  292. {
  293. #if SDP_CLIENT_ENABLED == TRUE
  294. tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
  295. p_attr = p_rec->p_first_attr;
  296. while (p_attr) {
  297. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  298. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  299. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  300. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
  301. if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_16) {
  302. p_uuid->len = LEN_UUID_16;
  303. p_uuid->uu.uuid16 = p_sattr->attr_value.v.u16;
  304. } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_128) {
  305. p_uuid->len = LEN_UUID_128;
  306. for (uint8_t i = 0; i != LEN_UUID_128; ++i) {
  307. p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128 - i - 1];
  308. }
  309. } else if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == LEN_UUID_32) {
  310. p_uuid->len = LEN_UUID_32;
  311. p_uuid->uu.uuid32 = p_sattr->attr_value.v.u32;
  312. }
  313. return (TRUE);
  314. }
  315. /* Checking for Toyota G Block Car Kit:
  316. ** This car kit puts an extra data element sequence
  317. ** where the UUID is suppose to be!!!
  318. */
  319. else {
  320. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) {
  321. /* Look through data element sequence until no more UUIDs */
  322. for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) {
  323. /* Increment past this to see if the next attribut is UUID */
  324. if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
  325. /* only support 16 bits UUID for now */
  326. && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)) {
  327. p_uuid->len = 2;
  328. p_uuid->uu.uuid16 = p_extra_sattr->attr_value.v.u16;
  329. return (TRUE);
  330. }
  331. }
  332. }
  333. }
  334. }
  335. break;
  336. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  337. if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
  338. /* only support 16 bits UUID for now */
  339. && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)) {
  340. p_uuid->len = 2;
  341. p_uuid->uu.uuid16 = p_attr->attr_value.v.u16;
  342. return (TRUE);
  343. }
  344. }
  345. p_attr = p_attr->p_next_attr;
  346. }
  347. return FALSE;
  348. #else
  349. return FALSE;
  350. #endif
  351. }
  352. /*******************************************************************************
  353. **
  354. ** Function SDP_FindServiceUUIDInRec_128bit
  355. **
  356. ** Description This function is called to read the 128-bit service UUID within a record
  357. ** if there is any.
  358. **
  359. ** Parameters: p_rec - pointer to a SDP record.
  360. ** p_uuid - output parameter to save the UUID found.
  361. **
  362. ** Returns TRUE if found, otherwise FALSE.
  363. **
  364. *******************************************************************************/
  365. BOOLEAN SDP_FindServiceUUIDInRec_128bit(tSDP_DISC_REC *p_rec, tBT_UUID *p_uuid)
  366. {
  367. #if SDP_CLIENT_ENABLED == TRUE
  368. tSDP_DISC_ATTR *p_attr, *p_sattr;
  369. p_attr = p_rec->p_first_attr;
  370. while (p_attr) {
  371. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  372. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  373. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  374. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
  375. /* only support 128 bits UUID for now */
  376. if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16) {
  377. p_uuid->len = LEN_UUID_128;
  378. for (uint8_t i = 0; i != LEN_UUID_128; ++i) {
  379. p_uuid->uu.uuid128[i] = p_sattr->attr_value.v.array[LEN_UUID_128 - i - 1];
  380. }
  381. }
  382. return (TRUE);
  383. }
  384. }
  385. break;
  386. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  387. if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
  388. /* only support 128 bits UUID for now */
  389. && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) {
  390. p_uuid->len = LEN_UUID_128;
  391. for (uint8_t i = 0; i != LEN_UUID_128; ++i) {
  392. p_uuid->uu.uuid128[i] = p_attr->attr_value.v.array[LEN_UUID_128 - i - 1];
  393. }
  394. return (TRUE);
  395. }
  396. }
  397. p_attr = p_attr->p_next_attr;
  398. }
  399. return FALSE;
  400. #else
  401. return FALSE;
  402. #endif
  403. }
  404. /*******************************************************************************
  405. **
  406. ** Function SDP_FindServiceInDb
  407. **
  408. ** Description This function queries an SDP database for a specific service.
  409. ** If the p_start_rec pointer is NULL, it looks from the beginning
  410. ** of the database, else it continues from the next record after
  411. ** p_start_rec.
  412. **
  413. ** Returns Pointer to record containing service class, or NULL
  414. **
  415. *******************************************************************************/
  416. tSDP_DISC_REC *SDP_FindServiceInDb (tSDP_DISCOVERY_DB *p_db, UINT16 service_uuid, tSDP_DISC_REC *p_start_rec)
  417. {
  418. #if SDP_CLIENT_ENABLED == TRUE
  419. tSDP_DISC_REC *p_rec;
  420. tSDP_DISC_ATTR *p_attr, *p_sattr, *p_extra_sattr;
  421. /* Must have a valid database */
  422. if (p_db == NULL) {
  423. return (NULL);
  424. }
  425. if (!p_start_rec) {
  426. p_rec = p_db->p_first_rec;
  427. } else {
  428. p_rec = p_start_rec->p_next_rec;
  429. }
  430. while (p_rec) {
  431. p_attr = p_rec->p_first_attr;
  432. while (p_attr) {
  433. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  434. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  435. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  436. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
  437. && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) ) {
  438. SDP_TRACE_DEBUG("SDP_FindServiceInDb - p_sattr value = 0x%x serviceuuid = 0x%x\r\n",
  439. p_sattr->attr_value.v.u16, service_uuid);
  440. if (service_uuid == UUID_SERVCLASS_HDP_PROFILE) {
  441. if ( (p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SOURCE) || ( p_sattr->attr_value.v.u16 == UUID_SERVCLASS_HDP_SINK)) {
  442. SDP_TRACE_DEBUG("SDP_FindServiceInDb found HDP source or sink\n" );
  443. return (p_rec);
  444. }
  445. }
  446. }
  447. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE && (service_uuid == 0
  448. || (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2
  449. && p_sattr->attr_value.v.u16 == service_uuid)))
  450. /* for a specific uuid, or any one */
  451. {
  452. return (p_rec);
  453. }
  454. /* Checking for Toyota G Block Car Kit:
  455. ** This car kit puts an extra data element sequence
  456. ** where the UUID is suppose to be!!!
  457. */
  458. else {
  459. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) {
  460. /* Look through data element sequence until no more UUIDs */
  461. for (p_extra_sattr = p_sattr->attr_value.v.p_sub_attr; p_extra_sattr; p_extra_sattr = p_extra_sattr->p_next_attr) {
  462. /* Increment past this to see if the next attribut is UUID */
  463. if ((SDP_DISC_ATTR_TYPE(p_extra_sattr->attr_len_type) == UUID_DESC_TYPE)
  464. && (SDP_DISC_ATTR_LEN(p_extra_sattr->attr_len_type) == 2)
  465. /* for a specific uuid, or any one */
  466. && ((p_extra_sattr->attr_value.v.u16 == service_uuid) || (service_uuid == 0))) {
  467. return (p_rec);
  468. }
  469. }
  470. }
  471. }
  472. }
  473. break;
  474. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  475. if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
  476. && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 2)
  477. /* find a specific UUID or anyone */
  478. && ((p_attr->attr_value.v.u16 == service_uuid) || service_uuid == 0)) {
  479. return (p_rec);
  480. }
  481. }
  482. p_attr = p_attr->p_next_attr;
  483. }
  484. p_rec = p_rec->p_next_rec;
  485. }
  486. #endif
  487. /* If here, no matching UUID found */
  488. return (NULL);
  489. }
  490. /*******************************************************************************
  491. **
  492. ** Function SDP_FindServiceInDb_128bit
  493. **
  494. ** Description This function queries an SDP database for a specific service.
  495. ** If the p_start_rec pointer is NULL, it looks from the beginning
  496. ** of the database, else it continues from the next record after
  497. ** p_start_rec.
  498. **
  499. ** This function is kept separate from SDP_FindServiceInDb since
  500. ** that API is expected to return only 16-bit UUIDs
  501. **
  502. ** Returns Pointer to record containing service class, or NULL
  503. **
  504. *******************************************************************************/
  505. tSDP_DISC_REC *SDP_FindServiceInDb_128bit(tSDP_DISCOVERY_DB *p_db, tSDP_DISC_REC *p_start_rec)
  506. {
  507. #if SDP_CLIENT_ENABLED == TRUE
  508. tSDP_DISC_REC *p_rec;
  509. tSDP_DISC_ATTR *p_attr, *p_sattr;
  510. /* Must have a valid database */
  511. if (p_db == NULL) {
  512. return (NULL);
  513. }
  514. if (!p_start_rec) {
  515. p_rec = p_db->p_first_rec;
  516. } else {
  517. p_rec = p_start_rec->p_next_rec;
  518. }
  519. while (p_rec) {
  520. p_attr = p_rec->p_first_attr;
  521. while (p_attr) {
  522. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  523. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  524. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  525. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
  526. && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 16)) {
  527. return (p_rec);
  528. }
  529. }
  530. break;
  531. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  532. if ((SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE)
  533. && (SDP_DISC_ATTR_LEN(p_attr->attr_len_type) == 16)) {
  534. return (p_rec);
  535. }
  536. }
  537. p_attr = p_attr->p_next_attr;
  538. }
  539. p_rec = p_rec->p_next_rec;
  540. }
  541. #endif
  542. /* If here, no matching UUID found */
  543. return (NULL);
  544. }
  545. /*******************************************************************************
  546. **
  547. ** Function SDP_FindServiceUUIDInDb
  548. **
  549. ** Description This function queries an SDP database for a specific service.
  550. ** If the p_start_rec pointer is NULL, it looks from the beginning
  551. ** of the database, else it continues from the next record after
  552. ** p_start_rec.
  553. **
  554. ** NOTE the only difference between this function and the previous function
  555. ** "SDP_FindServiceInDb()" is that this function takes a tBT_UUID input
  556. **
  557. ** Returns Pointer to record containing service class, or NULL
  558. **
  559. *******************************************************************************/
  560. tSDP_DISC_REC *SDP_FindServiceUUIDInDb (tSDP_DISCOVERY_DB *p_db, tBT_UUID *p_uuid, tSDP_DISC_REC *p_start_rec)
  561. {
  562. #if SDP_CLIENT_ENABLED == TRUE
  563. tSDP_DISC_REC *p_rec;
  564. tSDP_DISC_ATTR *p_attr, *p_sattr;
  565. /* Must have a valid database */
  566. if (p_db == NULL) {
  567. return (NULL);
  568. }
  569. if (!p_start_rec) {
  570. p_rec = p_db->p_first_rec;
  571. } else {
  572. p_rec = p_start_rec->p_next_rec;
  573. }
  574. while (p_rec) {
  575. p_attr = p_rec->p_first_attr;
  576. while (p_attr) {
  577. if ((p_attr->attr_id == ATTR_ID_SERVICE_CLASS_ID_LIST)
  578. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  579. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  580. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE) {
  581. if (sdpu_compare_uuid_with_attr (p_uuid, p_sattr)) {
  582. return (p_rec);
  583. }
  584. }
  585. }
  586. break;
  587. } else if (p_attr->attr_id == ATTR_ID_SERVICE_ID) {
  588. if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == UUID_DESC_TYPE ) {
  589. if (sdpu_compare_uuid_with_attr (p_uuid, p_attr)) {
  590. return (p_rec);
  591. }
  592. }
  593. }
  594. p_attr = p_attr->p_next_attr;
  595. }
  596. p_rec = p_rec->p_next_rec;
  597. }
  598. #endif /* CLIENT_ENABLED == TRUE */
  599. /* If here, no matching UUID found */
  600. return (NULL);
  601. }
  602. #if SDP_CLIENT_ENABLED == TRUE
  603. /*******************************************************************************
  604. **
  605. ** Function sdp_fill_proto_elem
  606. **
  607. ** Description This function retrieves the protocol element.
  608. **
  609. ** Returns TRUE if found, FALSE if not
  610. ** If found, the passed protocol list element is filled in.
  611. **
  612. *******************************************************************************/
  613. static BOOLEAN sdp_fill_proto_elem( tSDP_DISC_ATTR *p_attr, UINT16 layer_uuid,
  614. tSDP_PROTOCOL_ELEM *p_elem)
  615. {
  616. tSDP_DISC_ATTR *p_sattr;
  617. /* Walk through the protocol descriptor list */
  618. for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) {
  619. /* Safety check - each entry should itself be a sequence */
  620. if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
  621. return (FALSE);
  622. }
  623. /* Now, see if the entry contains the layer we are interested in */
  624. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  625. /* SDP_TRACE_DEBUG ("SDP - p_sattr 0x%x, layer_uuid:0x%x, u16:0x%x####",
  626. p_sattr, layer_uuid, p_sattr->attr_value.v.u16); */
  627. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
  628. && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)
  629. && (p_sattr->attr_value.v.u16 == layer_uuid)) {
  630. /* Bingo. Now fill in the passed element */
  631. p_elem->protocol_uuid = layer_uuid;
  632. p_elem->num_params = 0;
  633. /* Store the parameters, if any */
  634. for (p_sattr = p_sattr->p_next_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  635. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) != UINT_DESC_TYPE) {
  636. break;
  637. }
  638. if (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) {
  639. p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u16;
  640. } else {
  641. p_elem->params[p_elem->num_params++] = p_sattr->attr_value.v.u8;
  642. }
  643. if (p_elem->num_params >= SDP_MAX_PROTOCOL_PARAMS) {
  644. break;
  645. }
  646. }
  647. return (TRUE);
  648. }
  649. }
  650. }
  651. return (FALSE);
  652. }
  653. #endif /* CLIENT_ENABLED == TRUE */
  654. /*******************************************************************************
  655. **
  656. ** Function SDP_FindProtocolListElemInRec
  657. **
  658. ** Description This function looks at a specific discovery record for a protocol
  659. ** list element.
  660. **
  661. ** Returns TRUE if found, FALSE if not
  662. ** If found, the passed protocol list element is filled in.
  663. **
  664. *******************************************************************************/
  665. BOOLEAN SDP_FindProtocolListElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
  666. {
  667. #if SDP_CLIENT_ENABLED == TRUE
  668. tSDP_DISC_ATTR *p_attr;
  669. p_attr = p_rec->p_first_attr;
  670. while (p_attr) {
  671. /* Find the protocol descriptor list */
  672. if ((p_attr->attr_id == ATTR_ID_PROTOCOL_DESC_LIST)
  673. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  674. return sdp_fill_proto_elem(p_attr, layer_uuid, p_elem);
  675. }
  676. p_attr = p_attr->p_next_attr;
  677. }
  678. #endif
  679. /* If here, no match found */
  680. return (FALSE);
  681. }
  682. /*******************************************************************************
  683. **
  684. ** Function SDP_FindAddProtoListsElemInRec
  685. **
  686. ** Description This function looks at a specific discovery record for a protocol
  687. ** list element.
  688. **
  689. ** Returns TRUE if found, FALSE if not
  690. ** If found, the passed protocol list element is filled in.
  691. **
  692. *******************************************************************************/
  693. BOOLEAN SDP_FindAddProtoListsElemInRec (tSDP_DISC_REC *p_rec, UINT16 layer_uuid, tSDP_PROTOCOL_ELEM *p_elem)
  694. {
  695. #if SDP_CLIENT_ENABLED == TRUE
  696. tSDP_DISC_ATTR *p_attr, *p_sattr;
  697. BOOLEAN ret = FALSE;
  698. p_attr = p_rec->p_first_attr;
  699. while (p_attr) {
  700. /* Find the additional protocol descriptor list attribute */
  701. if ((p_attr->attr_id == ATTR_ID_ADDITION_PROTO_DESC_LISTS)
  702. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  703. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  704. /* Safety check - each entry should itself be a sequence */
  705. if (SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE) {
  706. if ( (ret = sdp_fill_proto_elem(p_sattr, layer_uuid, p_elem)) == TRUE) {
  707. break;
  708. }
  709. }
  710. }
  711. return ret;
  712. }
  713. p_attr = p_attr->p_next_attr;
  714. }
  715. #endif
  716. /* If here, no match found */
  717. return (FALSE);
  718. }
  719. /*******************************************************************************
  720. **
  721. ** Function SDP_FindProfileVersionInRec
  722. **
  723. ** Description This function looks at a specific discovery record for the
  724. ** Profile list descriptor, and pulls out the version number.
  725. ** The version number consists of an 8-bit major version and
  726. ** an 8-bit minor version.
  727. **
  728. ** Returns TRUE if found, FALSE if not
  729. ** If found, the major and minor version numbers that were passed
  730. ** in are filled in.
  731. **
  732. *******************************************************************************/
  733. BOOLEAN SDP_FindProfileVersionInRec (tSDP_DISC_REC *p_rec, UINT16 profile_uuid, UINT16 *p_version)
  734. {
  735. #if SDP_CLIENT_ENABLED == TRUE
  736. tSDP_DISC_ATTR *p_attr, *p_sattr;
  737. p_attr = p_rec->p_first_attr;
  738. while (p_attr) {
  739. /* Find the profile descriptor list */
  740. if ((p_attr->attr_id == ATTR_ID_BT_PROFILE_DESC_LIST)
  741. && (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) == DATA_ELE_SEQ_DESC_TYPE)) {
  742. /* Walk through the protocol descriptor list */
  743. for (p_attr = p_attr->attr_value.v.p_sub_attr; p_attr; p_attr = p_attr->p_next_attr) {
  744. /* Safety check - each entry should itself be a sequence */
  745. if (SDP_DISC_ATTR_TYPE(p_attr->attr_len_type) != DATA_ELE_SEQ_DESC_TYPE) {
  746. return (FALSE);
  747. }
  748. /* Now, see if the entry contains the profile UUID we are interested in */
  749. for (p_sattr = p_attr->attr_value.v.p_sub_attr; p_sattr; p_sattr = p_sattr->p_next_attr) {
  750. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UUID_DESC_TYPE)
  751. && (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2) /* <- This is bytes, not size code! */
  752. && (p_sattr->attr_value.v.u16 == profile_uuid)) {
  753. /* Now fill in the major and minor numbers */
  754. /* if the attribute matches the description for version (type UINT, size 2 bytes) */
  755. p_sattr = p_sattr->p_next_attr;
  756. if ((SDP_DISC_ATTR_TYPE(p_sattr->attr_len_type) == UINT_DESC_TYPE) &&
  757. (SDP_DISC_ATTR_LEN(p_sattr->attr_len_type) == 2)) {
  758. /* The high order 8 bits is the major number, low order is the minor number (big endian) */
  759. *p_version = p_sattr->attr_value.v.u16;
  760. return (TRUE);
  761. } else {
  762. return (FALSE); /* The type and/or size was not valid for the profile list version */
  763. }
  764. }
  765. }
  766. }
  767. return (FALSE);
  768. }
  769. p_attr = p_attr->p_next_attr;
  770. }
  771. #endif /* CLIENT_ENABLED == TRUE */
  772. /* If here, no match found */
  773. return (FALSE);
  774. }
  775. /*******************************************************************************
  776. ** Device Identification (DI) Client Functions
  777. *******************************************************************************/
  778. /*******************************************************************************
  779. **
  780. ** Function SDP_DiDiscover
  781. **
  782. ** Description This function queries a remote device for DI information.
  783. **
  784. ** Returns SDP_SUCCESS if query started successfully, else error
  785. **
  786. *******************************************************************************/
  787. UINT16 SDP_DiDiscover( BD_ADDR remote_device, tSDP_DISCOVERY_DB *p_db,
  788. UINT32 len, tSDP_DISC_CMPL_CB *p_cb )
  789. {
  790. #if SDP_CLIENT_ENABLED == TRUE
  791. UINT16 result = SDP_DI_DISC_FAILED;
  792. UINT16 num_uuids = 1;
  793. UINT16 di_uuid = UUID_SERVCLASS_PNP_INFORMATION;
  794. /* build uuid for db init */
  795. tSDP_UUID init_uuid;
  796. init_uuid.len = 2;
  797. init_uuid.uu.uuid16 = di_uuid;
  798. if ( SDP_InitDiscoveryDb(p_db, len, num_uuids, &init_uuid, 0, NULL) )
  799. if ( SDP_ServiceSearchRequest(remote_device, p_db, p_cb) ) {
  800. result = SDP_SUCCESS;
  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. }