2017-05-02 22:42:40 +02:00
|
|
|
|
/****************************************************************************
|
|
|
|
|
* wireless/ieee802154/mac802154.c
|
|
|
|
|
*
|
2024-09-11 09:04:25 +02:00
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*
|
2021-09-06 13:39:36 +02:00
|
|
|
|
* 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
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*
|
2021-09-06 13:39:36 +02:00
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
2021-09-06 13:39:36 +02:00
|
|
|
|
* 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.
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Included Files
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <debug.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <nuttx/kmalloc.h>
|
|
|
|
|
#include <nuttx/wqueue.h>
|
|
|
|
|
|
2017-05-09 15:34:59 +02:00
|
|
|
|
#include <nuttx/mm/iob.h>
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-05-16 03:44:51 +02:00
|
|
|
|
#include "mac802154.h"
|
2017-06-14 08:49:27 +02:00
|
|
|
|
#include "mac802154_internal.h"
|
|
|
|
|
#include "mac802154_assoc.h"
|
2017-06-26 00:07:50 +02:00
|
|
|
|
#include "mac802154_scan.h"
|
2017-06-14 08:49:27 +02:00
|
|
|
|
#include "mac802154_data.h"
|
|
|
|
|
#include "mac802154_poll.h"
|
2017-05-16 03:44:51 +02:00
|
|
|
|
|
2017-05-02 22:42:40 +02:00
|
|
|
|
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
|
2017-05-05 17:15:28 +02:00
|
|
|
|
#include <nuttx/wireless/ieee802154/ieee802154_radio.h>
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Private Function Prototypes
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
/* Data structure pools and allocation helpers */
|
|
|
|
|
|
2017-05-16 03:44:51 +02:00
|
|
|
|
static void mac802154_resetqueues(FAR struct ieee802154_privmac_s *priv);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
|
|
|
|
/* IEEE 802.15.4 PHY Interface OPs */
|
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
static int
|
|
|
|
|
mac802154_radiopoll(FAR const struct ieee802154_radiocb_s *radiocb,
|
|
|
|
|
bool gts, FAR struct ieee802154_txdesc_s **tx_desc);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
|
|
|
|
static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb,
|
2017-06-03 00:49:22 +02:00
|
|
|
|
FAR struct ieee802154_txdesc_s *tx_desc);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
static void mac802154_txdone_worker(FAR void *arg);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
|
|
|
|
static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb,
|
2017-05-05 23:12:26 +02:00
|
|
|
|
FAR struct ieee802154_data_ind_s *ind);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
static void mac802154_rxframe_worker(FAR void *arg);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
static void
|
|
|
|
|
mac802154_edresult(FAR const struct ieee802154_radiocb_s *radiocb,
|
|
|
|
|
uint8_t edval);
|
2019-08-10 19:03:24 +02:00
|
|
|
|
|
2017-06-20 18:57:24 +02:00
|
|
|
|
static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb,
|
|
|
|
|
enum ieee802154_sfevent_e sfevent);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
static void mac802154_purge_worker(FAR void *arg);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv,
|
|
|
|
|
FAR struct ieee802154_data_ind_s *ind);
|
|
|
|
|
static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv,
|
|
|
|
|
FAR struct ieee802154_data_ind_s *ind);
|
|
|
|
|
static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv,
|
|
|
|
|
FAR struct ieee802154_data_ind_s *ind);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
static void mac802154_notify_worker(FAR void *arg);
|
|
|
|
|
|
2017-05-02 22:42:40 +02:00
|
|
|
|
/****************************************************************************
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* Private Functions
|
2017-05-02 22:42:40 +02:00
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
2017-05-16 03:44:51 +02:00
|
|
|
|
* Name: mac802154_resetqueues
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
* Description:
|
2017-05-16 03:44:51 +02:00
|
|
|
|
* Initializes the various queues used in the MAC layer. Called on creation
|
|
|
|
|
* of MAC.
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2017-05-16 03:44:51 +02:00
|
|
|
|
static void mac802154_resetqueues(FAR struct ieee802154_privmac_s *priv)
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
2017-05-16 03:44:51 +02:00
|
|
|
|
int i;
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-05-16 03:44:51 +02:00
|
|
|
|
sq_init(&priv->txdone_queue);
|
|
|
|
|
sq_init(&priv->csma_queue);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
sq_init(&priv->gts_queue);
|
2017-05-16 03:44:51 +02:00
|
|
|
|
sq_init(&priv->indirect_queue);
|
|
|
|
|
sq_init(&priv->dataind_queue);
|
2017-11-01 21:15:21 +01:00
|
|
|
|
sq_init(&priv->primitive_queue);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
/* Initialize the tx descriptor allocation pool */
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
sq_init(&priv->txdesc_queue);
|
2017-05-16 03:44:51 +02:00
|
|
|
|
for (i = 0; i < CONFIG_MAC802154_NTXDESC; i++)
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
sq_addlast((FAR sq_entry_t *)&priv->txdesc_pool[i],
|
|
|
|
|
&priv->txdesc_queue);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
2017-06-20 23:00:23 +02:00
|
|
|
|
|
2017-10-03 20:51:15 +02:00
|
|
|
|
nxsem_init(&priv->txdesc_sem, 0, CONFIG_MAC802154_NTXDESC);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: mac802154_txdesc_pool
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* This function allocates a tx descriptor and the dependent primitive
|
|
|
|
|
* (data confirmation) from the free list. The primitive and tx descriptor
|
|
|
|
|
* must be freed separately.
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*
|
|
|
|
|
* Assumptions:
|
|
|
|
|
* priv MAC struct is locked when calling.
|
|
|
|
|
*
|
|
|
|
|
* Notes:
|
|
|
|
|
* If any of the semaphore waits inside this function get interrupted, the
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* function will release the MAC layer. If this function returns -EINTR,
|
|
|
|
|
* the calling code should NOT release the MAC semaphore.
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
int mac802154_txdesc_alloc(FAR struct ieee802154_privmac_s *priv,
|
2022-09-06 08:18:45 +02:00
|
|
|
|
FAR struct ieee802154_txdesc_s **txdesc)
|
2017-06-03 00:49:22 +02:00
|
|
|
|
{
|
|
|
|
|
int ret;
|
2017-11-01 21:15:21 +01:00
|
|
|
|
FAR struct ieee802154_primitive_s *primitive;
|
2017-05-06 16:20:10 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
/* Try and take a count from the semaphore. If this succeeds, we have
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* "reserved" the structure, but still need to unlink it from the free
|
|
|
|
|
* list. The MAC is already locked, so there shouldn't be any other
|
|
|
|
|
* conflicting calls.
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2017-10-05 15:59:06 +02:00
|
|
|
|
ret = nxsem_trywait(&priv->txdesc_sem);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
if (ret == OK)
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
*txdesc =
|
|
|
|
|
(FAR struct ieee802154_txdesc_s *)sq_remfirst(&priv->txdesc_queue);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Unlock MAC so that other work can be done to free a notification */
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
|
|
|
|
/* Take a count from the tx desc semaphore, waiting if necessary. We
|
|
|
|
|
* only return from here with an error if we are allowing interruptions
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* and we received a signal.
|
|
|
|
|
*/
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
ret = nxsem_wait_uninterruptible(&priv->txdesc_sem);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
if (ret < 0)
|
|
|
|
|
{
|
|
|
|
|
/* MAC is already released */
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
wlwarn("WARNING: nxsem_wait_uninterruptible failed: %d\n", ret);
|
2020-01-02 17:49:34 +01:00
|
|
|
|
return ret;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* If we've taken a count from the semaphore, we have "reserved" the
|
|
|
|
|
* struct but now we need to pop it off of the free list. We need to
|
|
|
|
|
* re-lock the MAC in order to ensure this happens correctly.
|
2017-06-15 18:46:48 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
ret = nxmutex_lock(&priv->lock);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
if (ret < 0)
|
|
|
|
|
{
|
2022-09-06 08:18:45 +02:00
|
|
|
|
wlwarn("WARNING: nxmutex_lock failed: %d\n", ret);
|
2017-06-20 19:50:04 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxsem_post(&priv->txdesc_sem);
|
2020-01-02 17:49:34 +01:00
|
|
|
|
return ret;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* We can now safely unlink the next structure from the free list */
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
*txdesc =
|
|
|
|
|
(FAR struct ieee802154_txdesc_s *)sq_remfirst(&priv->txdesc_queue);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* We have now successfully allocated the tx descriptor. Now we need to
|
|
|
|
|
* allocate the primitive for the data confirmation that gets passed along
|
|
|
|
|
* with the tx descriptor. These are allocated together, but not freed
|
|
|
|
|
* together.
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
primitive = ieee802154_primitive_allocate();
|
2017-05-06 16:20:10 +02:00
|
|
|
|
|
2017-07-10 00:38:56 +02:00
|
|
|
|
(*txdesc)->purgetime = 0;
|
2017-07-18 20:01:30 +02:00
|
|
|
|
(*txdesc)->retrycount = priv->maxretries;
|
2017-07-09 23:59:22 +02:00
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
(*txdesc)->conf = &primitive->u.dataconf;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
return OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-17 20:56:42 +02:00
|
|
|
|
/****************************************************************************
|
2017-06-19 21:59:21 +02:00
|
|
|
|
* Name: mac802154_createdatareq
|
2017-06-17 20:56:42 +02:00
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Internal function used by various parts of the MAC layer. This function
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* allocates an IOB, populates the frame according to input args, and
|
|
|
|
|
* links the IOB into the provided tx descriptor.
|
2017-06-17 20:56:42 +02:00
|
|
|
|
*
|
|
|
|
|
* Assumptions:
|
|
|
|
|
* Called with the MAC locked
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2017-06-19 21:59:21 +02:00
|
|
|
|
void mac802154_createdatareq(FAR struct ieee802154_privmac_s *priv,
|
|
|
|
|
FAR struct ieee802154_addr_s *coordaddr,
|
|
|
|
|
enum ieee802154_addrmode_e srcmode,
|
|
|
|
|
FAR struct ieee802154_txdesc_s *txdesc)
|
2017-06-17 20:56:42 +02:00
|
|
|
|
{
|
|
|
|
|
FAR struct iob_s *iob;
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* The only node allowed to use a source address of none is the PAN
|
|
|
|
|
* Coordinator. PAN coordinators should not be sending data request
|
|
|
|
|
* commands.
|
2017-06-17 20:56:42 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
DEBUGASSERT(srcmode != IEEE802154_ADDRMODE_NONE);
|
|
|
|
|
|
|
|
|
|
/* Allocate an IOB to put the frame in */
|
|
|
|
|
|
2022-08-08 04:21:03 +02:00
|
|
|
|
iob = iob_alloc(false);
|
2017-06-17 20:56:42 +02:00
|
|
|
|
DEBUGASSERT(iob != NULL);
|
|
|
|
|
|
2017-06-19 21:54:36 +02:00
|
|
|
|
/* Set the frame control fields */
|
2017-06-17 20:56:42 +02:00
|
|
|
|
|
2017-06-19 21:54:36 +02:00
|
|
|
|
iob->io_data[0] = 0;
|
|
|
|
|
iob->io_data[1] = 0;
|
|
|
|
|
IEEE802154_SETACKREQ(iob->io_data, 0);
|
|
|
|
|
IEEE802154_SETFTYPE(iob->io_data, 0, IEEE802154_FRAME_COMMAND);
|
|
|
|
|
IEEE802154_SETDADDRMODE(iob->io_data, 0, coordaddr->mode);
|
|
|
|
|
IEEE802154_SETSADDRMODE(iob->io_data, 0, srcmode);
|
2017-06-17 20:56:42 +02:00
|
|
|
|
iob->io_len = 2;
|
|
|
|
|
|
|
|
|
|
/* Each time a data or a MAC command frame is generated, the MAC sublayer
|
|
|
|
|
* shall copy the value of macDSN into the Sequence Number field of the
|
|
|
|
|
* MHR of the outgoing frame and then increment it by one. [1] pg. 40.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
iob->io_data[iob->io_len++] = priv->dsn++;
|
|
|
|
|
|
|
|
|
|
/* If the destination address is present, copy the PAN ID and one of the
|
|
|
|
|
* addresses, depending on mode, into the MHR.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (coordaddr->mode != IEEE802154_ADDRMODE_NONE)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_putpanid(iob, coordaddr->panid);
|
2017-06-17 20:56:42 +02:00
|
|
|
|
|
|
|
|
|
if (coordaddr->mode == IEEE802154_ADDRMODE_SHORT)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_putsaddr(iob, coordaddr->saddr);
|
2017-06-17 20:56:42 +02:00
|
|
|
|
}
|
|
|
|
|
else if (coordaddr->mode == IEEE802154_ADDRMODE_EXTENDED)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_puteaddr(iob, coordaddr->eaddr);
|
2017-06-17 20:56:42 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the Destination Addressing Mode field is set to indicate that
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* destination addressing information is not present, the PAN ID
|
|
|
|
|
* Compression field shall be set to zero and the source PAN identifier
|
|
|
|
|
* shall contain the value of macPANId. Otherwise, the PAN ID Compression
|
|
|
|
|
* field shall be set to one. In this case and in accordance with the PAN
|
|
|
|
|
* ID Compression field, the Destination PAN Identifier field shall
|
|
|
|
|
* contain the value of macPANId, while the Source PAN Identifier field
|
|
|
|
|
* shall be omitted. [1] pg. 72
|
2017-06-17 20:56:42 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (coordaddr->mode != IEEE802154_ADDRMODE_NONE &&
|
2017-06-19 11:55:28 +02:00
|
|
|
|
IEEE802154_PANIDCMP(coordaddr->panid, priv->addr.panid))
|
2017-06-17 20:56:42 +02:00
|
|
|
|
{
|
2017-06-19 21:54:36 +02:00
|
|
|
|
IEEE802154_SETPANIDCOMP(iob->io_data, 0);
|
2017-06-17 20:56:42 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_putpanid(iob, priv->addr.panid);
|
2017-06-17 20:56:42 +02:00
|
|
|
|
}
|
2017-06-17 22:13:25 +02:00
|
|
|
|
|
2017-06-17 20:56:42 +02:00
|
|
|
|
if (srcmode == IEEE802154_ADDRMODE_SHORT)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_putsaddr(iob, priv->addr.saddr);
|
2017-06-17 20:56:42 +02:00
|
|
|
|
}
|
|
|
|
|
else if (srcmode == IEEE802154_ADDRMODE_EXTENDED)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_puteaddr(iob, priv->addr.eaddr);
|
2017-06-17 20:56:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy in the Command Frame Identifier */
|
|
|
|
|
|
|
|
|
|
iob->io_data[iob->io_len++] = IEEE802154_CMD_DATA_REQ;
|
|
|
|
|
|
|
|
|
|
/* Copy the IOB reference to the descriptor */
|
|
|
|
|
|
|
|
|
|
txdesc->frame = iob;
|
|
|
|
|
txdesc->frametype = IEEE802154_FRAME_COMMAND;
|
2019-08-10 20:27:49 +02:00
|
|
|
|
txdesc->ackreq = true;
|
2017-06-17 20:56:42 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* Save a copy of the destination addressing information into the tx
|
|
|
|
|
* descriptor. We only do this for commands to help with handling their
|
|
|
|
|
* progession.
|
2017-06-17 20:56:42 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2022-03-08 13:31:54 +01:00
|
|
|
|
memcpy(&txdesc->destaddr, coordaddr, sizeof(struct ieee802154_addr_s));
|
2017-06-17 20:56:42 +02:00
|
|
|
|
|
2017-06-30 11:26:32 +02:00
|
|
|
|
/* Save a reference of the tx descriptor */
|
2017-06-17 20:56:42 +02:00
|
|
|
|
|
2017-06-30 11:26:32 +02:00
|
|
|
|
priv->cmd_desc = txdesc;
|
2017-06-17 20:56:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: mac802154_notify
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Queue the primitive in the queue and queue work on the LPWORK
|
|
|
|
|
* queue if is not already scheduled.
|
|
|
|
|
*
|
|
|
|
|
* Assumptions:
|
|
|
|
|
* Called with the MAC locked
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void mac802154_notify(FAR struct ieee802154_privmac_s *priv,
|
|
|
|
|
FAR struct ieee802154_primitive_s *primitive)
|
|
|
|
|
{
|
|
|
|
|
sq_addlast((FAR sq_entry_t *)primitive, &priv->primitive_queue);
|
|
|
|
|
|
|
|
|
|
if (work_available(&priv->notifwork))
|
|
|
|
|
{
|
|
|
|
|
work_queue(LPWORK, &priv->notifwork, mac802154_notify_worker,
|
|
|
|
|
(FAR void *)priv, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: mac802154_notify_worker
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Pop each primitive off the queue and call the registered
|
|
|
|
|
* callbacks. There is special logic for handling ieee802154_data_ind_s.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void mac802154_notify_worker(FAR void *arg)
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
FAR struct ieee802154_privmac_s *priv =
|
|
|
|
|
(FAR struct ieee802154_privmac_s *)arg;
|
2017-11-01 21:15:21 +01:00
|
|
|
|
FAR struct mac802154_maccb_s *cb;
|
|
|
|
|
FAR struct ieee802154_primitive_s *primitive;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-11-01 21:15:21 +01:00
|
|
|
|
primitive =
|
|
|
|
|
(FAR struct ieee802154_primitive_s *)sq_remfirst(&priv->primitive_queue);
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-01 21:15:21 +01:00
|
|
|
|
|
|
|
|
|
while (primitive != NULL)
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* Data indications are a special case since the frame can only be
|
|
|
|
|
* passed to one place. The return value of the notify call is used to
|
|
|
|
|
* accept or reject the primitive. In the case of the data indication,
|
|
|
|
|
* there can only be one accept. Callbacks are stored in order of
|
|
|
|
|
* there receiver priority ordered when the callbacks are bound in
|
|
|
|
|
* mac802154_bind().
|
2017-11-01 21:15:21 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (primitive->type == IEEE802154_PRIMITIVE_IND_DATA)
|
|
|
|
|
{
|
|
|
|
|
bool dispose = true;
|
|
|
|
|
|
|
|
|
|
primitive->nclients = 1;
|
|
|
|
|
|
|
|
|
|
for (cb = priv->cb; cb != NULL; cb = cb->flink)
|
|
|
|
|
{
|
|
|
|
|
if (cb->notify != NULL)
|
|
|
|
|
{
|
|
|
|
|
ret = cb->notify(cb, primitive);
|
|
|
|
|
if (ret >= 0)
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* The receiver accepted and disposed of the frame and
|
|
|
|
|
* it's meta-data. We are done.
|
2017-11-01 21:15:21 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
dispose = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dispose)
|
|
|
|
|
{
|
2022-08-08 04:21:03 +02:00
|
|
|
|
iob_free(primitive->u.dataind.frame);
|
2017-11-01 21:15:21 +01:00
|
|
|
|
ieee802154_primitive_free(primitive);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* Set the number of clients count so that the primitive resources
|
|
|
|
|
* will be preserved until all clients are finished with it.
|
2017-11-01 21:15:21 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
primitive->nclients = priv->nclients;
|
|
|
|
|
|
|
|
|
|
/* Try to notify every registered MAC client */
|
|
|
|
|
|
|
|
|
|
for (cb = priv->cb; cb != NULL; cb = cb->flink)
|
|
|
|
|
{
|
|
|
|
|
if (cb->notify != NULL)
|
|
|
|
|
{
|
|
|
|
|
ret = cb->notify(cb, primitive);
|
2018-03-28 17:50:41 +02:00
|
|
|
|
if (ret < 0)
|
2017-11-01 21:15:21 +01:00
|
|
|
|
{
|
|
|
|
|
ieee802154_primitive_free(primitive);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ieee802154_primitive_free(primitive);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Get the next primitive then loop */
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2019-02-27 15:41:08 +01:00
|
|
|
|
primitive = (FAR struct ieee802154_primitive_s *)
|
|
|
|
|
sq_remfirst(&priv->primitive_queue);
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-01 21:15:21 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-20 18:57:24 +02:00
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: mac802154_updatebeacon
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* This function is called in the following scenarios:
|
|
|
|
|
* - The MAC receives a START.request primitive
|
|
|
|
|
* - Upon receiving the IEEE802154_SFEVENT_ENDOFACTIVE event from the
|
2024-02-16 21:17:09 +01:00
|
|
|
|
* this radio layer, the MAC checks the beaconupdate flag and if set
|
|
|
|
|
* calls function. The beaconupdate flag is set when various
|
|
|
|
|
* attributes that effect the beacon are updated.
|
2017-06-20 18:57:24 +02:00
|
|
|
|
*
|
|
|
|
|
* Internal function used by various parts of the MAC layer. This function
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* uses the various MAC attributes to update the beacon frame. It loads
|
|
|
|
|
* the inactive beacon frame structure and then notifies the radio layer
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* new frame. the provided tx descriptor in the indirect list and manages
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* of the the scheduling for purging the transaction if it does not get
|
|
|
|
|
* extracted in time.
|
2017-06-20 18:57:24 +02:00
|
|
|
|
*
|
|
|
|
|
* Assumptions:
|
|
|
|
|
* Called with the MAC locked
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void mac802154_updatebeacon(FAR struct ieee802154_privmac_s *priv)
|
|
|
|
|
{
|
|
|
|
|
FAR struct ieee802154_txdesc_s *txdesc;
|
2019-02-27 15:41:08 +01:00
|
|
|
|
FAR struct ieee802154_beaconframe_s *beacon;
|
2017-06-20 18:57:24 +02:00
|
|
|
|
uint8_t pendaddrspec_ind;
|
|
|
|
|
uint8_t pendeaddr = 0;
|
|
|
|
|
uint8_t pendsaddr = 0;
|
|
|
|
|
|
|
|
|
|
/* Switch the buffer */
|
|
|
|
|
|
|
|
|
|
priv->bf_ind = !priv->bf_ind;
|
|
|
|
|
|
|
|
|
|
/* Get a local reference to the beacon frame */
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
beacon = &priv->beaconframe[priv->bf_ind];
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
|
|
|
|
/* Clear the frame control fields */
|
|
|
|
|
|
2017-06-26 19:03:44 +02:00
|
|
|
|
beacon->bf_data[0] = 0;
|
2017-06-20 18:57:24 +02:00
|
|
|
|
beacon->bf_data[1] = 0;
|
|
|
|
|
beacon->bf_len = 2;
|
|
|
|
|
|
|
|
|
|
IEEE802154_SETFTYPE(beacon->bf_data, 0, IEEE802154_FRAME_BEACON);
|
|
|
|
|
|
|
|
|
|
/* Check if there is a broadcast message pending, if there is, we must set
|
|
|
|
|
* the frame pending bit to 1.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* TODO: handle broadcast frame */
|
2017-06-26 19:03:44 +02:00
|
|
|
|
|
2017-06-20 18:57:24 +02:00
|
|
|
|
DEBUGASSERT(priv->addr.mode != IEEE802154_ADDRMODE_NONE);
|
|
|
|
|
|
|
|
|
|
IEEE802154_SETDADDRMODE(beacon->bf_data, 0, IEEE802154_ADDRMODE_NONE);
|
|
|
|
|
IEEE802154_SETSADDRMODE(beacon->bf_data, 0, priv->addr.mode);
|
|
|
|
|
IEEE802154_SETVERSION(beacon->bf_data, 0, 1);
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* The beacon sequence number has to be taken care of by the radio layer,
|
|
|
|
|
* since we only want to update the whole frame when more changes than
|
|
|
|
|
* just the bsn.
|
2017-06-30 11:26:32 +02:00
|
|
|
|
*/
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
2017-06-30 11:26:32 +02:00
|
|
|
|
beacon->bf_len++;
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
|
|
|
|
IEEE802154_PANIDCOPY(&beacon->bf_data[beacon->bf_len], priv->addr.panid);
|
|
|
|
|
beacon->bf_len += IEEE802154_PANIDSIZE;
|
|
|
|
|
|
|
|
|
|
if (priv->addr.mode == IEEE802154_ADDRMODE_SHORT)
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
IEEE802154_SADDRCOPY(&beacon->bf_data[beacon->bf_len],
|
|
|
|
|
priv->addr.saddr);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
beacon->bf_len += IEEE802154_SADDRSIZE;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
IEEE802154_EADDRCOPY(&beacon->bf_data[beacon->bf_len],
|
|
|
|
|
priv->addr.eaddr);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
beacon->bf_len += IEEE802154_EADDRSIZE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear the superframe specification, then set the appropriate bits */
|
|
|
|
|
|
|
|
|
|
beacon->bf_data[beacon->bf_len] = 0;
|
|
|
|
|
beacon->bf_data[beacon->bf_len + 1] = 0;
|
|
|
|
|
|
|
|
|
|
IEEE802154_SETBEACONORDER(beacon->bf_data, beacon->bf_len,
|
2017-06-26 00:07:50 +02:00
|
|
|
|
priv->sfspec.beaconorder);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
IEEE802154_SETSFORDER(beacon->bf_data, beacon->bf_len,
|
2017-06-26 00:07:50 +02:00
|
|
|
|
priv->sfspec.sforder);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
IEEE802154_SETFINCAPSLOT(beacon->bf_data, beacon->bf_len,
|
2017-06-26 00:07:50 +02:00
|
|
|
|
priv->sfspec.final_capslot);
|
|
|
|
|
if (priv->sfspec.ble)
|
2017-06-20 18:57:24 +02:00
|
|
|
|
{
|
|
|
|
|
IEEE802154_SETBLE(beacon->bf_data, beacon->bf_len);
|
|
|
|
|
}
|
2019-02-27 15:41:08 +01:00
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
if (priv->sfspec.pancoord)
|
2017-06-20 18:57:24 +02:00
|
|
|
|
{
|
|
|
|
|
IEEE802154_SETPANCOORD(beacon->bf_data, beacon->bf_len);
|
|
|
|
|
}
|
2019-02-27 15:41:08 +01:00
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
if (priv->sfspec.assocpermit)
|
2017-06-20 18:57:24 +02:00
|
|
|
|
{
|
|
|
|
|
IEEE802154_SETASSOCPERMIT(beacon->bf_data, beacon->bf_len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
beacon->bf_len += 2;
|
|
|
|
|
|
|
|
|
|
/* TODO: Handle GTS properly, for now, we just set the descriptor count to
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* zero and specify that we do not permit GTS requests.
|
|
|
|
|
*/
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
|
|
|
|
beacon->bf_data[beacon->bf_len++] = 0;
|
|
|
|
|
|
|
|
|
|
/* TODO: Add GTS List here */
|
|
|
|
|
|
|
|
|
|
/* Skip the pending address specification field for now */
|
|
|
|
|
|
|
|
|
|
pendaddrspec_ind = beacon->bf_len++;
|
2017-06-26 19:03:44 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
txdesc = (FAR struct ieee802154_txdesc_s *)
|
|
|
|
|
sq_peek(&priv->indirect_queue);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
while (txdesc != NULL)
|
2017-06-20 18:57:24 +02:00
|
|
|
|
{
|
|
|
|
|
if (txdesc->destaddr.mode == IEEE802154_ADDRMODE_SHORT)
|
|
|
|
|
{
|
|
|
|
|
pendsaddr++;
|
2019-02-27 15:41:08 +01:00
|
|
|
|
IEEE802154_SADDRCOPY(&beacon->bf_data[beacon->bf_len],
|
|
|
|
|
txdesc->destaddr.saddr);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
beacon->bf_len += IEEE802154_SADDRSIZE;
|
|
|
|
|
}
|
|
|
|
|
else if (txdesc->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED)
|
|
|
|
|
{
|
|
|
|
|
pendeaddr++;
|
2019-02-27 15:41:08 +01:00
|
|
|
|
IEEE802154_EADDRCOPY(&beacon->bf_data[beacon->bf_len],
|
|
|
|
|
txdesc->destaddr.eaddr);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
beacon->bf_len += IEEE802154_EADDRSIZE;
|
|
|
|
|
}
|
2017-06-26 19:03:44 +02:00
|
|
|
|
|
2017-06-20 18:57:24 +02:00
|
|
|
|
/* Check if we are up to 7 addresses yet */
|
|
|
|
|
|
|
|
|
|
if ((pendsaddr + pendeaddr) == 7)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-25 13:48:46 +01:00
|
|
|
|
/* Get the next pending indirect transaction */
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
txdesc = (FAR struct ieee802154_txdesc_s *)
|
|
|
|
|
sq_next((FAR sq_entry_t *)txdesc);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
}
|
2017-06-26 19:03:44 +02:00
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* At this point, we know how many of each transaction we have, we can
|
|
|
|
|
* setup the Pending Address Specification field
|
2017-06-20 18:57:24 +02:00
|
|
|
|
*/
|
2017-06-26 19:03:44 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
beacon->bf_data[pendaddrspec_ind] =
|
|
|
|
|
(pendsaddr & 0x07) | ((pendeaddr << 4) & 0x70);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
|
|
|
|
/* Copy in the beacon payload */
|
|
|
|
|
|
|
|
|
|
memcpy(&beacon->bf_data[beacon->bf_len], priv->beaconpayload,
|
|
|
|
|
priv->beaconpayloadlength);
|
|
|
|
|
beacon->bf_len += priv->beaconpayloadlength;
|
|
|
|
|
|
|
|
|
|
priv->beaconupdate = false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
/****************************************************************************
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* Name: mac802154_setupindirect
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*
|
|
|
|
|
* Description:
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* Internal function used by various parts of the MAC layer. This function
|
|
|
|
|
* places the provided tx descriptor in the indirect list and manages the
|
|
|
|
|
* scheduling for purging the transaction if it does not get extracted in
|
|
|
|
|
* time.
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*
|
|
|
|
|
* Assumptions:
|
2017-06-15 18:46:48 +02:00
|
|
|
|
* Called with the MAC locked
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
void mac802154_setupindirect(FAR struct ieee802154_privmac_s *priv,
|
|
|
|
|
FAR struct ieee802154_txdesc_s *txdesc)
|
2017-06-03 00:49:22 +02:00
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
uint32_t ticks;
|
|
|
|
|
uint32_t symbols;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Link the tx descriptor into the list */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
sq_addlast((FAR sq_entry_t *)txdesc, &priv->indirect_queue);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Update the timestamp for purging the transaction */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* The maximum time (in unit periods) that a transaction is stored by a
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* coordinator and indicated in its beacon. The unit period is governed
|
|
|
|
|
* by macBeaconOrder, BO, as follows: For 0 ≤ BO ≤ 14, the unit period
|
|
|
|
|
* will be aBaseSuperframeDuration × 2 BO . For BO = 15, the unit period
|
|
|
|
|
* will be aBaseSuperframeDuration. [1] pg. 129
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
if (priv->sfspec.beaconorder < 15)
|
2017-06-03 00:49:22 +02:00
|
|
|
|
{
|
2017-06-15 18:46:48 +02:00
|
|
|
|
symbols = priv->trans_persisttime *
|
2019-02-27 15:41:08 +01:00
|
|
|
|
(IEEE802154_BASE_SUPERFRAME_DURATION *
|
|
|
|
|
(1 << priv->sfspec.beaconorder));
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-05-04 19:34:04 +02:00
|
|
|
|
symbols = priv->trans_persisttime *
|
|
|
|
|
IEEE802154_BASE_SUPERFRAME_DURATION;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
2017-05-06 16:20:10 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
ticks = mac802154_symtoticks(priv, symbols);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2020-05-04 16:15:10 +02:00
|
|
|
|
txdesc->purgetime = clock_systime_ticks() + ticks;
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2017-06-20 18:57:24 +02:00
|
|
|
|
/* Make sure the beacon gets updated */
|
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
if (priv->sfspec.beaconorder < 15)
|
2017-06-20 18:57:24 +02:00
|
|
|
|
{
|
|
|
|
|
priv->beaconupdate = true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* Check to see if the purge indirect timer is scheduled. If it is, when
|
|
|
|
|
* the timer fires, it will schedule the next purge timer event.
|
|
|
|
|
* Inherently, the queue will be in order of which transaction needs to
|
|
|
|
|
* be purged next.
|
2017-05-02 19:58:57 +02:00
|
|
|
|
*
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* If the purge indirect timer has not been scheduled, schedule it for when
|
|
|
|
|
* this transaction should expire.
|
2017-05-02 19:58:57 +02:00
|
|
|
|
*/
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (work_available(&priv->purge_work))
|
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
work_queue(HPWORK, &priv->purge_work, mac802154_purge_worker,
|
2017-06-30 11:26:32 +02:00
|
|
|
|
(FAR void *)priv, ticks);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* Name: mac802154_purge_worker
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
* Description:
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* Worker function scheduled in order to purge expired indirect
|
|
|
|
|
* transactions. The first element in the list should always be removed.
|
|
|
|
|
* The list is searched and transactions are removed until a transaction
|
|
|
|
|
* has not yet expired. Then if there are any remaining transactions, the
|
|
|
|
|
* work function is rescheduled for the next expiring transaction.
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
static void mac802154_purge_worker(FAR void *arg)
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
FAR struct ieee802154_privmac_s *priv =
|
|
|
|
|
(FAR struct ieee802154_privmac_s *)arg;
|
|
|
|
|
FAR struct ieee802154_txdesc_s *txdesc;
|
|
|
|
|
|
|
|
|
|
/* Get exclusive access to the driver structure. We don't care about any
|
|
|
|
|
* signals so don't allow interruptions
|
|
|
|
|
*/
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
|
|
|
|
while (1)
|
2019-02-27 15:41:08 +01:00
|
|
|
|
{
|
|
|
|
|
/* Pop transactions off indirect queue until the transaction timeout
|
|
|
|
|
* has not passed.
|
|
|
|
|
*/
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
txdesc = (FAR struct ieee802154_txdesc_s *)
|
|
|
|
|
sq_peek(&priv->indirect_queue);
|
|
|
|
|
if (txdesc == NULL)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* Should probably check a little ahead and remove the transaction if
|
|
|
|
|
* it is within a certain number of clock ticks away. There is no
|
|
|
|
|
* since in scheduling the timer to expire in only a few ticks.
|
|
|
|
|
*/
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2020-05-04 16:15:10 +02:00
|
|
|
|
if (clock_systime_ticks() >= txdesc->purgetime)
|
2019-02-27 15:41:08 +01:00
|
|
|
|
{
|
|
|
|
|
/* Unlink the transaction */
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
sq_remfirst(&priv->indirect_queue);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* Free the IOB, the notification, and the tx descriptor */
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2022-08-08 04:21:03 +02:00
|
|
|
|
iob_free(txdesc->frame);
|
2019-02-27 15:41:08 +01:00
|
|
|
|
ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)
|
|
|
|
|
txdesc->conf);
|
|
|
|
|
mac802154_txdesc_free(priv, txdesc);
|
|
|
|
|
priv->beaconupdate = true;
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
wlinfo("Indirect TX purged");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Reschedule the transaction for the next timeout */
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
work_queue(HPWORK, &priv->purge_work, mac802154_purge_worker,
|
2020-05-04 16:15:10 +02:00
|
|
|
|
priv, txdesc->purgetime - clock_systime_ticks());
|
2019-02-27 15:41:08 +01:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-09 23:59:22 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
2017-06-17 20:50:25 +02:00
|
|
|
|
* Name: mac802154_radiopoll
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
* Description:
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* Called from the radio driver through the callback struct. This
|
|
|
|
|
* function is called when the radio has room for another transaction. If
|
|
|
|
|
* the MAC layer has a transaction, it copies it into the supplied buffer
|
|
|
|
|
* and returns the length. A descriptor is also populated with the
|
|
|
|
|
* transaction.
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
static int
|
2024-02-16 21:17:09 +01:00
|
|
|
|
mac802154_radiopoll(FAR const struct ieee802154_radiocb_s *radiocb,
|
|
|
|
|
bool gts, FAR struct ieee802154_txdesc_s **txdesc)
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
|
|
|
|
FAR struct mac802154_radiocb_s *cb =
|
|
|
|
|
(FAR struct mac802154_radiocb_s *)radiocb;
|
|
|
|
|
FAR struct ieee802154_privmac_s *priv;
|
|
|
|
|
|
|
|
|
|
DEBUGASSERT(cb != NULL && cb->priv != NULL);
|
|
|
|
|
priv = cb->priv;
|
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* Get exclusive access to the driver structure. Ignore EINTR signals */
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
if (gts)
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
2017-06-03 00:49:22 +02:00
|
|
|
|
/* Check to see if there are any GTS transactions waiting */
|
2017-05-16 03:44:51 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
*txdesc = (FAR struct ieee802154_txdesc_s *)
|
|
|
|
|
sq_remfirst(&priv->gts_queue);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
2017-06-03 00:49:22 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Check to see if there are any CSMA transactions waiting */
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
*txdesc = (FAR struct ieee802154_txdesc_s *)
|
|
|
|
|
sq_remfirst(&priv->csma_queue);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
if (*txdesc != NULL)
|
|
|
|
|
{
|
|
|
|
|
return (*txdesc)->frame->io_len;
|
|
|
|
|
}
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-05-16 03:44:51 +02:00
|
|
|
|
return 0;
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: mac802154_txdone
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* Called from the radio driver through the callback struct. This
|
|
|
|
|
* function is called when the radio has completed a transaction. The
|
|
|
|
|
* txdesc passed gives provides information about the completed
|
|
|
|
|
* transaction including the original handle provided when the transaction
|
|
|
|
|
* was created and the status of the transaction. This function copies
|
|
|
|
|
* the descriptor and schedules work to handle the transaction without
|
|
|
|
|
* blocking the radio.
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void mac802154_txdone(FAR const struct ieee802154_radiocb_s *radiocb,
|
2017-06-03 00:49:22 +02:00
|
|
|
|
FAR struct ieee802154_txdesc_s *txdesc)
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
|
|
|
|
FAR struct mac802154_radiocb_s *cb =
|
|
|
|
|
(FAR struct mac802154_radiocb_s *)radiocb;
|
|
|
|
|
FAR struct ieee802154_privmac_s *priv;
|
|
|
|
|
|
|
|
|
|
DEBUGASSERT(cb != NULL && cb->priv != NULL);
|
|
|
|
|
priv = cb->priv;
|
|
|
|
|
|
|
|
|
|
/* Get exclusive access to the driver structure. We don't care about any
|
2017-06-03 00:49:22 +02:00
|
|
|
|
* signals so don't allow interruptions
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-05-16 03:44:51 +02:00
|
|
|
|
sq_addlast((FAR sq_entry_t *)txdesc, &priv->txdone_queue);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
|
|
|
|
/* Schedule work with the work queue to process the completion further */
|
|
|
|
|
|
2019-08-19 17:17:01 +02:00
|
|
|
|
if (work_available(&priv->txdone_work))
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
2019-08-19 17:17:01 +02:00
|
|
|
|
work_queue(HPWORK, &priv->txdone_work, mac802154_txdone_worker,
|
2017-05-02 22:42:40 +02:00
|
|
|
|
(FAR void *)priv, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: mac802154_txdone_worker
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Worker function scheduled from mac802154_txdone. This function pops any
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* TX descriptors off of the list and calls the next highest layer callback
|
2017-05-02 22:42:40 +02:00
|
|
|
|
* to inform the layer of the completed transaction and the status of it.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void mac802154_txdone_worker(FAR void *arg)
|
|
|
|
|
{
|
|
|
|
|
FAR struct ieee802154_privmac_s *priv =
|
|
|
|
|
(FAR struct ieee802154_privmac_s *)arg;
|
2017-05-16 03:44:51 +02:00
|
|
|
|
FAR struct ieee802154_txdesc_s *txdesc;
|
2017-11-01 21:15:21 +01:00
|
|
|
|
FAR struct ieee802154_primitive_s *primitive;
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
|
|
|
|
/* Get exclusive access to the driver structure. We don't care about any
|
2017-06-03 00:49:22 +02:00
|
|
|
|
* signals so don't allow interruptions
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-05-16 03:44:51 +02:00
|
|
|
|
while (1)
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
txdesc = (FAR struct ieee802154_txdesc_s *)
|
|
|
|
|
sq_remfirst(&priv->txdone_queue);
|
2017-05-16 03:44:51 +02:00
|
|
|
|
|
|
|
|
|
if (txdesc == NULL)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* Cast the data_conf to a notification. We get both the private and
|
|
|
|
|
* public notification structure to make it easier to use.
|
2017-05-16 03:44:51 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
primitive = (FAR struct ieee802154_primitive_s *)txdesc->conf;
|
2017-05-16 03:44:51 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
wlinfo("Tx status: %s\n",
|
|
|
|
|
IEEE802154_STATUS_STRING[txdesc->conf->status]);
|
2017-06-30 11:26:32 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
switch (txdesc->frametype)
|
2017-05-16 03:44:51 +02:00
|
|
|
|
{
|
|
|
|
|
case IEEE802154_FRAME_DATA:
|
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
primitive->type = IEEE802154_PRIMITIVE_CONF_DATA;
|
|
|
|
|
mac802154_notify(priv, primitive);
|
2017-05-16 03:44:51 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-05-16 03:44:51 +02:00
|
|
|
|
case IEEE802154_FRAME_COMMAND:
|
|
|
|
|
{
|
2017-06-03 00:49:22 +02:00
|
|
|
|
switch (priv->curr_cmd)
|
|
|
|
|
{
|
|
|
|
|
case IEEE802154_CMD_ASSOC_REQ:
|
2017-06-14 08:49:27 +02:00
|
|
|
|
mac802154_txdone_assocreq(priv, txdesc);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
case IEEE802154_CMD_ASSOC_RESP:
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
case IEEE802154_CMD_DISASSOC_NOT:
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
case IEEE802154_CMD_DATA_REQ:
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Data requests can be sent for 3 different reasons.
|
|
|
|
|
*
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* 1. On a beacon-enabled PAN, this command shall be sent
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* by a device when macAutoRequest is equal to TRUE
|
|
|
|
|
* and a beacon frame indicating that data are pending
|
|
|
|
|
* for that device is received from its coordinator.
|
|
|
|
|
* 2. when instructed to do so by the next higher layer
|
|
|
|
|
* on reception of the MLME-POLL.request primitive.
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* 3. a device may send this command to the coordinator
|
|
|
|
|
* macResponseWaitTime after the acknowledgment to an
|
|
|
|
|
* association request command.
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
switch (priv->curr_op)
|
|
|
|
|
{
|
|
|
|
|
case MAC802154_OP_ASSOC:
|
|
|
|
|
mac802154_txdone_datareq_assoc(priv, txdesc);
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case MAC802154_OP_POLL:
|
|
|
|
|
mac802154_txdone_datareq_poll(priv, txdesc);
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-06-03 00:49:22 +02:00
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
case IEEE802154_CMD_PANID_CONF_NOT:
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
case IEEE802154_CMD_ORPHAN_NOT:
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
case IEEE802154_CMD_BEACON_REQ:
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
case IEEE802154_CMD_COORD_REALIGN:
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
case IEEE802154_CMD_GTS_REQ:
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
default:
|
2017-11-01 21:15:21 +01:00
|
|
|
|
ieee802154_primitive_free(primitive);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2017-05-16 03:44:51 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-05-16 03:44:51 +02:00
|
|
|
|
default:
|
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
ieee802154_primitive_free(primitive);
|
2017-05-16 03:44:51 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Free the IOB and the tx descriptor */
|
|
|
|
|
|
2022-08-08 04:21:03 +02:00
|
|
|
|
iob_free(txdesc->frame);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
mac802154_txdesc_free(priv, txdesc);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* Name: mac802154_rxframe
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*
|
|
|
|
|
* Description:
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* Called from the radio driver through the callback struct. This
|
|
|
|
|
* function is called when the radio has received a frame. The frame is
|
|
|
|
|
* passed in an iob, so that we can free it when we are done processing.
|
|
|
|
|
* A pointer to the RX descriptor is passed along with the iob, but it
|
|
|
|
|
* must be copied here as it is allocated directly on the caller's stack.
|
|
|
|
|
* We simply link the frame, copy the RX descriptor, and schedule a worker
|
|
|
|
|
* to process the frame later so that we do not hold up the radio.
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
static void mac802154_rxframe(FAR const struct ieee802154_radiocb_s *radiocb,
|
|
|
|
|
FAR struct ieee802154_data_ind_s *ind)
|
2017-06-03 00:49:22 +02:00
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
FAR struct mac802154_radiocb_s *cb =
|
|
|
|
|
(FAR struct mac802154_radiocb_s *)radiocb;
|
|
|
|
|
FAR struct ieee802154_privmac_s *priv;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
DEBUGASSERT(cb != NULL && cb->priv != NULL);
|
|
|
|
|
priv = cb->priv;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Get exclusive access to the driver structure. We don't care about any
|
|
|
|
|
* signals so if we see one, just go back to trying to get access again.
|
|
|
|
|
*/
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Push the iob onto the tail of the frame list for processing */
|
2017-05-16 03:44:51 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
sq_addlast((FAR sq_entry_t *)ind, &priv->dataind_queue);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-07-01 23:04:02 +02:00
|
|
|
|
wlinfo("Frame received\n");
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Schedule work with the work queue to process the completion further */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (work_available(&priv->rx_work))
|
2017-06-03 00:49:22 +02:00
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
work_queue(HPWORK, &priv->rx_work, mac802154_rxframe_worker,
|
2017-06-14 08:49:27 +02:00
|
|
|
|
(FAR void *)priv, 0);
|
2017-05-16 03:44:51 +02:00
|
|
|
|
}
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* Name: mac802154_rxframe_worker
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*
|
|
|
|
|
* Description:
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* Worker function scheduled from mac802154_rxframe. This function
|
|
|
|
|
* processes any frames in the list. Frames intended to be consumed by
|
|
|
|
|
* the MAC layer will not produce any callbacks to the next highest layer.
|
|
|
|
|
* Frames intended for the application layer will be forwarded to them.
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
2017-05-16 03:44:51 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
static void mac802154_rxframe_worker(FAR void *arg)
|
2017-06-03 00:49:22 +02:00
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
FAR struct ieee802154_privmac_s *priv =
|
|
|
|
|
(FAR struct ieee802154_privmac_s *)arg;
|
|
|
|
|
FAR struct ieee802154_data_ind_s *ind;
|
2017-06-19 11:55:28 +02:00
|
|
|
|
FAR struct iob_s *iob;
|
2023-05-17 22:09:06 +02:00
|
|
|
|
FAR uint16_t *frame_ctrl;
|
2017-06-14 08:49:27 +02:00
|
|
|
|
bool panid_comp;
|
|
|
|
|
uint8_t ftype;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
while (1)
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* Get exclusive access to the driver structure. We don't care about
|
|
|
|
|
* any signals so if we see one, just go back to trying to get access
|
|
|
|
|
* again.
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*/
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* Pop the data indication from the head of the frame list for
|
|
|
|
|
* processing. Note: dataind_queue contains ieee802154_primitive_s
|
|
|
|
|
* which is safe to cast directly to a data indication.
|
2017-11-01 21:15:21 +01:00
|
|
|
|
*/
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
ind = (FAR struct ieee802154_data_ind_s *)
|
|
|
|
|
sq_remfirst(&priv->dataind_queue);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* Once we pop off the indication, we needn't to keep the mac locked */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind == NULL)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Get a local copy of the frame to make it easier to access */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-19 11:55:28 +02:00
|
|
|
|
iob = ind->frame;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-15 18:46:48 +02:00
|
|
|
|
/* Set a local pointer to the frame control then move the offset past
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* the frame control field
|
|
|
|
|
*/
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2023-05-17 22:09:06 +02:00
|
|
|
|
frame_ctrl = (FAR uint16_t *)&iob->io_data[iob->io_offset];
|
2017-06-19 11:55:28 +02:00
|
|
|
|
iob->io_offset += 2;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* We use the data_ind_s as a container for the frame information even
|
|
|
|
|
* if this isn't a data frame
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*/
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
ind->src.mode = (*frame_ctrl & IEEE802154_FRAMECTRL_SADDR) >>
|
|
|
|
|
IEEE802154_FRAMECTRL_SHIFT_SADDR;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
ind->dest.mode = (*frame_ctrl & IEEE802154_FRAMECTRL_DADDR) >>
|
|
|
|
|
IEEE802154_FRAMECTRL_SHIFT_DADDR;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
panid_comp = (*frame_ctrl & IEEE802154_FRAMECTRL_PANIDCOMP) >>
|
|
|
|
|
IEEE802154_FRAMECTRL_SHIFT_PANIDCOMP;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-19 11:55:28 +02:00
|
|
|
|
ind->dsn = iob->io_data[iob->io_offset++];
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* If the destination address is included */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind->dest.mode != IEEE802154_ADDRMODE_NONE)
|
|
|
|
|
{
|
|
|
|
|
/* Get the destination PAN ID */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_takepanid(iob, ind->dest.panid);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind->dest.mode == IEEE802154_ADDRMODE_SHORT)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_takesaddr(iob, ind->dest.saddr);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
else if (ind->dest.mode == IEEE802154_ADDRMODE_EXTENDED)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_takeeaddr(iob, ind->dest.eaddr);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind->src.mode != IEEE802154_ADDRMODE_NONE)
|
2017-06-03 00:49:22 +02:00
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* If the source address is included, and the PAN ID compression
|
|
|
|
|
* field is set, get the PAN ID from the header.
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (panid_comp)
|
|
|
|
|
{
|
|
|
|
|
/* The source PAN ID is equal to the destination PAN ID */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-26 19:03:44 +02:00
|
|
|
|
IEEE802154_PANIDCOPY(ind->src.panid, ind->dest.panid);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_takepanid(iob, ind->src.panid);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind->src.mode == IEEE802154_ADDRMODE_SHORT)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_takesaddr(iob, ind->src.saddr);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
else if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_takeeaddr(iob, ind->src.eaddr);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* If the MAC is in promiscuous mode, just pass everything to the next
|
|
|
|
|
* layer assuming it is data
|
2017-11-01 21:15:21 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (priv->promisc)
|
|
|
|
|
{
|
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)ind);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
ftype = (*frame_ctrl & IEEE802154_FRAMECTRL_FTYPE) >>
|
|
|
|
|
IEEE802154_FRAMECTRL_SHIFT_FTYPE;
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
switch (ftype)
|
|
|
|
|
{
|
|
|
|
|
case IEEE802154_FRAME_DATA:
|
|
|
|
|
{
|
2017-06-26 00:07:50 +02:00
|
|
|
|
mac802154_rxdataframe(priv, ind);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_FRAME_COMMAND:
|
|
|
|
|
{
|
|
|
|
|
/* Get the command type. The command type is always the first
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* field after the MHR. Consu;me the byte by increasing offset
|
|
|
|
|
* so that subsequent functions can start from the byte after
|
|
|
|
|
* the command ID.
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*/
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-06-19 11:55:28 +02:00
|
|
|
|
uint8_t cmdtype = iob->io_data[iob->io_offset++];
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
switch (cmdtype)
|
|
|
|
|
{
|
|
|
|
|
case IEEE802154_CMD_ASSOC_REQ:
|
2017-06-26 00:07:50 +02:00
|
|
|
|
wlinfo("Assoc request received\n");
|
2017-06-14 08:49:27 +02:00
|
|
|
|
mac802154_rx_assocreq(priv, ind);
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_CMD_ASSOC_RESP:
|
2017-06-26 00:07:50 +02:00
|
|
|
|
wlinfo("Assoc response received\n");
|
2017-06-14 08:49:27 +02:00
|
|
|
|
mac802154_rx_assocresp(priv, ind);
|
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_CMD_DISASSOC_NOT:
|
2017-11-01 21:15:21 +01:00
|
|
|
|
wlinfo("Disassoc primitive received\n");
|
2017-06-14 08:49:27 +02:00
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_CMD_DATA_REQ:
|
2017-06-26 00:07:50 +02:00
|
|
|
|
wlinfo("Data request received\n");
|
|
|
|
|
mac802154_rxdatareq(priv, ind);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_CMD_PANID_CONF_NOT:
|
2017-11-01 21:15:21 +01:00
|
|
|
|
wlinfo("PAN ID Conflict primitive received\n");
|
2017-06-14 08:49:27 +02:00
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_CMD_ORPHAN_NOT:
|
2017-11-01 21:15:21 +01:00
|
|
|
|
wlinfo("Orphan primitive received\n");
|
2017-06-26 00:07:50 +02:00
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_CMD_BEACON_REQ:
|
2017-06-26 00:07:50 +02:00
|
|
|
|
wlinfo("Beacon request received\n");
|
2017-06-14 08:49:27 +02:00
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_CMD_COORD_REALIGN:
|
2017-06-26 00:07:50 +02:00
|
|
|
|
wlinfo("Coord realign received\n");
|
2017-06-14 08:49:27 +02:00
|
|
|
|
break;
|
2017-06-18 21:33:07 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_CMD_GTS_REQ:
|
2017-06-26 00:07:50 +02:00
|
|
|
|
wlinfo("GTS request received\n");
|
2017-06-14 08:49:27 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Free the data indication struct from the pool */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_FRAME_BEACON:
|
|
|
|
|
{
|
2017-07-13 23:57:33 +02:00
|
|
|
|
wlinfo("Beacon frame received. BSN: 0x%02X\n", ind->dsn);
|
2017-06-26 00:07:50 +02:00
|
|
|
|
mac802154_rxbeaconframe(priv, ind);
|
2019-02-27 15:41:08 +01:00
|
|
|
|
ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
case IEEE802154_FRAME_ACK:
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* The radio layer is responsible for handling all ACKs and
|
|
|
|
|
* retries. If for some reason an ACK gets here, just throw
|
|
|
|
|
* it out.
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*/
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
wlinfo("ACK received\n");
|
2019-02-27 15:41:08 +01:00
|
|
|
|
ieee802154_primitive_free((FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-06-03 00:49:22 +02:00
|
|
|
|
}
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
2017-06-26 00:07:50 +02:00
|
|
|
|
* Name: mac802154_rxdataframe
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
* Description:
|
2017-06-15 18:46:48 +02:00
|
|
|
|
* Function called from the generic RX Frame worker to parse and handle the
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* reception of a data frame.
|
2017-05-02 22:42:40 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
static void mac802154_rxdataframe(FAR struct ieee802154_privmac_s *priv,
|
|
|
|
|
FAR struct ieee802154_data_ind_s *ind)
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
FAR struct ieee802154_primitive_s *primitive;
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Get exclusive access to the MAC */
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* If we are currently performing a POLL operation and we've
|
2019-02-27 15:41:08 +01:00
|
|
|
|
* received a data response, use the addressing information
|
|
|
|
|
* to determine if it is extracted data. If the addressing info
|
|
|
|
|
* matches, notify the next highest layer using POLL.confirm
|
|
|
|
|
* primitive. If the addressing information does not match,
|
|
|
|
|
* handle the transaction like any other data transaction.
|
|
|
|
|
*
|
|
|
|
|
* Note: We can't receive frames without addressing information
|
|
|
|
|
* unless we are the PAN coordinator. And in that situation, we
|
|
|
|
|
* wouldn't be performing a POLL operation. Meaning:
|
|
|
|
|
*
|
|
|
|
|
* If the current operation is POLL, we aren't the PAN coordinator
|
|
|
|
|
* so the incoming frame CAN'T
|
|
|
|
|
*
|
|
|
|
|
* FIXME: Fix documentation
|
|
|
|
|
*/
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2017-06-30 11:26:32 +02:00
|
|
|
|
if (priv->curr_op == MAC802154_OP_POLL ||
|
|
|
|
|
priv->curr_op == MAC802154_OP_ASSOC ||
|
|
|
|
|
priv->curr_op == MAC802154_OP_AUTOEXTRACT)
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2017-06-15 18:46:48 +02:00
|
|
|
|
/* If we are in promiscuous mode, we need to check if the
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* frame is even for us first. If the address is not ours,
|
|
|
|
|
* then handle the frame like a normal transaction.
|
2017-05-06 16:20:10 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (priv->promisc)
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
if (!IEEE802154_PANIDCMP(ind->dest.panid, priv->addr.panid))
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-05-06 16:20:10 +02:00
|
|
|
|
}
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
|
|
|
|
if (ind->dest.mode == IEEE802154_ADDRMODE_SHORT &&
|
2017-06-19 11:55:28 +02:00
|
|
|
|
!IEEE802154_SADDRCMP(ind->dest.saddr, priv->addr.saddr))
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-05-06 16:20:10 +02:00
|
|
|
|
}
|
2017-06-14 08:49:27 +02:00
|
|
|
|
else if (ind->dest.mode == IEEE802154_ADDRMODE_EXTENDED &&
|
2017-06-19 11:55:28 +02:00
|
|
|
|
!IEEE802154_EADDRCMP(ind->dest.eaddr, priv->addr.eaddr))
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-05-06 16:20:10 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-05-06 16:20:10 +02:00
|
|
|
|
}
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
2017-05-06 16:20:10 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* If this was our extracted data, the source addressing field can only
|
2017-11-01 21:15:21 +01:00
|
|
|
|
* be NONE if we are trying to extract data from the PAN coordinator.
|
|
|
|
|
* A PAN coordinator shouldn't be sending us a frame if it wasn't
|
|
|
|
|
* our extracted data. Therefore just assume if the address mode is set
|
|
|
|
|
* to NONE, we process it as our extracted frame
|
|
|
|
|
*/
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
|
|
|
|
if (ind->src.mode != priv->cmd_desc->destaddr.mode)
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-05-06 16:20:10 +02:00
|
|
|
|
}
|
2017-05-08 22:21:29 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind->src.mode == IEEE802154_ADDRMODE_SHORT &&
|
2019-02-27 15:41:08 +01:00
|
|
|
|
!IEEE802154_SADDRCMP(ind->src.saddr,
|
|
|
|
|
priv->cmd_desc->destaddr.saddr))
|
2017-06-14 08:49:27 +02:00
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
else if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED &&
|
2019-02-27 15:41:08 +01:00
|
|
|
|
!IEEE802154_EADDRCMP(ind->src.eaddr,
|
|
|
|
|
priv->cmd_desc->destaddr.eaddr))
|
2017-06-14 08:49:27 +02:00
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)
|
|
|
|
|
ind);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* If we've gotten this far, the frame is our extracted data. Cancel
|
|
|
|
|
* the timeout
|
2017-06-30 11:26:32 +02:00
|
|
|
|
*/
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
mac802154_timercancel(priv);
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* If a frame is received from the coordinator with a zero length
|
|
|
|
|
* payload or if the frame is a MAC command frame, the MLME will issue
|
|
|
|
|
* the MLME-POLL.confirm primitive with a status of NO_DATA. [1] pg.
|
|
|
|
|
* 111
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
primitive = ieee802154_primitive_allocate();
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (priv->curr_op == MAC802154_OP_POLL)
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
primitive->type = IEEE802154_PRIMITIVE_CONF_POLL;
|
2017-05-06 16:20:10 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind->frame->io_offset == ind->frame->io_len)
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
primitive->u.pollconf.status = IEEE802154_STATUS_NO_DATA;
|
2017-05-06 16:20:10 +02:00
|
|
|
|
}
|
2017-06-15 18:46:48 +02:00
|
|
|
|
else
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
primitive->u.pollconf.status = IEEE802154_STATUS_SUCCESS;
|
2017-05-06 16:20:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-14 08:49:27 +02:00
|
|
|
|
else if (priv->curr_op == MAC802154_OP_ASSOC)
|
2017-05-06 16:20:10 +02:00
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* If we ever receive a data frame back as a response to the
|
|
|
|
|
* association request, we assume it means there wasn't any data.
|
2017-06-03 00:49:22 +02:00
|
|
|
|
*/
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
primitive->type = IEEE802154_PRIMITIVE_CONF_ASSOC;
|
|
|
|
|
primitive->u.assocconf.status = IEEE802154_STATUS_NO_DATA;
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* We are no longer performing the association operation */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
priv->curr_op = MAC802154_OP_NONE;
|
|
|
|
|
priv->cmd_desc = NULL;
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxsem_post(&priv->opsem);
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
/* Release the MAC and notify the next highest layer */
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
mac802154_notify(priv, primitive);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* If there was data, pass it along */
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind->frame->io_len > ind->frame->io_offset)
|
2017-05-02 22:42:40 +02:00
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)ind);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-05-04 19:34:04 +02:00
|
|
|
|
ieee802154_primitive_free(
|
|
|
|
|
(FAR struct ieee802154_primitive_s *)ind);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2017-06-14 08:49:27 +02:00
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
mac802154_notify(priv, (FAR struct ieee802154_primitive_s *)ind);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
2017-11-01 21:15:21 +01:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-03 19:26:06 +02:00
|
|
|
|
/****************************************************************************
|
2017-06-26 00:07:50 +02:00
|
|
|
|
* Name: mac802154_rxdatareq
|
2017-05-03 19:26:06 +02:00
|
|
|
|
*
|
|
|
|
|
* Description:
|
2017-06-15 18:46:48 +02:00
|
|
|
|
* Function called from the generic RX Frame worker to parse and handle the
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* reception of an Data Request MAC command frame.
|
2017-05-03 19:26:06 +02:00
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
static void mac802154_rxdatareq(FAR struct ieee802154_privmac_s *priv,
|
2023-05-17 22:09:06 +02:00
|
|
|
|
FAR struct ieee802154_data_ind_s *ind)
|
2017-05-03 19:26:06 +02:00
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
FAR struct ieee802154_txdesc_s *txdesc;
|
|
|
|
|
FAR struct iob_s *iob;
|
2023-05-17 22:09:06 +02:00
|
|
|
|
FAR uint16_t *frame_ctrl;
|
2017-05-03 19:26:06 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Get exclusive access to the MAC */
|
2017-05-02 22:42:40 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
|
|
|
|
/* Search the list of indirect transactions to see if there are any waiting
|
|
|
|
|
* for the requesting device.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* TODO: I believe there is an issue here. If there is for some reason a
|
|
|
|
|
* outgoing data frame to a device who is currently requesting association,
|
|
|
|
|
* we will send the data frame as a response to an association request. We
|
|
|
|
|
* need to check for this condition.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
txdesc = (FAR struct ieee802154_txdesc_s *)sq_peek(&priv->indirect_queue);
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
while (txdesc != NULL)
|
2017-05-03 17:14:06 +02:00
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (txdesc->destaddr.mode == ind->src.mode)
|
2017-05-03 17:14:06 +02:00
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (txdesc->destaddr.mode == IEEE802154_ADDRMODE_SHORT)
|
|
|
|
|
{
|
2020-05-04 19:34:04 +02:00
|
|
|
|
if (IEEE802154_SADDRCMP(txdesc->destaddr.saddr,
|
|
|
|
|
ind->src.saddr))
|
2017-06-14 08:49:27 +02:00
|
|
|
|
{
|
|
|
|
|
/* Remove the transaction from the queue */
|
|
|
|
|
|
|
|
|
|
sq_rem((FAR sq_entry_t *)txdesc, &priv->indirect_queue);
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* NOTE: We don't do anything with the purge timeout,
|
|
|
|
|
* because we really don't need to. As of now, I see no
|
|
|
|
|
* disadvantage to just letting the timeout expire, which
|
|
|
|
|
* won't purge the transaction since it is no longer on
|
|
|
|
|
* the list, and then it will reschedule the next timeout
|
|
|
|
|
* appropriately. The logic otherwise may get complicated
|
|
|
|
|
* even though it may save a few clock cycles.
|
2017-07-09 23:59:22 +02:00
|
|
|
|
*/
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* The addresses match, send the transaction immediately */
|
2017-05-03 17:14:06 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
priv->radio->txdelayed(priv->radio, txdesc, 0);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
priv->beaconupdate = true;
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
return;
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (txdesc->destaddr.mode == IEEE802154_ADDRMODE_EXTENDED)
|
|
|
|
|
{
|
2020-05-04 19:34:04 +02:00
|
|
|
|
if (IEEE802154_EADDRCMP(txdesc->destaddr.eaddr,
|
|
|
|
|
ind->src.eaddr))
|
2017-06-14 08:49:27 +02:00
|
|
|
|
{
|
|
|
|
|
/* Remove the transaction from the queue */
|
2017-05-03 17:14:06 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
sq_rem((FAR sq_entry_t *)txdesc, &priv->indirect_queue);
|
2017-05-03 17:14:06 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* The addresses match, send the transaction immediately */
|
|
|
|
|
|
|
|
|
|
priv->radio->txdelayed(priv->radio, txdesc, 0);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
priv->beaconupdate = true;
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
return;
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-07-13 19:35:38 +02:00
|
|
|
|
DEBUGPANIC();
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
2017-05-04 03:52:43 +02:00
|
|
|
|
}
|
2017-05-05 17:15:28 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
txdesc = (FAR struct ieee802154_txdesc_s *)
|
|
|
|
|
sq_next((FAR sq_entry_t *)txdesc);
|
2017-05-03 17:14:06 +02:00
|
|
|
|
}
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* If there is no data frame pending for the requesting device, the
|
|
|
|
|
* coordinator shall send a data frame without requesting acknowledgment
|
|
|
|
|
* to the device containing a zero length payload, indicating that no data
|
|
|
|
|
* are present, using one of the mechanisms described in this subclause.
|
|
|
|
|
* [1] pg. 43
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Allocate an IOB to put the frame in */
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2022-08-08 04:21:03 +02:00
|
|
|
|
iob = iob_alloc(false);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
DEBUGASSERT(iob != NULL);
|
2017-06-15 18:46:48 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
iob->io_len += 2;
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Cast the first two bytes of the IOB to a uint16_t frame control field */
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
frame_ctrl = (FAR uint16_t *)&iob->io_data[0];
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Ensure we start with a clear frame control field */
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*frame_ctrl = 0;
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Set the frame type to Data */
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*frame_ctrl |= IEEE802154_FRAME_DATA << IEEE802154_FRAMECTRL_SHIFT_FTYPE;
|
|
|
|
|
|
|
|
|
|
/* Each time a data or a MAC command frame is generated, the MAC sublayer
|
|
|
|
|
* shall copy the value of macDSN into the Sequence Number field of the MHR
|
|
|
|
|
* of the outgoing frame and then increment it by one. [1] pg. 40.
|
|
|
|
|
*/
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
iob->io_data[iob->io_len++] = priv->dsn++;
|
|
|
|
|
|
2017-06-15 18:46:48 +02:00
|
|
|
|
/* Use the source address information from the received data request to
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* respond.
|
|
|
|
|
*/
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_putpanid(iob, ind->src.panid);
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind->src.mode == IEEE802154_ADDRMODE_SHORT)
|
2017-05-09 23:22:30 +02:00
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_putsaddr(iob, ind->src.saddr);
|
2017-05-09 23:22:30 +02:00
|
|
|
|
}
|
2017-06-14 08:49:27 +02:00
|
|
|
|
else if (ind->src.mode == IEEE802154_ADDRMODE_EXTENDED)
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_puteaddr(iob, ind->src.eaddr);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-07-13 19:35:38 +02:00
|
|
|
|
DEBUGPANIC();
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set the destination addr mode inside the frame control field */
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*frame_ctrl |= (ind->src.mode << IEEE802154_FRAMECTRL_SHIFT_DADDR);
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* Check the source PAN ID of the incoming request is the same as ours. */
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
2017-06-19 11:55:28 +02:00
|
|
|
|
if (IEEE802154_PANIDCMP(ind->src.panid, priv->addr.panid))
|
2017-05-09 23:22:30 +02:00
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
*frame_ctrl |= IEEE802154_FRAMECTRL_PANIDCOMP;
|
2017-05-09 23:22:30 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Copy in our PAN ID */
|
|
|
|
|
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_putpanid(iob, priv->addr.panid);
|
2017-05-09 23:22:30 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Copy in our address using the mode that the device used to address us */
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
if (ind->dest.mode == IEEE802154_ADDRMODE_SHORT)
|
2017-05-09 23:22:30 +02:00
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_putsaddr(iob, priv->addr.saddr);
|
2019-02-27 15:41:08 +01:00
|
|
|
|
*frame_ctrl |= (IEEE802154_ADDRMODE_SHORT <<
|
|
|
|
|
IEEE802154_FRAMECTRL_SHIFT_SADDR);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-06-19 11:55:28 +02:00
|
|
|
|
mac802154_puteaddr(iob, priv->addr.eaddr);
|
2019-02-27 15:41:08 +01:00
|
|
|
|
*frame_ctrl |= (IEEE802154_ADDRMODE_EXTENDED <<
|
|
|
|
|
IEEE802154_FRAMECTRL_SHIFT_SADDR);
|
2017-05-09 23:22:30 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-14 08:49:27 +02:00
|
|
|
|
/* Allocate the txdesc, waiting if necessary, allow interruptions */
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
mac802154_txdesc_alloc(priv, &txdesc);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
|
|
|
|
txdesc->frame = iob;
|
|
|
|
|
txdesc->frametype = IEEE802154_FRAME_DATA;
|
2019-08-10 20:27:49 +02:00
|
|
|
|
txdesc->ackreq = false;
|
2017-05-09 23:22:30 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-06-14 08:49:27 +02:00
|
|
|
|
|
|
|
|
|
priv->radio->txdelayed(priv->radio, txdesc, 0);
|
2017-05-02 22:42:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-10 19:03:24 +02:00
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: mac802154_edresult
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* Called from the radio driver through the callback struct. This function
|
|
|
|
|
* is called when the radio has finished an energy detect operation. This
|
|
|
|
|
* is triggered by a SCAN.request primitive with ScanType set to Energy
|
2019-08-10 19:03:24 +02:00
|
|
|
|
* Detect (ED)
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
static void
|
|
|
|
|
mac802154_edresult(FAR const struct ieee802154_radiocb_s *radiocb,
|
|
|
|
|
uint8_t edval)
|
2019-08-10 19:03:24 +02:00
|
|
|
|
{
|
|
|
|
|
FAR struct mac802154_radiocb_s *cb =
|
|
|
|
|
(FAR struct mac802154_radiocb_s *)radiocb;
|
|
|
|
|
FAR struct ieee802154_privmac_s *priv;
|
|
|
|
|
|
|
|
|
|
DEBUGASSERT(cb != NULL && cb->priv != NULL);
|
|
|
|
|
priv = cb->priv;
|
|
|
|
|
|
|
|
|
|
/* Get exclusive access to the driver structure. We don't care about any
|
|
|
|
|
* signals so if we see one, just go back to trying to get access again.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2019-08-10 19:03:24 +02:00
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* If we are actively performing a scan operation, notify the handler */
|
2019-08-10 19:03:24 +02:00
|
|
|
|
|
|
|
|
|
if (priv->curr_op == MAC802154_OP_SCAN)
|
|
|
|
|
{
|
|
|
|
|
mac802154_edscan_onresult(priv, edval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Relinquish control of the private structure */
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2019-08-10 19:03:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-20 18:57:24 +02:00
|
|
|
|
static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb,
|
|
|
|
|
enum ieee802154_sfevent_e sfevent)
|
|
|
|
|
{
|
|
|
|
|
FAR struct mac802154_radiocb_s *cb =
|
|
|
|
|
(FAR struct mac802154_radiocb_s *)radiocb;
|
|
|
|
|
FAR struct ieee802154_privmac_s *priv;
|
|
|
|
|
|
|
|
|
|
DEBUGASSERT(cb != NULL && cb->priv != NULL);
|
|
|
|
|
priv = cb->priv;
|
|
|
|
|
|
|
|
|
|
/* Get exclusive access to the driver structure. We don't care about any
|
|
|
|
|
* signals so if we see one, just go back to trying to get access again.
|
|
|
|
|
*/
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
2017-07-01 23:05:09 +02:00
|
|
|
|
switch (sfevent)
|
2017-06-20 18:57:24 +02:00
|
|
|
|
{
|
2017-07-01 23:05:09 +02:00
|
|
|
|
case IEEE802154_SFEVENT_ENDOFACTIVE:
|
|
|
|
|
{
|
2017-07-10 05:57:11 +02:00
|
|
|
|
#ifdef CONFIG_MAC802154_SFEVENT_VERBOSE
|
2017-07-01 23:05:09 +02:00
|
|
|
|
wlinfo("End of superframe\n");
|
2017-07-10 05:57:11 +02:00
|
|
|
|
#endif
|
2017-07-01 23:05:09 +02:00
|
|
|
|
|
|
|
|
|
/* Check if there is any reason to update the beacon */
|
|
|
|
|
|
|
|
|
|
if (priv->beaconupdate)
|
|
|
|
|
{
|
|
|
|
|
mac802154_updatebeacon(priv);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
priv->radio->beaconupdate(priv->radio,
|
|
|
|
|
&priv->beaconframe[priv->bf_ind]);
|
2017-07-01 23:05:09 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2019-02-27 15:41:08 +01:00
|
|
|
|
|
2017-07-01 23:05:09 +02:00
|
|
|
|
default:
|
|
|
|
|
break;
|
2017-06-20 18:57:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-06-20 18:57:24 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
/****************************************************************************
|
|
|
|
|
* Name: mac802154_rxbeaconframe
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Function called from the generic RX Frame worker to parse and handle the
|
|
|
|
|
* reception of a beacon frame.
|
|
|
|
|
*
|
2017-11-01 21:15:21 +01:00
|
|
|
|
* Assumptions: MAC is unlocked
|
2017-06-28 04:01:40 +02:00
|
|
|
|
*
|
2017-06-26 00:07:50 +02:00
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv,
|
|
|
|
|
FAR struct ieee802154_data_ind_s *ind)
|
|
|
|
|
{
|
|
|
|
|
FAR struct ieee802154_txdesc_s *respdesc;
|
2017-11-01 21:15:21 +01:00
|
|
|
|
FAR struct ieee802154_primitive_s *primitive;
|
2017-06-28 04:01:40 +02:00
|
|
|
|
FAR struct ieee802154_beacon_ind_s *beacon;
|
|
|
|
|
FAR struct iob_s *iob = ind->frame;
|
|
|
|
|
uint8_t ngtsdesc;
|
2017-06-26 00:07:50 +02:00
|
|
|
|
uint8_t gtsdirmask;
|
2017-06-28 04:01:40 +02:00
|
|
|
|
bool pending_saddr = false;
|
|
|
|
|
bool pending_eaddr = false;
|
2017-06-26 00:07:50 +02:00
|
|
|
|
int i;
|
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* Even though we may not use the primitive, we allocate one to hold all
|
|
|
|
|
* the parsed beacon information. Freeing the primitive is quick, so it's
|
2017-11-01 21:15:21 +01:00
|
|
|
|
* worth saving a copy (If you were to parse all the info in locally, you
|
|
|
|
|
* would have to copy the data over in the case that you actually need to
|
|
|
|
|
* notify the next highest layer)
|
2017-06-28 04:01:40 +02:00
|
|
|
|
*/
|
2017-07-03 18:08:49 +02:00
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
primitive = ieee802154_primitive_allocate();
|
|
|
|
|
beacon = &primitive->u.beaconind;
|
2017-06-28 04:01:40 +02:00
|
|
|
|
|
|
|
|
|
/* Make sure there is another 2 bytes to process */
|
|
|
|
|
|
|
|
|
|
if (iob->io_len < iob->io_offset + 2)
|
|
|
|
|
{
|
|
|
|
|
goto errout;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
/* Copy the coordinator address and channel info into the pan descriptor */
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
memcpy(&beacon->pandesc.coordaddr, &ind->src,
|
|
|
|
|
sizeof(struct ieee802154_addr_s));
|
2017-06-28 04:01:40 +02:00
|
|
|
|
beacon->pandesc.chan = priv->currscan.channels[priv->scanindex];
|
|
|
|
|
beacon->pandesc.chpage = priv->currscan.chpage;
|
|
|
|
|
beacon->pandesc.lqi = ind->lqi;
|
|
|
|
|
beacon->pandesc.timestamp = ind->timestamp;
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
|
|
|
|
/* Parse the superframe specification field */
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
beacon->pandesc.sfspec.beaconorder =
|
|
|
|
|
IEEE802154_GETBEACONORDER(iob->io_data, iob->io_offset);
|
2017-06-28 04:01:40 +02:00
|
|
|
|
|
|
|
|
|
beacon->pandesc.sfspec.sforder =
|
|
|
|
|
IEEE802154_GETSFORDER(iob->io_data, iob->io_offset);
|
|
|
|
|
|
|
|
|
|
beacon->pandesc.sfspec.final_capslot =
|
|
|
|
|
IEEE802154_GETFINCAPSLOT(iob->io_data, iob->io_offset);
|
|
|
|
|
|
|
|
|
|
beacon->pandesc.sfspec.ble =
|
|
|
|
|
IEEE802154_GETBLE(iob->io_data, iob->io_offset);
|
|
|
|
|
|
|
|
|
|
beacon->pandesc.sfspec.pancoord =
|
|
|
|
|
IEEE802154_GETPANCOORD(iob->io_data, iob->io_offset);
|
|
|
|
|
|
|
|
|
|
beacon->pandesc.sfspec.assocpermit =
|
|
|
|
|
IEEE802154_GETASSOCPERMIT(iob->io_data, iob->io_offset);
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
|
|
|
|
iob->io_offset += 2;
|
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
/* Make sure there is another byte to process (GTS Spec) */
|
|
|
|
|
|
|
|
|
|
if (iob->io_len < iob->io_offset + 1)
|
|
|
|
|
{
|
|
|
|
|
goto errout;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
/* Parse the GTS Specification field */
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
ngtsdesc =
|
|
|
|
|
IEEE802154_GETGTSDESCCOUNT(iob->io_data, iob->io_offset);
|
|
|
|
|
beacon->pandesc.gtspermit =
|
|
|
|
|
IEEE802154_GETGTSPERMIT(iob->io_data, iob->io_offset);
|
2017-06-26 00:07:50 +02:00
|
|
|
|
iob->io_offset++;
|
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* If there are any GTS descriptors, handle the GTS Dir and List fields */
|
2017-06-28 04:01:40 +02:00
|
|
|
|
|
|
|
|
|
if (ngtsdesc > 0)
|
|
|
|
|
{
|
|
|
|
|
/* Make sure there is another bytes to process (GTS Direction) */
|
|
|
|
|
|
|
|
|
|
if (iob->io_len < iob->io_offset + 1)
|
|
|
|
|
{
|
|
|
|
|
goto errout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gtsdirmask = IEEE802154_GETGTSDIRMASK(iob->io_data, iob->io_offset);
|
2017-06-30 11:26:32 +02:00
|
|
|
|
UNUSED(gtsdirmask);
|
2017-06-28 04:01:40 +02:00
|
|
|
|
iob->io_offset++;
|
|
|
|
|
|
|
|
|
|
/* Make sure there are enough bytes left to represent the GTS List */
|
|
|
|
|
|
|
|
|
|
if (iob->io_len < iob->io_offset + (3 * ngtsdesc))
|
|
|
|
|
{
|
|
|
|
|
goto errout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ngtsdesc; i++)
|
|
|
|
|
{
|
|
|
|
|
/* For now we just discard the data by skipping over it */
|
|
|
|
|
|
|
|
|
|
iob->io_offset += 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pending address fields. Min 1 byte, the Pending Address Specification */
|
|
|
|
|
|
|
|
|
|
if (iob->io_len < iob->io_offset + 1)
|
|
|
|
|
{
|
|
|
|
|
goto errout;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
beacon->pendaddr.nsaddr =
|
|
|
|
|
IEEE802154_GETNPENDSADDR(iob->io_data, iob->io_offset);
|
|
|
|
|
beacon->pendaddr.neaddr =
|
|
|
|
|
IEEE802154_GETNPENDEADDR(iob->io_data, iob->io_offset);
|
2017-06-28 04:01:40 +02:00
|
|
|
|
iob->io_offset++;
|
|
|
|
|
|
|
|
|
|
/* Make sure there are enough bytes left to represent the address list */
|
|
|
|
|
|
|
|
|
|
if (iob->io_len < (iob->io_offset +
|
|
|
|
|
(IEEE802154_SADDRSIZE * beacon->pendaddr.nsaddr) +
|
|
|
|
|
(IEEE802154_EADDRSIZE * beacon->pendaddr.neaddr)))
|
|
|
|
|
{
|
|
|
|
|
goto errout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Copy in the pending addresses */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < beacon->pendaddr.nsaddr; i++)
|
|
|
|
|
{
|
|
|
|
|
beacon->pendaddr.addr[i].mode = IEEE802154_ADDRMODE_SHORT;
|
|
|
|
|
mac802154_takesaddr(iob, beacon->pendaddr.addr[i].saddr);
|
|
|
|
|
|
|
|
|
|
/* Check if the short address matches our short address */
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
if (IEEE802154_SADDRCMP(beacon->pendaddr.addr[i].saddr,
|
|
|
|
|
priv->addr.saddr))
|
2017-06-28 04:01:40 +02:00
|
|
|
|
{
|
|
|
|
|
/* Wait to actually decide how to handle this until we parse
|
|
|
|
|
* the rest of the frame
|
|
|
|
|
*/
|
2020-05-04 19:34:04 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
wlinfo("Data pending for us in coord\n");
|
|
|
|
|
pending_saddr = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = beacon->pendaddr.nsaddr;
|
|
|
|
|
i < (beacon->pendaddr.nsaddr + beacon->pendaddr.neaddr);
|
|
|
|
|
i++)
|
|
|
|
|
{
|
|
|
|
|
beacon->pendaddr.addr[i].mode = IEEE802154_ADDRMODE_EXTENDED;
|
|
|
|
|
|
|
|
|
|
mac802154_takeeaddr(iob, beacon->pendaddr.addr[i].eaddr);
|
|
|
|
|
|
|
|
|
|
/* If the extended address matches our extended address */
|
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
if (IEEE802154_EADDRCMP(beacon->pendaddr.addr[i].eaddr,
|
|
|
|
|
priv->addr.eaddr))
|
2017-06-28 04:01:40 +02:00
|
|
|
|
{
|
|
|
|
|
/* Wait to actually decide how to handle this until we parse
|
|
|
|
|
* the rest of the frame
|
|
|
|
|
*/
|
2020-05-04 19:34:04 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
wlinfo("Data pending for us in coord\n");
|
|
|
|
|
pending_eaddr = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* If there is anything left, process it as the beacon payload */
|
2017-06-28 04:01:40 +02:00
|
|
|
|
|
|
|
|
|
beacon->payloadlength = iob->io_len - iob->io_offset;
|
|
|
|
|
|
|
|
|
|
if (beacon->payloadlength > 0)
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
memcpy(beacon->payload, &iob->io_data[iob->io_offset],
|
|
|
|
|
beacon->payloadlength);
|
2017-06-28 04:01:40 +02:00
|
|
|
|
}
|
2017-07-03 18:08:49 +02:00
|
|
|
|
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* At this point, all relevant info is extracted from the incoming frame */
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_lock(&priv->lock);
|
2017-11-01 21:15:21 +01:00
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
if (priv->curr_op == MAC802154_OP_SCAN)
|
|
|
|
|
{
|
|
|
|
|
/* Check to see if we already have a frame from this coordinator */
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < priv->npandesc; i++)
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
if (priv->currscan.channels[priv->scanindex] !=
|
|
|
|
|
priv->pandescs[i].chan)
|
2017-06-26 00:07:50 +02:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-06-26 19:03:44 +02:00
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
if (memcmp(&ind->src, &priv->pandescs[i].coordaddr,
|
2017-06-28 04:01:40 +02:00
|
|
|
|
sizeof(struct ieee802154_addr_s)) != 0)
|
2017-06-26 00:07:50 +02:00
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The beacon is the same as another, so discard it */
|
2017-06-26 19:03:44 +02:00
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
ieee802154_primitive_free(primitive);
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-06-30 11:26:32 +02:00
|
|
|
|
return;
|
2017-06-26 00:07:50 +02:00
|
|
|
|
}
|
2017-07-03 18:08:49 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* TODO: There is supposed to be different logic for the scanning
|
|
|
|
|
* procedure based on the macAutoRequest attribute. Currently, we
|
|
|
|
|
* perform scan operations as if macAutoRequest is set to TRUE,
|
|
|
|
|
* without actually checking the value. Basically, if macAutoRequest
|
|
|
|
|
* is TRUE, we are supposed to round up all of the pandesc results and
|
|
|
|
|
* pass them all up via the SCAN.confirm primitive. If macAutoRequest
|
|
|
|
|
* is FALSE, we are supposed to notify the next highest layer each
|
|
|
|
|
* time a unique beacon is received via the BEACON.notify primitive,
|
|
|
|
|
* and pass a NULLed out list of pandesc when SCAN.confirm is sent.
|
2017-06-28 04:01:40 +02:00
|
|
|
|
*/
|
2017-07-03 18:08:49 +02:00
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
/* Copy the pan desc to the list of pan desc */
|
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
memcpy(&priv->pandescs[priv->npandesc], &beacon->pandesc,
|
2017-06-26 00:07:50 +02:00
|
|
|
|
sizeof(struct ieee802154_pandesc_s));
|
|
|
|
|
priv->npandesc++;
|
|
|
|
|
|
|
|
|
|
if (priv->npandesc == MAC802154_NPANDESC)
|
|
|
|
|
{
|
|
|
|
|
mac802154_scanfinish(priv, IEEE802154_STATUS_LIMITREACHED);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-28 04:01:40 +02:00
|
|
|
|
|
|
|
|
|
/* If we are not performing a SCAN operation */
|
|
|
|
|
|
2017-06-26 00:07:50 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2020-05-04 19:34:04 +02:00
|
|
|
|
/* Check superframe structure and update the appropriate attributes. */
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
if (memcmp(&priv->sfspec, &beacon->pandesc.sfspec,
|
|
|
|
|
sizeof(struct ieee802154_superframespec_s)) != 0)
|
2017-06-26 00:07:50 +02:00
|
|
|
|
{
|
2017-06-28 04:01:40 +02:00
|
|
|
|
/* Copy in the new superframe spec */
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
memcpy(&priv->sfspec, &beacon->pandesc.sfspec,
|
|
|
|
|
sizeof(struct ieee802154_superframespec_s));
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
/* Tell the radio layer about the superframe spec update */
|
|
|
|
|
|
|
|
|
|
priv->radio->sfupdate(priv->radio, &priv->sfspec);
|
2017-06-26 00:07:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
/* If we are performing an association and there is data pending for us
|
|
|
|
|
* we ignore the autoRequest logic and just extract it. We also don't
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* send a BEACON-NOTFIY.indication in this case, not sure if that is
|
|
|
|
|
* the right thing to do, can't find anything definitive in standard.
|
2017-06-28 04:01:40 +02:00
|
|
|
|
*/
|
2017-07-03 18:08:49 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
if (priv->curr_op == MAC802154_OP_ASSOC && pending_eaddr)
|
|
|
|
|
{
|
|
|
|
|
priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
|
2022-09-06 08:18:45 +02:00
|
|
|
|
mac802154_txdesc_alloc(priv, &respdesc);
|
2017-06-28 04:01:40 +02:00
|
|
|
|
mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
|
|
|
|
|
IEEE802154_ADDRMODE_EXTENDED, respdesc);
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
/* Link the transaction into the CSMA transaction list */
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
sq_addlast((FAR sq_entry_t *)respdesc, &priv->csma_queue);
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
/* Notify the radio driver that there is data available */
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
priv->radio->txnotify(priv->radio, false);
|
2017-06-26 00:07:50 +02:00
|
|
|
|
}
|
2017-06-28 04:01:40 +02:00
|
|
|
|
else
|
2017-06-26 00:07:50 +02:00
|
|
|
|
{
|
2017-06-30 11:26:32 +02:00
|
|
|
|
if (priv->autoreq || priv->curr_op == MAC802154_OP_POLL)
|
2017-06-28 04:01:40 +02:00
|
|
|
|
{
|
2017-06-30 11:26:32 +02:00
|
|
|
|
/* If a beacon frame is received and macAutoRequest is set to
|
|
|
|
|
* TRUE, the MLME shall first issue the MLME-
|
2020-05-04 19:34:04 +02:00
|
|
|
|
* BEACON-NOTIFY.indication primitive if the beacon contains
|
|
|
|
|
* any payload.
|
2017-06-30 11:26:32 +02:00
|
|
|
|
*/
|
2017-07-03 18:08:49 +02:00
|
|
|
|
|
2017-06-30 11:26:32 +02:00
|
|
|
|
if (beacon->payloadlength > 0)
|
2017-06-26 00:07:50 +02:00
|
|
|
|
{
|
2017-11-01 21:15:21 +01:00
|
|
|
|
mac802154_notify(priv, primitive);
|
2017-06-28 04:01:40 +02:00
|
|
|
|
}
|
2017-06-30 11:26:32 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* If we have data pending for us, attempt to extract it. If
|
|
|
|
|
* for some reason we have data pending under our short
|
|
|
|
|
* address and our extended address, let the short address
|
|
|
|
|
* arbitrarily take precedence
|
2017-06-30 11:26:32 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (pending_saddr | pending_eaddr)
|
2017-06-28 04:01:40 +02:00
|
|
|
|
{
|
2022-09-06 08:18:45 +02:00
|
|
|
|
mac802154_txdesc_alloc(priv, &respdesc);
|
2017-06-30 11:26:32 +02:00
|
|
|
|
|
|
|
|
|
if (priv->curr_op == MAC802154_OP_POLL)
|
|
|
|
|
{
|
|
|
|
|
priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
|
|
|
|
|
}
|
2017-07-13 23:56:31 +02:00
|
|
|
|
else if (priv->curr_op == MAC802154_OP_ASSOC)
|
|
|
|
|
{
|
|
|
|
|
priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
|
|
|
|
|
}
|
2017-06-30 11:26:32 +02:00
|
|
|
|
else if (priv->curr_op == MAC802154_OP_NONE)
|
|
|
|
|
{
|
|
|
|
|
DEBUGASSERT(priv->opsem.semcount == 1);
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxsem_wait_uninterruptible(&priv->opsem);
|
2017-06-30 11:26:32 +02:00
|
|
|
|
priv->curr_op = MAC802154_OP_AUTOEXTRACT;
|
|
|
|
|
priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pending_saddr)
|
|
|
|
|
{
|
|
|
|
|
mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
|
2019-02-27 15:41:08 +01:00
|
|
|
|
IEEE802154_ADDRMODE_SHORT,
|
|
|
|
|
respdesc);
|
2017-06-30 11:26:32 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
|
2019-02-27 15:41:08 +01:00
|
|
|
|
IEEE802154_ADDRMODE_EXTENDED,
|
|
|
|
|
respdesc);
|
2017-06-30 11:26:32 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Link the transaction into the CSMA transaction list */
|
|
|
|
|
|
|
|
|
|
sq_addlast((FAR sq_entry_t *)respdesc, &priv->csma_queue);
|
|
|
|
|
|
|
|
|
|
/* Notify the radio driver that there is data available */
|
|
|
|
|
|
|
|
|
|
priv->radio->txnotify(priv->radio, false);
|
2017-06-28 04:01:40 +02:00
|
|
|
|
}
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* If there was a beacon payload, we used the primitive, so
|
|
|
|
|
* return here to make sure we don't free the primitive.
|
|
|
|
|
*/
|
2017-07-03 18:08:49 +02:00
|
|
|
|
|
2019-02-27 15:41:08 +01:00
|
|
|
|
if (beacon->payloadlength > 0)
|
|
|
|
|
{
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2019-02-27 15:41:08 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-06-30 11:26:32 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-02-27 15:41:08 +01:00
|
|
|
|
/* If a valid beacon frame is received and macAutoRequest is
|
|
|
|
|
* set to FALSE, the MLME shall indicate the beacon parameters
|
|
|
|
|
* to the next higher layer by issuing the
|
|
|
|
|
* MLME-BEACON-NOTIFY.indication primitive. [1] pg. 38
|
2017-06-30 11:26:32 +02:00
|
|
|
|
*/
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
mac802154_notify(priv, primitive);
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-01 21:15:21 +01:00
|
|
|
|
return; /* Return so that we don't free the primitive */
|
2017-06-26 00:07:50 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-28 04:01:40 +02:00
|
|
|
|
}
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_unlock(&priv->lock);
|
2017-11-01 21:15:21 +01:00
|
|
|
|
ieee802154_primitive_free(primitive);
|
2017-06-28 04:01:40 +02:00
|
|
|
|
return;
|
2017-06-26 00:07:50 +02:00
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
errout:
|
|
|
|
|
wlwarn("Received beacon with bad format\n");
|
2017-11-01 21:15:21 +01:00
|
|
|
|
ieee802154_primitive_free(primitive);
|
2017-06-26 00:07:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
/****************************************************************************
|
2017-06-14 08:49:27 +02:00
|
|
|
|
* Public Functions
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
* Name: mac802154_create
|
|
|
|
|
*
|
|
|
|
|
* Description:
|
|
|
|
|
* Create a 802.15.4 MAC device from a 802.15.4 compatible radio device.
|
|
|
|
|
*
|
|
|
|
|
* The returned MAC structure should be passed to either the next highest
|
|
|
|
|
* layer in the network stack, or registered with a mac802154dev character
|
|
|
|
|
* or network drivers. In any of these scenarios, the next highest layer
|
|
|
|
|
* should register a set of callbacks with the MAC layer by setting the
|
|
|
|
|
* mac->cbs member.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: This API does not create any device accessible to userspace. If
|
|
|
|
|
* you want to call these APIs from userspace, you have to wrap your mac
|
|
|
|
|
* in a character device via mac802154_device.c.
|
|
|
|
|
*
|
|
|
|
|
* Input Parameters:
|
|
|
|
|
* radiodev - an instance of an IEEE 802.15.4 radio
|
|
|
|
|
*
|
|
|
|
|
* Returned Value:
|
|
|
|
|
* An opaque reference to the MAC state data.
|
|
|
|
|
*
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev)
|
|
|
|
|
{
|
|
|
|
|
FAR struct ieee802154_privmac_s *mac;
|
|
|
|
|
FAR struct ieee802154_radiocb_s *radiocb;
|
|
|
|
|
|
|
|
|
|
/* Allocate object */
|
|
|
|
|
|
|
|
|
|
mac = (FAR struct ieee802154_privmac_s *)
|
|
|
|
|
kmm_zalloc(sizeof(struct ieee802154_privmac_s));
|
|
|
|
|
|
|
|
|
|
if (mac == NULL)
|
2017-05-16 03:44:51 +02:00
|
|
|
|
{
|
2017-06-28 04:01:40 +02:00
|
|
|
|
wlinfo("Failed allocation privmac structure\n");
|
2017-06-03 00:49:22 +02:00
|
|
|
|
return NULL;
|
2017-05-16 03:44:51 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
/* Allow exclusive access to the privmac struct */
|
|
|
|
|
|
2022-09-06 08:18:45 +02:00
|
|
|
|
nxmutex_init(&mac->lock);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
|
|
|
|
/* Allow exclusive access to the dedicated command transaction */
|
|
|
|
|
|
2017-10-03 20:51:15 +02:00
|
|
|
|
nxsem_init(&mac->opsem, 0, 1);
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
|
|
|
|
/* Initialize fields */
|
|
|
|
|
|
|
|
|
|
mac->radio = radiodev;
|
|
|
|
|
|
|
|
|
|
/* Initialize the Radio callbacks */
|
|
|
|
|
|
|
|
|
|
mac->radiocb.priv = mac;
|
|
|
|
|
|
|
|
|
|
radiocb = &mac->radiocb.cb;
|
2017-06-17 20:50:25 +02:00
|
|
|
|
radiocb->poll = mac802154_radiopoll;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
radiocb->txdone = mac802154_txdone;
|
|
|
|
|
radiocb->rxframe = mac802154_rxframe;
|
2017-06-20 18:57:24 +02:00
|
|
|
|
radiocb->sfevent = mac802154_sfevent;
|
2019-08-10 19:03:24 +02:00
|
|
|
|
radiocb->edresult = mac802154_edresult;
|
2017-06-03 00:49:22 +02:00
|
|
|
|
|
|
|
|
|
/* Bind our callback structure */
|
|
|
|
|
|
|
|
|
|
radiodev->bind(radiodev, &mac->radiocb.cb);
|
|
|
|
|
|
|
|
|
|
/* Initialize our various data pools */
|
|
|
|
|
|
2017-11-01 21:15:21 +01:00
|
|
|
|
ieee802154_primitivepool_initialize();
|
2017-06-03 00:49:22 +02:00
|
|
|
|
mac802154_resetqueues(mac);
|
|
|
|
|
|
2017-06-28 04:01:40 +02:00
|
|
|
|
mac802154_req_reset((MACHANDLE)mac, true);
|
|
|
|
|
|
2017-06-03 00:49:22 +02:00
|
|
|
|
return (MACHANDLE)mac;
|
|
|
|
|
}
|