diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h index f67ac0d98e3..2e65199513f 100644 --- a/include/nuttx/net/sixlowpan.h +++ b/include/nuttx/net/sixlowpan.h @@ -402,6 +402,8 @@ * frame list. */ +struct ieee802154_frame_meta_s; /* Forward reference */ + struct ieee802154_driver_s { /* This definitiona must appear first in the structure definition to @@ -498,6 +500,33 @@ struct ieee802154_driver_s systime_t i_time; #endif /* CONFIG_NET_6LOWPAN_FRAG */ + + /* MAC network driver callback functions **********************************/ + /************************************************************************** + * Name: mac802154_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. + * + **************************************************************************/ + + CODE int (*i_get_mhrlen)(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta); + + /************************************************************************** + * Name: mac802154_req_data + * + * Description: + * The MCPS-DATA.request primitive requests the transfer of a data SPDU + * (i.e., MSDU) from a local SSCS entity to a single peer SSCS entity. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_data callback. + * + **************************************************************************/ + + CODE int (*i_req_data)(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frames); }; /**************************************************************************** diff --git a/include/nuttx/wireless/ieee802154/ieee802154_mac.h b/include/nuttx/wireless/ieee802154/ieee802154_mac.h index a51e8852871..4231374371b 100644 --- a/include/nuttx/wireless/ieee802154/ieee802154_mac.h +++ b/include/nuttx/wireless/ieee802154/ieee802154_mac.h @@ -479,7 +479,7 @@ struct ieee802154_frame_meta_s enum ieee802154_addr_mode_e src_addr_mode; /* Source Address Mode */ struct ieee802154_addr_s dest_addr; /* Destination Address */ - uint8_t msdu_handle; /* Handle assoc. with MSDU */ + uint8_t msdu_handle; /* Handle assoc. with MSDU */ /* Number of bytes contained in the MAC Service Data Unit (MSDU) * to be transmitted by the MAC sublayer enitity diff --git a/wireless/ieee802154/mac802154_loopback.c b/wireless/ieee802154/mac802154_loopback.c index 9733065f46d..92a30d35194 100644 --- a/wireless/ieee802154/mac802154_loopback.c +++ b/wireless/ieee802154/mac802154_loopback.c @@ -83,6 +83,10 @@ #define LO_WDDELAY (1*CLK_TCK) +/* Fake value for MAC header length */ + +#define MAC_HDRLEN 9 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -98,6 +102,8 @@ struct lo_driver_s uint16_t lo_panid; /* Fake PAN ID for testing */ WDOG_ID lo_polldog; /* TX poll timer */ struct work_s lo_work; /* For deferring poll work to the work queue */ + FAR struct iob_s *head; /* Head of IOBs queued for loopback */ + FAR struct iob_s *tail; /* Tail of IOBs queued for loopback */ /* This holds the information visible to the NuttX network */ @@ -117,33 +123,39 @@ static uint8_t g_iobuffer[CONFIG_NET_6LOWPAN_MTU + CONFIG_NET_GUARDSIZE]; /* Polling logic */ -static int lo_txpoll(FAR struct net_driver_s *dev); +static int lo_loopback(FAR struct net_driver_s *dev); +static void lo_loopback_work(FAR void *arg); static void lo_poll_work(FAR void *arg); static void lo_poll_expiry(int argc, wdparm_t arg, ...); /* NuttX callback functions */ -static int lo_ifup(FAR struct net_driver_s *dev); -static int lo_ifdown(FAR struct net_driver_s *dev); +static int lo_ifup(FAR struct net_driver_s *dev); +static int lo_ifdown(FAR struct net_driver_s *dev); static void lo_txavail_work(FAR void *arg); -static int lo_txavail(FAR struct net_driver_s *dev); +static int lo_txavail(FAR struct net_driver_s *dev); #if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6) -static int lo_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac); +static int lo_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac); #ifdef CONFIG_NET_IGMP -static int lo_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac); +static int lo_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac); #endif #endif #ifdef CONFIG_NETDEV_IOCTL static int lo_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg); #endif +static int lo_get_mhrlen(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta); +static int lo_req_data(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frames); /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: lo_txpoll + * Name: lo_loopback * * Description: * Check if the network has any outgoing packets ready to send. This is @@ -162,7 +174,7 @@ static int lo_ioctl(FAR struct net_driver_s *dev, int cmd, * ****************************************************************************/ -static int lo_txpoll(FAR struct net_driver_s *dev) +static int lo_loopback(FAR struct net_driver_s *dev) { FAR struct lo_driver_s *priv = (FAR struct lo_driver_s *)dev->d_private; FAR struct iob_s *head; @@ -270,6 +282,34 @@ static int lo_txpoll(FAR struct net_driver_s *dev) return 0; } +/**************************************************************************** + * Name: lo_loopback_work + * + * Description: + * Perform loopback of received frames. + * + * Parameters: + * arg - The argument passed when work_queue() as called. + * + * Returned Value: + * OK on success + * + * Assumptions: + * The network is locked + * + ****************************************************************************/ + +static void lo_loopback_work(FAR void *arg) +{ + FAR struct lo_driver_s *priv = (FAR struct lo_driver_s *)arg; + + /* Perform the loopback */ + + net_lock(); + (void)lo_loopback(&priv->lo_ieee.i_dev); + net_unlock(); +} + /**************************************************************************** * Name: lo_poll_work * @@ -295,7 +335,7 @@ static void lo_poll_work(FAR void *arg) net_lock(); priv->lo_txdone = false; - (void)devif_timer(&priv->lo_ieee.i_dev, lo_txpoll); + (void)devif_timer(&priv->lo_ieee.i_dev, lo_loopback); /* Was something received and looped back? */ @@ -304,7 +344,7 @@ static void lo_poll_work(FAR void *arg) /* Yes, poll again for more TX data */ priv->lo_txdone = false; - (void)devif_poll(&priv->lo_ieee.i_dev, lo_txpoll); + (void)devif_poll(&priv->lo_ieee.i_dev, lo_loopback); } /* Setup the watchdog poll timer again */ @@ -458,7 +498,7 @@ static void lo_txavail_work(FAR void *arg) /* If so, then poll the network for new XMIT data */ priv->lo_txdone = false; - (void)devif_poll(&priv->lo_ieee.i_dev, lo_txpoll); + (void)devif_poll(&priv->lo_ieee.i_dev, lo_loopback); } while (priv->lo_txdone); } @@ -492,8 +532,8 @@ static int lo_txavail(FAR struct net_driver_s *dev) ninfo("Available: %u\n", work_available(&priv->lo_work)); /* 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. + * pending actions and we will have to ignore the Tx availability + * action. */ if (work_available(&priv->lo_work)) @@ -644,6 +684,92 @@ static int lo_ioctl(FAR struct net_driver_s *dev, int cmd, } #endif +/**************************************************************************** + * Name: lo_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. + * + ****************************************************************************/ + +static int lo_get_mhrlen(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta) +{ + return MAC_HDRLEN; +} + +/**************************************************************************** + * Name: lo_req_data + * + * Description: + * The MCPS-DATA.request primitive requests the transfer of a data SPDU + * (i.e., MSDU) from a local SSCS entity to a single peer SSCS entity. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_data callback. + * + ****************************************************************************/ + +static int lo_req_data(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frames) +{ + FAR struct lo_driver_s *priv; + FAR struct iob_s *iob; + + DEBUGASSERT(netdev != NULL && netdev->i_dev.d_private != NULL && iob != NULL); + priv = (FAR struct lo_driver_s *)netdev->i_dev.d_private; + + /* Add the incoming list of frames to queue of frames to loopback */ + + for (iob = frames; iob != NULL; iob = frames) + { + /* Increment statistics */ + + NETDEV_RXPACKETS(&priv->lo_ieee.i_dev); + + /* Remove the IOB from the queue */ + + frames = iob->io_flink; + iob->io_flink = NULL; + + /* Just zero the MAC header for test purposes */ + + DEBUGASSERT(iob->io_offset == MAC_HDRLEN); + memset(iob->io_data, 0, MAC_HDRLEN); + + /* Add the IOB to the tail of teh queue of frames to be looped back */ + + if (priv->tail == NULL) + { + priv->head = iob; + } + else + { + priv->tail->io_flink = iob; + } + + /* Find the new tail of the IOB queue */ + + for (priv->tail = iob, iob = iob->io_flink; + iob != NULL; + priv->tail = iob, iob = iob->io_flink); + } + + /* Is our single work structure available? It may not be if there are + * pending actions and we will have to ignore the Tx availability + * action. + */ + + if (work_available(&priv->lo_work)) + { + /* Schedule to serialize the poll on the worker thread. */ + + work_queue(LPBKWORK, &priv->lo_work, lo_loopback_work, priv, 0); + } + + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -666,7 +792,8 @@ static int lo_ioctl(FAR struct net_driver_s *dev, int cmd, int ieee8021514_loopback(void) { - FAR struct lo_driver_s *priv; + FAR struct lo_driver_s *priv; + FAR struct ieee802154_driver_s *ieee; FAR struct net_driver_s *dev; ninfo("Initializing\n"); @@ -679,27 +806,33 @@ int ieee8021514_loopback(void) memset(priv, 0, sizeof(struct lo_driver_s)); - dev = &priv->lo_ieee.i_dev; - dev->d_ifup = lo_ifup; /* I/F up (new IP address) callback */ - dev->d_ifdown = lo_ifdown; /* I/F down callback */ - dev->d_txavail = lo_txavail; /* New TX data callback */ + ieee = &priv->lo_ieee; + dev = &ieee->i_dev; + dev->d_ifup = lo_ifup; /* I/F up (new IP address) callback */ + dev->d_ifdown = lo_ifdown; /* I/F down callback */ + dev->d_txavail = lo_txavail; /* New TX data callback */ #ifdef CONFIG_NET_IGMP - dev->d_addmac = lo_addmac; /* Add multicast MAC address */ - dev->d_rmmac = lo_rmmac; /* Remove multicast MAC address */ + dev->d_addmac = lo_addmac; /* Add multicast MAC address */ + dev->d_rmmac = lo_rmmac; /* Remove multicast MAC address */ #endif #ifdef CONFIG_NETDEV_IOCTL - dev->d_ioctl = lo_ioctl; /* Handle network IOCTL commands */ + dev->d_ioctl = lo_ioctl; /* Handle network IOCTL commands */ #endif - dev->d_buf = g_iobuffer; /* Attach the IO buffer */ - dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ - - /* Create a watchdog for timing polling for and timing of transmissions */ - - priv->lo_polldog = wd_create(); /* Create periodic poll timer */ + dev->d_buf = g_iobuffer; /* Attach the IO buffer */ + dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ /* Initialize the DSN to a "random" value */ - priv->lo_ieee.i_dsn = 42; + ieee->i_dsn = 42; + + /* Initialize the Network frame-related callbacks */ + + ieee->i_get_mhrlen = lo_get_mhrlen; /* Get MAC header length */ + ieee->i_req_data = lo_req_data; /* Enqueue frame for transmission */ + + /* Create a watchdog for timing polling for and timing of transmissions */ + + priv->lo_polldog = wd_create(); /* Create periodic poll timer */ /* Register the loopabck device with the OS so that socket IOCTLs can b * performed. diff --git a/wireless/ieee802154/mac802154_netdev.c b/wireless/ieee802154/mac802154_netdev.c index 18b2d6e1cd0..f0e4f43cbea 100644 --- a/wireless/ieee802154/mac802154_netdev.c +++ b/wireless/ieee802154/mac802154_netdev.c @@ -257,6 +257,11 @@ static void macnet_ipv6multicast(FAR struct macnet_driver_s *priv); static int macnet_ioctl(FAR struct net_driver_s *dev, int cmd, unsigned long arg); #endif +static int macnet_get_mhrlen(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta); +static int macnet_req_data(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frames); /**************************************************************************** * Private Functions @@ -1494,6 +1499,86 @@ static int macnet_ioctl(FAR struct net_driver_s *dev, int cmd, } #endif +/**************************************************************************** + * Name: macnet_get_mhrlen + * + * Description: + * Calculate the MAC header length given the frame meta-data. + * + ****************************************************************************/ + +static int macnet_get_mhrlen(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta) +{ + FAR struct macnet_driver_s *priv; + + DEBUGASSERT(netdev != NULL && netdev->i_dev.d_private != NULL && iob != NULL); + priv = (FAR struct macnet_driver_s *)netdev->i_dev.d_private; + + return mac802154_get_mhrlen(priv->md_mac, meta); +} + +/**************************************************************************** + * Name: macnet_req_data + * + * Description: + * The MCPS-DATA.request primitive requests the transfer of a data SPDU + * (i.e., MSDU) from a local SSCS entity to a single peer SSCS entity. + * Confirmation is returned via the + * struct ieee802154_maccb_s->conf_data callback. + * + ****************************************************************************/ + +static int macnet_req_data(FAR struct ieee802154_driver_s *netdev, + FAR struct ieee802154_frame_meta_s *meta, + FAR struct iob_s *frames) +{ + FAR struct macnet_driver_s *priv; + struct ieee802154_data_req_s req; + FAR struct iob_s *iob; + int ret; + + DEBUGASSERT(netdev != NULL && netdev->i_dev.d_private != NULL && iob != NULL); + priv = (FAR struct macnet_driver_s *)netdev->i_dev.d_private; + + /* Add the incoming list of frames to the MAC's outgoing queue */ + + for (iob = frames; iob != NULL; iob = frames) + { + /* Increment statistics */ + + NETDEV_RXPACKETS(&priv->lo_ieee.i_dev); + + /* Remove the IOB from the queue */ + + frames = iob->io_flink; + iob->io_flink = NULL; + + /* Transfer the frame to the MAC */ + + req.meta = mets; + req.frame = iob; + ret = mac802154_req_data(priv->md_mac, req); + if (ret < 0) + { + wlerr("ERROR: mac802154_req_data failed: %d\n", ret); + + iob_free(iob); + for (iob = frames; ; iob != NULL; iob = frames) + { + /* Remove the IOB from the queue and free */ + + frames = iob->io_flink; + iob_free(iob); + } + + return ret; + } + } + + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -1517,7 +1602,8 @@ static int macnet_ioctl(FAR struct net_driver_s *dev, int cmd, int mac802154netdev_register(MACHANDLE mac) { FAR struct macnet_driver_s *priv; - FAR struct net_driver_s *dev; + FAR struct ieee802154_driver_s *ieee; + FAR struct net_driver_s *dev; FAR struct ieee802154_maccb_s *maccb; FAR uint8_t *pktbuf; int ret; @@ -1549,28 +1635,34 @@ int mac802154netdev_register(MACHANDLE mac) /* Initialize the driver structure */ - dev = &priv->md_dev.i_dev; - dev->d_buf = pktbuf; /* Single packet buffer */ - dev->d_ifup = macnet_ifup; /* I/F up (new IP address) callback */ - dev->d_ifdown = macnet_ifdown; /* I/F down callback */ - dev->d_txavail = macnet_txavail; /* New TX data callback */ + ieee = &priv->lo_ieee; + dev = &ieee->i_dev; + dev->d_buf = pktbuf; /* Single packet buffer */ + dev->d_ifup = macnet_ifup; /* I/F up (new IP address) callback */ + dev->d_ifdown = macnet_ifdown; /* I/F down callback */ + dev->d_txavail = macnet_txavail; /* New TX data callback */ #ifdef CONFIG_NET_IGMP - dev->d_addmac = macnet_addmac; /* Add multicast MAC address */ - dev->d_rmmac = macnet_rmmac; /* Remove multicast MAC address */ + dev->d_addmac = macnet_addmac; /* Add multicast MAC address */ + dev->d_rmmac = macnet_rmmac; /* Remove multicast MAC address */ #endif #ifdef CONFIG_NETDEV_IOCTL - dev->d_ioctl = macnet_ioctl; /* Handle network IOCTL commands */ + dev->d_ioctl = macnet_ioctl; /* Handle network IOCTL commands */ #endif - dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ + dev->d_private = (FAR void *)priv; /* Used to recover private state from dev */ /* Create a watchdog for timing polling for and timing of transmisstions */ - priv->md_mac = mac; /* Save the MAC interface instance */ - priv->md_txpoll = wd_create(); /* Create periodic poll timer */ - priv->md_txtimeout = wd_create(); /* Create TX timeout timer */ + priv->md_mac = mac; /* Save the MAC interface instance */ + priv->md_txpoll = wd_create(); /* Create periodic poll timer */ + priv->md_txtimeout = wd_create(); /* Create TX timeout timer */ DEBUGASSERT(priv->md_txpoll != NULL && priv->md_txtimeout != NULL); + /* Initialize the Network frame-related callbacks */ + + ieee->i_get_mhrlen = macnet_get_mhrlen; /* Get MAC header length */ + ieee->i_req_data = macnet_req_data; /* Enqueue frame for transmission */ + /* Initialize the MAC callbacks */ priv->md_cb.mc_priv = priv;