bluetooth: Add support for HCI RAW channel; make host layer optional

This commit is contained in:
Matias N 2020-09-20 16:45:09 -03:00 committed by Brennan Ashton
parent 1080d3f411
commit 5386f972fa
15 changed files with 551 additions and 37 deletions

View file

@ -90,3 +90,4 @@ NXSYMBOLS(tcsetattr)
NXSYMBOLS(unlink) NXSYMBOLS(unlink)
NXSYMBOLS(usleep) NXSYMBOLS(usleep)
NXSYMBOLS(write) NXSYMBOLS(write)
NXSYMBOLS(sendmsg)

View file

@ -120,6 +120,8 @@ static int bthcisock_send(FAR const struct bt_driver_s *dev,
return -1; return -1;
} }
bt_buf_release(buf);
return buf->len; return buf->len;
} }
@ -197,7 +199,7 @@ int bthcisock_loop()
* to copy from * to copy from
*/ */
read_buf = bt_buf_alloc(BT_DUMMY, NULL, 0); read_buf = bt_buf_alloc(BT_DUMMY, NULL, BLUETOOTH_H4_HDRLEN);
if (read_buf == NULL) if (read_buf == NULL)
{ {
wlerr("ERROR: Failed to allocate buffer\n"); wlerr("ERROR: Failed to allocate buffer\n");

View file

@ -74,6 +74,9 @@
* is made, the first unused channel for the relevant bdaddr will be * is made, the first unused channel for the relevant bdaddr will be
* allocated and may be discovered using the getsockname(2) call. * allocated and may be discovered using the getsockname(2) call.
* *
* BTPROTO_NONE
* This is to be used internally to indicate unconfigured protocol. Not
* to be used on sockets by user.
*/ */
#define BTPROTO_L2CAP 0 #define BTPROTO_L2CAP 0
@ -84,6 +87,7 @@
#define BTPROTO_CMTP 5 #define BTPROTO_CMTP 5
#define BTPROTO_HIDP 6 #define BTPROTO_HIDP 6
#define BTPROTO_AVDTP 7 #define BTPROTO_AVDTP 7
#define BTPROTO_NONE 255
/* HCI socket options (SOL_HCI, see include/sys/socket.h): /* HCI socket options (SOL_HCI, see include/sys/socket.h):
* *
@ -242,6 +246,19 @@
#define BT_PSM_OTS 0x0025 /* Object Transfer Service (OTS), #define BT_PSM_OTS 0x0025 /* Object Transfer Service (OTS),
* Bluetooth SIG */ * Bluetooth SIG */
/* Channels for a BTPROTO_HCI socket */
#define HCI_CHANNEL_RAW 0x0
#define HCI_CHANNEL_USER 0x1
/* Packets types send over the network layer for BTPROTO_HCI */
#define HCI_COMMAND_PKT 0x01
#define HCI_ACLDATA_PKT 0x02
#define HCI_SCODATA_PKT 0x03
#define HCI_EVENT_PKT 0x04
#define HCI_VENDOR_PKT 0xff
/**************************************************************************** /****************************************************************************
* Public Type Definitions * Public Type Definitions
****************************************************************************/ ****************************************************************************/

View file

@ -71,6 +71,7 @@
struct bluetooth_frame_meta_s struct bluetooth_frame_meta_s
{ {
uint8_t bm_proto; /* Protocol */
bt_addr_t bm_raddr; /* Connected remote address */ bt_addr_t bm_raddr; /* Connected remote address */
uint8_t bm_channel; /* Connection channel */ uint8_t bm_channel; /* Connection channel */
}; };

View file

@ -97,6 +97,7 @@ struct bluetooth_conn_s
#if CONFIG_NET_BLUETOOTH_BACKLOG > 0 #if CONFIG_NET_BLUETOOTH_BACKLOG > 0
uint8_t bc_backlog; /* Number of frames in RX queue */ uint8_t bc_backlog; /* Number of frames in RX queue */
#endif #endif
uint8_t bc_proto; /* Protocol */
/* Queue of incoming packets */ /* Queue of incoming packets */

View file

@ -105,8 +105,16 @@ void bluetooth_conn_initialize(void)
dq_init(&g_free_bluetooth_connections); dq_init(&g_free_bluetooth_connections);
dq_init(&g_active_bluetooth_connections); dq_init(&g_active_bluetooth_connections);
/* Mark connections as uninitialized */
memset(g_bluetooth_connections, 0, sizeof(g_bluetooth_connections));
for (i = 0; i < CONFIG_NET_BLUETOOTH_NCONNS; i++) for (i = 0; i < CONFIG_NET_BLUETOOTH_NCONNS; i++)
{ {
/* Indicate a connection unbound with BTPROTO_NONE */
g_bluetooth_connections[i].bc_proto = BTPROTO_NONE;
/* Link each pre-allocated connection structure into the free list. */ /* Link each pre-allocated connection structure into the free list. */
dq_addlast(&g_bluetooth_connections[i].bc_node, dq_addlast(&g_bluetooth_connections[i].bc_node,
@ -192,6 +200,11 @@ void bluetooth_conn_free(FAR struct bluetooth_conn_s *conn)
/* Free the connection */ /* Free the connection */
dq_addlast(&conn->bc_node, &g_free_bluetooth_connections); dq_addlast(&conn->bc_node, &g_free_bluetooth_connections);
/* Mark as unbound */
conn->bc_proto = BTPROTO_NONE;
net_unlock(); net_unlock();
} }
@ -214,21 +227,52 @@ FAR struct bluetooth_conn_s *
DEBUGASSERT(meta != NULL); DEBUGASSERT(meta != NULL);
for (conn = (FAR struct bluetooth_conn_s *)g_active_bluetooth_connections.head; for (conn =
(FAR struct bluetooth_conn_s *)g_active_bluetooth_connections.head;
conn != NULL; conn != NULL;
conn = (FAR struct bluetooth_conn_s *)conn->bc_node.flink) conn = (FAR struct bluetooth_conn_s *)conn->bc_node.flink)
{ {
/* Does the destination address match the bound address of the socket. */ /* match protocol and channel first */
if ((BLUETOOTH_ADDRCMP(&conn->bc_raddr, &meta->bm_raddr) || if (meta->bm_proto != conn->bc_proto ||
BLUETOOTH_ADDRCMP(&conn->bc_raddr, &g_any_addr)) && meta->bm_channel != conn->bc_channel)
(meta->bm_channel == conn->bc_channel ||
BT_CHANNEL_ANY == conn->bc_channel))
{ {
continue; continue;
} }
switch (meta->bm_proto)
{
/* For BTPROTO_HCI, the socket will not be connected but only
* bound, thus we match for the device directly
*/
case BTPROTO_HCI:
/* TODO: handle when multiple devices supported, need to add ID
* to meta and conn structures
*/
goto stop;
break;
/* For BTPROTO_L2CAP, the destination address must match the
* bound address of the socket
*/
case BTPROTO_L2CAP:
if ((BLUETOOTH_ADDRCMP(&conn->bc_raddr, &meta->bm_raddr) ||
BLUETOOTH_ADDRCMP(&conn->bc_raddr, &g_any_addr)) &&
(meta->bm_channel == conn->bc_channel))
{
goto stop;
}
break;
}
} }
stop:
return conn; return conn;
} }

View file

@ -66,7 +66,7 @@ struct bluetooth_sendto_s
FAR struct socket *is_sock; /* Points to the parent socket structure */ FAR struct socket *is_sock; /* Points to the parent socket structure */
FAR struct devif_callback_s *is_cb; /* Reference to callback instance */ FAR struct devif_callback_s *is_cb; /* Reference to callback instance */
bt_addr_t is_destaddr; /* Frame destination address */ bt_addr_t is_destaddr; /* Frame destination address */
uint8_t is_channel; /* Frame destination channel */ uint16_t is_channel; /* Frame destination channel */
sem_t is_sem; /* Used to wake up the waiting thread */ sem_t is_sem; /* Used to wake up the waiting thread */
FAR const uint8_t *is_buffer; /* User buffer of data to send */ FAR const uint8_t *is_buffer; /* User buffer of data to send */
size_t is_buflen; /* Number of bytes in the is_buffer */ size_t is_buflen; /* Number of bytes in the is_buffer */
@ -117,6 +117,7 @@ static uint16_t bluetooth_sendto_eventhandler(FAR struct net_driver_s *dev,
BLUETOOTH_ADDRCOPY(&meta.bm_raddr, &pstate->is_destaddr); BLUETOOTH_ADDRCOPY(&meta.bm_raddr, &pstate->is_destaddr);
meta.bm_channel = pstate->is_channel; meta.bm_channel = pstate->is_channel;
meta.bm_proto = pstate->is_sock->s_proto;
/* Get the Bluetooth MAC header length */ /* Get the Bluetooth MAC header length */
@ -235,7 +236,6 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
FAR const struct sockaddr *to, FAR const struct sockaddr *to,
socklen_t tolen) socklen_t tolen)
{ {
FAR struct sockaddr_l2 *destaddr;
FAR struct radio_driver_s *radio; FAR struct radio_driver_s *radio;
FAR struct bluetooth_conn_s *conn; FAR struct bluetooth_conn_s *conn;
struct bluetooth_sendto_s state; struct bluetooth_sendto_s state;
@ -262,10 +262,31 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
/* Get the device driver that will service this transfer */ /* Get the device driver that will service this transfer */
radio = bluetooth_find_device(conn, &conn->bc_laddr); if (psock->s_proto == BTPROTO_L2CAP)
if (radio == NULL)
{ {
return -ENODEV; radio = bluetooth_find_device(conn, &conn->bc_laddr);
if (radio == NULL)
{
return -ENODEV;
}
}
else if (psock->s_proto == BTPROTO_HCI)
{
/* TODO: should actually look among BT devices */
radio =
(FAR struct radio_driver_s *)netdev_findbyindex(conn->bc_ldev + 1);
DEBUGASSERT(radio->r_dev.d_lltype == NET_LL_BLUETOOTH);
if (radio == NULL)
{
return -ENODEV;
}
}
else
{
return -EOPNOTSUPP;
} }
/* Perform the send operation */ /* Perform the send operation */
@ -290,9 +311,22 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
/* Copy the destination address */ /* Copy the destination address */
destaddr = (FAR struct sockaddr_l2 *)to; if (psock->s_proto == BTPROTO_L2CAP)
memcpy(&state.is_destaddr, &destaddr->l2_bdaddr, {
sizeof(bt_addr_t)); FAR struct sockaddr_l2 *destaddr = (FAR struct sockaddr_l2 *)to;
memcpy(&state.is_destaddr, &destaddr->l2_bdaddr,
sizeof(bt_addr_t));
}
else if (psock->s_proto == BTPROTO_HCI)
{
FAR struct sockaddr_hci *destaddr = (FAR struct sockaddr_hci *)to;
state.is_channel = destaddr->hci_channel;
}
else
{
ret = -EOPNOTSUPP;
goto err_with_net;
}
if (len > 0) if (len > 0)
{ {
@ -348,6 +382,12 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
/* Return the number of bytes actually sent */ /* Return the number of bytes actually sent */
return state.is_sent; return state.is_sent;
err_with_net:
nxsem_destroy(&state.is_sem);
net_unlock();
return ret;
} }
#endif /* CONFIG_NET_BLUETOOTH */ #endif /* CONFIG_NET_BLUETOOTH */

View file

@ -294,6 +294,7 @@ static int bluetooth_connect(FAR struct socket *psock,
btaddr = (FAR struct sockaddr_l2 *)addr; btaddr = (FAR struct sockaddr_l2 *)addr;
memcpy(&conn->bc_raddr, &btaddr->l2_bdaddr, sizeof(bt_addr_t)); memcpy(&conn->bc_raddr, &btaddr->l2_bdaddr, sizeof(bt_addr_t));
conn->bc_channel = btaddr->l2_cid; conn->bc_channel = btaddr->l2_cid;
conn->bc_proto = psock->s_proto;
} }
else else
{ {
@ -485,6 +486,8 @@ static int bluetooth_l2cap_bind(FAR struct socket *psock,
conn = (FAR struct bluetooth_conn_s *)psock->s_conn; conn = (FAR struct bluetooth_conn_s *)psock->s_conn;
conn->bc_proto = psock->s_proto;
/* Find the device associated with the requested address */ /* Find the device associated with the requested address */
radio = bluetooth_find_device(conn, &iaddr->l2_bdaddr); radio = bluetooth_find_device(conn, &iaddr->l2_bdaddr);
@ -549,6 +552,7 @@ static int bluetooth_hci_bind(FAR struct socket *psock,
conn = (FAR struct bluetooth_conn_s *)psock->s_conn; conn = (FAR struct bluetooth_conn_s *)psock->s_conn;
conn->bc_proto = psock->s_proto;
conn->bc_channel = hciaddr->hci_channel; conn->bc_channel = hciaddr->hci_channel;
conn->bc_ldev = hciaddr->hci_dev; conn->bc_ldev = hciaddr->hci_dev;
@ -766,6 +770,7 @@ static ssize_t bluetooth_send(FAR struct socket *psock, FAR const void *buf,
size_t len, int flags) size_t len, int flags)
{ {
ssize_t ret; ssize_t ret;
DEBUGASSERT(psock != NULL || buf != NULL); DEBUGASSERT(psock != NULL || buf != NULL);
/* Only SOCK_RAW is supported */ /* Only SOCK_RAW is supported */
@ -871,7 +876,7 @@ static ssize_t bluetooth_hci_send(FAR struct socket *psock,
FAR const void *buf, FAR const void *buf,
size_t len, int flags) size_t len, int flags)
{ {
#warning Missing logic /* We only support sendto() for HCI sockets */
return -EPFNOSUPPORT; return -EPFNOSUPPORT;
} }
@ -905,9 +910,9 @@ static ssize_t bluetooth_sendto(FAR struct socket *psock,
{ {
ssize_t ret; ssize_t ret;
/* Only SOCK_RAW on L2CAP is supported */ /* Only SOCK_RAW is supported */
if (psock->s_type == SOCK_RAW && psock->s_proto == BTPROTO_L2CAP) if (psock->s_type == SOCK_RAW)
{ {
/* Raw packet send */ /* Raw packet send */

View file

@ -105,7 +105,7 @@ ssize_t psock_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
return -EBADF; return -EBADF;
} }
/* Let logic specific to this address family handle the sendfrom() /* Let logic specific to this address family handle the sendmsg()
* operation. * operation.
*/ */

View file

@ -48,12 +48,19 @@ menuconfig WIRELESS_BLUETOOTH
---help--- ---help---
This option enables Bluetooth Low Energy support. This option enables Bluetooth Low Energy support.
NOTE: This selection is marked EXPERIMENTAL. It is incomplete and,
hence, untested. It still lacks any low-level Bluetooth drivers and
is missing the network interface driver.
if WIRELESS_BLUETOOTH if WIRELESS_BLUETOOTH
menuconfig WIRELESS_BLUETOOTH_HOST
bool "BLE Host Layer"
default y
---help---
This enables support for BLE host layer implementation. This can be
used to interface to a BLE controller via HCI protocol (either to a local
BLE link-layer or to an external device over HCI UART).
if WIRELESS_BLUETOOTH_HOST
endif # WIRELESS_BLUETOOTH_HOST
config BLUETOOTH_MAX_CONN config BLUETOOTH_MAX_CONN
int "Maximum number of simultaneous connections" int "Maximum number of simultaneous connections"
default 1 default 1

View file

@ -37,10 +37,18 @@ ifeq ($(CONFIG_WIRELESS_BLUETOOTH),y)
# Include Bluetooth support # Include Bluetooth support
CSRCS += bt_atomic.c bt_att.c bt_buf.c bt_conn.c bt_gatt.c bt_hcicore.c CSRCS += bt_buf.c bt_netdev.c bt_queue.c bt_hcicore.c
CSRCS += bt_ioctl.c bt_keys.c bt_l2cap.c bt_netdev.c bt_queue.c bt_smp.c
ifeq ($(CONFIG_WIRELESS_BLUETOOTH_HOST),y)
# Host-layer
CSRCS += bt_atomic.c bt_att.c bt_conn.c bt_gatt.c
CSRCS += bt_ioctl.c bt_keys.c bt_l2cap.c bt_smp.c
CSRCS += bt_uuid.c CSRCS += bt_uuid.c
endif
DEPPATH += --dep-path bluetooth DEPPATH += --dep-path bluetooth
VPATH += :bluetooth VPATH += :bluetooth
CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)wireless$(DELIM)bluetooth} CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)wireless$(DELIM)bluetooth}

View file

@ -388,9 +388,11 @@ FAR struct bt_buf_s *bt_buf_alloc(enum bt_buf_type_e type,
void bt_buf_release(FAR struct bt_buf_s *buf) void bt_buf_release(FAR struct bt_buf_s *buf)
{ {
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
enum bt_buf_type_e type; enum bt_buf_type_e type;
irqstate_t flags;
uint16_t handle; uint16_t handle;
#endif
irqstate_t flags;
wlinfo("buf %p ref %u type %d\n", buf, buf->ref, buf->type); wlinfo("buf %p ref %u type %d\n", buf, buf->ref, buf->type);
@ -400,8 +402,10 @@ void bt_buf_release(FAR struct bt_buf_s *buf)
return; return;
} }
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
handle = buf->u.acl.handle; handle = buf->u.acl.handle;
type = buf->type; type = buf->type;
#endif
/* Free the contained frame and return the container to the correct memory /* Free the contained frame and return the container to the correct memory
* pool. * pool.
@ -460,6 +464,7 @@ void bt_buf_release(FAR struct bt_buf_s *buf)
wlinfo("Buffer freed: %p\n", buf); wlinfo("Buffer freed: %p\n", buf);
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
if (type == BT_ACL_IN) if (type == BT_ACL_IN)
{ {
FAR struct bt_hci_cp_host_num_completed_packets_s *cp; FAR struct bt_hci_cp_host_num_completed_packets_s *cp;
@ -484,6 +489,7 @@ void bt_buf_release(FAR struct bt_buf_s *buf)
bt_hci_cmd_send(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, buf); bt_hci_cmd_send(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, buf);
} }
#endif
} }
/**************************************************************************** /****************************************************************************

View file

@ -100,8 +100,12 @@ struct bt_dev_s g_btdev;
* Private Data * Private Data
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
static FAR struct bt_conn_cb_s *g_callback_list; static FAR struct bt_conn_cb_s *g_callback_list;
static bt_le_scan_cb_t *g_scan_dev_found_cb; static bt_le_scan_cb_t *g_scan_dev_found_cb;
#else
static struct bt_hci_cb_s *g_hci_cb;
#endif
/* Lists of pending received messages. One for low priority input that is /* Lists of pending received messages. One for low priority input that is
* processed on the low priority work queue and one for high priority * processed on the low priority work queue and one for high priority
@ -229,6 +233,7 @@ static FAR struct bt_buf_s *
return buf; return buf;
} }
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
static void bt_connected(FAR struct bt_conn_s *conn) static void bt_connected(FAR struct bt_conn_s *conn)
{ {
FAR struct bt_conn_cb_s *cb; FAR struct bt_conn_cb_s *cb;
@ -982,6 +987,7 @@ static void hci_event(FAR struct bt_buf_s *buf)
bt_buf_release(buf); bt_buf_release(buf);
} }
#endif
/**************************************************************************** /****************************************************************************
* Name: hci_tx_kthread * Name: hci_tx_kthread
@ -1075,6 +1081,7 @@ static void hci_rx_work(FAR void *arg)
/* TODO: Hook monitor callback */ /* TODO: Hook monitor callback */
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
switch (buf->type) switch (buf->type)
{ {
case BT_ACL_IN: case BT_ACL_IN:
@ -1090,6 +1097,9 @@ static void hci_rx_work(FAR void *arg)
bt_buf_release(buf); bt_buf_release(buf);
break; break;
} }
#else
g_hci_cb->received(buf, g_hci_cb->context);
#endif
} }
} }
@ -1131,6 +1141,7 @@ static void priority_rx_work(FAR void *arg)
continue; continue;
} }
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
bt_buf_consume(buf, sizeof(struct bt_hci_evt_hdr_s)); bt_buf_consume(buf, sizeof(struct bt_hci_evt_hdr_s));
switch (hdr->evt) switch (hdr->evt)
@ -1151,11 +1162,15 @@ static void priority_rx_work(FAR void *arg)
wlerr("Unknown event 0x%02x\n", hdr->evt); wlerr("Unknown event 0x%02x\n", hdr->evt);
break; break;
} }
#else
UNUSED(hdr);
bt_buf_release(buf); g_hci_cb->received(buf, g_hci_cb->context);
#endif
} }
} }
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
static void read_local_features_complete(FAR struct bt_buf_s *buf) static void read_local_features_complete(FAR struct bt_buf_s *buf)
{ {
FAR struct bt_hci_rp_read_local_features_s *rp = (FAR void *)buf->data; FAR struct bt_hci_rp_read_local_features_s *rp = (FAR void *)buf->data;
@ -1433,6 +1448,7 @@ static int hci_initialize(void)
nxsem_init(&g_btdev.le_pkts_sem, 0, g_btdev.le_pkts); nxsem_init(&g_btdev.le_pkts_sem, 0, g_btdev.le_pkts);
return 0; return 0;
} }
#endif
/* threads, fifos and semaphores initialization */ /* threads, fifos and semaphores initialization */
@ -1496,6 +1512,7 @@ int bt_initialize(void)
return ret; return ret;
} }
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
ret = hci_initialize(); ret = hci_initialize();
if (ret < 0) if (ret < 0)
{ {
@ -1503,7 +1520,10 @@ int bt_initialize(void)
return ret; return ret;
} }
return bt_l2cap_init(); ret = bt_l2cap_init();
#endif
return ret;
} }
/**************************************************************************** /****************************************************************************
@ -1582,6 +1602,8 @@ void bt_driver_unregister(FAR const struct bt_driver_s *btdev)
* *
****************************************************************************/ ****************************************************************************/
/* TODO: rename to bt_receive? */
void bt_hci_receive(FAR struct bt_buf_s *buf) void bt_hci_receive(FAR struct bt_buf_s *buf)
{ {
FAR struct bt_hci_evt_hdr_s *hdr; FAR struct bt_hci_evt_hdr_s *hdr;
@ -1652,6 +1674,8 @@ void bt_hci_receive(FAR struct bt_buf_s *buf)
} }
} }
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/**************************************************************************** /****************************************************************************
* Name: bt_hci_cmd_create * Name: bt_hci_cmd_create
* *
@ -2143,3 +2167,27 @@ FAR const char *bt_addr_le_str(FAR const bt_addr_le_t *addr)
return str; return str;
} }
#endif /* CONFIG_DEBUG_WIRELESS_ERROR */ #endif /* CONFIG_DEBUG_WIRELESS_ERROR */
#else
/****************************************************************************
* Name: bt_hci_cb_register
*
* Description:
* Register callbacks to handle RAW HCI packets
*
* Input Parameters:
* cb - Instance of the callback structure.
*
* Returned Value:
* None
*
****************************************************************************/
void bt_hci_cb_register(FAR struct bt_hci_cb_s *cb)
{
g_hci_cb = cb;
}
#endif

View file

@ -72,10 +72,11 @@
struct bt_dev_s struct bt_dev_s
{ {
/* Local Bluetooth Device Address */ /* Local Bluetooth Device Address */
bt_addr_t bdaddr; bt_addr_t bdaddr;
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/* Controller version & manufacturer information */ /* Controller version & manufacturer information */
uint8_t hci_version; uint8_t hci_version;
@ -104,6 +105,7 @@ struct bt_dev_s
uint8_t le_pkts; uint8_t le_pkts;
uint16_t le_mtu; uint16_t le_mtu;
sem_t le_pkts_sem; sem_t le_pkts_sem;
#endif
/* Number of commands controller can accept */ /* Number of commands controller can accept */
@ -127,6 +129,7 @@ struct bt_dev_s
FAR const struct bt_driver_s *btdev; FAR const struct bt_driver_s *btdev;
}; };
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/* Connection callback structure */ /* Connection callback structure */
struct bt_conn_s; /* Forward reference */ struct bt_conn_s; /* Forward reference */
@ -138,7 +141,18 @@ struct bt_conn_cb_s
CODE void (*connected)(FAR struct bt_conn_s *conn, FAR void *context); CODE void (*connected)(FAR struct bt_conn_s *conn, FAR void *context);
CODE void (*disconnected)(FAR struct bt_conn_s *conn, FAR void *context); CODE void (*disconnected)(FAR struct bt_conn_s *conn, FAR void *context);
}; };
#else
/* RAW HCI packets callbacks */
struct bt_hci_cb_s
{
FAR void *context;
CODE void (*received)(FAR struct bt_buf_s *buf, FAR void *context);
};
#endif
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/**************************************************************************** /****************************************************************************
* Name: bt_le_scan_cb_t * Name: bt_le_scan_cb_t
* *
@ -160,6 +174,7 @@ struct bt_conn_cb_s
typedef CODE void bt_le_scan_cb_t(FAR const bt_addr_le_t *addr, int8_t rssi, typedef CODE void bt_le_scan_cb_t(FAR const bt_addr_le_t *addr, int8_t rssi,
uint8_t adv_type, uint8_t adv_type,
FAR const uint8_t *adv_data, uint8_t len); FAR const uint8_t *adv_data, uint8_t len);
#endif
/**************************************************************************** /****************************************************************************
* Public Data * Public Data
@ -171,6 +186,7 @@ extern struct bt_dev_s g_btdev;
* Inline Functions * Inline Functions
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
static inline int bt_addr_cmp(FAR const bt_addr_t *a, FAR const bt_addr_t *b) static inline int bt_addr_cmp(FAR const bt_addr_t *a, FAR const bt_addr_t *b)
{ {
return memcmp(a, b, sizeof(*a)); return memcmp(a, b, sizeof(*a));
@ -231,6 +247,8 @@ static inline bool bt_addr_le_is_identity(FAR const bt_addr_le_t *addr)
struct bt_eir_s; /* Forward reference */ struct bt_eir_s; /* Forward reference */
#endif
/**************************************************************************** /****************************************************************************
* Name: bt_initialize * Name: bt_initialize
* *
@ -284,6 +302,7 @@ int bt_driver_register(FAR const struct bt_driver_s *btdev);
void bt_driver_unregister(FAR const struct bt_driver_s *btdev); void bt_driver_unregister(FAR const struct bt_driver_s *btdev);
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/**************************************************************************** /****************************************************************************
* Name: bt_hci_cmd_create * Name: bt_hci_cmd_create
* *
@ -409,5 +428,24 @@ int bt_le_scan_update(void);
****************************************************************************/ ****************************************************************************/
void bt_conn_cb_register(FAR struct bt_conn_cb_s *cb); void bt_conn_cb_register(FAR struct bt_conn_cb_s *cb);
#else
/****************************************************************************
* Name: bt_hci_cb_register
*
* Description:
* Register callbacks to handle RAW HCI packets
*
* Input Parameters:
* cb - Instance of the callback structure.
*
* Returned Value:
* None
*
****************************************************************************/
void bt_hci_cb_register(FAR struct bt_hci_cb_s *cb);
#endif
#endif /* __WIRELESS_BLUETOOTH_BT_HDICORE_H */ #endif /* __WIRELESS_BLUETOOTH_BT_HDICORE_H */

View file

@ -63,10 +63,15 @@
#include <nuttx/net/bluetooth.h> #include <nuttx/net/bluetooth.h>
#include <nuttx/net/sixlowpan.h> #include <nuttx/net/sixlowpan.h>
#include <nuttx/wireless/bluetooth/bt_core.h> #include <nuttx/wireless/bluetooth/bt_core.h>
#include <netpacket/bluetooth.h>
#include "bt_hcicore.h" #include "bt_hcicore.h"
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
#include "bt_l2cap.h" #include "bt_l2cap.h"
#include "bt_conn.h" #include "bt_conn.h"
#endif
#include "bt_ioctl.h" #include "bt_ioctl.h"
#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_BLUETOOTH) #if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_BLUETOOTH)
@ -125,8 +130,13 @@ struct btnet_driver_s
bool bd_bifup; /* true:ifup false:ifdown */ bool bd_bifup; /* true:ifup false:ifdown */
struct wdog_s bd_txpoll; /* TX poll timer */ struct wdog_s bd_txpoll; /* TX poll timer */
struct work_s bd_pollwork; /* Defer poll work to the work queue */ struct work_s bd_pollwork; /* Defer poll work to the work queue */
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
struct bt_conn_cb_s bd_hcicb; /* HCI connection status callbacks */ struct bt_conn_cb_s bd_hcicb; /* HCI connection status callbacks */
struct bt_l2cap_chan_s bd_l2capcb; /* L2CAP status callbacks */ struct bt_l2cap_chan_s bd_l2capcb; /* L2CAP status callbacks */
#else
struct bt_hci_cb_s bd_hcicb; /* HCI RAW packet callbacks */
#endif
}; };
/**************************************************************************** /****************************************************************************
@ -140,6 +150,7 @@ static inline void btnet_netmask(FAR struct net_driver_s *netdev);
/* Bluetooth callback functions *********************************************/ /* Bluetooth callback functions *********************************************/
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/* L2CAP callbacks */ /* L2CAP callbacks */
static void btnet_l2cap_connected(FAR struct bt_conn_s *conn, static void btnet_l2cap_connected(FAR struct bt_conn_s *conn,
@ -157,6 +168,9 @@ static void btnet_hci_connected(FAR struct bt_conn_s *conn,
FAR void *context); FAR void *context);
static void btnet_hci_disconnected(FAR struct bt_conn_s *conn, static void btnet_hci_disconnected(FAR struct bt_conn_s *conn,
FAR void *context); FAR void *context);
#else
static void btnet_hci_received(FAR struct bt_buf_s *buf, FAR void *context);
#endif
/* Network interface support ************************************************/ /* Network interface support ************************************************/
@ -187,6 +201,16 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
static int btnet_properties(FAR struct radio_driver_s *netdev, static int btnet_properties(FAR struct radio_driver_s *netdev,
FAR struct radiodev_properties_s *properties); FAR struct radiodev_properties_s *properties);
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
static int btnet_req_l2cap_data(FAR struct btnet_driver_s *priv,
FAR struct bluetooth_frame_meta_s *meta,
FAR struct iob_s *framelist);
#endif
static int btnet_req_hci_data(FAR struct btnet_driver_s *priv,
FAR struct bluetooth_frame_meta_s *meta,
FAR struct iob_s *framelist);
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
****************************************************************************/ ****************************************************************************/
@ -276,6 +300,7 @@ static inline void btnet_netmask(FAR struct net_driver_s *netdev)
#endif #endif
} }
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/**************************************************************************** /****************************************************************************
* Name: btnet_hci_connect/disconnect/encrypt_change * Name: btnet_hci_connect/disconnect/encrypt_change
* *
@ -475,6 +500,126 @@ static void btnet_hci_disconnected(FAR struct bt_conn_s *conn,
wlinfo("Disconnected\n"); wlinfo("Disconnected\n");
#warning Missing logic #warning Missing logic
} }
#else
/****************************************************************************
* Name: btnet_hci_received
*
* Description:
* This callback is called from the RX queue handling when an HCI
* packet is received from controller.
*
* Input Parameters:
* buf - The packet
*
* Returned Value:
* None
*
* Assumptions:
* No assumption should be made about the thread of execution that these
* are called from
*
****************************************************************************/
static void btnet_hci_received(FAR struct bt_buf_s *buf, FAR void *context)
{
FAR struct btnet_driver_s *priv;
FAR struct iob_s *frame;
struct bluetooth_frame_meta_s meta;
int ret = -ENODEV;
wlinfo("Received frame\n");
DEBUGASSERT(buf != NULL && buf->frame != NULL);
/* Detach the IOB frame from the buffer structure */
frame = buf->frame;
buf->frame = NULL;
/* Ignore the frame if the network is not up */
priv = (FAR struct btnet_driver_s *)context;
if (!priv->bd_bifup)
{
wlwarn("WARNING: Dropped... Network is down\n");
goto drop;
}
/* Make sure that the size/offset data matches the buffer structure data. */
DEBUGASSERT(frame->io_offset == BLUETOOTH_H4_HDRLEN);
/* Rearrange IOB to consider H4 header */
frame->io_len = buf->len + frame->io_offset;
frame->io_pktlen = buf->len + frame->io_offset;
frame->io_offset = 0;
DEBUGASSERT(frame->io_len <= CONFIG_IOB_BUFSIZE);
/* Write H4 header */
switch (buf->type)
{
case BT_EVT:
frame->io_data[0] = HCI_EVENT_PKT;
break;
case BT_ACL_IN:
frame->io_data[0] = HCI_ACLDATA_PKT;
break;
default:
wlerr("Bad HCI type: %i\n", buf->type);
goto drop;
break;
}
/* Construct the frame meta data.
*/
meta.bm_channel = HCI_CHANNEL_RAW;
meta.bm_proto = BTPROTO_HCI;
/* Transfer the frame to the network logic */
net_lock();
#ifdef CONFIG_NET_BLUETOOTH
/* Invoke the PF_BLUETOOTH tap first. If the frame matches
* with a connected PF_BLUETOOTH socket, it will take the
* frame and return success.
*/
ret = bluetooth_input(&priv->bd_dev, frame, (FAR void *)&meta);
#endif
drop:
/* Handle errors */
if (ret < 0)
{
iob_free(frame, IOBUSER_WIRELESS_BLUETOOTH);
/* Increment statistics */
NETDEV_RXDROPPED(&priv->bd_dev.r_dev);
}
else
{
/* Increment statistics */
NETDEV_RXPACKETS(&priv->bd_dev.r_dev);
NETDEV_RXIPV6(&priv->bd_dev.r_dev);
}
/* Release our reference on the buffer */
bt_buf_release(buf);
net_unlock();
}
#endif
/**************************************************************************** /****************************************************************************
* Name: btnet_txpoll_callback * Name: btnet_txpoll_callback
@ -852,7 +997,26 @@ static int btnet_rmmac(FAR struct net_driver_s *netdev,
static int btnet_get_mhrlen(FAR struct radio_driver_s *netdev, static int btnet_get_mhrlen(FAR struct radio_driver_s *netdev,
FAR const void *meta) FAR const void *meta)
{ {
/* Always report the maximum frame length. */ const struct bluetooth_frame_meta_s *btmeta = meta;
if (btmeta->bm_proto == BTPROTO_HCI)
{
/* the net device only requires the H4 header, the rest is already
* part of the packet
*/
return BLUETOOTH_H4_HDRLEN;
}
else if (btmeta->bm_proto == BTPROTO_L2CAP)
{
/* Report the complete header size, since H4 + ACL + L2CAP header
* will not be part of the packet
*/
/* TODO: correct? */
return BLUETOOTH_MAX_HDRLEN;
}
return BLUETOOTH_MAX_HDRLEN; return BLUETOOTH_MAX_HDRLEN;
} }
@ -880,10 +1044,6 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
{ {
FAR struct btnet_driver_s *priv; FAR struct btnet_driver_s *priv;
FAR struct bluetooth_frame_meta_s *btmeta; FAR struct bluetooth_frame_meta_s *btmeta;
FAR struct bt_conn_s *conn;
FAR struct bt_buf_s *buf;
FAR struct iob_s *iob;
bt_addr_le_t peer;
wlinfo("Received framelist\n"); wlinfo("Received framelist\n");
DEBUGASSERT(priv != NULL && meta != NULL && framelist != NULL); DEBUGASSERT(priv != NULL && meta != NULL && framelist != NULL);
@ -891,6 +1051,52 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
priv = (FAR struct btnet_driver_s *)netdev; priv = (FAR struct btnet_driver_s *)netdev;
btmeta = (FAR struct bluetooth_frame_meta_s *)meta; btmeta = (FAR struct bluetooth_frame_meta_s *)meta;
if (btmeta->bm_proto == BTPROTO_HCI)
{
return btnet_req_hci_data(priv, btmeta, framelist);
}
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
else if (btmeta->bm_proto == BTPROTO_L2CAP)
{
return btnet_req_l2cap_data(priv, btmeta, framelist);
}
#endif
else
{
return -EOPNOTSUPP;
}
return OK;
}
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/****************************************************************************
* Name: btnet_req_l2cap_data
*
* Description:
* Requests the transfer of a list of L2CAP frames to the MAC.
*
* Input Parameters:
* priv - Bluetooth network device
* btmeta - Bluetooth frame metadata
* framelist - Head of a list of L2CAP frames to be transferred.
*
* Returned Value:
* Zero (OK) returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
static int btnet_req_l2cap_data(FAR struct btnet_driver_s *priv,
FAR struct bluetooth_frame_meta_s *btmeta,
FAR struct iob_s *framelist)
{
FAR struct bt_conn_s *conn;
bt_addr_le_t peer;
FAR struct iob_s *iob;
FAR struct bt_buf_s *buf;
UNUSED(priv);
/* Create a connection structure for this peer if one does not already /* Create a connection structure for this peer if one does not already
* exist. * exist.
* *
@ -945,7 +1151,84 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
NETDEV_TXDONE(&priv->bd_dev.r_dev); NETDEV_TXDONE(&priv->bd_dev.r_dev);
} }
UNUSED(priv); return OK;
}
#endif
/****************************************************************************
* Name: btnet_req_hci_data
*
* Description:
* Requests the transfer of a list of HCI frames to the MAC.
*
* Input Parameters:
* priv - Bluetooth network device
* btmeta - Bluetooth frame metadata
* framelist - Head of a list of HCI frames to be transferred.
*
* Returned Value:
* Zero (OK) returned on success; a negated errno value is returned on
* any failure.
*
****************************************************************************/
static int btnet_req_hci_data(FAR struct btnet_driver_s *priv,
FAR struct bluetooth_frame_meta_s *meta,
FAR struct iob_s *framelist)
{
FAR struct iob_s *iob;
FAR struct bt_buf_s *buf;
/* Add the incoming list of frames to the MAC's outgoing queue */
for (iob = framelist; iob != NULL; iob = framelist)
{
/* Increment statistics */
NETDEV_TXPACKETS(&priv->bd_dev.r_dev);
/* Remove the IOB from the queue */
framelist = iob->io_flink;
iob->io_flink = NULL;
DEBUGASSERT(iob->io_offset == BLUETOOTH_H4_HDRLEN &&
iob->io_len >= BLUETOOTH_H4_HDRLEN);
/* Allocate a buffer to contain the IOB */
switch (iob->io_data[iob->io_offset])
{
case HCI_ACLDATA_PKT:
iob->io_offset += 1;
buf = bt_buf_alloc(BT_ACL_OUT, iob, 0);
break;
case HCI_COMMAND_PKT:
iob->io_offset += 1;
buf = bt_buf_alloc(BT_CMD, iob, 0);
break;
case HCI_EVENT_PKT:
iob->io_offset += 1;
buf = bt_buf_alloc(BT_EVT, iob, 0);
break;
default:
return -EOPNOTSUPP;
break;
}
if (buf == NULL)
{
wlerr("ERROR: Failed to allocate buffer container\n");
return -ENOMEM;
}
g_btdev.btdev->send(g_btdev.btdev, buf);
/* Transfer the frame to the Bluetooth stack. */
NETDEV_TXDONE(&priv->bd_dev.r_dev);
}
return OK; return OK;
} }
@ -1009,8 +1292,13 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev)
FAR struct btnet_driver_s *priv; FAR struct btnet_driver_s *priv;
FAR struct radio_driver_s *radio; FAR struct radio_driver_s *radio;
FAR struct net_driver_s *netdev; FAR struct net_driver_s *netdev;
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
FAR struct bt_conn_cb_s *hcicb; FAR struct bt_conn_cb_s *hcicb;
FAR struct bt_l2cap_chan_s *l2capcb; FAR struct bt_l2cap_chan_s *l2capcb;
#else
FAR struct bt_hci_cb_s *hcicb;
#endif
int ret; int ret;
/* Get the interface structure associated with this interface number. */ /* Get the interface structure associated with this interface number. */
@ -1035,13 +1323,14 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev)
netdev->d_addmac = btnet_addmac; /* Add multicast MAC address */ netdev->d_addmac = btnet_addmac; /* Add multicast MAC address */
netdev->d_rmmac = btnet_rmmac; /* Remove multicast MAC address */ netdev->d_rmmac = btnet_rmmac; /* Remove multicast MAC address */
#endif #endif
#ifdef CONFIG_NETDEV_IOCTL #if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_WIRELESS_BLUETOOTH_HOST)
netdev->d_ioctl = btnet_ioctl; /* Handle network IOCTL commands */ netdev->d_ioctl = btnet_ioctl; /* Handle network IOCTL commands */
#endif #endif
netdev->d_private = priv; /* Used to recover private state from netdev */ netdev->d_private = priv; /* Used to recover private state from netdev */
/* Connection status change callbacks */ /* Connection status change callbacks */
#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
hcicb = &priv->bd_hcicb; hcicb = &priv->bd_hcicb;
hcicb->context = priv; hcicb->context = priv;
hcicb->connected = btnet_hci_connected; hcicb->connected = btnet_hci_connected;
@ -1059,6 +1348,13 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev)
l2capcb->receive = btnet_l2cap_receive; l2capcb->receive = btnet_l2cap_receive;
bt_l2cap_chan_default(l2capcb); bt_l2cap_chan_default(l2capcb);
#else
hcicb = &priv->bd_hcicb;
hcicb->context = priv;
hcicb->received = btnet_hci_received;
bt_hci_cb_register(hcicb);
#endif
/* Setup a locking semaphore for exclusive device driver access */ /* Setup a locking semaphore for exclusive device driver access */