13deb3ec6SMatthias Ringwald /* 23deb3ec6SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH 33deb3ec6SMatthias Ringwald * 43deb3ec6SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 53deb3ec6SMatthias Ringwald * modification, are permitted provided that the following conditions 63deb3ec6SMatthias Ringwald * are met: 73deb3ec6SMatthias Ringwald * 83deb3ec6SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 93deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 103deb3ec6SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 113deb3ec6SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 123deb3ec6SMatthias Ringwald * documentation and/or other materials provided with the distribution. 133deb3ec6SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 143deb3ec6SMatthias Ringwald * contributors may be used to endorse or promote products derived 153deb3ec6SMatthias Ringwald * from this software without specific prior written permission. 163deb3ec6SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for 173deb3ec6SMatthias Ringwald * personal benefit and not for any commercial purpose or for 183deb3ec6SMatthias Ringwald * monetary gain. 193deb3ec6SMatthias Ringwald * 203deb3ec6SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 213deb3ec6SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 223deb3ec6SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 233deb3ec6SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 243deb3ec6SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 253deb3ec6SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 263deb3ec6SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 273deb3ec6SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 283deb3ec6SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 293deb3ec6SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 303deb3ec6SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 313deb3ec6SMatthias Ringwald * SUCH DAMAGE. 323deb3ec6SMatthias Ringwald * 333deb3ec6SMatthias Ringwald * Please inquire about commercial licensing options at 343deb3ec6SMatthias Ringwald * [email protected] 353deb3ec6SMatthias Ringwald * 363deb3ec6SMatthias Ringwald */ 373deb3ec6SMatthias Ringwald 383deb3ec6SMatthias Ringwald /* 393deb3ec6SMatthias Ringwald * bnep.c 403deb3ec6SMatthias Ringwald * Author: Ole Reinhardt <[email protected]> 413deb3ec6SMatthias Ringwald * 423deb3ec6SMatthias Ringwald */ 433deb3ec6SMatthias Ringwald 443deb3ec6SMatthias Ringwald #include <stdio.h> 453deb3ec6SMatthias Ringwald #include <stdlib.h> 463deb3ec6SMatthias Ringwald #include <string.h> // memcpy 473deb3ec6SMatthias Ringwald #include <stdint.h> 483deb3ec6SMatthias Ringwald 4956042629SMatthias Ringwald #include "hci_cmd.h" 50eb886013SMatthias Ringwald #include "btstack_util.h" 513edc84c5SMatthias Ringwald #include "classic/sdp_util.h" 523deb3ec6SMatthias Ringwald 533deb3ec6SMatthias Ringwald #include "btstack_memory.h" 543deb3ec6SMatthias Ringwald #include "hci.h" 553deb3ec6SMatthias Ringwald #include "hci_dump.h" 5616ece135SMatthias Ringwald #include "btstack_debug.h" 573deb3ec6SMatthias Ringwald #include "bnep.h" 583deb3ec6SMatthias Ringwald 593deb3ec6SMatthias Ringwald #include "l2cap.h" 603deb3ec6SMatthias Ringwald 613deb3ec6SMatthias Ringwald #define BNEP_CONNECTION_TIMEOUT_MS 10000 623deb3ec6SMatthias Ringwald #define BNEP_CONNECTION_MAX_RETRIES 1 633deb3ec6SMatthias Ringwald 648f2a52f4SMatthias Ringwald static btstack_linked_list_t bnep_services = NULL; 658f2a52f4SMatthias Ringwald static btstack_linked_list_t bnep_channels = NULL; 663deb3ec6SMatthias Ringwald 673deb3ec6SMatthias Ringwald static gap_security_level_t bnep_security_level; 683deb3ec6SMatthias Ringwald 690cc6429eSMatthias Ringwald static void (*app_packet_handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 703deb3ec6SMatthias Ringwald 713deb3ec6SMatthias Ringwald 723deb3ec6SMatthias Ringwald static bnep_channel_t * bnep_channel_for_l2cap_cid(uint16_t l2cap_cid); 733deb3ec6SMatthias Ringwald static void bnep_channel_finalize(bnep_channel_t *channel); 743deb3ec6SMatthias Ringwald static void bnep_run(void); 753deb3ec6SMatthias Ringwald static void bnep_channel_start_timer(bnep_channel_t *channel, int timeout); 763deb3ec6SMatthias Ringwald inline static void bnep_channel_state_add(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event); 773deb3ec6SMatthias Ringwald 783deb3ec6SMatthias Ringwald static void bnep_emit_open_channel_complete(bnep_channel_t *channel, uint8_t status) 793deb3ec6SMatthias Ringwald { 803deb3ec6SMatthias Ringwald log_info("BNEP_EVENT_OPEN_CHANNEL_COMPLETE status 0x%02x bd_addr: %s", status, bd_addr_to_str(channel->remote_addr)); 813deb3ec6SMatthias Ringwald uint8_t event[3 + sizeof(bd_addr_t) + 3 * sizeof(uint16_t)]; 823deb3ec6SMatthias Ringwald event[0] = BNEP_EVENT_OPEN_CHANNEL_COMPLETE; 833deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2; 843deb3ec6SMatthias Ringwald event[2] = status; 85*f8fbdce0SMatthias Ringwald little_endian_store_16(event, 3, channel->uuid_source); 86*f8fbdce0SMatthias Ringwald little_endian_store_16(event, 5, channel->uuid_dest); 87*f8fbdce0SMatthias Ringwald little_endian_store_16(event, 7, channel->max_frame_size); 883deb3ec6SMatthias Ringwald BD_ADDR_COPY(&event[9], channel->remote_addr); 893deb3ec6SMatthias Ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 900cc6429eSMatthias Ringwald (*app_packet_handler)(HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event)); 913deb3ec6SMatthias Ringwald } 923deb3ec6SMatthias Ringwald 933deb3ec6SMatthias Ringwald static void bnep_emit_channel_timeout(bnep_channel_t *channel) 943deb3ec6SMatthias Ringwald { 953deb3ec6SMatthias Ringwald log_info("BNEP_EVENT_CHANNEL_TIMEOUT bd_addr: %s", bd_addr_to_str(channel->remote_addr)); 963deb3ec6SMatthias Ringwald uint8_t event[2 + sizeof(bd_addr_t) + 2 * sizeof(uint16_t) + sizeof(uint8_t)]; 973deb3ec6SMatthias Ringwald event[0] = BNEP_EVENT_CHANNEL_TIMEOUT; 983deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2; 99*f8fbdce0SMatthias Ringwald little_endian_store_16(event, 2, channel->uuid_source); 100*f8fbdce0SMatthias Ringwald little_endian_store_16(event, 4, channel->uuid_dest); 1013deb3ec6SMatthias Ringwald BD_ADDR_COPY(&event[6], channel->remote_addr); 1023deb3ec6SMatthias Ringwald event[12] = channel->state; 1033deb3ec6SMatthias Ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 1040cc6429eSMatthias Ringwald (*app_packet_handler)(HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event)); 1053deb3ec6SMatthias Ringwald } 1063deb3ec6SMatthias Ringwald 1073deb3ec6SMatthias Ringwald static void bnep_emit_channel_closed(bnep_channel_t *channel) 1083deb3ec6SMatthias Ringwald { 1093deb3ec6SMatthias Ringwald log_info("BNEP_EVENT_CHANNEL_CLOSED bd_addr: %s", bd_addr_to_str(channel->remote_addr)); 1103deb3ec6SMatthias Ringwald uint8_t event[2 + sizeof(bd_addr_t) + 2 * sizeof(uint16_t)]; 1113deb3ec6SMatthias Ringwald event[0] = BNEP_EVENT_CHANNEL_CLOSED; 1123deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2; 113*f8fbdce0SMatthias Ringwald little_endian_store_16(event, 2, channel->uuid_source); 114*f8fbdce0SMatthias Ringwald little_endian_store_16(event, 4, channel->uuid_dest); 1153deb3ec6SMatthias Ringwald BD_ADDR_COPY(&event[6], channel->remote_addr); 1163deb3ec6SMatthias Ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 1170cc6429eSMatthias Ringwald (*app_packet_handler)(HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event)); 1183deb3ec6SMatthias Ringwald } 1193deb3ec6SMatthias Ringwald 1203deb3ec6SMatthias Ringwald static void bnep_emit_ready_to_send(bnep_channel_t *channel) 1213deb3ec6SMatthias Ringwald { 1223deb3ec6SMatthias Ringwald uint8_t event[2]; 1233deb3ec6SMatthias Ringwald event[0] = BNEP_EVENT_READY_TO_SEND; 1243deb3ec6SMatthias Ringwald event[1] = sizeof(event) - 2; 1253deb3ec6SMatthias Ringwald hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); 1260cc6429eSMatthias Ringwald (*app_packet_handler)(HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event)); 1273deb3ec6SMatthias Ringwald } 1283deb3ec6SMatthias Ringwald 1293deb3ec6SMatthias Ringwald /* Send BNEP connection request */ 1303deb3ec6SMatthias Ringwald static int bnep_send_command_not_understood(bnep_channel_t *channel, uint8_t control_type) 1313deb3ec6SMatthias Ringwald { 1323deb3ec6SMatthias Ringwald uint8_t *bnep_out_buffer = NULL; 1333deb3ec6SMatthias Ringwald uint16_t pos = 0; 1343deb3ec6SMatthias Ringwald int err = 0; 1353deb3ec6SMatthias Ringwald 1363deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CLOSED) { 1373deb3ec6SMatthias Ringwald return -1; // TODO 1383deb3ec6SMatthias Ringwald } 1393deb3ec6SMatthias Ringwald 1403deb3ec6SMatthias Ringwald l2cap_reserve_packet_buffer(); 1413deb3ec6SMatthias Ringwald bnep_out_buffer = l2cap_get_outgoing_buffer(); 1423deb3ec6SMatthias Ringwald 1433deb3ec6SMatthias Ringwald /* Setup control packet type */ 1443deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL; 1453deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_COMMAND_NOT_UNDERSTOOD; 1463deb3ec6SMatthias Ringwald 1473deb3ec6SMatthias Ringwald /* Add not understood control type */ 1483deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = control_type; 1493deb3ec6SMatthias Ringwald 1503deb3ec6SMatthias Ringwald err = l2cap_send_prepared(channel->l2cap_cid, pos); 1513deb3ec6SMatthias Ringwald 1523deb3ec6SMatthias Ringwald if (err) { 1533deb3ec6SMatthias Ringwald // TODO: Log error 1543deb3ec6SMatthias Ringwald } 1553deb3ec6SMatthias Ringwald return err; 1563deb3ec6SMatthias Ringwald } 1573deb3ec6SMatthias Ringwald 1583deb3ec6SMatthias Ringwald 1593deb3ec6SMatthias Ringwald /* Send BNEP connection request */ 1603deb3ec6SMatthias Ringwald static int bnep_send_connection_request(bnep_channel_t *channel, uint16_t uuid_source, uint16_t uuid_dest) 1613deb3ec6SMatthias Ringwald { 1623deb3ec6SMatthias Ringwald uint8_t *bnep_out_buffer = NULL; 1633deb3ec6SMatthias Ringwald uint16_t pos = 0; 1643deb3ec6SMatthias Ringwald int err = 0; 1653deb3ec6SMatthias Ringwald 1663deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CLOSED) { 1673deb3ec6SMatthias Ringwald return -1; // TODO 1683deb3ec6SMatthias Ringwald } 1693deb3ec6SMatthias Ringwald 1703deb3ec6SMatthias Ringwald l2cap_reserve_packet_buffer(); 1713deb3ec6SMatthias Ringwald bnep_out_buffer = l2cap_get_outgoing_buffer(); 1723deb3ec6SMatthias Ringwald 1733deb3ec6SMatthias Ringwald /* Setup control packet type */ 1743deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL; 1753deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_SETUP_CONNECTION_REQUEST; 1763deb3ec6SMatthias Ringwald 1773deb3ec6SMatthias Ringwald /* Add UUID Size */ 1783deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = 2; 1793deb3ec6SMatthias Ringwald 1803deb3ec6SMatthias Ringwald /* Add dest and source UUID */ 181*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos, uuid_dest); 1823deb3ec6SMatthias Ringwald pos += 2; 1833deb3ec6SMatthias Ringwald 184*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos, uuid_source); 1853deb3ec6SMatthias Ringwald pos += 2; 1863deb3ec6SMatthias Ringwald 1873deb3ec6SMatthias Ringwald err = l2cap_send_prepared(channel->l2cap_cid, pos); 1883deb3ec6SMatthias Ringwald 1893deb3ec6SMatthias Ringwald if (err) { 1903deb3ec6SMatthias Ringwald // TODO: Log error 1913deb3ec6SMatthias Ringwald } 1923deb3ec6SMatthias Ringwald return err; 1933deb3ec6SMatthias Ringwald } 1943deb3ec6SMatthias Ringwald 1953deb3ec6SMatthias Ringwald /* Send BNEP connection response */ 1963deb3ec6SMatthias Ringwald static int bnep_send_connection_response(bnep_channel_t *channel, uint16_t response_code) 1973deb3ec6SMatthias Ringwald { 1983deb3ec6SMatthias Ringwald uint8_t *bnep_out_buffer = NULL; 1993deb3ec6SMatthias Ringwald uint16_t pos = 0; 2003deb3ec6SMatthias Ringwald int err = 0; 2013deb3ec6SMatthias Ringwald 2023deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CLOSED) { 2033deb3ec6SMatthias Ringwald return -1; // TODO 2043deb3ec6SMatthias Ringwald } 2053deb3ec6SMatthias Ringwald 2063deb3ec6SMatthias Ringwald l2cap_reserve_packet_buffer(); 2073deb3ec6SMatthias Ringwald bnep_out_buffer = l2cap_get_outgoing_buffer(); 2083deb3ec6SMatthias Ringwald 2093deb3ec6SMatthias Ringwald /* Setup control packet type */ 2103deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL; 2113deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_SETUP_CONNECTION_RESPONSE; 2123deb3ec6SMatthias Ringwald 2133deb3ec6SMatthias Ringwald /* Add response code */ 214*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos, response_code); 2153deb3ec6SMatthias Ringwald pos += 2; 2163deb3ec6SMatthias Ringwald 2173deb3ec6SMatthias Ringwald err = l2cap_send_prepared(channel->l2cap_cid, pos); 2183deb3ec6SMatthias Ringwald 2193deb3ec6SMatthias Ringwald if (err) { 2203deb3ec6SMatthias Ringwald // TODO: Log error 2213deb3ec6SMatthias Ringwald } 2223deb3ec6SMatthias Ringwald return err; 2233deb3ec6SMatthias Ringwald } 2243deb3ec6SMatthias Ringwald 2253deb3ec6SMatthias Ringwald /* Send BNEP filter net type set message */ 2263deb3ec6SMatthias Ringwald static int bnep_send_filter_net_type_set(bnep_channel_t *channel, bnep_net_filter_t *filter, uint16_t len) 2273deb3ec6SMatthias Ringwald { 2283deb3ec6SMatthias Ringwald uint8_t *bnep_out_buffer = NULL; 2293deb3ec6SMatthias Ringwald uint16_t pos = 0; 2303deb3ec6SMatthias Ringwald int err = 0; 2313deb3ec6SMatthias Ringwald int i; 2323deb3ec6SMatthias Ringwald 2333deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CLOSED) { 2343deb3ec6SMatthias Ringwald return -1; 2353deb3ec6SMatthias Ringwald } 2363deb3ec6SMatthias Ringwald 2373deb3ec6SMatthias Ringwald l2cap_reserve_packet_buffer(); 2383deb3ec6SMatthias Ringwald bnep_out_buffer = l2cap_get_outgoing_buffer(); 2393deb3ec6SMatthias Ringwald 2403deb3ec6SMatthias Ringwald /* Setup control packet type */ 2413deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL; 2423deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_NET_TYPE_SET; 2433deb3ec6SMatthias Ringwald 244*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos, len * 2 * 2); 2453deb3ec6SMatthias Ringwald pos += 2; 2463deb3ec6SMatthias Ringwald 2473deb3ec6SMatthias Ringwald for (i = 0; i < len; i ++) { 248*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos, filter[i].range_start); 2493deb3ec6SMatthias Ringwald pos += 2; 250*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos, filter[i].range_end); 2513deb3ec6SMatthias Ringwald pos += 2; 2523deb3ec6SMatthias Ringwald } 2533deb3ec6SMatthias Ringwald 2543deb3ec6SMatthias Ringwald err = l2cap_send_prepared(channel->l2cap_cid, pos); 2553deb3ec6SMatthias Ringwald 2563deb3ec6SMatthias Ringwald if (err) { 2573deb3ec6SMatthias Ringwald // TODO: Log error 2583deb3ec6SMatthias Ringwald } 2593deb3ec6SMatthias Ringwald return err; 2603deb3ec6SMatthias Ringwald } 2613deb3ec6SMatthias Ringwald 2623deb3ec6SMatthias Ringwald /* Send BNEP filter net type response message */ 2633deb3ec6SMatthias Ringwald static int bnep_send_filter_net_type_response(bnep_channel_t *channel, uint16_t response_code) 2643deb3ec6SMatthias Ringwald { 2653deb3ec6SMatthias Ringwald uint8_t *bnep_out_buffer = NULL; 2663deb3ec6SMatthias Ringwald uint16_t pos = 0; 2673deb3ec6SMatthias Ringwald int err = 0; 2683deb3ec6SMatthias Ringwald 2693deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CLOSED) { 2703deb3ec6SMatthias Ringwald return -1; 2713deb3ec6SMatthias Ringwald } 2723deb3ec6SMatthias Ringwald 2733deb3ec6SMatthias Ringwald l2cap_reserve_packet_buffer(); 2743deb3ec6SMatthias Ringwald bnep_out_buffer = l2cap_get_outgoing_buffer(); 2753deb3ec6SMatthias Ringwald 2763deb3ec6SMatthias Ringwald /* Setup control packet type */ 2773deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL; 2783deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_NET_TYPE_RESPONSE; 2793deb3ec6SMatthias Ringwald 2803deb3ec6SMatthias Ringwald /* Add response code */ 281*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos, response_code); 2823deb3ec6SMatthias Ringwald pos += 2; 2833deb3ec6SMatthias Ringwald 2843deb3ec6SMatthias Ringwald err = l2cap_send_prepared(channel->l2cap_cid, pos); 2853deb3ec6SMatthias Ringwald 2863deb3ec6SMatthias Ringwald if (err) { 2873deb3ec6SMatthias Ringwald // TODO: Log error 2883deb3ec6SMatthias Ringwald } 2893deb3ec6SMatthias Ringwald return err; 2903deb3ec6SMatthias Ringwald } 2913deb3ec6SMatthias Ringwald 2923deb3ec6SMatthias Ringwald /* Send BNEP filter multicast address set message */ 2933deb3ec6SMatthias Ringwald 2943deb3ec6SMatthias Ringwald static int bnep_send_filter_multi_addr_set(bnep_channel_t *channel, bnep_multi_filter_t *filter, uint16_t len) 2953deb3ec6SMatthias Ringwald { 2963deb3ec6SMatthias Ringwald uint8_t *bnep_out_buffer = NULL; 2973deb3ec6SMatthias Ringwald uint16_t pos = 0; 2983deb3ec6SMatthias Ringwald int err = 0; 2993deb3ec6SMatthias Ringwald int i; 3003deb3ec6SMatthias Ringwald 3013deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CLOSED) { 3023deb3ec6SMatthias Ringwald return -1; 3033deb3ec6SMatthias Ringwald } 3043deb3ec6SMatthias Ringwald 3053deb3ec6SMatthias Ringwald l2cap_reserve_packet_buffer(); 3063deb3ec6SMatthias Ringwald bnep_out_buffer = l2cap_get_outgoing_buffer(); 3073deb3ec6SMatthias Ringwald 3083deb3ec6SMatthias Ringwald /* Setup control packet type */ 3093deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL; 3103deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_SET; 3113deb3ec6SMatthias Ringwald 312*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos, len * 2 * ETHER_ADDR_LEN); 3133deb3ec6SMatthias Ringwald pos += 2; 3143deb3ec6SMatthias Ringwald 3153deb3ec6SMatthias Ringwald for (i = 0; i < len; i ++) { 3163deb3ec6SMatthias Ringwald BD_ADDR_COPY(bnep_out_buffer + pos, filter[i].addr_start); 3173deb3ec6SMatthias Ringwald pos += ETHER_ADDR_LEN; 3183deb3ec6SMatthias Ringwald BD_ADDR_COPY(bnep_out_buffer + pos, filter[i].addr_end); 3193deb3ec6SMatthias Ringwald pos += ETHER_ADDR_LEN; 3203deb3ec6SMatthias Ringwald } 3213deb3ec6SMatthias Ringwald 3223deb3ec6SMatthias Ringwald err = l2cap_send_prepared(channel->l2cap_cid, pos); 3233deb3ec6SMatthias Ringwald 3243deb3ec6SMatthias Ringwald if (err) { 3253deb3ec6SMatthias Ringwald // TODO: Log error 3263deb3ec6SMatthias Ringwald } 3273deb3ec6SMatthias Ringwald return err; 3283deb3ec6SMatthias Ringwald } 3293deb3ec6SMatthias Ringwald 3303deb3ec6SMatthias Ringwald /* Send BNEP filter multicast address response message */ 3313deb3ec6SMatthias Ringwald static int bnep_send_filter_multi_addr_response(bnep_channel_t *channel, uint16_t response_code) 3323deb3ec6SMatthias Ringwald { 3333deb3ec6SMatthias Ringwald uint8_t *bnep_out_buffer = NULL; 3343deb3ec6SMatthias Ringwald uint16_t pos = 0; 3353deb3ec6SMatthias Ringwald int err = 0; 3363deb3ec6SMatthias Ringwald 3373deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CLOSED) { 3383deb3ec6SMatthias Ringwald return -1; 3393deb3ec6SMatthias Ringwald } 3403deb3ec6SMatthias Ringwald 3413deb3ec6SMatthias Ringwald l2cap_reserve_packet_buffer(); 3423deb3ec6SMatthias Ringwald bnep_out_buffer = l2cap_get_outgoing_buffer(); 3433deb3ec6SMatthias Ringwald 3443deb3ec6SMatthias Ringwald /* Setup control packet type */ 3453deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL; 3463deb3ec6SMatthias Ringwald bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_RESPONSE; 3473deb3ec6SMatthias Ringwald 3483deb3ec6SMatthias Ringwald /* Add response code */ 349*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos, response_code); 3503deb3ec6SMatthias Ringwald pos += 2; 3513deb3ec6SMatthias Ringwald 3523deb3ec6SMatthias Ringwald err = l2cap_send_prepared(channel->l2cap_cid, pos); 3533deb3ec6SMatthias Ringwald 3543deb3ec6SMatthias Ringwald if (err) { 3553deb3ec6SMatthias Ringwald // TODO: Log error 3563deb3ec6SMatthias Ringwald } 3573deb3ec6SMatthias Ringwald return err; 3583deb3ec6SMatthias Ringwald } 3593deb3ec6SMatthias Ringwald 3603deb3ec6SMatthias Ringwald int bnep_can_send_packet_now(uint16_t bnep_cid) 3613deb3ec6SMatthias Ringwald { 3623deb3ec6SMatthias Ringwald bnep_channel_t *channel = bnep_channel_for_l2cap_cid(bnep_cid); 3633deb3ec6SMatthias Ringwald 3643deb3ec6SMatthias Ringwald if (!channel){ 3653deb3ec6SMatthias Ringwald log_error("bnep_can_send_packet_now cid 0x%02x doesn't exist!", bnep_cid); 3663deb3ec6SMatthias Ringwald return 0; 3673deb3ec6SMatthias Ringwald } 3683deb3ec6SMatthias Ringwald 3693deb3ec6SMatthias Ringwald return l2cap_can_send_packet_now(channel->l2cap_cid); 3703deb3ec6SMatthias Ringwald } 3713deb3ec6SMatthias Ringwald 3723deb3ec6SMatthias Ringwald 3733deb3ec6SMatthias Ringwald static int bnep_filter_protocol(bnep_channel_t *channel, uint16_t network_protocol_type) 3743deb3ec6SMatthias Ringwald { 3753deb3ec6SMatthias Ringwald int i; 3763deb3ec6SMatthias Ringwald 3773deb3ec6SMatthias Ringwald if (channel->net_filter_count == 0) { 3783deb3ec6SMatthias Ringwald /* No filter set */ 3793deb3ec6SMatthias Ringwald return 1; 3803deb3ec6SMatthias Ringwald } 3813deb3ec6SMatthias Ringwald 3823deb3ec6SMatthias Ringwald for (i = 0; i < channel->net_filter_count; i ++) { 3833deb3ec6SMatthias Ringwald if ((network_protocol_type >= channel->net_filter[i].range_start) && 3843deb3ec6SMatthias Ringwald (network_protocol_type <= channel->net_filter[i].range_end)) { 3853deb3ec6SMatthias Ringwald return 1; 3863deb3ec6SMatthias Ringwald } 3873deb3ec6SMatthias Ringwald } 3883deb3ec6SMatthias Ringwald 3893deb3ec6SMatthias Ringwald return 0; 3903deb3ec6SMatthias Ringwald } 3913deb3ec6SMatthias Ringwald 3923deb3ec6SMatthias Ringwald static int bnep_filter_multicast(bnep_channel_t *channel, bd_addr_t addr_dest) 3933deb3ec6SMatthias Ringwald { 3943deb3ec6SMatthias Ringwald int i; 3953deb3ec6SMatthias Ringwald 3963deb3ec6SMatthias Ringwald /* Check if the multicast flag is set int the destination address */ 3973deb3ec6SMatthias Ringwald if ((addr_dest[0] & 0x01) == 0x00) { 3983deb3ec6SMatthias Ringwald /* Not a multicast frame, do not apply filtering and send it in any case */ 3993deb3ec6SMatthias Ringwald return 1; 4003deb3ec6SMatthias Ringwald } 4013deb3ec6SMatthias Ringwald 4023deb3ec6SMatthias Ringwald if (channel->multicast_filter_count == 0) { 4033deb3ec6SMatthias Ringwald /* No filter set */ 4043deb3ec6SMatthias Ringwald return 1; 4053deb3ec6SMatthias Ringwald } 4063deb3ec6SMatthias Ringwald 4073deb3ec6SMatthias Ringwald for (i = 0; i < channel->multicast_filter_count; i ++) { 4083deb3ec6SMatthias Ringwald if ((memcmp(addr_dest, channel->multicast_filter[i].addr_start, sizeof(bd_addr_t)) >= 0) && 4093deb3ec6SMatthias Ringwald (memcmp(addr_dest, channel->multicast_filter[i].addr_end, sizeof(bd_addr_t)) <= 0)) { 4103deb3ec6SMatthias Ringwald return 1; 4113deb3ec6SMatthias Ringwald } 4123deb3ec6SMatthias Ringwald } 4133deb3ec6SMatthias Ringwald 4143deb3ec6SMatthias Ringwald return 0; 4153deb3ec6SMatthias Ringwald } 4163deb3ec6SMatthias Ringwald 4173deb3ec6SMatthias Ringwald 4183deb3ec6SMatthias Ringwald /* Send BNEP ethernet packet */ 4193deb3ec6SMatthias Ringwald int bnep_send(uint16_t bnep_cid, uint8_t *packet, uint16_t len) 4203deb3ec6SMatthias Ringwald { 4213deb3ec6SMatthias Ringwald bnep_channel_t *channel; 4223deb3ec6SMatthias Ringwald uint8_t *bnep_out_buffer = NULL; 4233deb3ec6SMatthias Ringwald uint16_t pos = 0; 4243deb3ec6SMatthias Ringwald uint16_t pos_out = 0; 4253deb3ec6SMatthias Ringwald uint16_t payload_len; 4263deb3ec6SMatthias Ringwald int err = 0; 4273deb3ec6SMatthias Ringwald int has_source; 4283deb3ec6SMatthias Ringwald int has_dest; 4293deb3ec6SMatthias Ringwald 4303deb3ec6SMatthias Ringwald bd_addr_t addr_dest; 4313deb3ec6SMatthias Ringwald bd_addr_t addr_source; 4323deb3ec6SMatthias Ringwald uint16_t network_protocol_type; 4333deb3ec6SMatthias Ringwald 4343deb3ec6SMatthias Ringwald channel = bnep_channel_for_l2cap_cid(bnep_cid); 4353deb3ec6SMatthias Ringwald if (channel == NULL) { 4363deb3ec6SMatthias Ringwald log_error("bnep_send cid 0x%02x doesn't exist!", bnep_cid); 4373deb3ec6SMatthias Ringwald return 1; 4383deb3ec6SMatthias Ringwald } 4393deb3ec6SMatthias Ringwald 4403deb3ec6SMatthias Ringwald if (channel->state != BNEP_CHANNEL_STATE_CONNECTED) { 4413deb3ec6SMatthias Ringwald return BNEP_CHANNEL_NOT_CONNECTED; 4423deb3ec6SMatthias Ringwald } 4433deb3ec6SMatthias Ringwald 4443deb3ec6SMatthias Ringwald /* Check for free ACL buffers */ 4453deb3ec6SMatthias Ringwald if (!l2cap_can_send_packet_now(channel->l2cap_cid)) { 4463deb3ec6SMatthias Ringwald return BTSTACK_ACL_BUFFERS_FULL; 4473deb3ec6SMatthias Ringwald } 4483deb3ec6SMatthias Ringwald 4493deb3ec6SMatthias Ringwald /* Extract destination and source address from the ethernet packet */ 4503deb3ec6SMatthias Ringwald pos = 0; 4513deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_dest, &packet[pos]); 4523deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 4533deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_source, &packet[pos]); 4543deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 455*f8fbdce0SMatthias Ringwald network_protocol_type = big_endian_read_16(packet, pos); 4563deb3ec6SMatthias Ringwald pos += sizeof(uint16_t); 4573deb3ec6SMatthias Ringwald 4583deb3ec6SMatthias Ringwald payload_len = len - pos; 4593deb3ec6SMatthias Ringwald 4603deb3ec6SMatthias Ringwald if (network_protocol_type == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */ 4613deb3ec6SMatthias Ringwald if (payload_len < 4) { 4623deb3ec6SMatthias Ringwald /* Omit this packet */ 4633deb3ec6SMatthias Ringwald return 0; 4643deb3ec6SMatthias Ringwald } 4653deb3ec6SMatthias Ringwald /* The "real" network protocol type is 4 bytes ahead in a VLAN packet */ 466*f8fbdce0SMatthias Ringwald network_protocol_type = big_endian_read_16(packet, pos + 2); 4673deb3ec6SMatthias Ringwald } 4683deb3ec6SMatthias Ringwald 4693deb3ec6SMatthias Ringwald /* Check network protocol and multicast filters before sending */ 4703deb3ec6SMatthias Ringwald if (!bnep_filter_protocol(channel, network_protocol_type) || 4713deb3ec6SMatthias Ringwald !bnep_filter_multicast(channel, addr_dest)) { 4723deb3ec6SMatthias Ringwald /* Packet did not pass filter... */ 4733deb3ec6SMatthias Ringwald if ((network_protocol_type == ETHERTYPE_VLAN) && 4743deb3ec6SMatthias Ringwald (payload_len >= 4)) { 4753deb3ec6SMatthias Ringwald /* The packet has been tagged as a with IEE 802.1Q tag and has been filtered out. 4763deb3ec6SMatthias Ringwald According to the spec the IEE802.1Q tag header shall be sended without ethernet payload. 4773deb3ec6SMatthias Ringwald So limit the payload_len to 4. 4783deb3ec6SMatthias Ringwald */ 4793deb3ec6SMatthias Ringwald payload_len = 4; 4803deb3ec6SMatthias Ringwald } else { 4813deb3ec6SMatthias Ringwald /* Packet is not tagged with IEE802.1Q header and was filtered out. Omit this packet */ 4823deb3ec6SMatthias Ringwald return 0; 4833deb3ec6SMatthias Ringwald } 4843deb3ec6SMatthias Ringwald } 4853deb3ec6SMatthias Ringwald 4863deb3ec6SMatthias Ringwald /* Reserve l2cap packet buffer */ 4873deb3ec6SMatthias Ringwald l2cap_reserve_packet_buffer(); 4883deb3ec6SMatthias Ringwald bnep_out_buffer = l2cap_get_outgoing_buffer(); 4893deb3ec6SMatthias Ringwald 4903deb3ec6SMatthias Ringwald /* Check if source address is the same as our local address and if the 4913deb3ec6SMatthias Ringwald destination address is the same as the remote addr. Maybe we can use 4923deb3ec6SMatthias Ringwald the compressed data format 4933deb3ec6SMatthias Ringwald */ 4943deb3ec6SMatthias Ringwald has_source = (memcmp(addr_source, channel->local_addr, ETHER_ADDR_LEN) != 0); 4953deb3ec6SMatthias Ringwald has_dest = (memcmp(addr_dest, channel->remote_addr, ETHER_ADDR_LEN) != 0); 4963deb3ec6SMatthias Ringwald 4973deb3ec6SMatthias Ringwald /* Check for MTU limits */ 4983deb3ec6SMatthias Ringwald if (payload_len > channel->max_frame_size) { 4993deb3ec6SMatthias Ringwald log_error("bnep_send: Max frame size (%d) exceeded: %d", channel->max_frame_size, payload_len); 5003deb3ec6SMatthias Ringwald return BNEP_DATA_LEN_EXCEEDS_MTU; 5013deb3ec6SMatthias Ringwald } 5023deb3ec6SMatthias Ringwald 5033deb3ec6SMatthias Ringwald /* Fill in the package type depending on the given source and destination address */ 5043deb3ec6SMatthias Ringwald if (has_source && has_dest) { 5053deb3ec6SMatthias Ringwald bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_GENERAL_ETHERNET; 5063deb3ec6SMatthias Ringwald } else 5073deb3ec6SMatthias Ringwald if (has_source && !has_dest) { 5083deb3ec6SMatthias Ringwald bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_COMPRESSED_ETHERNET_SOURCE_ONLY; 5093deb3ec6SMatthias Ringwald } else 5103deb3ec6SMatthias Ringwald if (!has_source && has_dest) { 5113deb3ec6SMatthias Ringwald bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_COMPRESSED_ETHERNET_DEST_ONLY; 5123deb3ec6SMatthias Ringwald } else { 5133deb3ec6SMatthias Ringwald bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_COMPRESSED_ETHERNET; 5143deb3ec6SMatthias Ringwald } 5153deb3ec6SMatthias Ringwald 5163deb3ec6SMatthias Ringwald /* Add the destination address if needed */ 5173deb3ec6SMatthias Ringwald if (has_dest) { 5183deb3ec6SMatthias Ringwald BD_ADDR_COPY(bnep_out_buffer + pos_out, addr_dest); 5193deb3ec6SMatthias Ringwald pos_out += sizeof(bd_addr_t); 5203deb3ec6SMatthias Ringwald } 5213deb3ec6SMatthias Ringwald 5223deb3ec6SMatthias Ringwald /* Add the source address if needed */ 5233deb3ec6SMatthias Ringwald if (has_source) { 5243deb3ec6SMatthias Ringwald BD_ADDR_COPY(bnep_out_buffer + pos_out, addr_source); 5253deb3ec6SMatthias Ringwald pos_out += sizeof(bd_addr_t); 5263deb3ec6SMatthias Ringwald } 5273deb3ec6SMatthias Ringwald 5283deb3ec6SMatthias Ringwald /* Add protocol type */ 529*f8fbdce0SMatthias Ringwald big_endian_store_16(bnep_out_buffer, pos_out, network_protocol_type); 5303deb3ec6SMatthias Ringwald pos_out += 2; 5313deb3ec6SMatthias Ringwald 5323deb3ec6SMatthias Ringwald /* TODO: Add extension headers, if we may support them at a later stage */ 5333deb3ec6SMatthias Ringwald /* Add the payload and then send out the package */ 5343deb3ec6SMatthias Ringwald memcpy(bnep_out_buffer + pos_out, packet + pos, payload_len); 5353deb3ec6SMatthias Ringwald pos_out += payload_len; 5363deb3ec6SMatthias Ringwald 5373deb3ec6SMatthias Ringwald err = l2cap_send_prepared(channel->l2cap_cid, pos_out); 5383deb3ec6SMatthias Ringwald 5393deb3ec6SMatthias Ringwald if (err) { 5403deb3ec6SMatthias Ringwald log_error("bnep_send: error %d", err); 5413deb3ec6SMatthias Ringwald } 5423deb3ec6SMatthias Ringwald return err; 5433deb3ec6SMatthias Ringwald } 5443deb3ec6SMatthias Ringwald 5453deb3ec6SMatthias Ringwald 5463deb3ec6SMatthias Ringwald /* Set BNEP network protocol type filter */ 5473deb3ec6SMatthias Ringwald int bnep_set_net_type_filter(uint16_t bnep_cid, bnep_net_filter_t *filter, uint16_t len) 5483deb3ec6SMatthias Ringwald { 5493deb3ec6SMatthias Ringwald bnep_channel_t *channel; 5503deb3ec6SMatthias Ringwald 5513deb3ec6SMatthias Ringwald if (filter == NULL) { 5523deb3ec6SMatthias Ringwald return -1; 5533deb3ec6SMatthias Ringwald } 5543deb3ec6SMatthias Ringwald 5553deb3ec6SMatthias Ringwald channel = bnep_channel_for_l2cap_cid(bnep_cid); 5563deb3ec6SMatthias Ringwald if (channel == NULL) { 5573deb3ec6SMatthias Ringwald log_error("bnep_set_net_type_filter cid 0x%02x doesn't exist!", bnep_cid); 5583deb3ec6SMatthias Ringwald return 1; 5593deb3ec6SMatthias Ringwald } 5603deb3ec6SMatthias Ringwald 5613deb3ec6SMatthias Ringwald if (channel->state != BNEP_CHANNEL_STATE_CONNECTED) { 5623deb3ec6SMatthias Ringwald return BNEP_CHANNEL_NOT_CONNECTED; 5633deb3ec6SMatthias Ringwald } 5643deb3ec6SMatthias Ringwald 5653deb3ec6SMatthias Ringwald if (len > MAX_BNEP_NETFILTER_OUT) { 5663deb3ec6SMatthias Ringwald return BNEP_DATA_LEN_EXCEEDS_MTU; 5673deb3ec6SMatthias Ringwald } 5683deb3ec6SMatthias Ringwald 5693deb3ec6SMatthias Ringwald channel->net_filter_out = filter; 5703deb3ec6SMatthias Ringwald channel->net_filter_out_count = len; 5713deb3ec6SMatthias Ringwald 5723deb3ec6SMatthias Ringwald /* Set flag to send out the network protocol type filter set reqeuest on next statemachine cycle */ 5733deb3ec6SMatthias Ringwald bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_SET); 5743deb3ec6SMatthias Ringwald bnep_run(); 5753deb3ec6SMatthias Ringwald 5763deb3ec6SMatthias Ringwald return 0; 5773deb3ec6SMatthias Ringwald } 5783deb3ec6SMatthias Ringwald 5793deb3ec6SMatthias Ringwald /* Set BNEP network protocol type filter */ 5803deb3ec6SMatthias Ringwald int bnep_set_multicast_filter(uint16_t bnep_cid, bnep_multi_filter_t *filter, uint16_t len) 5813deb3ec6SMatthias Ringwald { 5823deb3ec6SMatthias Ringwald bnep_channel_t *channel; 5833deb3ec6SMatthias Ringwald 5843deb3ec6SMatthias Ringwald if (filter == NULL) { 5853deb3ec6SMatthias Ringwald return -1; 5863deb3ec6SMatthias Ringwald } 5873deb3ec6SMatthias Ringwald 5883deb3ec6SMatthias Ringwald channel = bnep_channel_for_l2cap_cid(bnep_cid); 5893deb3ec6SMatthias Ringwald if (channel == NULL) { 5903deb3ec6SMatthias Ringwald log_error("bnep_set_net_type_filter cid 0x%02x doesn't exist!", bnep_cid); 5913deb3ec6SMatthias Ringwald return 1; 5923deb3ec6SMatthias Ringwald } 5933deb3ec6SMatthias Ringwald 5943deb3ec6SMatthias Ringwald if (channel->state != BNEP_CHANNEL_STATE_CONNECTED) { 5953deb3ec6SMatthias Ringwald return BNEP_CHANNEL_NOT_CONNECTED; 5963deb3ec6SMatthias Ringwald } 5973deb3ec6SMatthias Ringwald 59866b1fcb3SMatthias Ringwald if (len > MAX_BNEP_MULTICAST_FILTER_OUT) { 5993deb3ec6SMatthias Ringwald return BNEP_DATA_LEN_EXCEEDS_MTU; 6003deb3ec6SMatthias Ringwald } 6013deb3ec6SMatthias Ringwald 6023deb3ec6SMatthias Ringwald channel->multicast_filter_out = filter; 6033deb3ec6SMatthias Ringwald channel->multicast_filter_out_count = len; 6043deb3ec6SMatthias Ringwald 6053deb3ec6SMatthias Ringwald /* Set flag to send out the multicast filter set reqeuest on next statemachine cycle */ 6063deb3ec6SMatthias Ringwald bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_SET); 6073deb3ec6SMatthias Ringwald bnep_run(); 6083deb3ec6SMatthias Ringwald 6093deb3ec6SMatthias Ringwald return 0; 6103deb3ec6SMatthias Ringwald } 6113deb3ec6SMatthias Ringwald 6123deb3ec6SMatthias Ringwald /* BNEP timeout timer helper function */ 613ec820d77SMatthias Ringwald static void bnep_channel_timer_handler(btstack_timer_source_t *timer) 6143deb3ec6SMatthias Ringwald { 615665d90f2SMatthias Ringwald bnep_channel_t *channel = (bnep_channel_t *)btstack_linked_item_get_user((btstack_linked_item_t *) timer); 6163deb3ec6SMatthias Ringwald // retry send setup connection at least one time 6173deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE){ 6183deb3ec6SMatthias Ringwald if (channel->retry_count < BNEP_CONNECTION_MAX_RETRIES){ 6193deb3ec6SMatthias Ringwald channel->retry_count++; 6203deb3ec6SMatthias Ringwald bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS); 6213deb3ec6SMatthias Ringwald bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST); 6223deb3ec6SMatthias Ringwald bnep_run(); 6233deb3ec6SMatthias Ringwald return; 6243deb3ec6SMatthias Ringwald } 6253deb3ec6SMatthias Ringwald } 6263deb3ec6SMatthias Ringwald 6273deb3ec6SMatthias Ringwald log_info( "bnep_channel_timeout_handler callback: shutting down connection!"); 6283deb3ec6SMatthias Ringwald bnep_emit_channel_timeout(channel); 6293deb3ec6SMatthias Ringwald bnep_channel_finalize(channel); 6303deb3ec6SMatthias Ringwald } 6313deb3ec6SMatthias Ringwald 6323deb3ec6SMatthias Ringwald 6333deb3ec6SMatthias Ringwald static void bnep_channel_stop_timer(bnep_channel_t *channel) 6343deb3ec6SMatthias Ringwald { 6353deb3ec6SMatthias Ringwald if (channel->timer_active) { 636528a4a3bSMatthias Ringwald btstack_run_loop_remove_timer(&channel->timer); 6373deb3ec6SMatthias Ringwald channel->timer_active = 0; 6383deb3ec6SMatthias Ringwald } 6393deb3ec6SMatthias Ringwald } 6403deb3ec6SMatthias Ringwald 6413deb3ec6SMatthias Ringwald static void bnep_channel_start_timer(bnep_channel_t *channel, int timeout) 6423deb3ec6SMatthias Ringwald { 6433deb3ec6SMatthias Ringwald /* Stop any eventually running timeout timer */ 6443deb3ec6SMatthias Ringwald bnep_channel_stop_timer(channel); 6453deb3ec6SMatthias Ringwald 6463deb3ec6SMatthias Ringwald /* Start bnep channel timeout check timer */ 647528a4a3bSMatthias Ringwald btstack_run_loop_set_timer(&channel->timer, timeout); 6483deb3ec6SMatthias Ringwald channel->timer.process = bnep_channel_timer_handler; 649665d90f2SMatthias Ringwald btstack_linked_item_set_user((btstack_linked_item_t*) &channel->timer, channel); 650528a4a3bSMatthias Ringwald btstack_run_loop_add_timer(&channel->timer); 6513deb3ec6SMatthias Ringwald channel->timer_active = 1; 6523deb3ec6SMatthias Ringwald } 6533deb3ec6SMatthias Ringwald 6543deb3ec6SMatthias Ringwald /* BNEP statemachine functions */ 6553deb3ec6SMatthias Ringwald 6563deb3ec6SMatthias Ringwald inline static void bnep_channel_state_add(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event){ 6573deb3ec6SMatthias Ringwald channel->state_var = (BNEP_CHANNEL_STATE_VAR) (channel->state_var | event); 6583deb3ec6SMatthias Ringwald } 6593deb3ec6SMatthias Ringwald inline static void bnep_channel_state_remove(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event){ 6603deb3ec6SMatthias Ringwald channel->state_var = (BNEP_CHANNEL_STATE_VAR) (channel->state_var & ~event); 6613deb3ec6SMatthias Ringwald } 6623deb3ec6SMatthias Ringwald 6633deb3ec6SMatthias Ringwald static uint16_t bnep_max_frame_size_for_l2cap_mtu(uint16_t l2cap_mtu){ 6643deb3ec6SMatthias Ringwald 6653deb3ec6SMatthias Ringwald /* Assume a standard BNEP header, containing BNEP Type (1 Byte), dest and 6663deb3ec6SMatthias Ringwald source address (6 bytes each) and networking protocol type (2 bytes) 6673deb3ec6SMatthias Ringwald */ 6683deb3ec6SMatthias Ringwald uint16_t max_frame_size = l2cap_mtu - 15; // 15 bytes BNEP header 6693deb3ec6SMatthias Ringwald 6703deb3ec6SMatthias Ringwald log_info("bnep_max_frame_size_for_l2cap_mtu: %u -> %u", l2cap_mtu, max_frame_size); 6713deb3ec6SMatthias Ringwald return max_frame_size; 6723deb3ec6SMatthias Ringwald } 6733deb3ec6SMatthias Ringwald 6743deb3ec6SMatthias Ringwald static bnep_channel_t * bnep_channel_create_for_addr(bd_addr_t addr) 6753deb3ec6SMatthias Ringwald { 6763deb3ec6SMatthias Ringwald /* Allocate new channel structure */ 6773deb3ec6SMatthias Ringwald bnep_channel_t *channel = btstack_memory_bnep_channel_get(); 6783deb3ec6SMatthias Ringwald if (!channel) { 6793deb3ec6SMatthias Ringwald return NULL; 6803deb3ec6SMatthias Ringwald } 6813deb3ec6SMatthias Ringwald 6823deb3ec6SMatthias Ringwald /* Initialize the channel struct */ 6833deb3ec6SMatthias Ringwald memset(channel, 0, sizeof(bnep_channel_t)); 6843deb3ec6SMatthias Ringwald 6853deb3ec6SMatthias Ringwald channel->state = BNEP_CHANNEL_STATE_CLOSED; 6863deb3ec6SMatthias Ringwald channel->max_frame_size = bnep_max_frame_size_for_l2cap_mtu(l2cap_max_mtu()); 6873deb3ec6SMatthias Ringwald BD_ADDR_COPY(&channel->remote_addr, addr); 6883deb3ec6SMatthias Ringwald hci_local_bd_addr(channel->local_addr); 6893deb3ec6SMatthias Ringwald 6903deb3ec6SMatthias Ringwald channel->net_filter_count = 0; 6913deb3ec6SMatthias Ringwald channel->multicast_filter_count = 0; 6923deb3ec6SMatthias Ringwald channel->retry_count = 0; 6933deb3ec6SMatthias Ringwald 6943deb3ec6SMatthias Ringwald /* Finally add it to the channel list */ 695665d90f2SMatthias Ringwald btstack_linked_list_add(&bnep_channels, (btstack_linked_item_t *) channel); 6963deb3ec6SMatthias Ringwald 6973deb3ec6SMatthias Ringwald return channel; 6983deb3ec6SMatthias Ringwald } 6993deb3ec6SMatthias Ringwald 7003deb3ec6SMatthias Ringwald static bnep_channel_t* bnep_channel_for_addr(bd_addr_t addr) 7013deb3ec6SMatthias Ringwald { 702665d90f2SMatthias Ringwald btstack_linked_item_t *it; 703665d90f2SMatthias Ringwald for (it = (btstack_linked_item_t *) bnep_channels; it ; it = it->next){ 7043deb3ec6SMatthias Ringwald bnep_channel_t *channel = ((bnep_channel_t *) it); 7053deb3ec6SMatthias Ringwald if (BD_ADDR_CMP(addr, channel->remote_addr) == 0) { 7063deb3ec6SMatthias Ringwald return channel; 7073deb3ec6SMatthias Ringwald } 7083deb3ec6SMatthias Ringwald } 7093deb3ec6SMatthias Ringwald return NULL; 7103deb3ec6SMatthias Ringwald } 7113deb3ec6SMatthias Ringwald 7123deb3ec6SMatthias Ringwald static bnep_channel_t * bnep_channel_for_l2cap_cid(uint16_t l2cap_cid) 7133deb3ec6SMatthias Ringwald { 714665d90f2SMatthias Ringwald btstack_linked_item_t *it; 715665d90f2SMatthias Ringwald for (it = (btstack_linked_item_t *) bnep_channels; it ; it = it->next){ 7163deb3ec6SMatthias Ringwald bnep_channel_t *channel = ((bnep_channel_t *) it); 7173deb3ec6SMatthias Ringwald if (channel->l2cap_cid == l2cap_cid) { 7183deb3ec6SMatthias Ringwald return channel; 7193deb3ec6SMatthias Ringwald } 7203deb3ec6SMatthias Ringwald } 7213deb3ec6SMatthias Ringwald return NULL; 7223deb3ec6SMatthias Ringwald } 7233deb3ec6SMatthias Ringwald 7243deb3ec6SMatthias Ringwald static bnep_service_t * bnep_service_for_uuid(uint16_t uuid) 7253deb3ec6SMatthias Ringwald { 726665d90f2SMatthias Ringwald btstack_linked_item_t *it; 727665d90f2SMatthias Ringwald for (it = (btstack_linked_item_t *) bnep_services; it ; it = it->next){ 7283deb3ec6SMatthias Ringwald bnep_service_t * service = ((bnep_service_t *) it); 7293deb3ec6SMatthias Ringwald if ( service->service_uuid == uuid){ 7303deb3ec6SMatthias Ringwald return service; 7313deb3ec6SMatthias Ringwald } 7323deb3ec6SMatthias Ringwald } 7333deb3ec6SMatthias Ringwald return NULL; 7343deb3ec6SMatthias Ringwald } 7353deb3ec6SMatthias Ringwald 7363deb3ec6SMatthias Ringwald static void bnep_channel_free(bnep_channel_t *channel) 7373deb3ec6SMatthias Ringwald { 738665d90f2SMatthias Ringwald btstack_linked_list_remove( &bnep_channels, (btstack_linked_item_t *) channel); 7393deb3ec6SMatthias Ringwald btstack_memory_bnep_channel_free(channel); 7403deb3ec6SMatthias Ringwald } 7413deb3ec6SMatthias Ringwald 7423deb3ec6SMatthias Ringwald static void bnep_channel_finalize(bnep_channel_t *channel) 7433deb3ec6SMatthias Ringwald { 7443deb3ec6SMatthias Ringwald uint16_t l2cap_cid; 7453deb3ec6SMatthias Ringwald 7463deb3ec6SMatthias Ringwald /* Inform application about closed channel */ 7473deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) { 7483deb3ec6SMatthias Ringwald bnep_emit_channel_closed(channel); 7493deb3ec6SMatthias Ringwald } 7503deb3ec6SMatthias Ringwald 7513deb3ec6SMatthias Ringwald l2cap_cid = channel->l2cap_cid; 7523deb3ec6SMatthias Ringwald 7533deb3ec6SMatthias Ringwald /* Stop any eventually running timer */ 7543deb3ec6SMatthias Ringwald bnep_channel_stop_timer(channel); 7553deb3ec6SMatthias Ringwald 7563deb3ec6SMatthias Ringwald /* Free ressources and then close the l2cap channel */ 7573deb3ec6SMatthias Ringwald bnep_channel_free(channel); 758ce8f182eSMatthias Ringwald l2cap_disconnect(l2cap_cid, 0x13); 7593deb3ec6SMatthias Ringwald } 7603deb3ec6SMatthias Ringwald 7613deb3ec6SMatthias Ringwald static int bnep_handle_connection_request(bnep_channel_t *channel, uint8_t *packet, uint16_t size) 7623deb3ec6SMatthias Ringwald { 7633deb3ec6SMatthias Ringwald uint16_t uuid_size; 7643deb3ec6SMatthias Ringwald uint16_t uuid_offset; 7653deb3ec6SMatthias Ringwald uuid_size = packet[1]; 7663deb3ec6SMatthias Ringwald uint16_t response_code = BNEP_RESP_SETUP_SUCCESS; 7673deb3ec6SMatthias Ringwald bnep_service_t * service; 7683deb3ec6SMatthias Ringwald 7693deb3ec6SMatthias Ringwald /* Sanity check packet size */ 7703deb3ec6SMatthias Ringwald if (size < 1 + 1 + 2 * uuid_size) { 7713deb3ec6SMatthias Ringwald return 0; 7723deb3ec6SMatthias Ringwald } 7733deb3ec6SMatthias Ringwald 7743deb3ec6SMatthias Ringwald if ((channel->state != BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST) && 7753deb3ec6SMatthias Ringwald (channel->state != BNEP_CHANNEL_STATE_CONNECTED)) { 7763deb3ec6SMatthias Ringwald /* Ignore a connection request if not waiting for or still connected */ 7773deb3ec6SMatthias Ringwald log_error("BNEP_CONNECTION_REQUEST: ignored in state %d, l2cap_cid: %d!", channel->state, channel->l2cap_cid); 7783deb3ec6SMatthias Ringwald return 0; 7793deb3ec6SMatthias Ringwald } 7803deb3ec6SMatthias Ringwald 7813deb3ec6SMatthias Ringwald /* Extract source and destination UUID and convert them to UUID16 format */ 7823deb3ec6SMatthias Ringwald switch (uuid_size) { 7833deb3ec6SMatthias Ringwald case 2: /* UUID16 */ 7843deb3ec6SMatthias Ringwald uuid_offset = 0; 7853deb3ec6SMatthias Ringwald break; 7863deb3ec6SMatthias Ringwald case 4: /* UUID32 */ 7873deb3ec6SMatthias Ringwald case 16: /* UUID128 */ 7883deb3ec6SMatthias Ringwald uuid_offset = 2; 7893deb3ec6SMatthias Ringwald break; 7903deb3ec6SMatthias Ringwald default: 7913deb3ec6SMatthias Ringwald log_error("BNEP_CONNECTION_REQUEST: Invalid UUID size %d, l2cap_cid: %d!", channel->state, channel->l2cap_cid); 7923deb3ec6SMatthias Ringwald response_code = BNEP_RESP_SETUP_INVALID_SERVICE_UUID_SIZE; 7933deb3ec6SMatthias Ringwald break; 7943deb3ec6SMatthias Ringwald } 7953deb3ec6SMatthias Ringwald 7963deb3ec6SMatthias Ringwald /* Check source and destination UUIDs for valid combinations */ 7973deb3ec6SMatthias Ringwald if (response_code == BNEP_RESP_SETUP_SUCCESS) { 798*f8fbdce0SMatthias Ringwald channel->uuid_dest = big_endian_read_16(packet, 2 + uuid_offset); 799*f8fbdce0SMatthias Ringwald channel->uuid_source = big_endian_read_16(packet, 2 + uuid_offset + uuid_size); 8003deb3ec6SMatthias Ringwald 8013deb3ec6SMatthias Ringwald if ((channel->uuid_dest != SDP_PANU) && 8023deb3ec6SMatthias Ringwald (channel->uuid_dest != SDP_NAP) && 8033deb3ec6SMatthias Ringwald (channel->uuid_dest != SDP_GN)) { 8043deb3ec6SMatthias Ringwald log_error("BNEP_CONNECTION_REQUEST: Invalid destination service UUID: %04x", channel->uuid_dest); 8053deb3ec6SMatthias Ringwald channel->uuid_dest = 0; 8063deb3ec6SMatthias Ringwald } 8073deb3ec6SMatthias Ringwald if ((channel->uuid_source != SDP_PANU) && 8083deb3ec6SMatthias Ringwald (channel->uuid_source != SDP_NAP) && 8093deb3ec6SMatthias Ringwald (channel->uuid_source != SDP_GN)) { 8103deb3ec6SMatthias Ringwald log_error("BNEP_CONNECTION_REQUEST: Invalid source service UUID: %04x", channel->uuid_source); 8113deb3ec6SMatthias Ringwald channel->uuid_source = 0; 8123deb3ec6SMatthias Ringwald } 8133deb3ec6SMatthias Ringwald 8143deb3ec6SMatthias Ringwald /* Check if we have registered a service for the requested destination UUID */ 8153deb3ec6SMatthias Ringwald service = bnep_service_for_uuid(channel->uuid_dest); 8163deb3ec6SMatthias Ringwald if (service == NULL) { 8173deb3ec6SMatthias Ringwald response_code = BNEP_RESP_SETUP_INVALID_DEST_UUID; 8183deb3ec6SMatthias Ringwald } else 8193deb3ec6SMatthias Ringwald if ((channel->uuid_source != SDP_PANU) && (channel->uuid_dest != SDP_PANU)) { 8203deb3ec6SMatthias Ringwald response_code = BNEP_RESP_SETUP_INVALID_SOURCE_UUID; 8213deb3ec6SMatthias Ringwald } 8223deb3ec6SMatthias Ringwald } 8233deb3ec6SMatthias Ringwald 8243deb3ec6SMatthias Ringwald /* Set flag to send out the connection response on next statemachine cycle */ 8253deb3ec6SMatthias Ringwald bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE); 8263deb3ec6SMatthias Ringwald channel->response_code = response_code; 8273deb3ec6SMatthias Ringwald 8283deb3ec6SMatthias Ringwald /* Return the number of processed package bytes = BNEP Type, BNEP Control Type, UUID-Size + 2 * UUID */ 8293deb3ec6SMatthias Ringwald return 1 + 1 + 2 * uuid_size; 8303deb3ec6SMatthias Ringwald } 8313deb3ec6SMatthias Ringwald 8323deb3ec6SMatthias Ringwald static int bnep_handle_connection_response(bnep_channel_t *channel, uint8_t *packet, uint16_t size) 8333deb3ec6SMatthias Ringwald { 8343deb3ec6SMatthias Ringwald uint16_t response_code; 8353deb3ec6SMatthias Ringwald 8363deb3ec6SMatthias Ringwald /* Sanity check packet size */ 8373deb3ec6SMatthias Ringwald if (size < 1 + 2) { 8383deb3ec6SMatthias Ringwald return 0; 8393deb3ec6SMatthias Ringwald } 8403deb3ec6SMatthias Ringwald 8413deb3ec6SMatthias Ringwald if (channel->state != BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE) { 8423deb3ec6SMatthias Ringwald /* Ignore a connection response in any state but WAIT_FOR_CONNECTION_RESPONSE */ 8433deb3ec6SMatthias Ringwald log_error("BNEP_CONNECTION_RESPONSE: Ignored in channel state %d", channel->state); 8443deb3ec6SMatthias Ringwald return 1 + 2; 8453deb3ec6SMatthias Ringwald } 8463deb3ec6SMatthias Ringwald 847*f8fbdce0SMatthias Ringwald response_code = big_endian_read_16(packet, 1); 8483deb3ec6SMatthias Ringwald 8493deb3ec6SMatthias Ringwald if (response_code == BNEP_RESP_SETUP_SUCCESS) { 8503deb3ec6SMatthias Ringwald log_info("BNEP_CONNECTION_RESPONSE: Channel established to %s", bd_addr_to_str(channel->remote_addr)); 8513deb3ec6SMatthias Ringwald channel->state = BNEP_CHANNEL_STATE_CONNECTED; 8523deb3ec6SMatthias Ringwald /* Stop timeout timer! */ 8533deb3ec6SMatthias Ringwald bnep_channel_stop_timer(channel); 8543deb3ec6SMatthias Ringwald bnep_emit_open_channel_complete(channel, 0); 8553deb3ec6SMatthias Ringwald } else { 8563deb3ec6SMatthias Ringwald log_error("BNEP_CONNECTION_RESPONSE: Connection to %s failed. Err: %d", bd_addr_to_str(channel->remote_addr), response_code); 8573deb3ec6SMatthias Ringwald bnep_channel_finalize(channel); 8583deb3ec6SMatthias Ringwald } 8593deb3ec6SMatthias Ringwald return 1 + 2; 8603deb3ec6SMatthias Ringwald } 8613deb3ec6SMatthias Ringwald 8623deb3ec6SMatthias Ringwald static int bnep_can_handle_extensions(bnep_channel_t * channel){ 8633deb3ec6SMatthias Ringwald /* Extension are primarily handled in CONNECTED state */ 8643deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) return 1; 8653deb3ec6SMatthias Ringwald /* and if we've received connection request, but haven't sent the reponse yet. */ 8663deb3ec6SMatthias Ringwald if ((channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST) && 8673deb3ec6SMatthias Ringwald (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE)) { 8683deb3ec6SMatthias Ringwald return 1; 8693deb3ec6SMatthias Ringwald } 8703deb3ec6SMatthias Ringwald return 0; 8713deb3ec6SMatthias Ringwald } 8723deb3ec6SMatthias Ringwald 8733deb3ec6SMatthias Ringwald static int bnep_handle_filter_net_type_set(bnep_channel_t *channel, uint8_t *packet, uint16_t size) 8743deb3ec6SMatthias Ringwald { 8753deb3ec6SMatthias Ringwald uint16_t list_length; 8763deb3ec6SMatthias Ringwald uint16_t response_code = BNEP_RESP_FILTER_SUCCESS; 8773deb3ec6SMatthias Ringwald 8783deb3ec6SMatthias Ringwald /* Sanity check packet size */ 8793deb3ec6SMatthias Ringwald if (size < 3) { 8803deb3ec6SMatthias Ringwald return 0; 8813deb3ec6SMatthias Ringwald } 8823deb3ec6SMatthias Ringwald 883*f8fbdce0SMatthias Ringwald list_length = big_endian_read_16(packet, 1); 8843deb3ec6SMatthias Ringwald /* Sanity check packet size again with known package size */ 8853deb3ec6SMatthias Ringwald if (size < 3 + list_length) { 8863deb3ec6SMatthias Ringwald return 0; 8873deb3ec6SMatthias Ringwald } 8883deb3ec6SMatthias Ringwald 8893deb3ec6SMatthias Ringwald if (!bnep_can_handle_extensions(channel)){ 8903deb3ec6SMatthias Ringwald log_error("BNEP_FILTER_NET_TYPE_SET: Ignored in channel state %d", channel->state); 8913deb3ec6SMatthias Ringwald return 3 + list_length; 8923deb3ec6SMatthias Ringwald } 8933deb3ec6SMatthias Ringwald 8943deb3ec6SMatthias Ringwald /* Check if we have enough space for more filters */ 8953deb3ec6SMatthias Ringwald if ((list_length / (2*2)) > MAX_BNEP_NETFILTER) { 8963deb3ec6SMatthias Ringwald log_info("BNEP_FILTER_NET_TYPE_SET: Too many filter"); 8973deb3ec6SMatthias Ringwald response_code = BNEP_RESP_FILTER_ERR_TOO_MANY_FILTERS; 8983deb3ec6SMatthias Ringwald } else { 8993deb3ec6SMatthias Ringwald int i; 9003deb3ec6SMatthias Ringwald channel->net_filter_count = 0; 9013deb3ec6SMatthias Ringwald /* There is still enough space, copy the filters to our filter list */ 902ef907034SMatthias Ringwald /* There is still enough space, copy the filters to our filter list */ 9033deb3ec6SMatthias Ringwald for (i = 0; i < list_length / (2 * 2); i ++) { 904*f8fbdce0SMatthias Ringwald channel->net_filter[channel->net_filter_count].range_start = big_endian_read_16(packet, 1 + 2 + i * 4); 905*f8fbdce0SMatthias Ringwald channel->net_filter[channel->net_filter_count].range_end = big_endian_read_16(packet, 1 + 2 + i * 4 + 2); 9063deb3ec6SMatthias Ringwald if (channel->net_filter[channel->net_filter_count].range_start > channel->net_filter[channel->net_filter_count].range_end) { 9073deb3ec6SMatthias Ringwald /* Invalid filter range, ignore this filter rule */ 9083deb3ec6SMatthias Ringwald log_error("BNEP_FILTER_NET_TYPE_SET: Invalid filter: start: %d, end: %d", 9093deb3ec6SMatthias Ringwald channel->net_filter[channel->net_filter_count].range_start, 9103deb3ec6SMatthias Ringwald channel->net_filter[channel->net_filter_count].range_end); 9113deb3ec6SMatthias Ringwald response_code = BNEP_RESP_FILTER_ERR_INVALID_RANGE; 9123deb3ec6SMatthias Ringwald } else { 9133deb3ec6SMatthias Ringwald /* Valid filter, increase the filter count */ 9143deb3ec6SMatthias Ringwald log_info("BNEP_FILTER_NET_TYPE_SET: Add filter: start: %d, end: %d", 9153deb3ec6SMatthias Ringwald channel->net_filter[channel->net_filter_count].range_start, 9163deb3ec6SMatthias Ringwald channel->net_filter[channel->net_filter_count].range_end); 9173deb3ec6SMatthias Ringwald channel->net_filter_count ++; 9183deb3ec6SMatthias Ringwald } 9193deb3ec6SMatthias Ringwald } 9203deb3ec6SMatthias Ringwald } 9213deb3ec6SMatthias Ringwald 9223deb3ec6SMatthias Ringwald /* Set flag to send out the set net filter response on next statemachine cycle */ 9233deb3ec6SMatthias Ringwald bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_RESPONSE); 9243deb3ec6SMatthias Ringwald channel->response_code = response_code; 9253deb3ec6SMatthias Ringwald 9263deb3ec6SMatthias Ringwald return 3 + list_length; 9273deb3ec6SMatthias Ringwald } 9283deb3ec6SMatthias Ringwald 9293deb3ec6SMatthias Ringwald static int bnep_handle_filter_net_type_response(bnep_channel_t *channel, uint8_t *packet, uint16_t size) 9303deb3ec6SMatthias Ringwald { 9313deb3ec6SMatthias Ringwald uint16_t response_code; 9323deb3ec6SMatthias Ringwald 9333deb3ec6SMatthias Ringwald // TODO: Currently we do not support setting a network filter. 9343deb3ec6SMatthias Ringwald 9353deb3ec6SMatthias Ringwald /* Sanity check packet size */ 9363deb3ec6SMatthias Ringwald if (size < 1 + 2) { 9373deb3ec6SMatthias Ringwald return 0; 9383deb3ec6SMatthias Ringwald } 9393deb3ec6SMatthias Ringwald 9403deb3ec6SMatthias Ringwald if (!bnep_can_handle_extensions(channel)){ 9413deb3ec6SMatthias Ringwald log_error("BNEP_FILTER_NET_TYPE_RESPONSE: Ignored in channel state %d", channel->state); 9423deb3ec6SMatthias Ringwald return 1 + 2; 9433deb3ec6SMatthias Ringwald } 9443deb3ec6SMatthias Ringwald 945*f8fbdce0SMatthias Ringwald response_code = big_endian_read_16(packet, 1); 9463deb3ec6SMatthias Ringwald 9473deb3ec6SMatthias Ringwald if (response_code == BNEP_RESP_FILTER_SUCCESS) { 9483deb3ec6SMatthias Ringwald log_info("BNEP_FILTER_NET_TYPE_RESPONSE: Net filter set successfully for %s", bd_addr_to_str(channel->remote_addr)); 9493deb3ec6SMatthias Ringwald } else { 9503deb3ec6SMatthias Ringwald log_error("BNEP_FILTER_NET_TYPE_RESPONSE: Net filter setting for %s failed. Err: %d", bd_addr_to_str(channel->remote_addr), response_code); 9513deb3ec6SMatthias Ringwald } 9523deb3ec6SMatthias Ringwald 9533deb3ec6SMatthias Ringwald return 1 + 2; 9543deb3ec6SMatthias Ringwald } 9553deb3ec6SMatthias Ringwald 9563deb3ec6SMatthias Ringwald static int bnep_handle_multi_addr_set(bnep_channel_t *channel, uint8_t *packet, uint16_t size) 9573deb3ec6SMatthias Ringwald { 9583deb3ec6SMatthias Ringwald uint16_t list_length; 9593deb3ec6SMatthias Ringwald uint16_t response_code = BNEP_RESP_FILTER_SUCCESS; 9603deb3ec6SMatthias Ringwald 9613deb3ec6SMatthias Ringwald /* Sanity check packet size */ 9623deb3ec6SMatthias Ringwald if (size < 3) { 9633deb3ec6SMatthias Ringwald return 0; 9643deb3ec6SMatthias Ringwald } 9653deb3ec6SMatthias Ringwald 966*f8fbdce0SMatthias Ringwald list_length = big_endian_read_16(packet, 1); 9673deb3ec6SMatthias Ringwald /* Sanity check packet size again with known package size */ 9683deb3ec6SMatthias Ringwald if (size < 3 + list_length) { 9693deb3ec6SMatthias Ringwald return 0; 9703deb3ec6SMatthias Ringwald } 9713deb3ec6SMatthias Ringwald 9723deb3ec6SMatthias Ringwald if (!bnep_can_handle_extensions(channel)){ 9733deb3ec6SMatthias Ringwald log_error("BNEP_MULTI_ADDR_SET: Ignored in channel state %d", channel->state); 9743deb3ec6SMatthias Ringwald return 3 + list_length; 9753deb3ec6SMatthias Ringwald } 9763deb3ec6SMatthias Ringwald 9773deb3ec6SMatthias Ringwald /* Check if we have enough space for more filters */ 9783deb3ec6SMatthias Ringwald if ((list_length / (2 * ETHER_ADDR_LEN)) > MAX_BNEP_MULTICAST_FILTER) { 9793deb3ec6SMatthias Ringwald log_info("BNEP_MULTI_ADDR_SET: Too many filter"); 9803deb3ec6SMatthias Ringwald response_code = BNEP_RESP_FILTER_ERR_TOO_MANY_FILTERS; 9813deb3ec6SMatthias Ringwald } else { 9823deb3ec6SMatthias Ringwald unsigned int i; 9833deb3ec6SMatthias Ringwald channel->multicast_filter_count = 0; 9843deb3ec6SMatthias Ringwald /* There is enough space, copy the filters to our filter list */ 9853deb3ec6SMatthias Ringwald for (i = 0; i < list_length / (2 * ETHER_ADDR_LEN); i ++) { 9863deb3ec6SMatthias Ringwald BD_ADDR_COPY(channel->multicast_filter[channel->multicast_filter_count].addr_start, packet + 1 + 2 + i * ETHER_ADDR_LEN * 2); 9873deb3ec6SMatthias Ringwald BD_ADDR_COPY(channel->multicast_filter[channel->multicast_filter_count].addr_end, packet + 1 + 2 + i * ETHER_ADDR_LEN * 2 + ETHER_ADDR_LEN); 9883deb3ec6SMatthias Ringwald 9893deb3ec6SMatthias Ringwald if (memcmp(channel->multicast_filter[channel->multicast_filter_count].addr_start, 9903deb3ec6SMatthias Ringwald channel->multicast_filter[channel->multicast_filter_count].addr_end, ETHER_ADDR_LEN) > 0) { 9913deb3ec6SMatthias Ringwald /* Invalid filter range, ignore this filter rule */ 9923deb3ec6SMatthias Ringwald log_error("BNEP_MULTI_ADDR_SET: Invalid filter: start: %s", 9933deb3ec6SMatthias Ringwald bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_start)); 9943deb3ec6SMatthias Ringwald log_error("BNEP_MULTI_ADDR_SET: Invalid filter: end: %s", 9953deb3ec6SMatthias Ringwald bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_end)); 9963deb3ec6SMatthias Ringwald response_code = BNEP_RESP_FILTER_ERR_INVALID_RANGE; 9973deb3ec6SMatthias Ringwald } else { 9983deb3ec6SMatthias Ringwald /* Valid filter, increase the filter count */ 9993deb3ec6SMatthias Ringwald log_info("BNEP_MULTI_ADDR_SET: Add filter: start: %s", 10003deb3ec6SMatthias Ringwald bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_start)); 10013deb3ec6SMatthias Ringwald log_info("BNEP_MULTI_ADDR_SET: Add filter: end: %s", 10023deb3ec6SMatthias Ringwald bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_end)); 10033deb3ec6SMatthias Ringwald channel->multicast_filter_count ++; 10043deb3ec6SMatthias Ringwald } 10053deb3ec6SMatthias Ringwald } 10063deb3ec6SMatthias Ringwald } 10073deb3ec6SMatthias Ringwald /* Set flag to send out the set multi addr response on next statemachine cycle */ 10083deb3ec6SMatthias Ringwald bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_RESPONSE); 10093deb3ec6SMatthias Ringwald channel->response_code = response_code; 10103deb3ec6SMatthias Ringwald 10113deb3ec6SMatthias Ringwald return 3 + list_length; 10123deb3ec6SMatthias Ringwald } 10133deb3ec6SMatthias Ringwald 10143deb3ec6SMatthias Ringwald static int bnep_handle_multi_addr_response(bnep_channel_t *channel, uint8_t *packet, uint16_t size) 10153deb3ec6SMatthias Ringwald { 10163deb3ec6SMatthias Ringwald uint16_t response_code; 10173deb3ec6SMatthias Ringwald 10183deb3ec6SMatthias Ringwald // TODO: Currently we do not support setting multicast address filter. 10193deb3ec6SMatthias Ringwald 10203deb3ec6SMatthias Ringwald /* Sanity check packet size */ 10213deb3ec6SMatthias Ringwald if (size < 1 + 2) { 10223deb3ec6SMatthias Ringwald return 0; 10233deb3ec6SMatthias Ringwald } 10243deb3ec6SMatthias Ringwald 10253deb3ec6SMatthias Ringwald if (!bnep_can_handle_extensions(channel)){ 10263deb3ec6SMatthias Ringwald log_error("BNEP_MULTI_ADDR_RESPONSE: Ignored in channel state %d", channel->state); 10273deb3ec6SMatthias Ringwald return 1 + 2; 10283deb3ec6SMatthias Ringwald } 10293deb3ec6SMatthias Ringwald 1030*f8fbdce0SMatthias Ringwald response_code = big_endian_read_16(packet, 1); 10313deb3ec6SMatthias Ringwald 10323deb3ec6SMatthias Ringwald if (response_code == BNEP_RESP_FILTER_SUCCESS) { 10333deb3ec6SMatthias Ringwald log_info("BNEP_MULTI_ADDR_RESPONSE: Multicast address filter set successfully for %s", bd_addr_to_str(channel->remote_addr)); 10343deb3ec6SMatthias Ringwald } else { 10353deb3ec6SMatthias Ringwald log_error("BNEP_MULTI_ADDR_RESPONSE: Multicast address filter setting for %s failed. Err: %d", bd_addr_to_str(channel->remote_addr), response_code); 10363deb3ec6SMatthias Ringwald } 10373deb3ec6SMatthias Ringwald 10383deb3ec6SMatthias Ringwald return 1 + 2; 10393deb3ec6SMatthias Ringwald } 10403deb3ec6SMatthias Ringwald 10413deb3ec6SMatthias Ringwald static int bnep_handle_ethernet_packet(bnep_channel_t *channel, bd_addr_t addr_dest, bd_addr_t addr_source, uint16_t network_protocol_type, uint8_t *payload, uint16_t size) 10423deb3ec6SMatthias Ringwald { 10433deb3ec6SMatthias Ringwald uint16_t pos = 0; 10443deb3ec6SMatthias Ringwald 10453deb3ec6SMatthias Ringwald #if (HCI_INCOMING_PRE_BUFFER_SIZE) && (HCI_INCOMING_PRE_BUFFER_SIZE >= 14 - 8) // 2 * sizeof(bd_addr_t) + sizeof(uint16_t) - L2CAP Header (4) - ACL Header (4) 10463deb3ec6SMatthias Ringwald /* In-place modify the package and add the ethernet header in front of the payload. 10473deb3ec6SMatthias Ringwald * WARNING: This modifies the data in front of the payload and may overwrite 14 bytes there! 10483deb3ec6SMatthias Ringwald */ 10493deb3ec6SMatthias Ringwald uint8_t *ethernet_packet = payload - 2 * sizeof(bd_addr_t) - sizeof(uint16_t); 10503deb3ec6SMatthias Ringwald /* Restore the ethernet packet header */ 10513deb3ec6SMatthias Ringwald BD_ADDR_COPY(ethernet_packet + pos, addr_dest); 10523deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 10533deb3ec6SMatthias Ringwald BD_ADDR_COPY(ethernet_packet + pos, addr_source); 10543deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 1055*f8fbdce0SMatthias Ringwald big_endian_store_16(ethernet_packet, pos, network_protocol_type); 10563deb3ec6SMatthias Ringwald /* Payload is just in place... */ 10573deb3ec6SMatthias Ringwald #else 10583deb3ec6SMatthias Ringwald /* Copy ethernet frame to statically allocated buffer. This solution is more 10593deb3ec6SMatthias Ringwald * save, but needs an extra copy and more stack! 10603deb3ec6SMatthias Ringwald */ 10613deb3ec6SMatthias Ringwald uint8_t ethernet_packet[BNEP_MTU_MIN]; 10623deb3ec6SMatthias Ringwald 10633deb3ec6SMatthias Ringwald /* Restore the ethernet packet header */ 10643deb3ec6SMatthias Ringwald BD_ADDR_COPY(ethernet_packet + pos, addr_dest); 10653deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 10663deb3ec6SMatthias Ringwald BD_ADDR_COPY(ethernet_packet + pos, addr_source); 10673deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 1068*f8fbdce0SMatthias Ringwald big_endian_store_16(ethernet_packet, pos, network_protocol_type); 10693deb3ec6SMatthias Ringwald pos += 2; 10703deb3ec6SMatthias Ringwald memcpy(ethernet_packet + pos, payload, size); 10713deb3ec6SMatthias Ringwald #endif 10723deb3ec6SMatthias Ringwald 10733deb3ec6SMatthias Ringwald /* Notify application layer and deliver the ethernet packet */ 10740cc6429eSMatthias Ringwald (*app_packet_handler)(BNEP_DATA_PACKET, channel->uuid_source, 10753deb3ec6SMatthias Ringwald ethernet_packet, size + sizeof(uint16_t) + 2 * sizeof(bd_addr_t)); 10763deb3ec6SMatthias Ringwald 10773deb3ec6SMatthias Ringwald return size; 10783deb3ec6SMatthias Ringwald } 10793deb3ec6SMatthias Ringwald 10803deb3ec6SMatthias Ringwald static int bnep_handle_control_packet(bnep_channel_t *channel, uint8_t *packet, uint16_t size, int is_extension) 10813deb3ec6SMatthias Ringwald { 10823deb3ec6SMatthias Ringwald uint16_t len = 0; 10833deb3ec6SMatthias Ringwald uint8_t bnep_control_type; 10843deb3ec6SMatthias Ringwald 10853deb3ec6SMatthias Ringwald bnep_control_type = packet[0]; 10863deb3ec6SMatthias Ringwald /* Save last control type. Needed by statemachin in case of unknown control code */ 10873deb3ec6SMatthias Ringwald 10883deb3ec6SMatthias Ringwald channel->last_control_type = bnep_control_type; 10893deb3ec6SMatthias Ringwald log_info("BNEP_CONTROL: Type: %d, size: %d, is_extension: %d", bnep_control_type, size, is_extension); 10903deb3ec6SMatthias Ringwald switch (bnep_control_type) { 10913deb3ec6SMatthias Ringwald case BNEP_CONTROL_TYPE_COMMAND_NOT_UNDERSTOOD: 10923deb3ec6SMatthias Ringwald /* The last command we send was not understood. We should close the connection */ 10933deb3ec6SMatthias Ringwald log_error("BNEP_CONTROL: Received COMMAND_NOT_UNDERSTOOD: l2cap_cid: %d, cmd: %d", channel->l2cap_cid, packet[3]); 10943deb3ec6SMatthias Ringwald bnep_channel_finalize(channel); 10953deb3ec6SMatthias Ringwald len = 2; // Length of command not understood packet - bnep-type field 10963deb3ec6SMatthias Ringwald break; 10973deb3ec6SMatthias Ringwald case BNEP_CONTROL_TYPE_SETUP_CONNECTION_REQUEST: 10983deb3ec6SMatthias Ringwald if (is_extension) { 10993deb3ec6SMatthias Ringwald /* Connection requests are not allowed to be send in an extension header 11003deb3ec6SMatthias Ringwald * ignore, do not set "COMMAND_NOT_UNDERSTOOD" 11013deb3ec6SMatthias Ringwald */ 11023deb3ec6SMatthias Ringwald log_error("BNEP_CONTROL: Received SETUP_CONNECTION_REQUEST in extension header: l2cap_cid: %d", channel->l2cap_cid); 11033deb3ec6SMatthias Ringwald return 0; 11043deb3ec6SMatthias Ringwald } else { 11053deb3ec6SMatthias Ringwald len = bnep_handle_connection_request(channel, packet, size); 11063deb3ec6SMatthias Ringwald } 11073deb3ec6SMatthias Ringwald break; 11083deb3ec6SMatthias Ringwald case BNEP_CONTROL_TYPE_SETUP_CONNECTION_RESPONSE: 11093deb3ec6SMatthias Ringwald if (is_extension) { 11103deb3ec6SMatthias Ringwald /* Connection requests are not allowed to be send in an 11113deb3ec6SMatthias Ringwald * extension header, ignore, do not set "COMMAND_NOT_UNDERSTOOD" 11123deb3ec6SMatthias Ringwald */ 11133deb3ec6SMatthias Ringwald log_error("BNEP_CONTROL: Received SETUP_CONNECTION_RESPONSE in extension header: l2cap_cid: %d", channel->l2cap_cid); 11143deb3ec6SMatthias Ringwald return 0; 11153deb3ec6SMatthias Ringwald } else { 11163deb3ec6SMatthias Ringwald len = bnep_handle_connection_response(channel, packet, size); 11173deb3ec6SMatthias Ringwald } 11183deb3ec6SMatthias Ringwald break; 11193deb3ec6SMatthias Ringwald case BNEP_CONTROL_TYPE_FILTER_NET_TYPE_SET: 11203deb3ec6SMatthias Ringwald len = bnep_handle_filter_net_type_set(channel, packet, size); 11213deb3ec6SMatthias Ringwald break; 11223deb3ec6SMatthias Ringwald case BNEP_CONTROL_TYPE_FILTER_NET_TYPE_RESPONSE: 11233deb3ec6SMatthias Ringwald len = bnep_handle_filter_net_type_response(channel, packet, size); 11243deb3ec6SMatthias Ringwald break; 11253deb3ec6SMatthias Ringwald case BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_SET: 11263deb3ec6SMatthias Ringwald len = bnep_handle_multi_addr_set(channel, packet, size); 11273deb3ec6SMatthias Ringwald break; 11283deb3ec6SMatthias Ringwald case BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_RESPONSE: 11293deb3ec6SMatthias Ringwald len = bnep_handle_multi_addr_response(channel, packet, size); 11303deb3ec6SMatthias Ringwald break; 11313deb3ec6SMatthias Ringwald default: 11323deb3ec6SMatthias Ringwald log_error("BNEP_CONTROL: Invalid bnep control type: l2cap_cid: %d, cmd: %d", channel->l2cap_cid, bnep_control_type); 11333deb3ec6SMatthias Ringwald len = 0; 11343deb3ec6SMatthias Ringwald break; 11353deb3ec6SMatthias Ringwald } 11363deb3ec6SMatthias Ringwald 11373deb3ec6SMatthias Ringwald if (len == 0) { 11383deb3ec6SMatthias Ringwald /* In case the command could not be handled, send a 11393deb3ec6SMatthias Ringwald COMMAND_NOT_UNDERSTOOD message. 11403deb3ec6SMatthias Ringwald Set flag to process the request in the next statemachine loop 11413deb3ec6SMatthias Ringwald */ 11423deb3ec6SMatthias Ringwald bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_NOT_UNDERSTOOD); 11433deb3ec6SMatthias Ringwald } 11443deb3ec6SMatthias Ringwald 11453deb3ec6SMatthias Ringwald return len; 11463deb3ec6SMatthias Ringwald } 11473deb3ec6SMatthias Ringwald 11483deb3ec6SMatthias Ringwald /** 11493deb3ec6SMatthias Ringwald * @return handled packet 11503deb3ec6SMatthias Ringwald */ 11513deb3ec6SMatthias Ringwald static int bnep_hci_event_handler(uint8_t *packet, uint16_t size) 11523deb3ec6SMatthias Ringwald { 11533deb3ec6SMatthias Ringwald bd_addr_t event_addr; 11543deb3ec6SMatthias Ringwald uint16_t psm; 11553deb3ec6SMatthias Ringwald uint16_t l2cap_cid; 11563deb3ec6SMatthias Ringwald hci_con_handle_t con_handle; 11573deb3ec6SMatthias Ringwald bnep_channel_t *channel = NULL; 11583deb3ec6SMatthias Ringwald uint8_t status; 11593deb3ec6SMatthias Ringwald 11603deb3ec6SMatthias Ringwald switch (packet[0]) { 11613deb3ec6SMatthias Ringwald 11623deb3ec6SMatthias Ringwald /* Accept an incoming L2CAP connection on PSM_BNEP */ 11633deb3ec6SMatthias Ringwald case L2CAP_EVENT_INCOMING_CONNECTION: 11643deb3ec6SMatthias Ringwald /* L2CAP event data: event(8), len(8), address(48), handle (16), psm (16), source cid(16) dest cid(16) */ 11653deb3ec6SMatthias Ringwald bt_flip_addr(event_addr, &packet[2]); 1166*f8fbdce0SMatthias Ringwald con_handle = little_endian_read_16(packet, 8); 1167*f8fbdce0SMatthias Ringwald psm = little_endian_read_16(packet, 10); 1168*f8fbdce0SMatthias Ringwald l2cap_cid = little_endian_read_16(packet, 12); 11693deb3ec6SMatthias Ringwald 11703deb3ec6SMatthias Ringwald if (psm != PSM_BNEP) break; 11713deb3ec6SMatthias Ringwald 11723deb3ec6SMatthias Ringwald channel = bnep_channel_for_addr(event_addr); 11733deb3ec6SMatthias Ringwald 11743deb3ec6SMatthias Ringwald if (channel) { 11753deb3ec6SMatthias Ringwald log_error("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => decline - channel already exists", l2cap_cid); 1176ce8f182eSMatthias Ringwald l2cap_decline_connection(l2cap_cid, 0x04); // no resources available 11773deb3ec6SMatthias Ringwald return 1; 11783deb3ec6SMatthias Ringwald } 11793deb3ec6SMatthias Ringwald 11803deb3ec6SMatthias Ringwald /* Create a new BNEP channel instance (incoming) */ 11813deb3ec6SMatthias Ringwald channel = bnep_channel_create_for_addr(event_addr); 11823deb3ec6SMatthias Ringwald 11833deb3ec6SMatthias Ringwald if (!channel) { 11843deb3ec6SMatthias Ringwald log_error("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => decline - no memory left", l2cap_cid); 1185ce8f182eSMatthias Ringwald l2cap_decline_connection(l2cap_cid, 0x04); // no resources available 11863deb3ec6SMatthias Ringwald return 1; 11873deb3ec6SMatthias Ringwald } 11883deb3ec6SMatthias Ringwald 11893deb3ec6SMatthias Ringwald /* Assign connection handle and l2cap cid */ 11903deb3ec6SMatthias Ringwald channel->con_handle = con_handle; 11913deb3ec6SMatthias Ringwald channel->l2cap_cid = l2cap_cid; 11923deb3ec6SMatthias Ringwald 11933deb3ec6SMatthias Ringwald /* Set channel into accept state */ 11943deb3ec6SMatthias Ringwald channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST; 11953deb3ec6SMatthias Ringwald 11963deb3ec6SMatthias Ringwald /* Start connection timeout timer */ 11973deb3ec6SMatthias Ringwald bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS); 11983deb3ec6SMatthias Ringwald 11993deb3ec6SMatthias Ringwald log_info("L2CAP_EVENT_INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => accept", l2cap_cid); 1200ce8f182eSMatthias Ringwald l2cap_accept_connection(l2cap_cid); 12013deb3ec6SMatthias Ringwald return 1; 12023deb3ec6SMatthias Ringwald 12033deb3ec6SMatthias Ringwald /* Outgoing L2CAP connection has been opened -> store l2cap_cid, remote_addr */ 12043deb3ec6SMatthias Ringwald case L2CAP_EVENT_CHANNEL_OPENED: 12053deb3ec6SMatthias Ringwald /* Check if the l2cap channel has been opened for PSM_BNEP */ 1206*f8fbdce0SMatthias Ringwald if (little_endian_read_16(packet, 11) != PSM_BNEP) { 12073deb3ec6SMatthias Ringwald break; 12083deb3ec6SMatthias Ringwald } 12093deb3ec6SMatthias Ringwald 12103deb3ec6SMatthias Ringwald status = packet[2]; 12113deb3ec6SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED for PSM_BNEP, status %u", status); 12123deb3ec6SMatthias Ringwald 12133deb3ec6SMatthias Ringwald /* Get the bnep channel fpr remote address */ 1214*f8fbdce0SMatthias Ringwald con_handle = little_endian_read_16(packet, 9); 1215*f8fbdce0SMatthias Ringwald l2cap_cid = little_endian_read_16(packet, 13); 12163deb3ec6SMatthias Ringwald bt_flip_addr(event_addr, &packet[3]); 12173deb3ec6SMatthias Ringwald channel = bnep_channel_for_addr(event_addr); 12183deb3ec6SMatthias Ringwald if (!channel) { 12193deb3ec6SMatthias Ringwald log_error("L2CAP_EVENT_CHANNEL_OPENED but no BNEP channel prepared"); 12203deb3ec6SMatthias Ringwald return 1; 12213deb3ec6SMatthias Ringwald } 12223deb3ec6SMatthias Ringwald 12233deb3ec6SMatthias Ringwald /* On L2CAP open error discard everything */ 12243deb3ec6SMatthias Ringwald if (status) { 12253deb3ec6SMatthias Ringwald /* Emit bnep_open_channel_complete with status and free channel */ 12263deb3ec6SMatthias Ringwald bnep_emit_open_channel_complete(channel, status); 12273deb3ec6SMatthias Ringwald 12283deb3ec6SMatthias Ringwald /* Free BNEP channel mempory */ 12293deb3ec6SMatthias Ringwald bnep_channel_free(channel); 12303deb3ec6SMatthias Ringwald return 1; 12313deb3ec6SMatthias Ringwald } 12323deb3ec6SMatthias Ringwald 12333deb3ec6SMatthias Ringwald switch (channel->state){ 12343deb3ec6SMatthias Ringwald case BNEP_CHANNEL_STATE_CLOSED: 12353deb3ec6SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_OPENED: outgoing connection"); 12363deb3ec6SMatthias Ringwald 12373deb3ec6SMatthias Ringwald bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS); 12383deb3ec6SMatthias Ringwald 12393deb3ec6SMatthias Ringwald /* Assign connection handle and l2cap cid */ 12403deb3ec6SMatthias Ringwald channel->l2cap_cid = l2cap_cid; 12413deb3ec6SMatthias Ringwald channel->con_handle = con_handle; 12423deb3ec6SMatthias Ringwald 12433deb3ec6SMatthias Ringwald /* Initiate the connection request */ 12443deb3ec6SMatthias Ringwald channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE; 12453deb3ec6SMatthias Ringwald bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST); 1246*f8fbdce0SMatthias Ringwald channel->max_frame_size = bnep_max_frame_size_for_l2cap_mtu(little_endian_read_16(packet, 17)); 12473deb3ec6SMatthias Ringwald bnep_run(); 12483deb3ec6SMatthias Ringwald break; 12493deb3ec6SMatthias Ringwald case BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST: 12503deb3ec6SMatthias Ringwald /* New information: channel mtu */ 1251*f8fbdce0SMatthias Ringwald channel->max_frame_size = bnep_max_frame_size_for_l2cap_mtu(little_endian_read_16(packet, 17)); 12523deb3ec6SMatthias Ringwald break; 12533deb3ec6SMatthias Ringwald default: 12543deb3ec6SMatthias Ringwald log_error("L2CAP_EVENT_CHANNEL_OPENED: Invalid state: %d", channel->state); 12553deb3ec6SMatthias Ringwald break; 12563deb3ec6SMatthias Ringwald } 12573deb3ec6SMatthias Ringwald return 1; 12583deb3ec6SMatthias Ringwald 12593deb3ec6SMatthias Ringwald case DAEMON_EVENT_HCI_PACKET_SENT: 12603deb3ec6SMatthias Ringwald bnep_run(); 12613deb3ec6SMatthias Ringwald break; 12623deb3ec6SMatthias Ringwald 12633deb3ec6SMatthias Ringwald case L2CAP_EVENT_CHANNEL_CLOSED: 12643deb3ec6SMatthias Ringwald // data: event (8), len(8), channel (16) 1265*f8fbdce0SMatthias Ringwald l2cap_cid = little_endian_read_16(packet, 2); 12663deb3ec6SMatthias Ringwald channel = bnep_channel_for_l2cap_cid(l2cap_cid); 12673deb3ec6SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED cid 0x%0x, channel %p", l2cap_cid, channel); 12683deb3ec6SMatthias Ringwald 12693deb3ec6SMatthias Ringwald if (!channel) { 12703deb3ec6SMatthias Ringwald break; 12713deb3ec6SMatthias Ringwald } 12723deb3ec6SMatthias Ringwald 12733deb3ec6SMatthias Ringwald log_info("L2CAP_EVENT_CHANNEL_CLOSED state %u", channel->state); 12743deb3ec6SMatthias Ringwald switch (channel->state) { 12753deb3ec6SMatthias Ringwald case BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST: 12763deb3ec6SMatthias Ringwald case BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE: 12773deb3ec6SMatthias Ringwald case BNEP_CHANNEL_STATE_CONNECTED: 12783deb3ec6SMatthias Ringwald bnep_channel_finalize(channel); 12793deb3ec6SMatthias Ringwald return 1; 12803deb3ec6SMatthias Ringwald default: 12813deb3ec6SMatthias Ringwald break; 12823deb3ec6SMatthias Ringwald } 12833deb3ec6SMatthias Ringwald break; 12843deb3ec6SMatthias Ringwald default: 12853deb3ec6SMatthias Ringwald bnep_run(); 12863deb3ec6SMatthias Ringwald break; 12873deb3ec6SMatthias Ringwald } 12883deb3ec6SMatthias Ringwald return 0; 12893deb3ec6SMatthias Ringwald } 12903deb3ec6SMatthias Ringwald 12913deb3ec6SMatthias Ringwald static int bnep_l2cap_packet_handler(uint16_t l2cap_cid, uint8_t *packet, uint16_t size) 12923deb3ec6SMatthias Ringwald { 12933deb3ec6SMatthias Ringwald int rc = 0; 12943deb3ec6SMatthias Ringwald uint8_t bnep_type; 12953deb3ec6SMatthias Ringwald uint8_t bnep_header_has_ext; 12963deb3ec6SMatthias Ringwald uint8_t extension_type; 12973deb3ec6SMatthias Ringwald uint16_t pos = 0; 12983deb3ec6SMatthias Ringwald bd_addr_t addr_source; 12993deb3ec6SMatthias Ringwald bd_addr_t addr_dest; 13003deb3ec6SMatthias Ringwald uint16_t network_protocol_type = 0xffff; 13013deb3ec6SMatthias Ringwald bnep_channel_t *channel = NULL; 13023deb3ec6SMatthias Ringwald 13033deb3ec6SMatthias Ringwald /* Get the bnep channel for this package */ 13043deb3ec6SMatthias Ringwald channel = bnep_channel_for_l2cap_cid(l2cap_cid); 13053deb3ec6SMatthias Ringwald if (!channel) { 13063deb3ec6SMatthias Ringwald return rc; 13073deb3ec6SMatthias Ringwald } 13083deb3ec6SMatthias Ringwald 13093deb3ec6SMatthias Ringwald /* Sort out short packages */ 13103deb3ec6SMatthias Ringwald if (size < 2) { 13113deb3ec6SMatthias Ringwald return rc; 13123deb3ec6SMatthias Ringwald } 13133deb3ec6SMatthias Ringwald 13143deb3ec6SMatthias Ringwald bnep_type = BNEP_TYPE(packet[pos]); 13153deb3ec6SMatthias Ringwald bnep_header_has_ext = BNEP_HEADER_HAS_EXT(packet[pos]); 13163deb3ec6SMatthias Ringwald pos ++; 13173deb3ec6SMatthias Ringwald 13183deb3ec6SMatthias Ringwald switch(bnep_type) { 13193deb3ec6SMatthias Ringwald case BNEP_PKT_TYPE_GENERAL_ETHERNET: 13203deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_dest, &packet[pos]); 13213deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 13223deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_source, &packet[pos]); 13233deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 1324*f8fbdce0SMatthias Ringwald network_protocol_type = big_endian_read_16(packet, pos); 13253deb3ec6SMatthias Ringwald pos += 2; 13263deb3ec6SMatthias Ringwald break; 13273deb3ec6SMatthias Ringwald case BNEP_PKT_TYPE_COMPRESSED_ETHERNET: 13283deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_dest, channel->local_addr); 13293deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_source, channel->remote_addr); 1330*f8fbdce0SMatthias Ringwald network_protocol_type = big_endian_read_16(packet, pos); 13313deb3ec6SMatthias Ringwald pos += 2; 13323deb3ec6SMatthias Ringwald break; 13333deb3ec6SMatthias Ringwald case BNEP_PKT_TYPE_COMPRESSED_ETHERNET_SOURCE_ONLY: 13343deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_dest, channel->local_addr); 13353deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_source, &packet[pos]); 13363deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 1337*f8fbdce0SMatthias Ringwald network_protocol_type = big_endian_read_16(packet, pos); 13383deb3ec6SMatthias Ringwald pos += 2; 13393deb3ec6SMatthias Ringwald break; 13403deb3ec6SMatthias Ringwald case BNEP_PKT_TYPE_COMPRESSED_ETHERNET_DEST_ONLY: 13413deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_dest, &packet[pos]); 13423deb3ec6SMatthias Ringwald pos += sizeof(bd_addr_t); 13433deb3ec6SMatthias Ringwald BD_ADDR_COPY(addr_source, channel->remote_addr); 1344*f8fbdce0SMatthias Ringwald network_protocol_type = big_endian_read_16(packet, pos); 13453deb3ec6SMatthias Ringwald pos += 2; 13463deb3ec6SMatthias Ringwald break; 13473deb3ec6SMatthias Ringwald case BNEP_PKT_TYPE_CONTROL: 13483deb3ec6SMatthias Ringwald rc = bnep_handle_control_packet(channel, packet + pos, size - pos, 0); 13493deb3ec6SMatthias Ringwald pos += rc; 13503deb3ec6SMatthias Ringwald break; 13513deb3ec6SMatthias Ringwald default: 13523deb3ec6SMatthias Ringwald break; 13533deb3ec6SMatthias Ringwald } 13543deb3ec6SMatthias Ringwald 13553deb3ec6SMatthias Ringwald if (bnep_header_has_ext) { 13563deb3ec6SMatthias Ringwald do { 13573deb3ec6SMatthias Ringwald uint8_t ext_len; 13583deb3ec6SMatthias Ringwald 13593deb3ec6SMatthias Ringwald /* Read extension type and check for further extensions */ 13603deb3ec6SMatthias Ringwald extension_type = BNEP_TYPE(packet[pos]); 13613deb3ec6SMatthias Ringwald bnep_header_has_ext = BNEP_HEADER_HAS_EXT(packet[pos]); 13623deb3ec6SMatthias Ringwald pos ++; 13633deb3ec6SMatthias Ringwald 13643deb3ec6SMatthias Ringwald /* Read extension header length */ 13653deb3ec6SMatthias Ringwald ext_len = packet[pos]; 13663deb3ec6SMatthias Ringwald pos ++; 13673deb3ec6SMatthias Ringwald 13683deb3ec6SMatthias Ringwald if (size - pos < ext_len) { 13693deb3ec6SMatthias Ringwald log_error("BNEP pkt handler: Invalid extension length! Packet ignored"); 13703deb3ec6SMatthias Ringwald /* Invalid packet size! */ 13713deb3ec6SMatthias Ringwald return 0; 13723deb3ec6SMatthias Ringwald } 13733deb3ec6SMatthias Ringwald 13743deb3ec6SMatthias Ringwald switch (extension_type) { 13753deb3ec6SMatthias Ringwald case BNEP_EXT_HEADER_TYPE_EXTENSION_CONTROL: 13763deb3ec6SMatthias Ringwald if (ext_len != bnep_handle_control_packet(channel, packet + pos, ext_len, 1)) { 13773deb3ec6SMatthias Ringwald log_error("BNEP pkt handler: Ignore invalid control packet in extension header"); 13783deb3ec6SMatthias Ringwald } 13793deb3ec6SMatthias Ringwald 13803deb3ec6SMatthias Ringwald pos += ext_len; 13813deb3ec6SMatthias Ringwald break; 13823deb3ec6SMatthias Ringwald 13833deb3ec6SMatthias Ringwald default: 13843deb3ec6SMatthias Ringwald /* Extension header type unknown. Unknown extension SHALL be 13853deb3ec6SMatthias Ringwald * SHALL be forwarded in any way. But who shall handle these 13863deb3ec6SMatthias Ringwald * extension packets? 13873deb3ec6SMatthias Ringwald * For now: We ignore them and just drop them! 13883deb3ec6SMatthias Ringwald */ 13893deb3ec6SMatthias Ringwald log_error("BNEP pkt handler: Unknown extension type ignored, data dropped!"); 13903deb3ec6SMatthias Ringwald pos += ext_len; 13913deb3ec6SMatthias Ringwald break; 13923deb3ec6SMatthias Ringwald } 13933deb3ec6SMatthias Ringwald 13943deb3ec6SMatthias Ringwald } while (bnep_header_has_ext); 13953deb3ec6SMatthias Ringwald } 13963deb3ec6SMatthias Ringwald 13973deb3ec6SMatthias Ringwald if (bnep_type != BNEP_PKT_TYPE_CONTROL && network_protocol_type != 0xffff) { 13983deb3ec6SMatthias Ringwald if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) { 13993deb3ec6SMatthias Ringwald rc = bnep_handle_ethernet_packet(channel, addr_dest, addr_source, network_protocol_type, packet + pos, size - pos); 14003deb3ec6SMatthias Ringwald } else { 14013deb3ec6SMatthias Ringwald rc = 0; 14023deb3ec6SMatthias Ringwald } 14033deb3ec6SMatthias Ringwald } 14043deb3ec6SMatthias Ringwald 14053deb3ec6SMatthias Ringwald return rc; 14063deb3ec6SMatthias Ringwald 14073deb3ec6SMatthias Ringwald } 14083deb3ec6SMatthias Ringwald 14093deb3ec6SMatthias Ringwald void bnep_packet_handler(uint8_t packet_type, uint16_t l2cap_cid, uint8_t *packet, uint16_t size) 14103deb3ec6SMatthias Ringwald { 14113deb3ec6SMatthias Ringwald int handled = 0; 14123deb3ec6SMatthias Ringwald switch (packet_type) { 14133deb3ec6SMatthias Ringwald case HCI_EVENT_PACKET: 14143deb3ec6SMatthias Ringwald handled = bnep_hci_event_handler(packet, size); 14153deb3ec6SMatthias Ringwald break; 14163deb3ec6SMatthias Ringwald case L2CAP_DATA_PACKET: 14173deb3ec6SMatthias Ringwald handled = bnep_l2cap_packet_handler(l2cap_cid, packet, size); 14183deb3ec6SMatthias Ringwald break; 14193deb3ec6SMatthias Ringwald default: 14203deb3ec6SMatthias Ringwald break; 14213deb3ec6SMatthias Ringwald } 14223deb3ec6SMatthias Ringwald 14233deb3ec6SMatthias Ringwald if (handled) { 14243deb3ec6SMatthias Ringwald bnep_run(); 14253deb3ec6SMatthias Ringwald return; 14263deb3ec6SMatthias Ringwald } 14273deb3ec6SMatthias Ringwald 14283deb3ec6SMatthias Ringwald /* Forward non l2cap packages to application handler */ 14293deb3ec6SMatthias Ringwald if (packet_type != L2CAP_DATA_PACKET) { 14300cc6429eSMatthias Ringwald (*app_packet_handler)(packet_type, l2cap_cid, packet, size); 14313deb3ec6SMatthias Ringwald return; 14323deb3ec6SMatthias Ringwald } 14333deb3ec6SMatthias Ringwald 14343deb3ec6SMatthias Ringwald bnep_run(); 14353deb3ec6SMatthias Ringwald } 14363deb3ec6SMatthias Ringwald 14373deb3ec6SMatthias Ringwald static void bnep_channel_state_machine(bnep_channel_t* channel, bnep_channel_event_t *event) 14383deb3ec6SMatthias Ringwald { 14393deb3ec6SMatthias Ringwald log_info("bnep_state_machine: state %u, state var: %02x, event %u", channel->state, channel->state_var, event->type); 14403deb3ec6SMatthias Ringwald 14413deb3ec6SMatthias Ringwald if (event->type == BNEP_CH_EVT_READY_TO_SEND) { 14423deb3ec6SMatthias Ringwald /* Send outstanding packets. */ 14433deb3ec6SMatthias Ringwald if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_NOT_UNDERSTOOD) { 14443deb3ec6SMatthias Ringwald bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_NOT_UNDERSTOOD); 14453deb3ec6SMatthias Ringwald bnep_send_command_not_understood(channel, channel->last_control_type); 14463deb3ec6SMatthias Ringwald return; 14473deb3ec6SMatthias Ringwald } 14483deb3ec6SMatthias Ringwald if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST) { 14493deb3ec6SMatthias Ringwald bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST); 14503deb3ec6SMatthias Ringwald channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE; 14513deb3ec6SMatthias Ringwald bnep_send_connection_request(channel, channel->uuid_source, channel->uuid_dest); 14523deb3ec6SMatthias Ringwald } 14533deb3ec6SMatthias Ringwald if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE) { 14543deb3ec6SMatthias Ringwald int emit_connected = 0; 14553deb3ec6SMatthias Ringwald if ((channel->state == BNEP_CHANNEL_STATE_CLOSED) || 14563deb3ec6SMatthias Ringwald (channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST)) { 14573deb3ec6SMatthias Ringwald /* Set channel state to STATE_CONNECTED */ 14583deb3ec6SMatthias Ringwald channel->state = BNEP_CHANNEL_STATE_CONNECTED; 14593deb3ec6SMatthias Ringwald /* Stop timeout timer! */ 14603deb3ec6SMatthias Ringwald bnep_channel_stop_timer(channel); 14613deb3ec6SMatthias Ringwald emit_connected = 1; 14623deb3ec6SMatthias Ringwald } 14633deb3ec6SMatthias Ringwald 14643deb3ec6SMatthias Ringwald bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE); 14653deb3ec6SMatthias Ringwald bnep_send_connection_response(channel, channel->response_code); 14663deb3ec6SMatthias Ringwald if (emit_connected){ 14673deb3ec6SMatthias Ringwald bnep_emit_open_channel_complete(channel, 0); 14683deb3ec6SMatthias Ringwald } 14693deb3ec6SMatthias Ringwald return; 14703deb3ec6SMatthias Ringwald } 14713deb3ec6SMatthias Ringwald if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_SET) { 14723deb3ec6SMatthias Ringwald bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_SET); 14733deb3ec6SMatthias Ringwald if ((channel->net_filter_out_count > 0) && (channel->net_filter_out != NULL)) { 14743deb3ec6SMatthias Ringwald bnep_send_filter_net_type_set(channel, channel->net_filter_out, channel->net_filter_out_count); 14753deb3ec6SMatthias Ringwald channel->net_filter_out_count = 0; 14763deb3ec6SMatthias Ringwald channel->net_filter_out = NULL; 14773deb3ec6SMatthias Ringwald } 14783deb3ec6SMatthias Ringwald return; 14793deb3ec6SMatthias Ringwald } 14803deb3ec6SMatthias Ringwald if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_RESPONSE) { 14813deb3ec6SMatthias Ringwald bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_RESPONSE); 14823deb3ec6SMatthias Ringwald bnep_send_filter_net_type_response(channel, channel->response_code); 14833deb3ec6SMatthias Ringwald return; 14843deb3ec6SMatthias Ringwald } 14853deb3ec6SMatthias Ringwald if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_SET) { 14863deb3ec6SMatthias Ringwald bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_SET); 14873deb3ec6SMatthias Ringwald if ((channel->multicast_filter_out_count > 0) && (channel->multicast_filter_out != NULL)) { 14883deb3ec6SMatthias Ringwald bnep_send_filter_multi_addr_set(channel, channel->multicast_filter_out, channel->multicast_filter_out_count); 14893deb3ec6SMatthias Ringwald channel->multicast_filter_out_count = 0; 14903deb3ec6SMatthias Ringwald channel->multicast_filter_out = NULL; 14913deb3ec6SMatthias Ringwald } 14923deb3ec6SMatthias Ringwald return; 14933deb3ec6SMatthias Ringwald } 14943deb3ec6SMatthias Ringwald if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_RESPONSE) { 14953deb3ec6SMatthias Ringwald bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_RESPONSE); 14963deb3ec6SMatthias Ringwald bnep_send_filter_multi_addr_response(channel, channel->response_code); 14973deb3ec6SMatthias Ringwald return; 14983deb3ec6SMatthias Ringwald } 14993deb3ec6SMatthias Ringwald 15003deb3ec6SMatthias Ringwald 15013deb3ec6SMatthias Ringwald /* If the event was not yet handled, notify the application layer */ 15023deb3ec6SMatthias Ringwald bnep_emit_ready_to_send(channel); 15033deb3ec6SMatthias Ringwald } 15043deb3ec6SMatthias Ringwald } 15053deb3ec6SMatthias Ringwald 15063deb3ec6SMatthias Ringwald 15073deb3ec6SMatthias Ringwald /* Process oustanding signaling tasks */ 15083deb3ec6SMatthias Ringwald static void bnep_run(void) 15093deb3ec6SMatthias Ringwald { 1510665d90f2SMatthias Ringwald btstack_linked_item_t *it; 1511665d90f2SMatthias Ringwald btstack_linked_item_t *next; 15123deb3ec6SMatthias Ringwald 1513665d90f2SMatthias Ringwald for (it = (btstack_linked_item_t *) bnep_channels; it ; it = next){ 15143deb3ec6SMatthias Ringwald 15153deb3ec6SMatthias Ringwald next = it->next; // be prepared for removal of channel in state machine 15163deb3ec6SMatthias Ringwald 15173deb3ec6SMatthias Ringwald bnep_channel_t * channel = ((bnep_channel_t *) it); 15183deb3ec6SMatthias Ringwald 15193deb3ec6SMatthias Ringwald if (!l2cap_can_send_packet_now(channel->l2cap_cid)) { 15203deb3ec6SMatthias Ringwald continue; 15213deb3ec6SMatthias Ringwald } 15223deb3ec6SMatthias Ringwald 15233deb3ec6SMatthias Ringwald bnep_channel_event_t channel_event = { BNEP_CH_EVT_READY_TO_SEND }; 15243deb3ec6SMatthias Ringwald bnep_channel_state_machine(channel, &channel_event); 15253deb3ec6SMatthias Ringwald } 15263deb3ec6SMatthias Ringwald } 15273deb3ec6SMatthias Ringwald 15283deb3ec6SMatthias Ringwald /* BNEP BTStack API */ 15293deb3ec6SMatthias Ringwald void bnep_init(void) 15303deb3ec6SMatthias Ringwald { 15313deb3ec6SMatthias Ringwald bnep_security_level = LEVEL_0; 15323deb3ec6SMatthias Ringwald } 15333deb3ec6SMatthias Ringwald 15343deb3ec6SMatthias Ringwald void bnep_set_required_security_level(gap_security_level_t security_level) 15353deb3ec6SMatthias Ringwald { 15363deb3ec6SMatthias Ringwald bnep_security_level = security_level; 15373deb3ec6SMatthias Ringwald } 15383deb3ec6SMatthias Ringwald 15393deb3ec6SMatthias Ringwald /* Register application packet handler */ 15400cc6429eSMatthias Ringwald void bnep_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){ 15413deb3ec6SMatthias Ringwald app_packet_handler = handler; 15423deb3ec6SMatthias Ringwald } 15433deb3ec6SMatthias Ringwald 15440cc6429eSMatthias Ringwald int bnep_connect(bd_addr_t addr, uint16_t l2cap_psm, uint16_t uuid_src, uint16_t uuid_dest) 15453deb3ec6SMatthias Ringwald { 15463deb3ec6SMatthias Ringwald bnep_channel_t *channel; 15473deb3ec6SMatthias Ringwald log_info("BNEP_CONNECT addr %s", bd_addr_to_str(addr)); 15483deb3ec6SMatthias Ringwald 15493deb3ec6SMatthias Ringwald channel = bnep_channel_create_for_addr(addr); 15503deb3ec6SMatthias Ringwald if (channel == NULL) { 15513deb3ec6SMatthias Ringwald return -1; 15523deb3ec6SMatthias Ringwald } 15533deb3ec6SMatthias Ringwald 15543deb3ec6SMatthias Ringwald channel->uuid_source = uuid_src; 15553deb3ec6SMatthias Ringwald channel->uuid_dest = uuid_dest; 15563deb3ec6SMatthias Ringwald 155790a28bdeSMatthias Ringwald uint8_t status = l2cap_create_channel(bnep_packet_handler, addr, l2cap_psm, l2cap_max_mtu(), NULL); 155890a28bdeSMatthias Ringwald if (status){ 155990a28bdeSMatthias Ringwald return -1; 156090a28bdeSMatthias Ringwald } 15613deb3ec6SMatthias Ringwald return 0; 15623deb3ec6SMatthias Ringwald } 15633deb3ec6SMatthias Ringwald 15643deb3ec6SMatthias Ringwald void bnep_disconnect(bd_addr_t addr) 15653deb3ec6SMatthias Ringwald { 15663deb3ec6SMatthias Ringwald bnep_channel_t *channel; 15673deb3ec6SMatthias Ringwald log_info("BNEP_DISCONNECT"); 15683deb3ec6SMatthias Ringwald 15693deb3ec6SMatthias Ringwald channel = bnep_channel_for_addr(addr); 15703deb3ec6SMatthias Ringwald 15713deb3ec6SMatthias Ringwald bnep_channel_finalize(channel); 15723deb3ec6SMatthias Ringwald 15733deb3ec6SMatthias Ringwald bnep_run(); 15743deb3ec6SMatthias Ringwald } 15753deb3ec6SMatthias Ringwald 15763deb3ec6SMatthias Ringwald 15770cc6429eSMatthias Ringwald uint8_t bnep_register_service(uint16_t service_uuid, uint16_t max_frame_size) 15783deb3ec6SMatthias Ringwald { 15793deb3ec6SMatthias Ringwald log_info("BNEP_REGISTER_SERVICE mtu %d", max_frame_size); 15803deb3ec6SMatthias Ringwald 15813deb3ec6SMatthias Ringwald /* Check if we already registered a service */ 15823deb3ec6SMatthias Ringwald bnep_service_t * service = bnep_service_for_uuid(service_uuid); 15833deb3ec6SMatthias Ringwald if (service) { 15840cc6429eSMatthias Ringwald return BNEP_SERVICE_ALREADY_REGISTERED; 15853deb3ec6SMatthias Ringwald } 15863deb3ec6SMatthias Ringwald 15873deb3ec6SMatthias Ringwald /* Only alow one the three service types: PANU, NAP, GN */ 15883deb3ec6SMatthias Ringwald if ((service_uuid != SDP_PANU) && 15893deb3ec6SMatthias Ringwald (service_uuid != SDP_NAP) && 15903deb3ec6SMatthias Ringwald (service_uuid != SDP_GN)) { 15913deb3ec6SMatthias Ringwald log_info("BNEP_REGISTER_SERVICE: Invalid service UUID: %04x", service_uuid); 15920cc6429eSMatthias Ringwald return BNEP_SERVICE_ALREADY_REGISTERED; // TODO: define own error 15933deb3ec6SMatthias Ringwald } 15943deb3ec6SMatthias Ringwald 15953deb3ec6SMatthias Ringwald /* Allocate service memory */ 15963deb3ec6SMatthias Ringwald service = (bnep_service_t*) btstack_memory_bnep_service_get(); 15973deb3ec6SMatthias Ringwald if (!service) { 15980cc6429eSMatthias Ringwald return BTSTACK_MEMORY_ALLOC_FAILED; 15993deb3ec6SMatthias Ringwald } 16003deb3ec6SMatthias Ringwald memset(service, 0, sizeof(bnep_service_t)); 16013deb3ec6SMatthias Ringwald 16023deb3ec6SMatthias Ringwald /* register with l2cap if not registered before, max MTU */ 1603be2053a6SMatthias Ringwald l2cap_register_service(bnep_packet_handler, PSM_BNEP, 0xffff, bnep_security_level); 16043deb3ec6SMatthias Ringwald 16053deb3ec6SMatthias Ringwald /* Setup the service struct */ 16063deb3ec6SMatthias Ringwald service->max_frame_size = max_frame_size; 16073deb3ec6SMatthias Ringwald service->service_uuid = service_uuid; 16083deb3ec6SMatthias Ringwald 16093deb3ec6SMatthias Ringwald /* Add to services list */ 1610665d90f2SMatthias Ringwald btstack_linked_list_add(&bnep_services, (btstack_linked_item_t *) service); 16113deb3ec6SMatthias Ringwald 16120cc6429eSMatthias Ringwald return 0; 16133deb3ec6SMatthias Ringwald } 16143deb3ec6SMatthias Ringwald 16153deb3ec6SMatthias Ringwald void bnep_unregister_service(uint16_t service_uuid) 16163deb3ec6SMatthias Ringwald { 16173deb3ec6SMatthias Ringwald log_info("BNEP_UNREGISTER_SERVICE #%04x", service_uuid); 16183deb3ec6SMatthias Ringwald 16193deb3ec6SMatthias Ringwald bnep_service_t *service = bnep_service_for_uuid(service_uuid); 16203deb3ec6SMatthias Ringwald if (!service) { 16213deb3ec6SMatthias Ringwald return; 16223deb3ec6SMatthias Ringwald } 16233deb3ec6SMatthias Ringwald 1624665d90f2SMatthias Ringwald btstack_linked_list_remove(&bnep_services, (btstack_linked_item_t *) service); 16253deb3ec6SMatthias Ringwald btstack_memory_bnep_service_free(service); 16263deb3ec6SMatthias Ringwald service = NULL; 16273deb3ec6SMatthias Ringwald 162802f83142SMatthias Ringwald l2cap_unregister_service(PSM_BNEP); 16293deb3ec6SMatthias Ringwald } 16303deb3ec6SMatthias Ringwald 1631