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

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

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;
     }