12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424 |
- /****************************************************************************
- * wireless/bluetooth/bt_netdev.c
- * Network stack interface
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
- /****************************************************************************
- * Included Files
- ****************************************************************************/
- #include <nuttx/config.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <time.h>
- #include <string.h>
- #include <errno.h>
- #include <assert.h>
- #include <debug.h>
- #include <arpa/inet.h>
- #include <nuttx/arch.h>
- #include <nuttx/irq.h>
- #include <nuttx/kmalloc.h>
- #include <nuttx/signal.h>
- #include <nuttx/wdog.h>
- #include <nuttx/wqueue.h>
- #include <nuttx/mm/iob.h>
- #include <nuttx/net/arp.h>
- #include <nuttx/net/netdev.h>
- #include <nuttx/net/radiodev.h>
- #include <nuttx/net/bluetooth.h>
- #include <nuttx/net/sixlowpan.h>
- #include <nuttx/wireless/bluetooth/bt_core.h>
- #include <netpacket/bluetooth.h>
- #include "bt_hcicore.h"
- #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
- #include "bt_l2cap.h"
- #include "bt_conn.h"
- #endif
- #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 BLUETOOTH_MAX_FRAMELEN > CONFIG_IOB_BUFSIZE
- # error CONFIG_IOB_BUFSIZE to small for max Bluetooth frame
- #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 */
- struct wdog_s bd_txpoll; /* TX poll timer */
- struct work_s bd_pollwork; /* Defer poll work to the work queue */
- #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
- struct bt_conn_cb_s bd_hcicb; /* HCI connection status callbacks */
- struct bt_l2cap_chan_s bd_l2capcb; /* L2CAP status callbacks */
- #else
- struct bt_hci_cb_s bd_hcicb; /* HCI RAW packet callbacks */
- #endif
- };
- /****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
- /* Utility functions ********************************************************/
- static int btnet_advertise(FAR struct net_driver_s *netdev);
- static inline void btnet_netmask(FAR struct net_driver_s *netdev);
- /* Bluetooth callback functions *********************************************/
- #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
- /* L2CAP callbacks */
- static void btnet_l2cap_connected(FAR struct bt_conn_s *conn,
- FAR void *context, uint16_t cid);
- static void btnet_l2cap_disconnected(FAR struct bt_conn_s *conn,
- FAR void *context, uint16_t cid);
- static void btnet_l2cap_encrypt_change(FAR struct bt_conn_s *conn,
- FAR void *context, uint16_t cid);
- static void btnet_l2cap_receive(FAR struct bt_conn_s *conn,
- FAR struct bt_buf_s *buf, FAR void *context, uint16_t cid);
- /* HCI callbacks */
- static void btnet_hci_connected(FAR struct bt_conn_s *conn,
- FAR void *context);
- static void btnet_hci_disconnected(FAR struct bt_conn_s *conn,
- FAR void *context);
- #else
- static void btnet_hci_received(FAR struct bt_buf_s *buf, FAR void *context);
- #endif
- /* Network interface support ************************************************/
- /* Common TX logic */
- static int btnet_txpoll_callback(FAR struct net_driver_s *netdev);
- static void btnet_txpoll_work(FAR void *arg);
- static void btnet_txpoll_expiry(wdparm_t arg);
- /* NuttX callback functions */
- static int btnet_ifup(FAR struct net_driver_s *netdev);
- static int btnet_ifdown(FAR struct net_driver_s *netdev);
- static void btnet_txavail_work(FAR void *arg);
- static int btnet_txavail(FAR struct net_driver_s *netdev);
- #ifdef CONFIG_NET_MCASTGROUP
- static int btnet_addmac(FAR struct net_driver_s *netdev,
- FAR const uint8_t *mac);
- static int btnet_rmmac(FAR struct net_driver_s *netdev,
- 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);
- #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
- static int btnet_req_l2cap_data(FAR struct btnet_driver_s *priv,
- FAR struct bluetooth_frame_meta_s *meta,
- FAR struct iob_s *framelist);
- #endif
- static int btnet_req_hci_data(FAR struct btnet_driver_s *priv,
- FAR struct bluetooth_frame_meta_s *meta,
- FAR struct iob_s *framelist);
- /****************************************************************************
- * 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 *netdev)
- {
- FAR uint8_t *addr;
- DEBUGASSERT(netdev != NULL && netdev->d_private != NULL);
- /* Get the 6-byte local address from the device.
- *
- * REVISIT: The use of the g_btdev global restricts the implementation to
- * a single Bluetooth device.
- */
- addr = g_btdev.bdaddr.val;
- /* Set the MAC address using 6-byte local address from the device. */
- BLUETOOTH_ADDRCOPY(netdev->d_mac.radio.nv_addr, addr);
- netdev->d_mac.radio.nv_addrlen = BLUETOOTH_ADDRSIZE;
- #ifdef CONFIG_NET_IPv6
- /* Set the IP address based on the 6-byte address */
- netdev->d_ipv6addr[0] = HTONS(0xfe80);
- netdev->d_ipv6addr[1] = 0;
- netdev->d_ipv6addr[2] = 0;
- netdev->d_ipv6addr[3] = 0;
- netdev->d_ipv6addr[4] = HTONS(0x0200);
- netdev->d_ipv6addr[5] = (uint16_t)addr[0] << 8 | (uint16_t)addr[1];
- netdev->d_ipv6addr[6] = (uint16_t)addr[2] << 8 | (uint16_t)addr[3];
- netdev->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 *netdev)
- {
- #ifdef CONFIG_NET_IPv6
- netdev->d_ipv6netmask[0] = 0xffff;
- netdev->d_ipv6netmask[1] = 0xffff;
- netdev->d_ipv6netmask[2] = 0xffff;
- netdev->d_ipv6netmask[3] = 0xffff;
- netdev->d_ipv6netmask[4] = 0;
- netdev->d_ipv6netmask[5] = 0;
- netdev->d_ipv6netmask[6] = 0;
- netdev->d_ipv6netmask[7] = 0;
- #endif
- }
- #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
- /****************************************************************************
- * Name: btnet_hci_connect/disconnect/encrypt_change
- *
- * Description:
- * There are callbacks that are involved by the core HCI layer when a
- * change is detected in the connection status or encryption.
- *
- * 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_l2cap_connected(FAR struct bt_conn_s *conn,
- FAR void *context, uint16_t cid)
- {
- wlinfo("Connected\n");
- #warning Missing logic
- }
- static void btnet_l2cap_disconnected(FAR struct bt_conn_s *conn,
- FAR void *context, uint16_t cid)
- {
- wlinfo("Disconnected\n");
- #warning Missing logic
- }
- static void btnet_l2cap_encrypt_change(FAR struct bt_conn_s *conn,
- FAR void *context, uint16_t cid)
- {
- wlinfo("Encryption change\n");
- #warning Missing logic
- }
- /****************************************************************************
- * Name: btnet_l2cap_receive
- *
- * Description:
- * Handle received frames forward by the Bluetooth L2CAP layer.
- *
- * 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 void btnet_l2cap_receive(FAR struct bt_conn_s *conn,
- FAR struct bt_buf_s *buf,
- FAR void *context, uint16_t cid)
- {
- FAR struct btnet_driver_s *priv;
- FAR struct iob_s *frame;
- struct bluetooth_frame_meta_s meta;
- int ret = -ENODEV;
- wlinfo("Received frame\n");
- DEBUGASSERT(conn != NULL && buf != NULL && buf->frame != NULL &&
- context != NULL && cid < UINT8_MAX);
- /* Detach the IOB frame from the buffer structure */
- frame = buf->frame;
- buf->frame = NULL;
- /* Ignore the frame if the network is not up */
- priv = (FAR struct btnet_driver_s *)context;
- if (!priv->bd_bifup)
- {
- wlwarn("WARNING: Dropped... Network is down\n");
- goto drop;
- }
- /* Make sure that the size/offset data matches the buffer structure data.
- * REVISIT: Wouldn't it be better to just have one copy rather than having
- * to synchronize?
- */
- frame->io_len = buf->len;
- frame->io_pktlen = buf->len;
- frame->io_offset = (unsigned int)
- ((uintptr_t)buf->data - (uintptr_t)frame->io_data);
- DEBUGASSERT(frame->io_len <= CONFIG_IOB_BUFSIZE);
- DEBUGASSERT(frame->io_offset < CONFIG_IOB_BUFSIZE);
- /* Construct the frame meta data.
- * REVISIT: Where do we get the channel number?
- */
- BLUETOOTH_ADDRCOPY(meta.bm_raddr.val, conn->src.val);
- meta.bm_channel = cid;
- /* Transfer the frame to the network 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, frame, (FAR void *)&meta);
- #endif
- #ifdef CONFIG_NET_6LOWPAN
- if (ret < 0)
- {
- /* If the frame is not a 6LoWPAN frame, then thefirst byte 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);
- }
- }
- #endif
- drop:
- /* Handle errors */
- if (ret < 0)
- {
- iob_free(frame, IOBUSER_WIRELESS_BLUETOOTH);
- /* Increment statistics */
- NETDEV_RXDROPPED(&priv->bd_dev.r_dev);
- }
- else
- {
- /* Increment statistics */
- NETDEV_RXPACKETS(&priv->bd_dev.r_dev);
- NETDEV_RXIPV6(&priv->bd_dev.r_dev);
- }
- /* Release our reference on the buffer */
- bt_buf_release(buf);
- net_unlock();
- }
- /****************************************************************************
- * Name: btnet_hci_connect/disconnect
- *
- * 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_hci_connected(FAR struct bt_conn_s *conn,
- FAR void *context)
- {
- wlinfo("Connected\n");
- #warning Missing logic
- }
- static void btnet_hci_disconnected(FAR struct bt_conn_s *conn,
- FAR void *context)
- {
- wlinfo("Disconnected\n");
- #warning Missing logic
- }
- #else
- /****************************************************************************
- * Name: btnet_hci_received
- *
- * Description:
- * This callback is called from the RX queue handling when an HCI
- * packet is received from controller.
- *
- * Input Parameters:
- * buf - The packet
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * No assumption should be made about the thread of execution that these
- * are called from
- *
- ****************************************************************************/
- static void btnet_hci_received(FAR struct bt_buf_s *buf, FAR void *context)
- {
- FAR struct btnet_driver_s *priv;
- FAR struct iob_s *frame;
- struct bluetooth_frame_meta_s meta;
- int ret = -ENODEV;
- wlinfo("Received frame\n");
- DEBUGASSERT(buf != NULL && buf->frame != NULL);
- /* Detach the IOB frame from the buffer structure */
- frame = buf->frame;
- buf->frame = NULL;
- /* Ignore the frame if the network is not up */
- priv = (FAR struct btnet_driver_s *)context;
- if (!priv->bd_bifup)
- {
- wlwarn("WARNING: Dropped... Network is down\n");
- goto drop;
- }
- /* Make sure that the size/offset data matches the buffer structure data. */
- DEBUGASSERT(frame->io_offset == BLUETOOTH_H4_HDRLEN);
- /* Rearrange IOB to consider H4 header */
- frame->io_len = buf->len + frame->io_offset;
- frame->io_pktlen = buf->len + frame->io_offset;
- frame->io_offset = 0;
- DEBUGASSERT(frame->io_len <= CONFIG_IOB_BUFSIZE);
- /* Write H4 header */
- switch (buf->type)
- {
- case BT_EVT:
- frame->io_data[0] = HCI_EVENT_PKT;
- break;
- case BT_ACL_IN:
- frame->io_data[0] = HCI_ACLDATA_PKT;
- break;
- default:
- wlerr("Bad HCI type: %i\n", buf->type);
- goto drop;
- break;
- }
- /* Construct the frame meta data.
- */
- meta.bm_channel = HCI_CHANNEL_RAW;
- meta.bm_proto = BTPROTO_HCI;
- /* Transfer the frame to the network 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, frame, (FAR void *)&meta);
- #endif
- drop:
- /* Handle errors */
- if (ret < 0)
- {
- iob_free(frame, IOBUSER_WIRELESS_BLUETOOTH);
- /* Increment statistics */
- NETDEV_RXDROPPED(&priv->bd_dev.r_dev);
- }
- else
- {
- /* Increment statistics */
- NETDEV_RXPACKETS(&priv->bd_dev.r_dev);
- NETDEV_RXIPV6(&priv->bd_dev.r_dev);
- }
- /* Release our reference on the buffer */
- net_unlock();
- }
- #endif
- /****************************************************************************
- * 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:
- * netdev - 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 *netdev)
- {
- /* 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 */
- devif_timer(&priv->bd_dev.r_dev, TXPOLL_WDDELAY, btnet_txpoll_callback);
- /* Setup the watchdog poll timer again */
- wd_start(&priv->bd_txpoll, TXPOLL_WDDELAY,
- btnet_txpoll_expiry, (wdparm_t)priv);
- net_unlock();
- }
- /****************************************************************************
- * Name: btnet_txpoll_expiry
- *
- * Description:
- * Periodic timer handler. Called from the timer interrupt handler.
- *
- * Input Parameters:
- * arg - The argument
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Global interrupts are disabled by the watchdog logic.
- *
- ****************************************************************************/
- static void btnet_txpoll_expiry(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:
- * netdev - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
- static int btnet_ifup(FAR struct net_driver_s *netdev)
- {
- FAR struct btnet_driver_s *priv =
- (FAR struct btnet_driver_s *)netdev->d_private;
- int ret;
- /* Set the IP address based on the addressing assigned to the node */
- ret = btnet_advertise(netdev);
- if (ret >= 0)
- {
- #ifdef CONFIG_NET_IPv6
- wlinfo("Bringing up: IP %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
- netdev->d_ipv6addr[0], netdev->d_ipv6addr[1],
- netdev->d_ipv6addr[2], netdev->d_ipv6addr[3],
- netdev->d_ipv6addr[4], netdev->d_ipv6addr[5],
- netdev->d_ipv6addr[6], netdev->d_ipv6addr[7]);
- wlinfo(" ADDR %02x:%02x:%02x:%02x:%02x:%02x\n",
- netdev->d_mac.radio.nv_addr[0], netdev->d_mac.radio.nv_addr[1],
- netdev->d_mac.radio.nv_addr[2], netdev->d_mac.radio.nv_addr[3],
- netdev->d_mac.radio.nv_addr[4], netdev->d_mac.radio.nv_addr[5]);
- #else
- wlinfo("Bringing up: %02x:%02x:%02x:%02x:%02x:%02x\n",
- netdev->d_mac.radio.nv_addr[0], netdev->d_mac.radio.nv_addr[1],
- netdev->d_mac.radio.nv_addr[2], netdev->d_mac.radio.nv_addr[3],
- netdev->d_mac.radio.nv_addr[4], netdev->d_mac.radio.nv_addr[5]);
- #endif
- /* Set and activate a timer process */
- wd_start(&priv->bd_txpoll, TXPOLL_WDDELAY,
- btnet_txpoll_expiry, (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:
- * netdev - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
- static int btnet_ifdown(FAR struct net_driver_s *netdev)
- {
- FAR struct btnet_driver_s *priv =
- (FAR struct btnet_driver_s *)netdev->d_private;
- irqstate_t flags;
- /* Disable interruption */
- flags = spin_lock_irqsave(NULL);
- /* 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;
- spin_unlock_irqrestore(NULL, 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 */
- 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:
- * netdev - 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 *netdev)
- {
- FAR struct btnet_driver_s *priv =
- (FAR struct btnet_driver_s *)netdev->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:
- * netdev - Reference to the NuttX driver state structure
- * mac - The MAC address to be added
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
- #ifdef CONFIG_NET_MCASTGROUP
- static int btnet_addmac(FAR struct net_driver_s *netdev,
- 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:
- * netdev - Reference to the NuttX driver state structure
- * mac - The MAC address to be removed
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
- #ifdef CONFIG_NET_MCASTGROUP
- static int btnet_rmmac(FAR struct net_driver_s *netdev,
- 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)
- {
- const struct bluetooth_frame_meta_s *btmeta = meta;
- if (btmeta->bm_proto == BTPROTO_HCI)
- {
- /* the net device only requires the H4 header, the rest is already
- * part of the packet
- */
- return BLUETOOTH_H4_HDRLEN;
- }
- else if (btmeta->bm_proto == BTPROTO_L2CAP)
- {
- /* Report the complete header size, since H4 + ACL + L2CAP header
- * will not be part of the packet
- */
- /* TODO: correct? */
- return BLUETOOTH_MAX_HDRLEN;
- }
- return BLUETOOTH_MAX_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 bluetooth_frame_meta_s *btmeta;
- priv = (FAR struct btnet_driver_s *)netdev;
- btmeta = (FAR struct bluetooth_frame_meta_s *)meta;
- wlinfo("Received framelist\n");
- DEBUGASSERT(priv != NULL && meta != NULL && framelist != NULL);
- if (btmeta->bm_proto == BTPROTO_HCI)
- {
- return btnet_req_hci_data(priv, btmeta, framelist);
- }
- #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
- else if (btmeta->bm_proto == BTPROTO_L2CAP)
- {
- return btnet_req_l2cap_data(priv, btmeta, framelist);
- }
- #endif
- else
- {
- return -EOPNOTSUPP;
- }
- return OK;
- }
- #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
- /****************************************************************************
- * Name: btnet_req_l2cap_data
- *
- * Description:
- * Requests the transfer of a list of L2CAP frames to the MAC.
- *
- * Input Parameters:
- * priv - Bluetooth network device
- * btmeta - Bluetooth frame metadata
- * framelist - Head of a list of L2CAP frames to be transferred.
- *
- * Returned Value:
- * Zero (OK) returned on success; a negated errno value is returned on
- * any failure.
- *
- ****************************************************************************/
- static int btnet_req_l2cap_data(FAR struct btnet_driver_s *priv,
- FAR struct bluetooth_frame_meta_s *btmeta,
- FAR struct iob_s *framelist)
- {
- FAR struct bt_conn_s *conn;
- bt_addr_le_t peer;
- FAR struct iob_s *iob;
- FAR struct bt_buf_s *buf;
- UNUSED(priv);
- /* Create a connection structure for this peer if one does not already
- * exist.
- *
- * Assumptions to REVISIT:
- *
- * 1. Role is Master (see bt_conn_create_le())
- * 2. Address type is BT_ADDR_LE_PUBLIC (vs. BT_ADDR_LE_RANDOM)
- */
- BLUETOOTH_ADDRCOPY(peer.val, btmeta->bm_raddr.val);
- peer.type = BT_ADDR_LE_PUBLIC;
- conn = bt_conn_create_le(&peer);
- if (conn == NULL)
- {
- /* bt_conn_create_le() can fail if (1) the connection exists, but is
- * in a bad state or (2) CONFIG_BLUETOOTH_MAX_CONN has been exceeded.
- * Assume the latter.
- */
- return -ENOMEM;
- }
- /* 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;
- DEBUGASSERT(iob->io_offset == BLUETOOTH_MAX_HDRLEN &&
- iob->io_len >= BLUETOOTH_MAX_HDRLEN);
- /* Allocate a buffer to contain the IOB */
- buf = bt_buf_alloc(BT_ACL_OUT, iob, BLUETOOTH_MAX_HDRLEN);
- if (buf == NULL)
- {
- wlerr("ERROR: Failed to allocate buffer container\n");
- return -ENOMEM;
- }
- /* Transfer the frame to the Bluetooth stack. */
- bt_l2cap_send(conn, (uint16_t)btmeta->bm_channel, buf);
- NETDEV_TXDONE(&priv->bd_dev.r_dev);
- }
- return OK;
- }
- #endif
- /****************************************************************************
- * Name: btnet_req_hci_data
- *
- * Description:
- * Requests the transfer of a list of HCI frames to the MAC.
- *
- * Input Parameters:
- * priv - Bluetooth network device
- * btmeta - Bluetooth frame metadata
- * framelist - Head of a list of HCI frames to be transferred.
- *
- * Returned Value:
- * Zero (OK) returned on success; a negated errno value is returned on
- * any failure.
- *
- ****************************************************************************/
- static int btnet_req_hci_data(FAR struct btnet_driver_s *priv,
- FAR struct bluetooth_frame_meta_s *meta,
- FAR struct iob_s *framelist)
- {
- FAR struct iob_s *iob;
- FAR struct bt_buf_s *buf;
- /* 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;
- DEBUGASSERT(iob->io_offset == BLUETOOTH_H4_HDRLEN &&
- iob->io_len >= BLUETOOTH_H4_HDRLEN);
- /* Allocate a buffer to contain the IOB */
- switch (iob->io_data[iob->io_offset])
- {
- case HCI_ACLDATA_PKT:
- iob->io_offset += 1;
- buf = bt_buf_alloc(BT_ACL_OUT, iob, 0);
- break;
- case HCI_COMMAND_PKT:
- iob->io_offset += 1;
- buf = bt_buf_alloc(BT_CMD, iob, 0);
- break;
- case HCI_EVENT_PKT:
- iob->io_offset += 1;
- buf = bt_buf_alloc(BT_EVT, iob, 0);
- break;
- default:
- return -EOPNOTSUPP;
- break;
- }
- if (buf == NULL)
- {
- wlerr("ERROR: Failed to allocate buffer container\n");
- return -ENOMEM;
- }
- bt_send(g_btdev.btdev, buf);
- bt_buf_release(buf);
- /* Transfer the frame to the Bluetooth stack. */
- 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 = BLUETOOTH_MAX_FRAMELEN; /* Fixed frame length */
- /* Multicast, multicast, and star hub node addresses not supported */
- return OK;
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: bt_netdev_register
- *
- * Description:
- * Register a network driver to access the Bluetooth layer using a 6LoWPAN
- * IPv6 or AF_BLUETOOTH socket.
- *
- * Input Parameters:
- * btdev - An instance of the low-level drivers interface structure.
- *
- * 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(FAR const struct bt_driver_s *btdev)
- {
- FAR struct btnet_driver_s *priv;
- FAR struct radio_driver_s *radio;
- FAR struct net_driver_s *netdev;
- #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
- FAR struct bt_conn_cb_s *hcicb;
- FAR struct bt_l2cap_chan_s *l2capcb;
- #else
- FAR struct bt_hci_cb_s *hcicb;
- #endif
- 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;
- netdev = &radio->r_dev;
- netdev->d_ifup = btnet_ifup; /* I/F up (new IP address) callback */
- netdev->d_ifdown = btnet_ifdown; /* I/F down callback */
- netdev->d_txavail = btnet_txavail; /* New TX data callback */
- #ifdef CONFIG_NET_MCASTGROUP
- netdev->d_addmac = btnet_addmac; /* Add multicast MAC address */
- netdev->d_rmmac = btnet_rmmac; /* Remove multicast MAC address */
- #endif
- #if defined(CONFIG_NETDEV_IOCTL) && defined(CONFIG_WIRELESS_BLUETOOTH_HOST)
- netdev->d_ioctl = btnet_ioctl; /* Handle network IOCTL commands */
- #endif
- netdev->d_private = priv; /* Used to recover private state from netdev */
- /* Connection status change callbacks */
- #ifdef CONFIG_WIRELESS_BLUETOOTH_HOST
- hcicb = &priv->bd_hcicb;
- hcicb->context = priv;
- hcicb->connected = btnet_hci_connected;
- hcicb->disconnected = btnet_hci_disconnected;
- bt_conn_cb_register(hcicb);
- /* L2CAP status change callbacks */
- l2capcb = &priv->bd_l2capcb;
- l2capcb->context = priv;
- l2capcb->connected = btnet_l2cap_connected;
- l2capcb->disconnected = btnet_l2cap_disconnected;
- l2capcb->encrypt_change = btnet_l2cap_encrypt_change;
- l2capcb->receive = btnet_l2cap_receive;
- bt_l2cap_chan_default(l2capcb);
- #else
- hcicb = &priv->bd_hcicb;
- hcicb->context = priv;
- hcicb->received = btnet_hci_received;
- bt_hci_cb_register(hcicb);
- #endif
- /* Setup a locking semaphore for exclusive device driver access */
- nxsem_init(&priv->bd_exclsem, 0, 1);
- /* Set the network mask. */
- btnet_netmask(netdev);
- /* 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 */
- /* Associate the driver in with the Bluetooth stack.
- *
- * REVISIT: We will eventually need to remember which Bluetooth device
- * we a serving. Not a problem now because only a single BLE device is
- * supported.
- */
- ret = bt_driver_register(btdev);
- if (ret < 0)
- {
- nerr("ERROR: bt_driver_register() failed: %d\n", ret);
- goto errout;
- }
- /* Initialize the Bluetooth stack.
- *
- * REVISIT: This function should be called only once after all BLE
- * drivers are registered. Not a problem now because only a single
- * BLE device is supported.
- */
- ret = bt_initialize();
- if (ret < 0)
- {
- nerr("ERROR: bt_initialize() failed: %d\n", ret);
- goto errout;
- }
- /* Put the interface in the down state. */
- btnet_ifdown(netdev);
- #ifdef CONFIG_NET_6LOWPAN
- /* Make sure the our single packet buffer is attached.
- * We must do this before registering the device since, once the device is
- * registered, a packet may be attempted to be forwarded and require the
- * buffer.
- */
- priv->bd_dev.r_dev.d_buf = g_iobuffer.rb_buf;
- #endif
- /* Register the network 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;
- }
- nerr("ERROR: netdev_register() failed: %d\n", ret);
- errout:
- /* Un-initialize semaphores */
- nxsem_destroy(&priv->bd_exclsem);
- /* Free memory and return the error */
- kmm_free(priv);
- return ret;
- }
- #endif /* CONFIG_NET && CONFIG_NET_skeleton */
|