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:34 UTC

[incubator-nuttx] branch master updated (3098b61 -> 5386f97)

This is an automated email from the ASF dual-hosted git repository.

btashton pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git.


    from 3098b61  Revert "arch/sim: Make the SIGUSR1 host signal to use the NuttX irq logic"
     new 1080d3f  Bluetooth: Start implementing BTPROTO_HCI socket support
     new 5386f97  bluetooth: Add support for HCI RAW channel; make host layer optional

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 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 +
 include/nuttx/net/net.h          |   6 +-
 net/bluetooth/bluetooth.h        |  69 ++++-----
 net/bluetooth/bluetooth_conn.c   |  56 ++++++-
 net/bluetooth/bluetooth_sendto.c |  56 ++++++-
 net/bluetooth/bluetooth_sockif.c | 280 ++++++++++++++++++++++++++++++-----
 net/socket/sendmsg.c             |   2 +-
 net/socket/socket.c              |   1 +
 wireless/bluetooth/Kconfig       |  15 +-
 wireless/bluetooth/Make.defs     |  12 +-
 wireless/bluetooth/bt_buf.c      |   8 +-
 wireless/bluetooth/bt_hcicore.c  |  82 ++++++++++-
 wireless/bluetooth/bt_hcicore.h  |  42 +++++-
 wireless/bluetooth/bt_netdev.c   | 310 ++++++++++++++++++++++++++++++++++++++-
 17 files changed, 848 insertions(+), 114 deletions(-)


[incubator-nuttx] 02/02: bluetooth: Add support for HCI RAW channel; make host layer optional

Posted by bt...@apache.org.
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 */
 


[incubator-nuttx] 01/02: Bluetooth: Start implementing BTPROTO_HCI socket support

Posted by bt...@apache.org.
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 1080d3f411bfbb413a84a91b1d224d86f3aaf18c
Author: Brennan Ashton <ba...@brennanashton.com>
AuthorDate: Fri Aug 28 14:51:26 2020 -0700

    Bluetooth: Start implementing BTPROTO_HCI socket support
    
    Signed-off-by: Brennan Ashton <ba...@brennanashton.com>
---
 include/nuttx/net/net.h          |   6 +-
 net/bluetooth/bluetooth.h        |  68 ++++------
 net/bluetooth/bluetooth_sockif.c | 281 +++++++++++++++++++++++++++++++++------
 net/socket/socket.c              |   1 +
 wireless/bluetooth/bt_hcicore.c  |  30 ++++-
 5 files changed, 303 insertions(+), 83 deletions(-)

diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index 836edbf..33fe2ed 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -263,9 +263,9 @@ struct devif_callback_s;  /* Forward reference */
 struct socket
 {
   int16_t       s_crefs;     /* Reference count on the socket */
-  uint8_t       s_domain;    /* IP domain: PF_INET, PF_INET6, or PF_PACKET */
-  uint8_t       s_type;      /* Protocol type: Only SOCK_STREAM or
-                              * SOCK_DGRAM */
+  uint8_t       s_domain;    /* IP domain */
+  uint8_t       s_type;      /* Protocol type */
+  uint8_t       s_proto;     /* Socket Protocol */
   uint8_t       s_flags;     /* See _SF_* definitions */
 
   /* Socket options */
diff --git a/net/bluetooth/bluetooth.h b/net/bluetooth/bluetooth.h
index 29de921..8f8a1bb 100644
--- a/net/bluetooth/bluetooth.h
+++ b/net/bluetooth/bluetooth.h
@@ -1,35 +1,20 @@
 /****************************************************************************
  * net/bluetooth/bluetooth.h
  *
- *   Copyright (C) 2018-2019 Gregory Nutt. All rights reserved.
- *   Author: Gregory Nutt <gn...@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
  *
  ****************************************************************************/
 
@@ -106,6 +91,7 @@ struct bluetooth_conn_s
                                                * Necessary only to support multiple
                                                * Bluetooth devices */
   bt_addr_t bc_raddr;                         /* Connected remote address */
+  uint8_t bc_ldev;                            /* Locally bound device */
   uint8_t bc_channel;                         /* Connection channel */
   uint8_t bc_crefs;                           /* Reference counts on this instance */
 #if CONFIG_NET_BLUETOOTH_BACKLOG > 0
@@ -139,10 +125,10 @@ EXTERN const struct sock_intf_s g_bluetooth_sockif;
  ****************************************************************************/
 
 struct bluetooth_frame_meta_s;  /* Forward reference */
-struct radio_driver_s;        /* Forward reference */
-struct net_driver_s;          /* Forward reference */
-struct socket;                /* Forward reference */
-struct sockaddr;              /* Forward reference */
+struct radio_driver_s;          /* Forward reference */
+struct net_driver_s;            /* Forward reference */
+struct socket;                  /* Forward reference */
+struct sockaddr;                /* Forward reference */
 
 /****************************************************************************
  * Name: bluetooth_initialize()
@@ -272,7 +258,8 @@ FAR struct bluetooth_conn_s *
  * Name: bluetooth_callback
  *
  * Description:
- *   Inform the application holding the Bluetooth socket of a change in state.
+ *   Inform the application holding the Bluetooth socket of a change in
+ *   state.
  *
  * Returned Value:
  *   OK if Bluetooth has been processed, otherwise ERROR.
@@ -291,9 +278,9 @@ uint16_t bluetooth_callback(FAR struct radio_driver_s *radio,
  *
  * Description:
  *   Implements the socket recvfrom interface for the case of the AF_INET
- *   and AF_INET6 address families.  bluetooth_recvfrom() receives messages from
- *   a socket, and may be used to receive data on a socket whether or not it
- *   is connection-oriented.
+ *   and AF_INET6 address families.  bluetooth_recvfrom() receives messages
+ *   from a socket, and may be used to receive data on a socket whether or
+ *   not it is connection-oriented.
  *
  *   If 'from' is not NULL, and the underlying protocol provides the source
  *   address, this source address is filled in.  The argument 'fromlen' is
@@ -390,7 +377,8 @@ void bluetooth_poll(FAR struct net_driver_s *dev,
 ssize_t psock_bluetooth_sendto(FAR struct socket *psock,
                                 FAR const void *buf,
                                 size_t len, int flags,
-                                FAR const struct sockaddr *to, socklen_t tolen);
+                                FAR const struct sockaddr *to,
+                                socklen_t tolen);
 
 /****************************************************************************
  * Name: bluetooth_container_initialize
@@ -428,8 +416,8 @@ void bluetooth_container_initialize(void);
  *   None
  *
  * Returned Value:
- *   A reference to the allocated container structure.  All user fields in this
- *   structure have been zeroed.  On a failure to allocate, NULL is
+ *   A reference to the allocated container structure.  All user fields in
+ *   this structure have been zeroed.  On a failure to allocate, NULL is
  *   returned.
  *
  * Assumptions:
diff --git a/net/bluetooth/bluetooth_sockif.c b/net/bluetooth/bluetooth_sockif.c
index 911a70d..ba30746 100644
--- a/net/bluetooth/bluetooth_sockif.c
+++ b/net/bluetooth/bluetooth_sockif.c
@@ -72,6 +72,18 @@ static ssize_t    bluetooth_sendto(FAR struct socket *psock,
                    FAR const struct sockaddr *to, socklen_t tolen);
 static int        bluetooth_close(FAR struct socket *psock);
 
+/* Protocol Specific Interfaces */
+
+static int        bluetooth_l2cap_bind(FAR struct socket *psock,
+                    FAR const struct sockaddr_l2 *addr, socklen_t addrlen);
+static int        bluetooth_hci_bind(FAR struct socket *psock,
+                    FAR const struct sockaddr_hci *addr,
+                    socklen_t addrlen);
+static ssize_t    bluetooth_l2cap_send(FAR struct socket *psock,
+                   FAR const void *buf, size_t len, int flags);
+static ssize_t    bluetooth_hci_send(FAR struct socket *psock,
+                   FAR const void *buf, size_t len, int flags);
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
@@ -270,6 +282,13 @@ static int bluetooth_connect(FAR struct socket *psock,
 
   if (addr->sa_family == AF_BLUETOOTH)
     {
+      /* Verify the Protocol */
+
+      if (psock->s_proto != BTPROTO_L2CAP)
+        {
+          return -EPFNOSUPPORT;
+        }
+
       /* Save the "connection" address */
 
       btaddr = (FAR struct sockaddr_l2 *)addr;
@@ -333,9 +352,9 @@ static int bluetooth_connect(FAR struct socket *psock,
  ****************************************************************************/
 
 static int bluetooth_accept(FAR struct socket *psock,
-                             FAR struct sockaddr *addr,
-                             FAR socklen_t *addrlen,
-                             FAR struct socket *newsock)
+                            FAR struct sockaddr *addr,
+                            FAR socklen_t *addrlen,
+                            FAR struct socket *newsock)
 {
   return -EAFNOSUPPORT;
 }
@@ -364,22 +383,81 @@ static int bluetooth_accept(FAR struct socket *psock,
 static int bluetooth_bind(FAR struct socket *psock,
                           FAR const struct sockaddr *addr, socklen_t addrlen)
 {
-  FAR const struct sockaddr_l2 *iaddr;
-  FAR struct radio_driver_s *radio;
-  FAR struct bluetooth_conn_s *conn;
-
   DEBUGASSERT(psock != NULL && addr != NULL);
 
   /* Verify that a valid address has been provided */
 
-  if (addr->sa_family != AF_BLUETOOTH ||
-      addrlen < sizeof(struct sockaddr_l2))
+  if (addr->sa_family != AF_BLUETOOTH)
     {
-      nerr("ERROR: Invalid family: %u or address length: %d < %d\n",
-           addr->sa_family, addrlen, sizeof(struct sockaddr_l2));
+      nerr("ERROR: Invalid family: %u\n", addr->sa_family);
       return -EBADF;
     }
 
+  switch (psock->s_proto)
+    {
+      case BTPROTO_L2CAP:
+        {
+          FAR const struct sockaddr_l2 *iaddr;
+          if (addrlen < sizeof(struct sockaddr_l2))
+            {
+              nerr("ERROR: Invalid address length: %d < %d\n",
+                   addrlen, sizeof(struct sockaddr_l2));
+              return -EBADF;
+            }
+
+          iaddr = (FAR const struct sockaddr_l2 *)addr;
+          return bluetooth_l2cap_bind(psock, iaddr, addrlen);
+        }
+
+      case BTPROTO_HCI:
+        {
+          FAR const struct sockaddr_hci *hciaddr;
+          if (addrlen < sizeof(struct sockaddr_hci))
+            {
+              nerr("ERROR: Invalid address length: %d < %d\n",
+                   addrlen, sizeof(struct sockaddr_hci));
+              return -EBADF;
+            }
+
+          hciaddr = (FAR const struct sockaddr_hci *)addr;
+          return bluetooth_hci_bind(psock, hciaddr, addrlen);
+        }
+
+      default:
+        return -EPFNOSUPPORT;
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: bluetooth_l2cap_bind
+ *
+ * Description:
+ *   bluetooth_bind() gives the socket 'psock' the local address 'iaddr'.
+ *   'iaddr' is 'addrlen' bytes long.  Traditionally, this is called
+ *   "assigning a name to a socket."  When a socket is created with
+ *   socket(), it exists in a name space (address family) but has no name
+ *   assigned.
+ *
+ * Input Parameters:
+ *   psock    Socket structure of the socket to bind
+ *   iaddr    Socket local address
+ *   addrlen  Length of 'addr'
+ *
+ * Returned Value:
+ *   0 on success;  A negated errno value is returned on failure.  See
+ *   bind() for a list a appropriate error values.
+ *
+ ****************************************************************************/
+
+static int bluetooth_l2cap_bind(FAR struct socket *psock,
+                                FAR const struct sockaddr_l2 *iaddr,
+                                socklen_t addrlen)
+{
+  FAR struct radio_driver_s *radio;
+  FAR struct bluetooth_conn_s *conn;
+
   /* Bind a PF_BLUETOOTH socket to an network device.
    *
    * Only SOCK_RAW is supported
@@ -399,8 +477,6 @@ static int bluetooth_bind(FAR struct socket *psock,
       return -EINVAL;
     }
 
-  iaddr = (FAR const struct sockaddr_l2 *)addr;
-
   /* Very that some address was provided.
    *
    * REVISIT: Currently and explicit address must be assigned.  Should we
@@ -426,6 +502,60 @@ static int bluetooth_bind(FAR struct socket *psock,
 }
 
 /****************************************************************************
+ * Name: bluetooth_l2cap_bind
+ *
+ * Description:
+ *   bluetooth_bind() gives the socket 'psock' the local address 'hciaddr'.
+ *   'hciaddr' is 'addrlen' bytes long.  Traditionally, this is called
+ *   "assigning a name to a socket."  When a socket is created with
+ *   socket(), it exists in a name space (address family) but has no name
+ *   assigned.
+ *
+ * Input Parameters:
+ *   psock    Socket structure of the socket to bind
+ *   hciaddr  Socket local address
+ *   addrlen  Length of 'addr'
+ *
+ * Returned Value:
+ *   0 on success;  A negated errno value is returned on failure.  See
+ *   bind() for a list a appropriate error values.
+ *
+ ****************************************************************************/
+
+static int bluetooth_hci_bind(FAR struct socket *psock,
+                              FAR const struct sockaddr_hci *hciaddr,
+                             socklen_t addrlen)
+{
+  FAR struct bluetooth_conn_s *conn;
+
+  /* Bind a PF_BLUETOOTH socket to an network device.
+   *
+   * Only SOCK_RAW is supported
+   */
+
+  if (psock->s_type != SOCK_RAW)
+    {
+      nerr("ERROR: Invalid socket type: %u\n", psock->s_type);
+      return -EBADF;
+    }
+
+  /* Verify that the socket is not already bound. */
+
+  if (_SS_ISBOUND(psock->s_flags))
+    {
+      nerr("ERROR: Already bound\n");
+      return -EINVAL;
+    }
+
+  conn = (FAR struct bluetooth_conn_s *)psock->s_conn;
+
+  conn->bc_channel = hciaddr->hci_channel;
+  conn->bc_ldev = hciaddr->hci_dev;
+
+  return OK;
+}
+
+/****************************************************************************
  * Name: bluetooth_getsockname
  *
  * Description:
@@ -525,6 +655,11 @@ static int bluetooth_getpeername(FAR struct socket *psock,
 
   DEBUGASSERT(psock != NULL && addr != NULL && addrlen != NULL);
 
+  if (psock->s_proto != BTPROTO_L2CAP)
+    {
+      return -EPFNOSUPPORT;
+    }
+
   conn = (FAR struct bluetooth_conn_s *)psock->s_conn;
   DEBUGASSERT(conn != NULL);
 
@@ -628,52 +763,120 @@ static int bluetooth_poll_local(FAR struct socket *psock,
  ****************************************************************************/
 
 static ssize_t bluetooth_send(FAR struct socket *psock, FAR const void *buf,
-                               size_t len, int flags)
+                              size_t len, int flags)
 {
-  struct sockaddr_l2 to;
-  FAR struct bluetooth_conn_s *conn;
   ssize_t ret;
-
   DEBUGASSERT(psock != NULL || buf != NULL);
-  conn = (FAR struct bluetooth_conn_s *)psock->s_conn;
-  DEBUGASSERT(conn != NULL);
 
   /* Only SOCK_RAW is supported */
 
   if (psock->s_type == SOCK_RAW)
     {
-      /* send() may be used only if the socket is has been connected. */
-
-      if (!_SS_ISCONNECTED(psock->s_flags))
-        {
-          ret = -ENOTCONN;
-        }
-      else
+      switch (psock->s_proto)
         {
-          to.l2_family = AF_BLUETOOTH;
-          memcpy(&to.l2_bdaddr, &conn->bc_raddr, sizeof(bt_addr_t));
-          to.l2_cid = conn->bc_channel;
+          case BTPROTO_L2CAP:
+            {
+              ret = bluetooth_l2cap_send(psock, buf, len, flags);
+              break;
+            }
 
-          /* Then perform the send() as sendto() */
+          case BTPROTO_HCI:
+            {
+              ret = bluetooth_hci_send(psock, buf, len, flags);
+              break;
+            }
 
-          ret = psock_bluetooth_sendto(psock, buf, len, flags,
-                                        (FAR const struct sockaddr *)&to,
-                                        sizeof(struct sockaddr_l2));
+          default:
+            ret = -EPFNOSUPPORT;
         }
     }
   else
     {
-      /* EDESTADDRREQ.  Signifies that the socket is not connection-mode and
-       * no peer address is set.
-       */
+      ret = -EINVAL;
+    }
 
-      ret = -EDESTADDRREQ;
+  return ret;
+}
+
+/****************************************************************************
+ * Name: bluetooth_l2cap_send
+ *
+ * Description:
+ *   Socket send() method for the PF_BLUETOOTH socket over BTPROTO_L2CAP.
+ *
+ * Input Parameters:
+ *   psock    An instance of the internal socket structure.
+ *   buf      Data to send
+ *   len      Length of data to send
+ *   flags    Send flags
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error, a negated
+ *   errno value is returned (see send() for the list of appropriate error
+ *   values.
+ *
+ ****************************************************************************/
+
+static ssize_t bluetooth_l2cap_send(FAR struct socket *psock,
+                                    FAR const void *buf,
+                                    size_t len, int flags)
+{
+  struct sockaddr_l2 to;
+  FAR struct bluetooth_conn_s *conn;
+  ssize_t ret;
+
+  conn = (FAR struct bluetooth_conn_s *)psock->s_conn;
+  DEBUGASSERT(conn != NULL);
+
+  if (!_SS_ISCONNECTED(psock->s_flags))
+    {
+      ret = -ENOTCONN;
+    }
+  else
+    {
+      to.l2_family = AF_BLUETOOTH;
+      memcpy(&to.l2_bdaddr, &conn->bc_raddr, sizeof(bt_addr_t));
+      to.l2_cid = conn->bc_channel;
+
+      /* Then perform the send() as sendto() */
+
+      ret = psock_bluetooth_sendto(psock, buf, len, flags,
+                                   (FAR const struct sockaddr *)&to,
+                                   sizeof(struct sockaddr_l2));
     }
 
   return ret;
 }
 
 /****************************************************************************
+ * Name: bluetooth_hci_send
+ *
+ * Description:
+ *   Socket send() method for the PF_BLUETOOTH socket over BTPROTO_HCI.
+ *
+ * Input Parameters:
+ *   psock    An instance of the internal socket structure.
+ *   buf      Data to send
+ *   len      Length of data to send
+ *   flags    Send flags
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error, a negated
+ *   errno value is returned (see send() for the list of appropriate error
+ *   values.
+ *
+ ****************************************************************************/
+
+static ssize_t bluetooth_hci_send(FAR struct socket *psock,
+                                  FAR const void *buf,
+                                  size_t len, int flags)
+{
+#warning Missing logic
+
+  return -EPFNOSUPPORT;
+}
+
+/****************************************************************************
  * Name: bluetooth_sendto
  *
  * Description:
@@ -702,9 +905,9 @@ static ssize_t bluetooth_sendto(FAR struct socket *psock,
 {
   ssize_t ret;
 
-  /* Only SOCK_RAW is supported */
+  /* Only SOCK_RAW on L2CAP is supported */
 
-  if (psock->s_type == SOCK_RAW)
+  if (psock->s_type == SOCK_RAW && psock->s_proto == BTPROTO_L2CAP)
     {
       /* Raw packet send */
 
diff --git a/net/socket/socket.c b/net/socket/socket.c
index e481ce8..86fcfdb 100644
--- a/net/socket/socket.c
+++ b/net/socket/socket.c
@@ -86,6 +86,7 @@ int psock_socket(int domain, int type, int protocol,
 
   psock->s_crefs  = 1;
   psock->s_domain = domain;
+  psock->s_proto  = protocol;
   psock->s_conn   = NULL;
 #if defined(CONFIG_NET_TCP_WRITE_BUFFERS) || defined(CONFIG_NET_UDP_WRITE_BUFFERS)
   psock->s_sndcb  = NULL;
diff --git a/wireless/bluetooth/bt_hcicore.c b/wireless/bluetooth/bt_hcicore.c
index 7e2a42d..859a52b 100644
--- a/wireless/bluetooth/bt_hcicore.c
+++ b/wireless/bluetooth/bt_hcicore.c
@@ -121,6 +121,30 @@ static struct work_s g_hp_work;
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: bt_send
+ *
+ * Description:
+ *   Add the provided buffer 'buf' to the head selected buffer list 'list'
+ *
+ * Input Parameters:
+ *   btdev - An instance of the low-level drivers interface structure.
+ *   buf   - The buffer to be sent by the driver
+ *
+ * Returned Value:
+ *   Zero is returned on success; a negated errno value is returned on any
+ *   failure.
+ *
+ ****************************************************************************/
+
+static int bt_send(FAR const struct bt_driver_s *btdev,
+                   FAR struct bt_buf_s *buf)
+{
+  /* TODDO: Hook here to notify hci monitor */
+
+  return btdev->send(btdev, buf);
+}
+
+/****************************************************************************
  * Name: bt_enqueue_bufwork
  *
  * Description:
@@ -1049,6 +1073,8 @@ static void hci_rx_work(FAR void *arg)
     {
       wlinfo("buf %p type %u len %u\n", buf, buf->type, buf->len);
 
+      /* TODO: Hook monitor callback */
+
       switch (buf->type)
         {
           case BT_ACL_IN:
@@ -1096,6 +1122,8 @@ static void priority_rx_work(FAR void *arg)
 
       wlinfo("buf %p type %u len %u\n", buf, buf->type, buf->len);
 
+      /* TODO: Hook monitor callback */
+
       if (buf->type != BT_EVT)
         {
           wlerr("Unknown buf type %u\n", buf->type);
@@ -1684,7 +1712,7 @@ int bt_hci_cmd_send(uint16_t opcode, FAR struct bt_buf_s *buf)
 
   if (opcode == BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS)
     {
-      g_btdev.btdev->send(g_btdev.btdev, buf);
+      bt_send(g_btdev.btdev, buf);
       bt_buf_release(buf);
       return 0;
     }