Bluetooth: Start implementing BTPROTO_HCI socket support

Signed-off-by: Brennan Ashton <bashton@brennanashton.com>
This commit is contained in:
Brennan Ashton 2020-08-28 14:51:26 -07:00
parent 3098b61776
commit 1080d3f411
5 changed files with 302 additions and 82 deletions

View File

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

View File

@ -1,35 +1,20 @@
/****************************************************************************
* net/bluetooth/bluetooth.h
*
* Copyright (C) 2018-2019 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* 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
@ -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:

View File

@ -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;
@ -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);
@ -630,19 +765,68 @@ 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)
{
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. */
switch (psock->s_proto)
{
case BTPROTO_L2CAP:
{
ret = bluetooth_l2cap_send(psock, buf, len, flags);
break;
}
case BTPROTO_HCI:
{
ret = bluetooth_hci_send(psock, buf, len, flags);
break;
}
default:
ret = -EPFNOSUPPORT;
}
}
else
{
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))
{
@ -660,19 +844,38 @@ static ssize_t bluetooth_send(FAR struct socket *psock, FAR const void *buf,
(FAR const struct sockaddr *)&to,
sizeof(struct sockaddr_l2));
}
}
else
{
/* EDESTADDRREQ. Signifies that the socket is not connection-mode and
* no peer address is set.
*/
ret = -EDESTADDRREQ;
}
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 */

View File

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

View File

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