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 */