You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by bt...@apache.org on 2020/10/26 00:04:36 UTC
[incubator-nuttx] 02/02: bluetooth: Add support for HCI RAW channel;
make host layer optional
This is an automated email from the ASF dual-hosted git repository.
btashton pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 5386f972fa8020b69798ab70325b7f4df0f20cf3
Author: Matias N <ma...@protobits.dev>
AuthorDate: Sun Sep 20 16:45:09 2020 -0300
bluetooth: Add support for HCI RAW channel; make host layer optional
---
arch/sim/src/nuttx-names.in | 1 +
arch/sim/src/sim/up_hcisocket.c | 4 +-
include/netpacket/bluetooth.h | 17 +++
include/nuttx/net/bluetooth.h | 1 +
net/bluetooth/bluetooth.h | 1 +
net/bluetooth/bluetooth_conn.c | 56 ++++++-
net/bluetooth/bluetooth_sendto.c | 56 ++++++-
net/bluetooth/bluetooth_sockif.c | 11 +-
net/socket/sendmsg.c | 2 +-
wireless/bluetooth/Kconfig | 15 +-
wireless/bluetooth/Make.defs | 12 +-
wireless/bluetooth/bt_buf.c | 8 +-
wireless/bluetooth/bt_hcicore.c | 52 ++++++-
wireless/bluetooth/bt_hcicore.h | 42 +++++-
wireless/bluetooth/bt_netdev.c | 310 ++++++++++++++++++++++++++++++++++++++-
15 files changed, 551 insertions(+), 37 deletions(-)
diff --git a/arch/sim/src/nuttx-names.in b/arch/sim/src/nuttx-names.in
index 3117054..e235c87 100644
--- a/arch/sim/src/nuttx-names.in
+++ b/arch/sim/src/nuttx-names.in
@@ -90,3 +90,4 @@ NXSYMBOLS(tcsetattr)
NXSYMBOLS(unlink)
NXSYMBOLS(usleep)
NXSYMBOLS(write)
+NXSYMBOLS(sendmsg)
diff --git a/arch/sim/src/sim/up_hcisocket.c b/arch/sim/src/sim/up_hcisocket.c
index 2c0ba83..ff9da37 100644
--- a/arch/sim/src/sim/up_hcisocket.c
+++ b/arch/sim/src/sim/up_hcisocket.c
@@ -120,6 +120,8 @@ static int bthcisock_send(FAR const struct bt_driver_s *dev,
return -1;
}
+ bt_buf_release(buf);
+
return buf->len;
}
@@ -197,7 +199,7 @@ int bthcisock_loop()
* 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)
{
wlerr("ERROR: Failed to allocate buffer\n");
diff --git a/include/netpacket/bluetooth.h b/include/netpacket/bluetooth.h
index ec0c072..0dda89d 100644
--- a/include/netpacket/bluetooth.h
+++ b/include/netpacket/bluetooth.h
@@ -74,6 +74,9 @@
* is made, the first unused channel for the relevant bdaddr will be
* 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
@@ -84,6 +87,7 @@
#define BTPROTO_CMTP 5
#define BTPROTO_HIDP 6
#define BTPROTO_AVDTP 7
+#define BTPROTO_NONE 255
/* HCI socket options (SOL_HCI, see include/sys/socket.h):
*
@@ -242,6 +246,19 @@
#define BT_PSM_OTS 0x0025 /* Object Transfer Service (OTS),
* 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
****************************************************************************/
diff --git a/include/nuttx/net/bluetooth.h b/include/nuttx/net/bluetooth.h
index 0b9d3bc..cd52610 100644
--- a/include/nuttx/net/bluetooth.h
+++ b/include/nuttx/net/bluetooth.h
@@ -71,6 +71,7 @@
struct bluetooth_frame_meta_s
{
+ uint8_t bm_proto; /* Protocol */
bt_addr_t bm_raddr; /* Connected remote address */
uint8_t bm_channel; /* Connection channel */
};
diff --git a/net/bluetooth/bluetooth.h b/net/bluetooth/bluetooth.h
index 8f8a1bb..4843892 100644
--- a/net/bluetooth/bluetooth.h
+++ b/net/bluetooth/bluetooth.h
@@ -97,6 +97,7 @@ struct bluetooth_conn_s
#if CONFIG_NET_BLUETOOTH_BACKLOG > 0
uint8_t bc_backlog; /* Number of frames in RX queue */
#endif
+ uint8_t bc_proto; /* Protocol */
/* Queue of incoming packets */
diff --git a/net/bluetooth/bluetooth_conn.c b/net/bluetooth/bluetooth_conn.c
index bef7fbf..32c0504 100644
--- a/net/bluetooth/bluetooth_conn.c
+++ b/net/bluetooth/bluetooth_conn.c
@@ -105,8 +105,16 @@ void bluetooth_conn_initialize(void)
dq_init(&g_free_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++)
{
+ /* 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. */
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 */
dq_addlast(&conn->bc_node, &g_free_bluetooth_connections);
+
+ /* Mark as unbound */
+
+ conn->bc_proto = BTPROTO_NONE;
+
net_unlock();
}
@@ -214,21 +227,52 @@ FAR struct bluetooth_conn_s *
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 = (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) ||
- BLUETOOTH_ADDRCMP(&conn->bc_raddr, &g_any_addr)) &&
- (meta->bm_channel == conn->bc_channel ||
- BT_CHANNEL_ANY == conn->bc_channel))
+ if (meta->bm_proto != conn->bc_proto ||
+ meta->bm_channel != conn->bc_channel)
{
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;
}
diff --git a/net/bluetooth/bluetooth_sendto.c b/net/bluetooth/bluetooth_sendto.c
index 629147d..7223078 100644
--- a/net/bluetooth/bluetooth_sendto.c
+++ b/net/bluetooth/bluetooth_sendto.c
@@ -66,7 +66,7 @@ struct bluetooth_sendto_s
FAR struct socket *is_sock; /* Points to the parent socket structure */
FAR struct devif_callback_s *is_cb; /* Reference to callback instance */
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 */
FAR const uint8_t *is_buffer; /* User buffer of data to send */
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);
meta.bm_channel = pstate->is_channel;
+ meta.bm_proto = pstate->is_sock->s_proto;
/* 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,
socklen_t tolen)
{
- FAR struct sockaddr_l2 *destaddr;
FAR struct radio_driver_s *radio;
FAR struct bluetooth_conn_s *conn;
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 */
- radio = bluetooth_find_device(conn, &conn->bc_laddr);
- if (radio == NULL)
+ if (psock->s_proto == BTPROTO_L2CAP)
{
- 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 */
@@ -290,9 +311,22 @@ ssize_t psock_bluetooth_sendto(FAR struct socket *psock, FAR const void *buf,
/* Copy the destination address */
- destaddr = (FAR struct sockaddr_l2 *)to;
- memcpy(&state.is_destaddr, &destaddr->l2_bdaddr,
- sizeof(bt_addr_t));
+ if (psock->s_proto == BTPROTO_L2CAP)
+ {
+ 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)
{
@@ -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 state.is_sent;
+
+err_with_net:
+ nxsem_destroy(&state.is_sem);
+ net_unlock();
+
+ return ret;
}
#endif /* CONFIG_NET_BLUETOOTH */
diff --git a/net/bluetooth/bluetooth_sockif.c b/net/bluetooth/bluetooth_sockif.c
index ba30746..f1829e7 100644
--- a/net/bluetooth/bluetooth_sockif.c
+++ b/net/bluetooth/bluetooth_sockif.c
@@ -294,6 +294,7 @@ static int bluetooth_connect(FAR struct socket *psock,
btaddr = (FAR struct sockaddr_l2 *)addr;
memcpy(&conn->bc_raddr, &btaddr->l2_bdaddr, sizeof(bt_addr_t));
conn->bc_channel = btaddr->l2_cid;
+ conn->bc_proto = psock->s_proto;
}
else
{
@@ -485,6 +486,8 @@ static int bluetooth_l2cap_bind(FAR struct socket *psock,
conn = (FAR struct bluetooth_conn_s *)psock->s_conn;
+ conn->bc_proto = psock->s_proto;
+
/* Find the device associated with the requested address */
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->bc_proto = psock->s_proto;
conn->bc_channel = hciaddr->hci_channel;
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)
{
ssize_t ret;
+
DEBUGASSERT(psock != NULL || buf != NULL);
/* Only SOCK_RAW is supported */
@@ -871,7 +876,7 @@ static ssize_t bluetooth_hci_send(FAR struct socket *psock,
FAR const void *buf,
size_t len, int flags)
{
-#warning Missing logic
+ /* We only support sendto() for HCI sockets */
return -EPFNOSUPPORT;
}
@@ -905,9 +910,9 @@ static ssize_t bluetooth_sendto(FAR struct socket *psock,
{
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 */
diff --git a/net/socket/sendmsg.c b/net/socket/sendmsg.c
index a188b3a..c6513ed 100644
--- a/net/socket/sendmsg.c
+++ b/net/socket/sendmsg.c
@@ -105,7 +105,7 @@ ssize_t psock_sendmsg(FAR struct socket *psock, FAR struct msghdr *msg,
return -EBADF;
}
- /* Let logic specific to this address family handle the sendfrom()
+ /* Let logic specific to this address family handle the sendmsg()
* operation.
*/
diff --git a/wireless/bluetooth/Kconfig b/wireless/bluetooth/Kconfig
index c1cc691..6bf1193 100644
--- a/wireless/bluetooth/Kconfig
+++ b/wireless/bluetooth/Kconfig
@@ -48,12 +48,19 @@ menuconfig WIRELESS_BLUETOOTH
---help---
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
+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
int "Maximum number of simultaneous connections"
default 1
diff --git a/wireless/bluetooth/Make.defs b/wireless/bluetooth/Make.defs
index 8ca7edf..3fc56e8 100644
--- a/wireless/bluetooth/Make.defs
+++ b/wireless/bluetooth/Make.defs
@@ -37,10 +37,18 @@ ifeq ($(CONFIG_WIRELESS_BLUETOOTH),y)
# Include Bluetooth support
-CSRCS += bt_atomic.c bt_att.c bt_buf.c bt_conn.c bt_gatt.c bt_hcicore.c
-CSRCS += bt_ioctl.c bt_keys.c bt_l2cap.c bt_netdev.c bt_queue.c bt_smp.c
+CSRCS += bt_buf.c bt_netdev.c bt_queue.c bt_hcicore.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
+endif
+
DEPPATH += --dep-path bluetooth
VPATH += :bluetooth
CFLAGS += ${shell $(INCDIR) "$(CC)" $(TOPDIR)$(DELIM)wireless$(DELIM)bluetooth}
diff --git a/wireless/bluetooth/bt_buf.c b/wireless/bluetooth/bt_buf.c
index 4c70b88..e4d760e 100644
--- a/wireless/bluetooth/bt_buf.c
+++ b/wireless/bluetooth/bt_buf.c
@@ -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)
{
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
enum bt_buf_type_e type;
- irqstate_t flags;
uint16_t handle;
+#endif
+ irqstate_t flags;
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;
}
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
handle = buf->u.acl.handle;
type = buf->type;
+#endif
/* Free the contained frame and return the container to the correct memory
* pool.
@@ -460,6 +464,7 @@ void bt_buf_release(FAR struct bt_buf_s *buf)
wlinfo("Buffer freed: %p\n", buf);
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
if (type == BT_ACL_IN)
{
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);
}
+#endif
}
/****************************************************************************
diff --git a/wireless/bluetooth/bt_hcicore.c b/wireless/bluetooth/bt_hcicore.c
index 859a52b..e31cca7 100644
--- a/wireless/bluetooth/bt_hcicore.c
+++ b/wireless/bluetooth/bt_hcicore.c
@@ -100,8 +100,12 @@ struct bt_dev_s g_btdev;
* Private Data
****************************************************************************/
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
static FAR struct bt_conn_cb_s *g_callback_list;
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
* processed on the low priority work queue and one for high priority
@@ -229,6 +233,7 @@ static FAR struct bt_buf_s *
return buf;
}
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
static void bt_connected(FAR struct bt_conn_s *conn)
{
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);
}
+#endif
/****************************************************************************
* Name: hci_tx_kthread
@@ -1075,6 +1081,7 @@ static void hci_rx_work(FAR void *arg)
/* TODO: Hook monitor callback */
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
switch (buf->type)
{
case BT_ACL_IN:
@@ -1090,6 +1097,9 @@ static void hci_rx_work(FAR void *arg)
bt_buf_release(buf);
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;
}
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
bt_buf_consume(buf, sizeof(struct bt_hci_evt_hdr_s));
switch (hdr->evt)
@@ -1151,11 +1162,15 @@ static void priority_rx_work(FAR void *arg)
wlerr("Unknown event 0x%02x\n", hdr->evt);
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)
{
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);
return 0;
}
+#endif
/* threads, fifos and semaphores initialization */
@@ -1496,6 +1512,7 @@ int bt_initialize(void)
return ret;
}
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
ret = hci_initialize();
if (ret < 0)
{
@@ -1503,7 +1520,10 @@ int bt_initialize(void)
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)
{
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
*
@@ -2143,3 +2167,27 @@ FAR const char *bt_addr_le_str(FAR const bt_addr_le_t *addr)
return str;
}
#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
+
diff --git a/wireless/bluetooth/bt_hcicore.h b/wireless/bluetooth/bt_hcicore.h
index 946137e..343dfc2 100644
--- a/wireless/bluetooth/bt_hcicore.h
+++ b/wireless/bluetooth/bt_hcicore.h
@@ -72,10 +72,11 @@
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 */
uint8_t hci_version;
@@ -104,6 +105,7 @@ struct bt_dev_s
uint8_t le_pkts;
uint16_t le_mtu;
sem_t le_pkts_sem;
+#endif
/* Number of commands controller can accept */
@@ -127,6 +129,7 @@ struct bt_dev_s
FAR const struct bt_driver_s *btdev;
};
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/* Connection callback structure */
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 (*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
*
@@ -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,
uint8_t adv_type,
FAR const uint8_t *adv_data, uint8_t len);
+#endif
/****************************************************************************
* Public Data
@@ -171,6 +186,7 @@ extern struct bt_dev_s g_btdev;
* 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)
{
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 */
+#endif
+
/****************************************************************************
* 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);
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/****************************************************************************
* 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);
+#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 */
diff --git a/wireless/bluetooth/bt_netdev.c b/wireless/bluetooth/bt_netdev.c
index bc31c1d..bd64d6e 100644
--- a/wireless/bluetooth/bt_netdev.c
+++ b/wireless/bluetooth/bt_netdev.c
@@ -63,10 +63,15 @@
#include <nuttx/net/bluetooth.h>
#include <nuttx/net/sixlowpan.h>
#include <nuttx/wireless/bluetooth/bt_core.h>
+#include <netpacket/bluetooth.h>
#include "bt_hcicore.h"
+
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
#include "bt_l2cap.h"
#include "bt_conn.h"
+#endif
+
#include "bt_ioctl.h"
#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_BLUETOOTH)
@@ -125,8 +130,13 @@ struct btnet_driver_s
bool bd_bifup; /* true:ifup false:ifdown */
struct wdog_s bd_txpoll; /* TX poll timer */
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_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 *********************************************/
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/* L2CAP callbacks */
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);
static void btnet_hci_disconnected(FAR struct bt_conn_s *conn,
FAR void *context);
+#else
+static void btnet_hci_received(FAR struct bt_buf_s *buf, FAR void *context);
+#endif
/* 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,
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
****************************************************************************/
@@ -276,6 +300,7 @@ static inline void btnet_netmask(FAR struct net_driver_s *netdev)
#endif
}
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
/****************************************************************************
* 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");
#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
@@ -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,
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;
}
@@ -880,10 +1044,6 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
{
FAR struct btnet_driver_s *priv;
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");
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;
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
* exist.
*
@@ -945,7 +1151,84 @@ static int btnet_req_data(FAR struct radio_driver_s *netdev,
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;
}
@@ -1009,8 +1292,13 @@ int bt_netdev_register(FAR const struct bt_driver_s *btdev)
FAR struct btnet_driver_s *priv;
FAR struct radio_driver_s *radio;
FAR struct net_driver_s *netdev;
+
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
FAR struct bt_conn_cb_s *hcicb;
FAR struct bt_l2cap_chan_s *l2capcb;
+#else
+ FAR struct bt_hci_cb_s *hcicb;
+#endif
int ret;
/* 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_rmmac = btnet_rmmac; /* Remove multicast MAC address */
#endif
- #ifdef CONFIG_NETDEV_IOCTL
+#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_WIRELESS_BLUETOOTH_HOST)
netdev->d_ioctl = btnet_ioctl; /* Handle network IOCTL commands */
#endif
netdev->d_private = priv; /* Used to recover private state from netdev */
/* Connection status change callbacks */
+#ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
hcicb = &priv->bd_hcicb;
hcicb->context = priv;
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;
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 */