2014-10-08 13:21:40 +00:00
|
|
|
/*
|
2015-02-06 10:45:10 +00:00
|
|
|
* Copyright (C) 2014 BlueKitchen GmbH
|
|
|
|
*
|
2014-10-08 13:21:40 +00:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the copyright holders nor the names of
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
* 4. Any redistribution, use, or modification is done solely for
|
|
|
|
* personal benefit and not for any commercial purpose or for
|
|
|
|
* monetary gain.
|
|
|
|
*
|
2015-02-06 10:45:10 +00:00
|
|
|
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
2014-10-08 13:21:40 +00:00
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
2015-02-06 10:45:10 +00:00
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
|
|
|
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
2014-10-08 13:21:40 +00:00
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
|
|
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
2015-02-06 10:45:10 +00:00
|
|
|
* Please inquire about commercial licensing options at
|
|
|
|
* contact@bluekitchen-gmbh.com
|
2014-10-08 13:21:40 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2015-02-06 10:45:10 +00:00
|
|
|
* bnep.c
|
|
|
|
* Author: Ole Reinhardt <ole.reinhardt@kernelconcepts.de>
|
|
|
|
*
|
2014-10-08 13:21:40 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h> // memcpy
|
|
|
|
#include <stdint.h>
|
|
|
|
|
|
|
|
#include <btstack/btstack.h>
|
|
|
|
#include <btstack/hci_cmds.h>
|
|
|
|
#include <btstack/utils.h>
|
2015-02-13 09:28:39 +00:00
|
|
|
#include <btstack/sdp_util.h>
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
#include "btstack_memory.h"
|
|
|
|
#include "hci.h"
|
|
|
|
#include "hci_dump.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "bnep.h"
|
|
|
|
|
|
|
|
#include "l2cap.h"
|
|
|
|
|
2014-11-13 00:28:01 +00:00
|
|
|
#define BNEP_CONNECTION_TIMEOUT_MS 10000
|
2014-12-11 22:16:42 +00:00
|
|
|
#define BNEP_CONNECTION_MAX_RETRIES 1
|
2014-10-20 10:06:38 +00:00
|
|
|
|
2014-10-16 22:58:52 +00:00
|
|
|
static linked_list_t bnep_services = NULL;
|
2014-10-08 13:21:40 +00:00
|
|
|
static linked_list_t bnep_channels = NULL;
|
|
|
|
|
|
|
|
static gap_security_level_t bnep_security_level;
|
|
|
|
|
|
|
|
static void (*app_packet_handler)(void * connection, uint8_t packet_type,
|
|
|
|
uint16_t channel, uint8_t *packet, uint16_t size);
|
|
|
|
|
|
|
|
|
2014-10-28 01:16:50 +00:00
|
|
|
static bnep_channel_t * bnep_channel_for_l2cap_cid(uint16_t l2cap_cid);
|
2014-11-13 00:28:01 +00:00
|
|
|
static void bnep_channel_finalize(bnep_channel_t *channel);
|
2014-10-16 09:45:36 +00:00
|
|
|
static void bnep_run(void);
|
2014-12-11 22:16:42 +00:00
|
|
|
static void bnep_channel_start_timer(bnep_channel_t *channel, int timeout);
|
|
|
|
inline static void bnep_channel_state_add(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event);
|
2014-10-16 09:45:36 +00:00
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* Emit service registered event */
|
2014-10-20 10:06:07 +00:00
|
|
|
static void bnep_emit_service_registered(void *connection, uint8_t status, uint16_t service_uuid)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
2014-10-20 10:06:07 +00:00
|
|
|
log_info("BNEP_EVENT_SERVICE_REGISTERED status 0x%02x, uuid: 0x%04x", status, service_uuid);
|
|
|
|
uint8_t event[5];
|
2014-10-08 13:21:40 +00:00
|
|
|
event[0] = BNEP_EVENT_SERVICE_REGISTERED;
|
|
|
|
event[1] = sizeof(event) - 2;
|
|
|
|
event[2] = status;
|
2014-10-20 10:06:07 +00:00
|
|
|
bt_store_16(event, 3, service_uuid);
|
2014-10-08 13:21:40 +00:00
|
|
|
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
|
|
|
(*app_packet_handler)(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
|
|
|
|
}
|
|
|
|
|
2014-10-20 10:06:38 +00:00
|
|
|
static void bnep_emit_open_channel_complete(bnep_channel_t *channel, uint8_t status)
|
2014-10-20 10:06:07 +00:00
|
|
|
{
|
|
|
|
log_info("BNEP_EVENT_OPEN_CHANNEL_COMPLETE status 0x%02x bd_addr: %s", status, bd_addr_to_str(channel->remote_addr));
|
2014-10-20 10:06:38 +00:00
|
|
|
uint8_t event[3 + sizeof(bd_addr_t) + 3 * sizeof(uint16_t)];
|
|
|
|
event[0] = BNEP_EVENT_OPEN_CHANNEL_COMPLETE;
|
2014-10-20 10:06:07 +00:00
|
|
|
event[1] = sizeof(event) - 2;
|
|
|
|
event[2] = status;
|
|
|
|
bt_store_16(event, 3, channel->uuid_source);
|
|
|
|
bt_store_16(event, 5, channel->uuid_dest);
|
2014-10-20 10:06:38 +00:00
|
|
|
bt_store_16(event, 7, channel->max_frame_size);
|
2014-10-27 11:49:47 +00:00
|
|
|
BD_ADDR_COPY(&event[9], channel->remote_addr);
|
2014-10-20 10:06:07 +00:00
|
|
|
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
2014-10-28 01:16:50 +00:00
|
|
|
(*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event));
|
2014-10-20 10:06:07 +00:00
|
|
|
}
|
|
|
|
|
2014-11-13 00:28:01 +00:00
|
|
|
static void bnep_emit_channel_timeout(bnep_channel_t *channel)
|
|
|
|
{
|
|
|
|
log_info("BNEP_EVENT_CHANNEL_TIMEOUT bd_addr: %s", bd_addr_to_str(channel->remote_addr));
|
|
|
|
uint8_t event[2 + sizeof(bd_addr_t) + 2 * sizeof(uint16_t) + sizeof(uint8_t)];
|
|
|
|
event[0] = BNEP_EVENT_CHANNEL_TIMEOUT;
|
|
|
|
event[1] = sizeof(event) - 2;
|
|
|
|
bt_store_16(event, 2, channel->uuid_source);
|
|
|
|
bt_store_16(event, 4, channel->uuid_dest);
|
|
|
|
BD_ADDR_COPY(&event[6], channel->remote_addr);
|
|
|
|
event[12] = channel->state;
|
|
|
|
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
|
|
|
(*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event));
|
|
|
|
}
|
|
|
|
|
2014-10-20 10:06:07 +00:00
|
|
|
static void bnep_emit_channel_closed(bnep_channel_t *channel)
|
|
|
|
{
|
|
|
|
log_info("BNEP_EVENT_CHANNEL_CLOSED bd_addr: %s", bd_addr_to_str(channel->remote_addr));
|
|
|
|
uint8_t event[2 + sizeof(bd_addr_t) + 2 * sizeof(uint16_t)];
|
|
|
|
event[0] = BNEP_EVENT_CHANNEL_CLOSED;
|
|
|
|
event[1] = sizeof(event) - 2;
|
|
|
|
bt_store_16(event, 2, channel->uuid_source);
|
|
|
|
bt_store_16(event, 4, channel->uuid_dest);
|
2014-10-27 11:49:47 +00:00
|
|
|
BD_ADDR_COPY(&event[6], channel->remote_addr);
|
2014-10-20 10:06:07 +00:00
|
|
|
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
2014-10-28 01:16:50 +00:00
|
|
|
(*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bnep_emit_ready_to_send(bnep_channel_t *channel)
|
|
|
|
{
|
|
|
|
uint8_t event[2];
|
|
|
|
event[0] = BNEP_EVENT_READY_TO_SEND;
|
|
|
|
event[1] = sizeof(event) - 2;
|
|
|
|
hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event));
|
|
|
|
(*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event));
|
2014-10-20 10:06:07 +00:00
|
|
|
}
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* Send BNEP connection request */
|
|
|
|
static int bnep_send_command_not_understood(bnep_channel_t *channel, uint8_t control_type)
|
|
|
|
{
|
|
|
|
uint8_t *bnep_out_buffer = NULL;
|
|
|
|
uint16_t pos = 0;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
|
|
|
|
return -1; // TODO
|
|
|
|
}
|
2014-10-16 09:45:36 +00:00
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
l2cap_reserve_packet_buffer();
|
|
|
|
bnep_out_buffer = l2cap_get_outgoing_buffer();
|
|
|
|
|
|
|
|
/* Setup control packet type */
|
|
|
|
bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
|
|
|
|
bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_COMMAND_NOT_UNDERSTOOD;
|
|
|
|
|
|
|
|
/* Add not understood control type */
|
|
|
|
bnep_out_buffer[pos++] = control_type;
|
|
|
|
|
|
|
|
err = l2cap_send_prepared(channel->l2cap_cid, pos);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
// TODO: Log error
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Send BNEP connection request */
|
2014-10-20 10:06:07 +00:00
|
|
|
static int bnep_send_connection_request(bnep_channel_t *channel, uint16_t uuid_source, uint16_t uuid_dest)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
|
|
|
uint8_t *bnep_out_buffer = NULL;
|
|
|
|
uint16_t pos = 0;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
|
|
|
|
return -1; // TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
l2cap_reserve_packet_buffer();
|
|
|
|
bnep_out_buffer = l2cap_get_outgoing_buffer();
|
|
|
|
|
|
|
|
/* Setup control packet type */
|
|
|
|
bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
|
|
|
|
bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_SETUP_CONNECTION_REQUEST;
|
|
|
|
|
|
|
|
/* Add UUID Size */
|
|
|
|
bnep_out_buffer[pos++] = 2;
|
|
|
|
|
|
|
|
/* Add dest and source UUID */
|
2014-12-10 23:28:03 +00:00
|
|
|
net_store_16(bnep_out_buffer, pos, uuid_dest);
|
|
|
|
pos += 2;
|
|
|
|
|
|
|
|
net_store_16(bnep_out_buffer, pos, uuid_source);
|
|
|
|
pos += 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
err = l2cap_send_prepared(channel->l2cap_cid, pos);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
// TODO: Log error
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send BNEP connection response */
|
2014-10-20 10:06:07 +00:00
|
|
|
static int bnep_send_connection_response(bnep_channel_t *channel, uint16_t response_code)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
|
|
|
uint8_t *bnep_out_buffer = NULL;
|
|
|
|
uint16_t pos = 0;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
|
|
|
|
return -1; // TODO
|
|
|
|
}
|
|
|
|
|
|
|
|
l2cap_reserve_packet_buffer();
|
|
|
|
bnep_out_buffer = l2cap_get_outgoing_buffer();
|
|
|
|
|
|
|
|
/* Setup control packet type */
|
|
|
|
bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
|
|
|
|
bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_SETUP_CONNECTION_RESPONSE;
|
|
|
|
|
|
|
|
/* Add response code */
|
2014-12-10 23:28:03 +00:00
|
|
|
net_store_16(bnep_out_buffer, pos, response_code);
|
|
|
|
pos += 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
err = l2cap_send_prepared(channel->l2cap_cid, pos);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
// TODO: Log error
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send BNEP filter net type set message */
|
2015-01-02 01:13:53 +00:00
|
|
|
static int bnep_send_filter_net_type_set(bnep_channel_t *channel, bnep_net_filter_t *filter, uint16_t len)
|
2014-10-20 10:06:07 +00:00
|
|
|
{
|
2015-01-02 01:13:53 +00:00
|
|
|
uint8_t *bnep_out_buffer = NULL;
|
|
|
|
uint16_t pos = 0;
|
|
|
|
int err = 0;
|
|
|
|
int i;
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
|
2015-01-02 01:13:53 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
l2cap_reserve_packet_buffer();
|
|
|
|
bnep_out_buffer = l2cap_get_outgoing_buffer();
|
|
|
|
|
|
|
|
/* Setup control packet type */
|
|
|
|
bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
|
|
|
|
bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_NET_TYPE_SET;
|
|
|
|
|
|
|
|
net_store_16(bnep_out_buffer, pos, len * 2 * 2);
|
|
|
|
pos += 2;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i ++) {
|
|
|
|
net_store_16(bnep_out_buffer, pos, filter[i].range_start);
|
|
|
|
pos += 2;
|
|
|
|
net_store_16(bnep_out_buffer, pos, filter[i].range_end);
|
|
|
|
pos += 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2015-01-02 01:13:53 +00:00
|
|
|
err = l2cap_send_prepared(channel->l2cap_cid, pos);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
2015-01-02 01:13:53 +00:00
|
|
|
if (err) {
|
|
|
|
// TODO: Log error
|
|
|
|
}
|
|
|
|
return err;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Send BNEP filter net type response message */
|
2014-10-20 10:06:07 +00:00
|
|
|
static int bnep_send_filter_net_type_response(bnep_channel_t *channel, uint16_t response_code)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
|
|
|
uint8_t *bnep_out_buffer = NULL;
|
|
|
|
uint16_t pos = 0;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
|
2015-01-02 01:13:53 +00:00
|
|
|
return -1;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
l2cap_reserve_packet_buffer();
|
|
|
|
bnep_out_buffer = l2cap_get_outgoing_buffer();
|
|
|
|
|
|
|
|
/* Setup control packet type */
|
|
|
|
bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
|
|
|
|
bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_NET_TYPE_RESPONSE;
|
|
|
|
|
|
|
|
/* Add response code */
|
2014-12-10 23:28:03 +00:00
|
|
|
net_store_16(bnep_out_buffer, pos, response_code);
|
|
|
|
pos += 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
err = l2cap_send_prepared(channel->l2cap_cid, pos);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
// TODO: Log error
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send BNEP filter multicast address set message */
|
2015-01-02 01:13:53 +00:00
|
|
|
|
|
|
|
static int bnep_send_filter_multi_addr_set(bnep_channel_t *channel, bnep_multi_filter_t *filter, uint16_t len)
|
|
|
|
{
|
|
|
|
uint8_t *bnep_out_buffer = NULL;
|
|
|
|
uint16_t pos = 0;
|
|
|
|
int err = 0;
|
|
|
|
int i;
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
|
2015-01-02 01:13:53 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
l2cap_reserve_packet_buffer();
|
|
|
|
bnep_out_buffer = l2cap_get_outgoing_buffer();
|
|
|
|
|
|
|
|
/* Setup control packet type */
|
|
|
|
bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
|
|
|
|
bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_SET;
|
|
|
|
|
|
|
|
net_store_16(bnep_out_buffer, pos, len * 2 * ETHER_ADDR_LEN);
|
|
|
|
pos += 2;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i ++) {
|
|
|
|
BD_ADDR_COPY(bnep_out_buffer + pos, filter[i].addr_start);
|
|
|
|
pos += ETHER_ADDR_LEN;
|
|
|
|
BD_ADDR_COPY(bnep_out_buffer + pos, filter[i].addr_end);
|
|
|
|
pos += ETHER_ADDR_LEN;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2015-01-02 01:13:53 +00:00
|
|
|
err = l2cap_send_prepared(channel->l2cap_cid, pos);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
2015-01-02 01:13:53 +00:00
|
|
|
if (err) {
|
|
|
|
// TODO: Log error
|
|
|
|
}
|
|
|
|
return err;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Send BNEP filter multicast address response message */
|
2014-10-20 10:06:07 +00:00
|
|
|
static int bnep_send_filter_multi_addr_response(bnep_channel_t *channel, uint16_t response_code)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
|
|
|
uint8_t *bnep_out_buffer = NULL;
|
|
|
|
uint16_t pos = 0;
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CLOSED) {
|
2015-01-02 01:13:53 +00:00
|
|
|
return -1;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
l2cap_reserve_packet_buffer();
|
|
|
|
bnep_out_buffer = l2cap_get_outgoing_buffer();
|
|
|
|
|
|
|
|
/* Setup control packet type */
|
|
|
|
bnep_out_buffer[pos++] = BNEP_PKT_TYPE_CONTROL;
|
|
|
|
bnep_out_buffer[pos++] = BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_RESPONSE;
|
|
|
|
|
|
|
|
/* Add response code */
|
2014-12-10 23:28:03 +00:00
|
|
|
net_store_16(bnep_out_buffer, pos, response_code);
|
|
|
|
pos += 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
err = l2cap_send_prepared(channel->l2cap_cid, pos);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
// TODO: Log error
|
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2014-10-28 01:16:50 +00:00
|
|
|
int bnep_can_send_packet_now(uint16_t bnep_cid)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
2014-10-28 01:16:50 +00:00
|
|
|
bnep_channel_t *channel = bnep_channel_for_l2cap_cid(bnep_cid);
|
|
|
|
|
|
|
|
if (!channel){
|
|
|
|
log_error("bnep_can_send_packet_now cid 0x%02x doesn't exist!", bnep_cid);
|
|
|
|
return 0;
|
|
|
|
}
|
2014-10-08 13:21:40 +00:00
|
|
|
|
2014-10-28 01:16:50 +00:00
|
|
|
return l2cap_can_send_packet_now(channel->l2cap_cid);
|
|
|
|
}
|
|
|
|
|
2015-01-02 01:13:53 +00:00
|
|
|
|
|
|
|
static int bnep_filter_protocol(bnep_channel_t *channel, uint16_t network_protocol_type)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (channel->net_filter_count == 0) {
|
2015-01-04 00:19:28 +00:00
|
|
|
/* No filter set */
|
2015-01-02 01:13:53 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2015-01-04 00:19:28 +00:00
|
|
|
|
2015-01-02 01:13:53 +00:00
|
|
|
for (i = 0; i < channel->net_filter_count; i ++) {
|
|
|
|
if ((network_protocol_type >= channel->net_filter[i].range_start) &&
|
|
|
|
(network_protocol_type <= channel->net_filter[i].range_end)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bnep_filter_multicast(bnep_channel_t *channel, bd_addr_t addr_dest)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Check if the multicast flag is set int the destination address */
|
2015-01-04 00:19:28 +00:00
|
|
|
if ((addr_dest[0] & 0x01) == 0x00) {
|
2015-01-02 01:13:53 +00:00
|
|
|
/* Not a multicast frame, do not apply filtering and send it in any case */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-01-04 00:19:28 +00:00
|
|
|
if (channel->multicast_filter_count == 0) {
|
|
|
|
/* No filter set */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-01-02 01:13:53 +00:00
|
|
|
for (i = 0; i < channel->multicast_filter_count; i ++) {
|
|
|
|
if ((memcmp(addr_dest, channel->multicast_filter[i].addr_start, sizeof(bd_addr_t)) >= 0) &&
|
|
|
|
(memcmp(addr_dest, channel->multicast_filter[i].addr_end, sizeof(bd_addr_t)) <= 0)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-10-28 01:16:50 +00:00
|
|
|
/* Send BNEP ethernet packet */
|
|
|
|
int bnep_send(uint16_t bnep_cid, uint8_t *packet, uint16_t len)
|
|
|
|
{
|
|
|
|
bnep_channel_t *channel;
|
|
|
|
uint8_t *bnep_out_buffer = NULL;
|
|
|
|
uint16_t pos = 0;
|
|
|
|
uint16_t pos_out = 0;
|
2015-01-02 01:13:53 +00:00
|
|
|
uint16_t payload_len;
|
2014-10-28 01:16:50 +00:00
|
|
|
int err = 0;
|
|
|
|
int has_source;
|
|
|
|
int has_dest;
|
|
|
|
|
|
|
|
bd_addr_t addr_dest;
|
|
|
|
bd_addr_t addr_source;
|
|
|
|
uint16_t network_protocol_type;
|
|
|
|
|
|
|
|
channel = bnep_channel_for_l2cap_cid(bnep_cid);
|
|
|
|
if (channel == NULL) {
|
2015-01-02 01:13:53 +00:00
|
|
|
log_error("bnep_send cid 0x%02x doesn't exist!", bnep_cid);
|
2014-10-28 01:16:50 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (channel->state != BNEP_CHANNEL_STATE_CONNECTED) {
|
|
|
|
return BNEP_CHANNEL_NOT_CONNECTED;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for free ACL buffers */
|
|
|
|
if (!l2cap_can_send_packet_now(channel->l2cap_cid)) {
|
|
|
|
return BTSTACK_ACL_BUFFERS_FULL;
|
|
|
|
}
|
|
|
|
|
2014-10-28 01:16:50 +00:00
|
|
|
/* Extract destination and source address from the ethernet packet */
|
|
|
|
pos = 0;
|
|
|
|
BD_ADDR_COPY(addr_dest, &packet[pos]);
|
|
|
|
pos += sizeof(bd_addr_t);
|
|
|
|
BD_ADDR_COPY(addr_source, &packet[pos]);
|
|
|
|
pos += sizeof(bd_addr_t);
|
2014-12-10 23:28:03 +00:00
|
|
|
network_protocol_type = READ_NET_16(packet, pos);
|
2014-10-28 01:16:50 +00:00
|
|
|
pos += sizeof(uint16_t);
|
2015-01-02 01:13:53 +00:00
|
|
|
|
|
|
|
payload_len = len - pos;
|
|
|
|
|
|
|
|
if (network_protocol_type == ETHERTYPE_VLAN) { /* IEEE 802.1Q tag header */
|
|
|
|
if (payload_len < 4) {
|
|
|
|
/* Omit this packet */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* The "real" network protocol type is 4 bytes ahead in a VLAN packet */
|
|
|
|
network_protocol_type = READ_NET_16(packet, pos + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check network protocol and multicast filters before sending */
|
|
|
|
if (!bnep_filter_protocol(channel, network_protocol_type) ||
|
|
|
|
!bnep_filter_multicast(channel, addr_dest)) {
|
2015-01-04 00:19:28 +00:00
|
|
|
/* Packet did not pass filter... */
|
2015-01-02 01:13:53 +00:00
|
|
|
if ((network_protocol_type == ETHERTYPE_VLAN) &&
|
|
|
|
(payload_len >= 4)) {
|
|
|
|
/* The packet has been tagged as a with IEE 802.1Q tag and has been filtered out.
|
|
|
|
According to the spec the IEE802.1Q tag header shall be sended without ethernet payload.
|
|
|
|
So limit the payload_len to 4.
|
|
|
|
*/
|
|
|
|
payload_len = 4;
|
|
|
|
} else {
|
|
|
|
/* Packet is not tagged with IEE802.1Q header and was filtered out. Omit this packet */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reserve l2cap packet buffer */
|
|
|
|
l2cap_reserve_packet_buffer();
|
|
|
|
bnep_out_buffer = l2cap_get_outgoing_buffer();
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* Check if source address is the same as our local address and if the
|
|
|
|
destination address is the same as the remote addr. Maybe we can use
|
|
|
|
the compressed data format
|
|
|
|
*/
|
2014-10-28 01:16:50 +00:00
|
|
|
has_source = (memcmp(addr_source, channel->local_addr, ETHER_ADDR_LEN) != 0);
|
|
|
|
has_dest = (memcmp(addr_dest, channel->remote_addr, ETHER_ADDR_LEN) != 0);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
2014-11-12 00:12:13 +00:00
|
|
|
/* Check for MTU limits */
|
2015-01-02 01:13:53 +00:00
|
|
|
if (payload_len > channel->max_frame_size) {
|
|
|
|
log_error("bnep_send: Max frame size (%d) exceeded: %d", channel->max_frame_size, payload_len);
|
2014-11-12 00:12:13 +00:00
|
|
|
return BNEP_DATA_LEN_EXCEEDS_MTU;
|
|
|
|
}
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* Fill in the package type depending on the given source and destination address */
|
2014-10-28 01:16:50 +00:00
|
|
|
if (has_source && has_dest) {
|
|
|
|
bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_GENERAL_ETHERNET;
|
2014-10-08 13:21:40 +00:00
|
|
|
} else
|
2014-10-28 01:16:50 +00:00
|
|
|
if (has_source && !has_dest) {
|
|
|
|
bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_COMPRESSED_ETHERNET_SOURCE_ONLY;
|
2014-10-08 13:21:40 +00:00
|
|
|
} else
|
2014-10-28 01:16:50 +00:00
|
|
|
if (!has_source && has_dest) {
|
|
|
|
bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_COMPRESSED_ETHERNET_DEST_ONLY;
|
2014-10-08 13:21:40 +00:00
|
|
|
} else {
|
2014-10-28 01:16:50 +00:00
|
|
|
bnep_out_buffer[pos_out++] = BNEP_PKT_TYPE_COMPRESSED_ETHERNET;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the destination address if needed */
|
|
|
|
if (has_dest) {
|
2014-10-28 01:16:50 +00:00
|
|
|
BD_ADDR_COPY(bnep_out_buffer + pos_out, addr_dest);
|
|
|
|
pos_out += sizeof(bd_addr_t);
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the source address if needed */
|
2014-10-28 01:16:50 +00:00
|
|
|
if (has_source) {
|
|
|
|
BD_ADDR_COPY(bnep_out_buffer + pos_out, addr_source);
|
|
|
|
pos_out += sizeof(bd_addr_t);
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Add protocol type */
|
2014-12-10 23:28:03 +00:00
|
|
|
net_store_16(bnep_out_buffer, pos_out, network_protocol_type);
|
2014-10-28 01:16:50 +00:00
|
|
|
pos_out += 2;
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* TODO: Add extension headers, if we may support them at a later stage */
|
2014-11-12 00:12:13 +00:00
|
|
|
/* Add the payload and then send out the package */
|
2015-01-02 01:13:53 +00:00
|
|
|
memcpy(bnep_out_buffer + pos_out, packet + pos, payload_len);
|
|
|
|
pos_out += payload_len;
|
2014-10-08 13:21:40 +00:00
|
|
|
|
2014-11-12 00:12:13 +00:00
|
|
|
err = l2cap_send_prepared(channel->l2cap_cid, pos_out);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
if (err) {
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("bnep_send: error %d", err);
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2015-01-02 01:13:53 +00:00
|
|
|
|
|
|
|
/* Set BNEP network protocol type filter */
|
|
|
|
int bnep_set_net_type_filter(uint16_t bnep_cid, bnep_net_filter_t *filter, uint16_t len)
|
|
|
|
{
|
|
|
|
bnep_channel_t *channel;
|
|
|
|
|
|
|
|
if (filter == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
channel = bnep_channel_for_l2cap_cid(bnep_cid);
|
|
|
|
if (channel == NULL) {
|
|
|
|
log_error("bnep_set_net_type_filter cid 0x%02x doesn't exist!", bnep_cid);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (channel->state != BNEP_CHANNEL_STATE_CONNECTED) {
|
|
|
|
return BNEP_CHANNEL_NOT_CONNECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len > MAX_BNEP_NETFILTER_OUT) {
|
|
|
|
return BNEP_DATA_LEN_EXCEEDS_MTU;
|
|
|
|
}
|
|
|
|
|
|
|
|
channel->net_filter_out = filter;
|
|
|
|
channel->net_filter_out_count = len;
|
|
|
|
|
|
|
|
/* Set flag to send out the network protocol type filter set reqeuest on next statemachine cycle */
|
|
|
|
bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_SET);
|
|
|
|
bnep_run();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set BNEP network protocol type filter */
|
|
|
|
int bnep_set_multicast_filter(uint16_t bnep_cid, bnep_multi_filter_t *filter, uint16_t len)
|
|
|
|
{
|
|
|
|
bnep_channel_t *channel;
|
|
|
|
|
|
|
|
if (filter == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
channel = bnep_channel_for_l2cap_cid(bnep_cid);
|
|
|
|
if (channel == NULL) {
|
|
|
|
log_error("bnep_set_net_type_filter cid 0x%02x doesn't exist!", bnep_cid);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (channel->state != BNEP_CHANNEL_STATE_CONNECTED) {
|
|
|
|
return BNEP_CHANNEL_NOT_CONNECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len > MAX_BNEP_MULTICAST_FULTER_OUT) {
|
|
|
|
return BNEP_DATA_LEN_EXCEEDS_MTU;
|
|
|
|
}
|
|
|
|
|
|
|
|
channel->multicast_filter_out = filter;
|
|
|
|
channel->multicast_filter_out_count = len;
|
|
|
|
|
|
|
|
/* Set flag to send out the multicast filter set reqeuest on next statemachine cycle */
|
|
|
|
bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_SET);
|
|
|
|
bnep_run();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-11-13 00:28:01 +00:00
|
|
|
/* BNEP timeout timer helper function */
|
|
|
|
static void bnep_channel_timer_handler(timer_source_t *timer)
|
|
|
|
{
|
|
|
|
bnep_channel_t *channel = (bnep_channel_t *)linked_item_get_user((linked_item_t *) timer);
|
2014-12-11 22:16:42 +00:00
|
|
|
// retry send setup connection at least one time
|
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE){
|
|
|
|
if (channel->retry_count < BNEP_CONNECTION_MAX_RETRIES){
|
|
|
|
channel->retry_count++;
|
|
|
|
bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS);
|
|
|
|
bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST);
|
|
|
|
bnep_run();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-13 00:28:01 +00:00
|
|
|
log_info( "bnep_channel_timeout_handler callback: shutting down connection!");
|
|
|
|
bnep_emit_channel_timeout(channel);
|
|
|
|
bnep_channel_finalize(channel);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void bnep_channel_stop_timer(bnep_channel_t *channel)
|
|
|
|
{
|
|
|
|
if (channel->timer_active) {
|
|
|
|
run_loop_remove_timer(&channel->timer);
|
|
|
|
channel->timer_active = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bnep_channel_start_timer(bnep_channel_t *channel, int timeout)
|
|
|
|
{
|
|
|
|
/* Stop any eventually running timeout timer */
|
|
|
|
bnep_channel_stop_timer(channel);
|
|
|
|
|
|
|
|
/* Start bnep channel timeout check timer */
|
|
|
|
run_loop_set_timer(&channel->timer, timeout);
|
|
|
|
channel->timer.process = bnep_channel_timer_handler;
|
|
|
|
linked_item_set_user((linked_item_t*) &channel->timer, channel);
|
|
|
|
run_loop_add_timer(&channel->timer);
|
|
|
|
channel->timer_active = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* BNEP statemachine functions */
|
|
|
|
|
2014-10-16 22:58:52 +00:00
|
|
|
inline static void bnep_channel_state_add(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event){
|
|
|
|
channel->state_var = (BNEP_CHANNEL_STATE_VAR) (channel->state_var | event);
|
|
|
|
}
|
|
|
|
inline static void bnep_channel_state_remove(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event){
|
|
|
|
channel->state_var = (BNEP_CHANNEL_STATE_VAR) (channel->state_var & ~event);
|
|
|
|
}
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
static uint16_t bnep_max_frame_size_for_l2cap_mtu(uint16_t l2cap_mtu){
|
|
|
|
|
|
|
|
/* Assume a standard BNEP header, containing BNEP Type (1 Byte), dest and
|
|
|
|
source address (6 bytes each) and networking protocol type (2 bytes)
|
|
|
|
*/
|
|
|
|
uint16_t max_frame_size = l2cap_mtu - 15; // 15 bytes BNEP header
|
|
|
|
|
|
|
|
log_info("bnep_max_frame_size_for_l2cap_mtu: %u -> %u", l2cap_mtu, max_frame_size);
|
|
|
|
return max_frame_size;
|
|
|
|
}
|
|
|
|
|
2015-03-01 20:51:08 +00:00
|
|
|
static bnep_channel_t * bnep_channel_create_for_addr(bd_addr_t addr)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
|
|
|
/* Allocate new channel structure */
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_channel_t *channel = btstack_memory_bnep_channel_get();
|
2014-10-08 13:21:40 +00:00
|
|
|
if (!channel) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the channel struct */
|
|
|
|
memset(channel, 0, sizeof(bnep_channel_t));
|
|
|
|
|
|
|
|
channel->state = BNEP_CHANNEL_STATE_CLOSED;
|
|
|
|
channel->max_frame_size = bnep_max_frame_size_for_l2cap_mtu(l2cap_max_mtu());
|
|
|
|
BD_ADDR_COPY(&channel->remote_addr, addr);
|
2015-03-29 22:13:51 +02:00
|
|
|
hci_local_bd_addr(channel->local_addr);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
channel->net_filter_count = 0;
|
|
|
|
channel->multicast_filter_count = 0;
|
2014-12-11 22:16:42 +00:00
|
|
|
channel->retry_count = 0;
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
/* Finally add it to the channel list */
|
|
|
|
linked_list_add(&bnep_channels, (linked_item_t *) channel);
|
|
|
|
|
|
|
|
return channel;
|
|
|
|
}
|
|
|
|
|
2015-03-01 20:51:08 +00:00
|
|
|
static bnep_channel_t* bnep_channel_for_addr(bd_addr_t addr)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
|
|
|
linked_item_t *it;
|
|
|
|
for (it = (linked_item_t *) bnep_channels; it ; it = it->next){
|
|
|
|
bnep_channel_t *channel = ((bnep_channel_t *) it);
|
|
|
|
if (BD_ADDR_CMP(addr, channel->remote_addr) == 0) {
|
|
|
|
return channel;
|
2014-10-16 22:58:52 +00:00
|
|
|
}
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bnep_channel_t * bnep_channel_for_l2cap_cid(uint16_t l2cap_cid)
|
|
|
|
{
|
|
|
|
linked_item_t *it;
|
|
|
|
for (it = (linked_item_t *) bnep_channels; it ; it = it->next){
|
|
|
|
bnep_channel_t *channel = ((bnep_channel_t *) it);
|
2014-10-16 22:58:52 +00:00
|
|
|
if (channel->l2cap_cid == l2cap_cid) {
|
2014-10-08 13:21:40 +00:00
|
|
|
return channel;
|
2014-10-16 22:58:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bnep_service_t * bnep_service_for_uuid(uint16_t uuid)
|
|
|
|
{
|
|
|
|
linked_item_t *it;
|
|
|
|
for (it = (linked_item_t *) bnep_services; it ; it = it->next){
|
|
|
|
bnep_service_t * service = ((bnep_service_t *) it);
|
|
|
|
if ( service->service_uuid == uuid){
|
|
|
|
return service;
|
|
|
|
}
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bnep_channel_free(bnep_channel_t *channel)
|
|
|
|
{
|
|
|
|
linked_list_remove( &bnep_channels, (linked_item_t *) channel);
|
|
|
|
btstack_memory_bnep_channel_free(channel);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bnep_channel_finalize(bnep_channel_t *channel)
|
|
|
|
{
|
|
|
|
uint16_t l2cap_cid;
|
|
|
|
|
|
|
|
/* Inform application about closed channel */
|
2014-10-20 10:06:07 +00:00
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) {
|
2014-10-08 13:21:40 +00:00
|
|
|
bnep_emit_channel_closed(channel);
|
|
|
|
}
|
2014-11-13 00:28:01 +00:00
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
l2cap_cid = channel->l2cap_cid;
|
2014-11-13 00:28:01 +00:00
|
|
|
|
|
|
|
/* Stop any eventually running timer */
|
|
|
|
bnep_channel_stop_timer(channel);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
/* Free ressources and then close the l2cap channel */
|
|
|
|
bnep_channel_free(channel);
|
|
|
|
l2cap_disconnect_internal(l2cap_cid, 0x13);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bnep_handle_connection_request(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
|
|
|
|
{
|
|
|
|
uint16_t uuid_size;
|
|
|
|
uint16_t uuid_offset;
|
2014-11-12 22:42:04 +00:00
|
|
|
uuid_size = packet[1];
|
2014-10-08 13:21:40 +00:00
|
|
|
uint16_t response_code = BNEP_RESP_SETUP_SUCCESS;
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_service_t * service;
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
/* Sanity check packet size */
|
2014-11-12 22:42:04 +00:00
|
|
|
if (size < 1 + 1 + 2 * uuid_size) {
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((channel->state != BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST) &&
|
|
|
|
(channel->state != BNEP_CHANNEL_STATE_CONNECTED)) {
|
|
|
|
/* Ignore a connection request if not waiting for or still connected */
|
2014-12-11 22:16:42 +00:00
|
|
|
log_error("BNEP_CONNECTION_REQUEST: ignored in state %d, l2cap_cid: %d!", channel->state, channel->l2cap_cid);
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract source and destination UUID and convert them to UUID16 format */
|
|
|
|
switch (uuid_size) {
|
|
|
|
case 2: /* UUID16 */
|
|
|
|
uuid_offset = 0;
|
|
|
|
break;
|
|
|
|
case 4: /* UUID32 */
|
|
|
|
case 16: /* UUID128 */
|
|
|
|
uuid_offset = 2;
|
|
|
|
break;
|
|
|
|
default:
|
2014-12-11 22:16:42 +00:00
|
|
|
log_error("BNEP_CONNECTION_REQUEST: Invalid UUID size %d, l2cap_cid: %d!", channel->state, channel->l2cap_cid);
|
2014-10-08 13:21:40 +00:00
|
|
|
response_code = BNEP_RESP_SETUP_INVALID_SERVICE_UUID_SIZE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check source and destination UUIDs for valid combinations */
|
|
|
|
if (response_code == BNEP_RESP_SETUP_SUCCESS) {
|
2014-11-19 01:01:11 +00:00
|
|
|
channel->uuid_dest = READ_NET_16(packet, 2 + uuid_offset);
|
|
|
|
channel->uuid_source = READ_NET_16(packet, 2 + uuid_offset + uuid_size);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
2015-02-13 09:28:39 +00:00
|
|
|
if ((channel->uuid_dest != SDP_PANU) &&
|
|
|
|
(channel->uuid_dest != SDP_NAP) &&
|
|
|
|
(channel->uuid_dest != SDP_GN)) {
|
2014-12-11 22:16:42 +00:00
|
|
|
log_error("BNEP_CONNECTION_REQUEST: Invalid destination service UUID: %04x", channel->uuid_dest);
|
2014-10-08 13:21:40 +00:00
|
|
|
channel->uuid_dest = 0;
|
|
|
|
}
|
2015-02-13 09:28:39 +00:00
|
|
|
if ((channel->uuid_source != SDP_PANU) &&
|
|
|
|
(channel->uuid_source != SDP_NAP) &&
|
|
|
|
(channel->uuid_source != SDP_GN)) {
|
2014-12-11 22:16:42 +00:00
|
|
|
log_error("BNEP_CONNECTION_REQUEST: Invalid source service UUID: %04x", channel->uuid_source);
|
2014-10-08 13:21:40 +00:00
|
|
|
channel->uuid_source = 0;
|
|
|
|
}
|
|
|
|
|
2014-10-20 10:06:07 +00:00
|
|
|
/* Check if we have registered a service for the requested destination UUID */
|
|
|
|
service = bnep_service_for_uuid(channel->uuid_dest);
|
|
|
|
if (service == NULL) {
|
2014-10-08 13:21:40 +00:00
|
|
|
response_code = BNEP_RESP_SETUP_INVALID_DEST_UUID;
|
|
|
|
} else
|
2015-02-13 09:28:39 +00:00
|
|
|
if ((channel->uuid_source != SDP_PANU) && (channel->uuid_dest != SDP_PANU)) {
|
2014-10-08 13:21:40 +00:00
|
|
|
response_code = BNEP_RESP_SETUP_INVALID_SOURCE_UUID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-16 09:45:36 +00:00
|
|
|
/* Set flag to send out the connection response on next statemachine cycle */
|
2014-10-16 22:58:52 +00:00
|
|
|
bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE);
|
2014-10-16 09:45:36 +00:00
|
|
|
channel->response_code = response_code;
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* Return the number of processed package bytes = BNEP Type, BNEP Control Type, UUID-Size + 2 * UUID */
|
2014-11-12 22:42:04 +00:00
|
|
|
return 1 + 1 + 2 * uuid_size;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bnep_handle_connection_response(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
|
|
|
|
{
|
|
|
|
uint16_t response_code;
|
|
|
|
|
|
|
|
/* Sanity check packet size */
|
2014-11-12 22:42:04 +00:00
|
|
|
if (size < 1 + 2) {
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (channel->state != BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE) {
|
|
|
|
/* Ignore a connection response in any state but WAIT_FOR_CONNECTION_RESPONSE */
|
2014-12-11 22:16:42 +00:00
|
|
|
log_error("BNEP_CONNECTION_RESPONSE: Ignored in channel state %d", channel->state);
|
2014-11-12 22:42:04 +00:00
|
|
|
return 1 + 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-12-10 23:28:03 +00:00
|
|
|
response_code = READ_NET_16(packet, 1);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
if (response_code == BNEP_RESP_SETUP_SUCCESS) {
|
2014-12-11 22:16:42 +00:00
|
|
|
log_info("BNEP_CONNECTION_RESPONSE: Channel established to %s", bd_addr_to_str(channel->remote_addr));
|
2014-10-08 13:21:40 +00:00
|
|
|
channel->state = BNEP_CHANNEL_STATE_CONNECTED;
|
2014-11-13 00:28:01 +00:00
|
|
|
/* Stop timeout timer! */
|
|
|
|
bnep_channel_stop_timer(channel);
|
2014-10-20 10:06:38 +00:00
|
|
|
bnep_emit_open_channel_complete(channel, 0);
|
2014-10-08 13:21:40 +00:00
|
|
|
} else {
|
2014-12-11 22:16:42 +00:00
|
|
|
log_error("BNEP_CONNECTION_RESPONSE: Connection to %s failed. Err: %d", bd_addr_to_str(channel->remote_addr), response_code);
|
2014-10-08 13:21:40 +00:00
|
|
|
bnep_channel_finalize(channel);
|
|
|
|
}
|
2014-11-12 22:42:04 +00:00
|
|
|
return 1 + 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2015-08-03 10:51:41 +02:00
|
|
|
static int bnep_can_handle_extensions(bnep_channel_t * channel){
|
2015-08-03 10:59:51 +02:00
|
|
|
/* Extension are primarily handled in CONNECTED state */
|
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) return 1;
|
|
|
|
/* and if we've received connection request, but haven't sent the reponse yet. */
|
|
|
|
if ((channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST) &&
|
|
|
|
(channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
2015-08-03 10:51:41 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
static int bnep_handle_filter_net_type_set(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
|
|
|
|
{
|
|
|
|
uint16_t list_length;
|
|
|
|
uint16_t response_code = BNEP_RESP_FILTER_SUCCESS;
|
|
|
|
|
|
|
|
/* Sanity check packet size */
|
2014-11-12 22:42:04 +00:00
|
|
|
if (size < 3) {
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-10 23:28:03 +00:00
|
|
|
list_length = READ_NET_16(packet, 1);
|
2014-10-08 13:21:40 +00:00
|
|
|
/* Sanity check packet size again with known package size */
|
2014-11-12 22:42:04 +00:00
|
|
|
if (size < 3 + list_length) {
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-03 10:51:41 +02:00
|
|
|
if (!bnep_can_handle_extensions(channel)){
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_FILTER_NET_TYPE_SET: Ignored in channel state %d", channel->state);
|
|
|
|
return 3 + list_length;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we have enough space for more filters */
|
2015-01-04 00:19:28 +00:00
|
|
|
if ((list_length / (2*2)) > MAX_BNEP_NETFILTER) {
|
2014-10-08 13:21:40 +00:00
|
|
|
log_info("BNEP_FILTER_NET_TYPE_SET: Too many filter");
|
|
|
|
response_code = BNEP_RESP_FILTER_ERR_TOO_MANY_FILTERS;
|
|
|
|
} else {
|
|
|
|
int i;
|
2015-01-04 00:19:28 +00:00
|
|
|
channel->net_filter_count = 0;
|
2014-10-08 13:21:40 +00:00
|
|
|
/* There is still enough space, copy the filters to our filter list */
|
2014-11-12 22:42:04 +00:00
|
|
|
for (i = 0; i < list_length / (2 * 2); i ++) {
|
2014-12-10 23:28:03 +00:00
|
|
|
channel->net_filter[channel->net_filter_count].range_start = READ_NET_16(packet, 1 + 2 + i * 4);
|
|
|
|
channel->net_filter[channel->net_filter_count].range_end = READ_NET_16(packet, 1 + 2 + i * 4 + 2);
|
2014-10-08 13:21:40 +00:00
|
|
|
if (channel->net_filter[channel->net_filter_count].range_start > channel->net_filter[channel->net_filter_count].range_end) {
|
|
|
|
/* Invalid filter range, ignore this filter rule */
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_FILTER_NET_TYPE_SET: Invalid filter: start: %d, end: %d",
|
2014-10-08 13:21:40 +00:00
|
|
|
channel->net_filter[channel->net_filter_count].range_start,
|
|
|
|
channel->net_filter[channel->net_filter_count].range_end);
|
|
|
|
response_code = BNEP_RESP_FILTER_ERR_INVALID_RANGE;
|
|
|
|
} else {
|
|
|
|
/* Valid filter, increase the filter count */
|
|
|
|
log_info("BNEP_FILTER_NET_TYPE_SET: Add filter: start: %d, end: %d",
|
|
|
|
channel->net_filter[channel->net_filter_count].range_start,
|
|
|
|
channel->net_filter[channel->net_filter_count].range_end);
|
|
|
|
channel->net_filter_count ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-16 09:45:36 +00:00
|
|
|
/* Set flag to send out the set net filter response on next statemachine cycle */
|
2014-10-16 22:58:52 +00:00
|
|
|
bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_RESPONSE);
|
2014-10-16 09:45:36 +00:00
|
|
|
channel->response_code = response_code;
|
|
|
|
|
2014-11-12 22:42:04 +00:00
|
|
|
return 3 + list_length;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bnep_handle_filter_net_type_response(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
|
|
|
|
{
|
|
|
|
uint16_t response_code;
|
|
|
|
|
|
|
|
// TODO: Currently we do not support setting a network filter.
|
|
|
|
|
|
|
|
/* Sanity check packet size */
|
2014-11-12 22:42:04 +00:00
|
|
|
if (size < 1 + 2) {
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-03 10:51:41 +02:00
|
|
|
if (!bnep_can_handle_extensions(channel)){
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_FILTER_NET_TYPE_RESPONSE: Ignored in channel state %d", channel->state);
|
|
|
|
return 1 + 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-12-10 23:28:03 +00:00
|
|
|
response_code = READ_NET_16(packet, 1);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
if (response_code == BNEP_RESP_FILTER_SUCCESS) {
|
2014-10-20 10:06:07 +00:00
|
|
|
log_info("BNEP_FILTER_NET_TYPE_RESPONSE: Net filter set successfully for %s", bd_addr_to_str(channel->remote_addr));
|
2014-10-08 13:21:40 +00:00
|
|
|
} else {
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_FILTER_NET_TYPE_RESPONSE: Net filter setting for %s failed. Err: %d", bd_addr_to_str(channel->remote_addr), response_code);
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-11-12 22:42:04 +00:00
|
|
|
return 1 + 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bnep_handle_multi_addr_set(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
|
|
|
|
{
|
|
|
|
uint16_t list_length;
|
|
|
|
uint16_t response_code = BNEP_RESP_FILTER_SUCCESS;
|
|
|
|
|
|
|
|
/* Sanity check packet size */
|
2014-11-12 22:42:04 +00:00
|
|
|
if (size < 3) {
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-10 23:28:03 +00:00
|
|
|
list_length = READ_NET_16(packet, 1);
|
2014-10-08 13:21:40 +00:00
|
|
|
/* Sanity check packet size again with known package size */
|
2014-11-12 22:42:04 +00:00
|
|
|
if (size < 3 + list_length) {
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-03 10:51:41 +02:00
|
|
|
if (!bnep_can_handle_extensions(channel)){
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_MULTI_ADDR_SET: Ignored in channel state %d", channel->state);
|
|
|
|
return 3 + list_length;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if we have enough space for more filters */
|
2015-01-04 00:19:28 +00:00
|
|
|
if ((list_length / (2 * ETHER_ADDR_LEN)) > MAX_BNEP_MULTICAST_FILTER) {
|
2014-10-08 13:21:40 +00:00
|
|
|
log_info("BNEP_MULTI_ADDR_SET: Too many filter");
|
|
|
|
response_code = BNEP_RESP_FILTER_ERR_TOO_MANY_FILTERS;
|
|
|
|
} else {
|
2015-01-02 01:13:53 +00:00
|
|
|
unsigned int i;
|
2015-01-04 00:19:28 +00:00
|
|
|
channel->multicast_filter_count = 0;
|
|
|
|
/* There is enough space, copy the filters to our filter list */
|
2014-10-08 13:21:40 +00:00
|
|
|
for (i = 0; i < list_length / (2 * ETHER_ADDR_LEN); i ++) {
|
2014-11-12 22:42:04 +00:00
|
|
|
BD_ADDR_COPY(channel->multicast_filter[channel->multicast_filter_count].addr_start, packet + 1 + 2 + i * ETHER_ADDR_LEN * 2);
|
|
|
|
BD_ADDR_COPY(channel->multicast_filter[channel->multicast_filter_count].addr_end, packet + 1 + 2 + i * ETHER_ADDR_LEN * 2 + ETHER_ADDR_LEN);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
if (memcmp(channel->multicast_filter[channel->multicast_filter_count].addr_start,
|
2014-10-20 10:06:07 +00:00
|
|
|
channel->multicast_filter[channel->multicast_filter_count].addr_end, ETHER_ADDR_LEN) > 0) {
|
2014-10-08 13:21:40 +00:00
|
|
|
/* Invalid filter range, ignore this filter rule */
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_MULTI_ADDR_SET: Invalid filter: start: %s",
|
2014-10-20 10:06:07 +00:00
|
|
|
bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_start));
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_MULTI_ADDR_SET: Invalid filter: end: %s",
|
2014-10-20 10:06:07 +00:00
|
|
|
bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_end));
|
2014-10-08 13:21:40 +00:00
|
|
|
response_code = BNEP_RESP_FILTER_ERR_INVALID_RANGE;
|
|
|
|
} else {
|
|
|
|
/* Valid filter, increase the filter count */
|
|
|
|
log_info("BNEP_MULTI_ADDR_SET: Add filter: start: %s",
|
2014-10-20 10:06:07 +00:00
|
|
|
bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_start));
|
2014-10-08 13:21:40 +00:00
|
|
|
log_info("BNEP_MULTI_ADDR_SET: Add filter: end: %s",
|
2014-10-20 10:06:07 +00:00
|
|
|
bd_addr_to_str(channel->multicast_filter[channel->multicast_filter_count].addr_end));
|
2014-10-08 13:21:40 +00:00
|
|
|
channel->multicast_filter_count ++;
|
|
|
|
}
|
|
|
|
}
|
2014-10-16 09:45:36 +00:00
|
|
|
}
|
|
|
|
/* Set flag to send out the set multi addr response on next statemachine cycle */
|
2014-10-16 22:58:52 +00:00
|
|
|
bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_RESPONSE);
|
2014-10-16 09:45:36 +00:00
|
|
|
channel->response_code = response_code;
|
|
|
|
|
2014-11-12 22:42:04 +00:00
|
|
|
return 3 + list_length;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int bnep_handle_multi_addr_response(bnep_channel_t *channel, uint8_t *packet, uint16_t size)
|
|
|
|
{
|
|
|
|
uint16_t response_code;
|
|
|
|
|
|
|
|
// TODO: Currently we do not support setting multicast address filter.
|
|
|
|
|
|
|
|
/* Sanity check packet size */
|
2014-11-12 22:42:04 +00:00
|
|
|
if (size < 1 + 2) {
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-03 10:51:41 +02:00
|
|
|
if (!bnep_can_handle_extensions(channel)){
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_MULTI_ADDR_RESPONSE: Ignored in channel state %d", channel->state);
|
|
|
|
return 1 + 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-12-10 23:28:03 +00:00
|
|
|
response_code = READ_NET_16(packet, 1);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
if (response_code == BNEP_RESP_FILTER_SUCCESS) {
|
2014-10-20 10:06:07 +00:00
|
|
|
log_info("BNEP_MULTI_ADDR_RESPONSE: Multicast address filter set successfully for %s", bd_addr_to_str(channel->remote_addr));
|
2014-10-08 13:21:40 +00:00
|
|
|
} else {
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_MULTI_ADDR_RESPONSE: Multicast address filter setting for %s failed. Err: %d", bd_addr_to_str(channel->remote_addr), response_code);
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-11-12 22:42:04 +00:00
|
|
|
return 1 + 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-10-27 11:49:47 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
uint16_t pos = 0;
|
2014-11-12 00:12:23 +00:00
|
|
|
|
|
|
|
#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)
|
|
|
|
/* In-place modify the package and add the ethernet header in front of the payload.
|
|
|
|
* WARNING: This modifies the data in front of the payload and may overwrite 14 bytes there!
|
|
|
|
*/
|
|
|
|
uint8_t *ethernet_packet = payload - 2 * sizeof(bd_addr_t) - sizeof(uint16_t);
|
|
|
|
/* Restore the ethernet packet header */
|
|
|
|
BD_ADDR_COPY(ethernet_packet + pos, addr_dest);
|
|
|
|
pos += sizeof(bd_addr_t);
|
|
|
|
BD_ADDR_COPY(ethernet_packet + pos, addr_source);
|
|
|
|
pos += sizeof(bd_addr_t);
|
2014-12-10 23:28:03 +00:00
|
|
|
net_store_16(ethernet_packet, pos, network_protocol_type);
|
2014-11-12 00:12:23 +00:00
|
|
|
/* Payload is just in place... */
|
|
|
|
#else
|
|
|
|
/* Copy ethernet frame to statically allocated buffer. This solution is more
|
|
|
|
* save, but needs an extra copy and more stack!
|
|
|
|
*/
|
|
|
|
uint8_t ethernet_packet[BNEP_MTU_MIN];
|
2014-10-27 11:49:47 +00:00
|
|
|
|
|
|
|
/* Restore the ethernet packet header */
|
|
|
|
BD_ADDR_COPY(ethernet_packet + pos, addr_dest);
|
|
|
|
pos += sizeof(bd_addr_t);
|
|
|
|
BD_ADDR_COPY(ethernet_packet + pos, addr_source);
|
|
|
|
pos += sizeof(bd_addr_t);
|
2014-12-10 23:28:03 +00:00
|
|
|
net_store_16(ethernet_packet, pos, network_protocol_type);
|
2014-10-27 11:49:47 +00:00
|
|
|
pos += 2;
|
|
|
|
memcpy(ethernet_packet + pos, payload, size);
|
2014-11-12 00:12:23 +00:00
|
|
|
#endif
|
|
|
|
|
2014-10-27 11:49:47 +00:00
|
|
|
/* Notify application layer and deliver the ethernet packet */
|
|
|
|
(*app_packet_handler)(channel->connection, BNEP_DATA_PACKET, channel->uuid_source,
|
|
|
|
ethernet_packet, size + sizeof(uint16_t) + 2 * sizeof(bd_addr_t));
|
2014-11-12 00:12:23 +00:00
|
|
|
|
2014-10-27 11:49:47 +00:00
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
static int bnep_handle_control_packet(bnep_channel_t *channel, uint8_t *packet, uint16_t size, int is_extension)
|
|
|
|
{
|
2014-11-12 22:42:04 +00:00
|
|
|
uint16_t len = 0;
|
2014-10-08 13:21:40 +00:00
|
|
|
uint8_t bnep_control_type;
|
|
|
|
|
2014-11-12 22:42:04 +00:00
|
|
|
bnep_control_type = packet[0];
|
2014-10-16 09:45:36 +00:00
|
|
|
/* Save last control type. Needed by statemachin in case of unknown control code */
|
|
|
|
|
|
|
|
channel->last_control_type = bnep_control_type;
|
2014-11-12 22:42:04 +00:00
|
|
|
log_info("BNEP_CONTROL: Type: %d, size: %d, is_extension: %d", bnep_control_type, size, is_extension);
|
2014-10-08 13:21:40 +00:00
|
|
|
switch (bnep_control_type) {
|
|
|
|
case BNEP_CONTROL_TYPE_COMMAND_NOT_UNDERSTOOD:
|
|
|
|
/* The last command we send was not understood. We should close the connection */
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_CONTROL: Received COMMAND_NOT_UNDERSTOOD: l2cap_cid: %d, cmd: %d", channel->l2cap_cid, packet[3]);
|
2014-10-08 13:21:40 +00:00
|
|
|
bnep_channel_finalize(channel);
|
2014-11-12 22:42:04 +00:00
|
|
|
len = 2; // Length of command not understood packet - bnep-type field
|
2014-10-08 13:21:40 +00:00
|
|
|
break;
|
|
|
|
case BNEP_CONTROL_TYPE_SETUP_CONNECTION_REQUEST:
|
|
|
|
if (is_extension) {
|
2014-11-12 22:42:04 +00:00
|
|
|
/* Connection requests are not allowed to be send in an extension header
|
|
|
|
* ignore, do not set "COMMAND_NOT_UNDERSTOOD"
|
2014-10-16 09:45:36 +00:00
|
|
|
*/
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_CONTROL: Received SETUP_CONNECTION_REQUEST in extension header: l2cap_cid: %d", channel->l2cap_cid);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
len = bnep_handle_connection_request(channel, packet, size);
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BNEP_CONTROL_TYPE_SETUP_CONNECTION_RESPONSE:
|
|
|
|
if (is_extension) {
|
2014-10-16 09:45:36 +00:00
|
|
|
/* Connection requests are not allowed to be send in an
|
2014-11-12 22:42:04 +00:00
|
|
|
* extension header, ignore, do not set "COMMAND_NOT_UNDERSTOOD"
|
2014-10-16 09:45:36 +00:00
|
|
|
*/
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_CONTROL: Received SETUP_CONNECTION_RESPONSE in extension header: l2cap_cid: %d", channel->l2cap_cid);
|
2014-10-08 13:21:40 +00:00
|
|
|
return 0;
|
2014-11-12 22:42:04 +00:00
|
|
|
} else {
|
|
|
|
len = bnep_handle_connection_response(channel, packet, size);
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case BNEP_CONTROL_TYPE_FILTER_NET_TYPE_SET:
|
|
|
|
len = bnep_handle_filter_net_type_set(channel, packet, size);
|
|
|
|
break;
|
|
|
|
case BNEP_CONTROL_TYPE_FILTER_NET_TYPE_RESPONSE:
|
|
|
|
len = bnep_handle_filter_net_type_response(channel, packet, size);
|
|
|
|
break;
|
|
|
|
case BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_SET:
|
|
|
|
len = bnep_handle_multi_addr_set(channel, packet, size);
|
|
|
|
break;
|
|
|
|
case BNEP_CONTROL_TYPE_FILTER_MULTI_ADDR_RESPONSE:
|
|
|
|
len = bnep_handle_multi_addr_response(channel, packet, size);
|
|
|
|
break;
|
|
|
|
default:
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("BNEP_CONTROL: Invalid bnep control type: l2cap_cid: %d, cmd: %d", channel->l2cap_cid, bnep_control_type);
|
2014-10-08 13:21:40 +00:00
|
|
|
len = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len == 0) {
|
2014-10-16 09:45:36 +00:00
|
|
|
/* In case the command could not be handled, send a
|
|
|
|
COMMAND_NOT_UNDERSTOOD message.
|
|
|
|
Set flag to process the request in the next statemachine loop
|
|
|
|
*/
|
2014-10-16 22:58:52 +00:00
|
|
|
bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_NOT_UNDERSTOOD);
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-11-12 22:42:04 +00:00
|
|
|
return len;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return handled packet
|
|
|
|
*/
|
|
|
|
static int bnep_hci_event_handler(uint8_t *packet, uint16_t size)
|
|
|
|
{
|
|
|
|
bd_addr_t event_addr;
|
|
|
|
uint16_t psm;
|
|
|
|
uint16_t l2cap_cid;
|
|
|
|
hci_con_handle_t con_handle;
|
|
|
|
bnep_channel_t *channel = NULL;
|
|
|
|
uint8_t status;
|
|
|
|
|
|
|
|
switch (packet[0]) {
|
|
|
|
|
2014-10-20 10:06:38 +00:00
|
|
|
/* Accept an incoming L2CAP connection on PSM_BNEP */
|
2014-10-08 13:21:40 +00:00
|
|
|
case L2CAP_EVENT_INCOMING_CONNECTION:
|
|
|
|
/* L2CAP event data: event(8), len(8), address(48), handle (16), psm (16), source cid(16) dest cid(16) */
|
|
|
|
bt_flip_addr(event_addr, &packet[2]);
|
|
|
|
con_handle = READ_BT_16(packet, 8);
|
|
|
|
psm = READ_BT_16(packet, 10);
|
|
|
|
l2cap_cid = READ_BT_16(packet, 12);
|
|
|
|
|
|
|
|
if (psm != PSM_BNEP) break;
|
|
|
|
|
2015-03-01 20:51:08 +00:00
|
|
|
channel = bnep_channel_for_addr(event_addr);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
2014-11-19 01:01:11 +00:00
|
|
|
if (channel) {
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => decline - channel already exists", l2cap_cid);
|
2014-10-08 13:21:40 +00:00
|
|
|
l2cap_decline_connection_internal(l2cap_cid, 0x04); // no resources available
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-10-20 10:06:38 +00:00
|
|
|
/* Create a new BNEP channel instance (incoming) */
|
2015-03-01 20:51:08 +00:00
|
|
|
channel = bnep_channel_create_for_addr(event_addr);
|
2014-10-20 10:06:07 +00:00
|
|
|
|
|
|
|
if (!channel) {
|
2014-11-12 22:42:04 +00:00
|
|
|
log_error("INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => decline - no memory left", l2cap_cid);
|
2014-10-08 13:21:40 +00:00
|
|
|
l2cap_decline_connection_internal(l2cap_cid, 0x04); // no resources available
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Assign connection handle and l2cap cid */
|
|
|
|
channel->con_handle = con_handle;
|
|
|
|
channel->l2cap_cid = l2cap_cid;
|
|
|
|
|
|
|
|
/* Set channel into accept state */
|
|
|
|
channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST;
|
2014-11-13 00:28:01 +00:00
|
|
|
|
|
|
|
/* Start connection timeout timer */
|
|
|
|
bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
log_info("L2CAP_EVENT_INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => accept", l2cap_cid);
|
|
|
|
l2cap_accept_connection_internal(l2cap_cid);
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Outgoing L2CAP connection has been opened -> store l2cap_cid, remote_addr */
|
|
|
|
case L2CAP_EVENT_CHANNEL_OPENED:
|
|
|
|
/* Check if the l2cap channel has been opened for PSM_BNEP */
|
|
|
|
if (READ_BT_16(packet, 11) != PSM_BNEP) {
|
|
|
|
break;
|
|
|
|
}
|
2014-11-11 21:08:29 +00:00
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
status = packet[2];
|
|
|
|
log_info("L2CAP_EVENT_CHANNEL_OPENED for PSM_BNEP, status %u", status);
|
|
|
|
|
|
|
|
/* Get the bnep channel fpr remote address */
|
|
|
|
con_handle = READ_BT_16(packet, 9);
|
|
|
|
l2cap_cid = READ_BT_16(packet, 13);
|
|
|
|
bt_flip_addr(event_addr, &packet[3]);
|
2015-03-01 20:51:08 +00:00
|
|
|
channel = bnep_channel_for_addr(event_addr);
|
2014-10-08 13:21:40 +00:00
|
|
|
if (!channel) {
|
|
|
|
log_error("L2CAP_EVENT_CHANNEL_OPENED but no BNEP channel prepared");
|
|
|
|
return 1;
|
|
|
|
}
|
2014-11-11 21:08:29 +00:00
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* On L2CAP open error discard everything */
|
|
|
|
if (status) {
|
2014-10-20 10:06:38 +00:00
|
|
|
/* Emit bnep_open_channel_complete with status and free channel */
|
|
|
|
bnep_emit_open_channel_complete(channel, status);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
/* Free BNEP channel mempory */
|
2014-10-16 09:45:36 +00:00
|
|
|
bnep_channel_free(channel);
|
2014-10-08 13:21:40 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2014-11-11 21:08:29 +00:00
|
|
|
|
2015-08-03 10:39:10 +02:00
|
|
|
switch (channel->state){
|
|
|
|
case BNEP_CHANNEL_STATE_CLOSED:
|
|
|
|
log_info("L2CAP_EVENT_CHANNEL_OPENED: outgoing connection");
|
|
|
|
|
|
|
|
bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS);
|
|
|
|
|
|
|
|
/* Assign connection handle and l2cap cid */
|
|
|
|
channel->l2cap_cid = l2cap_cid;
|
|
|
|
channel->con_handle = con_handle;
|
|
|
|
|
|
|
|
/* Initiate the connection request */
|
|
|
|
channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE;
|
|
|
|
bnep_channel_state_add(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST);
|
|
|
|
channel->max_frame_size = bnep_max_frame_size_for_l2cap_mtu(READ_BT_16(packet, 17));
|
|
|
|
bnep_run();
|
|
|
|
break;
|
|
|
|
case BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST:
|
|
|
|
/* New information: channel mtu */
|
|
|
|
channel->max_frame_size = bnep_max_frame_size_for_l2cap_mtu(READ_BT_16(packet, 17));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
log_error("L2CAP_EVENT_CHANNEL_OPENED: Invalid state: %d", channel->state);
|
|
|
|
break;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case DAEMON_EVENT_HCI_PACKET_SENT:
|
2014-10-16 09:45:36 +00:00
|
|
|
bnep_run();
|
2014-10-08 13:21:40 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case L2CAP_EVENT_CHANNEL_CLOSED:
|
|
|
|
// data: event (8), len(8), channel (16)
|
|
|
|
l2cap_cid = READ_BT_16(packet, 2);
|
|
|
|
channel = bnep_channel_for_l2cap_cid(l2cap_cid);
|
|
|
|
log_info("L2CAP_EVENT_CHANNEL_CLOSED cid 0x%0x, channel %p", l2cap_cid, channel);
|
|
|
|
|
|
|
|
if (!channel) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_info("L2CAP_EVENT_CHANNEL_CLOSED state %u", channel->state);
|
2014-10-16 09:45:36 +00:00
|
|
|
switch (channel->state) {
|
|
|
|
case BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST:
|
|
|
|
case BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE:
|
2014-10-08 13:21:40 +00:00
|
|
|
case BNEP_CHANNEL_STATE_CONNECTED:
|
|
|
|
bnep_channel_finalize(channel);
|
|
|
|
return 1;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2014-11-11 21:08:29 +00:00
|
|
|
bnep_run();
|
2014-10-08 13:21:40 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bnep_l2cap_packet_handler(uint16_t l2cap_cid, uint8_t *packet, uint16_t size)
|
|
|
|
{
|
2014-10-27 11:49:47 +00:00
|
|
|
int rc = 0;
|
|
|
|
uint8_t bnep_type;
|
|
|
|
uint8_t bnep_header_has_ext;
|
2014-11-12 22:42:04 +00:00
|
|
|
uint8_t extension_type;
|
2014-10-27 11:49:47 +00:00
|
|
|
uint16_t pos = 0;
|
|
|
|
bd_addr_t addr_source;
|
|
|
|
bd_addr_t addr_dest;
|
2015-05-07 20:53:22 +02:00
|
|
|
uint16_t network_protocol_type = 0xffff;
|
2014-10-08 13:21:40 +00:00
|
|
|
bnep_channel_t *channel = NULL;
|
|
|
|
|
|
|
|
/* Get the bnep channel for this package */
|
2014-10-20 10:06:07 +00:00
|
|
|
channel = bnep_channel_for_l2cap_cid(l2cap_cid);
|
2014-10-08 13:21:40 +00:00
|
|
|
if (!channel) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sort out short packages */
|
|
|
|
if (size < 2) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-10-27 11:49:47 +00:00
|
|
|
bnep_type = BNEP_TYPE(packet[pos]);
|
|
|
|
bnep_header_has_ext = BNEP_HEADER_HAS_EXT(packet[pos]);
|
|
|
|
pos ++;
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
switch(bnep_type) {
|
|
|
|
case BNEP_PKT_TYPE_GENERAL_ETHERNET:
|
2014-10-27 11:49:47 +00:00
|
|
|
BD_ADDR_COPY(addr_dest, &packet[pos]);
|
|
|
|
pos += sizeof(bd_addr_t);
|
|
|
|
BD_ADDR_COPY(addr_source, &packet[pos]);
|
|
|
|
pos += sizeof(bd_addr_t);
|
2014-12-10 23:28:03 +00:00
|
|
|
network_protocol_type = READ_NET_16(packet, pos);
|
2014-10-27 11:49:47 +00:00
|
|
|
pos += 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
break;
|
|
|
|
case BNEP_PKT_TYPE_COMPRESSED_ETHERNET:
|
2014-10-27 11:49:47 +00:00
|
|
|
BD_ADDR_COPY(addr_dest, channel->local_addr);
|
|
|
|
BD_ADDR_COPY(addr_source, channel->remote_addr);
|
2014-12-10 23:28:03 +00:00
|
|
|
network_protocol_type = READ_NET_16(packet, pos);
|
2014-10-27 11:49:47 +00:00
|
|
|
pos += 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
break;
|
|
|
|
case BNEP_PKT_TYPE_COMPRESSED_ETHERNET_SOURCE_ONLY:
|
2014-10-27 11:49:47 +00:00
|
|
|
BD_ADDR_COPY(addr_dest, channel->local_addr);
|
|
|
|
BD_ADDR_COPY(addr_source, &packet[pos]);
|
|
|
|
pos += sizeof(bd_addr_t);
|
2014-12-10 23:28:03 +00:00
|
|
|
network_protocol_type = READ_NET_16(packet, pos);
|
2014-10-27 11:49:47 +00:00
|
|
|
pos += 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
break;
|
|
|
|
case BNEP_PKT_TYPE_COMPRESSED_ETHERNET_DEST_ONLY:
|
2014-10-27 11:49:47 +00:00
|
|
|
BD_ADDR_COPY(addr_dest, &packet[pos]);
|
|
|
|
pos += sizeof(bd_addr_t);
|
|
|
|
BD_ADDR_COPY(addr_source, channel->remote_addr);
|
2014-12-10 23:28:03 +00:00
|
|
|
network_protocol_type = READ_NET_16(packet, pos);
|
2014-10-27 11:49:47 +00:00
|
|
|
pos += 2;
|
2014-10-08 13:21:40 +00:00
|
|
|
break;
|
|
|
|
case BNEP_PKT_TYPE_CONTROL:
|
2014-11-12 22:42:04 +00:00
|
|
|
rc = bnep_handle_control_packet(channel, packet + pos, size - pos, 0);
|
|
|
|
pos += rc;
|
2014-10-08 13:21:40 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-11-12 22:42:04 +00:00
|
|
|
if (bnep_header_has_ext) {
|
|
|
|
do {
|
|
|
|
uint8_t ext_len;
|
|
|
|
|
|
|
|
/* Read extension type and check for further extensions */
|
|
|
|
extension_type = BNEP_TYPE(packet[pos]);
|
|
|
|
bnep_header_has_ext = BNEP_HEADER_HAS_EXT(packet[pos]);
|
|
|
|
pos ++;
|
|
|
|
|
|
|
|
/* Read extension header length */
|
|
|
|
ext_len = packet[pos];
|
|
|
|
pos ++;
|
|
|
|
|
|
|
|
if (size - pos < ext_len) {
|
|
|
|
log_error("BNEP pkt handler: Invalid extension length! Packet ignored");
|
|
|
|
/* Invalid packet size! */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (extension_type) {
|
|
|
|
case BNEP_EXT_HEADER_TYPE_EXTENSION_CONTROL:
|
|
|
|
if (ext_len != bnep_handle_control_packet(channel, packet + pos, ext_len, 1)) {
|
|
|
|
log_error("BNEP pkt handler: Ignore invalid control packet in extension header");
|
|
|
|
}
|
|
|
|
|
|
|
|
pos += ext_len;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* Extension header type unknown. Unknown extension SHALL be
|
|
|
|
* SHALL be forwarded in any way. But who shall handle these
|
|
|
|
* extension packets?
|
|
|
|
* For now: We ignore them and just drop them!
|
|
|
|
*/
|
|
|
|
log_error("BNEP pkt handler: Unknown extension type ignored, data dropped!");
|
|
|
|
pos += ext_len;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
} while (bnep_header_has_ext);
|
|
|
|
}
|
|
|
|
|
2015-05-07 20:53:22 +02:00
|
|
|
if (bnep_type != BNEP_PKT_TYPE_CONTROL && network_protocol_type != 0xffff) {
|
2014-11-12 22:42:04 +00:00
|
|
|
if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) {
|
|
|
|
rc = bnep_handle_ethernet_packet(channel, addr_dest, addr_source, network_protocol_type, packet + pos, size - pos);
|
|
|
|
} else {
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
}
|
2014-11-12 00:12:28 +00:00
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
return rc;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void bnep_packet_handler(uint8_t packet_type, uint16_t l2cap_cid, uint8_t *packet, uint16_t size)
|
|
|
|
{
|
|
|
|
int handled = 0;
|
|
|
|
switch (packet_type) {
|
|
|
|
case HCI_EVENT_PACKET:
|
|
|
|
handled = bnep_hci_event_handler(packet, size);
|
|
|
|
break;
|
|
|
|
case L2CAP_DATA_PACKET:
|
2014-10-20 10:06:07 +00:00
|
|
|
handled = bnep_l2cap_packet_handler(l2cap_cid, packet, size);
|
2014-10-08 13:21:40 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (handled) {
|
2014-10-16 09:45:36 +00:00
|
|
|
bnep_run();
|
2014-10-08 13:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Forward non l2cap packages to application handler */
|
|
|
|
if (packet_type != L2CAP_DATA_PACKET) {
|
|
|
|
(*app_packet_handler)(NULL, packet_type, l2cap_cid, packet, size);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-16 09:45:36 +00:00
|
|
|
bnep_run();
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-10-16 22:58:52 +00:00
|
|
|
static void bnep_channel_state_machine(bnep_channel_t* channel, bnep_channel_event_t *event)
|
|
|
|
{
|
|
|
|
log_info("bnep_state_machine: state %u, state var: %02x, event %u", channel->state, channel->state_var, event->type);
|
|
|
|
|
|
|
|
if (event->type == BNEP_CH_EVT_READY_TO_SEND) {
|
|
|
|
/* Send outstanding packets. */
|
|
|
|
if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_NOT_UNDERSTOOD) {
|
|
|
|
bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_NOT_UNDERSTOOD);
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_send_command_not_understood(channel, channel->last_control_type);
|
2014-10-16 22:58:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST) {
|
|
|
|
bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_REQUEST);
|
2014-10-20 10:06:07 +00:00
|
|
|
channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_RESPONSE;
|
2014-10-16 22:58:52 +00:00
|
|
|
bnep_send_connection_request(channel, channel->uuid_source, channel->uuid_dest);
|
|
|
|
}
|
|
|
|
if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE) {
|
2015-08-03 12:59:25 +02:00
|
|
|
int emit_connected = 0;
|
2014-10-16 22:58:52 +00:00
|
|
|
if ((channel->state == BNEP_CHANNEL_STATE_CLOSED) ||
|
|
|
|
(channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST)) {
|
|
|
|
/* Set channel state to STATE_CONNECTED */
|
|
|
|
channel->state = BNEP_CHANNEL_STATE_CONNECTED;
|
2014-11-13 00:28:01 +00:00
|
|
|
/* Stop timeout timer! */
|
|
|
|
bnep_channel_stop_timer(channel);
|
2015-08-03 12:59:25 +02:00
|
|
|
emit_connected = 1;
|
2014-10-16 22:58:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE);
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_send_connection_response(channel, channel->response_code);
|
2015-08-03 12:59:25 +02:00
|
|
|
if (emit_connected){
|
|
|
|
bnep_emit_open_channel_complete(channel, 0);
|
|
|
|
}
|
2014-10-16 22:58:52 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-01-02 01:13:53 +00:00
|
|
|
if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_SET) {
|
|
|
|
bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_SET);
|
|
|
|
if ((channel->net_filter_out_count > 0) && (channel->net_filter_out != NULL)) {
|
|
|
|
bnep_send_filter_net_type_set(channel, channel->net_filter_out, channel->net_filter_out_count);
|
|
|
|
channel->net_filter_out_count = 0;
|
|
|
|
channel->net_filter_out = NULL;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2014-10-16 22:58:52 +00:00
|
|
|
if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_RESPONSE) {
|
|
|
|
bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_NET_TYPE_RESPONSE);
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_send_filter_net_type_response(channel, channel->response_code);
|
2014-10-16 22:58:52 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-01-02 01:13:53 +00:00
|
|
|
if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_SET) {
|
|
|
|
bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_SET);
|
|
|
|
if ((channel->multicast_filter_out_count > 0) && (channel->multicast_filter_out != NULL)) {
|
|
|
|
bnep_send_filter_multi_addr_set(channel, channel->multicast_filter_out, channel->multicast_filter_out_count);
|
|
|
|
channel->multicast_filter_out_count = 0;
|
|
|
|
channel->multicast_filter_out = NULL;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2014-10-16 22:58:52 +00:00
|
|
|
if (channel->state_var & BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_RESPONSE) {
|
|
|
|
bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_FILTER_MULTI_ADDR_RESPONSE);
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_send_filter_multi_addr_response(channel, channel->response_code);
|
2014-10-16 22:58:52 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-10-28 01:16:50 +00:00
|
|
|
|
2015-01-02 01:13:53 +00:00
|
|
|
|
2014-10-28 01:16:50 +00:00
|
|
|
/* If the event was not yet handled, notify the application layer */
|
|
|
|
bnep_emit_ready_to_send(channel);
|
2014-10-16 22:58:52 +00:00
|
|
|
}
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-10-16 09:45:36 +00:00
|
|
|
|
|
|
|
/* Process oustanding signaling tasks */
|
|
|
|
static void bnep_run(void)
|
|
|
|
{
|
|
|
|
linked_item_t *it;
|
|
|
|
linked_item_t *next;
|
|
|
|
|
|
|
|
for (it = (linked_item_t *) bnep_channels; it ; it = next){
|
|
|
|
|
|
|
|
next = it->next; // be prepared for removal of channel in state machine
|
|
|
|
|
|
|
|
bnep_channel_t * channel = ((bnep_channel_t *) it);
|
|
|
|
|
|
|
|
if (!l2cap_can_send_packet_now(channel->l2cap_cid)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-10-16 22:58:52 +00:00
|
|
|
bnep_channel_event_t channel_event = { BNEP_CH_EVT_READY_TO_SEND };
|
|
|
|
bnep_channel_state_machine(channel, &channel_event);
|
2014-10-16 09:45:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* BNEP BTStack API */
|
|
|
|
void bnep_init(void)
|
|
|
|
{
|
|
|
|
bnep_security_level = LEVEL_0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bnep_set_required_security_level(gap_security_level_t security_level)
|
|
|
|
{
|
|
|
|
bnep_security_level = security_level;
|
|
|
|
}
|
|
|
|
|
2014-10-20 10:06:38 +00:00
|
|
|
/* Register application packet handler */
|
|
|
|
void bnep_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type,
|
|
|
|
uint16_t channel, uint8_t *packet, uint16_t size)){
|
|
|
|
app_packet_handler = handler;
|
|
|
|
}
|
|
|
|
|
2015-07-10 17:02:25 +02:00
|
|
|
int bnep_connect(void * connection, bd_addr_t addr, uint16_t l2cap_psm, uint16_t uuid_src, uint16_t uuid_dest)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_channel_t *channel;
|
2015-03-01 20:51:08 +00:00
|
|
|
log_info("BNEP_CONNECT addr %s", bd_addr_to_str(addr));
|
2014-10-20 10:06:07 +00:00
|
|
|
|
|
|
|
channel = bnep_channel_create_for_addr(addr);
|
|
|
|
if (channel == NULL) {
|
2014-10-16 22:58:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2014-10-20 10:06:07 +00:00
|
|
|
|
2015-07-10 17:02:25 +02:00
|
|
|
channel->uuid_source = uuid_src;
|
2014-10-20 10:06:07 +00:00
|
|
|
channel->uuid_dest = uuid_dest;
|
|
|
|
|
2015-03-01 20:51:08 +00:00
|
|
|
l2cap_create_channel_internal(connection, bnep_packet_handler, addr, l2cap_psm, l2cap_max_mtu());
|
2014-10-16 22:58:52 +00:00
|
|
|
|
2014-10-20 10:06:07 +00:00
|
|
|
return 0;
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2015-03-01 20:51:08 +00:00
|
|
|
void bnep_disconnect(bd_addr_t addr)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
2014-10-16 22:58:52 +00:00
|
|
|
bnep_channel_t *channel;
|
2014-10-08 13:21:40 +00:00
|
|
|
log_info("BNEP_DISCONNECT");
|
|
|
|
|
2014-10-16 22:58:52 +00:00
|
|
|
channel = bnep_channel_for_addr(addr);
|
|
|
|
|
|
|
|
bnep_channel_finalize(channel);
|
|
|
|
|
2014-10-16 09:45:36 +00:00
|
|
|
bnep_run();
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void bnep_register_service(void * connection, uint16_t service_uuid, uint16_t max_frame_size)
|
|
|
|
{
|
|
|
|
log_info("BNEP_REGISTER_SERVICE mtu %d", max_frame_size);
|
|
|
|
|
|
|
|
/* Check if we already registered a service */
|
2014-10-16 22:58:52 +00:00
|
|
|
bnep_service_t * service = bnep_service_for_uuid(service_uuid);
|
2014-10-08 13:21:40 +00:00
|
|
|
if (service) {
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_emit_service_registered(connection, BNEP_SERVICE_ALREADY_REGISTERED, service_uuid);
|
2014-10-08 13:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Only alow one the three service types: PANU, NAP, GN */
|
2015-02-13 09:28:39 +00:00
|
|
|
if ((service_uuid != SDP_PANU) &&
|
|
|
|
(service_uuid != SDP_NAP) &&
|
|
|
|
(service_uuid != SDP_GN)) {
|
2014-10-08 13:21:40 +00:00
|
|
|
log_info("BNEP_REGISTER_SERVICE: Invalid service UUID: %04x", service_uuid);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate service memory */
|
2014-10-16 22:58:52 +00:00
|
|
|
service = (bnep_service_t*) btstack_memory_bnep_service_get();
|
|
|
|
if (!service) {
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_emit_service_registered(connection, BTSTACK_MEMORY_ALLOC_FAILED, service_uuid);
|
2014-10-08 13:21:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-11-19 01:01:11 +00:00
|
|
|
memset(service, 0, sizeof(bnep_service_t));
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* register with l2cap if not registered before, max MTU */
|
2014-10-16 22:58:52 +00:00
|
|
|
l2cap_register_service_internal(NULL, bnep_packet_handler, PSM_BNEP, 0xffff, bnep_security_level);
|
|
|
|
|
2014-10-08 13:21:40 +00:00
|
|
|
/* Setup the service struct */
|
2014-10-16 22:58:52 +00:00
|
|
|
service->connection = connection;
|
|
|
|
service->max_frame_size = max_frame_size;
|
2014-10-20 10:06:07 +00:00
|
|
|
service->service_uuid = service_uuid;
|
2014-10-16 22:58:52 +00:00
|
|
|
|
|
|
|
/* Add to services list */
|
|
|
|
linked_list_add(&bnep_services, (linked_item_t *) service);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
|
|
|
/* Inform the application layer */
|
2014-10-20 10:06:07 +00:00
|
|
|
bnep_emit_service_registered(connection, 0, service_uuid);
|
2014-10-08 13:21:40 +00:00
|
|
|
}
|
|
|
|
|
2014-10-16 22:58:52 +00:00
|
|
|
void bnep_unregister_service(uint16_t service_uuid)
|
2014-10-08 13:21:40 +00:00
|
|
|
{
|
2014-10-20 10:06:07 +00:00
|
|
|
log_info("BNEP_UNREGISTER_SERVICE #%04x", service_uuid);
|
2014-10-08 13:21:40 +00:00
|
|
|
|
2014-10-16 22:58:52 +00:00
|
|
|
bnep_service_t *service = bnep_service_for_uuid(service_uuid);
|
2014-10-08 13:21:40 +00:00
|
|
|
if (!service) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-16 22:58:52 +00:00
|
|
|
linked_list_remove(&bnep_services, (linked_item_t *) service);
|
2014-10-08 13:21:40 +00:00
|
|
|
btstack_memory_bnep_service_free(service);
|
|
|
|
service = NULL;
|
|
|
|
|
|
|
|
l2cap_unregister_service_internal(NULL, PSM_BNEP);
|
|
|
|
}
|
2015-01-02 01:13:53 +00:00
|
|
|
|