204 lines
4.5 KiB
C
204 lines
4.5 KiB
C
/* net_driver_bt.c - IP Bluetooth LE driver */
|
|
|
|
/*
|
|
* Copyright (c) 2015 Intel Corporation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <nanokernel.h>
|
|
#include <toolchain.h>
|
|
#include <sections.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#if defined(CONFIG_STDOUT_CONSOLE)
|
|
#include <stdio.h>
|
|
#define PRINT printf
|
|
#else
|
|
#include <misc/printk.h>
|
|
#define PRINT printk
|
|
#endif
|
|
|
|
#include <net/buf.h>
|
|
#include <net/ip_buf.h>
|
|
#include <net/net_core.h>
|
|
#include <net/net_ip.h>
|
|
#include <net/net_socket.h>
|
|
#include "contiki/netstack.h"
|
|
#include <net_driver_bt.h>
|
|
|
|
#include <bluetooth/bluetooth.h>
|
|
#include <bluetooth/uuid.h>
|
|
#include <bluetooth/l2cap.h>
|
|
#include <bluetooth/gatt.h>
|
|
|
|
#define L2CAP_IPSP_PSM 0x0023
|
|
#define L2CAP_IPSP_MTU IP_BUF_MAX_DATA
|
|
|
|
static inline void memswap(void *dst, const void *src, int len)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
((uint8_t *)dst)[i] = ((uint8_t *)src)[(len - 1) - i];
|
|
}
|
|
}
|
|
|
|
static void ipsp_connected(struct bt_l2cap_chan *chan)
|
|
{
|
|
struct bt_conn_info info;
|
|
char src[BT_ADDR_LE_STR_LEN];
|
|
char dst[BT_ADDR_LE_STR_LEN];
|
|
linkaddr_t addr;
|
|
|
|
bt_conn_get_info(chan->conn, &info);
|
|
|
|
bt_addr_le_to_str(info.le.src, src, sizeof(src));
|
|
bt_addr_le_to_str(info.le.dst, dst, sizeof(dst));
|
|
|
|
NET_DBG("Channel %p Source %s connected to Destination %s\n", chan,
|
|
src, dst);
|
|
|
|
/* Swap bytes since net_set_mac expect big endian address */
|
|
memswap(addr.u8, info.le.src->val, sizeof(addr.u8));
|
|
|
|
net_set_mac(addr.u8, sizeof(addr));
|
|
}
|
|
|
|
static void ipsp_disconnected(struct bt_l2cap_chan *chan)
|
|
{
|
|
NET_DBG("Channel %p disconnected\n", chan);
|
|
}
|
|
|
|
static void ipsp_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
|
|
{
|
|
struct bt_conn_info info;
|
|
linkaddr_t src;
|
|
linkaddr_t dst;
|
|
|
|
NET_DBG("Incoming data channel %p len %u\n", chan, ip_buf_len(buf));
|
|
|
|
bt_conn_get_info(chan->conn, &info);
|
|
|
|
/* Swap bytes since linkaddr_copy expect big endian address */
|
|
memswap(src.u8, info.le.src->val, sizeof(src));
|
|
memswap(dst.u8, info.le.dst->val, sizeof(dst));
|
|
|
|
/* Add MAC addresses to the buffer */
|
|
linkaddr_copy(&ip_buf_ll_dest(buf), &src);
|
|
linkaddr_copy(&ip_buf_ll_src(buf), &dst);
|
|
|
|
/* Initialize uip_len */
|
|
uip_len(buf) = ip_buf_len(buf);
|
|
|
|
/* Uncompress data */
|
|
if (!NETSTACK_COMPRESS.uncompress(buf)) {
|
|
NET_ERR("uncompression failed\n");
|
|
return;
|
|
}
|
|
|
|
/* net_recv takes ownership of the buffer */
|
|
net_buf_ref(buf);
|
|
|
|
/* Add buffer to rx_queue */
|
|
if (net_recv(buf) < 0) {
|
|
NET_ERR("input to IP stack failed\n");
|
|
net_buf_unref(buf);
|
|
return;
|
|
}
|
|
}
|
|
|
|
static struct net_buf *ipsp_alloc_buf(struct bt_l2cap_chan *chan)
|
|
{
|
|
NET_DBG("Channel %p requires buffer\n", chan);
|
|
|
|
return ip_buf_get_reserve_rx(0);
|
|
}
|
|
|
|
static struct bt_l2cap_chan_ops ipsp_ops = {
|
|
.alloc_buf = ipsp_alloc_buf,
|
|
.recv = ipsp_recv,
|
|
.connected = ipsp_connected,
|
|
.disconnected = ipsp_disconnected,
|
|
};
|
|
|
|
static struct bt_l2cap_chan ipsp_chan = {
|
|
.ops = &ipsp_ops,
|
|
.rx.mtu = L2CAP_IPSP_MTU,
|
|
};
|
|
|
|
static int ipsp_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
|
|
{
|
|
NET_DBG("Incoming conn %p\n", conn);
|
|
|
|
if (ipsp_chan.conn) {
|
|
NET_ERR("No channels available");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
*chan = &ipsp_chan;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct bt_l2cap_server server = {
|
|
.psm = L2CAP_IPSP_PSM,
|
|
.accept = ipsp_accept,
|
|
};
|
|
|
|
static struct bt_gatt_attr attrs[] = {
|
|
/* IPSS Service Declaration */
|
|
BT_GATT_PRIMARY_SERVICE(BT_UUID_IPSS),
|
|
};
|
|
|
|
static int net_driver_bt_open(void)
|
|
{
|
|
bt_gatt_register(attrs, ARRAY_SIZE(attrs));
|
|
|
|
bt_l2cap_server_register(&server);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int net_driver_bt_send(struct net_buf *buf)
|
|
{
|
|
int orig_len = ip_buf_len(buf);
|
|
|
|
if (!NETSTACK_COMPRESS.compress(buf)) {
|
|
NET_DBG("compression failed\n");
|
|
ip_buf_unref(buf);
|
|
return -EINVAL;
|
|
}
|
|
|
|
NET_DBG("sending %d bytes (original len %d)\n", ip_buf_len(buf),
|
|
orig_len);
|
|
|
|
return bt_l2cap_chan_send(&ipsp_chan, buf);
|
|
}
|
|
|
|
static struct net_driver net_driver_bt = {
|
|
.head_reserve = 0,
|
|
.open = net_driver_bt_open,
|
|
.send = net_driver_bt_send,
|
|
};
|
|
|
|
int net_driver_bt_init(void)
|
|
{
|
|
NETSTACK_COMPRESS.init();
|
|
|
|
net_register_driver(&net_driver_bt);
|
|
|
|
return 0;
|
|
}
|