From 2d4ba3ee3f0d7311cb3325f9ad6719617f7830fc Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 18 Jun 2017 11:00:47 -0600 Subject: [PATCH] IEEE 802.15.4 MAC: Add list management and prioritization logic that will permit the MAC layer to support bound multiple clients. --- .../clicker2-stm32/mrf24j40-6lowpan/defconfig | 4 +- configs/clicker2-stm32/mrf24j40-mac/defconfig | 8 +- configs/sim/sixlowpan/defconfig | 2 +- sched/sched/sched_addprioritized.c | 4 +- wireless/ieee802154/Kconfig | 26 ++++-- wireless/ieee802154/mac802154.c | 79 ++++++++++++++++--- wireless/ieee802154/mac802154.h | 20 +++-- wireless/ieee802154/mac802154_bind.c | 35 +++++++- wireless/ieee802154/mac802154_device.c | 26 ++++-- wireless/ieee802154/mac802154_internal.h | 2 +- wireless/ieee802154/mac802154_netdev.c | 48 ++++++++--- 11 files changed, 204 insertions(+), 50 deletions(-) diff --git a/configs/clicker2-stm32/mrf24j40-6lowpan/defconfig b/configs/clicker2-stm32/mrf24j40-6lowpan/defconfig index b202b30aa8..df21e0d03e 100644 --- a/configs/clicker2-stm32/mrf24j40-6lowpan/defconfig +++ b/configs/clicker2-stm32/mrf24j40-6lowpan/defconfig @@ -1137,12 +1137,14 @@ CONFIG_IOB_THROTTLE=8 CONFIG_WIRELESS=y CONFIG_WIRELESS_IEEE802154=y CONFIG_IEEE802154_DEFAULT_EADDR=0x00fade00deadbeef -CONFIG_IEEE802154_MAC_DEV=y CONFIG_MAC802154_HPWORK=y CONFIG_IEEE802154_NTXDESC=3 CONFIG_IEEE802154_IND_PREALLOC=20 CONFIG_IEEE802154_IND_IRQRESERVE=10 +CONFIG_IEEE802154_MACDEV=y +CONFIG_IEEE802154_MACDEV_RECVRPRIO=0 CONFIG_IEEE802154_NETDEV=y +CONFIG_IEEE802154_NETDEV_RECVRPRIO=1 CONFIG_IEEE802154_NETDEV_HPWORK=y # CONFIG_IEEE802154_LOOPBACK is not set diff --git a/configs/clicker2-stm32/mrf24j40-mac/defconfig b/configs/clicker2-stm32/mrf24j40-mac/defconfig index 8ecd37bd89..d6ba224b4e 100644 --- a/configs/clicker2-stm32/mrf24j40-mac/defconfig +++ b/configs/clicker2-stm32/mrf24j40-mac/defconfig @@ -393,6 +393,7 @@ CONFIG_STM32_HAVE_I2C2=y CONFIG_STM32_HAVE_I2C3=y CONFIG_STM32_HAVE_SPI2=y CONFIG_STM32_HAVE_SPI3=y +CONFIG_STM32_HAVE_I2S3=y # CONFIG_STM32_HAVE_SPI4 is not set # CONFIG_STM32_HAVE_SPI5 is not set # CONFIG_STM32_HAVE_SPI6 is not set @@ -431,6 +432,7 @@ CONFIG_STM32_PWR=y # CONFIG_STM32_SPI1 is not set # CONFIG_STM32_SPI2 is not set CONFIG_STM32_SPI3=y +# CONFIG_STM32_I2S3 is not set CONFIG_STM32_SYSCFG=y # CONFIG_STM32_TIM1 is not set # CONFIG_STM32_TIM2 is not set @@ -968,6 +970,7 @@ CONFIG_MM_IOB=y CONFIG_IOB_NBUFFERS=8 CONFIG_IOB_BUFSIZE=196 CONFIG_IOB_NCHAINS=0 +CONFIG_IOB_THROTTLE=0 # # Audio Support @@ -980,11 +983,12 @@ CONFIG_IOB_NCHAINS=0 CONFIG_WIRELESS=y CONFIG_WIRELESS_IEEE802154=y CONFIG_IEEE802154_DEFAULT_EADDR=0x00fade00deadbeef -CONFIG_IEEE802154_MAC_DEV=y CONFIG_MAC802154_HPWORK=y CONFIG_IEEE802154_NTXDESC=3 CONFIG_IEEE802154_IND_PREALLOC=20 CONFIG_IEEE802154_IND_IRQRESERVE=10 +CONFIG_IEEE802154_MACDEV=y +CONFIG_IEEE802154_MACDEV_RECVRPRIO=0 # # Binary Loader @@ -1162,10 +1166,10 @@ CONFIG_BUILTIN_PROXY_STACKSIZE=1024 CONFIG_EXAMPLES_NSH=y CONFIG_EXAMPLES_NSH_CXXINITIALIZE=y # CONFIG_EXAMPLES_NULL is not set +# CONFIG_EXAMPLES_NX is not set # CONFIG_EXAMPLES_NXFFS is not set # CONFIG_EXAMPLES_NXHELLO is not set # CONFIG_EXAMPLES_NXIMAGE is not set -# CONFIG_EXAMPLES_NX is not set # CONFIG_EXAMPLES_NXLINES is not set # CONFIG_EXAMPLES_NXTERM is not set # CONFIG_EXAMPLES_NXTEXT is not set diff --git a/configs/sim/sixlowpan/defconfig b/configs/sim/sixlowpan/defconfig index 5613379e8e..3c2ac60369 100644 --- a/configs/sim/sixlowpan/defconfig +++ b/configs/sim/sixlowpan/defconfig @@ -710,11 +710,11 @@ CONFIG_IOB_THROTTLE=8 CONFIG_WIRELESS=y CONFIG_WIRELESS_IEEE802154=y CONFIG_IEEE802154_DEFAULT_EADDR=0x00fade00deadbeef -# CONFIG_IEEE802154_MAC_DEV is not set CONFIG_MAC802154_HPWORK=y CONFIG_IEEE802154_NTXDESC=3 CONFIG_IEEE802154_IND_PREALLOC=20 CONFIG_IEEE802154_IND_IRQRESERVE=10 +# CONFIG_IEEE802154_MACDEV is not set # CONFIG_IEEE802154_NETDEV is not set CONFIG_IEEE802154_LOOPBACK=y CONFIG_IEEE802154_LOOPBACK_HPWORK=y diff --git a/sched/sched/sched_addprioritized.c b/sched/sched/sched_addprioritized.c index 349889f488..1a990bd04d 100644 --- a/sched/sched/sched_addprioritized.c +++ b/sched/sched/sched_addprioritized.c @@ -88,12 +88,12 @@ bool sched_addprioritized(FAR struct tcb_s *tcb, DSEG dq_queue_t *list) ASSERT(sched_priority >= SCHED_PRIORITY_MIN); /* Search the list to find the location to insert the new Tcb. - * Each is list is maintained in ascending sched_priority order. + * Each is list is maintained in descending sched_priority order. */ for (next = (FAR struct tcb_s *)list->head; (next && sched_priority <= next->sched_priority); - next = next->flink); + next = next->flink); /* Add the tcb to the spot found in the list. Check if the tcb * goes at the end of the list. NOTE: This could only happen if list diff --git a/wireless/ieee802154/Kconfig b/wireless/ieee802154/Kconfig index 107063a43e..a471e4804e 100644 --- a/wireless/ieee802154/Kconfig +++ b/wireless/ieee802154/Kconfig @@ -21,8 +21,6 @@ config IEEE802154_DEFAULT_EADDR ---help--- Set the default extended address to be used by MAC networks on init - - choice prompt "IEEE 802.15.4 work queue" default MAC802154_LPWORK if SCHED_LPWORK @@ -88,14 +86,14 @@ config IEEE802154_MACDEV if IEEE802154_MACDEV -config IEEE802154_MACDEV_RECEIVERPRIORITY +config IEEE802154_MACDEV_RECVRPRIO int "Priority of frame receiver registerd with the MAC layer" default 0 ---help--- When the MAC layer receives an incoming data frame, it passes the frame to registered receivers, in order of receiver priority, until one of the - receivers claim the frame. - + receivers claim the frame. + An example case would be when 6LoWPAN and the MAC character driver are enabled. Both have receivers registered with the MAC. The 6LoWPAN layer should get assigned a higher priority than the character driver. In this @@ -119,6 +117,24 @@ config IEEE802154_NETDEV if IEEE802154_NETDEV +config IEEE802154_NETDEV_RECVRPRIO + int "Priority of frame receiver registerd with the MAC layer" + default 1 + ---help--- + When the MAC layer receives an incoming data frame, it passes the frame + to registered receivers, in order of receiver priority, until one of the + receivers claim the frame. + + An example case would be when 6LoWPAN and the MAC character driver are + enabled. Both have receivers registered with the MAC. The 6LoWPAN layer + should get assigned a higher priority than the character driver. In this + case, the 6LoWPAN receiver will receive the frame first. If the frame is + a 6LoWPAN frame, it will claim the frame and the MAC will not pass the + frame to any additional receivers. If it does not claim the frame, the + MAC layer will call the next highest priority receiver, in this case, + the MAC character driver (which should always be lowest priority since + it is a "catch-all" type receiver). + choice prompt "Work queue" default IEEE802154_NETDEV_LPWORK if SCHED_LPWORK diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index f9322c36df..fa51213218 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -73,6 +73,11 @@ static void mac802154_resetqueues(FAR struct ieee802154_privmac_s *priv); +/* MAC client notification */ + +static void mac802154_notify(FAR struct ieee802154_privmac_s *priv, + FAR struct ieee802154_notif_s *notif); + /* IEEE 802.15.4 PHY Interface OPs */ static int mac802154_radiopoll(FAR const struct ieee802154_radiocb_s *radiocb, @@ -491,6 +496,34 @@ static void mac802154_purge_worker(FAR void *arg) } } +/**************************************************************************** + * Name: mac802154_notify + * + * Description: + * Notify every register MAC client. + * + ****************************************************************************/ + +static void mac802154_notify(FAR struct ieee802154_privmac_s *priv, + FAR struct ieee802154_notif_s *notif) +{ + FAR struct mac802154_maccb_s *cb; + + /* Try to notify every registered MAC client */ + + for (cb = priv->cb; cb != NULL; cb = cb->flink) + { + /* Does this client want notifications? */ + + if (cb->notify != NULL) + { + /* Yes.. Notify */ + + cb->notify(cb, notif); + } + } +} + /**************************************************************************** * Name: mac802154_radiopoll * @@ -628,8 +661,9 @@ static void mac802154_txdone_worker(FAR void *arg) notif->notiftype = IEEE802154_NOTIFY_CONF_DATA; /* Release the MAC, call the callback, get exclusive access again */ + mac802154_givesem(&priv->exclsem); - priv->cb->notify(priv->cb, notif); + mac802154_notify(priv, notif); mac802154_takesem(&priv->exclsem, false); } break; @@ -1096,8 +1130,7 @@ static void mac802154_rx_dataframe(FAR struct ieee802154_privmac_s *priv, /* Release the MAC */ mac802154_givesem(&priv->exclsem); - - priv->cb->notify(priv->cb, notif); + mac802154_notify(priv, notif); /* If there was data, pass it along */ @@ -1108,26 +1141,48 @@ static void mac802154_rx_dataframe(FAR struct ieee802154_privmac_s *priv, } else { + FAR struct mac802154_maccb_s *cb; + notify_with_lock: mac802154_givesem(&priv->exclsem); notify_without_lock: - /* If there is a registered MCPS callback receiver registered, - * send the frame, otherwise, throw it out. + /* If there are registered MCPS callback receivers registered, + * then forward the frame in priority order. If there are no + * registered receivers or if none of the receivers accept the + * data frame then drop the frame. */ - if (priv->cb->rxframe != NULL) + for (cb = priv->cb; cb != NULL; cb = cb->flink) { - priv->cb->rxframe(priv->cb, ind); - } - else - { - /* Free the data indication struct from the pool */ + int ret; - ieee802154_ind_free(ind); + /* Does this MAC client want frames? */ + + if (cb->rxframe != NULL) + { + /* Yes.. Offer this frame to the receiver */ + + ret = cb->rxframe(cb, ind); + if (ret >= 0) + { + /* The receiver accepted and disposed of the frame and + * its metadata. We are done. + */ + + return; + } + } } + + /* We get here if the there are no registered receivers or if + * all of the registered receivers declined the frame. + * Free the data indication struct from the pool + */ + + ieee802154_ind_free(ind); } } diff --git a/wireless/ieee802154/mac802154.h b/wireless/ieee802154/mac802154.h index 40d00c9d69..90ff021952 100644 --- a/wireless/ieee802154/mac802154.h +++ b/wireless/ieee802154/mac802154.h @@ -58,18 +58,22 @@ * Public Data Types ****************************************************************************/ -/* Callback operations to notify the next highest layer of various asynchronous - * events, usually triggered by some previous request or response invoked by the - * upper layer. +/* Callback operations to notify the next highest layer of various + * asynchronous events, usually triggered by some previous request or + * response invoked by the upper layer. */ struct mac802154_maccb_s { - CODE void (*notify)(FAR const struct mac802154_maccb_s *maccb, - FAR struct ieee802154_notif_s *notif); + FAR struct mac802154_maccb_s *flink; /* Implements a singly linked list */ + uint8_t prio; /* RX frame callback priority */ - CODE void (*rxframe)(FAR const struct mac802154_maccb_s *maccb, - FAR struct ieee802154_data_ind_s *ind); + /* Callback methods */ + + CODE void (*notify)(FAR struct mac802154_maccb_s *maccb, + FAR struct ieee802154_notif_s *notif); + CODE int (*rxframe)(FAR struct mac802154_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind); }; /**************************************************************************** @@ -93,7 +97,7 @@ struct iob_s; /* Forward reference */ * ****************************************************************************/ -int mac802154_bind(MACHANDLE mac, FAR const struct mac802154_maccb_s *cb); +int mac802154_bind(MACHANDLE mac, FAR struct mac802154_maccb_s *cb); /**************************************************************************** * Name: mac802154_ioctl diff --git a/wireless/ieee802154/mac802154_bind.c b/wireless/ieee802154/mac802154_bind.c index c173aef477..9b6bacea39 100644 --- a/wireless/ieee802154/mac802154_bind.c +++ b/wireless/ieee802154/mac802154_bind.c @@ -69,12 +69,41 @@ * ****************************************************************************/ -int mac802154_bind(MACHANDLE mac, FAR const struct mac802154_maccb_s *cb) +int mac802154_bind(MACHANDLE mac, FAR struct mac802154_maccb_s *cb) { FAR struct ieee802154_privmac_s *priv = (FAR struct ieee802154_privmac_s *)mac; + FAR struct mac802154_maccb_s *next; + FAR struct mac802154_maccb_s *prev; + + /* Add the MAC client callback structure to the list of MAC callbacks in + * priority order. + * + * Search the list to find the location to insert the new instance. + * The list is maintained in descending priority order. + */ + + for (prev = NULL, next = priv->cb; + (next != NULL && cb->prio <= next->prio); + prev = next, next = next->flink); + + /* Add the instance to the spot found in the list. Check if the instance + * goes at the head of the list. + */ + + if (prev == NULL) + { + cb->flink = priv->cb; /* May be NULL */ + priv->cb = cb; + } + + /* No.. the instance goes between prev and next */ + + else + { + cb->flink = next; /* May be NULL */ + prev->flink = cb; + } - priv->cb = cb; return OK; } - diff --git a/wireless/ieee802154/mac802154_device.c b/wireless/ieee802154/mac802154_device.c index b03ce94ba8..1d634f9018 100644 --- a/wireless/ieee802154/mac802154_device.c +++ b/wireless/ieee802154/mac802154_device.c @@ -141,10 +141,9 @@ static inline void mac802154dev_pushevent(FAR struct mac802154_chardevice_s *dev static inline FAR struct ieee802154_notif_s * mac802154dev_popevent(FAR struct mac802154_chardevice_s *dev); -static void mac802154dev_notify(FAR const struct mac802154_maccb_s *maccb, +static void mac802154dev_notify(FAR struct mac802154_maccb_s *maccb, FAR struct ieee802154_notif_s *notif); - -static void mac802154dev_rxframe(FAR const struct mac802154_maccb_s *maccb, +static int mac802154dev_rxframe(FAR struct mac802154_maccb_s *maccb, FAR struct ieee802154_data_ind_s *ind); static int mac802154dev_open(FAR struct file *filep); @@ -762,7 +761,7 @@ static int mac802154dev_ioctl(FAR struct file *filep, int cmd, return ret; } -static void mac802154dev_notify(FAR const struct mac802154_maccb_s *maccb, +static void mac802154dev_notify(FAR struct mac802154_maccb_s *maccb, FAR struct ieee802154_notif_s *notif) { FAR struct mac802154dev_callback_s *cb = @@ -826,8 +825,20 @@ static void mac802154dev_notify(FAR const struct mac802154_maccb_s *maccb, mac802154dev_givesem(&dev->md_exclsem); } -static void mac802154dev_rxframe(FAR const struct mac802154_maccb_s *maccb, - FAR struct ieee802154_data_ind_s *ind) +/**************************************************************************** + * Name: mac802154dev_rxframe + * + * Description: + * Handle received frames forward by the IEEE 802.15.4 MAC. + * + * Returned Value: + * any failure. On success, the ind and its contained iob will be freed. + * The ind will be intact if this function returns a failure. + * + ****************************************************************************/ + +static int mac802154dev_rxframe(FAR struct mac802154_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind) { FAR struct mac802154dev_callback_s *cb = (FAR struct mac802154dev_callback_s *)maccb; @@ -858,6 +869,7 @@ static void mac802154dev_rxframe(FAR const struct mac802154_maccb_s *maccb, /* Release the driver */ mac802154dev_givesem(&dev->md_exclsem); + return OK; } /**************************************************************************** @@ -923,6 +935,8 @@ int mac802154dev_register(MACHANDLE mac, int minor) dev->md_cb.mc_priv = dev; maccb = &dev->md_cb.mc_cb; + maccb->flink = NULL; + maccb->prio = CONFIG_IEEE802154_MACDEV_RECVRPRIO; maccb->notify = mac802154dev_notify; maccb->rxframe = mac802154dev_rxframe; diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index 51c4a1c706..adfc176c03 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -147,7 +147,7 @@ typedef void (*mac802154_worker_t)(FAR struct ieee802154_privmac_s *priv); struct ieee802154_privmac_s { FAR struct ieee802154_radio_s *radio; /* Contained IEEE802.15.4 radio dev */ - FAR const struct mac802154_maccb_s *cb; /* Contained MAC callbacks */ + FAR struct mac802154_maccb_s *cb; /* Head of a list of MAC callbacks */ FAR struct mac802154_radiocb_s radiocb; /* Interface to bind to radio */ sem_t exclsem; /* Support exclusive access */ diff --git a/wireless/ieee802154/mac802154_netdev.c b/wireless/ieee802154/mac802154_netdev.c index 7fcd25e3af..41946846b9 100644 --- a/wireless/ieee802154/mac802154_netdev.c +++ b/wireless/ieee802154/mac802154_netdev.c @@ -109,7 +109,7 @@ struct macnet_callback_s { /* This holds the information visible to the MAC layer */ - struct mac802154_maccb_s mc_cb; /* Interface understood by the MAC layer */ + struct mac802154_maccb_s mc_cb; /* Interface understood by the MAC layer */ FAR struct macnet_driver_s *mc_priv; /* Our priv data */ }; @@ -138,9 +138,9 @@ struct macnet_driver_s /* IEE802.15.4 MAC callback functions ***************************************/ -static void macnet_notify(FAR const struct mac802154_maccb_s *maccb, +static void macnet_notify(FAR struct mac802154_maccb_s *maccb, FAR struct ieee802154_notif_s *notif); -static void macnet_rxframe(FAR const struct mac802154_maccb_s *maccb, +static int macnet_rxframe(FAR struct mac802154_maccb_s *maccb, FAR struct ieee802154_data_ind_s *ind); /* Asynchronous confirmations to requests */ @@ -223,7 +223,7 @@ static int macnet_req_data(FAR struct ieee802154_driver_s *netdev, * ****************************************************************************/ -static void macnet_notify(FAR const struct mac802154_maccb_s *maccb, +static void macnet_notify(FAR struct mac802154_maccb_s *maccb, FAR struct ieee802154_notif_s *notif) { FAR struct macnet_callback_s *cb = @@ -250,11 +250,17 @@ static void macnet_notify(FAR const struct mac802154_maccb_s *maccb, * Name: macnet_rxframe * * Description: + * Handle received frames forward by the IEEE 802.15.4 MAC. + * + * Returned Value: + * Zero (OK) is returned on success; a negated errno value is returned on + * any failure. On success, the ind and its contained iob will be freed. + * The ind will be intact if this function returns a failure. * ****************************************************************************/ -static void macnet_rxframe(FAR const struct mac802154_maccb_s *maccb, - FAR struct ieee802154_data_ind_s *ind) +static int macnet_rxframe(FAR struct mac802154_maccb_s *maccb, + FAR struct ieee802154_data_ind_s *ind) { FAR struct macnet_callback_s *cb = (FAR struct macnet_callback_s *)maccb; @@ -264,10 +270,31 @@ static void macnet_rxframe(FAR const struct mac802154_maccb_s *maccb, DEBUGASSERT(cb != NULL && cb->mc_priv != NULL); priv = cb->mc_priv; - /* Extract the IOB containing the frame from the struct ieee802154_data_ind_s */ + /* Ignore the frame if the network is not up */ + + if (!priv->md_bifup) + { + return -ENETDOWN; + } + + /* Peek the IOB contained the frame in the struct ieee802154_data_ind_s */ DEBUGASSERT(priv != NULL && ind != NULL && ind->frame != NULL); - iob = ind->frame; + iob = ind->frame; + + /* 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) + { + return -EINVAL; + } + + /* Remove the IOB containing the frame. */ + ind->frame = NULL; /* Transfer the frame to the network logic */ @@ -279,6 +306,7 @@ static void macnet_rxframe(FAR const struct mac802154_maccb_s *maccb, */ ieee802154_ind_free(ind); + return OK; } /**************************************************************************** @@ -993,7 +1021,7 @@ static int macnet_req_data(FAR struct ieee802154_driver_s *netdev, * * Description: * Register a network driver to access the IEEE 802.15.4 MAC layer from - * a socket using 6loWPAN + * a socket using 6LoWPAN * * Input Parameters: * mac - Pointer to the mac layer struct to be registered. @@ -1072,6 +1100,8 @@ int mac802154netdev_register(MACHANDLE mac) priv->md_cb.mc_priv = priv; maccb = &priv->md_cb.mc_cb; + maccb->flink = NULL; + maccb->prio = CONFIG_IEEE802154_NETDEV_RECVRPRIO; maccb->notify = macnet_notify; maccb->rxframe = macnet_rxframe;