xref: /btstack/src/classic/sdp_server.c (revision bc37f7b0d0a3eaa5763a873c5730bc14b849aaa0)
1 /*
2  * Copyright (C) 2014 BlueKitchen GmbH
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 BLUEKITCHEN GMBH 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
34  * [email protected]
35  *
36  */
37 
38 /*
39  * Implementation of the Service Discovery Protocol Server
40  */
41 
42 #include <stdio.h>
43 #include <string.h>
44 
45 #include "btstack_debug.h"
46 #include "btstack_event.h"
47 #include "btstack_memory.h"
48 #include "classic/core.h"
49 #include "classic/sdp_server.h"
50 #include "classic/sdp_util.h"
51 #include "hci_dump.h"
52 #include "l2cap.h"
53 
54 // max reserved ServiceRecordHandle
55 #define maxReservedServiceRecordHandle 0xffff
56 
57 // max SDP response matches L2CAP PDU -- allow to use smaller buffer
58 #ifndef SDP_RESPONSE_BUFFER_SIZE
59 #define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_BUFFER_SIZE-HCI_ACL_HEADER_SIZE)
60 #endif
61 
62 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
63 
64 // registered service records
65 static btstack_linked_list_t sdp_service_records = NULL;
66 
67 // our handles start after the reserved range
68 static uint32_t sdp_next_service_record_handle = ((uint32_t) maxReservedServiceRecordHandle) + 2;
69 
70 static uint8_t sdp_response_buffer[SDP_RESPONSE_BUFFER_SIZE];
71 
72 static uint16_t l2cap_cid = 0;
73 static uint16_t sdp_response_size = 0;
74 
75 void sdp_init(void){
76     // register with l2cap psm sevices - max MTU
77     l2cap_register_service(sdp_packet_handler, PSM_SDP, 0xffff, LEVEL_0);
78 }
79 
80 uint32_t sdp_get_service_record_handle(const uint8_t * record){
81     // TODO: make sdp_get_attribute_value_for_attribute_id accept const data to remove cast
82     uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id((uint8_t *)record, SDP_ServiceRecordHandle);
83     if (!serviceRecordHandleAttribute) return 0;
84     if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0;
85     if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0;
86     return big_endian_read_32(serviceRecordHandleAttribute, 1);
87 }
88 
89 static service_record_item_t * sdp_get_record_item_for_handle(uint32_t handle){
90     btstack_linked_item_t *it;
91     for (it = (btstack_linked_item_t *) sdp_service_records; it ; it = it->next){
92         service_record_item_t * item = (service_record_item_t *) it;
93         if (item->service_record_handle == handle){
94             return item;
95         }
96     }
97     return NULL;
98 }
99 
100 uint8_t * sdp_get_record_for_handle(uint32_t handle){
101     service_record_item_t * record_item =  sdp_get_record_item_for_handle(handle);
102     if (!record_item) return 0;
103     return record_item->service_record;
104 }
105 
106 // get next free, unregistered service record handle
107 uint32_t sdp_create_service_record_handle(void){
108     uint32_t handle = 0;
109     do {
110         handle = sdp_next_service_record_handle++;
111         if (sdp_get_record_item_for_handle(handle)) handle = 0;
112     } while (handle == 0);
113     return handle;
114 }
115 
116 /**
117  * @brief Register Service Record with database using ServiceRecordHandle stored in record
118  * @pre AttributeIDs are in ascending order
119  * @pre ServiceRecordHandle is first attribute and valid
120  * @param record is not copied!
121  * @result status
122  */
123 uint8_t sdp_register_service(const uint8_t * record){
124 
125     // validate service record handle. it must: exist, be in valid range, not have been already used
126     uint32_t record_handle = sdp_get_service_record_handle(record);
127     if (!record_handle) return SDP_HANDLE_INVALID;
128     if (record_handle <= maxReservedServiceRecordHandle) return SDP_HANDLE_INVALID;
129     if (sdp_get_record_item_for_handle(record_handle)) return SDP_HANDLE_ALREADY_REGISTERED;
130 
131     // alloc memory for new service_record_item
132     service_record_item_t * newRecordItem = btstack_memory_service_record_item_get();
133     if (!newRecordItem) return BTSTACK_MEMORY_ALLOC_FAILED;
134 
135     // set handle and record
136     newRecordItem->service_record_handle = record_handle;
137     newRecordItem->service_record = (uint8_t*) record;
138 
139     // add to linked list
140     btstack_linked_list_add(&sdp_service_records, (btstack_linked_item_t *) newRecordItem);
141 
142     return 0;
143 }
144 
145 //
146 // unregister service record
147 //
148 void sdp_unregister_service(uint32_t service_record_handle){
149     service_record_item_t * record_item = sdp_get_record_item_for_handle(service_record_handle);
150     if (!record_item) return;
151     btstack_linked_list_remove(&sdp_service_records, (btstack_linked_item_t *) record_item);
152 }
153 
154 // PDU
155 // PDU ID (1), Transaction ID (2), Param Length (2), Param 1, Param 2, ..
156 
157 static int sdp_create_error_response(uint16_t transaction_id, uint16_t error_code){
158     sdp_response_buffer[0] = SDP_ErrorResponse;
159     big_endian_store_16(sdp_response_buffer, 1, transaction_id);
160     big_endian_store_16(sdp_response_buffer, 3, 2);
161     big_endian_store_16(sdp_response_buffer, 5, error_code); // invalid syntax
162     return 7;
163 }
164 
165 int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu){
166 
167     // get request details
168     uint16_t  transaction_id = big_endian_read_16(packet, 1);
169     // not used yet - uint16_t  param_len = big_endian_read_16(packet, 3);
170     uint8_t * serviceSearchPattern = &packet[5];
171     uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
172     uint16_t  maximumServiceRecordCount = big_endian_read_16(packet, 5 + serviceSearchPatternLen);
173     uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2];
174 
175     // calc maxumumServiceRecordCount based on remote MTU
176     uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4;
177 
178     // continuation state contains index of next service record to examine
179     int      continuation = 0;
180     uint16_t continuation_index = 0;
181     if (continuationState[0] == 2){
182         continuation_index = big_endian_read_16(continuationState, 1);
183     }
184 
185     // get and limit total count
186     btstack_linked_item_t *it;
187     uint16_t total_service_count   = 0;
188     for (it = (btstack_linked_item_t *) sdp_service_records; it ; it = it->next){
189         service_record_item_t * item = (service_record_item_t *) it;
190         if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
191         total_service_count++;
192     }
193     if (total_service_count > maximumServiceRecordCount){
194         total_service_count = maximumServiceRecordCount;
195     }
196 
197     // ServiceRecordHandleList at 9
198     uint16_t pos = 9;
199     uint16_t current_service_count  = 0;
200     uint16_t current_service_index  = 0;
201     uint16_t matching_service_count = 0;
202     for (it = (btstack_linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index){
203         service_record_item_t * item = (service_record_item_t *) it;
204 
205         if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
206         matching_service_count++;
207 
208         if (current_service_index < continuation_index) continue;
209 
210         big_endian_store_32(sdp_response_buffer, pos, item->service_record_handle);
211         pos += 4;
212         current_service_count++;
213 
214         if (matching_service_count >= total_service_count) break;
215 
216         if (current_service_count >= maxNrServiceRecordsPerResponse){
217             continuation = 1;
218             continuation_index = current_service_index + 1;
219             break;
220         }
221     }
222 
223     // Store continuation state
224     if (continuation) {
225         sdp_response_buffer[pos++] = 2;
226         big_endian_store_16(sdp_response_buffer, pos, continuation_index);
227         pos += 2;
228     } else {
229         sdp_response_buffer[pos++] = 0;
230     }
231 
232     // header
233     sdp_response_buffer[0] = SDP_ServiceSearchResponse;
234     big_endian_store_16(sdp_response_buffer, 1, transaction_id);
235     big_endian_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload
236     big_endian_store_16(sdp_response_buffer, 5, total_service_count);
237     big_endian_store_16(sdp_response_buffer, 7, current_service_count);
238 
239     return pos;
240 }
241 
242 int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){
243 
244     // get request details
245     uint16_t  transaction_id = big_endian_read_16(packet, 1);
246     // not used yet - uint16_t  param_len = big_endian_read_16(packet, 3);
247     uint32_t  serviceRecordHandle = big_endian_read_32(packet, 5);
248     uint16_t  maximumAttributeByteCount = big_endian_read_16(packet, 9);
249     uint8_t * attributeIDList = &packet[11];
250     uint16_t  attributeIDListLen = de_get_len(attributeIDList);
251     uint8_t * continuationState = &packet[11+attributeIDListLen];
252 
253     // calc maximumAttributeByteCount based on remote MTU
254     uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3);
255     if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
256         maximumAttributeByteCount = maximumAttributeByteCount2;
257     }
258 
259     // continuation state contains the offset into the complete response
260     uint16_t continuation_offset = 0;
261     if (continuationState[0] == 2){
262         continuation_offset = big_endian_read_16(continuationState, 1);
263     }
264 
265     // get service record
266     service_record_item_t * item = sdp_get_record_item_for_handle(serviceRecordHandle);
267     if (!item){
268         // service record handle doesn't exist
269         return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle
270     }
271 
272 
273     // AttributeList - starts at offset 7
274     uint16_t pos = 7;
275 
276     if (continuation_offset == 0){
277 
278         // get size of this record
279         uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
280 
281         // store DES
282         de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
283         maximumAttributeByteCount -= 3;
284         pos += 3;
285     }
286 
287     // copy maximumAttributeByteCount from record
288     uint16_t bytes_used;
289     int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
290     pos += bytes_used;
291 
292     uint16_t attributeListByteCount = pos - 7;
293 
294     if (complete) {
295         sdp_response_buffer[pos++] = 0;
296     } else {
297         continuation_offset += bytes_used;
298         sdp_response_buffer[pos++] = 2;
299         big_endian_store_16(sdp_response_buffer, pos, continuation_offset);
300         pos += 2;
301     }
302 
303     // header
304     sdp_response_buffer[0] = SDP_ServiceAttributeResponse;
305     big_endian_store_16(sdp_response_buffer, 1, transaction_id);
306     big_endian_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
307     big_endian_store_16(sdp_response_buffer, 5, attributeListByteCount);
308 
309     return pos;
310 }
311 
312 static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){
313     uint16_t total_response_size = 0;
314     btstack_linked_item_t *it;
315     for (it = (btstack_linked_item_t *) sdp_service_records; it ; it = it->next){
316         service_record_item_t * item = (service_record_item_t *) it;
317 
318         if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
319 
320         // for all service records that match
321         total_response_size += 3 + spd_get_filtered_size(item->service_record, attributeIDList);
322     }
323     return total_response_size;
324 }
325 
326 int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){
327 
328     // SDP header before attribute sevice list: 7
329     // Continuation, worst case: 5
330 
331     // get request details
332     uint16_t  transaction_id = big_endian_read_16(packet, 1);
333     // not used yet - uint16_t  param_len = big_endian_read_16(packet, 3);
334     uint8_t * serviceSearchPattern = &packet[5];
335     uint16_t  serviceSearchPatternLen = de_get_len(serviceSearchPattern);
336     uint16_t  maximumAttributeByteCount = big_endian_read_16(packet, 5 + serviceSearchPatternLen);
337     uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2];
338     uint16_t  attributeIDListLen = de_get_len(attributeIDList);
339     uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen];
340 
341     // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block
342     uint16_t maximumAttributeByteCount2 = remote_mtu - 12;
343     if (maximumAttributeByteCount2 < maximumAttributeByteCount) {
344         maximumAttributeByteCount = maximumAttributeByteCount2;
345     }
346 
347     // continuation state contains: index of next service record to examine
348     // continuation state contains: byte offset into this service record
349     uint16_t continuation_service_index = 0;
350     uint16_t continuation_offset = 0;
351     if (continuationState[0] == 4){
352         continuation_service_index = big_endian_read_16(continuationState, 1);
353         continuation_offset = big_endian_read_16(continuationState, 3);
354     }
355 
356     // log_info("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u", continuation_service_index, continuation_offset, maximumAttributeByteCount);
357 
358     // AttributeLists - starts at offset 7
359     uint16_t pos = 7;
360 
361     // add DES with total size for first request
362     if (continuation_service_index == 0 && continuation_offset == 0){
363         uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList);
364         de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size);
365         // log_info("total response size %u", total_response_size);
366         pos += 3;
367         maximumAttributeByteCount -= 3;
368     }
369 
370     // create attribute list
371     int      first_answer = 1;
372     int      continuation = 0;
373     uint16_t current_service_index = 0;
374     btstack_linked_item_t *it = (btstack_linked_item_t *) sdp_service_records;
375     for ( ; it ; it = it->next, ++current_service_index){
376         service_record_item_t * item = (service_record_item_t *) it;
377 
378         if (current_service_index < continuation_service_index ) continue;
379         if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue;
380 
381         if (continuation_offset == 0){
382 
383             // get size of this record
384             uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList);
385 
386             // stop if complete record doesn't fits into response but we already have a partial response
387             if ((filtered_attributes_size + 3 > maximumAttributeByteCount) && !first_answer) {
388                 continuation = 1;
389                 break;
390             }
391 
392             // store DES
393             de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size);
394             pos += 3;
395             maximumAttributeByteCount -= 3;
396         }
397 
398         first_answer = 0;
399 
400         // copy maximumAttributeByteCount from record
401         uint16_t bytes_used;
402         int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]);
403         pos += bytes_used;
404         maximumAttributeByteCount -= bytes_used;
405 
406         if (complete) {
407             continuation_offset = 0;
408             continue;
409         }
410 
411         continuation = 1;
412         continuation_offset += bytes_used;
413         break;
414     }
415 
416     uint16_t attributeListsByteCount = pos - 7;
417 
418     // Continuation State
419     if (continuation){
420         sdp_response_buffer[pos++] = 4;
421         big_endian_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index);
422         pos += 2;
423         big_endian_store_16(sdp_response_buffer, pos, continuation_offset);
424         pos += 2;
425     } else {
426         // complete
427         sdp_response_buffer[pos++] = 0;
428     }
429 
430     // create SDP header
431     sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse;
432     big_endian_store_16(sdp_response_buffer, 1, transaction_id);
433     big_endian_store_16(sdp_response_buffer, 3, pos - 5);  // size of variable payload
434     big_endian_store_16(sdp_response_buffer, 5, attributeListsByteCount);
435 
436     return pos;
437 }
438 
439 static void sdp_respond(void){
440     if (!sdp_response_size ) return;
441     if (!l2cap_cid) return;
442 
443     // update state before sending packet (avoid getting called when new l2cap credit gets emitted)
444     uint16_t size = sdp_response_size;
445     sdp_response_size = 0;
446     l2cap_send(l2cap_cid, sdp_response_buffer, size);
447 }
448 
449 // we assume that we don't get two requests in a row
450 static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
451 	uint16_t transaction_id;
452     SDP_PDU_ID_t pdu_id;
453     uint16_t remote_mtu;
454     // uint16_t param_len;
455 
456 	switch (packet_type) {
457 
458 		case L2CAP_DATA_PACKET:
459             pdu_id = (SDP_PDU_ID_t) packet[0];
460             transaction_id = big_endian_read_16(packet, 1);
461             // param_len = big_endian_read_16(packet, 3);
462             remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel);
463             // account for our buffer
464             if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){
465                 remote_mtu = SDP_RESPONSE_BUFFER_SIZE;
466             }
467 
468             // log_info("SDP Request: type %u, transaction id %u, len %u, mtu %u", pdu_id, transaction_id, param_len, remote_mtu);
469             switch (pdu_id){
470 
471                 case SDP_ServiceSearchRequest:
472                     sdp_response_size = sdp_handle_service_search_request(packet, remote_mtu);
473                     break;
474 
475                 case SDP_ServiceAttributeRequest:
476                     sdp_response_size = sdp_handle_service_attribute_request(packet, remote_mtu);
477                     break;
478 
479                 case SDP_ServiceSearchAttributeRequest:
480                     sdp_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu);
481                     break;
482 
483                 default:
484                     sdp_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax
485                     break;
486             }
487             if (!sdp_response_size) break;
488             l2cap_request_can_send_now_event(l2cap_cid);
489 			break;
490 
491 		case HCI_EVENT_PACKET:
492 
493 			switch (hci_event_packet_get_type(packet)) {
494 
495 				case L2CAP_EVENT_INCOMING_CONNECTION:
496                     if (l2cap_cid) {
497                         // CONNECTION REJECTED DUE TO LIMITED RESOURCES
498                         l2cap_decline_connection(channel);
499                         break;
500                     }
501                     // accept
502                     l2cap_cid = channel;
503                     sdp_response_size = 0;
504                     l2cap_accept_connection(channel);
505 					break;
506 
507                 case L2CAP_EVENT_CHANNEL_OPENED:
508                     if (packet[2]) {
509                         // open failed -> reset
510                         l2cap_cid = 0;
511                     }
512                     break;
513 
514                 case L2CAP_EVENT_CAN_SEND_NOW:
515                     sdp_respond();
516                     break;
517 
518                 case L2CAP_EVENT_CHANNEL_CLOSED:
519                     if (channel == l2cap_cid){
520                         // reset
521                         l2cap_cid = 0;
522                     }
523                     break;
524 
525 				default:
526 					// other event
527 					break;
528 			}
529 			break;
530 
531 		default:
532 			// other packet type
533 			break;
534 	}
535 }
536 
537