source: asp3_tinet_ecnl_rx/trunk/btstack/src/sdp_client.c@ 374

Last change on this file since 374 was 374, checked in by coas-nagasima, 5 years ago

mbed関連を更新
シリアルドライバをmbedのHALを使うよう変更
ファイルディスクリプタの処理を更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 17.0 KB
Line 
1/*
2 * Copyright (C) 2009-2013 by Matthias Ringwald
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holders nor the names of
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * 4. Any redistribution, use, or modification is done solely for
17 * personal benefit and not for any commercial purpose or for
18 * monetary gain.
19 *
20 * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Please inquire about commercial licensing options at btstack@ringwald.ch
34 *
35 */
36
37/*
38 * sdp_client.c
39 */
40
41#include "btstack-config.h"
42#include "sdp_client.h"
43
44#include <btstack/hci_cmds.h>
45
46#include "l2cap.h"
47#include "sdp_parser.h"
48#include "sdp.h"
49#include "debug.h"
50
51typedef enum {
52 INIT, W4_CONNECT, W2_SEND, W4_RESPONSE, QUERY_COMPLETE
53} sdp_client_state_t;
54
55
56void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
57
58static uint16_t setup_service_search_attribute_request(uint8_t * data);
59
60#ifdef HAVE_SDP_EXTRA_QUERIES
61static uint16_t setup_service_search_request(uint8_t * data);
62static uint16_t setup_service_attribute_request(uint8_t * data);
63static void parse_service_search_response(uint8_t* packet);
64static void parse_service_attribute_response(uint8_t* packet);
65static uint32_t serviceRecordHandle;
66#endif
67
68// SDP Client Query
69static uint16_t mtu;
70static uint16_t sdp_cid = 0x40;
71static uint8_t * serviceSearchPattern;
72static uint8_t * attributeIDList;
73static uint16_t transactionID = 0;
74static uint8_t continuationState[16];
75static uint8_t continuationStateLen;
76static sdp_client_state_t sdp_client_state = INIT;
77static SDP_PDU_ID_t PDU_ID = SDP_Invalid;
78
79// TODO: inline if not needed (des(des))
80void parse_attribute_lists(uint8_t* packet, uint16_t length){
81 sdp_parser_handle_chunk(packet, length);
82}
83
84/* Queries the SDP service of the remote device given a service search pattern
85and a list of attribute IDs. The remote data is handled by the SDP parser. The
86SDP parser delivers attribute values and done event via a registered callback. */
87
88void sdp_client_query(bd_addr_t remote, uint8_t * des_serviceSearchPattern, uint8_t * des_attributeIDList){
89 serviceSearchPattern = des_serviceSearchPattern;
90 attributeIDList = des_attributeIDList;
91 continuationStateLen = 0;
92 PDU_ID = SDP_ServiceSearchAttributeResponse;
93
94 sdp_client_state = W4_CONNECT;
95 l2cap_create_channel_internal(NULL, sdp_packet_handler, remote, PSM_SDP, l2cap_max_mtu());
96}
97
98static int can_send_now(uint16_t channel){
99 if (sdp_client_state != W2_SEND) return 0;
100 if (!l2cap_can_send_packet_now(channel)) return 0;
101 return 1;
102}
103
104static void send_request(uint16_t channel){
105 uint8_t * data;
106 uint16_t request_len;
107 int err;
108
109 l2cap_reserve_packet_buffer();
110 data = l2cap_get_outgoing_buffer();
111 request_len = 0;
112
113 switch (PDU_ID){
114#ifdef HAVE_SDP_EXTRA_QUERIES
115 case SDP_ServiceSearchResponse:
116 request_len = setup_service_search_request(data);
117 break;
118 case SDP_ServiceAttributeResponse:
119 request_len = setup_service_attribute_request(data);
120 break;
121#endif
122 case SDP_ServiceSearchAttributeResponse:
123 request_len = setup_service_search_attribute_request(data);
124 break;
125 default:
126 log_error("SDP Client send_request :: PDU ID invalid. %u", PDU_ID);
127 return;
128 }
129
130 // prevent re-entrance
131 sdp_client_state = W4_RESPONSE;
132 err = l2cap_send_prepared(channel, request_len);
133 // l2cap_send_prepared shouldn't have failed as l2ap_can_send_packet_now() was true
134 switch (err){
135 case 0:
136 log_debug("l2cap_send_internal() -> OK");
137 PDU_ID = SDP_Invalid;
138 break;
139 case BTSTACK_ACL_BUFFERS_FULL:
140 sdp_client_state = W2_SEND;
141 log_info("l2cap_send_internal() ->BTSTACK_ACL_BUFFERS_FULL");
142 break;
143 default:
144 sdp_client_state = W2_SEND;
145 log_error("l2cap_send_internal() -> err %d", err);
146 break;
147 }
148}
149
150
151static void parse_service_search_attribute_response(uint8_t* packet){
152 uint16_t offset = 3;
153 uint16_t parameterLength = big_endian_read_16(packet,offset);
154 uint16_t attributeListByteCount;
155 offset+=2;
156 // AttributeListByteCount <= mtu
157 attributeListByteCount = big_endian_read_16(packet,offset);
158 offset+=2;
159
160 if (attributeListByteCount > mtu){
161 log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount.");
162 return;
163 }
164
165 // AttributeLists
166 parse_attribute_lists(packet+offset, attributeListByteCount);
167 offset+=attributeListByteCount;
168
169 continuationStateLen = packet[offset];
170 offset++;
171
172 if (continuationStateLen > 16){
173 log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in continuation state exceedes 16.");
174 return;
175 }
176 memcpy(continuationState, packet+offset, continuationStateLen);
177 offset+=continuationStateLen;
178
179 if (parameterLength != offset - 5){
180 log_error("Error parsing ServiceSearchAttributeResponse: wrong size of parameters, number of expected bytes%u, actual number %u.", parameterLength, offset);
181 }
182}
183
184void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
185 // uint16_t handle;
186 if (packet_type == L2CAP_DATA_PACKET){
187 uint16_t responseTransactionID = big_endian_read_16(packet,1);
188 if ( responseTransactionID != transactionID){
189 log_error("Missmatching transaction ID, expected %u, found %u.", transactionID, responseTransactionID);
190 return;
191 }
192
193 if (packet[0] != SDP_ServiceSearchAttributeResponse
194 && packet[0] != SDP_ServiceSearchResponse
195 && packet[0] != SDP_ServiceAttributeResponse){
196 log_error("Not a valid PDU ID, expected %u, %u or %u, found %u.", SDP_ServiceSearchResponse,
197 SDP_ServiceAttributeResponse, SDP_ServiceSearchAttributeResponse, packet[0]);
198 return;
199 }
200
201 PDU_ID = packet[0];
202 log_info("SDP Client :: PDU ID. %u ,%u", PDU_ID, packet[0]);
203 switch (PDU_ID){
204#ifdef HAVE_SDP_EXTRA_QUERIES
205 case SDP_ServiceSearchResponse:
206 parse_service_search_response(packet);
207 break;
208 case SDP_ServiceAttributeResponse:
209 parse_service_attribute_response(packet);
210 break;
211#endif
212 case SDP_ServiceSearchAttributeResponse:
213 parse_service_search_attribute_response(packet);
214 break;
215 default:
216 log_error("SDP Client :: PDU ID invalid. %u ,%u", PDU_ID, packet[0]);
217 return;
218 }
219
220 // continuation set or DONE?
221 if (continuationStateLen == 0){
222 log_info("SDP Client Query DONE! ");
223 sdp_client_state = QUERY_COMPLETE;
224 l2cap_disconnect_internal(sdp_cid, 0);
225 // sdp_parser_handle_done(0);
226 return;
227 }
228 // prepare next request and send
229 sdp_client_state = W2_SEND;
230 if (can_send_now(sdp_cid)) send_request(sdp_cid);
231 return;
232 }
233
234 if (packet_type != HCI_EVENT_PACKET) return;
235
236 switch(packet[0]){
237 case L2CAP_EVENT_TIMEOUT_CHECK:
238 log_info("sdp client: L2CAP_EVENT_TIMEOUT_CHECK");
239 break;
240 case L2CAP_EVENT_CHANNEL_OPENED:
241 if (sdp_client_state != W4_CONNECT) break;
242 // data: event (8), len(8), status (8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16), local_mtu(16), remote_mtu(16)
243 if (packet[2]) {
244 log_error("SDP Client Connection failed.");
245 sdp_parser_handle_done(packet[2]);
246 break;
247 }
248 sdp_cid = channel;
249 mtu = little_endian_read_16(packet, 17);
250 // handle = little_endian_read_16(packet, 9);
251 log_info("SDP Client Connected, cid %x, mtu %u.", sdp_cid, mtu);
252
253 sdp_client_state = W2_SEND;
254 if (can_send_now(sdp_cid)) send_request(sdp_cid);
255
256 break;
257 case L2CAP_EVENT_CREDITS:
258 case DAEMON_EVENT_HCI_PACKET_SENT:
259 if (can_send_now(sdp_cid)) send_request(sdp_cid);
260 break;
261 case L2CAP_EVENT_CHANNEL_CLOSED: {
262 uint8_t status;
263 if (sdp_cid != little_endian_read_16(packet, 2)) {
264 // log_info("Received L2CAP_EVENT_CHANNEL_CLOSED for cid %x, current cid %x\n", little_endian_read_16(packet, 2),sdp_cid);
265 break;
266 }
267 log_info("SDP Client disconnected.");
268 status = sdp_client_state == QUERY_COMPLETE ? 0 : SDP_QUERY_INCOMPLETE;
269 sdp_client_state = INIT;
270 sdp_parser_handle_done(status);
271 break;
272 }
273 default:
274 break;
275 }
276}
277
278
279static uint16_t setup_service_search_attribute_request(uint8_t * data){
280
281 uint16_t offset = 0;
282 uint16_t serviceSearchPatternLen;
283 uint16_t attributeIDListLen;
284 transactionID++;
285 // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
286 data[offset++] = SDP_ServiceSearchAttributeRequest;
287 // uint16_t transactionID
288 net_store_16(data, offset, transactionID);
289 offset += 2;
290
291 // param legnth
292 offset += 2;
293
294 // parameters:
295 // ServiceSearchPattern - DES (min 1 UUID, max 12)
296 serviceSearchPatternLen = de_get_len(serviceSearchPattern);
297 memcpy(data + offset, serviceSearchPattern, serviceSearchPatternLen);
298 offset += serviceSearchPatternLen;
299
300 // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu
301 net_store_16(data, offset, mtu);
302 offset += 2;
303
304 // AttibuteIDList
305 attributeIDListLen = de_get_len(attributeIDList);
306 memcpy(data + offset, attributeIDList, attributeIDListLen);
307 offset += attributeIDListLen;
308
309 // ContinuationState - uint8_t number of cont. bytes N<=16
310 data[offset++] = continuationStateLen;
311 // - N-bytes previous response from server
312 memcpy(data + offset, continuationState, continuationStateLen);
313 offset += continuationStateLen;
314
315 // uint16_t paramLength
316 net_store_16(data, 3, offset - 5);
317
318 return offset;
319}
320
321#ifdef HAVE_SDP_EXTRA_QUERIES
322void parse_service_record_handle_list(uint8_t* packet, uint16_t total_count, uint16_t current_count){
323 sdp_parser_handle_service_search(packet, total_count, current_count);
324}
325
326static uint16_t setup_service_search_request(uint8_t * data){
327 uint16_t offset = 0;
328 uint16_t serviceSearchPatternLen;
329 transactionID++;
330 // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
331 data[offset++] = SDP_ServiceSearchRequest;
332 // uint16_t transactionID
333 net_store_16(data, offset, transactionID);
334 offset += 2;
335
336 // param legnth
337 offset += 2;
338
339 // parameters:
340 // ServiceSearchPattern - DES (min 1 UUID, max 12)
341 serviceSearchPatternLen = de_get_len(serviceSearchPattern);
342 memcpy(data + offset, serviceSearchPattern, serviceSearchPatternLen);
343 offset += serviceSearchPatternLen;
344
345 // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu
346 net_store_16(data, offset, mtu);
347 offset += 2;
348
349 // ContinuationState - uint8_t number of cont. bytes N<=16
350 data[offset++] = continuationStateLen;
351 // - N-bytes previous response from server
352 memcpy(data + offset, continuationState, continuationStateLen);
353 offset += continuationStateLen;
354
355 // uint16_t paramLength
356 net_store_16(data, 3, offset - 5);
357
358 return offset;
359}
360
361
362static uint16_t setup_service_attribute_request(uint8_t * data){
363
364 uint16_t offset = 0;
365 uint16_t attributeIDListLen;
366 transactionID++;
367 // uint8_t SDP_PDU_ID_t.SDP_ServiceSearchRequest;
368 data[offset++] = SDP_ServiceAttributeRequest;
369 // uint16_t transactionID
370 net_store_16(data, offset, transactionID);
371 offset += 2;
372
373 // param legnth
374 offset += 2;
375
376 // parameters:
377 // ServiceRecordHandle
378 net_store_32(data, offset, serviceRecordHandle);
379 offset += 4;
380
381 // MaximumAttributeByteCount - uint16_t 0x0007 - 0xffff -> mtu
382 net_store_16(data, offset, mtu);
383 offset += 2;
384
385 // AttibuteIDList
386 attributeIDListLen = de_get_len(attributeIDList);
387 memcpy(data + offset, attributeIDList, attributeIDListLen);
388 offset += attributeIDListLen;
389
390 // ContinuationState - uint8_t number of cont. bytes N<=16
391 data[offset++] = continuationStateLen;
392 // - N-bytes previous response from server
393 memcpy(data + offset, continuationState, continuationStateLen);
394 offset += continuationStateLen;
395
396 // uint16_t paramLength
397 net_store_16(data, 3, offset - 5);
398
399 return offset;
400}
401
402static void parse_service_search_response(uint8_t* packet){
403 uint16_t offset = 3;
404 uint16_t parameterLength = big_endian_read_16(packet,offset);
405 uint16_t totalServiceRecordCount;
406 uint16_t currentServiceRecordCount;
407 offset+=2;
408
409 totalServiceRecordCount = big_endian_read_16(packet,offset);
410 offset+=2;
411
412 currentServiceRecordCount = big_endian_read_16(packet,offset);
413 offset+=2;
414 if (currentServiceRecordCount > totalServiceRecordCount){
415 log_error("CurrentServiceRecordCount is larger then TotalServiceRecordCount.");
416 return;
417 }
418
419 parse_service_record_handle_list(packet+offset, totalServiceRecordCount, currentServiceRecordCount);
420 offset+=(currentServiceRecordCount * 4);
421
422 continuationStateLen = packet[offset];
423 offset++;
424 if (continuationStateLen > 16){
425 log_error("Error parsing ServiceSearchResponse: Number of bytes in continuation state exceedes 16.");
426 return;
427 }
428 memcpy(continuationState, packet+offset, continuationStateLen);
429 offset+=continuationStateLen;
430
431 if (parameterLength != offset - 5){
432 log_error("Error parsing ServiceSearchResponse: wrong size of parameters, number of expected bytes%u, actual number %u.", parameterLength, offset);
433 }
434}
435
436static void parse_service_attribute_response(uint8_t* packet){
437 uint16_t offset = 3;
438 uint16_t parameterLength = big_endian_read_16(packet,offset);
439 uint16_t attributeListByteCount;
440 offset+=2;
441
442 // AttributeListByteCount <= mtu
443 attributeListByteCount = big_endian_read_16(packet,offset);
444 offset+=2;
445
446 if (attributeListByteCount > mtu){
447 log_error("Error parsing ServiceSearchAttributeResponse: Number of bytes in found attribute list is larger then the MaximumAttributeByteCount.");
448 return;
449 }
450
451 // AttributeLists
452 parse_attribute_lists(packet+offset, attributeListByteCount);
453 offset+=attributeListByteCount;
454
455 continuationStateLen = packet[offset];
456 offset++;
457
458 if (continuationStateLen > 16){
459 log_error("Error parsing ServiceAttributeResponse: Number of bytes in continuation state exceedes 16.");
460 return;
461 }
462 memcpy(continuationState, packet+offset, continuationStateLen);
463 offset+=continuationStateLen;
464
465 if (parameterLength != offset - 5){
466 log_error("Error parsing ServiceAttributeResponse: wrong size of parameters, number of expected bytes%u, actual number %u.", parameterLength, offset);
467 }
468}
469
470void sdp_client_service_attribute_search(bd_addr_t remote, uint32_t search_serviceRecordHandle, uint8_t * des_attributeIDList){
471 serviceRecordHandle = search_serviceRecordHandle;
472 attributeIDList = des_attributeIDList;
473 continuationStateLen = 0;
474 PDU_ID = SDP_ServiceAttributeResponse;
475
476 sdp_client_state = W4_CONNECT;
477 l2cap_create_channel_internal(NULL, sdp_packet_handler, remote, PSM_SDP, l2cap_max_mtu());
478}
479
480void sdp_client_service_search(bd_addr_t remote, uint8_t * des_serviceSearchPattern){
481 serviceSearchPattern = des_serviceSearchPattern;
482 continuationStateLen = 0;
483 PDU_ID = SDP_ServiceSearchResponse;
484
485 sdp_client_state = W4_CONNECT;
486 l2cap_create_channel_internal(NULL, sdp_packet_handler, remote, PSM_SDP, l2cap_max_mtu());
487}
488#endif
489
Note: See TracBrowser for help on using the repository browser.