![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
BTstack for Nucleo F401RE/FRDM-KL46Z example program
Dependencies: F401RE-USBHost mbed
The usage is the same as KL46Z-BTstack_example.
使い方はKL46Z-BTstack_exampleと同じです。
BTstack/sdp.c@0:a05a07cd6fdf, 2014-06-09 (annotated)
- Committer:
- va009039
- Date:
- Mon Jun 09 09:03:25 2014 +0000
- Revision:
- 0:a05a07cd6fdf
first commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
va009039 | 0:a05a07cd6fdf | 1 | /* |
va009039 | 0:a05a07cd6fdf | 2 | * Copyright (C) 2009-2012 by Matthias Ringwald |
va009039 | 0:a05a07cd6fdf | 3 | * |
va009039 | 0:a05a07cd6fdf | 4 | * Redistribution and use in source and binary forms, with or without |
va009039 | 0:a05a07cd6fdf | 5 | * modification, are permitted provided that the following conditions |
va009039 | 0:a05a07cd6fdf | 6 | * are met: |
va009039 | 0:a05a07cd6fdf | 7 | * |
va009039 | 0:a05a07cd6fdf | 8 | * 1. Redistributions of source code must retain the above copyright |
va009039 | 0:a05a07cd6fdf | 9 | * notice, this list of conditions and the following disclaimer. |
va009039 | 0:a05a07cd6fdf | 10 | * 2. Redistributions in binary form must reproduce the above copyright |
va009039 | 0:a05a07cd6fdf | 11 | * notice, this list of conditions and the following disclaimer in the |
va009039 | 0:a05a07cd6fdf | 12 | * documentation and/or other materials provided with the distribution. |
va009039 | 0:a05a07cd6fdf | 13 | * 3. Neither the name of the copyright holders nor the names of |
va009039 | 0:a05a07cd6fdf | 14 | * contributors may be used to endorse or promote products derived |
va009039 | 0:a05a07cd6fdf | 15 | * from this software without specific prior written permission. |
va009039 | 0:a05a07cd6fdf | 16 | * 4. Any redistribution, use, or modification is done solely for |
va009039 | 0:a05a07cd6fdf | 17 | * personal benefit and not for any commercial purpose or for |
va009039 | 0:a05a07cd6fdf | 18 | * monetary gain. |
va009039 | 0:a05a07cd6fdf | 19 | * |
va009039 | 0:a05a07cd6fdf | 20 | * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS |
va009039 | 0:a05a07cd6fdf | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
va009039 | 0:a05a07cd6fdf | 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
va009039 | 0:a05a07cd6fdf | 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS |
va009039 | 0:a05a07cd6fdf | 24 | * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
va009039 | 0:a05a07cd6fdf | 25 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
va009039 | 0:a05a07cd6fdf | 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
va009039 | 0:a05a07cd6fdf | 27 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
va009039 | 0:a05a07cd6fdf | 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
va009039 | 0:a05a07cd6fdf | 29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF |
va009039 | 0:a05a07cd6fdf | 30 | * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
va009039 | 0:a05a07cd6fdf | 31 | * SUCH DAMAGE. |
va009039 | 0:a05a07cd6fdf | 32 | * |
va009039 | 0:a05a07cd6fdf | 33 | * Please inquire about commercial licensing options at btstack@ringwald.ch |
va009039 | 0:a05a07cd6fdf | 34 | * |
va009039 | 0:a05a07cd6fdf | 35 | */ |
va009039 | 0:a05a07cd6fdf | 36 | |
va009039 | 0:a05a07cd6fdf | 37 | /* |
va009039 | 0:a05a07cd6fdf | 38 | * Implementation of the Service Discovery Protocol Server |
va009039 | 0:a05a07cd6fdf | 39 | */ |
va009039 | 0:a05a07cd6fdf | 40 | |
va009039 | 0:a05a07cd6fdf | 41 | #include "sdp.h" |
va009039 | 0:a05a07cd6fdf | 42 | |
va009039 | 0:a05a07cd6fdf | 43 | |
va009039 | 0:a05a07cd6fdf | 44 | #include <stdio.h> |
va009039 | 0:a05a07cd6fdf | 45 | #include <string.h> |
va009039 | 0:a05a07cd6fdf | 46 | |
va009039 | 0:a05a07cd6fdf | 47 | #include <btstack/sdp_util.h> |
va009039 | 0:a05a07cd6fdf | 48 | |
va009039 | 0:a05a07cd6fdf | 49 | #include "hci_dump.h" |
va009039 | 0:a05a07cd6fdf | 50 | #include "l2cap.h" |
va009039 | 0:a05a07cd6fdf | 51 | |
va009039 | 0:a05a07cd6fdf | 52 | #include "debug.h" |
va009039 | 0:a05a07cd6fdf | 53 | |
va009039 | 0:a05a07cd6fdf | 54 | // max reserved ServiceRecordHandle |
va009039 | 0:a05a07cd6fdf | 55 | #define maxReservedServiceRecordHandle 0xffff |
va009039 | 0:a05a07cd6fdf | 56 | |
va009039 | 0:a05a07cd6fdf | 57 | // max SDP response |
va009039 | 0:a05a07cd6fdf | 58 | #define SDP_RESPONSE_BUFFER_SIZE (HCI_ACL_BUFFER_SIZE-HCI_ACL_HEADER_SIZE) |
va009039 | 0:a05a07cd6fdf | 59 | |
va009039 | 0:a05a07cd6fdf | 60 | static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); |
va009039 | 0:a05a07cd6fdf | 61 | |
va009039 | 0:a05a07cd6fdf | 62 | // registered service records |
va009039 | 0:a05a07cd6fdf | 63 | static linked_list_t sdp_service_records = NULL; |
va009039 | 0:a05a07cd6fdf | 64 | |
va009039 | 0:a05a07cd6fdf | 65 | // our handles start after the reserved range |
va009039 | 0:a05a07cd6fdf | 66 | static uint32_t sdp_next_service_record_handle = maxReservedServiceRecordHandle + 2; |
va009039 | 0:a05a07cd6fdf | 67 | |
va009039 | 0:a05a07cd6fdf | 68 | static uint8_t sdp_response_buffer[SDP_RESPONSE_BUFFER_SIZE]; |
va009039 | 0:a05a07cd6fdf | 69 | |
va009039 | 0:a05a07cd6fdf | 70 | static void (*app_packet_handler)(void * connection, uint8_t packet_type, |
va009039 | 0:a05a07cd6fdf | 71 | uint16_t channel, uint8_t *packet, uint16_t size) = NULL; |
va009039 | 0:a05a07cd6fdf | 72 | |
va009039 | 0:a05a07cd6fdf | 73 | static uint16_t l2cap_cid = 0; |
va009039 | 0:a05a07cd6fdf | 74 | static uint16_t sdp_response_size = 0; |
va009039 | 0:a05a07cd6fdf | 75 | |
va009039 | 0:a05a07cd6fdf | 76 | void sdp_init(){ |
va009039 | 0:a05a07cd6fdf | 77 | // register with l2cap psm sevices - max MTU |
va009039 | 0:a05a07cd6fdf | 78 | l2cap_register_service_internal(NULL, sdp_packet_handler, PSM_SDP, 0xffff); |
va009039 | 0:a05a07cd6fdf | 79 | } |
va009039 | 0:a05a07cd6fdf | 80 | |
va009039 | 0:a05a07cd6fdf | 81 | // register packet handler |
va009039 | 0:a05a07cd6fdf | 82 | void sdp_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, |
va009039 | 0:a05a07cd6fdf | 83 | uint16_t channel, uint8_t *packet, uint16_t size)){ |
va009039 | 0:a05a07cd6fdf | 84 | app_packet_handler = handler; |
va009039 | 0:a05a07cd6fdf | 85 | l2cap_cid = 0; |
va009039 | 0:a05a07cd6fdf | 86 | } |
va009039 | 0:a05a07cd6fdf | 87 | |
va009039 | 0:a05a07cd6fdf | 88 | uint32_t sdp_get_service_record_handle(uint8_t * record){ |
va009039 | 0:a05a07cd6fdf | 89 | uint8_t * serviceRecordHandleAttribute = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle); |
va009039 | 0:a05a07cd6fdf | 90 | if (!serviceRecordHandleAttribute) return 0; |
va009039 | 0:a05a07cd6fdf | 91 | if (de_get_element_type(serviceRecordHandleAttribute) != DE_UINT) return 0; |
va009039 | 0:a05a07cd6fdf | 92 | if (de_get_size_type(serviceRecordHandleAttribute) != DE_SIZE_32) return 0; |
va009039 | 0:a05a07cd6fdf | 93 | return READ_NET_32(serviceRecordHandleAttribute, 1); |
va009039 | 0:a05a07cd6fdf | 94 | } |
va009039 | 0:a05a07cd6fdf | 95 | |
va009039 | 0:a05a07cd6fdf | 96 | // data: event(8), len(8), status(8), service_record_handle(32) |
va009039 | 0:a05a07cd6fdf | 97 | static void sdp_emit_service_registered(void *connection, uint32_t handle, uint8_t status) { |
va009039 | 0:a05a07cd6fdf | 98 | if (!app_packet_handler) return; |
va009039 | 0:a05a07cd6fdf | 99 | uint8_t event[7]; |
va009039 | 0:a05a07cd6fdf | 100 | event[0] = SDP_SERVICE_REGISTERED; |
va009039 | 0:a05a07cd6fdf | 101 | event[1] = sizeof(event) - 2; |
va009039 | 0:a05a07cd6fdf | 102 | event[2] = status; |
va009039 | 0:a05a07cd6fdf | 103 | bt_store_32(event, 3, handle); |
va009039 | 0:a05a07cd6fdf | 104 | hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event)); |
va009039 | 0:a05a07cd6fdf | 105 | (*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event)); |
va009039 | 0:a05a07cd6fdf | 106 | } |
va009039 | 0:a05a07cd6fdf | 107 | |
va009039 | 0:a05a07cd6fdf | 108 | service_record_item_t * sdp_get_record_for_handle(uint32_t handle){ |
va009039 | 0:a05a07cd6fdf | 109 | linked_item_t *it; |
va009039 | 0:a05a07cd6fdf | 110 | for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){ |
va009039 | 0:a05a07cd6fdf | 111 | service_record_item_t * item = (service_record_item_t *) it; |
va009039 | 0:a05a07cd6fdf | 112 | if (item->service_record_handle == handle){ |
va009039 | 0:a05a07cd6fdf | 113 | return item; |
va009039 | 0:a05a07cd6fdf | 114 | } |
va009039 | 0:a05a07cd6fdf | 115 | } |
va009039 | 0:a05a07cd6fdf | 116 | return NULL; |
va009039 | 0:a05a07cd6fdf | 117 | } |
va009039 | 0:a05a07cd6fdf | 118 | |
va009039 | 0:a05a07cd6fdf | 119 | // get next free, unregistered service record handle |
va009039 | 0:a05a07cd6fdf | 120 | uint32_t sdp_create_service_record_handle(void){ |
va009039 | 0:a05a07cd6fdf | 121 | uint32_t handle = 0; |
va009039 | 0:a05a07cd6fdf | 122 | do { |
va009039 | 0:a05a07cd6fdf | 123 | handle = sdp_next_service_record_handle++; |
va009039 | 0:a05a07cd6fdf | 124 | if (sdp_get_record_for_handle(handle)) handle = 0; |
va009039 | 0:a05a07cd6fdf | 125 | } while (handle == 0); |
va009039 | 0:a05a07cd6fdf | 126 | return handle; |
va009039 | 0:a05a07cd6fdf | 127 | } |
va009039 | 0:a05a07cd6fdf | 128 | |
va009039 | 0:a05a07cd6fdf | 129 | #ifdef EMBEDDED |
va009039 | 0:a05a07cd6fdf | 130 | |
va009039 | 0:a05a07cd6fdf | 131 | // register service record internally - this special version doesn't copy the record, it should not be freeed |
va009039 | 0:a05a07cd6fdf | 132 | // pre: AttributeIDs are in ascending order |
va009039 | 0:a05a07cd6fdf | 133 | // pre: ServiceRecordHandle is first attribute and valid |
va009039 | 0:a05a07cd6fdf | 134 | // pre: record |
va009039 | 0:a05a07cd6fdf | 135 | // @returns ServiceRecordHandle or 0 if registration failed |
va009039 | 0:a05a07cd6fdf | 136 | uint32_t sdp_register_service_internal(void *connection, service_record_item_t * record_item){ |
va009039 | 0:a05a07cd6fdf | 137 | // get user record handle |
va009039 | 0:a05a07cd6fdf | 138 | uint32_t record_handle = record_item->service_record_handle; |
va009039 | 0:a05a07cd6fdf | 139 | // get actual record |
va009039 | 0:a05a07cd6fdf | 140 | uint8_t *record = record_item->service_record; |
va009039 | 0:a05a07cd6fdf | 141 | |
va009039 | 0:a05a07cd6fdf | 142 | // check for ServiceRecordHandle attribute, returns pointer or null |
va009039 | 0:a05a07cd6fdf | 143 | uint8_t * req_record_handle = sdp_get_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle); |
va009039 | 0:a05a07cd6fdf | 144 | if (!req_record_handle) { |
va009039 | 0:a05a07cd6fdf | 145 | log_error("SDP Error - record does not contain ServiceRecordHandle attribute\n"); |
va009039 | 0:a05a07cd6fdf | 146 | return 0; |
va009039 | 0:a05a07cd6fdf | 147 | } |
va009039 | 0:a05a07cd6fdf | 148 | |
va009039 | 0:a05a07cd6fdf | 149 | // validate service record handle is not in reserved range |
va009039 | 0:a05a07cd6fdf | 150 | if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0; |
va009039 | 0:a05a07cd6fdf | 151 | |
va009039 | 0:a05a07cd6fdf | 152 | // check if already in use |
va009039 | 0:a05a07cd6fdf | 153 | if (record_handle) { |
va009039 | 0:a05a07cd6fdf | 154 | if (sdp_get_record_for_handle(record_handle)) { |
va009039 | 0:a05a07cd6fdf | 155 | record_handle = 0; |
va009039 | 0:a05a07cd6fdf | 156 | } |
va009039 | 0:a05a07cd6fdf | 157 | } |
va009039 | 0:a05a07cd6fdf | 158 | |
va009039 | 0:a05a07cd6fdf | 159 | // create new handle if needed |
va009039 | 0:a05a07cd6fdf | 160 | if (!record_handle){ |
va009039 | 0:a05a07cd6fdf | 161 | record_handle = sdp_create_service_record_handle(); |
va009039 | 0:a05a07cd6fdf | 162 | // Write the handle back into the record too |
va009039 | 0:a05a07cd6fdf | 163 | record_item->service_record_handle = record_handle; |
va009039 | 0:a05a07cd6fdf | 164 | sdp_set_attribute_value_for_attribute_id(record, SDP_ServiceRecordHandle, record_handle); |
va009039 | 0:a05a07cd6fdf | 165 | } |
va009039 | 0:a05a07cd6fdf | 166 | |
va009039 | 0:a05a07cd6fdf | 167 | // add to linked list |
va009039 | 0:a05a07cd6fdf | 168 | linked_list_add(&sdp_service_records, (linked_item_t *) record_item); |
va009039 | 0:a05a07cd6fdf | 169 | |
va009039 | 0:a05a07cd6fdf | 170 | sdp_emit_service_registered(connection, 0, record_item->service_record_handle); |
va009039 | 0:a05a07cd6fdf | 171 | |
va009039 | 0:a05a07cd6fdf | 172 | return record_handle; |
va009039 | 0:a05a07cd6fdf | 173 | } |
va009039 | 0:a05a07cd6fdf | 174 | |
va009039 | 0:a05a07cd6fdf | 175 | #else |
va009039 | 0:a05a07cd6fdf | 176 | |
va009039 | 0:a05a07cd6fdf | 177 | // AttributeIDList used to remove ServiceRecordHandle |
va009039 | 0:a05a07cd6fdf | 178 | static const uint8_t removeServiceRecordHandleAttributeIDList[] = { 0x36, 0x00, 0x05, 0x0A, 0x00, 0x01, 0xFF, 0xFF }; |
va009039 | 0:a05a07cd6fdf | 179 | |
va009039 | 0:a05a07cd6fdf | 180 | // register service record internally - the normal version creates a copy of the record |
va009039 | 0:a05a07cd6fdf | 181 | // pre: AttributeIDs are in ascending order => ServiceRecordHandle is first attribute if present |
va009039 | 0:a05a07cd6fdf | 182 | // @returns ServiceRecordHandle or 0 if registration failed |
va009039 | 0:a05a07cd6fdf | 183 | uint32_t sdp_register_service_internal(void *connection, uint8_t * record){ |
va009039 | 0:a05a07cd6fdf | 184 | |
va009039 | 0:a05a07cd6fdf | 185 | // dump for now |
va009039 | 0:a05a07cd6fdf | 186 | // printf("Register service record\n"); |
va009039 | 0:a05a07cd6fdf | 187 | // de_dump_data_element(record); |
va009039 | 0:a05a07cd6fdf | 188 | |
va009039 | 0:a05a07cd6fdf | 189 | // get user record handle |
va009039 | 0:a05a07cd6fdf | 190 | uint32_t record_handle = sdp_get_service_record_handle(record); |
va009039 | 0:a05a07cd6fdf | 191 | |
va009039 | 0:a05a07cd6fdf | 192 | // validate service record handle is not in reserved range |
va009039 | 0:a05a07cd6fdf | 193 | if (record_handle <= maxReservedServiceRecordHandle) record_handle = 0; |
va009039 | 0:a05a07cd6fdf | 194 | |
va009039 | 0:a05a07cd6fdf | 195 | // check if already in use |
va009039 | 0:a05a07cd6fdf | 196 | if (record_handle) { |
va009039 | 0:a05a07cd6fdf | 197 | if (sdp_get_record_for_handle(record_handle)) { |
va009039 | 0:a05a07cd6fdf | 198 | record_handle = 0; |
va009039 | 0:a05a07cd6fdf | 199 | } |
va009039 | 0:a05a07cd6fdf | 200 | } |
va009039 | 0:a05a07cd6fdf | 201 | |
va009039 | 0:a05a07cd6fdf | 202 | // create new handle if needed |
va009039 | 0:a05a07cd6fdf | 203 | if (!record_handle){ |
va009039 | 0:a05a07cd6fdf | 204 | record_handle = sdp_create_service_record_handle(); |
va009039 | 0:a05a07cd6fdf | 205 | } |
va009039 | 0:a05a07cd6fdf | 206 | |
va009039 | 0:a05a07cd6fdf | 207 | // calculate size of new service record: DES (2 byte len) |
va009039 | 0:a05a07cd6fdf | 208 | // + ServiceRecordHandle attribute (UINT16 UINT32) + size of existing attributes |
va009039 | 0:a05a07cd6fdf | 209 | uint16_t recordSize = 3 + (3 + 5) + de_get_data_size(record); |
va009039 | 0:a05a07cd6fdf | 210 | |
va009039 | 0:a05a07cd6fdf | 211 | // alloc memory for new service_record_item |
va009039 | 0:a05a07cd6fdf | 212 | service_record_item_t * newRecordItem = (service_record_item_t *) malloc(recordSize + sizeof(service_record_item_t)); |
va009039 | 0:a05a07cd6fdf | 213 | if (!newRecordItem) { |
va009039 | 0:a05a07cd6fdf | 214 | sdp_emit_service_registered(connection, 0, BTSTACK_MEMORY_ALLOC_FAILED); |
va009039 | 0:a05a07cd6fdf | 215 | return 0; |
va009039 | 0:a05a07cd6fdf | 216 | } |
va009039 | 0:a05a07cd6fdf | 217 | // link new service item to client connection |
va009039 | 0:a05a07cd6fdf | 218 | newRecordItem->connection = connection; |
va009039 | 0:a05a07cd6fdf | 219 | |
va009039 | 0:a05a07cd6fdf | 220 | // set new handle |
va009039 | 0:a05a07cd6fdf | 221 | newRecordItem->service_record_handle = record_handle; |
va009039 | 0:a05a07cd6fdf | 222 | |
va009039 | 0:a05a07cd6fdf | 223 | // create updated service record |
va009039 | 0:a05a07cd6fdf | 224 | uint8_t * newRecord = (uint8_t *) &(newRecordItem->service_record); |
va009039 | 0:a05a07cd6fdf | 225 | |
va009039 | 0:a05a07cd6fdf | 226 | // create DES for new record |
va009039 | 0:a05a07cd6fdf | 227 | de_create_sequence(newRecord); |
va009039 | 0:a05a07cd6fdf | 228 | |
va009039 | 0:a05a07cd6fdf | 229 | // set service record handle |
va009039 | 0:a05a07cd6fdf | 230 | de_add_number(newRecord, DE_UINT, DE_SIZE_16, 0); |
va009039 | 0:a05a07cd6fdf | 231 | de_add_number(newRecord, DE_UINT, DE_SIZE_32, record_handle); |
va009039 | 0:a05a07cd6fdf | 232 | |
va009039 | 0:a05a07cd6fdf | 233 | // add other attributes |
va009039 | 0:a05a07cd6fdf | 234 | sdp_append_attributes_in_attributeIDList(record, (uint8_t *) removeServiceRecordHandleAttributeIDList, 0, recordSize, newRecord); |
va009039 | 0:a05a07cd6fdf | 235 | |
va009039 | 0:a05a07cd6fdf | 236 | // dump for now |
va009039 | 0:a05a07cd6fdf | 237 | // de_dump_data_element(newRecord); |
va009039 | 0:a05a07cd6fdf | 238 | // printf("reserved size %u, actual size %u\n", recordSize, de_get_len(newRecord)); |
va009039 | 0:a05a07cd6fdf | 239 | |
va009039 | 0:a05a07cd6fdf | 240 | // add to linked list |
va009039 | 0:a05a07cd6fdf | 241 | linked_list_add(&sdp_service_records, (linked_item_t *) newRecordItem); |
va009039 | 0:a05a07cd6fdf | 242 | |
va009039 | 0:a05a07cd6fdf | 243 | sdp_emit_service_registered(connection, 0, newRecordItem->service_record_handle); |
va009039 | 0:a05a07cd6fdf | 244 | |
va009039 | 0:a05a07cd6fdf | 245 | return record_handle; |
va009039 | 0:a05a07cd6fdf | 246 | } |
va009039 | 0:a05a07cd6fdf | 247 | |
va009039 | 0:a05a07cd6fdf | 248 | #endif |
va009039 | 0:a05a07cd6fdf | 249 | |
va009039 | 0:a05a07cd6fdf | 250 | // unregister service record internally |
va009039 | 0:a05a07cd6fdf | 251 | // |
va009039 | 0:a05a07cd6fdf | 252 | // makes sure one client cannot remove service records of other clients |
va009039 | 0:a05a07cd6fdf | 253 | // |
va009039 | 0:a05a07cd6fdf | 254 | void sdp_unregister_service_internal(void *connection, uint32_t service_record_handle){ |
va009039 | 0:a05a07cd6fdf | 255 | service_record_item_t * record_item = sdp_get_record_for_handle(service_record_handle); |
va009039 | 0:a05a07cd6fdf | 256 | if (record_item && record_item->connection == connection) { |
va009039 | 0:a05a07cd6fdf | 257 | linked_list_remove(&sdp_service_records, (linked_item_t *) record_item); |
va009039 | 0:a05a07cd6fdf | 258 | } |
va009039 | 0:a05a07cd6fdf | 259 | } |
va009039 | 0:a05a07cd6fdf | 260 | |
va009039 | 0:a05a07cd6fdf | 261 | // remove all service record for a client connection |
va009039 | 0:a05a07cd6fdf | 262 | void sdp_unregister_services_for_connection(void *connection){ |
va009039 | 0:a05a07cd6fdf | 263 | linked_item_t *it = (linked_item_t *) &sdp_service_records; |
va009039 | 0:a05a07cd6fdf | 264 | while (it->next){ |
va009039 | 0:a05a07cd6fdf | 265 | service_record_item_t *record_item = (service_record_item_t *) it->next; |
va009039 | 0:a05a07cd6fdf | 266 | if (record_item->connection == connection){ |
va009039 | 0:a05a07cd6fdf | 267 | it->next = it->next->next; |
va009039 | 0:a05a07cd6fdf | 268 | #ifndef EMBEDDED |
va009039 | 0:a05a07cd6fdf | 269 | free(record_item); |
va009039 | 0:a05a07cd6fdf | 270 | #endif |
va009039 | 0:a05a07cd6fdf | 271 | } else { |
va009039 | 0:a05a07cd6fdf | 272 | it = it->next; |
va009039 | 0:a05a07cd6fdf | 273 | } |
va009039 | 0:a05a07cd6fdf | 274 | } |
va009039 | 0:a05a07cd6fdf | 275 | } |
va009039 | 0:a05a07cd6fdf | 276 | |
va009039 | 0:a05a07cd6fdf | 277 | // PDU |
va009039 | 0:a05a07cd6fdf | 278 | // PDU ID (1), Transaction ID (2), Param Length (2), Param 1, Param 2, .. |
va009039 | 0:a05a07cd6fdf | 279 | |
va009039 | 0:a05a07cd6fdf | 280 | int sdp_create_error_response(uint16_t transaction_id, uint16_t error_code){ |
va009039 | 0:a05a07cd6fdf | 281 | sdp_response_buffer[0] = SDP_ErrorResponse; |
va009039 | 0:a05a07cd6fdf | 282 | net_store_16(sdp_response_buffer, 1, transaction_id); |
va009039 | 0:a05a07cd6fdf | 283 | net_store_16(sdp_response_buffer, 3, 2); |
va009039 | 0:a05a07cd6fdf | 284 | net_store_16(sdp_response_buffer, 5, error_code); // invalid syntax |
va009039 | 0:a05a07cd6fdf | 285 | return 7; |
va009039 | 0:a05a07cd6fdf | 286 | } |
va009039 | 0:a05a07cd6fdf | 287 | |
va009039 | 0:a05a07cd6fdf | 288 | int sdp_handle_service_search_request(uint8_t * packet, uint16_t remote_mtu){ |
va009039 | 0:a05a07cd6fdf | 289 | |
va009039 | 0:a05a07cd6fdf | 290 | // get request details |
va009039 | 0:a05a07cd6fdf | 291 | uint16_t transaction_id = READ_NET_16(packet, 1); |
va009039 | 0:a05a07cd6fdf | 292 | // not used yet - uint16_t param_len = READ_NET_16(packet, 3); |
va009039 | 0:a05a07cd6fdf | 293 | uint8_t * serviceSearchPattern = &packet[5]; |
va009039 | 0:a05a07cd6fdf | 294 | uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern); |
va009039 | 0:a05a07cd6fdf | 295 | uint16_t maximumServiceRecordCount = READ_NET_16(packet, 5 + serviceSearchPatternLen); |
va009039 | 0:a05a07cd6fdf | 296 | uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2]; |
va009039 | 0:a05a07cd6fdf | 297 | |
va009039 | 0:a05a07cd6fdf | 298 | // calc maxumumServiceRecordCount based on remote MTU |
va009039 | 0:a05a07cd6fdf | 299 | uint16_t maxNrServiceRecordsPerResponse = (remote_mtu - (9+3))/4; |
va009039 | 0:a05a07cd6fdf | 300 | |
va009039 | 0:a05a07cd6fdf | 301 | // continuation state contains index of next service record to examine |
va009039 | 0:a05a07cd6fdf | 302 | int continuation = 0; |
va009039 | 0:a05a07cd6fdf | 303 | uint16_t continuation_index = 0; |
va009039 | 0:a05a07cd6fdf | 304 | if (continuationState[0] == 2){ |
va009039 | 0:a05a07cd6fdf | 305 | continuation_index = READ_NET_16(continuationState, 1); |
va009039 | 0:a05a07cd6fdf | 306 | } |
va009039 | 0:a05a07cd6fdf | 307 | |
va009039 | 0:a05a07cd6fdf | 308 | // get and limit total count |
va009039 | 0:a05a07cd6fdf | 309 | linked_item_t *it; |
va009039 | 0:a05a07cd6fdf | 310 | uint16_t total_service_count = 0; |
va009039 | 0:a05a07cd6fdf | 311 | for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){ |
va009039 | 0:a05a07cd6fdf | 312 | service_record_item_t * item = (service_record_item_t *) it; |
va009039 | 0:a05a07cd6fdf | 313 | if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; |
va009039 | 0:a05a07cd6fdf | 314 | total_service_count++; |
va009039 | 0:a05a07cd6fdf | 315 | } |
va009039 | 0:a05a07cd6fdf | 316 | if (total_service_count > maximumServiceRecordCount){ |
va009039 | 0:a05a07cd6fdf | 317 | total_service_count = maximumServiceRecordCount; |
va009039 | 0:a05a07cd6fdf | 318 | } |
va009039 | 0:a05a07cd6fdf | 319 | |
va009039 | 0:a05a07cd6fdf | 320 | // ServiceRecordHandleList at 9 |
va009039 | 0:a05a07cd6fdf | 321 | uint16_t pos = 9; |
va009039 | 0:a05a07cd6fdf | 322 | uint16_t current_service_count = 0; |
va009039 | 0:a05a07cd6fdf | 323 | uint16_t current_service_index = 0; |
va009039 | 0:a05a07cd6fdf | 324 | uint16_t matching_service_count = 0; |
va009039 | 0:a05a07cd6fdf | 325 | for (it = (linked_item_t *) sdp_service_records; it ; it = it->next, ++current_service_index){ |
va009039 | 0:a05a07cd6fdf | 326 | service_record_item_t * item = (service_record_item_t *) it; |
va009039 | 0:a05a07cd6fdf | 327 | |
va009039 | 0:a05a07cd6fdf | 328 | if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; |
va009039 | 0:a05a07cd6fdf | 329 | matching_service_count++; |
va009039 | 0:a05a07cd6fdf | 330 | |
va009039 | 0:a05a07cd6fdf | 331 | if (current_service_index < continuation_index) continue; |
va009039 | 0:a05a07cd6fdf | 332 | |
va009039 | 0:a05a07cd6fdf | 333 | net_store_32(sdp_response_buffer, pos, item->service_record_handle); |
va009039 | 0:a05a07cd6fdf | 334 | pos += 4; |
va009039 | 0:a05a07cd6fdf | 335 | current_service_count++; |
va009039 | 0:a05a07cd6fdf | 336 | |
va009039 | 0:a05a07cd6fdf | 337 | if (matching_service_count >= total_service_count) break; |
va009039 | 0:a05a07cd6fdf | 338 | |
va009039 | 0:a05a07cd6fdf | 339 | if (current_service_count >= maxNrServiceRecordsPerResponse){ |
va009039 | 0:a05a07cd6fdf | 340 | continuation = 1; |
va009039 | 0:a05a07cd6fdf | 341 | continuation_index = current_service_index + 1; |
va009039 | 0:a05a07cd6fdf | 342 | break; |
va009039 | 0:a05a07cd6fdf | 343 | } |
va009039 | 0:a05a07cd6fdf | 344 | } |
va009039 | 0:a05a07cd6fdf | 345 | |
va009039 | 0:a05a07cd6fdf | 346 | // Store continuation state |
va009039 | 0:a05a07cd6fdf | 347 | if (continuation) { |
va009039 | 0:a05a07cd6fdf | 348 | sdp_response_buffer[pos++] = 2; |
va009039 | 0:a05a07cd6fdf | 349 | net_store_16(sdp_response_buffer, pos, continuation_index); |
va009039 | 0:a05a07cd6fdf | 350 | pos += 2; |
va009039 | 0:a05a07cd6fdf | 351 | } else { |
va009039 | 0:a05a07cd6fdf | 352 | sdp_response_buffer[pos++] = 0; |
va009039 | 0:a05a07cd6fdf | 353 | } |
va009039 | 0:a05a07cd6fdf | 354 | |
va009039 | 0:a05a07cd6fdf | 355 | // header |
va009039 | 0:a05a07cd6fdf | 356 | sdp_response_buffer[0] = SDP_ServiceSearchResponse; |
va009039 | 0:a05a07cd6fdf | 357 | net_store_16(sdp_response_buffer, 1, transaction_id); |
va009039 | 0:a05a07cd6fdf | 358 | net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload |
va009039 | 0:a05a07cd6fdf | 359 | net_store_16(sdp_response_buffer, 5, total_service_count); |
va009039 | 0:a05a07cd6fdf | 360 | net_store_16(sdp_response_buffer, 7, current_service_count); |
va009039 | 0:a05a07cd6fdf | 361 | |
va009039 | 0:a05a07cd6fdf | 362 | return pos; |
va009039 | 0:a05a07cd6fdf | 363 | } |
va009039 | 0:a05a07cd6fdf | 364 | |
va009039 | 0:a05a07cd6fdf | 365 | int sdp_handle_service_attribute_request(uint8_t * packet, uint16_t remote_mtu){ |
va009039 | 0:a05a07cd6fdf | 366 | |
va009039 | 0:a05a07cd6fdf | 367 | // get request details |
va009039 | 0:a05a07cd6fdf | 368 | uint16_t transaction_id = READ_NET_16(packet, 1); |
va009039 | 0:a05a07cd6fdf | 369 | // not used yet - uint16_t param_len = READ_NET_16(packet, 3); |
va009039 | 0:a05a07cd6fdf | 370 | uint32_t serviceRecordHandle = READ_NET_32(packet, 5); |
va009039 | 0:a05a07cd6fdf | 371 | uint16_t maximumAttributeByteCount = READ_NET_16(packet, 9); |
va009039 | 0:a05a07cd6fdf | 372 | uint8_t * attributeIDList = &packet[11]; |
va009039 | 0:a05a07cd6fdf | 373 | uint16_t attributeIDListLen = de_get_len(attributeIDList); |
va009039 | 0:a05a07cd6fdf | 374 | uint8_t * continuationState = &packet[11+attributeIDListLen]; |
va009039 | 0:a05a07cd6fdf | 375 | |
va009039 | 0:a05a07cd6fdf | 376 | // calc maximumAttributeByteCount based on remote MTU |
va009039 | 0:a05a07cd6fdf | 377 | uint16_t maximumAttributeByteCount2 = remote_mtu - (7+3); |
va009039 | 0:a05a07cd6fdf | 378 | if (maximumAttributeByteCount2 < maximumAttributeByteCount) { |
va009039 | 0:a05a07cd6fdf | 379 | maximumAttributeByteCount = maximumAttributeByteCount2; |
va009039 | 0:a05a07cd6fdf | 380 | } |
va009039 | 0:a05a07cd6fdf | 381 | |
va009039 | 0:a05a07cd6fdf | 382 | // continuation state contains the offset into the complete response |
va009039 | 0:a05a07cd6fdf | 383 | uint16_t continuation_offset = 0; |
va009039 | 0:a05a07cd6fdf | 384 | if (continuationState[0] == 2){ |
va009039 | 0:a05a07cd6fdf | 385 | continuation_offset = READ_NET_16(continuationState, 1); |
va009039 | 0:a05a07cd6fdf | 386 | } |
va009039 | 0:a05a07cd6fdf | 387 | |
va009039 | 0:a05a07cd6fdf | 388 | // get service record |
va009039 | 0:a05a07cd6fdf | 389 | service_record_item_t * item = sdp_get_record_for_handle(serviceRecordHandle); |
va009039 | 0:a05a07cd6fdf | 390 | if (!item){ |
va009039 | 0:a05a07cd6fdf | 391 | // service record handle doesn't exist |
va009039 | 0:a05a07cd6fdf | 392 | return sdp_create_error_response(transaction_id, 0x0002); /// invalid Service Record Handle |
va009039 | 0:a05a07cd6fdf | 393 | } |
va009039 | 0:a05a07cd6fdf | 394 | |
va009039 | 0:a05a07cd6fdf | 395 | |
va009039 | 0:a05a07cd6fdf | 396 | // AttributeList - starts at offset 7 |
va009039 | 0:a05a07cd6fdf | 397 | uint16_t pos = 7; |
va009039 | 0:a05a07cd6fdf | 398 | |
va009039 | 0:a05a07cd6fdf | 399 | if (continuation_offset == 0){ |
va009039 | 0:a05a07cd6fdf | 400 | |
va009039 | 0:a05a07cd6fdf | 401 | // get size of this record |
va009039 | 0:a05a07cd6fdf | 402 | uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList); |
va009039 | 0:a05a07cd6fdf | 403 | |
va009039 | 0:a05a07cd6fdf | 404 | // store DES |
va009039 | 0:a05a07cd6fdf | 405 | de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); |
va009039 | 0:a05a07cd6fdf | 406 | maximumAttributeByteCount -= 3; |
va009039 | 0:a05a07cd6fdf | 407 | pos += 3; |
va009039 | 0:a05a07cd6fdf | 408 | } |
va009039 | 0:a05a07cd6fdf | 409 | |
va009039 | 0:a05a07cd6fdf | 410 | // copy maximumAttributeByteCount from record |
va009039 | 0:a05a07cd6fdf | 411 | uint16_t bytes_used; |
va009039 | 0:a05a07cd6fdf | 412 | int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); |
va009039 | 0:a05a07cd6fdf | 413 | pos += bytes_used; |
va009039 | 0:a05a07cd6fdf | 414 | |
va009039 | 0:a05a07cd6fdf | 415 | uint16_t attributeListByteCount = pos - 7; |
va009039 | 0:a05a07cd6fdf | 416 | |
va009039 | 0:a05a07cd6fdf | 417 | if (complete) { |
va009039 | 0:a05a07cd6fdf | 418 | sdp_response_buffer[pos++] = 0; |
va009039 | 0:a05a07cd6fdf | 419 | } else { |
va009039 | 0:a05a07cd6fdf | 420 | continuation_offset += bytes_used; |
va009039 | 0:a05a07cd6fdf | 421 | sdp_response_buffer[pos++] = 2; |
va009039 | 0:a05a07cd6fdf | 422 | net_store_16(sdp_response_buffer, pos, continuation_offset); |
va009039 | 0:a05a07cd6fdf | 423 | pos += 2; |
va009039 | 0:a05a07cd6fdf | 424 | } |
va009039 | 0:a05a07cd6fdf | 425 | |
va009039 | 0:a05a07cd6fdf | 426 | // header |
va009039 | 0:a05a07cd6fdf | 427 | sdp_response_buffer[0] = SDP_ServiceAttributeResponse; |
va009039 | 0:a05a07cd6fdf | 428 | net_store_16(sdp_response_buffer, 1, transaction_id); |
va009039 | 0:a05a07cd6fdf | 429 | net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload |
va009039 | 0:a05a07cd6fdf | 430 | net_store_16(sdp_response_buffer, 5, attributeListByteCount); |
va009039 | 0:a05a07cd6fdf | 431 | |
va009039 | 0:a05a07cd6fdf | 432 | return pos; |
va009039 | 0:a05a07cd6fdf | 433 | } |
va009039 | 0:a05a07cd6fdf | 434 | |
va009039 | 0:a05a07cd6fdf | 435 | static uint16_t sdp_get_size_for_service_search_attribute_response(uint8_t * serviceSearchPattern, uint8_t * attributeIDList){ |
va009039 | 0:a05a07cd6fdf | 436 | uint16_t total_response_size = 0; |
va009039 | 0:a05a07cd6fdf | 437 | linked_item_t *it; |
va009039 | 0:a05a07cd6fdf | 438 | for (it = (linked_item_t *) sdp_service_records; it ; it = it->next){ |
va009039 | 0:a05a07cd6fdf | 439 | service_record_item_t * item = (service_record_item_t *) it; |
va009039 | 0:a05a07cd6fdf | 440 | |
va009039 | 0:a05a07cd6fdf | 441 | if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; |
va009039 | 0:a05a07cd6fdf | 442 | |
va009039 | 0:a05a07cd6fdf | 443 | // for all service records that match |
va009039 | 0:a05a07cd6fdf | 444 | total_response_size += 3 + spd_get_filtered_size(item->service_record, attributeIDList); |
va009039 | 0:a05a07cd6fdf | 445 | } |
va009039 | 0:a05a07cd6fdf | 446 | return total_response_size; |
va009039 | 0:a05a07cd6fdf | 447 | } |
va009039 | 0:a05a07cd6fdf | 448 | |
va009039 | 0:a05a07cd6fdf | 449 | int sdp_handle_service_search_attribute_request(uint8_t * packet, uint16_t remote_mtu){ |
va009039 | 0:a05a07cd6fdf | 450 | |
va009039 | 0:a05a07cd6fdf | 451 | // SDP header before attribute sevice list: 7 |
va009039 | 0:a05a07cd6fdf | 452 | // Continuation, worst case: 5 |
va009039 | 0:a05a07cd6fdf | 453 | |
va009039 | 0:a05a07cd6fdf | 454 | // get request details |
va009039 | 0:a05a07cd6fdf | 455 | uint16_t transaction_id = READ_NET_16(packet, 1); |
va009039 | 0:a05a07cd6fdf | 456 | // not used yet - uint16_t param_len = READ_NET_16(packet, 3); |
va009039 | 0:a05a07cd6fdf | 457 | uint8_t * serviceSearchPattern = &packet[5]; |
va009039 | 0:a05a07cd6fdf | 458 | uint16_t serviceSearchPatternLen = de_get_len(serviceSearchPattern); |
va009039 | 0:a05a07cd6fdf | 459 | uint16_t maximumAttributeByteCount = READ_NET_16(packet, 5 + serviceSearchPatternLen); |
va009039 | 0:a05a07cd6fdf | 460 | uint8_t * attributeIDList = &packet[5+serviceSearchPatternLen+2]; |
va009039 | 0:a05a07cd6fdf | 461 | uint16_t attributeIDListLen = de_get_len(attributeIDList); |
va009039 | 0:a05a07cd6fdf | 462 | uint8_t * continuationState = &packet[5+serviceSearchPatternLen+2+attributeIDListLen]; |
va009039 | 0:a05a07cd6fdf | 463 | |
va009039 | 0:a05a07cd6fdf | 464 | // calc maximumAttributeByteCount based on remote MTU, SDP header and reserved Continuation block |
va009039 | 0:a05a07cd6fdf | 465 | uint16_t maximumAttributeByteCount2 = remote_mtu - 12; |
va009039 | 0:a05a07cd6fdf | 466 | if (maximumAttributeByteCount2 < maximumAttributeByteCount) { |
va009039 | 0:a05a07cd6fdf | 467 | maximumAttributeByteCount = maximumAttributeByteCount2; |
va009039 | 0:a05a07cd6fdf | 468 | } |
va009039 | 0:a05a07cd6fdf | 469 | |
va009039 | 0:a05a07cd6fdf | 470 | // continuation state contains: index of next service record to examine |
va009039 | 0:a05a07cd6fdf | 471 | // continuation state contains: byte offset into this service record |
va009039 | 0:a05a07cd6fdf | 472 | uint16_t continuation_service_index = 0; |
va009039 | 0:a05a07cd6fdf | 473 | uint16_t continuation_offset = 0; |
va009039 | 0:a05a07cd6fdf | 474 | if (continuationState[0] == 4){ |
va009039 | 0:a05a07cd6fdf | 475 | continuation_service_index = READ_NET_16(continuationState, 1); |
va009039 | 0:a05a07cd6fdf | 476 | continuation_offset = READ_NET_16(continuationState, 3); |
va009039 | 0:a05a07cd6fdf | 477 | } |
va009039 | 0:a05a07cd6fdf | 478 | |
va009039 | 0:a05a07cd6fdf | 479 | // printf("--> sdp_handle_service_search_attribute_request, cont %u/%u, max %u\n", continuation_service_index, continuation_offset, maximumAttributeByteCount); |
va009039 | 0:a05a07cd6fdf | 480 | |
va009039 | 0:a05a07cd6fdf | 481 | // AttributeLists - starts at offset 7 |
va009039 | 0:a05a07cd6fdf | 482 | uint16_t pos = 7; |
va009039 | 0:a05a07cd6fdf | 483 | |
va009039 | 0:a05a07cd6fdf | 484 | // add DES with total size for first request |
va009039 | 0:a05a07cd6fdf | 485 | if (continuation_service_index == 0 && continuation_offset == 0){ |
va009039 | 0:a05a07cd6fdf | 486 | uint16_t total_response_size = sdp_get_size_for_service_search_attribute_response(serviceSearchPattern, attributeIDList); |
va009039 | 0:a05a07cd6fdf | 487 | de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, total_response_size); |
va009039 | 0:a05a07cd6fdf | 488 | // log_info("total response size %u\n", total_response_size); |
va009039 | 0:a05a07cd6fdf | 489 | pos += 3; |
va009039 | 0:a05a07cd6fdf | 490 | maximumAttributeByteCount -= 3; |
va009039 | 0:a05a07cd6fdf | 491 | } |
va009039 | 0:a05a07cd6fdf | 492 | |
va009039 | 0:a05a07cd6fdf | 493 | // create attribute list |
va009039 | 0:a05a07cd6fdf | 494 | int first_answer = 1; |
va009039 | 0:a05a07cd6fdf | 495 | int continuation = 0; |
va009039 | 0:a05a07cd6fdf | 496 | uint16_t current_service_index = 0; |
va009039 | 0:a05a07cd6fdf | 497 | linked_item_t *it = (linked_item_t *) sdp_service_records; |
va009039 | 0:a05a07cd6fdf | 498 | for ( ; it ; it = it->next, ++current_service_index){ |
va009039 | 0:a05a07cd6fdf | 499 | service_record_item_t * item = (service_record_item_t *) it; |
va009039 | 0:a05a07cd6fdf | 500 | |
va009039 | 0:a05a07cd6fdf | 501 | if (current_service_index < continuation_service_index ) continue; |
va009039 | 0:a05a07cd6fdf | 502 | if (!sdp_record_matches_service_search_pattern(item->service_record, serviceSearchPattern)) continue; |
va009039 | 0:a05a07cd6fdf | 503 | |
va009039 | 0:a05a07cd6fdf | 504 | if (continuation_offset == 0){ |
va009039 | 0:a05a07cd6fdf | 505 | |
va009039 | 0:a05a07cd6fdf | 506 | // get size of this record |
va009039 | 0:a05a07cd6fdf | 507 | uint16_t filtered_attributes_size = spd_get_filtered_size(item->service_record, attributeIDList); |
va009039 | 0:a05a07cd6fdf | 508 | |
va009039 | 0:a05a07cd6fdf | 509 | // stop if complete record doesn't fits into response but we already have a partial response |
va009039 | 0:a05a07cd6fdf | 510 | if ((filtered_attributes_size + 3 > maximumAttributeByteCount) && !first_answer) { |
va009039 | 0:a05a07cd6fdf | 511 | continuation = 1; |
va009039 | 0:a05a07cd6fdf | 512 | break; |
va009039 | 0:a05a07cd6fdf | 513 | } |
va009039 | 0:a05a07cd6fdf | 514 | |
va009039 | 0:a05a07cd6fdf | 515 | // store DES |
va009039 | 0:a05a07cd6fdf | 516 | de_store_descriptor_with_len(&sdp_response_buffer[pos], DE_DES, DE_SIZE_VAR_16, filtered_attributes_size); |
va009039 | 0:a05a07cd6fdf | 517 | pos += 3; |
va009039 | 0:a05a07cd6fdf | 518 | maximumAttributeByteCount -= 3; |
va009039 | 0:a05a07cd6fdf | 519 | } |
va009039 | 0:a05a07cd6fdf | 520 | |
va009039 | 0:a05a07cd6fdf | 521 | first_answer = 0; |
va009039 | 0:a05a07cd6fdf | 522 | |
va009039 | 0:a05a07cd6fdf | 523 | // copy maximumAttributeByteCount from record |
va009039 | 0:a05a07cd6fdf | 524 | uint16_t bytes_used; |
va009039 | 0:a05a07cd6fdf | 525 | int complete = sdp_filter_attributes_in_attributeIDList(item->service_record, attributeIDList, continuation_offset, maximumAttributeByteCount, &bytes_used, &sdp_response_buffer[pos]); |
va009039 | 0:a05a07cd6fdf | 526 | pos += bytes_used; |
va009039 | 0:a05a07cd6fdf | 527 | maximumAttributeByteCount -= bytes_used; |
va009039 | 0:a05a07cd6fdf | 528 | |
va009039 | 0:a05a07cd6fdf | 529 | if (complete) { |
va009039 | 0:a05a07cd6fdf | 530 | continuation_offset = 0; |
va009039 | 0:a05a07cd6fdf | 531 | continue; |
va009039 | 0:a05a07cd6fdf | 532 | } |
va009039 | 0:a05a07cd6fdf | 533 | |
va009039 | 0:a05a07cd6fdf | 534 | continuation = 1; |
va009039 | 0:a05a07cd6fdf | 535 | continuation_offset += bytes_used; |
va009039 | 0:a05a07cd6fdf | 536 | break; |
va009039 | 0:a05a07cd6fdf | 537 | } |
va009039 | 0:a05a07cd6fdf | 538 | |
va009039 | 0:a05a07cd6fdf | 539 | uint16_t attributeListsByteCount = pos - 7; |
va009039 | 0:a05a07cd6fdf | 540 | |
va009039 | 0:a05a07cd6fdf | 541 | // Continuation State |
va009039 | 0:a05a07cd6fdf | 542 | if (continuation){ |
va009039 | 0:a05a07cd6fdf | 543 | sdp_response_buffer[pos++] = 4; |
va009039 | 0:a05a07cd6fdf | 544 | net_store_16(sdp_response_buffer, pos, (uint16_t) current_service_index); |
va009039 | 0:a05a07cd6fdf | 545 | pos += 2; |
va009039 | 0:a05a07cd6fdf | 546 | net_store_16(sdp_response_buffer, pos, continuation_offset); |
va009039 | 0:a05a07cd6fdf | 547 | pos += 2; |
va009039 | 0:a05a07cd6fdf | 548 | } else { |
va009039 | 0:a05a07cd6fdf | 549 | // complete |
va009039 | 0:a05a07cd6fdf | 550 | sdp_response_buffer[pos++] = 0; |
va009039 | 0:a05a07cd6fdf | 551 | } |
va009039 | 0:a05a07cd6fdf | 552 | |
va009039 | 0:a05a07cd6fdf | 553 | // create SDP header |
va009039 | 0:a05a07cd6fdf | 554 | sdp_response_buffer[0] = SDP_ServiceSearchAttributeResponse; |
va009039 | 0:a05a07cd6fdf | 555 | net_store_16(sdp_response_buffer, 1, transaction_id); |
va009039 | 0:a05a07cd6fdf | 556 | net_store_16(sdp_response_buffer, 3, pos - 5); // size of variable payload |
va009039 | 0:a05a07cd6fdf | 557 | net_store_16(sdp_response_buffer, 5, attributeListsByteCount); |
va009039 | 0:a05a07cd6fdf | 558 | |
va009039 | 0:a05a07cd6fdf | 559 | return pos; |
va009039 | 0:a05a07cd6fdf | 560 | } |
va009039 | 0:a05a07cd6fdf | 561 | |
va009039 | 0:a05a07cd6fdf | 562 | static void sdp_try_respond(void){ |
va009039 | 0:a05a07cd6fdf | 563 | if (!sdp_response_size ) return; |
va009039 | 0:a05a07cd6fdf | 564 | if (!l2cap_cid) return; |
va009039 | 0:a05a07cd6fdf | 565 | if (!l2cap_can_send_packet_now(l2cap_cid)) return; |
va009039 | 0:a05a07cd6fdf | 566 | |
va009039 | 0:a05a07cd6fdf | 567 | // update state before sending packet (avoid getting called when new l2cap credit gets emitted) |
va009039 | 0:a05a07cd6fdf | 568 | uint16_t size = sdp_response_size; |
va009039 | 0:a05a07cd6fdf | 569 | sdp_response_size = 0; |
va009039 | 0:a05a07cd6fdf | 570 | l2cap_send_internal(l2cap_cid, sdp_response_buffer, size); |
va009039 | 0:a05a07cd6fdf | 571 | } |
va009039 | 0:a05a07cd6fdf | 572 | |
va009039 | 0:a05a07cd6fdf | 573 | // we assume that we don't get two requests in a row |
va009039 | 0:a05a07cd6fdf | 574 | static void sdp_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ |
va009039 | 0:a05a07cd6fdf | 575 | uint16_t transaction_id; |
va009039 | 0:a05a07cd6fdf | 576 | SDP_PDU_ID_t pdu_id; |
va009039 | 0:a05a07cd6fdf | 577 | uint16_t remote_mtu; |
va009039 | 0:a05a07cd6fdf | 578 | // uint16_t param_len; |
va009039 | 0:a05a07cd6fdf | 579 | |
va009039 | 0:a05a07cd6fdf | 580 | switch (packet_type) { |
va009039 | 0:a05a07cd6fdf | 581 | |
va009039 | 0:a05a07cd6fdf | 582 | case L2CAP_DATA_PACKET: |
va009039 | 0:a05a07cd6fdf | 583 | pdu_id = (SDP_PDU_ID_t) packet[0]; |
va009039 | 0:a05a07cd6fdf | 584 | transaction_id = READ_NET_16(packet, 1); |
va009039 | 0:a05a07cd6fdf | 585 | // param_len = READ_NET_16(packet, 3); |
va009039 | 0:a05a07cd6fdf | 586 | remote_mtu = l2cap_get_remote_mtu_for_local_cid(channel); |
va009039 | 0:a05a07cd6fdf | 587 | // account for our buffer |
va009039 | 0:a05a07cd6fdf | 588 | if (remote_mtu > SDP_RESPONSE_BUFFER_SIZE){ |
va009039 | 0:a05a07cd6fdf | 589 | remote_mtu = SDP_RESPONSE_BUFFER_SIZE; |
va009039 | 0:a05a07cd6fdf | 590 | } |
va009039 | 0:a05a07cd6fdf | 591 | |
va009039 | 0:a05a07cd6fdf | 592 | // printf("SDP Request: type %u, transaction id %u, len %u, mtu %u\n", pdu_id, transaction_id, param_len, remote_mtu); |
va009039 | 0:a05a07cd6fdf | 593 | switch (pdu_id){ |
va009039 | 0:a05a07cd6fdf | 594 | |
va009039 | 0:a05a07cd6fdf | 595 | case SDP_ServiceSearchRequest: |
va009039 | 0:a05a07cd6fdf | 596 | sdp_response_size = sdp_handle_service_search_request(packet, remote_mtu); |
va009039 | 0:a05a07cd6fdf | 597 | break; |
va009039 | 0:a05a07cd6fdf | 598 | |
va009039 | 0:a05a07cd6fdf | 599 | case SDP_ServiceAttributeRequest: |
va009039 | 0:a05a07cd6fdf | 600 | sdp_response_size = sdp_handle_service_attribute_request(packet, remote_mtu); |
va009039 | 0:a05a07cd6fdf | 601 | break; |
va009039 | 0:a05a07cd6fdf | 602 | |
va009039 | 0:a05a07cd6fdf | 603 | case SDP_ServiceSearchAttributeRequest: |
va009039 | 0:a05a07cd6fdf | 604 | sdp_response_size = sdp_handle_service_search_attribute_request(packet, remote_mtu); |
va009039 | 0:a05a07cd6fdf | 605 | break; |
va009039 | 0:a05a07cd6fdf | 606 | |
va009039 | 0:a05a07cd6fdf | 607 | default: |
va009039 | 0:a05a07cd6fdf | 608 | sdp_response_size = sdp_create_error_response(transaction_id, 0x0003); // invalid syntax |
va009039 | 0:a05a07cd6fdf | 609 | break; |
va009039 | 0:a05a07cd6fdf | 610 | } |
va009039 | 0:a05a07cd6fdf | 611 | |
va009039 | 0:a05a07cd6fdf | 612 | sdp_try_respond(); |
va009039 | 0:a05a07cd6fdf | 613 | |
va009039 | 0:a05a07cd6fdf | 614 | break; |
va009039 | 0:a05a07cd6fdf | 615 | |
va009039 | 0:a05a07cd6fdf | 616 | case HCI_EVENT_PACKET: |
va009039 | 0:a05a07cd6fdf | 617 | |
va009039 | 0:a05a07cd6fdf | 618 | switch (packet[0]) { |
va009039 | 0:a05a07cd6fdf | 619 | |
va009039 | 0:a05a07cd6fdf | 620 | case L2CAP_EVENT_INCOMING_CONNECTION: |
va009039 | 0:a05a07cd6fdf | 621 | if (l2cap_cid) { |
va009039 | 0:a05a07cd6fdf | 622 | // CONNECTION REJECTED DUE TO LIMITED RESOURCES |
va009039 | 0:a05a07cd6fdf | 623 | l2cap_decline_connection_internal(channel, 0x0d); |
va009039 | 0:a05a07cd6fdf | 624 | break; |
va009039 | 0:a05a07cd6fdf | 625 | } |
va009039 | 0:a05a07cd6fdf | 626 | // accept |
va009039 | 0:a05a07cd6fdf | 627 | l2cap_cid = channel; |
va009039 | 0:a05a07cd6fdf | 628 | sdp_response_size = 0; |
va009039 | 0:a05a07cd6fdf | 629 | l2cap_accept_connection_internal(channel); |
va009039 | 0:a05a07cd6fdf | 630 | break; |
va009039 | 0:a05a07cd6fdf | 631 | |
va009039 | 0:a05a07cd6fdf | 632 | case L2CAP_EVENT_CHANNEL_OPENED: |
va009039 | 0:a05a07cd6fdf | 633 | if (packet[2]) { |
va009039 | 0:a05a07cd6fdf | 634 | // open failed -> reset |
va009039 | 0:a05a07cd6fdf | 635 | l2cap_cid = 0; |
va009039 | 0:a05a07cd6fdf | 636 | } |
va009039 | 0:a05a07cd6fdf | 637 | break; |
va009039 | 0:a05a07cd6fdf | 638 | |
va009039 | 0:a05a07cd6fdf | 639 | case L2CAP_EVENT_CREDITS: |
va009039 | 0:a05a07cd6fdf | 640 | case DAEMON_EVENT_HCI_PACKET_SENT: |
va009039 | 0:a05a07cd6fdf | 641 | sdp_try_respond(); |
va009039 | 0:a05a07cd6fdf | 642 | break; |
va009039 | 0:a05a07cd6fdf | 643 | |
va009039 | 0:a05a07cd6fdf | 644 | case L2CAP_EVENT_CHANNEL_CLOSED: |
va009039 | 0:a05a07cd6fdf | 645 | if (channel == l2cap_cid){ |
va009039 | 0:a05a07cd6fdf | 646 | // reset |
va009039 | 0:a05a07cd6fdf | 647 | l2cap_cid = 0; |
va009039 | 0:a05a07cd6fdf | 648 | } |
va009039 | 0:a05a07cd6fdf | 649 | break; |
va009039 | 0:a05a07cd6fdf | 650 | |
va009039 | 0:a05a07cd6fdf | 651 | default: |
va009039 | 0:a05a07cd6fdf | 652 | // other event |
va009039 | 0:a05a07cd6fdf | 653 | break; |
va009039 | 0:a05a07cd6fdf | 654 | } |
va009039 | 0:a05a07cd6fdf | 655 | break; |
va009039 | 0:a05a07cd6fdf | 656 | |
va009039 | 0:a05a07cd6fdf | 657 | default: |
va009039 | 0:a05a07cd6fdf | 658 | // other packet type |
va009039 | 0:a05a07cd6fdf | 659 | break; |
va009039 | 0:a05a07cd6fdf | 660 | } |
va009039 | 0:a05a07cd6fdf | 661 | } |
va009039 | 0:a05a07cd6fdf | 662 |