diff --git a/drivers/wireless/bluetooth/bt_uart.c b/drivers/wireless/bluetooth/bt_uart.c index 8b3e50c7159..26baf4b7e4f 100644 --- a/drivers/wireless/bluetooth/bt_uart.c +++ b/drivers/wireless/bluetooth/bt_uart.c @@ -268,7 +268,7 @@ static void btuart_interrupt(FAR const struct btuart_lowerhalf_s *lower, /* Pass buffer to the stack */ - bt_recv(buf); + bt_input(buf); buf = NULL; } diff --git a/include/netpacket/bluetooth.h b/include/netpacket/bluetooth.h new file mode 100644 index 00000000000..acb55afedf5 --- /dev/null +++ b/include/netpacket/bluetooth.h @@ -0,0 +1,84 @@ +/**************************************************************************** + * include/netpacket/bluetooth.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NETPACKET_BLUETOOTH_H +#define __INCLUDE_NETPACKET_BLUETOOTH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Well known addresses */ + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/* See include/nuttx/wireless/bt_hci.h for address definitions. In + * particular, type bt_addr_t + */ + +/* Socket address used with: + * + * bind() - Associates local address with socket + * connect() - Associates a remote address with the socket (for send()) + * sendto() - Send to specified remote address + * recvfrom()- Receive from indicated remote address. + * + * The 'rc' in the naming derives from RFCCOMM as used in Linux. The + * resemblances are superficial beyond that, however. + */ + +struct sockaddr_rc_s +{ + sa_family_t rc_family; + bt_addr_t rc_bdaddr; + uint8_t rc_channel; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#endif /* __INCLUDE_NETPACKET_BLUETOOTH_H */ diff --git a/include/nuttx/net/bluetooth.h b/include/nuttx/net/bluetooth.h new file mode 100644 index 00000000000..4d56d072251 --- /dev/null +++ b/include/nuttx/net/bluetooth.h @@ -0,0 +1,128 @@ +/**************************************************************************** + * include/nuttx/net/bluetooth.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_NET_BLUETOOTH_H +#define __INCLUDE_NUTTX_NET_BLUETOOTH_H + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* REVISIT: Is there any header on the Bluetooth data as received by the + * network stack? + */ + +#warning REVISIT + +#define BLUETOOTH_HDRLEN 0 +#define BLUETOOTH_ADDRSIZE 6 +#define BLUETOOTH_ADDRCOPY(d,s) memcpy((d),(s),BLUETOOTH_ADDRSIZE) +#define BLUETOOTH_ADDRCMP(a,b) (memcmp((a),(b),BLUETOOTH_ADDRSIZE) == 0) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* This is the form of the meta-data that accompanies frames received from + * the Bluetooth stack. + */ + +struct bluetooth_frame_meta_s +{ + bt_addr_t bm_raddr; /* Connected remote address */ + uint8_t bm_channel; /* Connection channel */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_input + * + * Description: + * Handle incoming Bluetooth input + * + * This function is called when the radio device driver has received an + * frame from the network. The frame from the device driver must be + * provided in by the IOB frame argument of the function call: + * + * - The frame data is in the IOB io_data[] buffer, + * - The length of the frame is in the IOB io_len field, and + * - The offset past and radio MAC header is provided in the io_offset + * field. + * + * The frame argument may refer to a single frame (a list of length one) + * or may it be the head of a list of multiple frames. + * + * - The io_flink field points to the next frame in the list (if enable) + * - The last frame in the list will have io_flink == NULL. + * + * Input Parameters: + * radio The radio network driver interface. + * framelist - The head of an incoming list of frames. Normally this + * would be a single frame. A list may be provided if + * appropriate, however. + * meta - Meta data characterizing the received frame. + * + * If there are multiple frames in the list, this metadata + * must apply to all of the frames in the list. + * + * Returned Value: + * OK The Bluetooth has been processed and can be deleted + * ERROR Hold the Bluetooth and try again later. There is a listening + * socket but no recv in place to catch the Bluetooth yet. + * Useful when a packet arrives before a recv call is in place. + * + * Assumptions: + * Called from the network diver with the network locked. + * + ****************************************************************************/ + +struct radio_driver_s; /* Forward reference */ +struct bluetooth_data_ind_s; /* Forward reference */ +struct iob_s; /* Forward reference */ + +int bluetooth_input(FAR struct radio_driver_s *radio, + FAR struct iob_s *framelist, + FAR struct bluetooth_frame_meta_s *meta); + +#endif /* __INCLUDE_NUTTX_NET_BLUETOOTH_H */ diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h index 5161550415a..677984753cb 100644 --- a/include/nuttx/net/net.h +++ b/include/nuttx/net/net.h @@ -116,6 +116,7 @@ enum net_lltype_e NET_LL_LOOPBACK, /* Local loopback */ NET_LL_SLIP, /* Serial Line Internet Protocol (SLIP) */ NET_LL_TUN, /* TUN Virtual Network Device */ + NET_LL_BLUETOOTH, /* Bluetooth */ NET_LL_IEEE80211, /* IEEE 802.11 */ NET_LL_IEEE802154, /* IEEE 802.15.4 MAC */ NET_LL_PKTRADIO /* Non-standard packet radio */ diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index 0693dab1fb5..3e9121f8615 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -77,6 +77,12 @@ # endif #elif defined(CONFIG_WIRELESS_IEEE802154) # define RADIO_MAX_ADDRLEN 8 +#elif defined(CONFIG_WIRELESS_BLUETOOTH) +# if CONFIG_PKTRADIO_ADDRLEN > 6 +# define RADIO_MAX_ADDRLEN CONFIG_PKTRADIO_ADDRLEN +# else +# define RADIO_MAX_ADDRLEN 6 +# endif #else /* if defined(CONFIG_WIRELESS_PKTRADIO) */ # define RADIO_MAX_ADDRLEN CONFIG_PKTRADIO_ADDRLEN #endif @@ -182,9 +188,13 @@ struct netdev_statistics_s }; #endif -#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_IEEE802154) +#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_BLUETOOTH) || \ + defined(CONFIG_NET_IEEE802154) /* This structure is used to represent addresses of varying length. This * structure is used to represent the address assigned to a radio. + * + * NOTE: the Bluetooth address is not variable, but shares struct + * radio_driver_s which depends on this type. */ struct netdev_maxaddr_s @@ -237,7 +247,7 @@ struct net_driver_s #endif #if defined(CONFIG_NET_ETHERNET) || defined(CONFIG_NET_6LOWPAN) || \ - defined(CONFIG_NET_IEEE802154) + defined(CONFIG_NET_BLUETOOTH) || defined(CONFIG_NET_IEEE802154) /* Link layer address */ @@ -249,13 +259,14 @@ struct net_driver_s struct ether_addr ether; /* Device Ethernet MAC address */ #endif -#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_IEEE802154) +#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_BLUETOOTH) || \ + defined(CONFIG_NET_IEEE802154) /* The address assigned to an IEEE 802.15.4 or generic packet radio. */ struct netdev_varaddr_s radio; -#endif /* CONFIG_NET_6LOWPAN || CONFIG_NET_IEEE802154 */ +#endif } d_mac; -#endif /* CONFIG_NET_ETHERNET || CONFIG_NET_6LOWPAN || CONFIG_NET_IEEE802154 */ +#endif /* CONFIG_NET_ETHERNET || CONFIG_NET_6LOWPAN ... || CONFIG_NET_IEEE802154 */ /* Network identity */ diff --git a/include/nuttx/net/radiodev.h b/include/nuttx/net/radiodev.h index b2e95e72725..641548419cf 100644 --- a/include/nuttx/net/radiodev.h +++ b/include/nuttx/net/radiodev.h @@ -44,7 +44,8 @@ #include -#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_IEEE802154) +#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_BLUETOOTH) || \ + defined (CONFIG_NET_IEEE802154) /**************************************************************************** * Public Types @@ -155,7 +156,7 @@ struct iob_s; /* Forward reference */ struct radio_driver_s { - /* This definitiona must appear first in the structure definition to + /* This definition must appear first in the structure definition to * assure cast compatibility. */ @@ -251,5 +252,5 @@ struct radio_driver_s * Public Function Prototypes ****************************************************************************/ -#endif /* CONFIG_NET_6LOWPAN || CONFIG_NET_IEEE802154 */ +#endif /* CONFIG_NET_6LOWPAN || CONFIG_NET_BLUETOOTH || CONFIG_NET_IEEE802154 */ #endif /* __INCLUDE_NUTTX_NET_RADIODEV_H */ diff --git a/include/nuttx/wireless/bt_conn.h b/include/nuttx/wireless/bt_conn.h deleted file mode 100644 index 5088a732504..00000000000 --- a/include/nuttx/wireless/bt_conn.h +++ /dev/null @@ -1,232 +0,0 @@ -/**************************************************************************** - * wireless/bluetooth/bt_conn.h - * Bluetooth connection handling. - * - * Copyright (C) 2018 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * Ported from the Intel/Zephyr arduino101_firmware_source-v1.tar package - * where the code was released with a compatible 3-clause BSD license: - * - * Copyright (c) 2016, Intel Corporation - * All rights reserved. - * - * 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 of the copyright holder 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 HOLDER 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. - * - ****************************************************************************/ - -#ifndef __INCLUDE_NUTTX_WIRELESS_BT_CONN_H -#define __INCLUDE_NUTTX_WIRELESS_BT_CONN_H 1 - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/* Connection callback structure */ - -struct bt_conn_s; /* Forward Reference */ -struct bt_conn_cb_s -{ - CODE void (*connected)(FAR struct bt_conn_s *conn); - CODE void (*disconnected)(FAR struct bt_conn_s *conn); - FAR struct bt_conn_cb_s *next; -}; - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Name: bt_conn_get - * - * Description: - * Increment the reference count of a connection object. - * - * Input Parameters: - * conn - Connection object. - * - * Returned Value: - * Connection object with incremented reference count. - * - ****************************************************************************/ - -FAR struct bt_conn_s *bt_conn_get(FAR struct bt_conn_s *conn); - -/**************************************************************************** - * Name: bt_conn_put - * - * Description: - * Decrement the reference count of a connection object. - * - * Input Parameters: - * conn - Connection object. - * - ****************************************************************************/ - -void bt_conn_put(FAR struct bt_conn_s *conn); - -/**************************************************************************** - * Name: bt_conn_lookup_addr_le - * - * Description: - * Look up an existing connection based on the remote address. - * - * Input Parameters: - * peer - Remote address. - * - * Returned Value: - * Connection object or NULL if not found. The caller gets a new reference - * to the connection object which must be released with bt_conn_put() once - * done using the object. - * - ****************************************************************************/ - -FAR struct bt_conn_s *bt_conn_lookup_addr_le(const bt_addr_le_t *peer); - -/**************************************************************************** - * Name: bt_conn_get_dst - * - * Description: - * Get destination (peer) address of a connection. - * - * Input Parameters: - * conn - Connection object. - * - * Returned Value: - * Destination address. - * - ****************************************************************************/ - -FAR const bt_addr_le_t *bt_conn_get_dst(FAR const struct bt_conn_s *conn); - -/**************************************************************************** - * Name: bt_conn_disconnect - * - * Description: - * Disconnect an active connection with the specified reason code or cancel - * pending outgoing connection. - * - * Input Parameters: - * conn - Connection to disconnect. - * reason - Reason code for the disconnection. - * - * Returned Value: - * Zero on success or (negative) error code on failure. - * - ****************************************************************************/ - -int bt_conn_disconnect(FAR struct bt_conn_s *conn, uint8_t reason); - -/**************************************************************************** - * Name: bt_conn_create_le - * - * Description: - * Allows initiate new LE link to remote peer using its address. - * Returns a new reference that the the caller is responsible for managing. - * - * Input Parameters: - * peer - Remote address. - * - * Returned Value: - * Valid connection object on success or NULL otherwise. - * - ****************************************************************************/ - -FAR struct bt_conn_s *bt_conn_create_le(const bt_addr_le_t *peer); - -/**************************************************************************** - * Name: bt_conn_security - * - * Description: - * This function enable security (encryption) for a connection. If device is - * already paired with sufficiently strong key encryption will be enabled. If - * link is already encrypted with sufficiently strong key this function does - * nothing. - * - * If device is not paired pairing will be initiated. If device is paired and - * keys are too weak but input output capabilities allow for strong enough keys - * pairing will be initiated. - * - * This function may return error if required level of security is not possible - * to achieve due to local or remote device limitation (eg input output - * capabilities). - * - * Input Parameters: - * conn - Connection object. - * sec - Requested security level. - * - * Returned Value: - * 0 on success or negative error - * - ****************************************************************************/ - -int bt_conn_security(FAR struct bt_conn_s *conn, enum bt_security_e sec); - -/**************************************************************************** - * Name: bt_conn_cb_register - * - * Description: - * Register callbacks to monitor the state of connections. - * - * Input Parameters: - * cb - Callback struct. - * - ****************************************************************************/ - -void bt_conn_cb_register(struct bt_conn_cb_s *cb); - -/**************************************************************************** - * Name: - * - * Description: - * This function enables/disables automatic connection initiation. - * Every time the device looses the connection with peer, this connection - * will be re-established if connectible advertisement from peer is - * received. - * - * Input Parameters: - * conn - Existing connection object. - * auto_conn - boolean value. If true, auto connect is enabled, if false, - * auto connect is disabled. - * - * Returned Value: - * None - * - ****************************************************************************/ - -void bt_conn_set_auto_conn(FAR struct bt_conn_s *conn, bool auto_conn); - -#endif /* __INCLUDE_NUTTX_WIRELESS_BT_CONN_H */ diff --git a/include/nuttx/wireless/bt_core.h b/include/nuttx/wireless/bt_core.h index 6906e761045..3c657a73c65 100644 --- a/include/nuttx/wireless/bt_core.h +++ b/include/nuttx/wireless/bt_core.h @@ -223,17 +223,4 @@ static inline int bt_addr_le_to_str(FAR const bt_addr_le_t *addr, char *str, * Public Function Prototypes ****************************************************************************/ -/**************************************************************************** - * Name: bt_init - * - * Description: - * Initialize Bluetooth. Must be the called before anything else. - * - * Returned Value: - * Zero on success or (negative) error code otherwise. - * - ****************************************************************************/ - -int bt_init(void); - #endif /* __INCLUDE_NUTTX_WIRELESS_BT_CORE_H */ diff --git a/include/nuttx/wireless/bt_driver.h b/include/nuttx/wireless/bt_driver.h index 5c4c3290344..6f6fbf729d0 100644 --- a/include/nuttx/wireless/bt_driver.h +++ b/include/nuttx/wireless/bt_driver.h @@ -72,16 +72,60 @@ struct bt_driver_s * Public Function Prototypes ****************************************************************************/ -/* Register a new HCI driver to the Bluetooth stack */ +/**************************************************************************** + * Name: bt_driver_register + * + * Description: + * Register the Bluetooth low-level driver with the Bluetooth stack. + * This is called from the low-level driver and is part of the driver + * interface prototyped in include/nuttx/wireless/bt_driver.h + * + * Input Parameters: + * dev - An instance of the low-level drivers interface structure. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ int bt_driver_register(FAR const struct bt_driver_s *dev); -/* Unregister a previously registered HCI driver */ +/**************************************************************************** + * Name: bt_driver_unregister + * + * Description: + * Unregister a Bluetooth low-level driver previously registered with + * bt_driver_register. This may be called from the low-level driver and + * is part of the driver interface prototyped in + * include/nuttx/wireless/bt_driver.h + * + * Input Parameters: + * dev - An instance of the low-level drivers interface structure. + * + * Returned Value: + * None + * + ****************************************************************************/ void bt_driver_unregister(FAR const struct bt_driver_s *dev); -/* Receive data from the controller/HCI driver */ +/**************************************************************************** + * Name: bt_input + * + * Description: + * Called by the Bluetooth low-level driver when new data is received from + * the radio. This may be called from the low-level driver and is part of + * the driver interface prototyped in include/nuttx/wireless/bt_driver.h + * + * Input Parameters: + * buf - An instance of the buffer structure providing the received frame. + * + * Returned Value: + * None + * + ****************************************************************************/ -void bt_recv(FAR struct bt_buf_s *buf); +void bt_input(FAR struct bt_buf_s *buf); #endif /* __INCLUDE_NUTTX_WIRELESS_BT_DRIVER_H */ diff --git a/include/nuttx/wireless/bt_gatt.h b/include/nuttx/wireless/bt_gatt.h index d931c6539e8..fa72b191c5e 100644 --- a/include/nuttx/wireless/bt_gatt.h +++ b/include/nuttx/wireless/bt_gatt.h @@ -46,7 +46,6 @@ * Included Files ****************************************************************************/ -#include #include /**************************************************************************** diff --git a/net/Kconfig b/net/Kconfig index 3c4f969486b..4093b62d4d7 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -294,6 +294,7 @@ source "net/pkt/Kconfig" source "net/local/Kconfig" source "net/tcp/Kconfig" source "net/udp/Kconfig" +source "net/bluetooth/Kconfig" source "net/ieee802154/Kconfig" source "net/icmp/Kconfig" source "net/icmpv6/Kconfig" diff --git a/net/Makefile b/net/Makefile index eb51cc79b0d..a9a26970f1d 100644 --- a/net/Makefile +++ b/net/Makefile @@ -1,7 +1,7 @@ ############################################################################ # net/Makefile # -# Copyright (C) 2007, 2008, 2011-2017 Gregory Nutt. All rights reserved. +# Copyright (C) 2007, 2008, 2011-2018 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -68,6 +68,7 @@ include local/Make.defs include tcp/Make.defs include udp/Make.defs include sixlowpan/Make.defs +include bluetooth/Make.defs include ieee802154/Make.defs include devif/Make.defs include ipforward/Make.defs diff --git a/net/README.txt b/net/README.txt index a912e881be8..30de5341d81 100644 --- a/net/README.txt +++ b/net/README.txt @@ -9,6 +9,7 @@ Directory Structure `- net/ | +- arp - Address resolution protocol (IPv4) + +- bluetooth - PF_BLUETOOTH socket interface +- devif - Stack/device interface layer +- icmp - Internet Control Message Protocol (IPv4) +- icmpv6 - Internet Control Message Protocol (IPv6) @@ -28,7 +29,6 @@ Directory Structure +- usrsock - User socket API for user-space networking stack `- utils - Miscellaneous utility functions - +-------------------------------------------------------------------++------------------------+ | Application layer || usrsock daemon | +-------------------------------------------------------------------++------------------------+ diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig new file mode 100644 index 00000000000..49f1e8d1ed4 --- /dev/null +++ b/net/bluetooth/Kconfig @@ -0,0 +1,62 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menu "Bluetooth socket support" + +config NET_BLUETOOTH + bool "Bluetooth socket support" + default n + depends on WIRELESS_BLUETOOTH + select NETDEV_IOCTL + ---help--- + Enable support for raw, Bluetooth sockets. + + Raw sockets allow receiving and transmitting Bluetooth radio + frames without a layer2 protocol such as 6LoWPAN in between. Frames + received are copied into a Bluetooth socket tap before they + enter the network. Frames written into a Bluetooth socket will + bypass the network altogether and will be sent directly to the + Bluetooth MAC network interface driver outgoing frame queue. + +if NET_BLUETOOTH + +config NET_BLUETOOTH_FRAMELEN + int "Bluetooth Frame Length" + default 127 + range 1 999999 + ---help--- + For standard Bluetooth radios, this should always be 127 bytes. + However, some Bluetooth radios may non-standard frame lengths. + + This setting is currently used only for detection data transfers + that would exceed the radio frame length. + +config NET_BLUETOOTH_NCONNS + int "Max Bluetooth sockets" + default 4 + +config NET_BLUETOOTH_NCONTAINERS + int "Number of pre-allocated frame containers" + default 8 + ---help--- + This specifies the total number of preallocated frame containers. + One must be allocated with each incoming frame. + +config NET_BLUETOOTH_BACKLOG + int "Maximum frame backlog" + default 8 + range 0 255 + ---help--- + As frames are received, then are help in an RX queue. They remain + in the RX queue until application logic reads the queue frames. To + prevent overrun, the maximum backlog may be set to a nonzero value. + What the backlog of queue frames reaches that count, the olds frame + will be freed, preventing overrun at the cost of losing the oldest + frames. + + NOTE: The special value of zero will disable all backlog checkes. + +endif # NET_BLUETOOTH +endmenu # Bluetooth Socket Support diff --git a/net/bluetooth/Make.defs b/net/bluetooth/Make.defs new file mode 100644 index 00000000000..1eda5052769 --- /dev/null +++ b/net/bluetooth/Make.defs @@ -0,0 +1,64 @@ +############################################################################ +# net/bluetooth/Make.defs +# +# Copyright (C) 2018 Gregory Nutt. All rights reserved. +# Author: Gregory Nutt +# +# 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. +# +############################################################################ + +# Packet socket support + +ifeq ($(CONFIG_NET_BLUETOOTH),y) + +# Initialization / resource managment + +NET_CSRCS += bluetooth_initialize.c +NET_CSRCS += bluetooth_conn.c +NET_CSRCS += bluetooth_container.c + +# Socket layer + +SOCK_CSRCS += bluetooth_sockif.c +SOCK_CSRCS += bluetooth_sendto.c +SOCK_CSRCS += bluetooth_recvfrom.c + +# Device interface + +NET_CSRCS += bluetooth_input.c +NET_CSRCS += bluetooth_callback.c +NET_CSRCS += bluetooth_poll.c +NET_CSRCS += bluetooth_finddev.c + +# Include packet socket build support + +DEPPATH += --dep-path bluetooth +VPATH += :bluetooth + +endif # CONFIG_NET_BLUETOOTH diff --git a/net/bluetooth/bluetooth.h b/net/bluetooth/bluetooth.h new file mode 100644 index 00000000000..01910b1350e --- /dev/null +++ b/net/bluetooth/bluetooth.h @@ -0,0 +1,487 @@ +/**************************************************************************** + * net/bluetooth/bluetooth.h + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +#ifndef _NET_BLUETOOTH_BLUETOOTH_H +#define _NET_BLUETOOTH_BLUETOOTH_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Allocate a new Bluetooth socket data callback */ + +#define bluetooth_callback_alloc(dev,conn) \ + devif_callback_alloc(dev, &conn->list) +#define bluetooth_callback_free(dev,conn,cb) \ + devif_conn_callback_free(dev, cb, &conn->list) + +/* Memory Pools */ + +#define BLUETOOTH_POOL_PREALLOCATED 0 +#define BLUETOOTH_POOL_DYNAMIC 1 + +/* Frame size */ + +/* This maximum size of an Bluetooth frame. Certain, non-standard + * devices may exceed this value, however. + */ + +#define BLUETOOTH_MAC_STDFRAME 127 + +/* Space for a two byte FCS must be reserved at the end of the frame */ + +#define BLUETOOTH_MAC_FCSSIZE 2 + +/* This, then, is the usable size of the frame... */ + +#if defined(CONFIG_NET_BLUETOOTH_FRAMELEN) +# define BLUETOOTH_MAX_FRAMELEN CONFIG_NET_BLUETOOTH_FRAMELEN +#else +# define BLUETOOTH_MAX_FRAMELEN BLUETOOTH_MAC_STDFRAME +#endif + +#define BLUETOOTH_FRAMELEN (BLUETOOTH_MAX_FRAMELEN - BLUETOOTH_MAC_FCSSIZE) + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +/* Used for containing and queuing IOBs along with information about the + * source of the frame. + */ + +struct iob_s; /* Forward reference */ + +struct bluetooth_container_s +{ + FAR struct bluetooth_container_s *bn_flink; /* Supports a singly linked list */ + FAR struct iob_s *bn_iob; /* Contained IOB */ + bt_addr_t bn_raddr; /* Source address of the packet */ + uint8_t bn_channel; /* Source channel of the packet */ + uint8_t bn_pool; /* See BLUETOOTH_POOL_* definitions */ +}; + +/* Representation of a Bluetooth socket connection */ + +struct devif_callback_s; /* Forward reference */ + +struct bluetooth_conn_s +{ + dq_entry_t bc_node; /* Supports a double linked list */ + bt_addr_t bc_laddr; /* Locally bound / source address. + * Necessary only to support multiple + * Bluetooth devices */ + bt_addr_t bc_raddr; /* Connected remote address */ + uint8_t bc_channel; /* Connection channel */ + uint8_t bc_crefs; /* Reference counts on this instance */ +#if CONFIG_NET_BLUETOOTH_BACKLOG > 0 + uint8_t bc_backlog; /* Number of frames in RX queue */ +#endif + + /* Queue of incoming packets */ + + FAR struct bluetooth_container_s *bc_rxhead; + FAR struct bluetooth_container_s *bc_rxtail; + + /* This is a list of Bluetooth callbacks. Each callback represents + * a thread that is stalled, waiting for a device-specific event. + */ + + FAR struct devif_callback_s *list; +}; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +# define EXTERN extern "C" +extern "C" +{ +#else +# define EXTERN extern +#endif + +/* The Bluetooth socket interface */ + +EXTERN const struct sock_intf_s g_bluetooth_sockif; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +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 */ + +/**************************************************************************** + * Name: bluetooth_initialize() + * + * Description: + * Initialize the Bluetooth socket support. Called once and only + * from the network initialization logic. + * + * Assumptions: + * Called early in the initialization sequence + * + ****************************************************************************/ + +void bluetooth_initialize(void); + +/**************************************************************************** + * Name: bluetooth_conn_initialize + * + * Description: + * Initialize the Bluetooth connection structure allocator. Called + * once and only from bluetooth_initialize(). + * + * Assumptions: + * Called early in the initialization sequence + * + ****************************************************************************/ + +void bluetooth_conn_initialize(void); + +/**************************************************************************** + * Name: bluetooth_conn_alloc() + * + * Description: + * Allocate a new, uninitialized Bluetooth socket connection + * structure. This is normally something done by the implementation of + * the socket() API + * + ****************************************************************************/ + +FAR struct bluetooth_conn_s *bluetooth_conn_alloc(void); + +/**************************************************************************** + * Name: bluetooth_conn_free() + * + * Description: + * Free a Bluetooth socket connection structure that is no longer in + * use. This should be done by the implementation of close(). + * + ****************************************************************************/ + +void bluetooth_conn_free(FAR struct bluetooth_conn_s *conn); + +/**************************************************************************** + * Name: bluetooth_conn_active() + * + * Description: + * Find a connection structure that is the appropriate + * connection to be used with the provided Ethernet header + * + * Assumptions: + * This function is called from network logic at with the network locked. + * + ****************************************************************************/ + +FAR struct bluetooth_conn_s * + bluetooth_conn_active(FAR const struct bluetooth_frame_meta_s *meta); + +/**************************************************************************** + * Name: bluetooth_conn_next() + * + * Description: + * Traverse the list of allocated Bluetooth connections + * + * Assumptions: + * This function is called from network logic at with the network locked. + * + ****************************************************************************/ + +FAR struct bluetooth_conn_s * + bluetooth_conn_next(FAR struct bluetooth_conn_s *conn); + +/**************************************************************************** + * Name: bluetooth_input + * + * Description: + * Handle incoming Bluetooth input + * + * This function is called when the radio device driver has received an + * frame from the network. The frame from the device driver must be + * provided in by the IOB frame argument of the function call: + * + * - The frame data is in the IOB io_data[] buffer, + * - The length of the frame is in the IOB io_len field, and + * - The offset past and radio MAC header is provided in the io_offset + * field. + * + * The frame argument may refer to a single frame (a list of length one) + * or may it be the head of a list of multiple frames. + * + * - The io_flink field points to the next frame in the list (if enable) + * - The last frame in the list will have io_flink == NULL. + * + * Input Parameters: + * radio The radio network driver interface. + * framelist - The head of an incoming list of frames. Normally this + * would be a single frame. A list may be provided if + * appropriate, however. + * meta - Meta data characterizing the received frame. + * + * If there are multiple frames in the list, this metadata + * must apply to all of the frames in the list. + * + * Returned Value: + * OK The Bluetooth has been processed and can be deleted + * ERROR Hold the Bluetooth and try again later. There is a listening + * socket but no recv in place to catch the Bluetooth yet. + * Useful when a packet arrives before a recv call is in place. + * + * Assumptions: + * Called from the network diver with the network locked. + * + ****************************************************************************/ + +/* bluetooth_input() is prototyped in include/nuttx/net/bluetooth.h */ + +/**************************************************************************** + * Name: bluetooth_callback + * + * Description: + * Inform the application holding the Bluetooth socket of a change in state. + * + * Returned Value: + * OK if Bluetooth has been processed, otherwise ERROR. + * + * Assumptions: + * This function is called from network logic at with the network locked. + * + ****************************************************************************/ + +uint16_t bluetooth_callback(FAR struct radio_driver_s *radio, + FAR struct bluetooth_conn_s *conn, + uint16_t flags); + +/**************************************************************************** + * Name: bluetooth_recvfrom + * + * 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. + * + * If 'from' is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument 'fromlen' is + * initialized to the size of the buffer associated with from, and + * modified on return to indicate the actual size of the address stored + * there. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters received. If no data is + * available to be received and the peer has performed an orderly shutdown, + * recv() will return 0. Otherwise, on errors, a negated errno value is + * returned (see recvfrom() for the list of appropriate error values). + * + ****************************************************************************/ + +ssize_t bluetooth_recvfrom(FAR struct socket *psock, FAR void *buf, + size_t len, int flags, FAR struct sockaddr *from, + FAR socklen_t *fromlen); + +/**************************************************************************** + * Name: bluetooth_find_device + * + * Description: + * Select the network driver to use with the Bluetooth transaction. + * + * Input Parameters: + * conn - Bluetooth connection structure (not currently used). + * addr - The address to match the devices assigned address + * + * Returned Value: + * A pointer to the network driver to use. NULL is returned on any + * failure. + * + ****************************************************************************/ + +FAR struct radio_driver_s * + bluetooth_find_device(FAR struct bluetooth_conn_s *conn, + FAR const bt_addr_t *addr); + +/**************************************************************************** + * Name: bluetooth_poll + * + * Description: + * Poll a Bluetooth "connection" structure for availability of TX data + * + * Input Parameters: + * dev - The device driver structure to use in the send operation + * conn - The Bluetooth "connection" to poll for TX data + * + * Returned Value: + * None + * + * Assumptions: + * Called from the network device interface (devif) with the network + * locked. + * + ****************************************************************************/ + +void bluetooth_poll(FAR struct net_driver_s *dev, + FAR struct bluetooth_conn_s *conn); + +/**************************************************************************** + * Name: psock_bluetooth_sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * a negated errno value is retruend. See sendto() for the complete list + * of return values. + * + ****************************************************************************/ + +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); + +/**************************************************************************** + * Name: bluetooth_container_initialize + * + * Description: + * This function initializes the container allocator. This function must + * be called early in the initialization sequence before any socket + * activity. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * Called early in the initialization sequence + * + ****************************************************************************/ + +void bluetooth_container_initialize(void); + +/**************************************************************************** + * Name: bluetooth_container_allocate + * + * Description: + * The bluetooth_container_allocate function will get a free continer + * for use by the recvfrom() logic. + * + * This function will first attempt to allocate from the g_free_container + * list. If that the list is empty, then the meta-data structure will be + * allocated from the dynamic memory pool. + * + * Input Parameters: + * 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 + * returned. + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +FAR struct bluetooth_container_s *bluetooth_container_allocate(void); + +/**************************************************************************** + * Name: bluetooth_container_free + * + * Description: + * The bluetooth_container_free function will return a container structure + * to the free list of containers if it was a pre-allocated container + * structure. If the container structure was allocated dynamically it will + * be deallocated. + * + * Input Parameters: + * container - container structure to free + * + * Returned Value: + * None + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +void bluetooth_container_free(FAR struct bluetooth_container_s *container); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_NET_BLUETOOTH */ +#endif /* _NET_BLUETOOTH_BLUETOOTH_H */ diff --git a/net/bluetooth/bluetooth_callback.c b/net/bluetooth/bluetooth_callback.c new file mode 100644 index 00000000000..a2bfc97e1e9 --- /dev/null +++ b/net/bluetooth/bluetooth_callback.c @@ -0,0 +1,88 @@ +/**************************************************************************** + * net/bluetooth/bluetooth_callback.c + * Forward events to waiting PF_BLUETOOTH sockets. + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include + +#include "devif/devif.h" +#include "bluetooth/bluetooth.h" + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_callback + * + * Description: + * Inform the application holding the packet socket of a change in state. + * + * Returned Value: + * OK if packet has been processed, otherwise ERROR. + * + * Assumptions: + * This function is called at the interrupt level with interrupts disabled. + * + ****************************************************************************/ + +uint16_t bluetooth_callback(FAR struct radio_driver_s *radio, + FAR struct bluetooth_conn_s *conn, + uint16_t flags) +{ + ninfo("flags: %04x\n", flags); + + /* Some sanity checking */ + + if (conn != NULL) + { + /* Perform the callback */ + + flags = devif_conn_event(&radio->r_dev, conn, flags, conn->list); + } + + return flags; +} + +#endif /* CONFIG_NET_BLUETOOTH */ diff --git a/net/bluetooth/bluetooth_conn.c b/net/bluetooth/bluetooth_conn.c new file mode 100644 index 00000000000..20a091e4d76 --- /dev/null +++ b/net/bluetooth/bluetooth_conn.c @@ -0,0 +1,260 @@ +/**************************************************************************** + * net/bluetooth/bluetooth_conn.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "devif/devif.h" +#include "bluetooth/bluetooth.h" + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The array containing all packet socket connections. Protected via the + * network lock. + */ + +static struct bluetooth_conn_s + g_bluetooth_connections[CONFIG_NET_BLUETOOTH_NCONNS]; + +/* A list of all free packet socket connections */ + +static dq_queue_t g_free_bluetooth_connections; + +/* A list of all allocated packet socket connections */ + +static dq_queue_t g_active_bluetooth_connections; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_conn_initialize + * + * Description: + * Initialize the Bluetooth connection structure allocator. Called + * once and only from bluetooth_initialize(). + * + * Assumptions: + * Called early in the initialization sequence + * + ****************************************************************************/ + +void bluetooth_conn_initialize(void) +{ + int i; + + /* Initialize the queues */ + + dq_init(&g_free_bluetooth_connections); + dq_init(&g_active_bluetooth_connections); + + for (i = 0; i < CONFIG_NET_BLUETOOTH_NCONNS; i++) + { + /* Link each pre-allocated connection structure into the free list. */ + + dq_addlast(&g_bluetooth_connections[i].bc_node, + &g_free_bluetooth_connections); + } +} + +/**************************************************************************** + * Name: bluetooth_conn_alloc() + * + * Description: + * Allocate a new, uninitialized packet socket connection structure. This + * is normally something done by the implementation of the socket() API + * + ****************************************************************************/ + +FAR struct bluetooth_conn_s *bluetooth_conn_alloc(void) +{ + FAR struct bluetooth_conn_s *conn; + + /* The free list is only accessed from user, non-interrupt level and + * is protected by a semaphore (that behaves like a mutex). + */ + + net_lock(); + conn = (FAR struct bluetooth_conn_s *) + dq_remfirst(&g_free_bluetooth_connections); + + if (conn) + { + /* Enqueue the connection into the active list */ + + memset(conn, 0, sizeof(struct bluetooth_conn_s)); + dq_addlast(&conn->bc_node, &g_active_bluetooth_connections); + } + + net_unlock(); + return conn; +} + +/**************************************************************************** + * Name: bluetooth_conn_free() + * + * Description: + * Free a packet socket connection structure that is no longer in use. + * This should be done by the implementation of close(). + * + ****************************************************************************/ + +void bluetooth_conn_free(FAR struct bluetooth_conn_s *conn) +{ + FAR struct bluetooth_container_s *container; + FAR struct bluetooth_container_s *next; + + /* The free list is only accessed from user, non-interrupt level and + * is protected by a semaphore (that behaves like a mutex). + */ + + DEBUGASSERT(conn->bc_crefs == 0); + + /* Remove the connection from the active list */ + + net_lock(); + dq_rem(&conn->bc_node, &g_active_bluetooth_connections); + + /* Check if there any any frames attached to the container */ + + for (container = conn->bc_rxhead; container != NULL; container = next) + { + /* Remove the frame from the list */ + + next = container->bn_flink; + container->bn_flink = NULL; + + /* Free the contained frame data (should be only one in chain) */ + + if (container->bn_iob) + { + iob_free(container->bn_iob); + } + + /* And free the container itself */ + + bluetooth_container_free(container); + } + + /* Free the connection */ + + dq_addlast(&conn->bc_node, &g_free_bluetooth_connections); + net_unlock(); +} + +/**************************************************************************** + * Name: bluetooth_conn_active() + * + * Description: + * Find a connection structure that is the appropriate + * connection to be used with the provided Bluetooth header + * + * Assumptions: + * This function is called from network logic at with the network locked. + * + ****************************************************************************/ + +FAR struct bluetooth_conn_s * + bluetooth_conn_active(FAR const struct bluetooth_frame_meta_s *meta) +{ + FAR struct bluetooth_conn_s *conn; + + DEBUGASSERT(meta != NULL); + + for (conn = (FAR struct bluetooth_conn_s *)g_active_bluetooth_connections.head; + conn != NULL; + conn = (FAR struct bluetooth_conn_s *)conn->bc_node.flink) + { + /* Does the destination address match the bound address of the socket. */ + /* REVISIT: Currently and explicit address must be assigned. Should we + * support some moral equivalent to INADDR_ANY? + */ + + if (!BLUETOOTH_ADDRCMP(&meta->bm_raddr, &conn->bc_laddr) || + meta->bm_channel != conn->bc_channel) + { + continue; + } + } + + return conn; +} + +/**************************************************************************** + * Name: bluetooth_conn_next() + * + * Description: + * Traverse the list of allocated packet connections + * + * Assumptions: + * This function is called from network logic at with the network locked. + * + ****************************************************************************/ + +FAR struct bluetooth_conn_s * + bluetooth_conn_next(FAR struct bluetooth_conn_s *conn) +{ + if (!conn) + { + return (FAR struct bluetooth_conn_s *) + g_active_bluetooth_connections.head; + } + else + { + return (FAR struct bluetooth_conn_s *)conn->bc_node.flink; + } +} + +#endif /* CONFIG_NET_BLUETOOTH */ diff --git a/net/bluetooth/bluetooth_container.c b/net/bluetooth/bluetooth_container.c new file mode 100644 index 00000000000..8953e7cf716 --- /dev/null +++ b/net/bluetooth/bluetooth_container.c @@ -0,0 +1,221 @@ +/**************************************************************************** + * net/bluetooth/bluetooth_container.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bluetooth/bluetooth.h" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* The g_free_container is a list of IOB container structures that are + * available for general use. The number of messages in this list is a + * system configuration item. + * + * Mutually exclusive access to this list is managed via the network lock: + * i.e., the network must be locked beffore accessing this free list. + */ + +static FAR struct bluetooth_container_s *g_free_container; + +/* Pool of pre-allocated meta-data stuctures */ + +static struct bluetooth_container_s + g_container_pool[CONFIG_NET_BLUETOOTH_NCONTAINERS]; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_container_initialize + * + * Description: + * This function initializes the container allocator. This function must + * be called early in the initialization sequence before any socket + * activity. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + * Assumptions: + * Called early in the initialization sequence + * + ****************************************************************************/ + +void bluetooth_container_initialize(void) +{ + FAR struct bluetooth_container_s *container; + int i; + + /* Initialize g_free_container, the list of meta-data structures that + * are available for allocation. + */ + + g_free_container = NULL; + for (i = 0, container = g_container_pool; + i < CONFIG_NET_BLUETOOTH_NCONTAINERS; + i++, container++) + { + /* Add the next meta data structure from the pool to the list of + * general structures. + */ + + container->bn_flink = g_free_container; + g_free_container = container; + } +} + +/**************************************************************************** + * Name: bluetooth_container_allocate + * + * Description: + * The bluetooth_container_allocate function will get a free continer + * for use by the recvfrom() logic. + * + * This function will first attempt to allocate from the g_free_container + * list. If that the list is empty, then the meta-data structure will be + * allocated from the dynamic memory pool. + * + * Input Parameters: + * 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 + * returned. + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +FAR struct bluetooth_container_s *bluetooth_container_allocate(void) +{ + FAR struct bluetooth_container_s *container; + uint8_t pool; + + /* Try the free list first */ + + net_lock(); + if (g_free_container != NULL) + { + container = g_free_container; + g_free_container = container->bn_flink; + pool = BLUETOOTH_POOL_PREALLOCATED; + net_unlock(); + } + else + { + net_unlock(); + container = (FAR struct bluetooth_container_s *) + kmm_malloc((sizeof (struct bluetooth_container_s))); + pool = BLUETOOTH_POOL_DYNAMIC; + } + + /* We have successfully allocated memory from some source? */ + + if (container != NULL) + { + /* Zero and tag the allocated meta-data structure. */ + + memset(container, 0, sizeof(struct bluetooth_container_s)); + container->bn_pool = pool; + } + + return container; +} + +/**************************************************************************** + * Name: bluetooth_container_free + * + * Description: + * The bluetooth_container_free function will return a container structure + * to the free list of containers if it was a pre-allocated container + * structure. If the container structure was allocated dynamically it will + * be deallocated. + * + * Input Parameters: + * container - container structure to free + * + * Returned Value: + * None + * + * Assumptions: + * The caller has locked the network. + * + ****************************************************************************/ + +void bluetooth_container_free(FAR struct bluetooth_container_s *container) +{ + /* If this is a pre-allocated meta-data structure, then just put it back + * in the free list. + */ + + net_lock(); + if (container->bn_pool == BLUETOOTH_POOL_PREALLOCATED) + { + container->bn_flink = g_free_container; + g_free_container = container; + net_unlock(); + } + else + { + DEBUGASSERT(container->bn_pool == BLUETOOTH_POOL_DYNAMIC); + + /* Otherwise, deallocate it. */ + + net_unlock(); + sched_kfree(container); + } +} diff --git a/net/bluetooth/bluetooth_finddev.c b/net/bluetooth/bluetooth_finddev.c new file mode 100644 index 00000000000..6cb19448c8a --- /dev/null +++ b/net/bluetooth/bluetooth_finddev.c @@ -0,0 +1,159 @@ +/**************************************************************************** + * net/bluetooth/bluetooth_finddev.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include + +#include "netdev/netdev.h" +#include "bluetooth/bluetooth.h" + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct bluetooth_finddev_s +{ + FAR const bt_addr_t *bf_addr; + FAR struct radio_driver_s *bf_radio; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_dev_callback + * + * Description: + * Check if this device matches the connections local address. + * + * Input Parameters: + * dev - The next network device in the enumeration + * + * Returned Value: + * 0 if there is no match (meaning to continue looking); 1 if there is a + * match (meaning to stop the search). + * + ****************************************************************************/ + +static int bluetooth_dev_callback(FAR struct net_driver_s *dev, FAR void *arg) +{ + FAR struct bluetooth_finddev_s *match = + (FAR struct bluetooth_finddev_s *)arg; + + DEBUGASSERT(dev != NULL && match != NULL && match->bf_addr != NULL); + + /* First, check if this network device is an Bluetooth radio and that + * it has an assigned Bluetooth address. + */ + + if (dev->d_lltype == NET_LL_BLUETOOTH && dev->d_mac.radio.nv_addrlen > 0) + { + DEBUGASSERT(dev->d_mac.radio.nv_addrlen == BLUETOOTH_ADDRSIZE); + + /* Does the device address match */ + + if (BLUETOOTH_ADDRCMP(dev->d_mac.radio.nv_addr, match->bf_addr)) + { + /* Yes.. save the match and return 1 to stop the search */ + + match->bf_radio = (FAR struct radio_driver_s *)dev; + return 1; + } + } + + /* Keep looking */ + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_find_device + * + * Description: + * Select the network driver to use with the Bluetooth transaction. + * + * Input Parameters: + * conn - Bluetooth connection structure (not currently used). + * addr - The address to match the devices assigned address + * + * Returned Value: + * A pointer to the network driver to use. NULL is returned on any + * failure. + * + ****************************************************************************/ + +FAR struct radio_driver_s * + bluetooth_find_device(FAR struct bluetooth_conn_s *conn, + FAR const bt_addr_t *addr) +{ + struct bluetooth_finddev_s match; + int ret; + + DEBUGASSERT(conn != NULL); + match.bf_addr = addr; + match.bf_radio = NULL; + + /* Search for the Bluetooth network device whose MAC is equal to the + * sockets bound local address. + */ + + ret = netdev_foreach(bluetooth_dev_callback, (FAR void *)&match); + if (ret == 1) + { + DEBUGASSERT(match.bf_radio != NULL); + return match.bf_radio; + } + + return NULL; +} + +#endif /* CONFIG_NET_BLUETOOTH */ diff --git a/net/bluetooth/bluetooth_initialize.c b/net/bluetooth/bluetooth_initialize.c new file mode 100644 index 00000000000..9769be6cdce --- /dev/null +++ b/net/bluetooth/bluetooth_initialize.c @@ -0,0 +1,71 @@ +/**************************************************************************** + * net/bluetooth/bluetooth_initialize.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "bluetooth/bluetooth.h" + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_initialize() + * + * Description: + * Initialize the Bluetooth socket support. Called once and only + * from the network initialization logic. + * + * Assumptions: + * Called early in the initialization sequence + * + ****************************************************************************/ + +void bluetooth_initialize(void) +{ + /* Initialize connection structions */ + + bluetooth_conn_initialize(); + + /* Initialize the container allocator */ + + bluetooth_container_initialize(); +} + +#endif /* CONFIG_NET_BLUETOOTH */ diff --git a/net/bluetooth/bluetooth_input.c b/net/bluetooth/bluetooth_input.c new file mode 100644 index 00000000000..da0df50984a --- /dev/null +++ b/net/bluetooth/bluetooth_input.c @@ -0,0 +1,292 @@ +/**************************************************************************** + * net/bluetooth/bluetooth_input.c + * Handle incoming Bluetooth frame input + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "devif/devif.h" +#include "bluetooth/bluetooth.h" + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_count_frames + * + * Description: + * Return the number of frames in the RX queue. + * + * Input Parameters: + * conn - The socket connection structure. + * + * Returned Value: + * The number of frames in the queue. + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_ASSERTIONS) && CONFIG_NET_BLUETOOTH_BACKLOG > 0 +static int bluetooth_count_frames(FAR struct bluetooth_conn_s *conn) +{ + FAR struct bluetooth_container_s *container; + int count; + + for (count = 0, container = conn->bc_rxhead; + container != NULL; + count++, container = container->bn_flink) + { + } + + return count; +} +#endif + +/**************************************************************************** + * Name: bluetooth_queue_frame + * + * Description: + * Add one frame to the connection's RX queue. + * + * Input Parameters: + * conn - The socket connection structure. + * framel - A single frame to add to the RX queue. + * meta - Meta data characterizing the received frane. + * + * Returned Value: + * Zero (OK) is returned on success; A negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int bluetooth_queue_frame(FAR struct bluetooth_conn_s *conn, + FAR struct iob_s *frame, + FAR struct bluetooth_frame_meta_s *meta) +{ + FAR struct bluetooth_container_s *container; + + /* Allocate a container for the frame */ + + container = bluetooth_container_allocate(); + if (container == NULL) + { + nerr("ERROR: Failed to allocate a container\n"); + return -ENOMEM; + } + + /* Initialize the container */ + + memset(&container->bn_raddr, 0, sizeof(bt_addr_t)); + container->bn_channel = meta->bm_channel; + BLUETOOTH_ADDRCOPY(&container->bn_raddr, &meta->bm_raddr); + + DEBUGASSERT(frame != NULL); + container->bn_iob = frame; + + /* Add the container to the tail of the list of incoming frames */ + + container->bn_flink = NULL; + if (conn->bc_rxtail == NULL) + { + conn->bc_rxhead = container; + } + else + { + conn->bc_rxtail->bn_flink = container; + } + +#if CONFIG_NET_BLUETOOTH_BACKLOG > 0 + /* If incrementing the count would exceed the maximum bc_backlog value, then + * delete the oldest frame from the head of the RX queue. + */ + + if (conn->bc_backlog >= CONFIG_NET_BLUETOOTH_BACKLOG) + { + DEBUGASSERT(conn->bc_backlog == CONFIG_NET_BLUETOOTH_BACKLOG); + + /* Remove the container from the tail RX input queue. */ + + container = conn->bc_rxhead; + DEBUGASSERT(container != NULL); + conn->bc_rxhead = container->bn_flink; + container->bn_flink = NULL; + + /* Did the RX queue become empty? */ + + if (conn->bc_rxhead == NULL) + { + conn->bc_rxtail = NULL; + } + + DEBUGASSERT(container != NULL && container->bn_iob != NULL); + + /* Free both the IOB and the container */ + + iob_free(container->bn_iob); + bluetooth_container_free(container); + } + else + { + /* Increment the count of frames in the queue. */ + + conn->bc_backlog++; + } + + DEBUGASSERT((int)conn->bc_backlog == bluetooth_count_frames(conn)); +#endif + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_input + * + * Description: + * Handle incoming Bluetooth input + * + * This function is called when the radio device driver has received an + * frame from the network. The frame from the device driver must be + * provided in by the IOB frame argument of the function call: + * + * - The frame data is in the IOB io_data[] buffer, + * - The length of the frame is in the IOB io_len field, and + * - The offset past and radio MAC header is provided in the io_offset + * field. + * + * The frame argument may refer to a single frame (a list of length one) + * or may it be the head of a list of multiple frames. + * + * - The io_flink field points to the next frame in the list (if enable) + * - The last frame in the list will have io_flink == NULL. + * + * Input Parameters: + * radio The radio network driver interface. + * framelist - The head of an incoming list of frames. Normally this + * would be a single frame. A list may be provided if + * appropriate, however. + * meta - Meta data characterizing the received frame. + * + * If there are multiple frames in the list, this metadata + * must apply to all of the frames in the list. + * + * Returned Value: + * OK The Bluetooth has been processed and can be deleted + * ERROR Hold the Bluetooth and try again later. There is a listening + * socket but no recv in place to catch the Bluetooth yet. + * Useful when a packet arrives before a recv call is in place. + * + * Assumptions: + * Called from the network diver with the network locked. + * + ****************************************************************************/ + +int bluetooth_input(FAR struct radio_driver_s *radio, + FAR struct iob_s *framelist, + FAR struct bluetooth_frame_meta_s *meta) +{ + FAR struct bluetooth_conn_s *conn; + FAR struct iob_s *frame; + FAR struct iob_s *next; + int ret = OK; + + /* Check if there is a connection that will accept this packet */ + + conn = bluetooth_conn_active(meta); + if (conn != NULL) + { + /* Setup for the application callback (NOTE: These should not be + * used by PF_BLUETOOTH sockets). + */ + + radio->r_dev.d_appdata = radio->r_dev.d_buf; + radio->r_dev.d_len = 0; + radio->r_dev.d_sndlen = 0; + + /* The framelist probably contains only a single frame, but we will + * process it as a list of frames. + */ + + for (frame = framelist; frame != NULL; frame = next) + { + /* Remove the frame from the list */ + + next = frame->io_flink; + frame->io_flink = NULL; + + /* Add the frame to the RX queue */ + + ret = bluetooth_queue_frame(conn, frame, meta); + if (ret < 0) + { + nerr("ERROR: Failed to queue frame: %d\n", ret); + iob_free(frame); + } + } + + /* Perform the application callback. The frame may be processed now + * if there is a user wait for an incoming frame. Or it may pend in + * the RX queue until some user process reads the frame. NOTE: The + * return value from bluetooth_callback would distinguish these + * cases: BLUETOOTH_NEWDATA will still be processed if the frame + * was not consumed. + */ + + (void)bluetooth_callback(radio, conn, BLUETOOTH_NEWDATA); + } + else + { + nwarn("WARNING: No listener\n"); + } + + return ret; +} + +#endif /* CONFIG_NET_BLUETOOTH */ diff --git a/net/bluetooth/bluetooth_poll.c b/net/bluetooth/bluetooth_poll.c new file mode 100644 index 00000000000..2632675daaf --- /dev/null +++ b/net/bluetooth/bluetooth_poll.c @@ -0,0 +1,105 @@ +/**************************************************************************** + * net/bluetooth/bluetooth_poll.c + * Poll for the availability of ougoing Bluetooth frames + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include + +#include "devif/devif.h" +#include "bluetooth/bluetooth.h" + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_poll + * + * Description: + * Poll a packet "connection" structure for availability of TX data + * + * Input Parameters: + * dev - The device driver structure to use in the send operation + * conn - The packet "connection" to poll for TX data + * + * Returned Value: + * None + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +void bluetooth_poll(FAR struct net_driver_s *dev, + FAR struct bluetooth_conn_s *conn) +{ + FAR struct radio_driver_s *radio; + + DEBUGASSERT(dev != NULL && conn != NULL); + radio = (FAR struct radio_driver_s *)dev; + + /* Verify that the packet connection is valid */ + + if (conn != NULL) + { + /* Setup for the application callback (NOTE: These should not be + * used by PF_BLUETOOTH sockets). + */ + + radio->r_dev.d_appdata = radio->r_dev.d_buf; + radio->r_dev.d_len = 0; + radio->r_dev.d_sndlen = 0; + + /* Perform the application callback */ + /* REVISIT: Need to pass the meta data and the IOB through the callback */ +#warning Missing logic + + /* Perform the application callback */ + + (void)bluetooth_callback(radio, conn, BLUETOOTH_POLL); + } +} + +#endif /* CONFIG_NET && CONFIG_NET_PKT */ diff --git a/net/bluetooth/bluetooth_recvfrom.c b/net/bluetooth/bluetooth_recvfrom.c new file mode 100644 index 00000000000..473a80fe72d --- /dev/null +++ b/net/bluetooth/bluetooth_recvfrom.c @@ -0,0 +1,430 @@ +/**************************************************************************** + * net/socket/bluetooth_recvfrom.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "netdev/netdev.h" +#include "devif/devif.h" +#include "socket/socket.h" +#include "bluetooth/bluetooth.h" + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct bluetooth_recvfrom_s +{ + FAR struct socket *ir_sock; /* Points to the parent socket structure */ + FAR struct devif_callback_s *ir_cb; /* Reference to callback instance */ + FAR struct sockaddr *ir_from; /* Location to return the from address */ + FAR uint8_t *ir_buffer; /* Pointer to receive buffer */ + size_t ir_buflen; /* Length of receive buffer */ + sem_t ir_sem; /* Semaphore signals recv completion */ + ssize_t ir_result; /* Success:size, failure:negated errno */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_count_frames + * + * Description: + * Return the number of frames in the RX queue. + * + * Input Parameters: + * conn - The socket connection structure. + * + * Returned Value: + * The number of frames in the queue. + * + ****************************************************************************/ + +#if defined(CONFIG_DEBUG_ASSERTIONS) && CONFIG_NET_BLUETOOTH_BACKLOG > 0 +static int bluetooth_count_frames(FAR struct bluetooth_conn_s *conn) +{ + FAR struct bluetooth_container_s *container; + int count; + + for (count = 0, container = conn->bc_rxhead; + container != NULL; + count++, container = container->bn_flink) + { + } + + return count; +} +#endif + +/**************************************************************************** + * Name: bluetooth_recvfrom_sender + * + * Description: + * Perform the reception operation if there are any queued frames in the + * RX frame queue. + * + * Input Parameters: + * + * Returned Value: + * + * Assumptions: + * The network is lockec + * + ****************************************************************************/ + +static ssize_t bluetooth_recvfrom_rxqueue(FAR struct radio_driver_s *radio, + FAR struct bluetooth_recvfrom_s *pstate) +{ + FAR struct bluetooth_container_s *container; + FAR struct sockaddr_rc_s *iaddr; + FAR struct bluetooth_conn_s *conn; + FAR struct iob_s *iob; + size_t copylen; + int ret = -EAGAIN; + + /* Check if there is anyting in in the RX input queue */ + + DEBUGASSERT(pstate != NULL && pstate->ir_sock != NULL); + conn = (FAR struct bluetooth_conn_s *)pstate->ir_sock->s_conn; + DEBUGASSERT(conn != NULL); + + if (conn->bc_rxhead != NULL) + { + /* Remove the container from the RX input queue. */ + + container = conn->bc_rxhead; + DEBUGASSERT(container != NULL); + conn->bc_rxhead = container->bn_flink; + container->bn_flink = NULL; + + /* Did the RX queue become empty? */ + + if (conn->bc_rxhead == NULL) + { + conn->bc_rxtail = NULL; + } + +#if CONFIG_NET_BLUETOOTH_BACKLOG > 0 + /* Decrement the count of frames in the queue. */ + + DEBUGASSERT(conn->bc_backlog > 0); + conn->bc_backlog--; + DEBUGASSERT((int)conn->bc_backlog == bluetooth_count_frames(conn)); +#endif + + /* Extract the IOB containing the frame from the container */ + + iob = container->bn_iob; + container->bn_iob = NULL; + DEBUGASSERT(iob != NULL); + + /* Copy the new packet data into the user buffer */ + + copylen = iob->io_len - iob->io_offset; + memcpy(pstate->ir_buffer, &iob->io_data[iob->io_offset], copylen); + + ninfo("Received %d bytes\n", (int)copylen); + ret = copylen; + + /* If a 'from' address poiner was supplied, copy the source address + * in the container there. + */ + + if (pstate->ir_from != NULL) + { + iaddr = (FAR struct sockaddr_rc_s *)pstate->ir_from; + iaddr->rc_family = AF_BLUETOOTH; + BLUETOOTH_ADDRCOPY(&iaddr->rc_bdaddr, &container->bn_raddr); + iaddr->rc_channel = container->bn_channel; + } + + /* Free both the IOB and the container */ + + iob_free(iob); + bluetooth_container_free(container); + } + + return ret; +} + +/**************************************************************************** + * Name: bluetooth_recvfrom_eventhandler + * + * Description: + * + * Input Parameters: + * + * Returned Value: + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static uint16_t bluetooth_recvfrom_eventhandler(FAR struct net_driver_s *dev, + FAR void *pvconn, + FAR void *pvpriv, + uint16_t flags) +{ + FAR struct bluetooth_recvfrom_s *pstate; + FAR struct radio_driver_s *radio; + ssize_t ret; + + ninfo("flags: %04x\n", flags); + + DEBUGASSERT(pvpriv != NULL && dev != NULL && pvconn != NULL); + + /* Ignore polls from non Bluetooth network drivers */ + + if (dev->d_lltype != NET_LL_BLUETOOTH) + { + return flags; + } + + /* Make sure that this is the driver to which the socket is bound. */ +#warning Missing logic + + pstate = (FAR struct bluetooth_recvfrom_s *)pvpriv; + radio = (FAR struct radio_driver_s *)dev; + + /* 'pstate' might be null in some race conditions (?) */ + + if (pstate != NULL) + { + /* If a new packet is available, then complete the read action. */ + + if ((flags & BLUETOOTH_NEWDATA) != 0) + { + /* Attempt to receive the frame */ + + ret = bluetooth_recvfrom_rxqueue(radio, pstate); + if (ret > 0) + { + /* Don't allow any further call backs. */ + + pstate->ir_cb->flags = 0; + pstate->ir_cb->priv = NULL; + pstate->ir_cb->event = NULL; + pstate->ir_result = ret; + + /* indicate that the data has been consumed */ + + flags &= ~BLUETOOTH_NEWDATA; + + /* Wake up the waiting thread, returning the number of bytes + * actually read. + */ + + nxsem_post(&pstate->ir_sem); + } + } + } + + return flags; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_recvfrom + * + * 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. + * + * If 'from' is not NULL, and the underlying protocol provides the source + * address, this source address is filled in. The argument 'fromlen' is + * initialized to the size of the buffer associated with from, and + * modified on return to indicate the actual size of the address stored + * there. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Buffer to receive data + * len Length of buffer + * flags Receive flags + * from Address of source (may be NULL) + * fromlen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters received. If no data is + * available to be received and the peer has performed an orderly shutdown, + * recv() will return 0. Otherwise, on errors, a negated errno value is + * returned (see recvfrom() for the list of appropriate error values). + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +ssize_t bluetooth_recvfrom(FAR struct socket *psock, FAR void *buf, + size_t len, int flags, FAR struct sockaddr *from, + FAR socklen_t *fromlen) +{ + FAR struct bluetooth_conn_s *conn = (FAR struct bluetooth_conn_s *)psock->s_conn; + FAR struct radio_driver_s *radio; + struct bluetooth_recvfrom_s state; + ssize_t ret; + + /* If a 'from' address has been provided, verify that it is large + * enough to hold this address family. + */ + + if (from != NULL && *fromlen < sizeof(struct sockaddr_rc_s)) + { + return -EINVAL; + } + + if (psock->s_type != SOCK_DGRAM) + { + nerr("ERROR: Unsupported socket type: %d\n", psock->s_type); + return -EPROTONOSUPPORT; + } + + /* Perform the packet recvfrom() operation */ + + /* Initialize the state structure. This is done with the network + * locked because we don't want anything to happen until we are ready. + */ + + net_lock(); + memset(&state, 0, sizeof(struct bluetooth_recvfrom_s)); + + state.ir_buflen = len; + state.ir_buffer = buf; + state.ir_sock = psock; + state.ir_from = from; + + /* Get the device driver that will service this transfer */ + + radio = bluetooth_find_device(conn, &conn->bc_laddr); + if (radio == NULL) + { + ret = -ENODEV; + goto errout_with_lock; + } + + /* Before we wait for data, let's check if there are already frame(s) + * waiting in the RX queue. + */ + + ret = bluetooth_recvfrom_rxqueue(radio, &state); + if (ret > 0) + { + /* Good newe! We have a frame and we are done. */ + + net_unlock(); + return ret; + } + + /* We will have to wait. This semaphore is used for signaling and, + * hence, should not have priority inheritance enabled. + */ + + (void)nxsem_init(&state.ir_sem, 0, 0); /* Doesn't really fail */ + (void)nxsem_setprotocol(&state.ir_sem, SEM_PRIO_NONE); + + /* Set the socket state to receiving */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_RECV); + + /* Set up the callback in the connection */ + + state.ir_cb = bluetooth_callback_alloc(&radio->r_dev, conn); + if (state.ir_cb) + { + state.ir_cb->flags = (BLUETOOTH_NEWDATA | BLUETOOTH_POLL); + state.ir_cb->priv = (FAR void *)&state; + state.ir_cb->event = bluetooth_recvfrom_eventhandler; + + /* Wait for either the receive to complete or for an error/timeout to + * occur. NOTES: (1) net_lockedwait will also terminate if a signal + * is received, (2) the network is locked! It will be un-locked while + * the task sleeps and automatically re-locked when the task restarts. + */ + + (void)net_lockedwait(&state.ir_sem); + + /* Make sure that no further events are processed */ + + bluetooth_callback_free(&radio->r_dev, conn, state.ir_cb); + ret = state.ir_result; + } + else + { + ret = -EBUSY; + } + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + nxsem_destroy(&state.ir_sem); + +errout_with_lock: + net_unlock(); + return ret; +} + +#endif /* CONFIG_NET_BLUETOOTH */ diff --git a/net/bluetooth/bluetooth_sendto.c b/net/bluetooth/bluetooth_sendto.c new file mode 100644 index 00000000000..a8d776e72d7 --- /dev/null +++ b/net/bluetooth/bluetooth_sendto.c @@ -0,0 +1,375 @@ +/**************************************************************************** + * net/bluetooth/bluetooth_sendto.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "netdev/netdev.h" +#include "devif/devif.h" +#include "socket/socket.h" +#include "bluetooth/bluetooth.h" + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure holds the state of the send operation until it can be + * operated upon from the interrupt level. + */ + +struct bluetooth_sendto_s +{ + FAR struct socket *is_sock; /* Points to the parent socket structure */ + FAR struct devif_callback_s *is_cb; /* Reference to callback instance */ + bt_addr_t is_destaddr; /* Frame destination address */ + uint8_t is_channel; /* Frame destination channel */ + sem_t is_sem; /* Used to wake up the waiting thread */ + FAR const uint8_t *is_buffer; /* User buffer of data to send */ + size_t is_buflen; /* Number of bytes in the is_buffer */ + ssize_t is_sent; /* The number of bytes sent (or error) */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_sendto_eventhandler + ****************************************************************************/ + +static uint16_t bluetooth_sendto_eventhandler(FAR struct net_driver_s *dev, + FAR void *pvconn, + FAR void *pvpriv, + uint16_t flags) +{ + FAR struct radio_driver_s *radio; + FAR struct bluetooth_sendto_s *pstate; + struct bluetooth_frame_meta_s meta; + FAR struct iob_s *iob; + int hdrlen; + int ret; + + DEBUGASSERT(pvpriv != NULL && dev != NULL && pvconn != NULL); + + /* Ignore polls from non Bluetooth network drivers */ + + if (dev->d_lltype != NET_LL_BLUETOOTH) + { + return flags; + } + + /* Make sure that this is the driver to which the socket is connected. */ +#warning Missing logic + + pstate = (FAR struct bluetooth_sendto_s *)pvpriv; + radio = (FAR struct radio_driver_s *)dev; + + ninfo("flags: %04x sent: %d\n", flags, pstate->is_sent); + + if (pstate != NULL && (flags & BLUETOOTH_POLL) != 0) + { + /* Initialize the meta data */ + + BLUETOOTH_ADDRCOPY(&meta.bm_raddr, &pstate->is_destaddr); + meta.bm_channel = pstate->is_channel; + + /* Get the Bluetooth MAC header length */ + + hdrlen = radio->r_get_mhrlen(radio, &meta); + if (hdrlen < 0) + { + nerr("ERROR: Failed to get header length: %d\n", hdrlen); + ret = hdrlen; + goto errout; + } + + /* Verify that the user buffer can fit within the frame with this + * MAC header. + */ + + DEBUGASSERT(CONFIG_NET_BLUETOOTH_FRAMELEN <= CONFIG_IOB_BUFSIZE); + if (pstate->is_buflen + hdrlen > BLUETOOTH_FRAMELEN) + { + nerr("ERROR: User buffer will not fit into the frame: %u > %u\n", + (unsigned int)(pstate->is_buflen + hdrlen), + (unsigned int)CONFIG_IOB_BUFSIZE); + ret = -E2BIG; + goto errout; + } + + /* Allocate an IOB to hold the frame data */ + + iob = iob_alloc(0); + if (iob == NULL) + { + nwarn("WARNING: Failed to allocate IOB\n"); + return flags; + } + + /* Initialize the IOB */ + + iob->io_offset = hdrlen; + iob->io_len = pstate->is_buflen + hdrlen; + iob->io_pktlen = pstate->is_buflen + hdrlen; + + /* Copy the user data into the IOB */ + + memcpy(&iob->io_data[hdrlen], pstate->is_buffer, pstate->is_buflen); + + /* And submit the IOB to the network driver */ + + ret = radio->r_req_data(radio, &meta, iob); + if (ret < 0) + { + nerr("ERROR: r_req_data() failed: %d\n", ret); + goto errout; + } + + /* Save the successful result */ + + pstate->is_sent = pstate->is_buflen; + + /* Don't allow any further call backs. */ + + pstate->is_cb->flags = 0; + pstate->is_cb->priv = NULL; + pstate->is_cb->event = NULL; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->is_sem); + } + + return flags; + +errout: + /* Don't allow any further call backs. */ + + pstate->is_cb->flags = 0; + pstate->is_cb->priv = NULL; + pstate->is_cb->event = NULL; + pstate->is_sent = ret; + + /* Wake up the waiting thread */ + + nxsem_post(&pstate->is_sem); + return flags; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: psock_bluetooth_sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * a negated errno value is retruend. See sendto() for the complete list + * of return values. + * + ****************************************************************************/ + +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 struct sockaddr_rc_s *destaddr; + FAR struct radio_driver_s *radio; + FAR struct bluetooth_conn_s *conn; + struct bluetooth_sendto_s state; + int ret = OK; + + /* Verify that the sockfd corresponds to valid, allocated socket */ + + if (psock == NULL || psock->s_crefs <= 0) + { + return -EBADF; + } + + conn = (FAR struct bluetooth_conn_s *)psock->s_conn; + DEBUGASSERT(conn != NULL); + + /* Verify that the address is large enough to be a valid PF_BLUETOOTH + * address. + */ + + if (tolen < sizeof(bt_addr_t)) + { + return -EDESTADDRREQ; + } + + /* Get the device driver that will service this transfer */ + + radio = bluetooth_find_device(conn, &conn->bc_laddr); + if (radio == NULL) + { + return -ENODEV; + } + + /* Set the socket state to sending */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); + + /* Perform the send operation */ + + /* Initialize the state structure. This is done with interrupts + * disabled because we don't want anything to happen until we + * are ready. + */ + + net_lock(); + memset(&state, 0, sizeof(struct bluetooth_sendto_s)); + + /* This semaphore is used for signaling and, hence, should not have + * priority inheritance enabled. + */ + + (void)nxsem_init(&state.is_sem, 0, 0); /* Doesn't really fail */ + (void)nxsem_setprotocol(&state.is_sem, SEM_PRIO_NONE); + + state.is_sock = psock; /* Socket descriptor to use */ + state.is_buflen = len; /* Number of bytes to send */ + state.is_buffer = buf; /* Buffer to send from */ + + /* Copy the destination address */ + + destaddr = (FAR struct sockaddr_rc_s *)to; + memcpy(&state.is_destaddr, &destaddr->rc_bdaddr, + sizeof(bt_addr_t)); + + if (len > 0) + { + /* Allocate resource to receive a callback */ + + state.is_cb = bluetooth_callback_alloc(&radio->r_dev, conn); + if (state.is_cb) + { + /* Set up the callback in the connection */ + + state.is_cb->flags = PKT_POLL; + state.is_cb->priv = (FAR void *)&state; + state.is_cb->event = bluetooth_sendto_eventhandler; + + /* Notify the device driver that new TX data is available. */ + + netdev_txnotify_dev(&radio->r_dev); + + /* Wait for the send to complete or an error to occur: NOTES: (1) + * net_lockedwait will also terminate if a signal is received, (2) + * interrupts may be disabled! They will be re-enabled while the + * task sleeps and automatically re-enabled when the task restarts. + */ + + ret = net_lockedwait(&state.is_sem); + + /* Make sure that no further interrupts are processed */ + + bluetooth_callback_free(&radio->r_dev, conn, state.is_cb); + } + } + + nxsem_destroy(&state.is_sem); + net_unlock(); + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + + /* Check for a errors, Errors are signaled by negative errno values + * for the send length + */ + + if (state.is_sent < 0) + { + return state.is_sent; + } + + /* If net_lockedwait failed, then we were probably reawakened by a signal. In + * this case, net_lockedwait will have returned negated errno appropriately. + */ + + if (ret < 0) + { + return ret; + } + + /* Return the number of bytes actually sent */ + + return state.is_sent; +} + +#endif /* CONFIG_NET_BLUETOOTH */ diff --git a/net/bluetooth/bluetooth_sockif.c b/net/bluetooth/bluetooth_sockif.c new file mode 100644 index 00000000000..3e061ca41b9 --- /dev/null +++ b/net/bluetooth/bluetooth_sockif.c @@ -0,0 +1,741 @@ +/**************************************************************************** + * net/socket/bluetooth_sockif.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "bluetooth/bluetooth.h" + +#ifdef CONFIG_NET_BLUETOOTH + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int bluetooth_setup(FAR struct socket *psock, int protocol); +static sockcaps_t bluetooth_sockcaps(FAR struct socket *psock); +static void bluetooth_addref(FAR struct socket *psock); +static int bluetooth_bind(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen); +static int bluetooth_getsockname(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR socklen_t *addrlen); +static int bluetooth_listen(FAR struct socket *psock, int backlog); +static int bluetooth_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen); +static int bluetooth_accept(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR socklen_t *addrlen, + FAR struct socket *newsock); +#ifndef CONFIG_DISABLE_POLL +static int bluetooth_poll_local(FAR struct socket *psock, + FAR struct pollfd *fds, bool setup); +#endif +static ssize_t bluetooth_send(FAR struct socket *psock, + FAR const void *buf, size_t len, int flags); +static ssize_t bluetooth_sendto(FAR struct socket *psock, + FAR const void *buf, size_t len, int flags, + FAR const struct sockaddr *to, socklen_t tolen); +static int bluetooth_close(FAR struct socket *psock); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +const struct sock_intf_s g_bluetooth_sockif = +{ + bluetooth_setup, /* si_setup */ + bluetooth_sockcaps, /* si_sockcaps */ + bluetooth_addref, /* si_addref */ + bluetooth_bind, /* si_bind */ + bluetooth_getsockname, /* si_getsockname */ + bluetooth_listen, /* si_listen */ + bluetooth_connect, /* si_connect */ + bluetooth_accept, /* si_accept */ +#ifndef CONFIG_DISABLE_POLL + bluetooth_poll_local, /* si_poll */ +#endif + bluetooth_send, /* si_send */ + bluetooth_sendto, /* si_sendto */ +#ifdef CONFIG_NET_SENDFILE + NULL, /* si_sendfile */ +#endif + bluetooth_recvfrom, /* si_recvfrom */ + bluetooth_close /* si_close */ +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bluetooth_sockif_alloc + * + * Description: + * Allocate and attach a PF_BLUETOOTH connection structure. + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +static int bluetooth_sockif_alloc(FAR struct socket *psock) +{ + /* Allocate the packet socket connection structure and save in the new + * socket instance. + */ + + FAR struct bluetooth_conn_s *conn = bluetooth_conn_alloc(); + if (conn == NULL) + { + /* Failed to reserve a connection structure */ + + return -ENOMEM; + } + + /* Set the reference count on the connection structure. This reference + * count will be incremented only if the socket is dup'ed + */ + + DEBUGASSERT(conn->bc_crefs == 0); + conn->bc_crefs = 1; + + /* Save the pre-allocated connection in the socket structure */ + + psock->s_conn = conn; + return OK; +} + +/**************************************************************************** + * Name: bluetooth_setup + * + * Description: + * Called for socket() to verify that the provided socket type and + * protocol are usable by this address family. Perform any family- + * specific socket fields. + * + * Input Parameters: + * psock A pointer to a user allocated socket structure to be + * initialized. + * protocol (see sys/socket.h) + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise, a negater errno value is + * returned. + * + ****************************************************************************/ + +static int bluetooth_setup(FAR struct socket *psock, int protocol) +{ + /* Allocate the appropriate connection structure. This reserves the + * the connection structure is is unallocated at this point. It will + * not actually be initialized until the socket is connected. + * + * Only SOCK_DGRAM is supported (since the MAC header is stripped) + */ + + if (psock->s_type == SOCK_DGRAM) + { + return bluetooth_sockif_alloc(psock); + } + else + { + return -EPROTONOSUPPORT; + } +} + +/**************************************************************************** + * Name: bluetooth_sockcaps + * + * Description: + * Return the bit encoded capabilities of this socket. + * + * Input Parameters: + * psock - Socket structure of the socket whose capabilities are being + * queried. + * + * Returned Value: + * The set of socket cababilities is returned. + * + ****************************************************************************/ + +static sockcaps_t bluetooth_sockcaps(FAR struct socket *psock) +{ + return 0; +} + +/**************************************************************************** + * Name: bluetooth_addref + * + * Description: + * Increment the refernce count on the underlying connection structure. + * + * Input Parameters: + * psock - Socket structure of the socket whose reference count will be + * incremented. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void bluetooth_addref(FAR struct socket *psock) +{ + FAR struct bluetooth_conn_s *conn; + + DEBUGASSERT(psock != NULL && psock->s_conn != NULL && + psock->s_type == SOCK_DGRAM); + + conn = (FAR struct bluetooth_conn_s *)psock->s_conn; + DEBUGASSERT(conn->bc_crefs > 0 && conn->bc_crefs < 255); + conn->bc_crefs++; +} + +/**************************************************************************** + * Name: bluetooth_connect + * + * Description: + * bluetooth_connect() connects the local socket referred to by the structure + * 'psock' to the address specified by 'addr'. The addrlen argument + * specifies the size of 'addr'. The format of the address in 'addr' is + * determined by the address space of the socket 'psock'. + * + * If the socket 'psock' is of type SOCK_DGRAM then 'addr' is the address + * to which datagrams are sent by default, and the only address from which + * datagrams are received. If the socket is of type SOCK_STREAM or + * SOCK_SEQPACKET, this call attempts to make a connection to the socket + * that is bound to the address specified by 'addr'. + * + * Generally, connection-based protocol sockets may successfully + * bluetooth_connect() only once; connectionless protocol sockets may use + * bluetooth_connect() multiple times to change their association. + * Connectionless sockets may dissolve the association by connecting to + * an address with the rc_family member of sockaddr set to AF_UNSPEC. + * + * Input Parameters: + * psock Pointer to a socket structure initialized by psock_socket() + * addr Server address (form depends on type of socket) + * addrlen Length of actual 'addr' + * + * Returned Value: + * 0 on success; a negated errno value on failue. See connect() for the + * list of appropriate errno values to be returned. + * + ****************************************************************************/ + +static int bluetooth_connect(FAR struct socket *psock, + FAR const struct sockaddr *addr, + socklen_t addrlen) +{ + FAR struct bluetooth_conn_s *conn; + FAR struct sockaddr_rc_s *btaddr; + int ret; + + DEBUGASSERT(psock != NULL || addr != NULL); + conn = (FAR struct bluetooth_conn_s *)psock->s_conn; + DEBUGASSERT(conn != NULL); + + /* Verify the address family */ + + if (addr->sa_family == AF_BLUETOOTH) + { + /* Save the "connection" address */ + + btaddr = (FAR struct sockaddr_rc_s *)addr; + memcpy(&conn->bc_raddr, &btaddr->rc_bdaddr, sizeof(bt_addr_t)); + conn->bc_channel = btaddr->rc_channel; + + /* Mark the socket as connected. */ + + psock->s_flags |= _SF_CONNECTED; + ret = OK; + } + else + { + /* The specified address is not a valid address for the address family + * of the specified socket. + */ + + ret = -EAFNOSUPPORT; + } + + return ret; +} + +/**************************************************************************** + * Name: bluetooth_accept + * + * Description: + * The bluetooth_accept function is used with connection-based socket types + * (SOCK_STREAM, SOCK_SEQPACKET and SOCK_RDM). It extracts the first + * connection request on the queue of pending connections, creates a new + * connected socket with mostly the same properties as 'sockfd', and + * allocates a new socket descriptor for the socket, which is returned. The + * newly created socket is no longer in the listening state. The original + * socket 'sockfd' is unaffected by this call. Per file descriptor flags + * are not inherited across an bluetooth_accept. + * + * The 'sockfd' argument is a socket descriptor that has been created with + * socket(), bound to a local address with bind(), and is listening for + * connections after a call to listen(). + * + * On return, the 'addr' structure is filled in with the address of the + * connecting entity. The 'addrlen' argument initially contains the size + * of the structure pointed to by 'addr'; on return it will contain the + * actual length of the address returned. + * + * If no pending connections are present on the queue, and the socket is + * not marked as non-blocking, bluetooth_accept blocks the caller until a + * connection is present. If the socket is marked non-blocking and no + * pending connections are present on the queue, bluetooth_accept returns + * EAGAIN. + * + * Input Parameters: + * psock Reference to the listening socket structure + * addr Receives the address of the connecting client + * addrlen Input: allocated size of 'addr', Return: returned size of 'addr' + * newsock Location to return the accepted socket information. + * + * Returned Value: + * Returns 0 (OK) on success. On failure, it returns a negated errno + * value. See accept() for a desrciption of the approriate error value. + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static int bluetooth_accept(FAR struct socket *psock, + FAR struct sockaddr *addr, + FAR socklen_t *addrlen, + FAR struct socket *newsock) +{ + return -EAFNOSUPPORT; +} + +/**************************************************************************** + * Name: bluetooth_bind + * + * Description: + * bluetooth_bind() gives the socket 'psock' the local address 'addr'. + * 'addr' 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 + * addr 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_bind(FAR struct socket *psock, + FAR const struct sockaddr *addr, socklen_t addrlen) +{ + FAR const struct sockaddr_rc_s *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_rc_s)) + { + nerr("ERROR: Invalid family: %u or address length: %d < %d\n", + addr->sa_family, addrlen, sizeof(struct sockaddr_ll)); + return -EBADF; + } + + /* Bind a PF_BLUETOOTH socket to an network device. */ + + if (psock->s_type != SOCK_DGRAM) + { + 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; + } + + iaddr = (FAR const struct sockaddr_rc_s *)addr; + + /* Very that some address was provided */ + /* REVISIT: Currently and explict address must be assigned. Should we + * support some moral equivalent to INADDR_ANY? + */ + + conn = (FAR struct bluetooth_conn_s *)psock->s_conn; + + /* Find the device associated with the requested address */ + + radio = bluetooth_find_device(conn, &iaddr->rc_bdaddr); + if (radio == NULL) + { + nerr("ERROR: No radio at this address\n"); + return -ENODEV; + } + + /* Save the address as the socket's local address */ + + memcpy(&conn->bc_laddr, &iaddr->rc_bdaddr, sizeof(bt_addr_t)); + + /* Mark the socket bound */ + + psock->s_flags |= _SF_BOUND; + return OK; +} + +/**************************************************************************** + * Name: bluetooth_getsockname + * + * Description: + * The bluetooth_getsockname() function retrieves the locally-bound name of the + * specified packet socket, stores this address in the sockaddr structure + * pointed to by the 'addr' argument, and stores the length of this + * address in the object pointed to by the 'addrlen' argument. + * + * If the actual length of the address is greater than the length of the + * supplied sockaddr structure, the stored address will be truncated. + * + * If the socket has not been bound to a local name, the value stored in + * the object pointed to by address is unspecified. + * + * Input Parameters: + * psock Socket structure of the socket to be queried + * addr sockaddr structure to receive data [out] + * addrlen Length of sockaddr structure [in/out] + * + * Returned Value: + * On success, 0 is returned, the 'addr' argument points to the address + * of the socket, and the 'addrlen' argument points to the length of the + * address. Otherwise, a negated errno value is returned. See + * getsockname() for the list of appropriate error numbers. + * + ****************************************************************************/ + +static int bluetooth_getsockname(FAR struct socket *psock, + FAR struct sockaddr *addr, FAR + socklen_t *addrlen) +{ + FAR struct bluetooth_conn_s *conn; + FAR struct sockaddr_rc_s tmp; + socklen_t copylen; + + DEBUGASSERT(psock != NULL && addr != NULL && addrlen != NULL); + + conn = (FAR struct bluetooth_conn_s *)psock->s_conn; + DEBUGASSERT(conn != NULL); + + /* Create a copy of the full address on the stack */ + + tmp.rc_family = AF_BLUETOOTH; + memcpy(&tmp.rc_bdaddr, &conn->bc_laddr, sizeof(bt_addr_t)); + + /* Copy to the user buffer, truncating if necessary */ + + copylen = sizeof(struct sockaddr_rc_s); + if (copylen > *addrlen) + { + copylen = *addrlen; + } + + memcpy(addr, &tmp, copylen); + + /* Return the actual size transferred */ + + *addrlen = copylen; + return OK; +} + +/**************************************************************************** + * Name: bluetooth_listen + * + * Description: + * To accept connections, a socket is first created with psock_socket(), a + * willingness to accept incoming connections and a queue limit for + * incoming connections are specified with psock_listen(), and then the + * connections are accepted with psock_accept(). For the case of + * PF_BLUETOOTH sockets, psock_listen() calls this function. The listen() + * call does not apply only to PF_BLUETOOTH sockets. + * + * Input Parameters: + * psock Reference to an internal, boound socket structure. + * backlog The maximum length the queue of pending connections may grow. + * If a connection request arrives with the queue full, the client + * may receive an error with an indication of ECONNREFUSED or, + * if the underlying protocol supports retransmission, the request + * may be ignored so that retries succeed. + * + * Returned Value: + * On success, zero is returned. On error, a negated errno value is + * returned. See list() for the set of appropriate error values. + * + ****************************************************************************/ + +int bluetooth_listen(FAR struct socket *psock, int backlog) +{ + return -EOPNOTSUPP; +} + +/**************************************************************************** + * Name: bluetooth_poll + * + * Description: + * The standard poll() operation redirects operations on socket descriptors + * to net_poll which, indiectly, calls to function. + * + * Input Parameters: + * psock - An instance of the internal socket structure. + * fds - The structure describing the events to be monitored, OR NULL if + * this is a request to stop monitoring events. + * setup - true: Setup up the poll; false: Teardown the poll + * + * Returned Value: + * 0: Success; Negated errno on failure + * + ****************************************************************************/ + +#ifndef CONFIG_DISABLE_POLL +static int bluetooth_poll_local(FAR struct socket *psock, + FAR struct pollfd *fds, bool setup) +{ + /* We should need to support some kind of write ahead buffering for this + * feature. + */ + +#warning Missing logic + return -ENOSYS; +} +#endif /* !CONFIG_DISABLE_POLL */ + +/**************************************************************************** + * Name: bluetooth_send + * + * Description: + * Socket send() method for the PF_BLUETOOTH socket. + * + * 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_send(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags) +{ + struct sockaddr_rc_s 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_DGRAM is supported (because the MAC header is stripped) */ + + if (psock->s_type == SOCK_DGRAM) + { + /* send() may be used only if the socket is has been connected. */ + + if (!_SS_ISCONNECTED( psock->s_flags)) + { + ret = -ENOTCONN; + } + else + { + to.rc_family = AF_BLUETOOTH; + memcpy(&to.rc_bdaddr, &conn->bc_raddr, sizeof(bt_addr_t)); + to.rc_channel = 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_rc_s)); + } + } + else + { + /* EDESTADDRREQ. Signifies that the socket is not connection-mode and + * no peer address is set. + */ + + ret = -EDESTADDRREQ; + } + + return ret; +} + +/**************************************************************************** + * Name: bluetooth_sendto + * + * Description: + * Implements the sendto() operation for the case of the PF_BLUETOOTH + * socket. + * + * Input Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, a negated + * errno value is returned (see send_to() for the list of appropriate error + * values. + * + ****************************************************************************/ + +static ssize_t bluetooth_sendto(FAR struct socket *psock, FAR const void *buf, + size_t len, int flags, + FAR const struct sockaddr *to, socklen_t tolen) +{ + ssize_t ret; + + /* Only SOCK_DGRAM is supported (because the MAC header is stripped) */ + + if (psock->s_type == SOCK_DGRAM) + { + /* Raw packet send */ + + ret = psock_bluetooth_sendto(psock, buf, len, flags, to, tolen); + } + else + { + /* EDESTADDRREQ. Signifies that the socket is not connection-mode and + * no peer address is set. + */ + + ret = -EDESTADDRREQ; + } + + return ret; +} + +/**************************************************************************** + * Name: bluetooth_close + * + * Description: + * Performs the close operation on a PF_BLUETOOTH socket instance + * + * Input Parameters: + * psock Socket instance + * + * Returned Value: + * 0 on success; a negated errno value is returned on any failure. + * + * Assumptions: + * + ****************************************************************************/ + +static int bluetooth_close(FAR struct socket *psock) +{ + /* Perform some pre-close operations for the PF_BLUETOOTH address type */ + + switch (psock->s_type) + { + case SOCK_DGRAM: + { + FAR struct bluetooth_conn_s *conn = psock->s_conn; + + /* Is this the last reference to the connection structure (there + * could be more if the socket was dup'ed). + */ + + if (conn->bc_crefs <= 1) + { + /* Yes... free the connection structure */ + + conn->bc_crefs = 0; /* No more references on the connection */ + bluetooth_conn_free(psock->s_conn); /* Free network resources */ + } + else + { + /* No.. Just decrement the reference count */ + + conn->bc_crefs--; + } + + return OK; + } + + default: + return -EBADF; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#endif /* CONFIG_NET_BLUETOOTH */ diff --git a/net/devif/devif.h b/net/devif/devif.h index c1406e2e786..ae15637b3ad 100644 --- a/net/devif/devif.h +++ b/net/devif/devif.h @@ -74,7 +74,8 @@ * TCP_NEWDATA IN: Set to indicate that the peer has sent us new data. * UDP_NEWDATA OUT: Cleared (only) by the socket layer logic to indicate * PKT_NEWDATA that the new data was consumed, suppressing further - * IEEE802154_NEWDATA attempts to process the new data. + * BLUETOOTH_NEWDATA attempts to process the new data. + * IEEE802154_NEWDATA * * TCP_SNDACK IN: Not used; always zero * OUT: Set by the socket layer if the new data was consumed @@ -87,8 +88,8 @@ * TCP_POLL IN: Used for polling the socket layer. This is provided * UDP_POLL periodically from the drivers to support (1) timed * PKT_POLL operations, and (2) to check if the socket layer has - * IEEE802154_POLL data that it wants to send. These are socket oriented - * callbacks where the context depends on the specific + * BLUETOOTH_POLL data that it wants to send. These are socket oriented + * IEEE802154_POLL callbacks where the context depends on the specific * set * OUT: Not used * @@ -177,6 +178,7 @@ #define TCP_ACKDATA (1 << 0) #define TCP_NEWDATA (1 << 1) #define UDP_NEWDATA TCP_NEWDATA +#define BLUETOOTH_NEWDATA TCP_NEWDATA #define IEEE802154_NEWDATA TCP_NEWDATA #define PKT_NEWDATA TCP_NEWDATA #define WPAN_NEWDATA TCP_NEWDATA @@ -186,6 +188,7 @@ #define TCP_POLL (1 << 4) #define UDP_POLL TCP_POLL #define PKT_POLL TCP_POLL +#define BLUETOOTH_POLL TCP_POLL #define IEEE802154_POLL TCP_POLL #define WPAN_POLL TCP_POLL #define TCP_BACKLOG (1 << 5) diff --git a/net/devif/devif_poll.c b/net/devif/devif_poll.c index d2febe0da4a..dd3810e0fa6 100644 --- a/net/devif/devif_poll.c +++ b/net/devif/devif_poll.c @@ -1,7 +1,8 @@ /**************************************************************************** * net/devif/devif_poll.c * - * Copyright (C) 2007-2010, 2012, 2014, 2016-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2010, 2012, 2014, 2016-2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -53,6 +54,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "bluetooth/bluetooth.h" #include "ieee802154/ieee802154.h" #include "icmp/icmp.h" #include "icmpv6/icmpv6.h" @@ -238,6 +240,42 @@ static int devif_poll_pkt_connections(FAR struct net_driver_s *dev, } #endif /* CONFIG_NET_PKT */ +/**************************************************************************** + * Name: devif_poll_bluetooth_connections + * + * Description: + * Poll all packet connections for available packets to send. + * + * Assumptions: + * This function is called from the MAC device driver with the network + * locked. + * + ****************************************************************************/ + +#ifdef CONFIG_NET_BLUETOOTH +static int devif_poll_bluetooth_connections(FAR struct net_driver_s *dev, + devif_poll_callback_t callback) +{ + FAR struct bluetooth_conn_s *bluetooth_conn = NULL; + int bstop = 0; + + /* Traverse all of the allocated packet connections and perform the poll action */ + + while (!bstop && (bluetooth_conn = bluetooth_conn_next(bluetooth_conn))) + { + /* Perform the packet TX poll */ + + bluetooth_poll(dev, bluetooth_conn); + + /* Call back into the driver */ + + bstop = callback(dev); + } + + return bstop; +} +#endif /* CONFIG_NET_BLUETOOTH */ + /**************************************************************************** * Name: devif_poll_ieee802154_connections * @@ -561,6 +599,15 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback) if (!bstop) #endif +#ifdef CONFIG_NET_BLUETOOTH + { + /* Check for pending PF_BLUETOOTH socket transfer */ + + bstop = devif_poll_bluetooth_connections(dev, callback); + } + + if (!bstop) +#endif #ifdef CONFIG_NET_IEEE802154 { /* Check for pending PF_IEEE802154 socket transfer */ diff --git a/net/net_initialize.c b/net/net_initialize.c index 0447f88dfcf..e8a3b440d22 100644 --- a/net/net_initialize.c +++ b/net/net_initialize.c @@ -1,7 +1,8 @@ /**************************************************************************** * net/net_initialize.c * - * Copyright (C) 2007-2009, 2011-2015, 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2015, 2017-2018 Gregory Nutt. All rights + * reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -56,6 +57,7 @@ #include "tcp/tcp.h" #include "udp/udp.h" #include "pkt/pkt.h" +#include "bluetooth/bluetooth.h" #include "ieee802154/ieee802154.h" #include "local/local.h" #include "igmp/igmp.h" @@ -140,6 +142,12 @@ void net_setup(void) icmpv6_sock_initialize(); #endif +#ifdef CONFIG_NET_BLUETOOTH + /* Initialize Bluetooth socket support */ + + bluetooth_initialize(); +#endif + #ifdef CONFIG_NET_IEEE802154 /* Initialize IEEE 802.15.4 socket support */ diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c index 027f7271210..bfe6fb2e221 100644 --- a/net/netdev/netdev_ioctl.c +++ b/net/netdev/netdev_ioctl.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/netdev/netdev_ioctl.c * - * Copyright (C) 2007-2012, 2015-2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2012, 2015-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -73,6 +73,10 @@ #endif #if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NET_6LOWPAN) +# ifdef CONFIG_WIRELESS_BLUETOOTH +# include +# endif + # ifdef CONFIG_WIRELESS_IEEE802154 # include # endif @@ -370,6 +374,68 @@ static void ioctl_set_ipv6addr(FAR net_ipv6addr_t outaddr, } #endif +/**************************************************************************** + * Name: netdev_iee802154_ioctl + * + * Description: + * Perform Bluetooth network device specific operations. + * + * Input Parameters: + * psock - Socket structure + * dev - Ethernet driver device structure + * cmd - The ioctl command + * req - The argument of the ioctl cmd + * + * Returned Value: + * >=0 on success (positive non-zero values are cmd-specific) + * Negated errno returned on failure. + * + ****************************************************************************/ + +#if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_NET_6LOWPAN) && \ + defined(CONFIG_WIRELESS_BLUETOOTH) +static int netdev_iee802154_ioctl(FAR struct socket *psock, int cmd, + unsigned long arg) +{ + FAR struct net_driver_s *dev; + FAR char *ifname; + int ret = -ENOTTY; + + if (arg != 0ul) + { + if (WL_IBLUETOOTHCMD(cmd)) + { + /* Get the name of the Bluetooth device to receive the IOCTL + * command + */ + + FAR struct bluetooth_ifreq_s *cmddata = + (FAR struct bluetooth_ifreq_s *)((uintptr_t)arg); + + ifname = cmddata->ifr_name; + } + else + { + /* Not a Bluetooth IOCTL command */ + + return -ENOTTY; + } + + /* Find the device with this name */ + + dev = netdev_findbyname(ifname); + if (dev != NULL && dev->d_lltype == NET_LL_BLUETOOTH) + { + /* Perform the device IOCTL */ + + ret = dev->d_ioctl(dev, cmd, arg); + } + } + + return ret; +} +#endif + /**************************************************************************** * Name: netdev_iee802154_ioctl * diff --git a/net/netdev/netdev_lladdrsize.c b/net/netdev/netdev_lladdrsize.c index d499f4619bf..2640d034064 100644 --- a/net/netdev/netdev_lladdrsize.c +++ b/net/netdev/netdev_lladdrsize.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/netdev/netdev_lladdrsize.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "netdev/netdev.h" @@ -62,7 +63,7 @@ * Description: * Returns the size of the node address associated with a packet radio. * This is probably CONFIG_PKTRADIO_ADDRLEN but we cannot be sure in the - * case that there ar mutiple packet radios. In that case, we have to + * case that there are multiple packet radios. In that case, we have to * query the radio for its address length. * * Input Parameters: @@ -127,6 +128,17 @@ int netdev_dev_lladdrsize(FAR struct net_driver_s *dev) #endif #ifdef CONFIG_NET_6LOWPAN +#ifdef CONFIG_WIRELESS_BLUETOOTH + case NET_LL_BLUETOOTH: + { + /* 6LoWPAN can be configured to use either extended or short + * addressing. + */ + + return BLUETOOTH_HDRLEN; + } +#endif /* CONFIG_WIRELESS_BLUETOOTH */ + #ifdef CONFIG_WIRELESS_IEEE802154 case NET_LL_IEEE802154: { @@ -140,7 +152,6 @@ int netdev_dev_lladdrsize(FAR struct net_driver_s *dev) return NET_6LOWPAN_SADDRSIZE; #endif } - #endif /* CONFIG_WIRELESS_IEEE802154 */ #ifdef CONFIG_WIRELESS_PKTRADIO diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c index f4561b856d1..b9e77b94882 100644 --- a/net/netdev/netdev_register.c +++ b/net/netdev/netdev_register.c @@ -53,6 +53,7 @@ #include #include #include +#include #include "utils/utils.h" #include "igmp/igmp.h" @@ -66,6 +67,8 @@ #define NETDEV_LO_FORMAT "lo" #define NETDEV_SLIP_FORMAT "sl%d" #define NETDEV_TUN_FORMAT "tun%d" +#define NETDEV_BNEP_FORMAT "bnep%d" +#define NETDEV_PAN_FORMAT "pan%d" #define NETDEV_WLAN_FORMAT "wlan%d" #define NETDEV_WPAN_FORMAT "wpan%d" @@ -215,6 +218,21 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype) break; #endif +#ifdef CONFIG_NET_BLUETOOTH + case NET_LL_BLUETOOTH: /* Bluetooth */ + dev->d_llhdrlen = BLUETOOTH_HDRLEN; +#ifdef CONFIG_NET_6LOWPAN +# warning Missing logic + dev->d_mtu = ???; +#ifdef CONFIG_NET_TCP +# warning Missing logic + dev->d_recvwndo = ???; +#endif +#endif + devfmt = NETDEV_BNEP_FORMAT; + break; +#endif + #if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_IEEE802154) case NET_LL_IEEE802154: /* IEEE 802.15.4 MAC */ case NET_LL_PKTRADIO: /* Non-IEEE 802.15.4 packet radio */ diff --git a/net/socket/net_sockif.c b/net/socket/net_sockif.c index cd029b3fe1d..d755c3d2a36 100644 --- a/net/socket/net_sockif.c +++ b/net/socket/net_sockif.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/net_sockif.c * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. + * Copyright (C) 2017-2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,7 @@ #include "inet/inet.h" #include "local/local.h" #include "pkt/pkt.h" +#include "bluetooth/bluetooth.h" #include "ieee802154/ieee802154.h" #include "socket/socket.h" @@ -104,6 +105,12 @@ FAR const struct sock_intf_s * break; #endif +#ifdef CONFIG_NET_BLUETOOTH + case PF_BLUETOOTH: + sockif = &g_bluetooth_sockif; + break; +#endif + #ifdef CONFIG_NET_IEEE802154 case PF_IEEE802154: sockif = &g_ieee802154_sockif; diff --git a/wireless/bluetooth/Make.defs b/wireless/bluetooth/Make.defs index 7e3c2394042..3618ecf0c9d 100644 --- a/wireless/bluetooth/Make.defs +++ b/wireless/bluetooth/Make.defs @@ -38,7 +38,8 @@ ifeq ($(CONFIG_WIRELESS_BLUETOOTH),y) # Include Bluetooth support CSRCS += bt_atomic.c bt_att.c bt_buf.c bt_conn.c bt_gatt.c bt_hcicore.c -CSRCS += bt_ioctl.c bt_keys.c bt_l2cap.c bt_queue.c bt_smp.c bt_uuid.c +CSRCS += bt_ioctl.c bt_keys.c bt_l2cap.c bt_netdev.c bt_queue.c bt_smp.c +CSRCS += bt_uuid.c DEPPATH += --dep-path bluetooth VPATH += :bluetooth diff --git a/wireless/bluetooth/bt_conn.c b/wireless/bluetooth/bt_conn.c index 02ddc8d5a76..9b18e90999f 100644 --- a/wireless/bluetooth/bt_conn.c +++ b/wireless/bluetooth/bt_conn.c @@ -128,11 +128,144 @@ static void bt_conn_reset_rx_state(FAR struct bt_conn_s *conn) conn->rx_len = 0; } +static int conn_tx_kthread(int argc, FAR char *argv[]) +{ + FAR struct bt_conn_s *conn; + FAR struct bt_buf_s *buf; + int ret; + + /* Get the connection instance */ + + conn = g_conn_handoff.conn; + DEBUGASSERT(conn != NULL); + nxsem_post(&g_conn_handoff.sync_sem); + + wlinfo("Started for handle %u\n", conn->handle); + + while (conn->state == BT_CONN_CONNECTED) + { + /* Wait until the controller can accept ACL packets */ + + wlinfo("calling nxsem_wait\n"); + + do + { + ret = nxsem_wait(&g_btdev.le_pkts_sem); + } + while (ret == -EINTR); + + DEBUGASSERT(ret == OK); + + /* Check for disconnection */ + + if (conn->state != BT_CONN_CONNECTED) + { + nxsem_post(&g_btdev.le_pkts_sem); + break; + } + + /* Get next ACL packet for connection */ + + ret = bt_queue_recv(conn->tx_queue, &buf); + DEBUGASSERT(ret >= 0 && buf != NULL); + UNUSED(ret); + + if (conn->state != BT_CONN_CONNECTED) + { + nxsem_post(&g_btdev.le_pkts_sem); + bt_buf_put(buf); + break; + } + + wlinfo("passing buf %p len %u to driver\n", buf, buf->len); + g_btdev.dev->send(g_btdev.dev, buf); + bt_buf_put(buf); + } + + wlinfo("handle %u disconnected - cleaning up\n", conn->handle); + + /* Give back any allocated buffers */ + + do + { + buf = NULL; + ret = bt_queue_recv(conn->tx_queue, &buf); + if (ret >= 0) + { + DEBUGASSERT(buf != NULL); + bt_buf_put(buf); + } + } + while (ret >= OK); + + bt_conn_reset_rx_state(conn); + + wlinfo("handle %u exiting\n", conn->handle); + bt_conn_release(conn); + return EXIT_SUCCESS; +} + +static int bt_hci_disconnect(FAR struct bt_conn_s *conn, uint8_t reason) +{ + FAR struct bt_buf_s *buf; + FAR struct bt_hci_cp_disconnect_s *disconn; + int err; + + buf = bt_hci_cmd_create(BT_HCI_OP_DISCONNECT, sizeof(*disconn)); + if (!buf) + { + return -ENOBUFS; + } + + disconn = bt_buf_add(buf, sizeof(*disconn)); + disconn->handle = BT_HOST2LE16(conn->handle); + disconn->reason = reason; + + err = bt_hci_cmd_send(BT_HCI_OP_DISCONNECT, buf); + if (err) + { + return err; + } + + bt_conn_set_state(conn, BT_CONN_DISCONNECT); + return 0; +} + +static int bt_hci_connect_le_cancel(FAR struct bt_conn_s *conn) +{ + int err; + + err = bt_hci_cmd_send(BT_HCI_OP_LE_CREATE_CONN_CANCEL, NULL); + if (err) + { + return err; + } + + return 0; +} + /**************************************************************************** * Public Functions ****************************************************************************/ -void bt_conn_recv(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf, uint8_t flags) +/**************************************************************************** + * Name: bt_conn_input + * + * Description: + * Receive packets from the HCI core on a registered connection. + * + * Input Parameters: + * conn - The registered connection + * buf - The buffer structure containing the packet + * flags - Packet boundary flags + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bt_conn_input(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf, + uint8_t flags) { FAR struct bt_l2cap_hdr_s *hdr; uint16_t len; @@ -140,6 +273,7 @@ void bt_conn_recv(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf, uint8_t wlinfo("handle %u len %u flags %02x\n", conn->handle, buf->len, flags); /* Check packet boundary flags */ + switch (flags) { case 0x02: @@ -232,6 +366,21 @@ void bt_conn_recv(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf, uint8_t bt_l2cap_recv(conn, buf); } +/**************************************************************************** + * Name: bt_conn_send + * + * Description: + * Send data over a connection + * + * Input Parameters: + * conn - The registered connection + * buf - The buffer structure containing the packet to be sent + * + * Returned Value: + * None + * + ****************************************************************************/ + void bt_conn_send(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf) { FAR struct bt_hci_acl_hdr_s *hdr; @@ -308,82 +457,20 @@ void bt_conn_send(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf) } } -static int conn_tx_kthread(int argc, FAR char *argv[]) -{ - FAR struct bt_conn_s *conn; - FAR struct bt_buf_s *buf; - int ret; - - /* Get the connection instance */ - - conn = g_conn_handoff.conn; - DEBUGASSERT(conn != NULL); - nxsem_post(&g_conn_handoff.sync_sem); - - wlinfo("Started for handle %u\n", conn->handle); - - while (conn->state == BT_CONN_CONNECTED) - { - /* Wait until the controller can accept ACL packets */ - - wlinfo("calling nxsem_wait\n"); - - do - { - ret = nxsem_wait(&g_btdev.le_pkts_sem); - } - while (ret == -EINTR); - - DEBUGASSERT(ret == OK); - - /* Check for disconnection */ - - if (conn->state != BT_CONN_CONNECTED) - { - nxsem_post(&g_btdev.le_pkts_sem); - break; - } - - /* Get next ACL packet for connection */ - - ret = bt_queue_recv(conn->tx_queue, &buf); - DEBUGASSERT(ret >= 0 && buf != NULL); - UNUSED(ret); - - if (conn->state != BT_CONN_CONNECTED) - { - nxsem_post(&g_btdev.le_pkts_sem); - bt_buf_put(buf); - break; - } - - wlinfo("passing buf %p len %u to driver\n", buf, buf->len); - g_btdev.dev->send(g_btdev.dev, buf); - bt_buf_put(buf); - } - - wlinfo("handle %u disconnected - cleaning up\n", conn->handle); - - /* Give back any allocated buffers */ - - do - { - buf = NULL; - ret = bt_queue_recv(conn->tx_queue, &buf); - if (ret >= 0) - { - DEBUGASSERT(buf != NULL); - bt_buf_put(buf); - } - } - while (ret >= OK); - - bt_conn_reset_rx_state(conn); - - wlinfo("handle %u exiting\n", conn->handle); - bt_conn_put(conn); - return EXIT_SUCCESS; -} +/**************************************************************************** + * Name: bt_conn_add + * + * Description: + * Add a new connection + * + * Input Parameters: + * peer - The address of the Bluetooth peer + * role - Either BT_HCI_ROLE_MASTER or BT_HCI_ROLE_SLAVE + * + * Returned Value: + * A reference to the new connection structure is returned on success. + * + ****************************************************************************/ FAR struct bt_conn_s *bt_conn_add(FAR const bt_addr_le_t *peer, uint8_t role) @@ -414,6 +501,22 @@ FAR struct bt_conn_s *bt_conn_add(FAR const bt_addr_le_t *peer, return conn; } +/**************************************************************************** + * Name: bt_conn_set_state + * + * Description: + * Set connection object in certain state and perform actions related to + * state change. + * + * Input Parameters: + * conn - The connection whose state will be changed. + * state - The new state of the connection. + * + * Returned Value: + * None + * + ****************************************************************************/ + void bt_conn_set_state(FAR struct bt_conn_s *conn, enum bt_conn_state_e state) { @@ -436,7 +539,7 @@ void bt_conn_set_state(FAR struct bt_conn_s *conn, if (old_state == BT_CONN_DISCONNECTED) { - bt_conn_get(conn); + bt_conn_addref(conn); } switch (conn->state) @@ -465,7 +568,7 @@ void bt_conn_set_state(FAR struct bt_conn_s *conn, /* Start the Tx connection kernel thread */ - g_conn_handoff.conn = bt_conn_get(conn); + g_conn_handoff.conn = bt_conn_addref(conn); pid = kthread_create("BT Conn Tx", CONFIG_BLUETOOTH_TXCONN_PRIORITY, CONFIG_BLUETOOTH_TXCONN_STACKSIZE, conn_tx_kthread, NULL); @@ -498,7 +601,7 @@ void bt_conn_set_state(FAR struct bt_conn_s *conn, /* Release the reference we took for the very first state transition. */ - bt_conn_put(conn); + bt_conn_release(conn); break; case BT_CONN_CONNECT_SCAN: @@ -512,6 +615,23 @@ void bt_conn_set_state(FAR struct bt_conn_s *conn, } } +/**************************************************************************** + * Name: bt_conn_lookup_handle + * + * Description: + * Look up an existing connection + * + * Input Parameters: + * handle - The handle to be used to perform the lookup + * + * Returned Value: + * A reference to the connection state instance is returned on success. + * NULL is returned if the connection is not found. On succes, the + * caller gets a new reference to the connection object which must be + * released with bt_conn_release() once done using the connection. + * + ****************************************************************************/ + FAR struct bt_conn_s *bt_conn_lookup_handle(uint16_t handle) { int i; @@ -528,13 +648,30 @@ FAR struct bt_conn_s *bt_conn_lookup_handle(uint16_t handle) if (g_conns[i].handle == handle) { - return bt_conn_get(&g_conns[i]); + return bt_conn_addref(&g_conns[i]); } } return NULL; } +/**************************************************************************** + * Name: bt_conn_lookup_addr_le + * + * Description: + * Look up an existing connection based on the remote address. + * + * Input Parameters: + * peer - Remote address. + * + * Returned Value: + * A reference to the connection state instance is returned on success. + * NULL is returned if the connection is not found. On succes, the + * caller gets a new reference to the connection object which must be + * released with bt_conn_release() once done using the connection. + * + ****************************************************************************/ + FAR struct bt_conn_s *bt_conn_lookup_addr_le(FAR const bt_addr_le_t * peer) { int i; @@ -543,13 +680,32 @@ FAR struct bt_conn_s *bt_conn_lookup_addr_le(FAR const bt_addr_le_t * peer) { if (!bt_addr_le_cmp(peer, &g_conns[i].dst)) { - return bt_conn_get(&g_conns[i]); + return bt_conn_addref(&g_conns[i]); } } return NULL; } +/**************************************************************************** + * Name: bt_conn_lookup_state + * + * Description: + * Look up a connection state. For BT_ADDR_LE_ANY, returns the first + * connection with the specific state + * + * Input Parameters: + * peer - The peer address to match + * state - The connection state to match + * + * Returned Value: + * A reference to the connection state instance is returned on success. + * NULL is returned if the connection is not found. On succes, the + * caller gets a new reference to the connection object which must be + * released with bt_conn_release() once done using the connection. + * + ****************************************************************************/ + FAR struct bt_conn_s *bt_conn_lookup_state(FAR const bt_addr_le_t * peer, enum bt_conn_state_e state) { @@ -570,14 +726,28 @@ FAR struct bt_conn_s *bt_conn_lookup_state(FAR const bt_addr_le_t * peer, if (g_conns[i].state == state) { - return bt_conn_get(&g_conns[i]); + return bt_conn_addref(&g_conns[i]); } } return NULL; } -FAR struct bt_conn_s *bt_conn_get(FAR struct bt_conn_s *conn) +/**************************************************************************** + * Name: bt_conn_addref + * + * Description: + * Increment the reference count of a connection object. + * + * Input Parameters: + * conn - Connection object. + * + * Returned Value: + * Connection object with incremented reference count. + * + ****************************************************************************/ + +FAR struct bt_conn_s *bt_conn_addref(FAR struct bt_conn_s *conn) { bt_atomic_incr(&conn->ref); @@ -586,7 +756,21 @@ FAR struct bt_conn_s *bt_conn_get(FAR struct bt_conn_s *conn) return conn; } -void bt_conn_put(FAR struct bt_conn_s *conn) +/**************************************************************************** + * Name: bt_conn_release + * + * Description: + * Decrement the reference count of a connection object. + * + * Input Parameters: + * conn - Connection object. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bt_conn_release(FAR struct bt_conn_s *conn) { bt_atomic_t old_ref; @@ -602,11 +786,51 @@ void bt_conn_put(FAR struct bt_conn_s *conn) bt_addr_le_copy(&conn->dst, BT_ADDR_LE_ANY); } -const bt_addr_le_t *bt_conn_get_dst(FAR const struct bt_conn_s *conn) +/**************************************************************************** + * Name: bt_conn_get_dst + * + * Description: + * Get destination (peer) address of a connection. + * + * Input Parameters: + * conn - Connection object. + * + * Returned Value: + * Destination address. + * + ****************************************************************************/ + +FAR const bt_addr_le_t *bt_conn_get_dst(FAR const struct bt_conn_s *conn) { return &conn->dst; } +/**************************************************************************** + * Name: bt_conn_security + * + * Description: + * This function enable security (encryption) for a connection. If device is + * already paired with sufficiently strong key encryption will be enabled. If + * link is already encrypted with sufficiently strong key this function does + * nothing. + * + * If device is not paired pairing will be initiated. If device is paired and + * keys are too weak but input output capabilities allow for strong enough keys + * pairing will be initiated. + * + * This function may return error if required level of security is not possible + * to achieve due to local or remote device limitation (eg input output + * capabilities). + * + * Input Parameters: + * conn - Connection object. + * sec - Requested security level. + * + * Returned Value: + * 0 on success or negative error + * + ****************************************************************************/ + int bt_conn_security(FAR struct bt_conn_s *conn, enum bt_security_e sec) { FAR struct bt_keys_s *keys; @@ -650,6 +874,25 @@ int bt_conn_security(FAR struct bt_conn_s *conn, enum bt_security_e sec) return bt_smp_send_pairing_req(conn); } +/**************************************************************************** + * Name:bt_conn_set_auto_conn + * + * Description: + * This function enables/disables automatic connection initiation. + * Every time the device looses the connection with peer, this connection + * will be re-established if connectible advertisement from peer is + * received. + * + * Input Parameters: + * conn - Existing connection object. + * auto_conn - boolean value. If true, auto connect is enabled, if false, + * auto connect is disabled. + * + * Returned Value: + * None + * + ****************************************************************************/ + void bt_conn_set_auto_conn(FAR struct bt_conn_s *conn, bool auto_conn) { if (auto_conn) @@ -662,44 +905,21 @@ void bt_conn_set_auto_conn(FAR struct bt_conn_s *conn, bool auto_conn) } } -static int bt_hci_disconnect(FAR struct bt_conn_s *conn, uint8_t reason) -{ - FAR struct bt_buf_s *buf; - FAR struct bt_hci_cp_disconnect_s *disconn; - int err; - - buf = bt_hci_cmd_create(BT_HCI_OP_DISCONNECT, sizeof(*disconn)); - if (!buf) - { - return -ENOBUFS; - } - - disconn = bt_buf_add(buf, sizeof(*disconn)); - disconn->handle = BT_HOST2LE16(conn->handle); - disconn->reason = reason; - - err = bt_hci_cmd_send(BT_HCI_OP_DISCONNECT, buf); - if (err) - { - return err; - } - - bt_conn_set_state(conn, BT_CONN_DISCONNECT); - return 0; -} - -static int bt_hci_connect_le_cancel(FAR struct bt_conn_s *conn) -{ - int err; - - err = bt_hci_cmd_send(BT_HCI_OP_LE_CREATE_CONN_CANCEL, NULL); - if (err) - { - return err; - } - - return 0; -} +/**************************************************************************** + * Name: bt_conn_disconnect + * + * Description: + * Disconnect an active connection with the specified reason code or cancel + * pending outgoing connection. + * + * Input Parameters: + * conn - Connection to disconnect. + * reason - Reason code for the disconnection. + * + * Returned Value: + * Zero on success or (negative) error code on failure. + * + ****************************************************************************/ int bt_conn_disconnect(FAR struct bt_conn_s *conn, uint8_t reason) { @@ -732,6 +952,21 @@ int bt_conn_disconnect(FAR struct bt_conn_s *conn, uint8_t reason) } } +/**************************************************************************** + * Name: bt_conn_create_le + * + * Description: + * Allows initiate new LE link to remote peer using its address. + * Returns a new reference that the the caller is responsible for managing. + * + * Input Parameters: + * peer - Remote address. + * + * Returned Value: + * Valid connection object on success or NULL otherwise. + * + ****************************************************************************/ + FAR struct bt_conn_s *bt_conn_create_le(FAR const bt_addr_le_t *peer) { FAR struct bt_conn_s *conn; @@ -747,7 +982,7 @@ FAR struct bt_conn_s *bt_conn_create_le(FAR const bt_addr_le_t *peer) return conn; default: - bt_conn_put(conn); + bt_conn_release(conn); return NULL; } } @@ -763,6 +998,25 @@ FAR struct bt_conn_s *bt_conn_create_le(FAR const bt_addr_le_t *peer) return conn; } +/**************************************************************************** + * Name: bt_conn_le_start_encryption + * + * Description: + * See the HCI start encryption command. + * + * NOTE: rand and ediv should be in BT order. + * + * Input Parameters: + * conn - The connection to send the command on. + * rand, ediv - Values to use for the encryption key + * ltk - + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + int bt_conn_le_start_encryption(FAR struct bt_conn_s *conn, uint64_t rand, uint16_t ediv, FAR const uint8_t *ltk) { diff --git a/wireless/bluetooth/bt_conn.h b/wireless/bluetooth/bt_conn.h index 822411557a6..b53efe5a60c 100644 --- a/wireless/bluetooth/bt_conn.h +++ b/wireless/bluetooth/bt_conn.h @@ -50,8 +50,6 @@ #include -#include - #include "bt_atomic.h" /**************************************************************************** @@ -116,39 +114,302 @@ struct bt_conn_s * Public Data ****************************************************************************/ -/* Process incoming data for a connection */ +/**************************************************************************** + * Name: bt_conn_input + * + * Description: + * Receive packets from the HCI core on a registered connection. + * + * Input Parameters: + * conn - The registered connection + * buf - The buffer structure containing the received packet + * flags - Packet boundary flags + * + * Returned Value: + * None + * + ****************************************************************************/ -void bt_conn_recv(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf, - uint8_t flags); +void bt_conn_input(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf, + uint8_t flags); -/* Send data over a connection */ +/**************************************************************************** + * Name: bt_conn_send + * + * Description: + * Send data over a connection + * + * Input Parameters: + * conn - The registered connection + * buf - The buffer structure containing the packet to be sent + * + * Returned Value: + * None + * + ****************************************************************************/ void bt_conn_send(FAR struct bt_conn_s *conn, FAR struct bt_buf_s *buf); -/* Add a new connection */ +/**************************************************************************** + * Name: bt_conn_add + * + * Description: + * Add a new connection + * + * Input Parameters: + * peer - The address of the Bluetooth peer + * role - Either BT_HCI_ROLE_MASTER or BT_HCI_ROLE_SLAVE + * + * Returned Value: + * A reference to the new connection structure is returned on success. + * + ****************************************************************************/ FAR struct bt_conn_s *bt_conn_add(FAR const bt_addr_le_t *peer, uint8_t role); -/* Look up an existing connection */ - -FAR struct bt_conn_s *bt_conn_lookup_handle(uint16_t handle); - -/* Look up a connection state. For BT_ADDR_LE_ANY, returns the first connection - * with the specific state - */ - -FAR struct bt_conn_s *bt_conn_lookup_state(FAR const bt_addr_le_t * peer, - enum bt_conn_state_e state); - -/* Set connection object in certain state and perform action related to state */ +/**************************************************************************** + * Name: bt_conn_set_state + * + * Description: + * Set connection object in certain state and perform actions related to + * state change. + * + * Input Parameters: + * conn - The connection whose state will be changed. + * state - The new state of the connection. + * + * Returned Value: + * None + * + ****************************************************************************/ void bt_conn_set_state(FAR struct bt_conn_s *conn, enum bt_conn_state_e state); -/* rand and ediv should be in BT order */ +/**************************************************************************** + * Name: bt_conn_lookup_handle + * + * Description: + * Look up an existing connection + * + * Input Parameters: + * handle - The handle to be used to perform the lookup + * + * Returned Value: + * A reference to the connection state instance is returned on success. + * NULL is returned if the connection is not found. On succes, the + * caller gets a new reference to the connection object which must be + * released with bt_conn_release() once done using the connection. + * + ****************************************************************************/ + +FAR struct bt_conn_s *bt_conn_lookup_handle(uint16_t handle); + +/**************************************************************************** + * Name: bt_conn_lookup_addr_le + * + * Description: + * Look up an existing connection based on the remote address. + * + * Input Parameters: + * peer - Remote address. + * + * Returned Value: + * A reference to the connection state instance is returned on success. + * NULL is returned if the connection is not found. On succes, the + * caller gets a new reference to the connection object which must be + * released with bt_conn_release() once done using the connection. + * + ****************************************************************************/ + +FAR struct bt_conn_s *bt_conn_lookup_addr_le(const bt_addr_le_t *peer); + +/**************************************************************************** + * Name: bt_conn_lookup_state + * + * Description: + * Look up a connection state. For BT_ADDR_LE_ANY, returns the first + * connection with the specific state + * + * Input Parameters: + * peer - The peer address to match + * state - The connection state to match + * + * Returned Value: + * A reference to the connection state instance is returned on success. + * NULL is returned if the connection is not found. On succes, the + * caller gets a new reference to the connection object which must be + * released with bt_conn_release() once done using the connection. + * + ****************************************************************************/ + +FAR struct bt_conn_s *bt_conn_lookup_state(FAR const bt_addr_le_t *peer, + enum bt_conn_state_e state); + +/**************************************************************************** + * Name: bt_conn_addref + * + * Description: + * Increment the reference count of a connection object. + * + * Input Parameters: + * conn - Connection object. + * + * Returned Value: + * Connection object with incremented reference count. + * + ****************************************************************************/ + +FAR struct bt_conn_s *bt_conn_addref(FAR struct bt_conn_s *conn); + +/**************************************************************************** + * Name: bt_conn_release + * + * Description: + * Decrement the reference count of a connection object. + * + * Input Parameters: + * conn - Connection object. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bt_conn_release(FAR struct bt_conn_s *conn); + +/**************************************************************************** + * Name: bt_conn_get_dst + * + * Description: + * Get destination (peer) address of a connection. + * + * Input Parameters: + * conn - Connection object. + * + * Returned Value: + * Destination address. + * + ****************************************************************************/ + +FAR const bt_addr_le_t *bt_conn_get_dst(FAR const struct bt_conn_s *conn); + +/**************************************************************************** + * Name: bt_conn_security + * + * Description: + * This function enable security (encryption) for a connection. If device is + * already paired with sufficiently strong key encryption will be enabled. If + * link is already encrypted with sufficiently strong key this function does + * nothing. + * + * If device is not paired pairing will be initiated. If device is paired and + * keys are too weak but input output capabilities allow for strong enough keys + * pairing will be initiated. + * + * This function may return error if required level of security is not possible + * to achieve due to local or remote device limitation (eg input output + * capabilities). + * + * Input Parameters: + * conn - Connection object. + * sec - Requested security level. + * + * Returned Value: + * 0 on success or negative error + * + ****************************************************************************/ + +int bt_conn_security(FAR struct bt_conn_s *conn, enum bt_security_e sec); + +/**************************************************************************** + * Name:bt_conn_set_auto_conn + * + * Description: + * This function enables/disables automatic connection initiation. + * Every time the device looses the connection with peer, this connection + * will be re-established if connectible advertisement from peer is + * received. + * + * Input Parameters: + * conn - Existing connection object. + * auto_conn - boolean value. If true, auto connect is enabled, if false, + * auto connect is disabled. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bt_conn_set_auto_conn(FAR struct bt_conn_s *conn, bool auto_conn); + +/**************************************************************************** + * Name: bt_conn_disconnect + * + * Description: + * Disconnect an active connection with the specified reason code or cancel + * pending outgoing connection. + * + * Input Parameters: + * conn - Connection to disconnect. + * reason - Reason code for the disconnection. + * + * Returned Value: + * Zero on success or (negative) error code on failure. + * + ****************************************************************************/ + +int bt_conn_disconnect(FAR struct bt_conn_s *conn, uint8_t reason); + +/**************************************************************************** + * Name: bt_conn_create_le + * + * Description: + * Allows initiate new LE link to remote peer using its address. + * Returns a new reference that the the caller is responsible for managing. + * + * Input Parameters: + * peer - Remote address. + * + * Returned Value: + * Valid connection object on success or NULL otherwise. + * + ****************************************************************************/ + +FAR struct bt_conn_s *bt_conn_create_le(FAR const bt_addr_le_t *peer); + +/**************************************************************************** + * Name: bt_conn_le_start_encryption + * + * Description: + * See the HCI start encryption command. + * + * NOTE: rand and ediv should be in BT order. + * + * Input Parameters: + * conn - The connection to send the command on. + * rand, ediv - Values to use for the encryption key + * ltk - + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ int bt_conn_le_start_encryption(FAR struct bt_conn_s *conn, uint64_t rand, uint16_t ediv, FAR const uint8_t *ltk); +/**************************************************************************** + * Name: + * + * Description: + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + int bt_conn_le_conn_update(FAR struct bt_conn_s *conn, uint16_t min, uint16_t max, uint16_t latency, uint16_t timeout); diff --git a/wireless/bluetooth/bt_gatt.c b/wireless/bluetooth/bt_gatt.c index cff95754a1f..c0ed2782d73 100644 --- a/wireless/bluetooth/bt_gatt.c +++ b/wireless/bluetooth/bt_gatt.c @@ -436,7 +436,7 @@ static uint8_t notify_cb(FAR const struct bt_gatt_attr_s *attr, if (!buf) { wlwarn("No buffer available to send notification"); - bt_conn_put(conn); + bt_conn_release(conn); return BT_GATT_ITER_STOP; } @@ -449,7 +449,7 @@ static uint8_t notify_cb(FAR const struct bt_gatt_attr_s *attr, memcpy(nfy->value, data->data, data->len); bt_l2cap_send(conn, BT_L2CAP_CID_ATT, buf); - bt_conn_put(conn); + bt_conn_release(conn); } return BT_GATT_ITER_CONTINUE; @@ -555,7 +555,7 @@ static uint8_t disconnected_cb(FAR const struct bt_gatt_attr_s *attr, tmp = bt_conn_lookup_addr_le(&ccc->cfg[i].peer); if (tmp && tmp->state == BT_CONN_CONNECTED) { - bt_conn_put(tmp); + bt_conn_release(tmp); return BT_GATT_ITER_CONTINUE; } } diff --git a/wireless/bluetooth/bt_hcicore.c b/wireless/bluetooth/bt_hcicore.c index 54f1a77df37..3b85aec69e7 100644 --- a/wireless/bluetooth/bt_hcicore.c +++ b/wireless/bluetooth/bt_hcicore.c @@ -1,5 +1,5 @@ /**************************************************************************** - * wireless/bluetooth/bt_att.c + * wireless/bluetooth/bt_hdicore.c * HCI core Bluetooth handling. * * Copyright (C) 2018 Gregory Nutt. All rights reserved. @@ -117,140 +117,6 @@ static void bt_disconnected(FAR struct bt_conn_s *conn) } } -void bt_conn_cb_register(FAR struct bt_conn_cb_s *cb) -{ - cb->next = g_callback_list; - g_callback_list = cb; -} - -FAR struct bt_buf_s *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len) -{ - FAR struct bt_hci_cmd_hdr_s *hdr; - FAR struct bt_buf_s *buf; - - wlinfo("opcode %x param_len %u\n", opcode, param_len); - - buf = bt_buf_get(BT_CMD, g_btdev.dev->head_reserve); - if (!buf) - { - wlerr("ERROR: Cannot get free buffer\n"); - return NULL; - } - - wlinfo("buf %p\n", buf); - - buf->u.hci.opcode = opcode; - buf->u.hci.sync = NULL; - - hdr = bt_buf_add(buf, sizeof(*hdr)); - hdr->opcode = BT_HOST2LE16(opcode); - hdr->param_len = param_len; - - return buf; -} - -int bt_hci_cmd_send(uint16_t opcode, FAR struct bt_buf_s *buf) -{ - int ret; - if (!buf) - { - buf = bt_hci_cmd_create(opcode, 0); - if (!buf) - { - return -ENOBUFS; - } - } - - wlinfo("opcode %x len %u\n", opcode, buf->len); - - /* Host Number of Completed Packets can ignore the ncmd value and does not - * generate any cmd complete/status events. - */ - - if (opcode == BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS) - { - g_btdev.dev->send(g_btdev.dev, buf); - bt_buf_put(buf); - return 0; - } - - ret = bt_queue_send(g_btdev.tx_queue, buf, BT_NORMAL_PRIO); - if (ret < 0) - { - wlerr("ERROR: bt_queue_send() failed: %d\n", ret); - } - - return ret; -} - -int bt_hci_cmd_send_sync(uint16_t opcode, FAR struct bt_buf_s *buf, - FAR struct bt_buf_s **rsp) -{ - sem_t sync_sem; - int ret; - - /* NOTE: This function cannot be called from the rx thread since it relies - * on the very same thread in processing the cmd_complete event and giving - * back the blocking semaphore. - */ - - if (!buf) - { - buf = bt_hci_cmd_create(opcode, 0); - if (!buf) - { - return -ENOBUFS; - } - } - - wlinfo("opcode %x len %u\n", opcode, buf->len); - - nxsem_init(&sync_sem, 0, 0); - nxsem_setprotocol(&sync_sem, SEM_PRIO_NONE); - buf->u.hci.sync = &sync_sem; - - ret = bt_queue_send(g_btdev.tx_queue, buf, BT_NORMAL_PRIO); - if (ret < 0) - { - wlerr("ERROR: bt_queue_send() failed: %d\n", ret); - } - - if (ret >= 0) - { - do - { - ret = nxsem_wait(&sync_sem); - } - while (ret == -EINTR); - } - - /* Indicate failure if we failed to get the return parameters */ - - if (ret >= 0) - { - if (!buf->u.hci.sync) - { - ret = -EIO; - } - else - { - ret = 0; - } - } - - if (rsp) - { - *rsp = buf->u.hci.sync; - } - else if (buf->u.hci.sync) - { - bt_buf_put(buf->u.hci.sync); - } - - bt_buf_put(buf); - return ret; -} - static void hci_acl(FAR struct bt_buf_s *buf) { FAR struct bt_hci_acl_hdr_s *hdr = (FAR void *)buf->data; @@ -284,8 +150,8 @@ static void hci_acl(FAR struct bt_buf_s *buf) return; } - bt_conn_recv(conn, buf, flags); - bt_conn_put(conn); + bt_conn_input(conn, buf, flags); + bt_conn_release(conn); } /* HCI event processing */ @@ -314,7 +180,7 @@ static void hci_encrypt_change(FAR struct bt_buf_s *buf) conn->encrypt = evt->encrypt; bt_l2cap_encrypt_change(conn); - bt_conn_put(conn); + bt_conn_release(conn); } static void hci_reset_complete(FAR struct bt_buf_s *buf) @@ -485,7 +351,7 @@ static void hci_encrypt_key_refresh_complete(FAR struct bt_buf_s *buf) } bt_l2cap_encrypt_change(conn); - bt_conn_put(conn); + bt_conn_release(conn); } static void copy_id_addr(FAR struct bt_conn_s *conn, @@ -665,7 +531,7 @@ static void hci_disconn_complete(FAR struct bt_buf_s *buf) bt_le_scan_update(); } - bt_conn_put(conn); + bt_conn_release(conn); if (g_btdev.adv_enable) { @@ -715,7 +581,7 @@ static void le_conn_complete(FAR struct bt_buf_s *buf) * DISCONNECTED state since no successful LE link been made. */ - bt_conn_put(conn); + bt_conn_release(conn); return; } @@ -746,7 +612,7 @@ static void le_conn_complete(FAR struct bt_buf_s *buf) } bt_connected(conn); - bt_conn_put(conn); + bt_conn_release(conn); bt_le_scan_update(); } @@ -789,7 +655,7 @@ static void check_pending_conn(FAR const bt_addr_le_t *addr, uint8_t evtype, bt_conn_set_state(conn, BT_CONN_CONNECT); done: - bt_conn_put(conn); + bt_conn_release(conn); } static void le_adv_report(FAR struct bt_buf_s *buf) @@ -898,7 +764,7 @@ static void le_ltk_request(FAR struct bt_buf_s *buf) } done: - bt_conn_put(conn); + bt_conn_release(conn); } static void hci_le_meta_event(FAR struct bt_buf_s *buf) @@ -1339,7 +1205,7 @@ static void rx_queue_init(void) pid_t pid; int ret; - /* When a buffer is received from the Bluetooth driver via bt_recv() on + /* When a buffer is received from the Bluetooth driver via bt_input() on * the Rx queue and received by logic on the Rx kernel thread. */ @@ -1360,9 +1226,113 @@ static void rx_queue_init(void) * Public Functions ****************************************************************************/ -/* Interface to HCI driver layer */ +/**************************************************************************** + * Name: bt_initialize + * + * Description: + * Initialize Bluetooth. Must be the called before anything else. + * + * Returned Value: + * Zero on success or (negative) error code otherwise. + * + ****************************************************************************/ -void bt_recv(FAR struct bt_buf_s *buf) +int bt_initialize(void) +{ + FAR const struct bt_driver_s *dev = g_btdev.dev; + int err; + + DEBUGASSERT(dev != NULL); + bt_buf_init(); + + cmd_queue_init(); + rx_queue_init(); + + err = dev->open(dev); + if (err) + { + wlerr("ERROR: HCI driver open failed (%d)\n", err); + return err; + } + + err = hci_init(); + if (err) + { + return err; + } + + return bt_l2cap_init(); +} + +/**************************************************************************** + * Name: bt_driver_register + * + * Description: + * Register the Bluetooth low-level driver with the Bluetooth stack. + * This is called from the low-level driver and is part of the driver + * interface prototyped in include/nuttx/wireless/bt_driver.h + * + * Input Parameters: + * dev - An instance of the low-level drivers interface structure. + * + * Returned Value: + * Zero is returned on success; a negated errno value is returned on any + * failure. + * + ****************************************************************************/ + +int bt_driver_register(FAR const struct bt_driver_s *dev) +{ + DEBUGASSERT(dev != NULL && dev->open != NULL && dev->send != NULL); + + if (g_btdev.dev != NULL) + { + return -EALREADY; + } + + g_btdev.dev = dev; + return 0; +} + +/**************************************************************************** + * Name: bt_driver_unregister + * + * Description: + * Unregister a Bluetooth low-level driver previously registered with + * bt_driver_register. This may be called from the low-level driver and + * is part of the driver interface prototyped in + * include/nuttx/wireless/bt_driver.h + * + * Input Parameters: + * dev - An instance of the low-level drivers interface structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bt_driver_unregister(FAR const struct bt_driver_s *dev) +{ + g_btdev.dev = NULL; +} + +/**************************************************************************** + * Name: bt_input + * + * Description: + * Called by the Bluetooth low-level driver when new data is received from + * the radio. This may be called from the low-level driver and is part of + * the driver interface prototyped in include/nuttx/wireless/bt_driver.h + * + * Input Parameters: + * buf - An instance of the buffer structure providing the received frame. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bt_input(FAR struct bt_buf_s *buf) { FAR struct bt_hci_evt_hdr_s *hdr; int prio = BT_NORMAL_PRIO; @@ -1397,49 +1367,144 @@ void bt_recv(FAR struct bt_buf_s *buf) } } -int bt_driver_register(FAR const struct bt_driver_s *dev) -{ - DEBUGASSERT(dev != NULL && dev->open != NULL && dev->send != NULL); +/**************************************************************************** + * Name: bt_hci_cmd_create + * + * Description: + * Allocate and initialize a buffer for a command + * + * Returned Value: + * A reference to the allocated buffer. NULL could possibly be returned + * on any failure to allocate. + * + ****************************************************************************/ - if (g_btdev.dev != NULL) +FAR struct bt_buf_s *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len) +{ + FAR struct bt_hci_cmd_hdr_s *hdr; + FAR struct bt_buf_s *buf; + + wlinfo("opcode %x param_len %u\n", opcode, param_len); + + buf = bt_buf_get(BT_CMD, g_btdev.dev->head_reserve); + if (!buf) { - return -EALREADY; + wlerr("ERROR: Cannot get free buffer\n"); + return NULL; } - g_btdev.dev = dev; - return 0; + wlinfo("buf %p\n", buf); + + buf->u.hci.opcode = opcode; + buf->u.hci.sync = NULL; + + hdr = bt_buf_add(buf, sizeof(*hdr)); + hdr->opcode = BT_HOST2LE16(opcode); + hdr->param_len = param_len; + + return buf; } -void bt_driver_unregister(FAR const struct bt_driver_s *dev) +int bt_hci_cmd_send(uint16_t opcode, FAR struct bt_buf_s *buf) { - g_btdev.dev = NULL; + int ret; + if (!buf) + { + buf = bt_hci_cmd_create(opcode, 0); + if (!buf) + { + return -ENOBUFS; + } + } + + wlinfo("opcode %x len %u\n", opcode, buf->len); + + /* Host Number of Completed Packets can ignore the ncmd value and does not + * generate any cmd complete/status events. + */ + + if (opcode == BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS) + { + g_btdev.dev->send(g_btdev.dev, buf); + bt_buf_put(buf); + return 0; + } + + ret = bt_queue_send(g_btdev.tx_queue, buf, BT_NORMAL_PRIO); + if (ret < 0) + { + wlerr("ERROR: bt_queue_send() failed: %d\n", ret); + } + + return ret; } -int bt_init(void) +int bt_hci_cmd_send_sync(uint16_t opcode, FAR struct bt_buf_s *buf, + FAR struct bt_buf_s **rsp) { - FAR const struct bt_driver_s *dev = g_btdev.dev; - int err; + sem_t sync_sem; + int ret; - DEBUGASSERT(dev != NULL); - bt_buf_init(); + /* NOTE: This function cannot be called from the rx thread since it relies + * on the very same thread in processing the cmd_complete event and giving + * back the blocking semaphore. + */ - cmd_queue_init(); - rx_queue_init(); - - err = dev->open(dev); - if (err) + if (!buf) { - wlerr("ERROR: HCI driver open failed (%d)\n", err); - return err; + buf = bt_hci_cmd_create(opcode, 0); + if (!buf) + { + return -ENOBUFS; + } } - err = hci_init(); - if (err) + wlinfo("opcode %x len %u\n", opcode, buf->len); + + nxsem_init(&sync_sem, 0, 0); + nxsem_setprotocol(&sync_sem, SEM_PRIO_NONE); + buf->u.hci.sync = &sync_sem; + + ret = bt_queue_send(g_btdev.tx_queue, buf, BT_NORMAL_PRIO); + if (ret < 0) { - return err; + wlerr("ERROR: bt_queue_send() failed: %d\n", ret); } - return bt_l2cap_init(); + if (ret >= 0) + { + do + { + ret = nxsem_wait(&sync_sem); + } + while (ret == -EINTR); + } + + /* Indicate failure if we failed to get the return parameters */ + + if (ret >= 0) + { + if (!buf->u.hci.sync) + { + ret = -EIO; + } + else + { + ret = 0; + } + } + + if (rsp) + { + *rsp = buf->u.hci.sync; + } + else if (buf->u.hci.sync) + { + bt_buf_put(buf->u.hci.sync); + } + + bt_buf_put(buf); + return ret; } /**************************************************************************** @@ -1651,25 +1716,35 @@ int bt_stop_scanning(void) return bt_le_scan_update(); } -/* Used to determine whether to start scan and which scan type should be used */ +/**************************************************************************** + * Name: bt_le_scan_update + * + * Description: + * Used to determine whether to start scan and which scan type should be + * used. + * + * Returned Value: + * Zero on success or error code otherwise, positive in case + * of protocol error or negative (POSIX) in case of stack internal error + * + ****************************************************************************/ int bt_le_scan_update(void) { FAR struct bt_conn_s *conn; + int ret; if (g_btdev.scan_enable) { - int err; - if (g_scan_dev_found_cb) { return 0; } - err = bt_hci_stop_scanning(); - if (err) + ret = bt_hci_stop_scanning(); + if (ret) { - return err; + return ret; } } @@ -1684,11 +1759,27 @@ int bt_le_scan_update(void) return 0; } - bt_conn_put(conn); - + bt_conn_release(conn); return bt_hci_start_scanning(BT_LE_SCAN_PASSIVE, g_btdev.scan_filter); } +/**************************************************************************** + * Name: bt_conn_cb_register + * + * Description: + * Register callbacks to monitor the state of connections. + * + * Input Parameters: + * cb - Instance of the callback structure. + * + ****************************************************************************/ + +void bt_conn_cb_register(FAR struct bt_conn_cb_s *cb) +{ + cb->next = g_callback_list; + g_callback_list = cb; +} + #ifdef CONFIG_DEBUG_WIRELESS_INFO FAR const char *bt_addr_str(FAR const bt_addr_t *addr) { diff --git a/wireless/bluetooth/bt_hcicore.h b/wireless/bluetooth/bt_hcicore.h index 9b4eb012151..61c19f7d6b3 100644 --- a/wireless/bluetooth/bt_hcicore.h +++ b/wireless/bluetooth/bt_hcicore.h @@ -1,5 +1,5 @@ /**************************************************************************** - * wireless/bluetooth/bt_att.c + * wireless/bluetooth/bt_hdicore.h * HCI core Bluetooth handling. * * Copyright (C) 2018 Gregory Nutt. All rights reserved. @@ -139,6 +139,16 @@ struct bt_dev_s FAR const struct bt_driver_s *dev; }; +/* Connection callback structure */ + +struct bt_conn_s; /* Forward reference */ +struct bt_conn_cb_s +{ + CODE void (*connected)(FAR struct bt_conn_s *conn); + CODE void (*disconnected)(FAR struct bt_conn_s *conn); + FAR struct bt_conn_cb_s *next; +}; + /**************************************************************************** * Name: bt_le_scan_cb_t * @@ -227,11 +237,40 @@ static inline bool bt_addr_le_is_identity(FAR const bt_addr_le_t *addr) * Public Function Prototypes ****************************************************************************/ +struct bt_eir_s; /* Forward reference */ + +/**************************************************************************** + * Name: bt_initialize + * + * Description: + * Initialize Bluetooth. Must be the called before anything else. + * + * Returned Value: + * Zero on success or (negative) error code otherwise. + * + ****************************************************************************/ + +int bt_initialize(void); + +/**************************************************************************** + * Name: bt_hci_cmd_create + * + * Description: + * Allocate and initialize a buffer for a command + * + * Returned Value: + * A reference to the allocated buffer. NULL could possibly be returned + * on any failure to allocate. + * + ****************************************************************************/ + FAR struct bt_buf_s *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len); + +/* Send HCI commands */ + int bt_hci_cmd_send(uint16_t opcode, FAR struct bt_buf_s *buf); int bt_hci_cmd_send_sync(uint16_t opcode, FAR struct bt_buf_s *buf, FAR struct bt_buf_s **rsp); -int bt_le_scan_update(void); /* The helper is only safe to be called from internal kernel threads as it's * not multi-threading safe @@ -308,4 +347,35 @@ int bt_start_scanning(uint8_t filter_dups, bt_le_scan_cb_t cb); int bt_stop_scanning(void); +/**************************************************************************** + * Name: bt_le_scan_update + * + * Description: + * Used to determine whether to start scan and which scan type should be + * used. + * + * Returned Value: + * Zero on success or error code otherwise, positive in case + * of protocol error or negative (POSIX) in case of stack internal error + * + ****************************************************************************/ + +int bt_le_scan_update(void); + +/**************************************************************************** + * Name: bt_conn_cb_register + * + * Description: + * Register callbacks to monitor the state of connections. + * + * Input Parameters: + * cb - Instance of the callback structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +void bt_conn_cb_register(FAR struct bt_conn_cb_s *cb); + #endif /* __WIRELESS_BLUETOOTH_BT_HDICORE_H */ diff --git a/wireless/bluetooth/bt_ioctl.c b/wireless/bluetooth/bt_ioctl.c index d72a1eb1289..bc4a48a85c4 100644 --- a/wireless/bluetooth/bt_ioctl.c +++ b/wireless/bluetooth/bt_ioctl.c @@ -62,7 +62,7 @@ /* This structure encapsulates all globals used by the IOCTL logic */ -struct bt_scanstate_s +struct btnet_scanstate_s { sem_t bs_exclsem; /* Manages exclusive access */ bool bs_scanning; /* True: Scanning in progress */ @@ -80,14 +80,14 @@ struct bt_scanstate_s * maintain the scan state as a global. */ -static struct bt_scanstate_s g_scanstate; +static struct btnet_scanstate_s g_scanstate; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: bt_scan_callback + * Name: btnet_scan_callback * * Description: * This is an HCI callback function. HCI provides scan result data via @@ -102,9 +102,9 @@ static struct bt_scanstate_s g_scanstate; * ****************************************************************************/ -static void bt_scan_callback(FAR const bt_addr_le_t *addr, int8_t rssi, - uint8_t adv_type, FAR const uint8_t *adv_data, - uint8_t len) +static void btnet_scan_callback(FAR const bt_addr_le_t *addr, int8_t rssi, + uint8_t adv_type, FAR const uint8_t *adv_data, + uint8_t len) { FAR struct bt_scanresponse_s *rsp; uint8_t nexttail; @@ -174,7 +174,7 @@ static void bt_scan_callback(FAR const bt_addr_le_t *addr, int8_t rssi, } /**************************************************************************** - * Name: bt_scan_result + * Name: btnet_scan_result * * Description: * This is an HCI callback function. HCI provides scan result data via @@ -189,7 +189,7 @@ static void bt_scan_callback(FAR const bt_addr_le_t *addr, int8_t rssi, * ****************************************************************************/ -static int bt_scan_result(FAR struct bt_scanresult_s *result) +static int btnet_scan_result(FAR struct bt_scanresult_s *result) { uint8_t head; uint8_t tail; @@ -248,7 +248,7 @@ static int bt_scan_result(FAR struct bt_scanresult_s *result) ****************************************************************************/ /**************************************************************************** - * Name: bt_ioctl + * Name: btnet_ioctl * * Description: * Handle network IOCTL commands directed to this device. @@ -263,7 +263,7 @@ static int bt_scan_result(FAR struct bt_scanresult_s *result) * ****************************************************************************/ -int bt_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg) +int btnet_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg) { int ret; @@ -338,7 +338,7 @@ int bt_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg) g_scanstate.bs_head = 0; g_scanstate.bs_tail = 0; - ret = bt_start_scanning(dup_enable, bt_scan_callback); + ret = bt_start_scanning(dup_enable, btnet_scan_callback); wlinfo("Start scan: %d\n", ret); if (ret < 0) @@ -370,7 +370,7 @@ int bt_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg) } else { - ret = bt_scan_result(result); + ret = btnet_scan_result(result); wlinfo("Get scan results: %d\n", ret); } } diff --git a/wireless/bluetooth/bt_ioctl.h b/wireless/bluetooth/bt_ioctl.h index c53be4b061e..a98c6570e39 100644 --- a/wireless/bluetooth/bt_ioctl.h +++ b/wireless/bluetooth/bt_ioctl.h @@ -52,7 +52,7 @@ ****************************************************************************/ /**************************************************************************** - * Name: bt_ioctl + * Name: btnet_ioctl * * Description: * Handle network IOCTL commands directed to this device. @@ -68,6 +68,6 @@ ****************************************************************************/ struct net_driver_s; /* Forward reference */ -int bt_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg); +int btnet_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg); #endif /* __WIRELESS_BLUETOOTH_BT_IOCTL_H */ diff --git a/wireless/bluetooth/bt_netdev.c b/wireless/bluetooth/bt_netdev.c new file mode 100644 index 00000000000..6dd364702c1 --- /dev/null +++ b/wireless/bluetooth/bt_netdev.c @@ -0,0 +1,1009 @@ +/**************************************************************************** + * wireless/bluetooth/bt_netdev.c + * Network stack interface + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bt_hcicore.h" +#include "bt_ioctl.h" + +#if defined(CONFIG_NET_6LOWPAN) || defined(CONFIG_NET_BLUETOOTH) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* If processing is not done at the interrupt level, then work queue support + * is required. + */ + +#if !defined(CONFIG_SCHED_WORKQUEUE) +# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE) +#endif + +/* Frame size */ + +#if defined(CONFIG_NET_BLUETOOTH_FRAMELEN) +# define MACNET_FRAMELEN CONFIG_NET_BLUETOOTH_FRAMELEN +#else +# define MACNET_FRAMELEN BLUETOOTH_MAX_PHY_PACKET_SIZE +#endif + +/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */ + +#define TXPOLL_WDDELAY (1*CLK_TCK) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This is our private version of the MAC callback structure */ + +struct btnet_callback_s +{ + /* This holds the information visible to the MAC layer */ + + FAR struct btnet_driver_s *bc_priv; /* Our priv data */ +}; + +/* The btnet_driver_s encapsulates all state information for a single + * Bluetooth device interface. + */ + +struct btnet_driver_s +{ + /* This holds the information visible to the NuttX network */ + + struct radio_driver_s bd_dev; /* Interface understood by the network */ + /* Cast compatible with struct btnet_driver_s */ + + /* For internal use by this driver */ + + sem_t bd_exclsem; /* Exclusive access to struct */ + bool bd_bifup; /* true:ifup false:ifdown */ + WDOG_ID bd_txpoll; /* TX poll timer */ + struct work_s bd_pollwork; /* Defer poll work to the work queue */ + FAR struct bt_conn_cb_s bd_hcicb; /* Connection status callbacks */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Utility functions ********************************************************/ + +static int btnet_advertise(FAR struct net_driver_s *dev); +static inline void btnet_netmask(FAR struct net_driver_s *dev); + +/* Bluetooth callback functions ***************************************/ + +static int btnet_rxframe(FAR struct btnet_driver_s *maccb, + FAR struct bluetooth_frame_meta_s *meta); +static void btnet_connected(FAR struct bt_conn_s *conn); +static void btnet_disconnected(FAR struct bt_conn_s *conn); + +/* Network interface support ************************************************/ +/* Common TX logic */ + +static int btnet_txpoll_callback(FAR struct net_driver_s *dev); +static void btnet_txpoll_work(FAR void *arg); +static void btnet_txpoll_expiry(int argc, wdparm_t arg, ...); + +/* NuttX callback functions */ + +static int btnet_ifup(FAR struct net_driver_s *dev); +static int btnet_ifdown(FAR struct net_driver_s *dev); + +static void btnet_txavail_work(FAR void *arg); +static int btnet_txavail(FAR struct net_driver_s *dev); + +#ifdef CONFIG_NET_IGMP +static int btnet_addmac(FAR struct net_driver_s *dev, + FAR const uint8_t *mac); +static int btnet_rmmac(FAR struct net_driver_s *dev, + FAR const uint8_t *mac); +#endif +static int btnet_get_mhrlen(FAR struct radio_driver_s *netdev, + FAR const void *meta); +static int btnet_req_data(FAR struct radio_driver_s *netdev, + FAR const void *meta, FAR struct iob_s *framelist); +static int btnet_properties(FAR struct radio_driver_s *netdev, + FAR struct radiodev_properties_s *properties); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_NET_6LOWPAN +static struct sixlowpan_reassbuf_s g_iobuffer; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: btnet_advertise + * + * Description: + * Advertise the MAC and IPv6 address for this node. + * + * Creates a MAC-based IP address from the 6-byte address address assigned + * to the device. + * + * 128 112 96 80 64 48 32 16 + * ---- ---- ---- ---- ---- ---- ---- ---- + * fe80 0000 0000 0000 0200 xxxx xxxx xxxx + * + ****************************************************************************/ + +static int btnet_advertise(FAR struct net_driver_s *dev) +{ + FAR uint8_t *addr; + + DEBUGASSERT(dev != NULL && dev->d_private != NULL); + + /* Get the 6-byte local address from the device */ +#warning Missing logic + + /* Set the MAC address using that address */ + + BLUETOOTH_ADDRCOPY(dev->d_mac.radio.nv_addr, addr); + dev->d_mac.radio.nv_addrlen = BLUETOOTH_ADDRSIZE; + +#ifdef CONFIG_NET_IPv6 + /* Set the IP address based on the 6-byte address */ + + dev->d_ipv6addr[0] = HTONS(0xfe80); + dev->d_ipv6addr[1] = 0; + dev->d_ipv6addr[2] = 0; + dev->d_ipv6addr[3] = 0x200; + dev->d_ipv6addr[5] = (uint16_t)addr[0] << 8 | (uint16_t)addr[1]; + dev->d_ipv6addr[6] = (uint16_t)addr[2] << 8 | (uint16_t)addr[3]; + dev->d_ipv6addr[7] = (uint16_t)addr[4] << 8 | (uint16_t)addr[5]; +#endif + return OK; +} + +/**************************************************************************** + * Name: btnet_netmask + * + * Description: + * Create a netmask of a MAC-based IP address which is based on the 6-byte + * Bluetooth address. + * + * 128 112 96 80 64 48 32 16 + * ---- ---- ---- ---- ---- ---- ---- ---- + * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx + * + ****************************************************************************/ + +static inline void btnet_netmask(FAR struct net_driver_s *dev) +{ +#ifdef CONFIG_NET_IPv6 + dev->d_ipv6netmask[0] = 0xffff; + dev->d_ipv6netmask[1] = 0xffff; + dev->d_ipv6netmask[2] = 0xffff; + dev->d_ipv6netmask[3] = 0xffff; + dev->d_ipv6netmask[4] = 0; + dev->d_ipv6netmask[5] = 0; + dev->d_ipv6netmask[6] = 0; + dev->d_ipv6netmask[7] = 0; +#endif +} + +/**************************************************************************** + * Name: btnet_rxframe + * + * Description: + * Handle received frames forward by the Bluetooth stack. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. On success, the meta data and its contained iob will be + * freed. The meta data will be intact if this function returns a + * failure. + * + ****************************************************************************/ + +static int btnet_rxframe(FAR struct btnet_driver_s *priv, + FAR struct bluetooth_frame_meta_s *meta) +{ + FAR struct iob_s *iob; + int ret; + + DEBUGASSERT(priv != NULL && meta != NULL); + + /* Ignore the frame if the network is not up */ + + if (!priv->bd_bifup) + { + wlwarn("WARNING: Dropped... Network is down\n"); + return -ENETDOWN; + } + + /* Transfer the frame to the network logic */ +#warning Missing logic + + net_lock(); + +#ifdef CONFIG_NET_BLUETOOTH + /* Invoke the PF_BLUETOOTH tap first. If the frame matches + * with a connected PF_BLUETOOTH socket, it will take the + * frame and return success. + */ + + ret = bluetooth_input(&priv->bd_dev, iob, (FAR void *)meta); + if (ret < 0) +#endif +#ifdef CONFIG_NET_6LOWPAN + { + /* If the frame is not a 6LoWPAN frame, then return an error. The + * first byte following the MAC head at the io_offset should be a + * valid IPHC header. + */ + + if ((iob->io_data[iob->io_offset] & SIXLOWPAN_DISPATCH_NALP_MASK) == + SIXLOWPAN_DISPATCH_NALP) + { + wlwarn("WARNING: Dropped... Not a 6LoWPAN frame: %02x\n", + iob->io_data[iob->io_offset]); + ret = -EINVAL; + } + else + { + /* Make sure the our single packet buffer is attached */ + + priv->bd_dev.r_dev.d_buf = g_iobuffer.rb_buf; + + /* And give the packet to 6LoWPAN */ + + ret = sixlowpan_input(&priv->bd_dev, iob, (FAR void *)meta); + } + } + + if (ret < 0) +#endif + { + net_unlock(); + return ret; + } + + /* Increment statistics */ + + NETDEV_RXPACKETS(&priv->bd_dev.r_dev); + NETDEV_RXIPV6(&priv->bd_dev.r_dev); + + net_unlock(); + return OK; +} + +/**************************************************************************** + * Name: btnet_txpoll_callback + * + * Description: + * There are callbacks that are involved by the core HCI layer when a + * change is detected in the connection status. + * + * Input Parameters: + * conn - The connection whose + * + * Returned Value: + * None + * + * Assumptions: + * No assumption should be made about the thread of execution that these + * are called from + * + ****************************************************************************/ + +static void btnet_connected(FAR struct bt_conn_s *conn) +{ +#warning Missing logic +} + +static void btnet_disconnected(FAR struct bt_conn_s *conn) +{ +#warning Missing logic +} + +/**************************************************************************** + * Name: btnet_txpoll_callback + * + * Description: + * The transmitter is available, check if the network has any outgoing + * packets ready to send. This is a callback from devif_poll(). + * devif_poll() may be called: + * + * 1. When the preceding TX packet send is complete, + * 2. When the preceding TX packet send timesout and the interface is reset + * 3. During normal TX polling + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * OK on success; a negated errno on failure + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static int btnet_txpoll_callback(FAR struct net_driver_s *dev) +{ + /* If zero is returned, the polling will continue until all connections have + * been examined. + */ + + return 0; +} + +/**************************************************************************** + * Name: btnet_txpoll_work + * + * Description: + * Perform periodic polling from the worker thread + * + * Input Parameters: + * arg - The argument passed when work_queue() as called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * The network is locked. + * + ****************************************************************************/ + +static void btnet_txpoll_work(FAR void *arg) +{ + FAR struct btnet_driver_s *priv = (FAR struct btnet_driver_s *)arg; + + /* Lock the network and serialize driver operations if necessary. + * NOTE: Serialization is only required in the case where the driver work + * is performed on an LP worker thread and where more than one LP worker + * thread has been configured. + */ + + net_lock(); + +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->bd_dev.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + + /* Then perform the poll */ + + (void)devif_timer(&priv->bd_dev.r_dev, btnet_txpoll_callback); + + /* Setup the watchdog poll timer again */ + + (void)wd_start(priv->bd_txpoll, TXPOLL_WDDELAY, btnet_txpoll_expiry, 1, + (wdparm_t)priv); + net_unlock(); +} + +/**************************************************************************** + * Name: btnet_txpoll_expiry + * + * Description: + * Periodic timer handler. Called from the timer interrupt handler. + * + * Input Parameters: + * argc - The number of available arguments + * arg - The first argument + * + * Returned Value: + * None + * + * Assumptions: + * Global interrupts are disabled by the watchdog logic. + * + ****************************************************************************/ + +static void btnet_txpoll_expiry(int argc, wdparm_t arg, ...) +{ + FAR struct btnet_driver_s *priv = (FAR struct btnet_driver_s *)arg; + + /* Schedule to perform the interrupt processing on the worker thread. */ + + work_queue(LPWORK, &priv->bd_pollwork, btnet_txpoll_work, priv, 0); +} + +/**************************************************************************** + * Name: btnet_ifup + * + * Description: + * NuttX Callback: Bring up the Bluetooth interface when an IP address + * is provided + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int btnet_ifup(FAR struct net_driver_s *dev) +{ + FAR struct btnet_driver_s *priv = + (FAR struct btnet_driver_s *)dev->d_private; + int ret; + + /* Set the IP address based on the addressing assigned to the node */ + + ret = btnet_advertise(dev); + if (ret >= 0) + { +#ifdef CONFIG_NET_IPv6 + wlinfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2], + dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5], + dev->d_ipv6addr[6], dev->d_ipv6addr[7]); + +#ifdef CONFIG_NET_6LOWPAN_EXTENDEDADDR + wlinfo(" Node: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->d_mac.radio.nv_addr[0], dev->d_mac.radio.nv_addr[1], + dev->d_mac.radio.nv_addr[2], dev->d_mac.radio.nv_addr[3], + dev->d_mac.radio.nv_addr[4], dev->d_mac.radio.nv_addr[5], + dev->d_mac.radio.nv_addr[6], dev->d_mac.radio.nv_addr[7]); +#else + wlinfo(" Node: %02x:%02x\n", + dev->d_mac.radio.nv_addr[0], dev->d_mac.radio.nv_addr[1]); +#endif +#else + if (dev->d_mac.radio.nv_addrlen == 8) + { + ninfo("Bringing up: Node: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x PANID=%02x:%02x\n", + dev->d_mac.radio.nv_addr[0], dev->d_mac.radio.nv_addr[1], + dev->d_mac.radio.nv_addr[2], dev->d_mac.radio.nv_addr[3], + dev->d_mac.radio.nv_addr[4], dev->d_mac.radio.nv_addr[5], + dev->d_mac.radio.nv_addr[6], dev->d_mac.radio.nv_addr[7], + priv->lo_panid[0], priv->lo_panid[1]); + } + else if (dev->d_mac.radio.nv_addrlen == 2) + { + ninfo("Bringing up: Node: %02x:%02x PANID=%02x:%02x\n", + dev->d_mac.radio.nv_addr[0], dev->d_mac.radio.nv_addr[1], + priv->lo_panid[0], priv->lo_panid[1]); + } + else + { + nerr("ERROR: No address assigned\n"); + } +#endif + + /* Set and activate a timer process */ + + (void)wd_start(priv->bd_txpoll, TXPOLL_WDDELAY, btnet_txpoll_expiry, + 1, (wdparm_t)priv); + + /* The interface is now up */ + + priv->bd_bifup = true; + ret = OK; + } + + return ret; +} + +/**************************************************************************** + * Name: btnet_ifdown + * + * Description: + * NuttX Callback: Stop the interface. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static int btnet_ifdown(FAR struct net_driver_s *dev) +{ + FAR struct btnet_driver_s *priv = (FAR struct btnet_driver_s *)dev->d_private; + irqstate_t flags; + + /* Disable interruption */ + + flags = enter_critical_section(); + + /* Cancel the TX poll timer and TX timeout timers */ + + wd_cancel(priv->bd_txpoll); + + /* Put the EMAC in its reset, non-operational state. This should be + * a known configuration that will guarantee the btnet_ifup() always + * successfully brings the interface back up. + */ + + /* Mark the device "down" */ + + priv->bd_bifup = false; + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: btnet_txavail_work + * + * Description: + * Perform an out-of-cycle poll on the worker thread. + * + * Input Parameters: + * arg - Reference to the NuttX driver state structure (cast to void*) + * + * Returned Value: + * None + * + * Assumptions: + * Called on the higher priority worker thread. + * + ****************************************************************************/ + +static void btnet_txavail_work(FAR void *arg) +{ + FAR struct btnet_driver_s *priv = (FAR struct btnet_driver_s *)arg; + + wlinfo("ifup=%u\n", priv->bd_bifup); + + /* Lock the network and serialize driver operations if necessary. + * NOTE: Serialization is only required in the case where the driver work + * is performed on an LP worker thread and where more than one LP worker + * thread has been configured. + */ + + net_lock(); + + /* Ignore the notification if the interface is not yet up */ + + if (priv->bd_bifup) + { +#ifdef CONFIG_NET_6LOWPAN + /* Make sure the our single packet buffer is attached */ + + priv->bd_dev.r_dev.d_buf = g_iobuffer.rb_buf; +#endif + + /* Then poll the network for new XMIT data */ + + (void)devif_poll(&priv->bd_dev.r_dev, btnet_txpoll_callback); + } + + net_unlock(); +} + +/**************************************************************************** + * Name: btnet_txavail + * + * Description: + * Driver callback invoked when new TX data is available. This is a + * stimulus perform an out-of-cycle poll and, thereby, reduce the TX + * latency. + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called in normal user mode + * + ****************************************************************************/ + +static int btnet_txavail(FAR struct net_driver_s *dev) +{ + FAR struct btnet_driver_s *priv = (FAR struct btnet_driver_s *)dev->d_private; + + wlinfo("Available=%u\n", work_available(&priv->bd_pollwork)); + + /* Is our single work structure available? It may not be if there are + * pending interrupt actions and we will have to ignore the Tx + * availability action. + */ + + if (work_available(&priv->bd_pollwork)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(LPWORK, &priv->bd_pollwork, btnet_txavail_work, priv, 0); + } + + return OK; +} + +/**************************************************************************** + * Name: btnet_addmac + * + * Description: + * NuttX Callback: Add the specified MAC address to the hardware multicast + * address filtering + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be added + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IGMP +static int btnet_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) +{ + /* Add the MAC address to the hardware multicast routing table. Not used + * with Bluetooth. + */ + + return -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: btnet_rmmac + * + * Description: + * NuttX Callback: Remove the specified MAC address from the hardware multicast + * address filtering + * + * Input Parameters: + * dev - Reference to the NuttX driver state structure + * mac - The MAC address to be removed + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_IGMP +static int btnet_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac) +{ + /* Remove the MAC address from the hardware multicast routing table Not used + * with Bluetooth. + */ + + return -ENOSYS; +} +#endif + +/**************************************************************************** + * Name: btnet_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. + * + * Input Parameters: + * netdev - The networkd device that will mediate the MAC interface + * meta - Obfuscated meta-data structure needed to create the radio + * MAC header + * + * Returned Value: + * A non-negative MAC header length is returned on success; a negated + * errno value is returned on any failure. + * + ****************************************************************************/ + +static int btnet_get_mhrlen(FAR struct radio_driver_s *netdev, + FAR const void *meta) +{ + return BLUETOOTH_HDRLEN; +} + +/**************************************************************************** + * Name: btnet_req_data + * + * Description: + * Requests the transfer of a list of frames to the MAC. + * + * Input Parameters: + * netdev - The networkd device that will mediate the MAC interface + * meta - Obfuscated metadata structure needed to create the radio + * MAC header + * framelist - Head of a list of frames to be transferred. + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int btnet_req_data(FAR struct radio_driver_s *netdev, + FAR const void *meta, FAR struct iob_s *framelist) +{ + FAR struct btnet_driver_s *priv = + (FAR struct btnet_driver_s *)netdev; + FAR const struct bluetooth_frame_meta_s *pktmeta = + (FAR const struct bluetooth_frame_meta_s *)meta; + FAR struct iob_s *iob; + int ret; + + wlinfo("Received framelist\n"); + + DEBUGASSERT(priv != NULL && pktmeta != NULL && framelist != NULL); + + /* Add the incoming list of frames to the MAC's outgoing queue */ + + for (iob = framelist; iob != NULL; iob = framelist) + { + /* Increment statistics */ + + NETDEV_TXPACKETS(&priv->bd_dev.r_dev); + + /* Remove the IOB from the queue */ + + framelist = iob->io_flink; + iob->io_flink = NULL; + + /* Transfer the frame to the MAC. */ + + do + { + ret = btnet_req_data(netdev, pktmeta, iob); + } + while (ret == -EINTR); + + if (ret < 0) + { + wlerr("ERROR: btnet_req_data failed: %d\n", ret); + + iob_free(iob); + for (iob = framelist; iob != NULL; iob = framelist) + { + /* Remove the IOB from the queue and free */ + + framelist = iob->io_flink; + iob_free(iob); + } + + NETDEV_TXERRORS(&priv->bd_dev.r_dev); + return ret; + } + + NETDEV_TXDONE(&priv->bd_dev.r_dev); + } + + return OK; +} + +/**************************************************************************** + * Name: btnet_properties + * + * Description: + * Different packet radios may have different properties. If there are + * multiple packet radios, then those properties have to be queried at + * run time. This information is provided to the 6LoWPAN network via the + * following structure. + * + * Input Parameters: + * netdev - The network device to be queried + * properties - Location where radio properties will be returned. + * + * Returned Value: + * Zero (OK) returned on success; a negated errno value is returned on + * any failure. + * + ****************************************************************************/ + +static int btnet_properties(FAR struct radio_driver_s *netdev, + FAR struct radiodev_properties_s *properties) +{ + DEBUGASSERT(netdev != NULL && properties != NULL); + memset(properties, 0, sizeof(struct radiodev_properties_s)); + + /* General */ + + properties->sp_addrlen = BLUETOOTH_ADDRSIZE; /* Length of an address */ + properties->sp_framelen = MACNET_FRAMELEN; /* Fixed frame length */ + + /* Multicast address -- not supported */ + + properties->sp_mcast.nv_addrlen = BLUETOOTH_ADDRSIZE; + memset(properties->sp_mcast.nv_addr, 0xff, RADIO_MAX_ADDRLEN); + + /* Broadcast address -- not supported */ + + properties->sp_bcast.nv_addrlen = BLUETOOTH_ADDRSIZE; + memset(properties->sp_mcast.nv_addr, 0xff, RADIO_MAX_ADDRLEN); + +#ifdef CONFIG_NET_STARPOINT + /* Star hub node address -- not supported. */ + + properties->sp_hubnode.nv_addrlen = BLUETOOTH_ADDRSIZE; + memset(properties->sp_hubnode.nv_addr, RADIO_MAX_ADDRLEN); +#endif + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bt_netdev_register + * + * Description: + * Register a network driver to access the Bluetooth MAC layer using a + * 6LoWPAN IPv6 or AF_BLUETOOTH socket. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ + +int bt_netdev_register(void) +{ + FAR struct btnet_driver_s *priv; + FAR struct radio_driver_s *radio; + FAR struct net_driver_s *dev; + FAR struct bt_conn_cb_s *hcicb; + int ret; + + /* Get the interface structure associated with this interface number. */ + + priv = (FAR struct btnet_driver_s *) + kmm_zalloc(sizeof(struct btnet_driver_s)); + + if (priv == NULL) + { + nerr("ERROR: Failed to allocate the device structure\n"); + return -ENOMEM; + } + + /* Initialize the driver structure */ + + radio = &priv->bd_dev; + dev = &radio->r_dev; + dev->d_ifup = btnet_ifup; /* I/F up (new IP address) callback */ + dev->d_ifdown = btnet_ifdown; /* I/F down callback */ + dev->d_txavail = btnet_txavail; /* New TX data callback */ +#ifdef CONFIG_NET_IGMP + dev->d_addmac = btnet_addmac; /* Add multicast MAC address */ + dev->d_rmmac = btnet_rmmac; /* Remove multicast MAC address */ +#endif + #ifdef CONFIG_NETDEV_IOCTL + dev->d_ioctl = btnet_ioctl; /* Handle network IOCTL commands */ +#endif + dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ + + /* Connection status change callbacks */ + + hcicb = &priv->bd_hcicb; + hcicb->connected = btnet_connected; + hcicb->disconnected = btnet_disconnected; + + bt_conn_cb_register(hcicb); + + /* REVISIT: When and where to we register to get frames on a connection? */ +#warning Missing logic + + /* Create a watchdog for timing polling for and timing of transmissions */ + + priv->bd_txpoll = wd_create(); /* Create periodic poll timer */ + + /* Setup a locking semaphore for exclusive device driver access */ + + nxsem_init(&priv->bd_exclsem, 0, 1); + + DEBUGASSERT(priv->bd_txpoll != NULL); + + /* Set the network mask. */ + + btnet_netmask(dev); + + /* Initialize the Network frame-related callbacks */ + + radio->r_get_mhrlen = btnet_get_mhrlen; /* Get MAC header length */ + radio->r_req_data = btnet_req_data; /* Enqueue frame for transmission */ + radio->r_properties = btnet_properties; /* Return radio properties */ + + /* Initialize the Bluetooth stack */ + + ret = bt_initialize(); + if (ret < 0) + { + nerr("ERROR: Failed to initialize Bluetooth: %d\n", ret); + goto errout; + } + + /* Put the interface in the down state. */ + + btnet_ifdown(dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + ret = netdev_register(&priv->bd_dev.r_dev, NET_LL_BLUETOOTH); + if (ret >= 0) + { + return OK; + } + +errout: + /* Release wdog timers */ + + wd_delete(priv->bd_txpoll); + + /* Free memory and return the error */ + + kmm_free(priv); + return ret; +} + +#endif /* CONFIG_NET && CONFIG_NET_skeleton */ diff --git a/wireless/bluetooth/bt_smp.h b/wireless/bluetooth/bt_smp.h index 80ece113bdc..317cff08dbd 100644 --- a/wireless/bluetooth/bt_smp.h +++ b/wireless/bluetooth/bt_smp.h @@ -48,7 +48,7 @@ #include -#include +#include "bt_conn.h" /**************************************************************************** * Pre-processor Definitions