xref: /btstack/src/classic/bnep.c (revision 0e2df43f5cbae3fc71139523458b98f30307d21b)
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 
49*0e2df43fSMatthias Ringwald #include "bnep.h"
50*0e2df43fSMatthias Ringwald #include "btstack_debug.h"
51*0e2df43fSMatthias Ringwald #include "btstack_event.h"
52*0e2df43fSMatthias Ringwald #include "btstack_memory.h"
53eb886013SMatthias Ringwald #include "btstack_util.h"
543edc84c5SMatthias Ringwald #include "classic/sdp_util.h"
553deb3ec6SMatthias Ringwald #include "hci.h"
56*0e2df43fSMatthias Ringwald #include "hci_cmd.h"
573deb3ec6SMatthias Ringwald #include "hci_dump.h"
583deb3ec6SMatthias Ringwald #include "l2cap.h"
593deb3ec6SMatthias Ringwald 
603deb3ec6SMatthias Ringwald #define BNEP_CONNECTION_TIMEOUT_MS 10000
613deb3ec6SMatthias Ringwald #define BNEP_CONNECTION_MAX_RETRIES 1
623deb3ec6SMatthias Ringwald 
638f2a52f4SMatthias Ringwald static btstack_linked_list_t bnep_services = NULL;
648f2a52f4SMatthias Ringwald static btstack_linked_list_t bnep_channels = NULL;
653deb3ec6SMatthias Ringwald 
663deb3ec6SMatthias Ringwald static gap_security_level_t bnep_security_level;
673deb3ec6SMatthias Ringwald 
680cc6429eSMatthias Ringwald static void (*app_packet_handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
693deb3ec6SMatthias Ringwald 
703deb3ec6SMatthias Ringwald 
713deb3ec6SMatthias Ringwald static bnep_channel_t * bnep_channel_for_l2cap_cid(uint16_t l2cap_cid);
723deb3ec6SMatthias Ringwald static void bnep_channel_finalize(bnep_channel_t *channel);
733deb3ec6SMatthias Ringwald static void bnep_run(void);
743deb3ec6SMatthias Ringwald static void bnep_channel_start_timer(bnep_channel_t *channel, int timeout);
753deb3ec6SMatthias Ringwald inline static void bnep_channel_state_add(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event);
763deb3ec6SMatthias Ringwald 
773deb3ec6SMatthias Ringwald static void bnep_emit_open_channel_complete(bnep_channel_t *channel, uint8_t status)
783deb3ec6SMatthias Ringwald {
793deb3ec6SMatthias Ringwald     log_info("BNEP_EVENT_OPEN_CHANNEL_COMPLETE status 0x%02x bd_addr: %s", status, bd_addr_to_str(channel->remote_addr));
803deb3ec6SMatthias Ringwald     uint8_t event[3 + sizeof(bd_addr_t) + 3 * sizeof(uint16_t)];
813deb3ec6SMatthias Ringwald     event[0] = BNEP_EVENT_OPEN_CHANNEL_COMPLETE;
823deb3ec6SMatthias Ringwald     event[1] = sizeof(event) - 2;
833deb3ec6SMatthias Ringwald     event[2] = status;
84f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 3, channel->uuid_source);
85f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 5, channel->uuid_dest);
86f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 7, channel->max_frame_size);
87058e3d6bSMatthias Ringwald     bd_addr_copy(&event[9], channel->remote_addr);
883deb3ec6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
890cc6429eSMatthias Ringwald 	(*app_packet_handler)(HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event));
903deb3ec6SMatthias Ringwald }
913deb3ec6SMatthias Ringwald 
923deb3ec6SMatthias Ringwald static void bnep_emit_channel_timeout(bnep_channel_t *channel)
933deb3ec6SMatthias Ringwald {
943deb3ec6SMatthias Ringwald     log_info("BNEP_EVENT_CHANNEL_TIMEOUT bd_addr: %s", bd_addr_to_str(channel->remote_addr));
953deb3ec6SMatthias Ringwald     uint8_t event[2 + sizeof(bd_addr_t) + 2 * sizeof(uint16_t) + sizeof(uint8_t)];
963deb3ec6SMatthias Ringwald     event[0] = BNEP_EVENT_CHANNEL_TIMEOUT;
973deb3ec6SMatthias Ringwald     event[1] = sizeof(event) - 2;
98f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 2, channel->uuid_source);
99f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 4, channel->uuid_dest);
100058e3d6bSMatthias Ringwald     bd_addr_copy(&event[6], channel->remote_addr);
1013deb3ec6SMatthias Ringwald     event[12] = channel->state;
1023deb3ec6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
1030cc6429eSMatthias Ringwald 	(*app_packet_handler)(HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event));
1043deb3ec6SMatthias Ringwald }
1053deb3ec6SMatthias Ringwald 
1063deb3ec6SMatthias Ringwald static void bnep_emit_channel_closed(bnep_channel_t *channel)
1073deb3ec6SMatthias Ringwald {
1083deb3ec6SMatthias Ringwald     log_info("BNEP_EVENT_CHANNEL_CLOSED bd_addr: %s", bd_addr_to_str(channel->remote_addr));
1093deb3ec6SMatthias Ringwald     uint8_t event[2 + sizeof(bd_addr_t) + 2 * sizeof(uint16_t)];
1103deb3ec6SMatthias Ringwald     event[0] = BNEP_EVENT_CHANNEL_CLOSED;
1113deb3ec6SMatthias Ringwald     event[1] = sizeof(event) - 2;
112f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 2, channel->uuid_source);
113f8fbdce0SMatthias Ringwald     little_endian_store_16(event, 4, channel->uuid_dest);
114058e3d6bSMatthias Ringwald     bd_addr_copy(&event[6], channel->remote_addr);
1153deb3ec6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
1160cc6429eSMatthias Ringwald 	(*app_packet_handler)(HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event));
1173deb3ec6SMatthias Ringwald }
1183deb3ec6SMatthias Ringwald 
1193deb3ec6SMatthias Ringwald static void bnep_emit_ready_to_send(bnep_channel_t *channel)
1203deb3ec6SMatthias Ringwald {
1213deb3ec6SMatthias Ringwald     uint8_t event[2];
1223deb3ec6SMatthias Ringwald     event[0] = BNEP_EVENT_READY_TO_SEND;
1233deb3ec6SMatthias Ringwald     event[1] = sizeof(event) - 2;
1243deb3ec6SMatthias Ringwald     hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
1250cc6429eSMatthias Ringwald 	(*app_packet_handler)(HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event));
1263deb3ec6SMatthias Ringwald }
1273deb3ec6SMatthias Ringwald 
1283deb3ec6SMatthias Ringwald /* Send BNEP connection request */
1293deb3ec6SMatthias Ringwald static int bnep_send_command_not_understood(bnep_channel_t *channel, uint8_t control_type)
1303deb3ec6SMatthias Ringwald {
1313deb3ec6SMatthias Ringwald     uint8_t *bnep_out_buffer = NULL;
1323deb3ec6SMatthias Ringwald     uint16_t pos = 0;
1333deb3ec6SMatthias Ringwald     int      err = 0;
1343deb3ec6SMatthias Ringwald 
1353deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
1363deb3ec6SMatthias Ringwald         return -1; // TODO
1373deb3ec6SMatthias Ringwald     }
1383deb3ec6SMatthias Ringwald 
1393deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
1403deb3ec6SMatthias Ringwald     bnep_out_buffer = l2cap_get_outgoing_buffer();
1413deb3ec6SMatthias Ringwald 
1423deb3ec6SMatthias Ringwald     /* Setup control packet type */
1433deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
1443deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_COMMAND_NOT_UNDERSTOOD;
1453deb3ec6SMatthias Ringwald 
1463deb3ec6SMatthias Ringwald     /* Add not understood control type */
1473deb3ec6SMatthias Ringwald     bnep_out_buffer[pos++] = control_type;
1483deb3ec6SMatthias Ringwald 
1493deb3ec6SMatthias Ringwald     err = l2cap_send_prepared(channel->l2cap_cid, pos);
1503deb3ec6SMatthias Ringwald 
1513deb3ec6SMatthias Ringwald     if (err) {
1523deb3ec6SMatthias Ringwald         // TODO: Log error
1533deb3ec6SMatthias Ringwald     }
1543deb3ec6SMatthias Ringwald     return err;
1553deb3ec6SMatthias Ringwald }
1563deb3ec6SMatthias Ringwald 
1573deb3ec6SMatthias Ringwald 
1583deb3ec6SMatthias Ringwald /* Send BNEP connection request */
1593deb3ec6SMatthias Ringwald static int bnep_send_connection_request(bnep_channel_t *channel, uint16_t uuid_source, uint16_t uuid_dest)
1603deb3ec6SMatthias Ringwald {
1613deb3ec6SMatthias Ringwald     uint8_t *bnep_out_buffer = NULL;
1623deb3ec6SMatthias Ringwald     uint16_t pos = 0;
1633deb3ec6SMatthias Ringwald     int      err = 0;
1643deb3ec6SMatthias Ringwald 
1653deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
1663deb3ec6SMatthias Ringwald         return -1; // TODO
1673deb3ec6SMatthias Ringwald     }
1683deb3ec6SMatthias Ringwald 
1693deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
1703deb3ec6SMatthias Ringwald     bnep_out_buffer = l2cap_get_outgoing_buffer();
1713deb3ec6SMatthias Ringwald 
1723deb3ec6SMatthias Ringwald     /* Setup control packet type */
1733deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
1743deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_SETUP_CONNECTION_REQUEST;
1753deb3ec6SMatthias Ringwald 
1763deb3ec6SMatthias Ringwald     /* Add UUID Size */
1773deb3ec6SMatthias Ringwald     bnep_out_buffer[pos++] = 2;
1783deb3ec6SMatthias Ringwald 
1793deb3ec6SMatthias Ringwald     /* Add dest and source UUID */
180f8fbdce0SMatthias Ringwald     big_endian_store_16(bnep_out_buffer, pos, uuid_dest);
1813deb3ec6SMatthias Ringwald     pos += 2;
1823deb3ec6SMatthias Ringwald 
183f8fbdce0SMatthias Ringwald     big_endian_store_16(bnep_out_buffer, pos, uuid_source);
1843deb3ec6SMatthias Ringwald     pos += 2;
1853deb3ec6SMatthias Ringwald 
1863deb3ec6SMatthias Ringwald     err = l2cap_send_prepared(channel->l2cap_cid, pos);
1873deb3ec6SMatthias Ringwald 
1883deb3ec6SMatthias Ringwald     if (err) {
1893deb3ec6SMatthias Ringwald         // TODO: Log error
1903deb3ec6SMatthias Ringwald     }
1913deb3ec6SMatthias Ringwald     return err;
1923deb3ec6SMatthias Ringwald }
1933deb3ec6SMatthias Ringwald 
1943deb3ec6SMatthias Ringwald /* Send BNEP connection response */
1953deb3ec6SMatthias Ringwald static int bnep_send_connection_response(bnep_channel_t *channel, uint16_t response_code)
1963deb3ec6SMatthias Ringwald {
1973deb3ec6SMatthias Ringwald     uint8_t *bnep_out_buffer = NULL;
1983deb3ec6SMatthias Ringwald     uint16_t pos = 0;
1993deb3ec6SMatthias Ringwald     int      err = 0;
2003deb3ec6SMatthias Ringwald 
2013deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
2023deb3ec6SMatthias Ringwald         return -1; // TODO
2033deb3ec6SMatthias Ringwald     }
2043deb3ec6SMatthias Ringwald 
2053deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
2063deb3ec6SMatthias Ringwald     bnep_out_buffer = l2cap_get_outgoing_buffer();
2073deb3ec6SMatthias Ringwald 
2083deb3ec6SMatthias Ringwald     /* Setup control packet type */
2093deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
2103deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_SETUP_CONNECTION_RESPONSE;
2113deb3ec6SMatthias Ringwald 
2123deb3ec6SMatthias Ringwald     /* Add response code */
213f8fbdce0SMatthias Ringwald     big_endian_store_16(bnep_out_buffer, pos, response_code);
2143deb3ec6SMatthias Ringwald     pos += 2;
2153deb3ec6SMatthias Ringwald 
2163deb3ec6SMatthias Ringwald     err = l2cap_send_prepared(channel->l2cap_cid, pos);
2173deb3ec6SMatthias Ringwald 
2183deb3ec6SMatthias Ringwald     if (err) {
2193deb3ec6SMatthias Ringwald         // TODO: Log error
2203deb3ec6SMatthias Ringwald     }
2213deb3ec6SMatthias Ringwald     return err;
2223deb3ec6SMatthias Ringwald }
2233deb3ec6SMatthias Ringwald 
2243deb3ec6SMatthias Ringwald /* Send BNEP filter net type set message */
2253deb3ec6SMatthias Ringwald static int bnep_send_filter_net_type_set(bnep_channel_t *channel, bnep_net_filter_t *filter, uint16_t len)
2263deb3ec6SMatthias Ringwald {
2273deb3ec6SMatthias Ringwald     uint8_t *bnep_out_buffer = NULL;
2283deb3ec6SMatthias Ringwald     uint16_t pos = 0;
2293deb3ec6SMatthias Ringwald     int      err = 0;
2303deb3ec6SMatthias Ringwald     int      i;
2313deb3ec6SMatthias Ringwald 
2323deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
2333deb3ec6SMatthias Ringwald         return -1;
2343deb3ec6SMatthias Ringwald     }
2353deb3ec6SMatthias Ringwald 
2363deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
2373deb3ec6SMatthias Ringwald     bnep_out_buffer = l2cap_get_outgoing_buffer();
2383deb3ec6SMatthias Ringwald 
2393deb3ec6SMatthias Ringwald     /* Setup control packet type */
2403deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
2413deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_NET_TYPE_SET;
2423deb3ec6SMatthias Ringwald 
243f8fbdce0SMatthias Ringwald     big_endian_store_16(bnep_out_buffer, pos, len * 2 * 2);
2443deb3ec6SMatthias Ringwald     pos += 2;
2453deb3ec6SMatthias Ringwald 
2463deb3ec6SMatthias Ringwald     for (i = 0; i < len; i ++) {
247f8fbdce0SMatthias Ringwald         big_endian_store_16(bnep_out_buffer, pos, filter[i].range_start);
2483deb3ec6SMatthias Ringwald         pos += 2;
249f8fbdce0SMatthias Ringwald         big_endian_store_16(bnep_out_buffer, pos, filter[i].range_end);
2503deb3ec6SMatthias Ringwald         pos += 2;
2513deb3ec6SMatthias Ringwald     }
2523deb3ec6SMatthias Ringwald 
2533deb3ec6SMatthias Ringwald     err = l2cap_send_prepared(channel->l2cap_cid, pos);
2543deb3ec6SMatthias Ringwald 
2553deb3ec6SMatthias Ringwald     if (err) {
2563deb3ec6SMatthias Ringwald         // TODO: Log error
2573deb3ec6SMatthias Ringwald     }
2583deb3ec6SMatthias Ringwald     return err;
2593deb3ec6SMatthias Ringwald }
2603deb3ec6SMatthias Ringwald 
2613deb3ec6SMatthias Ringwald /* Send BNEP filter net type response message */
2623deb3ec6SMatthias Ringwald static int bnep_send_filter_net_type_response(bnep_channel_t *channel, uint16_t response_code)
2633deb3ec6SMatthias Ringwald {
2643deb3ec6SMatthias Ringwald     uint8_t *bnep_out_buffer = NULL;
2653deb3ec6SMatthias Ringwald     uint16_t pos = 0;
2663deb3ec6SMatthias Ringwald     int      err = 0;
2673deb3ec6SMatthias Ringwald 
2683deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
2693deb3ec6SMatthias Ringwald         return -1;
2703deb3ec6SMatthias Ringwald     }
2713deb3ec6SMatthias Ringwald 
2723deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
2733deb3ec6SMatthias Ringwald     bnep_out_buffer = l2cap_get_outgoing_buffer();
2743deb3ec6SMatthias Ringwald 
2753deb3ec6SMatthias Ringwald     /* Setup control packet type */
2763deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
2773deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_NET_TYPE_RESPONSE;
2783deb3ec6SMatthias Ringwald 
2793deb3ec6SMatthias Ringwald     /* Add response code */
280f8fbdce0SMatthias Ringwald     big_endian_store_16(bnep_out_buffer, pos, response_code);
2813deb3ec6SMatthias Ringwald     pos += 2;
2823deb3ec6SMatthias Ringwald 
2833deb3ec6SMatthias Ringwald     err = l2cap_send_prepared(channel->l2cap_cid, pos);
2843deb3ec6SMatthias Ringwald 
2853deb3ec6SMatthias Ringwald     if (err) {
2863deb3ec6SMatthias Ringwald         // TODO: Log error
2873deb3ec6SMatthias Ringwald     }
2883deb3ec6SMatthias Ringwald     return err;
2893deb3ec6SMatthias Ringwald }
2903deb3ec6SMatthias Ringwald 
2913deb3ec6SMatthias Ringwald /* Send BNEP filter multicast address set message */
2923deb3ec6SMatthias Ringwald 
2933deb3ec6SMatthias Ringwald static int bnep_send_filter_multi_addr_set(bnep_channel_t *channel, bnep_multi_filter_t *filter, uint16_t len)
2943deb3ec6SMatthias Ringwald {
2953deb3ec6SMatthias Ringwald     uint8_t *bnep_out_buffer = NULL;
2963deb3ec6SMatthias Ringwald     uint16_t pos = 0;
2973deb3ec6SMatthias Ringwald     int      err = 0;
2983deb3ec6SMatthias Ringwald     int      i;
2993deb3ec6SMatthias Ringwald 
3003deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
3013deb3ec6SMatthias Ringwald         return -1;
3023deb3ec6SMatthias Ringwald     }
3033deb3ec6SMatthias Ringwald 
3043deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
3053deb3ec6SMatthias Ringwald     bnep_out_buffer = l2cap_get_outgoing_buffer();
3063deb3ec6SMatthias Ringwald 
3073deb3ec6SMatthias Ringwald     /* Setup control packet type */
3083deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
3093deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_SET;
3103deb3ec6SMatthias Ringwald 
311f8fbdce0SMatthias Ringwald     big_endian_store_16(bnep_out_buffer, pos, len * 2 * ETHER_ADDR_LEN);
3123deb3ec6SMatthias Ringwald     pos += 2;
3133deb3ec6SMatthias Ringwald 
3143deb3ec6SMatthias Ringwald     for (i = 0; i < len; i ++) {
315058e3d6bSMatthias Ringwald         bd_addr_copy(bnep_out_buffer + pos, filter[i].addr_start);
3163deb3ec6SMatthias Ringwald         pos += ETHER_ADDR_LEN;
317058e3d6bSMatthias Ringwald         bd_addr_copy(bnep_out_buffer + pos, filter[i].addr_end);
3183deb3ec6SMatthias Ringwald         pos += ETHER_ADDR_LEN;
3193deb3ec6SMatthias Ringwald     }
3203deb3ec6SMatthias Ringwald 
3213deb3ec6SMatthias Ringwald     err = l2cap_send_prepared(channel->l2cap_cid, pos);
3223deb3ec6SMatthias Ringwald 
3233deb3ec6SMatthias Ringwald     if (err) {
3243deb3ec6SMatthias Ringwald         // TODO: Log error
3253deb3ec6SMatthias Ringwald     }
3263deb3ec6SMatthias Ringwald     return err;
3273deb3ec6SMatthias Ringwald }
3283deb3ec6SMatthias Ringwald 
3293deb3ec6SMatthias Ringwald /* Send BNEP filter multicast address response message */
3303deb3ec6SMatthias Ringwald static int bnep_send_filter_multi_addr_response(bnep_channel_t *channel, uint16_t response_code)
3313deb3ec6SMatthias Ringwald {
3323deb3ec6SMatthias Ringwald     uint8_t *bnep_out_buffer = NULL;
3333deb3ec6SMatthias Ringwald     uint16_t pos = 0;
3343deb3ec6SMatthias Ringwald     int      err = 0;
3353deb3ec6SMatthias Ringwald 
3363deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
3373deb3ec6SMatthias Ringwald         return -1;
3383deb3ec6SMatthias Ringwald     }
3393deb3ec6SMatthias Ringwald 
3403deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
3413deb3ec6SMatthias Ringwald     bnep_out_buffer = l2cap_get_outgoing_buffer();
3423deb3ec6SMatthias Ringwald 
3433deb3ec6SMatthias Ringwald     /* Setup control packet type */
3443deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
3453deb3ec6SMatthias Ringwald 	bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_RESPONSE;
3463deb3ec6SMatthias Ringwald 
3473deb3ec6SMatthias Ringwald     /* Add response code */
348f8fbdce0SMatthias Ringwald     big_endian_store_16(bnep_out_buffer, pos, response_code);
3493deb3ec6SMatthias Ringwald     pos += 2;
3503deb3ec6SMatthias Ringwald 
3513deb3ec6SMatthias Ringwald     err = l2cap_send_prepared(channel->l2cap_cid, pos);
3523deb3ec6SMatthias Ringwald 
3533deb3ec6SMatthias Ringwald     if (err) {
3543deb3ec6SMatthias Ringwald         // TODO: Log error
3553deb3ec6SMatthias Ringwald     }
3563deb3ec6SMatthias Ringwald     return err;
3573deb3ec6SMatthias Ringwald }
3583deb3ec6SMatthias Ringwald 
3593deb3ec6SMatthias Ringwald int bnep_can_send_packet_now(uint16_t bnep_cid)
3603deb3ec6SMatthias Ringwald {
3613deb3ec6SMatthias Ringwald     bnep_channel_t *channel = bnep_channel_for_l2cap_cid(bnep_cid);
3623deb3ec6SMatthias Ringwald 
3633deb3ec6SMatthias Ringwald     if (!channel){
3643deb3ec6SMatthias Ringwald         log_error("bnep_can_send_packet_now cid 0x%02x doesn't exist!", bnep_cid);
3653deb3ec6SMatthias Ringwald         return 0;
3663deb3ec6SMatthias Ringwald     }
3673deb3ec6SMatthias Ringwald 
3683deb3ec6SMatthias Ringwald     return l2cap_can_send_packet_now(channel->l2cap_cid);
3693deb3ec6SMatthias Ringwald }
3703deb3ec6SMatthias Ringwald 
3713deb3ec6SMatthias Ringwald 
3723deb3ec6SMatthias Ringwald static int bnep_filter_protocol(bnep_channel_t *channel, uint16_t network_protocol_type)
3733deb3ec6SMatthias Ringwald {
3743deb3ec6SMatthias Ringwald 	int i;
3753deb3ec6SMatthias Ringwald 
3763deb3ec6SMatthias Ringwald     if (channel->net_filter_count == 0) {
3773deb3ec6SMatthias Ringwald         /* No filter set */
3783deb3ec6SMatthias Ringwald         return 1;
3793deb3ec6SMatthias Ringwald     }
3803deb3ec6SMatthias Ringwald 
3813deb3ec6SMatthias Ringwald     for (i = 0; i < channel->net_filter_count; i ++) {
3823deb3ec6SMatthias Ringwald         if ((network_protocol_type >= channel->net_filter[i].range_start) &&
3833deb3ec6SMatthias Ringwald             (network_protocol_type <= channel->net_filter[i].range_end)) {
3843deb3ec6SMatthias Ringwald             return 1;
3853deb3ec6SMatthias Ringwald         }
3863deb3ec6SMatthias Ringwald     }
3873deb3ec6SMatthias Ringwald 
3883deb3ec6SMatthias Ringwald     return 0;
3893deb3ec6SMatthias Ringwald }
3903deb3ec6SMatthias Ringwald 
3913deb3ec6SMatthias Ringwald static int bnep_filter_multicast(bnep_channel_t *channel, bd_addr_t addr_dest)
3923deb3ec6SMatthias Ringwald {
3933deb3ec6SMatthias Ringwald 	int i;
3943deb3ec6SMatthias Ringwald 
3953deb3ec6SMatthias Ringwald     /* Check if the multicast flag is set int the destination address */
3963deb3ec6SMatthias Ringwald 	if ((addr_dest[0] & 0x01) == 0x00) {
3973deb3ec6SMatthias Ringwald         /* Not a multicast frame, do not apply filtering and send it in any case */
3983deb3ec6SMatthias Ringwald 		return 1;
3993deb3ec6SMatthias Ringwald     }
4003deb3ec6SMatthias Ringwald 
4013deb3ec6SMatthias Ringwald     if (channel->multicast_filter_count == 0) {
4023deb3ec6SMatthias Ringwald         /* No filter set */
4033deb3ec6SMatthias Ringwald         return 1;
4043deb3ec6SMatthias Ringwald     }
4053deb3ec6SMatthias Ringwald 
4063deb3ec6SMatthias Ringwald 	for (i = 0; i < channel->multicast_filter_count; i ++) {
4073deb3ec6SMatthias Ringwald 		if ((memcmp(addr_dest, channel->multicast_filter[i].addr_start, sizeof(bd_addr_t)) >= 0) &&
4083deb3ec6SMatthias Ringwald 		    (memcmp(addr_dest, channel->multicast_filter[i].addr_end, sizeof(bd_addr_t)) <= 0)) {
4093deb3ec6SMatthias Ringwald 			return 1;
4103deb3ec6SMatthias Ringwald         }
4113deb3ec6SMatthias Ringwald 	}
4123deb3ec6SMatthias Ringwald 
4133deb3ec6SMatthias Ringwald 	return 0;
4143deb3ec6SMatthias Ringwald }
4153deb3ec6SMatthias Ringwald 
4163deb3ec6SMatthias Ringwald 
4173deb3ec6SMatthias Ringwald /* Send BNEP ethernet packet */
4183deb3ec6SMatthias Ringwald int bnep_send(uint16_t bnep_cid, uint8_t *packet, uint16_t len)
4193deb3ec6SMatthias Ringwald {
4203deb3ec6SMatthias Ringwald     bnep_channel_t *channel;
4213deb3ec6SMatthias Ringwald     uint8_t        *bnep_out_buffer = NULL;
4223deb3ec6SMatthias Ringwald     uint16_t        pos = 0;
4233deb3ec6SMatthias Ringwald     uint16_t        pos_out = 0;
4243deb3ec6SMatthias Ringwald     uint16_t        payload_len;
4253deb3ec6SMatthias Ringwald     int             err = 0;
4263deb3ec6SMatthias Ringwald     int             has_source;
4273deb3ec6SMatthias Ringwald     int             has_dest;
4283deb3ec6SMatthias Ringwald 
4293deb3ec6SMatthias Ringwald     bd_addr_t       addr_dest;
4303deb3ec6SMatthias Ringwald     bd_addr_t       addr_source;
4313deb3ec6SMatthias Ringwald     uint16_t        network_protocol_type;
4323deb3ec6SMatthias Ringwald 
4333deb3ec6SMatthias Ringwald     channel = bnep_channel_for_l2cap_cid(bnep_cid);
4343deb3ec6SMatthias Ringwald     if (channel == NULL) {
4353deb3ec6SMatthias Ringwald         log_error("bnep_send cid 0x%02x doesn't exist!", bnep_cid);
4363deb3ec6SMatthias Ringwald         return 1;
4373deb3ec6SMatthias Ringwald     }
4383deb3ec6SMatthias Ringwald 
4393deb3ec6SMatthias Ringwald     if (channel->state != BNEP_CHANNEL_STATE_CONNECTED) {
4403deb3ec6SMatthias Ringwald         return BNEP_CHANNEL_NOT_CONNECTED;
4413deb3ec6SMatthias Ringwald     }
4423deb3ec6SMatthias Ringwald 
4433deb3ec6SMatthias Ringwald     /* Check for free ACL buffers */
4443deb3ec6SMatthias Ringwald     if (!l2cap_can_send_packet_now(channel->l2cap_cid)) {
4453deb3ec6SMatthias Ringwald         return BTSTACK_ACL_BUFFERS_FULL;
4463deb3ec6SMatthias Ringwald     }
4473deb3ec6SMatthias Ringwald 
4483deb3ec6SMatthias Ringwald     /* Extract destination and source address from the ethernet packet */
4493deb3ec6SMatthias Ringwald     pos = 0;
450058e3d6bSMatthias Ringwald     bd_addr_copy(addr_dest, &packet[pos]);
4513deb3ec6SMatthias Ringwald     pos += sizeof(bd_addr_t);
452058e3d6bSMatthias Ringwald     bd_addr_copy(addr_source, &packet[pos]);
4533deb3ec6SMatthias Ringwald     pos += sizeof(bd_addr_t);
454f8fbdce0SMatthias Ringwald     network_protocol_type = big_endian_read_16(packet, pos);
4553deb3ec6SMatthias Ringwald     pos += sizeof(uint16_t);
4563deb3ec6SMatthias Ringwald 
4573deb3ec6SMatthias Ringwald     payload_len = len - pos;
4583deb3ec6SMatthias Ringwald 
4593deb3ec6SMatthias Ringwald 	if (network_protocol_type == ETHERTYPE_VLAN) {	/* IEEE 802.1Q tag header */
4603deb3ec6SMatthias Ringwald 		if (payload_len < 4) {
4613deb3ec6SMatthias Ringwald             /* Omit this packet */
4623deb3ec6SMatthias Ringwald 			return 0;
4633deb3ec6SMatthias Ringwald         }
4643deb3ec6SMatthias Ringwald         /* The "real" network protocol type is 4 bytes ahead in a VLAN packet */
465f8fbdce0SMatthias Ringwald 		network_protocol_type = big_endian_read_16(packet, pos + 2);
4663deb3ec6SMatthias Ringwald 	}
4673deb3ec6SMatthias Ringwald 
4683deb3ec6SMatthias Ringwald     /* Check network protocol and multicast filters before sending */
4693deb3ec6SMatthias Ringwald     if (!bnep_filter_protocol(channel, network_protocol_type) ||
4703deb3ec6SMatthias Ringwald         !bnep_filter_multicast(channel, addr_dest)) {
4713deb3ec6SMatthias Ringwald         /* Packet did not pass filter... */
4723deb3ec6SMatthias Ringwald         if ((network_protocol_type == ETHERTYPE_VLAN) &&
4733deb3ec6SMatthias Ringwald             (payload_len >= 4)) {
4743deb3ec6SMatthias Ringwald             /* The packet has been tagged as a with IEE 802.1Q tag and has been filtered out.
4753deb3ec6SMatthias Ringwald                According to the spec the IEE802.1Q tag header shall be sended without ethernet payload.
4763deb3ec6SMatthias Ringwald                So limit the payload_len to 4.
4773deb3ec6SMatthias Ringwald              */
4783deb3ec6SMatthias Ringwald             payload_len = 4;
4793deb3ec6SMatthias Ringwald         } else {
4803deb3ec6SMatthias Ringwald             /* Packet is not tagged with IEE802.1Q header and was filtered out. Omit this packet */
4813deb3ec6SMatthias Ringwald             return 0;
4823deb3ec6SMatthias Ringwald         }
4833deb3ec6SMatthias Ringwald     }
4843deb3ec6SMatthias Ringwald 
4853deb3ec6SMatthias Ringwald     /* Reserve l2cap packet buffer */
4863deb3ec6SMatthias Ringwald     l2cap_reserve_packet_buffer();
4873deb3ec6SMatthias Ringwald     bnep_out_buffer = l2cap_get_outgoing_buffer();
4883deb3ec6SMatthias Ringwald 
4893deb3ec6SMatthias Ringwald     /* Check if source address is the same as our local address and if the
4903deb3ec6SMatthias Ringwald        destination address is the same as the remote addr. Maybe we can use
4913deb3ec6SMatthias Ringwald        the compressed data format
4923deb3ec6SMatthias Ringwald      */
4933deb3ec6SMatthias Ringwald     has_source = (memcmp(addr_source, channel->local_addr, ETHER_ADDR_LEN) != 0);
4943deb3ec6SMatthias Ringwald     has_dest = (memcmp(addr_dest, channel->remote_addr, ETHER_ADDR_LEN) != 0);
4953deb3ec6SMatthias Ringwald 
4963deb3ec6SMatthias Ringwald     /* Check for MTU limits */
4973deb3ec6SMatthias Ringwald     if (payload_len > channel->max_frame_size) {
4983deb3ec6SMatthias Ringwald         log_error("bnep_send: Max frame size (%d) exceeded: %d", channel->max_frame_size, payload_len);
4993deb3ec6SMatthias Ringwald         return BNEP_DATA_LEN_EXCEEDS_MTU;
5003deb3ec6SMatthias Ringwald     }
5013deb3ec6SMatthias Ringwald 
5023deb3ec6SMatthias Ringwald     /* Fill in the package type depending on the given source and destination address */
5033deb3ec6SMatthias Ringwald     if (has_source && has_dest) {
5043deb3ec6SMatthias Ringwald         bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_GENERAL_ETHERNET;
5053deb3ec6SMatthias Ringwald     } else
5063deb3ec6SMatthias Ringwald     if (has_source && !has_dest) {
5073deb3ec6SMatthias Ringwald         bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_COMPRESSED_ETHERNET_SOURCE_ONLY;
5083deb3ec6SMatthias Ringwald     } else
5093deb3ec6SMatthias Ringwald     if (!has_source && has_dest) {
5103deb3ec6SMatthias Ringwald         bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_COMPRESSED_ETHERNET_DEST_ONLY;
5113deb3ec6SMatthias Ringwald     } else {
5123deb3ec6SMatthias Ringwald         bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_COMPRESSED_ETHERNET;
5133deb3ec6SMatthias Ringwald     }
5143deb3ec6SMatthias Ringwald 
5153deb3ec6SMatthias Ringwald     /* Add the destination address if needed */
5163deb3ec6SMatthias Ringwald     if (has_dest) {
517058e3d6bSMatthias Ringwald         bd_addr_copy(bnep_out_buffer + pos_out, addr_dest);
5183deb3ec6SMatthias Ringwald         pos_out += sizeof(bd_addr_t);
5193deb3ec6SMatthias Ringwald     }
5203deb3ec6SMatthias Ringwald 
5213deb3ec6SMatthias Ringwald     /* Add the source address if needed */
5223deb3ec6SMatthias Ringwald     if (has_source) {
523058e3d6bSMatthias Ringwald         bd_addr_copy(bnep_out_buffer + pos_out, addr_source);
5243deb3ec6SMatthias Ringwald         pos_out += sizeof(bd_addr_t);
5253deb3ec6SMatthias Ringwald     }
5263deb3ec6SMatthias Ringwald 
5273deb3ec6SMatthias Ringwald     /* Add protocol type */
528f8fbdce0SMatthias Ringwald     big_endian_store_16(bnep_out_buffer, pos_out, network_protocol_type);
5293deb3ec6SMatthias Ringwald     pos_out += 2;
5303deb3ec6SMatthias Ringwald 
5313deb3ec6SMatthias Ringwald     /* TODO: Add extension headers, if we may support them at a later stage */
5323deb3ec6SMatthias Ringwald     /* Add the payload and then send out the package */
5333deb3ec6SMatthias Ringwald     memcpy(bnep_out_buffer + pos_out, packet + pos, payload_len);
5343deb3ec6SMatthias Ringwald     pos_out += payload_len;
5353deb3ec6SMatthias Ringwald 
5363deb3ec6SMatthias Ringwald     err = l2cap_send_prepared(channel->l2cap_cid, pos_out);
5373deb3ec6SMatthias Ringwald 
5383deb3ec6SMatthias Ringwald     if (err) {
5393deb3ec6SMatthias Ringwald         log_error("bnep_send: error %d", err);
5403deb3ec6SMatthias Ringwald     }
5413deb3ec6SMatthias Ringwald     return err;
5423deb3ec6SMatthias Ringwald }
5433deb3ec6SMatthias Ringwald 
5443deb3ec6SMatthias Ringwald 
5453deb3ec6SMatthias Ringwald /* Set BNEP network protocol type filter */
5463deb3ec6SMatthias Ringwald int bnep_set_net_type_filter(uint16_t bnep_cid, bnep_net_filter_t *filter, uint16_t len)
5473deb3ec6SMatthias Ringwald {
5483deb3ec6SMatthias Ringwald     bnep_channel_t *channel;
5493deb3ec6SMatthias Ringwald 
5503deb3ec6SMatthias Ringwald     if (filter == NULL) {
5513deb3ec6SMatthias Ringwald         return -1;
5523deb3ec6SMatthias Ringwald     }
5533deb3ec6SMatthias Ringwald 
5543deb3ec6SMatthias Ringwald     channel = bnep_channel_for_l2cap_cid(bnep_cid);
5553deb3ec6SMatthias Ringwald     if (channel == NULL) {
5563deb3ec6SMatthias Ringwald         log_error("bnep_set_net_type_filter cid 0x%02x doesn't exist!", bnep_cid);
5573deb3ec6SMatthias Ringwald         return 1;
5583deb3ec6SMatthias Ringwald     }
5593deb3ec6SMatthias Ringwald 
5603deb3ec6SMatthias Ringwald     if (channel->state != BNEP_CHANNEL_STATE_CONNECTED) {
5613deb3ec6SMatthias Ringwald         return BNEP_CHANNEL_NOT_CONNECTED;
5623deb3ec6SMatthias Ringwald     }
5633deb3ec6SMatthias Ringwald 
5643deb3ec6SMatthias Ringwald     if (len > MAX_BNEP_NETFILTER_OUT) {
5653deb3ec6SMatthias Ringwald         return BNEP_DATA_LEN_EXCEEDS_MTU;
5663deb3ec6SMatthias Ringwald     }
5673deb3ec6SMatthias Ringwald 
5683deb3ec6SMatthias Ringwald     channel->net_filter_out = filter;
5693deb3ec6SMatthias Ringwald     channel->net_filter_out_count = len;
5703deb3ec6SMatthias Ringwald 
5713deb3ec6SMatthias Ringwald     /* Set flag to send out the network protocol type filter set reqeuest on next statemachine cycle */
5723deb3ec6SMatthias Ringwald     bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_SET);
5733deb3ec6SMatthias Ringwald     bnep_run();
5743deb3ec6SMatthias Ringwald 
5753deb3ec6SMatthias Ringwald     return 0;
5763deb3ec6SMatthias Ringwald }
5773deb3ec6SMatthias Ringwald 
5783deb3ec6SMatthias Ringwald /* Set BNEP network protocol type filter */
5793deb3ec6SMatthias Ringwald int bnep_set_multicast_filter(uint16_t bnep_cid,  bnep_multi_filter_t *filter, uint16_t len)
5803deb3ec6SMatthias Ringwald {
5813deb3ec6SMatthias Ringwald     bnep_channel_t *channel;
5823deb3ec6SMatthias Ringwald 
5833deb3ec6SMatthias Ringwald     if (filter == NULL) {
5843deb3ec6SMatthias Ringwald         return -1;
5853deb3ec6SMatthias Ringwald     }
5863deb3ec6SMatthias Ringwald 
5873deb3ec6SMatthias Ringwald     channel = bnep_channel_for_l2cap_cid(bnep_cid);
5883deb3ec6SMatthias Ringwald     if (channel == NULL) {
5893deb3ec6SMatthias Ringwald         log_error("bnep_set_net_type_filter cid 0x%02x doesn't exist!", bnep_cid);
5903deb3ec6SMatthias Ringwald         return 1;
5913deb3ec6SMatthias Ringwald     }
5923deb3ec6SMatthias Ringwald 
5933deb3ec6SMatthias Ringwald     if (channel->state != BNEP_CHANNEL_STATE_CONNECTED) {
5943deb3ec6SMatthias Ringwald         return BNEP_CHANNEL_NOT_CONNECTED;
5953deb3ec6SMatthias Ringwald     }
5963deb3ec6SMatthias Ringwald 
59766b1fcb3SMatthias Ringwald     if (len > MAX_BNEP_MULTICAST_FILTER_OUT) {
5983deb3ec6SMatthias Ringwald         return BNEP_DATA_LEN_EXCEEDS_MTU;
5993deb3ec6SMatthias Ringwald     }
6003deb3ec6SMatthias Ringwald 
6013deb3ec6SMatthias Ringwald     channel->multicast_filter_out = filter;
6023deb3ec6SMatthias Ringwald     channel->multicast_filter_out_count = len;
6033deb3ec6SMatthias Ringwald 
6043deb3ec6SMatthias Ringwald     /* Set flag to send out the multicast filter set reqeuest on next statemachine cycle */
6053deb3ec6SMatthias Ringwald     bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_SET);
6063deb3ec6SMatthias Ringwald     bnep_run();
6073deb3ec6SMatthias Ringwald 
6083deb3ec6SMatthias Ringwald     return 0;
6093deb3ec6SMatthias Ringwald }
6103deb3ec6SMatthias Ringwald 
6113deb3ec6SMatthias Ringwald /* BNEP timeout timer helper function */
612ec820d77SMatthias Ringwald static void bnep_channel_timer_handler(btstack_timer_source_t *timer)
6133deb3ec6SMatthias Ringwald {
61491a977e8SMatthias Ringwald     bnep_channel_t *channel = btstack_run_loop_get_timer_context(timer);
6153deb3ec6SMatthias Ringwald     // retry send setup connection at least one time
6163deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE){
6173deb3ec6SMatthias Ringwald         if (channel->retry_count < BNEP_CONNECTION_MAX_RETRIES){
6183deb3ec6SMatthias Ringwald             channel->retry_count++;
6193deb3ec6SMatthias Ringwald             bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS);
6203deb3ec6SMatthias Ringwald             bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST);
6213deb3ec6SMatthias Ringwald             bnep_run();
6223deb3ec6SMatthias Ringwald             return;
6233deb3ec6SMatthias Ringwald         }
6243deb3ec6SMatthias Ringwald     }
6253deb3ec6SMatthias Ringwald 
6263deb3ec6SMatthias Ringwald     log_info( "bnep_channel_timeout_handler callback: shutting down connection!");
6273deb3ec6SMatthias Ringwald     bnep_emit_channel_timeout(channel);
6283deb3ec6SMatthias Ringwald     bnep_channel_finalize(channel);
6293deb3ec6SMatthias Ringwald }
6303deb3ec6SMatthias Ringwald 
6313deb3ec6SMatthias Ringwald 
6323deb3ec6SMatthias Ringwald static void bnep_channel_stop_timer(bnep_channel_t *channel)
6333deb3ec6SMatthias Ringwald {
6343deb3ec6SMatthias Ringwald     if (channel->timer_active) {
635528a4a3bSMatthias Ringwald         btstack_run_loop_remove_timer(&channel->timer);
6363deb3ec6SMatthias Ringwald         channel->timer_active = 0;
6373deb3ec6SMatthias Ringwald     }
6383deb3ec6SMatthias Ringwald }
6393deb3ec6SMatthias Ringwald 
6403deb3ec6SMatthias Ringwald static void bnep_channel_start_timer(bnep_channel_t *channel, int timeout)
6413deb3ec6SMatthias Ringwald {
6423deb3ec6SMatthias Ringwald     /* Stop any eventually running timeout timer */
6433deb3ec6SMatthias Ringwald     bnep_channel_stop_timer(channel);
6443deb3ec6SMatthias Ringwald 
6453deb3ec6SMatthias Ringwald     /* Start bnep channel timeout check timer */
646528a4a3bSMatthias Ringwald     btstack_run_loop_set_timer(&channel->timer, timeout);
64791a977e8SMatthias Ringwald     btstack_run_loop_set_timer_handler(&channel->timer, bnep_channel_timer_handler);
64891a977e8SMatthias Ringwald     btstack_run_loop_set_timer_context(&channel->timer, channel);
649528a4a3bSMatthias Ringwald     btstack_run_loop_add_timer(&channel->timer);
6503deb3ec6SMatthias Ringwald     channel->timer_active = 1;
6513deb3ec6SMatthias Ringwald }
6523deb3ec6SMatthias Ringwald 
6533deb3ec6SMatthias Ringwald /* BNEP statemachine functions */
6543deb3ec6SMatthias Ringwald 
6553deb3ec6SMatthias Ringwald inline static void bnep_channel_state_add(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event){
6563deb3ec6SMatthias Ringwald     channel->state_var = (BNEP_CHANNEL_STATE_VAR) (channel->state_var | event);
6573deb3ec6SMatthias Ringwald }
6583deb3ec6SMatthias Ringwald inline static void bnep_channel_state_remove(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event){
6593deb3ec6SMatthias Ringwald     channel->state_var = (BNEP_CHANNEL_STATE_VAR) (channel->state_var & ~event);
6603deb3ec6SMatthias Ringwald }
6613deb3ec6SMatthias Ringwald 
6623deb3ec6SMatthias Ringwald static uint16_t bnep_max_frame_size_for_l2cap_mtu(uint16_t l2cap_mtu){
6633deb3ec6SMatthias Ringwald 
6643deb3ec6SMatthias Ringwald     /* Assume a standard BNEP header, containing BNEP Type (1 Byte), dest and
6653deb3ec6SMatthias Ringwald        source address (6 bytes each) and networking protocol type (2 bytes)
6663deb3ec6SMatthias Ringwald      */
6673deb3ec6SMatthias Ringwald     uint16_t max_frame_size = l2cap_mtu - 15; // 15 bytes BNEP header
6683deb3ec6SMatthias Ringwald 
6693deb3ec6SMatthias Ringwald     log_info("bnep_max_frame_size_for_l2cap_mtu:  %u -> %u", l2cap_mtu, max_frame_size);
6703deb3ec6SMatthias Ringwald     return max_frame_size;
6713deb3ec6SMatthias Ringwald }
6723deb3ec6SMatthias Ringwald 
6733deb3ec6SMatthias Ringwald static bnep_channel_t * bnep_channel_create_for_addr(bd_addr_t addr)
6743deb3ec6SMatthias Ringwald {
6753deb3ec6SMatthias Ringwald     /* Allocate new channel structure */
6763deb3ec6SMatthias Ringwald     bnep_channel_t *channel = btstack_memory_bnep_channel_get();
6773deb3ec6SMatthias Ringwald     if (!channel) {
6783deb3ec6SMatthias Ringwald         return NULL;
6793deb3ec6SMatthias Ringwald     }
6803deb3ec6SMatthias Ringwald 
6813deb3ec6SMatthias Ringwald     /* Initialize the channel struct */
6823deb3ec6SMatthias Ringwald     memset(channel, 0, sizeof(bnep_channel_t));
6833deb3ec6SMatthias Ringwald 
6843deb3ec6SMatthias Ringwald     channel->state = BNEP_CHANNEL_STATE_CLOSED;
6853deb3ec6SMatthias Ringwald     channel->max_frame_size = bnep_max_frame_size_for_l2cap_mtu(l2cap_max_mtu());
68673988a59SMatthias Ringwald     bd_addr_copy(channel->remote_addr, addr);
68715a95bd5SMatthias Ringwald     gap_local_bd_addr(channel->local_addr);
6883deb3ec6SMatthias Ringwald 
6893deb3ec6SMatthias Ringwald     channel->net_filter_count = 0;
6903deb3ec6SMatthias Ringwald     channel->multicast_filter_count = 0;
6913deb3ec6SMatthias Ringwald     channel->retry_count = 0;
6923deb3ec6SMatthias Ringwald 
6933deb3ec6SMatthias Ringwald     /* Finally add it to the channel list */
694665d90f2SMatthias Ringwald     btstack_linked_list_add(&bnep_channels, (btstack_linked_item_t *) channel);
6953deb3ec6SMatthias Ringwald 
6963deb3ec6SMatthias Ringwald     return channel;
6973deb3ec6SMatthias Ringwald }
6983deb3ec6SMatthias Ringwald 
6993deb3ec6SMatthias Ringwald static bnep_channel_t* bnep_channel_for_addr(bd_addr_t addr)
7003deb3ec6SMatthias Ringwald {
701665d90f2SMatthias Ringwald     btstack_linked_item_t *it;
702665d90f2SMatthias Ringwald     for (it = (btstack_linked_item_t *) bnep_channels; it ; it = it->next){
7033deb3ec6SMatthias Ringwald         bnep_channel_t *channel = ((bnep_channel_t *) it);
704058e3d6bSMatthias Ringwald         if (bd_addr_cmp(addr, channel->remote_addr) == 0) {
7053deb3ec6SMatthias Ringwald             return channel;
7063deb3ec6SMatthias Ringwald         }
7073deb3ec6SMatthias Ringwald     }
7083deb3ec6SMatthias Ringwald     return NULL;
7093deb3ec6SMatthias Ringwald }
7103deb3ec6SMatthias Ringwald 
7113deb3ec6SMatthias Ringwald static bnep_channel_t * bnep_channel_for_l2cap_cid(uint16_t l2cap_cid)
7123deb3ec6SMatthias Ringwald {
713665d90f2SMatthias Ringwald     btstack_linked_item_t *it;
714665d90f2SMatthias Ringwald     for (it = (btstack_linked_item_t *) bnep_channels; it ; it = it->next){
7153deb3ec6SMatthias Ringwald         bnep_channel_t *channel = ((bnep_channel_t *) it);
7163deb3ec6SMatthias Ringwald         if (channel->l2cap_cid == l2cap_cid) {
7173deb3ec6SMatthias Ringwald             return channel;
7183deb3ec6SMatthias Ringwald         }
7193deb3ec6SMatthias Ringwald     }
7203deb3ec6SMatthias Ringwald     return NULL;
7213deb3ec6SMatthias Ringwald }
7223deb3ec6SMatthias Ringwald 
7233deb3ec6SMatthias Ringwald static bnep_service_t * bnep_service_for_uuid(uint16_t uuid)
7243deb3ec6SMatthias Ringwald {
725665d90f2SMatthias Ringwald     btstack_linked_item_t *it;
726665d90f2SMatthias Ringwald     for (it = (btstack_linked_item_t *) bnep_services; it ; it = it->next){
7273deb3ec6SMatthias Ringwald         bnep_service_t * service = ((bnep_service_t *) it);
7283deb3ec6SMatthias Ringwald         if ( service->service_uuid == uuid){
7293deb3ec6SMatthias Ringwald             return service;
7303deb3ec6SMatthias Ringwald         }
7313deb3ec6SMatthias Ringwald     }
7323deb3ec6SMatthias Ringwald     return NULL;
7333deb3ec6SMatthias Ringwald }
7343deb3ec6SMatthias Ringwald 
7353deb3ec6SMatthias Ringwald static void bnep_channel_free(bnep_channel_t *channel)
7363deb3ec6SMatthias Ringwald {
737665d90f2SMatthias Ringwald     btstack_linked_list_remove( &bnep_channels, (btstack_linked_item_t *) channel);
7383deb3ec6SMatthias Ringwald     btstack_memory_bnep_channel_free(channel);
7393deb3ec6SMatthias Ringwald }
7403deb3ec6SMatthias Ringwald 
7413deb3ec6SMatthias Ringwald static void bnep_channel_finalize(bnep_channel_t *channel)
7423deb3ec6SMatthias Ringwald {
7433deb3ec6SMatthias Ringwald     uint16_t l2cap_cid;
7443deb3ec6SMatthias Ringwald 
7453deb3ec6SMatthias Ringwald     /* Inform application about closed channel */
7463deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) {
7473deb3ec6SMatthias Ringwald         bnep_emit_channel_closed(channel);
7483deb3ec6SMatthias Ringwald     }
7493deb3ec6SMatthias Ringwald 
7503deb3ec6SMatthias Ringwald     l2cap_cid = channel->l2cap_cid;
7513deb3ec6SMatthias Ringwald 
7523deb3ec6SMatthias Ringwald     /* Stop any eventually running timer */
7533deb3ec6SMatthias Ringwald     bnep_channel_stop_timer(channel);
7543deb3ec6SMatthias Ringwald 
7553deb3ec6SMatthias Ringwald     /* Free ressources and then close the l2cap channel */
7563deb3ec6SMatthias Ringwald     bnep_channel_free(channel);
757ce8f182eSMatthias Ringwald     l2cap_disconnect(l2cap_cid, 0x13);
7583deb3ec6SMatthias Ringwald }
7593deb3ec6SMatthias Ringwald 
7603deb3ec6SMatthias Ringwald static int bnep_handle_connection_request(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
7613deb3ec6SMatthias Ringwald {
7623deb3ec6SMatthias Ringwald     uint16_t uuid_size;
7633deb3ec6SMatthias Ringwald     uint16_t uuid_offset;
7643deb3ec6SMatthias Ringwald     uuid_size = packet[1];
7653deb3ec6SMatthias Ringwald     uint16_t response_code = BNEP_RESP_SETUP_SUCCESS;
7663deb3ec6SMatthias Ringwald     bnep_service_t * service;
7673deb3ec6SMatthias Ringwald 
7683deb3ec6SMatthias Ringwald     /* Sanity check packet size */
7693deb3ec6SMatthias Ringwald     if (size < 1 + 1 + 2 * uuid_size) {
7703deb3ec6SMatthias Ringwald         return 0;
7713deb3ec6SMatthias Ringwald     }
7723deb3ec6SMatthias Ringwald 
7733deb3ec6SMatthias Ringwald     if ((channel->state != BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST) &&
7743deb3ec6SMatthias Ringwald         (channel->state != BNEP_CHANNEL_STATE_CONNECTED)) {
7753deb3ec6SMatthias Ringwald         /* Ignore a connection request if not waiting for or still connected */
7763deb3ec6SMatthias Ringwald         log_error("BNEP_CONNECTION_REQUEST: ignored in state %d, l2cap_cid: %d!", channel->state, channel->l2cap_cid);
7773deb3ec6SMatthias Ringwald         return 0;
7783deb3ec6SMatthias Ringwald     }
7793deb3ec6SMatthias Ringwald 
7803deb3ec6SMatthias Ringwald      /* Extract source and destination UUID and convert them to UUID16 format */
7813deb3ec6SMatthias Ringwald     switch (uuid_size) {
7823deb3ec6SMatthias Ringwald         case 2:  /* UUID16  */
7833deb3ec6SMatthias Ringwald             uuid_offset = 0;
7843deb3ec6SMatthias Ringwald             break;
7853deb3ec6SMatthias Ringwald         case 4:  /* UUID32  */
7863deb3ec6SMatthias Ringwald         case 16: /* UUID128 */
7873deb3ec6SMatthias Ringwald             uuid_offset = 2;
7883deb3ec6SMatthias Ringwald             break;
7893deb3ec6SMatthias Ringwald         default:
7903deb3ec6SMatthias Ringwald             log_error("BNEP_CONNECTION_REQUEST: Invalid UUID size %d, l2cap_cid: %d!", channel->state, channel->l2cap_cid);
7913deb3ec6SMatthias Ringwald             response_code = BNEP_RESP_SETUP_INVALID_SERVICE_UUID_SIZE;
7923deb3ec6SMatthias Ringwald             break;
7933deb3ec6SMatthias Ringwald     }
7943deb3ec6SMatthias Ringwald 
7953deb3ec6SMatthias Ringwald     /* Check source and destination UUIDs for valid combinations */
7963deb3ec6SMatthias Ringwald     if (response_code == BNEP_RESP_SETUP_SUCCESS) {
797f8fbdce0SMatthias Ringwald         channel->uuid_dest = big_endian_read_16(packet, 2 + uuid_offset);
798f8fbdce0SMatthias Ringwald         channel->uuid_source = big_endian_read_16(packet, 2 + uuid_offset + uuid_size);
7993deb3ec6SMatthias Ringwald 
8003deb3ec6SMatthias Ringwald         if ((channel->uuid_dest != SDP_PANU) &&
8013deb3ec6SMatthias Ringwald             (channel->uuid_dest != SDP_NAP) &&
8023deb3ec6SMatthias Ringwald             (channel->uuid_dest != SDP_GN)) {
8033deb3ec6SMatthias Ringwald             log_error("BNEP_CONNECTION_REQUEST: Invalid destination service UUID: %04x", channel->uuid_dest);
8043deb3ec6SMatthias Ringwald             channel->uuid_dest = 0;
8053deb3ec6SMatthias Ringwald         }
8063deb3ec6SMatthias Ringwald         if ((channel->uuid_source != SDP_PANU) &&
8073deb3ec6SMatthias Ringwald             (channel->uuid_source != SDP_NAP) &&
8083deb3ec6SMatthias Ringwald             (channel->uuid_source != SDP_GN)) {
8093deb3ec6SMatthias Ringwald             log_error("BNEP_CONNECTION_REQUEST: Invalid source service UUID: %04x", channel->uuid_source);
8103deb3ec6SMatthias Ringwald             channel->uuid_source = 0;
8113deb3ec6SMatthias Ringwald         }
8123deb3ec6SMatthias Ringwald 
8133deb3ec6SMatthias Ringwald         /* Check if we have registered a service for the requested destination UUID */
8143deb3ec6SMatthias Ringwald         service = bnep_service_for_uuid(channel->uuid_dest);
8153deb3ec6SMatthias Ringwald         if (service == NULL) {
8163deb3ec6SMatthias Ringwald             response_code = BNEP_RESP_SETUP_INVALID_DEST_UUID;
8173deb3ec6SMatthias Ringwald         } else
8183deb3ec6SMatthias Ringwald         if ((channel->uuid_source != SDP_PANU) && (channel->uuid_dest != SDP_PANU)) {
8193deb3ec6SMatthias Ringwald             response_code = BNEP_RESP_SETUP_INVALID_SOURCE_UUID;
8203deb3ec6SMatthias Ringwald         }
8213deb3ec6SMatthias Ringwald     }
8223deb3ec6SMatthias Ringwald 
8233deb3ec6SMatthias Ringwald     /* Set flag to send out the connection response on next statemachine cycle */
8243deb3ec6SMatthias Ringwald     bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE);
8253deb3ec6SMatthias Ringwald     channel->response_code = response_code;
8263deb3ec6SMatthias Ringwald 
8273deb3ec6SMatthias Ringwald     /* Return the number of processed package bytes = BNEP Type, BNEP Control Type, UUID-Size + 2 * UUID */
8283deb3ec6SMatthias Ringwald     return 1 + 1 + 2 * uuid_size;
8293deb3ec6SMatthias Ringwald }
8303deb3ec6SMatthias Ringwald 
8313deb3ec6SMatthias Ringwald static int bnep_handle_connection_response(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
8323deb3ec6SMatthias Ringwald {
8333deb3ec6SMatthias Ringwald     uint16_t response_code;
8343deb3ec6SMatthias Ringwald 
8353deb3ec6SMatthias Ringwald     /* Sanity check packet size */
8363deb3ec6SMatthias Ringwald     if (size < 1 + 2) {
8373deb3ec6SMatthias Ringwald         return 0;
8383deb3ec6SMatthias Ringwald     }
8393deb3ec6SMatthias Ringwald 
8403deb3ec6SMatthias Ringwald     if (channel->state != BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE) {
8413deb3ec6SMatthias Ringwald         /* Ignore a connection response in any state but WAIT_FOR_CONNECTION_RESPONSE */
8423deb3ec6SMatthias Ringwald         log_error("BNEP_CONNECTION_RESPONSE: Ignored in channel state %d", channel->state);
8433deb3ec6SMatthias Ringwald         return 1 + 2;
8443deb3ec6SMatthias Ringwald     }
8453deb3ec6SMatthias Ringwald 
846f8fbdce0SMatthias Ringwald     response_code = big_endian_read_16(packet, 1);
8473deb3ec6SMatthias Ringwald 
8483deb3ec6SMatthias Ringwald     if (response_code == BNEP_RESP_SETUP_SUCCESS) {
8493deb3ec6SMatthias Ringwald         log_info("BNEP_CONNECTION_RESPONSE: Channel established to %s", bd_addr_to_str(channel->remote_addr));
8503deb3ec6SMatthias Ringwald         channel->state = BNEP_CHANNEL_STATE_CONNECTED;
8513deb3ec6SMatthias Ringwald         /* Stop timeout timer! */
8523deb3ec6SMatthias Ringwald         bnep_channel_stop_timer(channel);
8533deb3ec6SMatthias Ringwald         bnep_emit_open_channel_complete(channel, 0);
8543deb3ec6SMatthias Ringwald     } else {
8553deb3ec6SMatthias Ringwald         log_error("BNEP_CONNECTION_RESPONSE: Connection to %s failed. Err: %d", bd_addr_to_str(channel->remote_addr), response_code);
8563deb3ec6SMatthias Ringwald         bnep_channel_finalize(channel);
8573deb3ec6SMatthias Ringwald     }
8583deb3ec6SMatthias Ringwald     return 1 + 2;
8593deb3ec6SMatthias Ringwald }
8603deb3ec6SMatthias Ringwald 
8613deb3ec6SMatthias Ringwald static int bnep_can_handle_extensions(bnep_channel_t * channel){
8623deb3ec6SMatthias Ringwald     /* Extension are primarily handled in CONNECTED state */
8633deb3ec6SMatthias Ringwald     if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) return 1;
8643deb3ec6SMatthias Ringwald     /* and if we've received connection request, but haven't sent the reponse yet. */
8653deb3ec6SMatthias Ringwald     if ((channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST) &&
8663deb3ec6SMatthias Ringwald         (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE)) {
8673deb3ec6SMatthias Ringwald         return 1;
8683deb3ec6SMatthias Ringwald     }
8693deb3ec6SMatthias Ringwald     return 0;
8703deb3ec6SMatthias Ringwald }
8713deb3ec6SMatthias Ringwald 
8723deb3ec6SMatthias Ringwald static int bnep_handle_filter_net_type_set(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
8733deb3ec6SMatthias Ringwald {
8743deb3ec6SMatthias Ringwald     uint16_t list_length;
8753deb3ec6SMatthias Ringwald     uint16_t response_code = BNEP_RESP_FILTER_SUCCESS;
8763deb3ec6SMatthias Ringwald 
8773deb3ec6SMatthias Ringwald     /* Sanity check packet size */
8783deb3ec6SMatthias Ringwald     if (size < 3) {
8793deb3ec6SMatthias Ringwald         return 0;
8803deb3ec6SMatthias Ringwald     }
8813deb3ec6SMatthias Ringwald 
882f8fbdce0SMatthias Ringwald     list_length = big_endian_read_16(packet, 1);
8833deb3ec6SMatthias Ringwald     /* Sanity check packet size again with known package size */
8843deb3ec6SMatthias Ringwald     if (size < 3 + list_length) {
8853deb3ec6SMatthias Ringwald         return 0;
8863deb3ec6SMatthias Ringwald     }
8873deb3ec6SMatthias Ringwald 
8883deb3ec6SMatthias Ringwald     if (!bnep_can_handle_extensions(channel)){
8893deb3ec6SMatthias Ringwald         log_error("BNEP_FILTER_NET_TYPE_SET: Ignored in channel state %d", channel->state);
8903deb3ec6SMatthias Ringwald         return 3 + list_length;
8913deb3ec6SMatthias Ringwald     }
8923deb3ec6SMatthias Ringwald 
8933deb3ec6SMatthias Ringwald     /* Check if we have enough space for more filters */
8943deb3ec6SMatthias Ringwald     if ((list_length / (2*2)) > MAX_BNEP_NETFILTER) {
8953deb3ec6SMatthias Ringwald         log_info("BNEP_FILTER_NET_TYPE_SET: Too many filter");
8963deb3ec6SMatthias Ringwald         response_code = BNEP_RESP_FILTER_ERR_TOO_MANY_FILTERS;
8973deb3ec6SMatthias Ringwald     } else {
8983deb3ec6SMatthias Ringwald         int i;
8993deb3ec6SMatthias Ringwald         channel->net_filter_count = 0;
9003deb3ec6SMatthias Ringwald         /* There is still enough space, copy the filters to our filter list */
901ef907034SMatthias Ringwald         /* There is still enough space, copy the filters to our filter list */
9023deb3ec6SMatthias Ringwald         for (i = 0; i < list_length / (2 * 2); i ++) {
903f8fbdce0SMatthias Ringwald             channel->net_filter[channel->net_filter_count].range_start = big_endian_read_16(packet, 1 + 2 + i * 4);
904f8fbdce0SMatthias Ringwald             channel->net_filter[channel->net_filter_count].range_end = big_endian_read_16(packet, 1 + 2 + i * 4 + 2);
9053deb3ec6SMatthias Ringwald             if (channel->net_filter[channel->net_filter_count].range_start > channel->net_filter[channel->net_filter_count].range_end) {
9063deb3ec6SMatthias Ringwald                 /* Invalid filter range, ignore this filter rule */
9073deb3ec6SMatthias Ringwald                 log_error("BNEP_FILTER_NET_TYPE_SET: Invalid filter: start: %d, end: %d",
9083deb3ec6SMatthias Ringwald                          channel->net_filter[channel->net_filter_count].range_start,
9093deb3ec6SMatthias Ringwald                          channel->net_filter[channel->net_filter_count].range_end);
9103deb3ec6SMatthias Ringwald                 response_code = BNEP_RESP_FILTER_ERR_INVALID_RANGE;
9113deb3ec6SMatthias Ringwald             } else {
9123deb3ec6SMatthias Ringwald                 /* Valid filter, increase the filter count */
9133deb3ec6SMatthias Ringwald                 log_info("BNEP_FILTER_NET_TYPE_SET: Add filter: start: %d, end: %d",
9143deb3ec6SMatthias Ringwald                          channel->net_filter[channel->net_filter_count].range_start,
9153deb3ec6SMatthias Ringwald                          channel->net_filter[channel->net_filter_count].range_end);
9163deb3ec6SMatthias Ringwald                 channel->net_filter_count ++;
9173deb3ec6SMatthias Ringwald             }
9183deb3ec6SMatthias Ringwald         }
9193deb3ec6SMatthias Ringwald     }
9203deb3ec6SMatthias Ringwald 
9213deb3ec6SMatthias Ringwald     /* Set flag to send out the set net filter response on next statemachine cycle */
9223deb3ec6SMatthias Ringwald     bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_RESPONSE);
9233deb3ec6SMatthias Ringwald     channel->response_code = response_code;
9243deb3ec6SMatthias Ringwald 
9253deb3ec6SMatthias Ringwald     return 3 + list_length;
9263deb3ec6SMatthias Ringwald }
9273deb3ec6SMatthias Ringwald 
9283deb3ec6SMatthias Ringwald static int bnep_handle_filter_net_type_response(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
9293deb3ec6SMatthias Ringwald {
9303deb3ec6SMatthias Ringwald 	uint16_t response_code;
9313deb3ec6SMatthias Ringwald 
9323deb3ec6SMatthias Ringwald     // TODO: Currently we do not support setting a network filter.
9333deb3ec6SMatthias Ringwald 
9343deb3ec6SMatthias Ringwald     /* Sanity check packet size */
9353deb3ec6SMatthias Ringwald     if (size < 1 + 2) {
9363deb3ec6SMatthias Ringwald         return 0;
9373deb3ec6SMatthias Ringwald     }
9383deb3ec6SMatthias Ringwald 
9393deb3ec6SMatthias Ringwald     if (!bnep_can_handle_extensions(channel)){
9403deb3ec6SMatthias Ringwald         log_error("BNEP_FILTER_NET_TYPE_RESPONSE: Ignored in channel state %d", channel->state);
9413deb3ec6SMatthias Ringwald         return 1 + 2;
9423deb3ec6SMatthias Ringwald     }
9433deb3ec6SMatthias Ringwald 
944f8fbdce0SMatthias Ringwald     response_code = big_endian_read_16(packet, 1);
9453deb3ec6SMatthias Ringwald 
9463deb3ec6SMatthias Ringwald     if (response_code == BNEP_RESP_FILTER_SUCCESS) {
9473deb3ec6SMatthias Ringwald         log_info("BNEP_FILTER_NET_TYPE_RESPONSE: Net filter set successfully for %s", bd_addr_to_str(channel->remote_addr));
9483deb3ec6SMatthias Ringwald     } else {
9493deb3ec6SMatthias 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);
9503deb3ec6SMatthias Ringwald     }
9513deb3ec6SMatthias Ringwald 
9523deb3ec6SMatthias Ringwald     return 1 + 2;
9533deb3ec6SMatthias Ringwald }
9543deb3ec6SMatthias Ringwald 
9553deb3ec6SMatthias Ringwald static int bnep_handle_multi_addr_set(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
9563deb3ec6SMatthias Ringwald {
9573deb3ec6SMatthias Ringwald     uint16_t list_length;
9583deb3ec6SMatthias Ringwald     uint16_t response_code = BNEP_RESP_FILTER_SUCCESS;
9593deb3ec6SMatthias Ringwald 
9603deb3ec6SMatthias Ringwald     /* Sanity check packet size */
9613deb3ec6SMatthias Ringwald     if (size < 3) {
9623deb3ec6SMatthias Ringwald         return 0;
9633deb3ec6SMatthias Ringwald     }
9643deb3ec6SMatthias Ringwald 
965f8fbdce0SMatthias Ringwald     list_length = big_endian_read_16(packet, 1);
9663deb3ec6SMatthias Ringwald     /* Sanity check packet size again with known package size */
9673deb3ec6SMatthias Ringwald     if (size < 3 + list_length) {
9683deb3ec6SMatthias Ringwald         return 0;
9693deb3ec6SMatthias Ringwald     }
9703deb3ec6SMatthias Ringwald 
9713deb3ec6SMatthias Ringwald     if (!bnep_can_handle_extensions(channel)){
9723deb3ec6SMatthias Ringwald         log_error("BNEP_MULTI_ADDR_SET: Ignored in channel state %d", channel->state);
9733deb3ec6SMatthias Ringwald         return 3 + list_length;
9743deb3ec6SMatthias Ringwald     }
9753deb3ec6SMatthias Ringwald 
9763deb3ec6SMatthias Ringwald     /* Check if we have enough space for more filters */
9773deb3ec6SMatthias Ringwald     if ((list_length / (2 * ETHER_ADDR_LEN)) > MAX_BNEP_MULTICAST_FILTER) {
9783deb3ec6SMatthias Ringwald         log_info("BNEP_MULTI_ADDR_SET: Too many filter");
9793deb3ec6SMatthias Ringwald         response_code = BNEP_RESP_FILTER_ERR_TOO_MANY_FILTERS;
9803deb3ec6SMatthias Ringwald     } else {
9813deb3ec6SMatthias Ringwald         unsigned int i;
9823deb3ec6SMatthias Ringwald         channel->multicast_filter_count = 0;
9833deb3ec6SMatthias Ringwald         /* There is enough space, copy the filters to our filter list */
9843deb3ec6SMatthias Ringwald         for (i = 0; i < list_length / (2 * ETHER_ADDR_LEN); i ++) {
985058e3d6bSMatthias Ringwald             bd_addr_copy(channel->multicast_filter[channel->multicast_filter_count].addr_start, packet + 1 + 2 + i * ETHER_ADDR_LEN * 2);
986058e3d6bSMatthias Ringwald             bd_addr_copy(channel->multicast_filter[channel->multicast_filter_count].addr_end, packet + 1 + 2 + i * ETHER_ADDR_LEN * 2 + ETHER_ADDR_LEN);
9873deb3ec6SMatthias Ringwald 
9883deb3ec6SMatthias Ringwald             if (memcmp(channel->multicast_filter[channel->multicast_filter_count].addr_start,
9893deb3ec6SMatthias Ringwald                        channel->multicast_filter[channel->multicast_filter_count].addr_end, ETHER_ADDR_LEN) > 0) {
9903deb3ec6SMatthias Ringwald                 /* Invalid filter range, ignore this filter rule */
9913deb3ec6SMatthias Ringwald                 log_error("BNEP_MULTI_ADDR_SET: Invalid filter: start: %s",
9923deb3ec6SMatthias Ringwald                          bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_start));
9933deb3ec6SMatthias Ringwald                 log_error("BNEP_MULTI_ADDR_SET: Invalid filter: end: %s",
9943deb3ec6SMatthias Ringwald                          bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_end));
9953deb3ec6SMatthias Ringwald                 response_code = BNEP_RESP_FILTER_ERR_INVALID_RANGE;
9963deb3ec6SMatthias Ringwald             } else {
9973deb3ec6SMatthias Ringwald                 /* Valid filter, increase the filter count */
9983deb3ec6SMatthias Ringwald                 log_info("BNEP_MULTI_ADDR_SET: Add filter: start: %s",
9993deb3ec6SMatthias Ringwald                          bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_start));
10003deb3ec6SMatthias Ringwald                 log_info("BNEP_MULTI_ADDR_SET: Add filter: end: %s",
10013deb3ec6SMatthias Ringwald                          bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_end));
10023deb3ec6SMatthias Ringwald                 channel->multicast_filter_count ++;
10033deb3ec6SMatthias Ringwald             }
10043deb3ec6SMatthias Ringwald         }
10053deb3ec6SMatthias Ringwald     }
10063deb3ec6SMatthias Ringwald     /* Set flag to send out the set multi addr response on next statemachine cycle */
10073deb3ec6SMatthias Ringwald     bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_RESPONSE);
10083deb3ec6SMatthias Ringwald     channel->response_code = response_code;
10093deb3ec6SMatthias Ringwald 
10103deb3ec6SMatthias Ringwald     return 3 + list_length;
10113deb3ec6SMatthias Ringwald }
10123deb3ec6SMatthias Ringwald 
10133deb3ec6SMatthias Ringwald static int bnep_handle_multi_addr_response(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
10143deb3ec6SMatthias Ringwald {
10153deb3ec6SMatthias Ringwald 	uint16_t response_code;
10163deb3ec6SMatthias Ringwald 
10173deb3ec6SMatthias Ringwald     // TODO: Currently we do not support setting multicast address filter.
10183deb3ec6SMatthias Ringwald 
10193deb3ec6SMatthias Ringwald     /* Sanity check packet size */
10203deb3ec6SMatthias Ringwald     if (size < 1 + 2) {
10213deb3ec6SMatthias Ringwald         return 0;
10223deb3ec6SMatthias Ringwald     }
10233deb3ec6SMatthias Ringwald 
10243deb3ec6SMatthias Ringwald     if (!bnep_can_handle_extensions(channel)){
10253deb3ec6SMatthias Ringwald         log_error("BNEP_MULTI_ADDR_RESPONSE: Ignored in channel state %d", channel->state);
10263deb3ec6SMatthias Ringwald         return 1 + 2;
10273deb3ec6SMatthias Ringwald     }
10283deb3ec6SMatthias Ringwald 
1029f8fbdce0SMatthias Ringwald     response_code = big_endian_read_16(packet, 1);
10303deb3ec6SMatthias Ringwald 
10313deb3ec6SMatthias Ringwald     if (response_code == BNEP_RESP_FILTER_SUCCESS) {
10323deb3ec6SMatthias Ringwald         log_info("BNEP_MULTI_ADDR_RESPONSE: Multicast address filter set successfully for %s", bd_addr_to_str(channel->remote_addr));
10333deb3ec6SMatthias Ringwald     } else {
10343deb3ec6SMatthias 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);
10353deb3ec6SMatthias Ringwald     }
10363deb3ec6SMatthias Ringwald 
10373deb3ec6SMatthias Ringwald     return 1 + 2;
10383deb3ec6SMatthias Ringwald }
10393deb3ec6SMatthias Ringwald 
10403deb3ec6SMatthias 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)
10413deb3ec6SMatthias Ringwald {
10423deb3ec6SMatthias Ringwald     uint16_t pos = 0;
10433deb3ec6SMatthias Ringwald 
10443deb3ec6SMatthias 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)
10453deb3ec6SMatthias Ringwald     /* In-place modify the package and add the ethernet header in front of the payload.
10463deb3ec6SMatthias Ringwald      * WARNING: This modifies the data in front of the payload and may overwrite 14 bytes there!
10473deb3ec6SMatthias Ringwald      */
10483deb3ec6SMatthias Ringwald     uint8_t *ethernet_packet = payload - 2 * sizeof(bd_addr_t) - sizeof(uint16_t);
10493deb3ec6SMatthias Ringwald     /* Restore the ethernet packet header */
1050058e3d6bSMatthias Ringwald     bd_addr_copy(ethernet_packet + pos, addr_dest);
10513deb3ec6SMatthias Ringwald     pos += sizeof(bd_addr_t);
1052058e3d6bSMatthias Ringwald     bd_addr_copy(ethernet_packet + pos, addr_source);
10533deb3ec6SMatthias Ringwald     pos += sizeof(bd_addr_t);
1054f8fbdce0SMatthias Ringwald     big_endian_store_16(ethernet_packet, pos, network_protocol_type);
10553deb3ec6SMatthias Ringwald     /* Payload is just in place... */
10563deb3ec6SMatthias Ringwald #else
10573deb3ec6SMatthias Ringwald     /* Copy ethernet frame to statically allocated buffer. This solution is more
10583deb3ec6SMatthias Ringwald      * save, but needs an extra copy and more stack!
10593deb3ec6SMatthias Ringwald      */
10603deb3ec6SMatthias Ringwald     uint8_t ethernet_packet[BNEP_MTU_MIN];
10613deb3ec6SMatthias Ringwald 
10623deb3ec6SMatthias Ringwald     /* Restore the ethernet packet header */
1063058e3d6bSMatthias Ringwald     bd_addr_copy(ethernet_packet + pos, addr_dest);
10643deb3ec6SMatthias Ringwald     pos += sizeof(bd_addr_t);
1065058e3d6bSMatthias Ringwald     bd_addr_copy(ethernet_packet + pos, addr_source);
10663deb3ec6SMatthias Ringwald     pos += sizeof(bd_addr_t);
1067f8fbdce0SMatthias Ringwald     big_endian_store_16(ethernet_packet, pos, network_protocol_type);
10683deb3ec6SMatthias Ringwald     pos += 2;
10693deb3ec6SMatthias Ringwald     memcpy(ethernet_packet + pos, payload, size);
10703deb3ec6SMatthias Ringwald #endif
10713deb3ec6SMatthias Ringwald 
10723deb3ec6SMatthias Ringwald     /* Notify application layer and deliver the ethernet packet */
10730cc6429eSMatthias Ringwald     (*app_packet_handler)(BNEP_DATA_PACKET, channel->uuid_source,
10743deb3ec6SMatthias Ringwald                           ethernet_packet, size + sizeof(uint16_t) + 2 * sizeof(bd_addr_t));
10753deb3ec6SMatthias Ringwald 
10763deb3ec6SMatthias Ringwald     return size;
10773deb3ec6SMatthias Ringwald }
10783deb3ec6SMatthias Ringwald 
10793deb3ec6SMatthias Ringwald static int bnep_handle_control_packet(bnep_channel_t *channel, uint8_t *packet, uint16_t size, int is_extension)
10803deb3ec6SMatthias Ringwald {
10813deb3ec6SMatthias Ringwald     uint16_t len = 0;
10823deb3ec6SMatthias Ringwald     uint8_t  bnep_control_type;
10833deb3ec6SMatthias Ringwald 
10843deb3ec6SMatthias Ringwald     bnep_control_type = packet[0];
10853deb3ec6SMatthias Ringwald     /* Save last control type. Needed by statemachin in case of unknown control code */
10863deb3ec6SMatthias Ringwald 
10873deb3ec6SMatthias Ringwald     channel->last_control_type = bnep_control_type;
10883deb3ec6SMatthias Ringwald     log_info("BNEP_CONTROL: Type: %d, size: %d, is_extension: %d", bnep_control_type, size, is_extension);
10893deb3ec6SMatthias Ringwald     switch (bnep_control_type) {
10903deb3ec6SMatthias Ringwald         case BNEP_CONTROL_TYPE_COMMAND_NOT_UNDERSTOOD:
10913deb3ec6SMatthias Ringwald             /* The last command we send was not understood. We should close the connection */
10923deb3ec6SMatthias Ringwald             log_error("BNEP_CONTROL: Received COMMAND_NOT_UNDERSTOOD: l2cap_cid: %d, cmd: %d", channel->l2cap_cid, packet[3]);
10933deb3ec6SMatthias Ringwald             bnep_channel_finalize(channel);
10943deb3ec6SMatthias Ringwald             len = 2; // Length of command not understood packet - bnep-type field
10953deb3ec6SMatthias Ringwald             break;
10963deb3ec6SMatthias Ringwald         case BNEP_CONTROL_TYPE_SETUP_CONNECTION_REQUEST:
10973deb3ec6SMatthias Ringwald             if (is_extension) {
10983deb3ec6SMatthias Ringwald                 /* Connection requests are not allowed to be send in an extension header
10993deb3ec6SMatthias Ringwald                  *  ignore, do not set "COMMAND_NOT_UNDERSTOOD"
11003deb3ec6SMatthias Ringwald                  */
11013deb3ec6SMatthias Ringwald                 log_error("BNEP_CONTROL: Received SETUP_CONNECTION_REQUEST in extension header: l2cap_cid: %d", channel->l2cap_cid);
11023deb3ec6SMatthias Ringwald                 return 0;
11033deb3ec6SMatthias Ringwald             } else {
11043deb3ec6SMatthias Ringwald                 len = bnep_handle_connection_request(channel, packet, size);
11053deb3ec6SMatthias Ringwald             }
11063deb3ec6SMatthias Ringwald             break;
11073deb3ec6SMatthias Ringwald         case BNEP_CONTROL_TYPE_SETUP_CONNECTION_RESPONSE:
11083deb3ec6SMatthias Ringwald             if (is_extension) {
11093deb3ec6SMatthias Ringwald                 /* Connection requests are not allowed to be send in an
11103deb3ec6SMatthias Ringwald                  * extension header, ignore, do not set "COMMAND_NOT_UNDERSTOOD"
11113deb3ec6SMatthias Ringwald                  */
11123deb3ec6SMatthias Ringwald                 log_error("BNEP_CONTROL: Received SETUP_CONNECTION_RESPONSE in extension header: l2cap_cid: %d", channel->l2cap_cid);
11133deb3ec6SMatthias Ringwald                 return 0;
11143deb3ec6SMatthias Ringwald             } else {
11153deb3ec6SMatthias Ringwald                 len = bnep_handle_connection_response(channel, packet, size);
11163deb3ec6SMatthias Ringwald             }
11173deb3ec6SMatthias Ringwald             break;
11183deb3ec6SMatthias Ringwald         case BNEP_CONTROL_TYPE_FILTER_NET_TYPE_SET:
11193deb3ec6SMatthias Ringwald             len = bnep_handle_filter_net_type_set(channel, packet, size);
11203deb3ec6SMatthias Ringwald             break;
11213deb3ec6SMatthias Ringwald         case BNEP_CONTROL_TYPE_FILTER_NET_TYPE_RESPONSE:
11223deb3ec6SMatthias Ringwald             len = bnep_handle_filter_net_type_response(channel, packet, size);
11233deb3ec6SMatthias Ringwald             break;
11243deb3ec6SMatthias Ringwald         case BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_SET:
11253deb3ec6SMatthias Ringwald             len = bnep_handle_multi_addr_set(channel, packet, size);
11263deb3ec6SMatthias Ringwald             break;
11273deb3ec6SMatthias Ringwald         case BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_RESPONSE:
11283deb3ec6SMatthias Ringwald             len = bnep_handle_multi_addr_response(channel, packet, size);
11293deb3ec6SMatthias Ringwald             break;
11303deb3ec6SMatthias Ringwald         default:
11313deb3ec6SMatthias Ringwald             log_error("BNEP_CONTROL: Invalid bnep control type: l2cap_cid: %d, cmd: %d", channel->l2cap_cid, bnep_control_type);
11323deb3ec6SMatthias Ringwald             len = 0;
11333deb3ec6SMatthias Ringwald             break;
11343deb3ec6SMatthias Ringwald     }
11353deb3ec6SMatthias Ringwald 
11363deb3ec6SMatthias Ringwald     if (len == 0) {
11373deb3ec6SMatthias Ringwald         /* In case the command could not be handled, send a
11383deb3ec6SMatthias Ringwald            COMMAND_NOT_UNDERSTOOD message.
11393deb3ec6SMatthias Ringwald            Set flag to process the request in the next statemachine loop
11403deb3ec6SMatthias Ringwald          */
11413deb3ec6SMatthias Ringwald         bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_NOT_UNDERSTOOD);
11423deb3ec6SMatthias Ringwald     }
11433deb3ec6SMatthias Ringwald 
11443deb3ec6SMatthias Ringwald     return len;
11453deb3ec6SMatthias Ringwald }
11463deb3ec6SMatthias Ringwald 
11473deb3ec6SMatthias Ringwald /**
11483deb3ec6SMatthias Ringwald  * @return handled packet
11493deb3ec6SMatthias Ringwald  */
11503deb3ec6SMatthias Ringwald static int bnep_hci_event_handler(uint8_t *packet, uint16_t size)
11513deb3ec6SMatthias Ringwald {
11523deb3ec6SMatthias Ringwald     bd_addr_t event_addr;
11533deb3ec6SMatthias Ringwald     uint16_t  psm;
11543deb3ec6SMatthias Ringwald     uint16_t  l2cap_cid;
11553deb3ec6SMatthias Ringwald     hci_con_handle_t con_handle;
11563deb3ec6SMatthias Ringwald     bnep_channel_t  *channel = NULL;
11573deb3ec6SMatthias Ringwald     uint8_t   status;
11583deb3ec6SMatthias Ringwald 
1159*0e2df43fSMatthias Ringwald     switch (hci_event_packet_get_type(packet)) {
11603deb3ec6SMatthias Ringwald 
11613deb3ec6SMatthias Ringwald         /* Accept an incoming L2CAP connection on PSM_BNEP */
11623deb3ec6SMatthias Ringwald         case L2CAP_EVENT_INCOMING_CONNECTION:
11633deb3ec6SMatthias Ringwald             /* L2CAP event data: event(8), len(8), address(48), handle (16),  psm (16), source cid(16) dest cid(16) */
1164724d70a2SMatthias Ringwald             reverse_bd_addr(&packet[2], event_addr);
1165f8fbdce0SMatthias Ringwald             con_handle = little_endian_read_16(packet,  8);
1166f8fbdce0SMatthias Ringwald             psm        = little_endian_read_16(packet, 10);
1167f8fbdce0SMatthias Ringwald             l2cap_cid  = little_endian_read_16(packet, 12);
11683deb3ec6SMatthias Ringwald 
11693deb3ec6SMatthias Ringwald             if (psm != PSM_BNEP) break;
11703deb3ec6SMatthias Ringwald 
11713deb3ec6SMatthias Ringwald             channel = bnep_channel_for_addr(event_addr);
11723deb3ec6SMatthias Ringwald 
11733deb3ec6SMatthias Ringwald             if (channel) {
11743deb3ec6SMatthias Ringwald                 log_error("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => decline - channel already exists", l2cap_cid);
1175ce8f182eSMatthias Ringwald                 l2cap_decline_connection(l2cap_cid,  0x04);    // no resources available
11763deb3ec6SMatthias Ringwald                 return 1;
11773deb3ec6SMatthias Ringwald             }
11783deb3ec6SMatthias Ringwald 
11793deb3ec6SMatthias Ringwald             /* Create a new BNEP channel instance (incoming) */
11803deb3ec6SMatthias Ringwald             channel = bnep_channel_create_for_addr(event_addr);
11813deb3ec6SMatthias Ringwald 
11823deb3ec6SMatthias Ringwald             if (!channel) {
11833deb3ec6SMatthias Ringwald                 log_error("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => decline - no memory left", l2cap_cid);
1184ce8f182eSMatthias Ringwald                 l2cap_decline_connection(l2cap_cid,  0x04);    // no resources available
11853deb3ec6SMatthias Ringwald                 return 1;
11863deb3ec6SMatthias Ringwald             }
11873deb3ec6SMatthias Ringwald 
11883deb3ec6SMatthias Ringwald             /* Assign connection handle and l2cap cid */
11893deb3ec6SMatthias Ringwald             channel->con_handle = con_handle;
11903deb3ec6SMatthias Ringwald             channel->l2cap_cid = l2cap_cid;
11913deb3ec6SMatthias Ringwald 
11923deb3ec6SMatthias Ringwald             /* Set channel into accept state */
11933deb3ec6SMatthias Ringwald             channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST;
11943deb3ec6SMatthias Ringwald 
11953deb3ec6SMatthias Ringwald             /* Start connection timeout timer */
11963deb3ec6SMatthias Ringwald             bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS);
11973deb3ec6SMatthias Ringwald 
11983deb3ec6SMatthias Ringwald             log_info("L2CAP_EVENT_INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => accept", l2cap_cid);
1199ce8f182eSMatthias Ringwald             l2cap_accept_connection(l2cap_cid);
12003deb3ec6SMatthias Ringwald             return 1;
12013deb3ec6SMatthias Ringwald 
12023deb3ec6SMatthias Ringwald         /* Outgoing L2CAP connection has been opened -> store l2cap_cid, remote_addr */
12033deb3ec6SMatthias Ringwald         case L2CAP_EVENT_CHANNEL_OPENED:
12043deb3ec6SMatthias Ringwald             /* Check if the l2cap channel has been opened for PSM_BNEP */
1205f8fbdce0SMatthias Ringwald             if (little_endian_read_16(packet, 11) != PSM_BNEP) {
12063deb3ec6SMatthias Ringwald                 break;
12073deb3ec6SMatthias Ringwald             }
12083deb3ec6SMatthias Ringwald 
12093deb3ec6SMatthias Ringwald             status = packet[2];
12103deb3ec6SMatthias Ringwald             log_info("L2CAP_EVENT_CHANNEL_OPENED for PSM_BNEP, status %u", status);
12113deb3ec6SMatthias Ringwald 
12123deb3ec6SMatthias Ringwald             /* Get the bnep channel fpr remote address */
1213f8fbdce0SMatthias Ringwald             con_handle = little_endian_read_16(packet, 9);
1214f8fbdce0SMatthias Ringwald             l2cap_cid  = little_endian_read_16(packet, 13);
1215724d70a2SMatthias Ringwald             reverse_bd_addr(&packet[3], event_addr);
12163deb3ec6SMatthias Ringwald             channel = bnep_channel_for_addr(event_addr);
12173deb3ec6SMatthias Ringwald             if (!channel) {
12183deb3ec6SMatthias Ringwald                 log_error("L2CAP_EVENT_CHANNEL_OPENED but no BNEP channel prepared");
12193deb3ec6SMatthias Ringwald                 return 1;
12203deb3ec6SMatthias Ringwald             }
12213deb3ec6SMatthias Ringwald 
12223deb3ec6SMatthias Ringwald             /* On L2CAP open error discard everything */
12233deb3ec6SMatthias Ringwald             if (status) {
12243deb3ec6SMatthias Ringwald                 /* Emit bnep_open_channel_complete with status and free channel */
12253deb3ec6SMatthias Ringwald                 bnep_emit_open_channel_complete(channel, status);
12263deb3ec6SMatthias Ringwald 
12273deb3ec6SMatthias Ringwald                 /* Free BNEP channel mempory */
12283deb3ec6SMatthias Ringwald                 bnep_channel_free(channel);
12293deb3ec6SMatthias Ringwald                 return 1;
12303deb3ec6SMatthias Ringwald             }
12313deb3ec6SMatthias Ringwald 
12323deb3ec6SMatthias Ringwald             switch (channel->state){
12333deb3ec6SMatthias Ringwald                 case BNEP_CHANNEL_STATE_CLOSED:
12343deb3ec6SMatthias Ringwald                     log_info("L2CAP_EVENT_CHANNEL_OPENED: outgoing connection");
12353deb3ec6SMatthias Ringwald 
12363deb3ec6SMatthias Ringwald                     bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS);
12373deb3ec6SMatthias Ringwald 
12383deb3ec6SMatthias Ringwald                     /* Assign connection handle and l2cap cid */
12393deb3ec6SMatthias Ringwald                     channel->l2cap_cid  = l2cap_cid;
12403deb3ec6SMatthias Ringwald                     channel->con_handle = con_handle;
12413deb3ec6SMatthias Ringwald 
12423deb3ec6SMatthias Ringwald                     /* Initiate the connection request */
12433deb3ec6SMatthias Ringwald                     channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE;
12443deb3ec6SMatthias Ringwald                     bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST);
1245f8fbdce0SMatthias Ringwald                     channel->max_frame_size = bnep_max_frame_size_for_l2cap_mtu(little_endian_read_16(packet, 17));
12463deb3ec6SMatthias Ringwald                     bnep_run();
12473deb3ec6SMatthias Ringwald                     break;
12483deb3ec6SMatthias Ringwald                 case BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST:
12493deb3ec6SMatthias Ringwald                     /* New information: channel mtu */
1250f8fbdce0SMatthias Ringwald                     channel->max_frame_size = bnep_max_frame_size_for_l2cap_mtu(little_endian_read_16(packet, 17));
12513deb3ec6SMatthias Ringwald                     break;
12523deb3ec6SMatthias Ringwald                 default:
12533deb3ec6SMatthias Ringwald                     log_error("L2CAP_EVENT_CHANNEL_OPENED: Invalid state: %d", channel->state);
12543deb3ec6SMatthias Ringwald                     break;
12553deb3ec6SMatthias Ringwald             }
12563deb3ec6SMatthias Ringwald             return 1;
12573deb3ec6SMatthias Ringwald 
12581b89a84bSMatthias Ringwald         case L2CAP_EVENT_CAN_SEND_NOW:
12593deb3ec6SMatthias Ringwald             bnep_run();
12603deb3ec6SMatthias Ringwald             break;
12613deb3ec6SMatthias Ringwald 
12623deb3ec6SMatthias Ringwald         case L2CAP_EVENT_CHANNEL_CLOSED:
12633deb3ec6SMatthias Ringwald             // data: event (8), len(8), channel (16)
1264f8fbdce0SMatthias Ringwald             l2cap_cid   = little_endian_read_16(packet, 2);
12653deb3ec6SMatthias Ringwald             channel = bnep_channel_for_l2cap_cid(l2cap_cid);
12663deb3ec6SMatthias Ringwald             log_info("L2CAP_EVENT_CHANNEL_CLOSED cid 0x%0x, channel %p", l2cap_cid, channel);
12673deb3ec6SMatthias Ringwald 
12683deb3ec6SMatthias Ringwald             if (!channel) {
12693deb3ec6SMatthias Ringwald                 break;
12703deb3ec6SMatthias Ringwald             }
12713deb3ec6SMatthias Ringwald 
12723deb3ec6SMatthias Ringwald             log_info("L2CAP_EVENT_CHANNEL_CLOSED state %u", channel->state);
12733deb3ec6SMatthias Ringwald             switch (channel->state) {
12743deb3ec6SMatthias Ringwald                 case BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST:
12753deb3ec6SMatthias Ringwald                 case BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE:
12763deb3ec6SMatthias Ringwald                 case BNEP_CHANNEL_STATE_CONNECTED:
12773deb3ec6SMatthias Ringwald                     bnep_channel_finalize(channel);
12783deb3ec6SMatthias Ringwald                     return 1;
12793deb3ec6SMatthias Ringwald                 default:
12803deb3ec6SMatthias Ringwald                     break;
12813deb3ec6SMatthias Ringwald             }
12823deb3ec6SMatthias Ringwald             break;
12833deb3ec6SMatthias Ringwald         default:
12843deb3ec6SMatthias Ringwald             bnep_run();
12853deb3ec6SMatthias Ringwald             break;
12863deb3ec6SMatthias Ringwald     }
12873deb3ec6SMatthias Ringwald     return 0;
12883deb3ec6SMatthias Ringwald }
12893deb3ec6SMatthias Ringwald 
12903deb3ec6SMatthias Ringwald static int bnep_l2cap_packet_handler(uint16_t l2cap_cid, uint8_t *packet, uint16_t size)
12913deb3ec6SMatthias Ringwald {
12923deb3ec6SMatthias Ringwald     int             rc = 0;
12933deb3ec6SMatthias Ringwald     uint8_t         bnep_type;
12943deb3ec6SMatthias Ringwald     uint8_t         bnep_header_has_ext;
12953deb3ec6SMatthias Ringwald     uint8_t         extension_type;
12963deb3ec6SMatthias Ringwald     uint16_t        pos = 0;
12973deb3ec6SMatthias Ringwald     bd_addr_t       addr_source;
12983deb3ec6SMatthias Ringwald     bd_addr_t       addr_dest;
12993deb3ec6SMatthias Ringwald     uint16_t        network_protocol_type = 0xffff;
13003deb3ec6SMatthias Ringwald     bnep_channel_t *channel = NULL;
13013deb3ec6SMatthias Ringwald 
13023deb3ec6SMatthias Ringwald     /* Get the bnep channel for this package */
13033deb3ec6SMatthias Ringwald     channel = bnep_channel_for_l2cap_cid(l2cap_cid);
13043deb3ec6SMatthias Ringwald     if (!channel) {
13053deb3ec6SMatthias Ringwald         return rc;
13063deb3ec6SMatthias Ringwald     }
13073deb3ec6SMatthias Ringwald 
13083deb3ec6SMatthias Ringwald     /* Sort out short packages */
13093deb3ec6SMatthias Ringwald     if (size < 2) {
13103deb3ec6SMatthias Ringwald         return rc;
13113deb3ec6SMatthias Ringwald     }
13123deb3ec6SMatthias Ringwald 
13133deb3ec6SMatthias Ringwald     bnep_type = BNEP_TYPE(packet[pos]);
13143deb3ec6SMatthias Ringwald     bnep_header_has_ext = BNEP_HEADER_HAS_EXT(packet[pos]);
13153deb3ec6SMatthias Ringwald     pos ++;
13163deb3ec6SMatthias Ringwald 
13173deb3ec6SMatthias Ringwald     switch(bnep_type) {
13183deb3ec6SMatthias Ringwald         case BNEP_PKT_TYPE_GENERAL_ETHERNET:
1319058e3d6bSMatthias Ringwald             bd_addr_copy(addr_dest, &packet[pos]);
13203deb3ec6SMatthias Ringwald             pos += sizeof(bd_addr_t);
1321058e3d6bSMatthias Ringwald             bd_addr_copy(addr_source, &packet[pos]);
13223deb3ec6SMatthias Ringwald             pos += sizeof(bd_addr_t);
1323f8fbdce0SMatthias Ringwald             network_protocol_type = big_endian_read_16(packet, pos);
13243deb3ec6SMatthias Ringwald             pos += 2;
13253deb3ec6SMatthias Ringwald             break;
13263deb3ec6SMatthias Ringwald         case BNEP_PKT_TYPE_COMPRESSED_ETHERNET:
1327058e3d6bSMatthias Ringwald             bd_addr_copy(addr_dest, channel->local_addr);
1328058e3d6bSMatthias Ringwald             bd_addr_copy(addr_source, channel->remote_addr);
1329f8fbdce0SMatthias Ringwald             network_protocol_type = big_endian_read_16(packet, pos);
13303deb3ec6SMatthias Ringwald             pos += 2;
13313deb3ec6SMatthias Ringwald             break;
13323deb3ec6SMatthias Ringwald         case BNEP_PKT_TYPE_COMPRESSED_ETHERNET_SOURCE_ONLY:
1333058e3d6bSMatthias Ringwald             bd_addr_copy(addr_dest, channel->local_addr);
1334058e3d6bSMatthias Ringwald             bd_addr_copy(addr_source, &packet[pos]);
13353deb3ec6SMatthias Ringwald             pos += sizeof(bd_addr_t);
1336f8fbdce0SMatthias Ringwald             network_protocol_type = big_endian_read_16(packet, pos);
13373deb3ec6SMatthias Ringwald             pos += 2;
13383deb3ec6SMatthias Ringwald             break;
13393deb3ec6SMatthias Ringwald         case BNEP_PKT_TYPE_COMPRESSED_ETHERNET_DEST_ONLY:
1340058e3d6bSMatthias Ringwald             bd_addr_copy(addr_dest, &packet[pos]);
13413deb3ec6SMatthias Ringwald             pos += sizeof(bd_addr_t);
1342058e3d6bSMatthias Ringwald             bd_addr_copy(addr_source, channel->remote_addr);
1343f8fbdce0SMatthias Ringwald             network_protocol_type = big_endian_read_16(packet, pos);
13443deb3ec6SMatthias Ringwald             pos += 2;
13453deb3ec6SMatthias Ringwald             break;
13463deb3ec6SMatthias Ringwald         case BNEP_PKT_TYPE_CONTROL:
13473deb3ec6SMatthias Ringwald             rc = bnep_handle_control_packet(channel, packet + pos, size - pos, 0);
13483deb3ec6SMatthias Ringwald             pos += rc;
13493deb3ec6SMatthias Ringwald             break;
13503deb3ec6SMatthias Ringwald         default:
13513deb3ec6SMatthias Ringwald             break;
13523deb3ec6SMatthias Ringwald     }
13533deb3ec6SMatthias Ringwald 
13543deb3ec6SMatthias Ringwald     if (bnep_header_has_ext) {
13553deb3ec6SMatthias Ringwald         do {
13563deb3ec6SMatthias Ringwald             uint8_t ext_len;
13573deb3ec6SMatthias Ringwald 
13583deb3ec6SMatthias Ringwald             /* Read extension type and check for further extensions */
13593deb3ec6SMatthias Ringwald             extension_type        = BNEP_TYPE(packet[pos]);
13603deb3ec6SMatthias Ringwald             bnep_header_has_ext   = BNEP_HEADER_HAS_EXT(packet[pos]);
13613deb3ec6SMatthias Ringwald             pos ++;
13623deb3ec6SMatthias Ringwald 
13633deb3ec6SMatthias Ringwald             /* Read extension header length */
13643deb3ec6SMatthias Ringwald             ext_len = packet[pos];
13653deb3ec6SMatthias Ringwald             pos ++;
13663deb3ec6SMatthias Ringwald 
13673deb3ec6SMatthias Ringwald             if (size - pos < ext_len) {
13683deb3ec6SMatthias Ringwald                 log_error("BNEP pkt handler: Invalid extension length! Packet ignored");
13693deb3ec6SMatthias Ringwald                 /* Invalid packet size! */
13703deb3ec6SMatthias Ringwald                 return 0;
13713deb3ec6SMatthias Ringwald             }
13723deb3ec6SMatthias Ringwald 
13733deb3ec6SMatthias Ringwald             switch (extension_type) {
13743deb3ec6SMatthias Ringwald                 case BNEP_EXT_HEADER_TYPE_EXTENSION_CONTROL:
13753deb3ec6SMatthias Ringwald                     if (ext_len != bnep_handle_control_packet(channel, packet + pos, ext_len, 1)) {
13763deb3ec6SMatthias Ringwald                         log_error("BNEP pkt handler: Ignore invalid control packet in extension header");
13773deb3ec6SMatthias Ringwald                     }
13783deb3ec6SMatthias Ringwald 
13793deb3ec6SMatthias Ringwald                     pos += ext_len;
13803deb3ec6SMatthias Ringwald                     break;
13813deb3ec6SMatthias Ringwald 
13823deb3ec6SMatthias Ringwald                 default:
13833deb3ec6SMatthias Ringwald                     /* Extension header type unknown. Unknown extension SHALL be
13843deb3ec6SMatthias Ringwald 			         * SHALL be forwarded in any way. But who shall handle these
13853deb3ec6SMatthias Ringwald                      * extension packets?
13863deb3ec6SMatthias Ringwald                      * For now: We ignore them and just drop them!
13873deb3ec6SMatthias Ringwald                      */
13883deb3ec6SMatthias Ringwald                     log_error("BNEP pkt handler: Unknown extension type ignored, data dropped!");
13893deb3ec6SMatthias Ringwald                     pos += ext_len;
13903deb3ec6SMatthias Ringwald                     break;
13913deb3ec6SMatthias Ringwald             }
13923deb3ec6SMatthias Ringwald 
13933deb3ec6SMatthias Ringwald         } while (bnep_header_has_ext);
13943deb3ec6SMatthias Ringwald     }
13953deb3ec6SMatthias Ringwald 
13963deb3ec6SMatthias Ringwald     if (bnep_type != BNEP_PKT_TYPE_CONTROL && network_protocol_type != 0xffff) {
13973deb3ec6SMatthias Ringwald         if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) {
13983deb3ec6SMatthias Ringwald             rc = bnep_handle_ethernet_packet(channel, addr_dest, addr_source, network_protocol_type, packet + pos, size - pos);
13993deb3ec6SMatthias Ringwald         } else {
14003deb3ec6SMatthias Ringwald             rc = 0;
14013deb3ec6SMatthias Ringwald         }
14023deb3ec6SMatthias Ringwald     }
14033deb3ec6SMatthias Ringwald 
14043deb3ec6SMatthias Ringwald     return rc;
14053deb3ec6SMatthias Ringwald 
14063deb3ec6SMatthias Ringwald }
14073deb3ec6SMatthias Ringwald 
14083deb3ec6SMatthias Ringwald void bnep_packet_handler(uint8_t packet_type, uint16_t l2cap_cid, uint8_t *packet, uint16_t size)
14093deb3ec6SMatthias Ringwald {
14103deb3ec6SMatthias Ringwald     int handled = 0;
14113deb3ec6SMatthias Ringwald     switch (packet_type) {
14123deb3ec6SMatthias Ringwald         case HCI_EVENT_PACKET:
14133deb3ec6SMatthias Ringwald             handled = bnep_hci_event_handler(packet, size);
14143deb3ec6SMatthias Ringwald             break;
14153deb3ec6SMatthias Ringwald         case L2CAP_DATA_PACKET:
14163deb3ec6SMatthias Ringwald             handled = bnep_l2cap_packet_handler(l2cap_cid, packet, size);
14173deb3ec6SMatthias Ringwald             break;
14183deb3ec6SMatthias Ringwald         default:
14193deb3ec6SMatthias Ringwald             break;
14203deb3ec6SMatthias Ringwald     }
14213deb3ec6SMatthias Ringwald 
14223deb3ec6SMatthias Ringwald     bnep_run();
14233deb3ec6SMatthias Ringwald }
14243deb3ec6SMatthias Ringwald 
14253deb3ec6SMatthias Ringwald static void bnep_channel_state_machine(bnep_channel_t* channel, bnep_channel_event_t *event)
14263deb3ec6SMatthias Ringwald {
14273deb3ec6SMatthias Ringwald     log_info("bnep_state_machine: state %u, state var: %02x, event %u", channel->state, channel->state_var, event->type);
14283deb3ec6SMatthias Ringwald 
14293deb3ec6SMatthias Ringwald     if (event->type == BNEP_CH_EVT_READY_TO_SEND) {
14303deb3ec6SMatthias Ringwald         /* Send outstanding packets. */
14313deb3ec6SMatthias Ringwald         if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_NOT_UNDERSTOOD) {
14323deb3ec6SMatthias Ringwald             bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_NOT_UNDERSTOOD);
14333deb3ec6SMatthias Ringwald             bnep_send_command_not_understood(channel, channel->last_control_type);
14343deb3ec6SMatthias Ringwald             return;
14353deb3ec6SMatthias Ringwald         }
14363deb3ec6SMatthias Ringwald         if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST) {
14373deb3ec6SMatthias Ringwald             bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST);
14383deb3ec6SMatthias Ringwald             channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE;
14393deb3ec6SMatthias Ringwald             bnep_send_connection_request(channel, channel->uuid_source, channel->uuid_dest);
14403deb3ec6SMatthias Ringwald         }
14413deb3ec6SMatthias Ringwald         if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE) {
14423deb3ec6SMatthias Ringwald             int emit_connected = 0;
14433deb3ec6SMatthias Ringwald             if ((channel->state == BNEP_CHANNEL_STATE_CLOSED) ||
14443deb3ec6SMatthias Ringwald                 (channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST)) {
14453deb3ec6SMatthias Ringwald                 /* Set channel state to STATE_CONNECTED */
14463deb3ec6SMatthias Ringwald                 channel->state = BNEP_CHANNEL_STATE_CONNECTED;
14473deb3ec6SMatthias Ringwald                 /* Stop timeout timer! */
14483deb3ec6SMatthias Ringwald                 bnep_channel_stop_timer(channel);
14493deb3ec6SMatthias Ringwald                 emit_connected = 1;
14503deb3ec6SMatthias Ringwald             }
14513deb3ec6SMatthias Ringwald 
14523deb3ec6SMatthias Ringwald             bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE);
14533deb3ec6SMatthias Ringwald             bnep_send_connection_response(channel, channel->response_code);
14543deb3ec6SMatthias Ringwald             if (emit_connected){
14553deb3ec6SMatthias Ringwald                 bnep_emit_open_channel_complete(channel, 0);
14563deb3ec6SMatthias Ringwald             }
14573deb3ec6SMatthias Ringwald             return;
14583deb3ec6SMatthias Ringwald         }
14593deb3ec6SMatthias Ringwald         if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_SET) {
14603deb3ec6SMatthias Ringwald             bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_SET);
14613deb3ec6SMatthias Ringwald             if ((channel->net_filter_out_count > 0) && (channel->net_filter_out != NULL)) {
14623deb3ec6SMatthias Ringwald                 bnep_send_filter_net_type_set(channel, channel->net_filter_out, channel->net_filter_out_count);
14633deb3ec6SMatthias Ringwald                 channel->net_filter_out_count = 0;
14643deb3ec6SMatthias Ringwald                 channel->net_filter_out = NULL;
14653deb3ec6SMatthias Ringwald             }
14663deb3ec6SMatthias Ringwald             return;
14673deb3ec6SMatthias Ringwald         }
14683deb3ec6SMatthias Ringwald         if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_RESPONSE) {
14693deb3ec6SMatthias Ringwald             bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_RESPONSE);
14703deb3ec6SMatthias Ringwald             bnep_send_filter_net_type_response(channel, channel->response_code);
14713deb3ec6SMatthias Ringwald             return;
14723deb3ec6SMatthias Ringwald         }
14733deb3ec6SMatthias Ringwald         if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_SET) {
14743deb3ec6SMatthias Ringwald             bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_SET);
14753deb3ec6SMatthias Ringwald             if ((channel->multicast_filter_out_count > 0) && (channel->multicast_filter_out != NULL)) {
14763deb3ec6SMatthias Ringwald                 bnep_send_filter_multi_addr_set(channel, channel->multicast_filter_out, channel->multicast_filter_out_count);
14773deb3ec6SMatthias Ringwald                 channel->multicast_filter_out_count = 0;
14783deb3ec6SMatthias Ringwald                 channel->multicast_filter_out = NULL;
14793deb3ec6SMatthias Ringwald             }
14803deb3ec6SMatthias Ringwald             return;
14813deb3ec6SMatthias Ringwald         }
14823deb3ec6SMatthias Ringwald         if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_RESPONSE) {
14833deb3ec6SMatthias Ringwald             bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_RESPONSE);
14843deb3ec6SMatthias Ringwald             bnep_send_filter_multi_addr_response(channel, channel->response_code);
14853deb3ec6SMatthias Ringwald             return;
14863deb3ec6SMatthias Ringwald         }
14873deb3ec6SMatthias Ringwald 
14883deb3ec6SMatthias Ringwald 
14893deb3ec6SMatthias Ringwald         /* If the event was not yet handled, notify the application layer */
14903deb3ec6SMatthias Ringwald         bnep_emit_ready_to_send(channel);
14913deb3ec6SMatthias Ringwald     }
14923deb3ec6SMatthias Ringwald }
14933deb3ec6SMatthias Ringwald 
14943deb3ec6SMatthias Ringwald 
14953deb3ec6SMatthias Ringwald /* Process oustanding signaling tasks */
14963deb3ec6SMatthias Ringwald static void bnep_run(void)
14973deb3ec6SMatthias Ringwald {
1498665d90f2SMatthias Ringwald     btstack_linked_item_t *it;
1499665d90f2SMatthias Ringwald     btstack_linked_item_t *next;
15003deb3ec6SMatthias Ringwald 
1501665d90f2SMatthias Ringwald     for (it = (btstack_linked_item_t *) bnep_channels; it ; it = next){
15023deb3ec6SMatthias Ringwald 
15033deb3ec6SMatthias Ringwald         next = it->next;    // be prepared for removal of channel in state machine
15043deb3ec6SMatthias Ringwald 
15053deb3ec6SMatthias Ringwald         bnep_channel_t * channel = ((bnep_channel_t *) it);
15063deb3ec6SMatthias Ringwald 
15073deb3ec6SMatthias Ringwald         if (!l2cap_can_send_packet_now(channel->l2cap_cid)) {
15083deb3ec6SMatthias Ringwald             continue;
15093deb3ec6SMatthias Ringwald         }
15103deb3ec6SMatthias Ringwald 
15113deb3ec6SMatthias Ringwald         bnep_channel_event_t channel_event = { BNEP_CH_EVT_READY_TO_SEND };
15123deb3ec6SMatthias Ringwald         bnep_channel_state_machine(channel, &channel_event);
15133deb3ec6SMatthias Ringwald     }
15143deb3ec6SMatthias Ringwald }
15153deb3ec6SMatthias Ringwald 
15163deb3ec6SMatthias Ringwald /* BNEP BTStack API */
15173deb3ec6SMatthias Ringwald void bnep_init(void)
15183deb3ec6SMatthias Ringwald {
15193deb3ec6SMatthias Ringwald     bnep_security_level = LEVEL_0;
15203deb3ec6SMatthias Ringwald }
15213deb3ec6SMatthias Ringwald 
15223deb3ec6SMatthias Ringwald void bnep_set_required_security_level(gap_security_level_t security_level)
15233deb3ec6SMatthias Ringwald {
15243deb3ec6SMatthias Ringwald     bnep_security_level = security_level;
15253deb3ec6SMatthias Ringwald }
15263deb3ec6SMatthias Ringwald 
15273deb3ec6SMatthias Ringwald /* Register application packet handler */
15280cc6429eSMatthias Ringwald void bnep_register_packet_handler(void (*handler)(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)){
15293deb3ec6SMatthias Ringwald 	app_packet_handler = handler;
15303deb3ec6SMatthias Ringwald }
15313deb3ec6SMatthias Ringwald 
15320cc6429eSMatthias Ringwald int bnep_connect(bd_addr_t addr, uint16_t l2cap_psm, uint16_t uuid_src, uint16_t uuid_dest)
15333deb3ec6SMatthias Ringwald {
15343deb3ec6SMatthias Ringwald     bnep_channel_t *channel;
15353deb3ec6SMatthias Ringwald     log_info("BNEP_CONNECT addr %s", bd_addr_to_str(addr));
15363deb3ec6SMatthias Ringwald 
15373deb3ec6SMatthias Ringwald     channel = bnep_channel_create_for_addr(addr);
15383deb3ec6SMatthias Ringwald     if (channel == NULL) {
15393deb3ec6SMatthias Ringwald         return -1;
15403deb3ec6SMatthias Ringwald     }
15413deb3ec6SMatthias Ringwald 
15423deb3ec6SMatthias Ringwald     channel->uuid_source = uuid_src;
15433deb3ec6SMatthias Ringwald     channel->uuid_dest   = uuid_dest;
15443deb3ec6SMatthias Ringwald 
154590a28bdeSMatthias Ringwald     uint8_t status = l2cap_create_channel(bnep_packet_handler, addr, l2cap_psm, l2cap_max_mtu(), NULL);
154690a28bdeSMatthias Ringwald     if (status){
154790a28bdeSMatthias Ringwald         return -1;
154890a28bdeSMatthias Ringwald     }
15493deb3ec6SMatthias Ringwald     return 0;
15503deb3ec6SMatthias Ringwald }
15513deb3ec6SMatthias Ringwald 
15523deb3ec6SMatthias Ringwald void bnep_disconnect(bd_addr_t addr)
15533deb3ec6SMatthias Ringwald {
15543deb3ec6SMatthias Ringwald     bnep_channel_t *channel;
15553deb3ec6SMatthias Ringwald     log_info("BNEP_DISCONNECT");
15563deb3ec6SMatthias Ringwald 
15573deb3ec6SMatthias Ringwald     channel = bnep_channel_for_addr(addr);
15583deb3ec6SMatthias Ringwald 
15593deb3ec6SMatthias Ringwald     bnep_channel_finalize(channel);
15603deb3ec6SMatthias Ringwald 
15613deb3ec6SMatthias Ringwald     bnep_run();
15623deb3ec6SMatthias Ringwald }
15633deb3ec6SMatthias Ringwald 
15643deb3ec6SMatthias Ringwald 
15650cc6429eSMatthias Ringwald uint8_t bnep_register_service(uint16_t service_uuid, uint16_t max_frame_size)
15663deb3ec6SMatthias Ringwald {
15673deb3ec6SMatthias Ringwald     log_info("BNEP_REGISTER_SERVICE mtu %d", max_frame_size);
15683deb3ec6SMatthias Ringwald 
15693deb3ec6SMatthias Ringwald     /* Check if we already registered a service */
15703deb3ec6SMatthias Ringwald     bnep_service_t * service = bnep_service_for_uuid(service_uuid);
15713deb3ec6SMatthias Ringwald     if (service) {
15720cc6429eSMatthias Ringwald         return BNEP_SERVICE_ALREADY_REGISTERED;
15733deb3ec6SMatthias Ringwald     }
15743deb3ec6SMatthias Ringwald 
15753deb3ec6SMatthias Ringwald     /* Only alow one the three service types: PANU, NAP, GN */
15763deb3ec6SMatthias Ringwald     if ((service_uuid != SDP_PANU) &&
15773deb3ec6SMatthias Ringwald         (service_uuid != SDP_NAP) &&
15783deb3ec6SMatthias Ringwald         (service_uuid != SDP_GN)) {
15793deb3ec6SMatthias Ringwald         log_info("BNEP_REGISTER_SERVICE: Invalid service UUID: %04x", service_uuid);
15800cc6429eSMatthias Ringwald         return BNEP_SERVICE_ALREADY_REGISTERED; // TODO: define own error
15813deb3ec6SMatthias Ringwald     }
15823deb3ec6SMatthias Ringwald 
15833deb3ec6SMatthias Ringwald     /* Allocate service memory */
15843deb3ec6SMatthias Ringwald     service = (bnep_service_t*) btstack_memory_bnep_service_get();
15853deb3ec6SMatthias Ringwald     if (!service) {
15860cc6429eSMatthias Ringwald         return BTSTACK_MEMORY_ALLOC_FAILED;
15873deb3ec6SMatthias Ringwald     }
15883deb3ec6SMatthias Ringwald     memset(service, 0, sizeof(bnep_service_t));
15893deb3ec6SMatthias Ringwald 
15903deb3ec6SMatthias Ringwald     /* register with l2cap if not registered before, max MTU */
1591be2053a6SMatthias Ringwald     l2cap_register_service(bnep_packet_handler, PSM_BNEP, 0xffff, bnep_security_level);
15923deb3ec6SMatthias Ringwald 
15933deb3ec6SMatthias Ringwald     /* Setup the service struct */
15943deb3ec6SMatthias Ringwald     service->max_frame_size = max_frame_size;
15953deb3ec6SMatthias Ringwald     service->service_uuid    = service_uuid;
15963deb3ec6SMatthias Ringwald 
15973deb3ec6SMatthias Ringwald     /* Add to services list */
1598665d90f2SMatthias Ringwald     btstack_linked_list_add(&bnep_services, (btstack_linked_item_t *) service);
15993deb3ec6SMatthias Ringwald 
16000cc6429eSMatthias Ringwald     return 0;
16013deb3ec6SMatthias Ringwald }
16023deb3ec6SMatthias Ringwald 
16033deb3ec6SMatthias Ringwald void bnep_unregister_service(uint16_t service_uuid)
16043deb3ec6SMatthias Ringwald {
16053deb3ec6SMatthias Ringwald     log_info("BNEP_UNREGISTER_SERVICE #%04x", service_uuid);
16063deb3ec6SMatthias Ringwald 
16073deb3ec6SMatthias Ringwald     bnep_service_t *service = bnep_service_for_uuid(service_uuid);
16083deb3ec6SMatthias Ringwald     if (!service) {
16093deb3ec6SMatthias Ringwald         return;
16103deb3ec6SMatthias Ringwald     }
16113deb3ec6SMatthias Ringwald 
1612665d90f2SMatthias Ringwald     btstack_linked_list_remove(&bnep_services, (btstack_linked_item_t *) service);
16133deb3ec6SMatthias Ringwald     btstack_memory_bnep_service_free(service);
16143deb3ec6SMatthias Ringwald     service = NULL;
16153deb3ec6SMatthias Ringwald 
161602f83142SMatthias Ringwald     l2cap_unregister_service(PSM_BNEP);
16173deb3ec6SMatthias Ringwald }
16183deb3ec6SMatthias Ringwald 
1619