ieee802154: Finishes beacon association functionality

This commit is contained in:
Anthony Merlino 2017-06-27 22:01:40 -04:00
parent 6b17d5ccc9
commit b981ced4d4
5 changed files with 2590 additions and 2388 deletions

File diff suppressed because it is too large Load Diff

View File

@ -593,19 +593,10 @@ struct ieee802154_pandesc_s
* in symbols */
};
struct ieee802154_pend_addr_s
struct ieee802154_pendaddr_s
{
union
{
uint8_t pa_spec;
struct
{
uint8_t num_short_addr : 3; /* Number of short addresses pending */
uint8_t reserved_3 : 1; /* Reserved bit */
uint8_t num_ext_addr : 3; /* Number of extended addresses pending */
uint8_t reserved_7 : 1; /* Reserved bit */
} pa_addr;
} u;
uint8_t nsaddr : 3; /* Number of short addresses pending */
uint8_t neaddr : 3; /* Number of extended addresses pending */
struct ieee802154_addr_s addr[7]; /* Array of at most 7 addresses */
};
@ -632,7 +623,7 @@ union ieee802154_macattr_u
bool is_assoc;
bool assocpermit;
bool auto_req;
bool autoreq;
bool batt_life_ext;
bool gts_permit;
bool promisc_mode;
@ -1112,7 +1103,7 @@ struct ieee802154_disassoc_conf_s
*
*****************************************************************************/
struct ieee802154_beaconnotify_ind_s
struct ieee802154_beacon_ind_s
{
uint8_t bsn; /* Beacon sequence number */
@ -1122,20 +1113,11 @@ struct ieee802154_beaconnotify_ind_s
/* Beacon pending addresses */
struct ieee802154_pend_addr_s pend_addr;
uint8_t sdu_length; /* Number of octets contained in the beacon
* payload of the received beacond frame */
/* Beacon payload */
uint8_t sdu[IEEE802154_MAX_BEACON_PAYLOAD_LEN];
struct ieee802154_pendaddr_s pendaddr;
uint8_t payloadlength; /* # of octets contained in the beacon payload */
uint8_t payload[IEEE802154_MAX_BEACON_PAYLOAD_LEN];
};
#define SIZEOF_IEEE802154_BEACONNOTIFY_IND_S(n) \
(sizeof(struct ieee802154_beaconnotify_ind_s) \
- IEEE802154_MAX_BEACON_PAYLOAD_LEN + (n))
/*****************************************************************************
* Primitive: MLME-COMM-STATUS.indication
*
@ -1538,21 +1520,21 @@ union ieee802154_notif_u
/* MLME Notifications */
struct ieee802154_assoc_conf_s assocconf;
struct ieee802154_disassoc_conf_s disassocconf;
struct ieee802154_gts_conf_s gtsconf;
struct ieee802154_rxenable_conf_s rxenableconf;
struct ieee802154_scan_conf_s scanconf;
struct ieee802154_start_conf_s startconf;
struct ieee802154_poll_conf_s pollconf;
struct ieee802154_assoc_conf_s assocconf;
struct ieee802154_disassoc_conf_s disassocconf;
struct ieee802154_gts_conf_s gtsconf;
struct ieee802154_rxenable_conf_s rxenableconf;
struct ieee802154_scan_conf_s scanconf;
struct ieee802154_start_conf_s startconf;
struct ieee802154_poll_conf_s pollconf;
struct ieee802154_assoc_ind_s assocind;
struct ieee802154_disassoc_ind_s disassocind;
struct ieee802154_beaconnotify_ind_s beaconnotifyind;
struct ieee802154_gts_ind_s gtsind;
struct ieee802154_orphan_ind_s orphanind;
struct ieee802154_commstatus_ind_s commstatusind;
struct ieee802154_syncloss_ind_s synclossind;
struct ieee802154_assoc_ind_s assocind;
struct ieee802154_disassoc_ind_s disassocind;
struct ieee802154_beacon_ind_s beaconind;
struct ieee802154_gts_ind_s gtsind;
struct ieee802154_orphan_ind_s orphanind;
struct ieee802154_commstatus_ind_s commstatusind;
struct ieee802154_syncloss_ind_s synclossind;
};
struct ieee802154_notif_s

View File

@ -1528,51 +1528,181 @@ static void mac802154_sfevent(FAR const struct ieee802154_radiocb_s *radiocb,
* Function called from the generic RX Frame worker to parse and handle the
* reception of a beacon frame.
*
* Assumptions: MAC is locked
*
****************************************************************************/
static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv,
FAR struct ieee802154_data_ind_s *ind)
{
FAR struct iob_s *iob = ind->frame;
struct ieee802154_pandesc_s pandesc;
FAR struct ieee802154_txdesc_s *respdesc;
uint8_t numgtsdesc;
FAR struct ieee802154_notif_s *notif;
FAR struct ieee802154_beacon_ind_s *beacon;
FAR struct iob_s *iob = ind->frame;
uint8_t ngtsdesc;
uint8_t gtsdirmask;
uint8_t npendsaddr;
uint8_t npendeaddr;
bool pending_saddr = false;
bool pending_eaddr = false;
int i;
/* Even though we may not use the notification, we use a notification to
* hold all the parsed beacon information. Freeing the notification is quick,
* so it's 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)
*/
mac802154_notif_alloc(priv, &notif, false);
beacon = &notif->u.beaconind;
/* Make sure there is another 2 bytes to process */
if (iob->io_len < iob->io_offset + 2)
{
goto errout;
}
/* Copy the coordinator address and channel info into the pan descriptor */
memcpy(&pandesc.coordaddr, &ind->src, sizeof(struct ieee802154_addr_s));
pandesc.chan = priv->currscan.channels[priv->scanindex];
pandesc.chpage = priv->currscan.chpage;
pandesc.lqi = ind->lqi;
pandesc.timestamp = ind->timestamp;
memcpy(&beacon->pandesc.coordaddr, &ind->src, sizeof(struct ieee802154_addr_s));
beacon->pandesc.chan = priv->currscan.channels[priv->scanindex];
beacon->pandesc.chpage = priv->currscan.chpage;
beacon->pandesc.lqi = ind->lqi;
beacon->pandesc.timestamp = ind->timestamp;
/* Parse the superframe specification field */
pandesc.sfspec.beaconorder = IEEE802154_GETBEACONORDER(iob->io_data,
iob->io_offset);
beacon->pandesc.sfspec.beaconorder = IEEE802154_GETBEACONORDER(iob->io_data,
iob->io_offset);
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);
pandesc.sfspec.sforder = IEEE802154_GETSFORDER(iob->io_data, iob->io_offset);
pandesc.sfspec.final_capslot = IEEE802154_GETFINCAPSLOT(iob->io_data,
iob->io_offset);
pandesc.sfspec.ble = IEEE802154_GETBLE(iob->io_data, iob->io_offset);
pandesc.sfspec.pancoord = IEEE802154_GETPANCOORD(iob->io_data, iob->io_offset);
pandesc.sfspec.assocpermit = IEEE802154_GETASSOCPERMIT(iob->io_data,
iob->io_offset);
iob->io_offset += 2;
/* Make sure there is another byte to process (GTS Spec) */
if (iob->io_len < iob->io_offset + 1)
{
goto errout;
}
/* Parse the GTS Specification field */
numgtsdesc = IEEE802154_GETGTSDESCCOUNT(iob->io_data, iob->io_offset);
pandesc.gtspermit = IEEE802154_GETGTSPERMIT(iob->io_data, iob->io_offset);
ngtsdesc = IEEE802154_GETGTSDESCCOUNT(iob->io_data, iob->io_offset);
beacon->pandesc.gtspermit = IEEE802154_GETGTSPERMIT(iob->io_data, iob->io_offset);
iob->io_offset++;
/* We only need to parse the rest of the frame if we are not performing a
* scan
*/
/* If there are any GTS descriptors, handle the GTS Dir and GTS List fields */
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);
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;
}
beacon->pendaddr.nsaddr = IEEE802154_GETNPENDSADDR(iob->io_data, iob->io_offset);
beacon->pendaddr.neaddr = IEEE802154_GETNPENDEADDR(iob->io_data, iob->io_offset);
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 */
if (IEEE802154_SADDRCMP(beacon->pendaddr.addr[i].saddr, priv->addr.saddr))
{
/* Wait to actually decide how to handle this until we parse
* the rest of the frame
*/
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 */
if (IEEE802154_EADDRCMP(beacon->pendaddr.addr[i].eaddr, priv->addr.eaddr))
{
/* Wait to actually decide how to handle this until we parse
* the rest of the frame
*/
wlinfo("Data pending for us in coord\n");
pending_eaddr = true;
}
}
/* If there is anything left in the frame, process it as the beacon payload */
beacon->payloadlength = iob->io_len - iob->io_offset;
if (beacon->payloadlength > 0)
{
memcpy(beacon->payload, &iob->io_data[iob->io_offset], beacon->payloadlength);
}
/* At this point, we have extracted all relevant info from the incoming frame */
if (priv->curr_op == MAC802154_OP_SCAN)
{
@ -1586,19 +1716,30 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv,
}
if (memcmp(&ind->src, &priv->pandescs[i].coordaddr,
sizeof(struct ieee802154_addr_s)))
sizeof(struct ieee802154_addr_s)) != 0)
{
continue;
}
/* The beacon is the same as another, so discard it */
return;
goto done;
}
/* 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.
*/
/* Copy the pan desc to the list of pan desc */
memcpy(&priv->pandescs[priv->npandesc], &pandesc,
memcpy(&priv->pandescs[priv->npandesc], &beacon->pandesc,
sizeof(struct ieee802154_pandesc_s));
priv->npandesc++;
@ -1607,101 +1748,116 @@ static void mac802154_rxbeaconframe(FAR struct ieee802154_privmac_s *priv,
mac802154_scanfinish(priv, IEEE802154_STATUS_LIMITREACHED);
}
}
/* If we are not performing a SCAN operation */
else
{
/* If there are any GTS descriptors, handle the GTS Directions and
* GTS List fields
*/
if (numgtsdesc > 0)
{
gtsdirmask = IEEE802154_GETGTSDIRMASK(iob->io_data, iob->io_offset);
iob->io_offset++;
for (i = 0; i < numgtsdesc; 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 */
npendsaddr = IEEE802154_GETNPENDSADDR(iob->io_data, iob->io_offset);
npendeaddr = IEEE802154_GETNPENDEADDR(iob->io_data, iob->io_offset);
iob->io_offset++;
/* The pending address field tells us whether or not there is any data
* pending for us.
*/
for (i = 0; i < npendsaddr; i++)
{
/* If the short address matches our short address */
if (IEEE802154_SADDRCMP(&iob->io_data[iob->io_offset], priv->addr.saddr))
{
/* TODO: Handle data pending in coordinator for us */
}
iob->io_offset += IEEE802154_SADDRSIZE;
}
for (i = 0; i < npendeaddr; i++)
{
/* If the extended address matches our extended address */
if (IEEE802154_EADDRCMP(&iob->io_data[iob->io_offset], priv->addr.eaddr))
{
/* If we are associating, polling, or if macAutoRequest is TRUE,
* extract the data.
*/
if ((priv->autoreq) || (priv->curr_op == MAC802154_OP_ASSOC) ||
(priv->curr_op == MAC802154_OP_POLL))
{
mac802154_txdesc_alloc(priv, &respdesc, false);
mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
IEEE802154_ADDRMODE_EXTENDED, respdesc);
if (priv->curr_op == MAC802154_OP_ASSOC ||
priv->curr_op == MAC802154_OP_POLL)
{
priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
}
/* 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);
}
}
iob->io_offset += IEEE802154_EADDRSIZE;
}
/* TODO: Process incoming beacon payload
* If there is anything left in the frame, process it as the beacon payload
*/
/* Check the superframe structure and update the appropriate attributes. */
if (memcmp(&priv->sfspec, &pandesc.sfspec,
sizeof(struct ieee802154_superframespec_s)) != 0)
if (memcmp(&priv->sfspec, &beacon->pandesc.sfspec,
sizeof(struct ieee802154_superframespec_s)) != 0)
{
/* Copy in the new superframe spec */
memcpy(&priv->sfspec, &pandesc.sfspec,
sizeof(struct ieee802154_superframespec_s));
memcpy(&priv->sfspec, &beacon->pandesc.sfspec,
sizeof(struct ieee802154_superframespec_s));
/* Tell the radio layer about the superframe spec update */
priv->radio->sfupdate(priv->radio, &pandesc.sfspec);
priv->radio->sfupdate(priv->radio, &priv->sfspec);
}
/* 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
* 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.
*/
if (priv->curr_op == MAC802154_OP_ASSOC && pending_eaddr)
{
priv->curr_cmd = IEEE802154_CMD_DATA_REQ;
mac802154_txdesc_alloc(priv, &respdesc, false);
mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
IEEE802154_ADDRMODE_EXTENDED, respdesc);
/* 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);
}
else if (!priv->autoreq)
{
/* 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
*/
/* Unlock the MAC, notify, then lock again */
mac802154_givesem(&priv->exclsem);
mac802154_notify(priv, notif);
mac802154_takesem(&priv->exclsem, false);
return; /* Return so that we don't free the notificaiton */
}
else
{
/* If a beacon frame is received and macAutoRequest is set to TRUE, the
* MLME shall first issue the MLME- BEACON-NOTIFY.indication primitive if
* the beacon contains any payload.
*/
if (beacon->payloadlength > 0)
{
/* Unlock the MAC, notify, then lock again */
mac802154_givesem(&priv->exclsem);
mac802154_notify(priv, notif);
mac802154_takesem(&priv->exclsem, false);
return; /* Return so that we don't free the notificaiton */
}
/* 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
*/
if (pending_saddr | pending_eaddr)
{
mac802154_txdesc_alloc(priv, &respdesc, false);
if (pending_saddr)
{
mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
IEEE802154_ADDRMODE_SHORT, respdesc);
}
else
{
mac802154_createdatareq(priv, &priv->pandesc.coordaddr,
IEEE802154_ADDRMODE_EXTENDED, respdesc);
}
/* 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);
}
}
}
done:
mac802154_notif_free_locked(priv, notif);
return;
errout:
wlwarn("Received beacon with bad format\n");
mac802154_notif_free_locked(priv, notif);
}
/****************************************************************************
@ -1864,6 +2020,7 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev)
if (mac == NULL)
{
wlinfo("Failed allocation privmac structure\n");
return NULL;
}
@ -1883,8 +2040,6 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev)
mac->radio = radiodev;
mac802154_req_reset((MACHANDLE)mac, true);
/* Initialize the Radio callbacks */
mac->radiocb.priv = mac;
@ -1904,16 +2059,16 @@ MACHANDLE mac802154_create(FAR struct ieee802154_radio_s *radiodev)
ieee802154_indpool_initialize();
mac802154_resetqueues(mac);
mac802154_req_reset((MACHANDLE)mac, true);
/* Set the default extended address */
for (i = 0; i < IEEE802154_EADDRSIZE; i++)
{
eaddr[i] = (CONFIG_IEEE802154_DEFAULT_EADDR >> (8 * i)) & 0xFF;
}
IEEE802154_EADDRCOPY(mac->addr.eaddr, eaddr);
mac->radio->setattr(mac->radio, IEEE802154_ATTR_MAC_EADDR,
(union ieee802154_attr_u *)&eaddr[0]);
mac802154_seteaddr(mac, eaddr);
return (MACHANDLE)mac;
}

View File

@ -88,6 +88,7 @@ int mac802154_req_associate(MACHANDLE mac,
FAR struct iob_s *iob;
bool rxonidle;
int ret;
int i;
if (req->coordaddr.mode == IEEE802154_ADDRMODE_NONE)
{
@ -248,14 +249,68 @@ int mac802154_req_associate(MACHANDLE mac,
priv->cmd_desc = txdesc;
/* Search the list of PAN descriptors, that would have been populated by the
* latest scan procedure. If we have seen a beacon from the coordinator that
* we are about to associate with, we can check the beacon order to determine
* whether we can send the command during the CAP. If we haven't received
* a beacon frame from the desired coordinator address, we have to just
* send the frame out immediately.
*/
for (i = 0; i < priv->npandesc; i++)
{
/* Check to make sure the beacon is from the same channel as the request */
if (req->chan != priv->pandescs[i].chan)
{
continue;
}
if (memcmp(&req->coordaddr, &priv->pandescs[i].coordaddr,
sizeof(struct ieee802154_addr_s)) == 0)
{
wlinfo("Found matching beacon to use for settings\n");
/* We have a beacon frame from this coordinator, we can set the
* sfspec and send accordingly.
*/
/* Copy in the new superframe spec */
memcpy(&priv->sfspec, &priv->pandescs[i].sfspec,
sizeof(struct ieee802154_superframespec_s));
/* Tell the radio layer about the superframe spec update */
priv->radio->sfupdate(priv->radio, &priv->pandescs[i].sfspec);
}
}
if (priv->sfspec.beaconorder == 15)
{
wlinfo("Transmitting assoc request\n");
/* Association Request command gets sent out immediately */
priv->radio->txdelayed(priv->radio, txdesc, 0);
}
else
{
wlinfo("Queuing assoc request for CAP\n");
/* Link the transaction into the CSMA transaction list */
sq_addlast((FAR sq_entry_t *)txdesc, &priv->csma_queue);
/* Notify the radio driver that there is data available */
priv->radio->txnotify(priv->radio, false);
}
/* We no longer need to have the MAC layer locked. */
mac802154_givesem(&priv->exclsem);
/* Association Request command gets sent out immediately */
priv->radio->txdelayed(priv->radio, txdesc, 0);
return OK;
}

View File

@ -173,8 +173,8 @@ static void macnet_ind_associate(FAR struct macnet_driver_s *priv,
FAR struct ieee802154_assoc_ind_s *conf);
static void macnet_ind_disassociate(FAR struct macnet_driver_s *priv,
FAR struct ieee802154_disassoc_ind_s *conf);
static void macnet_ind_beaconnotify(FAR struct macnet_driver_s *priv,
FAR struct ieee802154_beaconnotify_ind_s *conf);
static void macnet_ind_beacon(FAR struct macnet_driver_s *priv,
FAR struct ieee802154_beacon_ind_s *conf);
static void macnet_ind_gts(FAR struct macnet_driver_s *priv,
FAR struct ieee802154_gts_ind_s *conf);
static void macnet_ind_orphan(FAR struct macnet_driver_s *priv,
@ -589,15 +589,15 @@ static void macnet_ind_disassociate(FAR struct macnet_driver_s *priv,
}
/****************************************************************************
* Name: macnet_ind_beaconnotify
* Name: macnet_ind_beacon
*
* Description:
* Beacon notification
*
****************************************************************************/
static void macnet_ind_beaconnotify(FAR struct macnet_driver_s *priv,
FAR struct ieee802154_beaconnotify_ind_s *ind)
static void macnet_ind_beacon(FAR struct macnet_driver_s *priv,
FAR struct ieee802154_beacon_ind_s *ind)
{
}