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