From 1080d3f411bfbb413a84a91b1d224d86f3aaf18c Mon Sep 17 00:00:00 2001 From: Brennan Ashton Date: Fri, 28 Aug 2020 14:51:26 -0700 Subject: [PATCH] Bluetooth: Start implementing BTPROTO_HCI socket support Signed-off-by: Brennan Ashton --- include/nuttx/net/net.h | 6 +- net/bluetooth/bluetooth.h | 64 +++---- net/bluetooth/bluetooth_sockif.c | 283 ++++++++++++++++++++++++++----- net/socket/socket.c | 1 + wireless/bluetooth/bt_hcicore.c | 30 +++- 5 files changed, 302 insertions(+), 82 deletions(-) diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 836edbf140..33fe2edea1 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 29de921182..8f8a1bb92c 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 + * 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 * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * 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 911a70d30a..ba30746e1a 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 @@ -425,6 +501,60 @@ static int bluetooth_bind(FAR struct socket *psock, return OK; } +/**************************************************************************** + * 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 * @@ -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,51 +763,119 @@ 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)) + switch (psock->s_proto) { - 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; + 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 = -EDESTADDRREQ; + ret = -EINVAL; } 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 * @@ -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 e481ce84be..86fcfdb1e4 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 7e2a42d405..859a52b627 100644 --- a/wireless/bluetooth/bt_hcicore.c +++ b/wireless/bluetooth/bt_hcicore.c @@ -120,6 +120,30 @@ static struct work_s g_hp_work; * Private Functions ****************************************************************************/ +/**************************************************************************** + * 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 * @@ -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; }