Bluetooth: Start implementing BTPROTO_HCI socket support
Signed-off-by: Brennan Ashton <bashton@brennanashton.com>
This commit is contained in:
parent
3098b61776
commit
1080d3f411
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user