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