From 8afeb5249c8a330213902e4e17a27525b0e5d6e0 Mon Sep 17 00:00:00 2001 From: Alberto Gallegos Ramonet Date: Fri, 3 Mar 2023 12:06:01 +0900 Subject: [PATCH] lr-wpan: Orphan scan support --- CHANGES.md | 2 + RELEASE_NOTES.md | 2 + src/lr-wpan/doc/lr-wpan.rst | 11 +- src/lr-wpan/examples/CMakeLists.txt | 1 + src/lr-wpan/examples/lr-wpan-orphan-scan.cc | 215 ++++++++++++ src/lr-wpan/model/lr-wpan-csmaca.cc | 4 +- src/lr-wpan/model/lr-wpan-mac-pl-headers.cc | 77 ++++- src/lr-wpan/model/lr-wpan-mac-pl-headers.h | 70 +++- src/lr-wpan/model/lr-wpan-mac.cc | 360 +++++++++++++++++--- src/lr-wpan/model/lr-wpan-mac.h | 122 +++++-- src/lr-wpan/test/lr-wpan-mac-test.cc | 228 +++++++++++-- 11 files changed, 994 insertions(+), 98 deletions(-) create mode 100644 src/lr-wpan/examples/lr-wpan-orphan-scan.cc diff --git a/CHANGES.md b/CHANGES.md index 6f4e46cb4..0afc469d8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,8 @@ Changes from ns-3.38 to ns-3-dev ### New API +* (lr-wpan) Added support for orphan scans. Orphan scans can now be performed using the existing `LrWpanMac::MlmeScanRequest`; This orphan scan use the added orphan notification commands and coordinator realigment commands. Usage is shown in added `lr-wpan-orphan-scan.cc` example and in the `TestOrphanScan` included in `lr-wpan-mac-test.cc`. + ### Changes to existing API * (dsr) The spelling of the class `DsrOptionRerrUnsupportHeader` from `dsr-option-header.h` was corrected to `DsrOptionRerrUnsupportedHeader`; this will affect existing users who were using the class with the misspelling. diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 50e27ffcf..e99d528ed 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -20,6 +20,8 @@ Release 3-dev ### New user-visible features +- (lr-wpan) !1399 - Add orphan scan support. + ### Bugs fixed Release 3.38 diff --git a/src/lr-wpan/doc/lr-wpan.rst b/src/lr-wpan/doc/lr-wpan.rst index a94300d2f..25d2bee6b 100644 --- a/src/lr-wpan/doc/lr-wpan.rst +++ b/src/lr-wpan/doc/lr-wpan.rst @@ -155,11 +155,11 @@ IEEE 802.15.4 supports 4 types of scanning: * *Energy Detection (ED) Scan:* In an energy scan, a device or a coordinator scan a set number of channels looking for traces of energy. The maximum energy registered during a given amount of time is stored. Energy scan is typically used to measure the quality of a channel at any given time. For this reason, coordinators often use this scan before initiating a PAN on a channel. -* *Active Scan:* A device sends beacon requests on a set number of channels looking for a PAN coordinator. The receiving coordinator must be configured on non-beacon mode. Coordinators on beacon-mode ignore these requests. The coordinators who accept the request, respond with a beacon. After an active scan take place, during the association process devices extract the information in the PAN descriptors from the collected beacons and based on this information (e.g. channel, LQI level), choose a coordinator to associate with. +* *Active Scan:* A device sends ``beacon request commands`` on a set number of channels looking for a PAN coordinator. The receiving coordinator must be configured on non-beacon mode. Coordinators on beacon-mode ignore these requests. The coordinators who accept the request, respond with a beacon. After an active scan take place, during the association process devices extract the information in the PAN descriptors from the collected beacons and based on this information (e.g. channel, LQI level), choose a coordinator to associate with. -* *Passive Scan:* In a passive scan, no beacon requests are sent. Devices scan a set number of channels looking for beacons currently being transmitted (coordinators in beacon-mode). Like in the active scan, the information from beacons is stored in PAN descriptors and used by the device to choose a coordinator to associate with. +* *Passive Scan:* In a passive scan, no ``beacon requests commands`` are sent. Devices scan a set number of channels looking for beacons currently being transmitted (coordinators in beacon-mode). Like in the active scan, the information from beacons is stored in PAN descriptors and used by the device to choose a coordinator to associate with. -* *Orphan Scan:* +* *Orphan Scan:* Orphan scan is used typically by device as a result of repeated communication failure attempts with a coordinator. In other words, an orphan scan represents the intent of a device to relocate its coordinator. In some situations, it can be used by devices higher layers to not only rejoin a network but also join a network for the first time. In an orphan scan, a device send a ``orphan notification command`` to a given list of channels. If a coordinator receives this notification, it responds to the device with a ``coordinator realignment command``. In active and passive scans, the link quality indicator (LQI) is the main parameter used to determine the optimal coordinator. LQI values range from 0 to 255. Where 255 is the highest quality link value and 0 the lowest. Typically, a link lower than 127 is considered a link with poor quality. @@ -315,7 +315,7 @@ running on both, slotted and unslotted mode (CSMA/CA) of 802.15.4 operation for - The standard describes the support of multiple PHY band-modulations but currently, only 250kbps O-QPSK (channel page 0) is supported. - Active and passive MAC scans are able to obtain a LQI value from a beacon frame, however, the scan primitives assumes LQI is correctly implemented and does not check the validity of its value. - Configuration of the ED thresholds are currently not supported. -- Orphan scans are not supported. +- Coordinator realignment command is only supported in orphan scans. - Disassociation primitives are not supported. - Security is not supported. - Beacon enabled mode GTS are not supported. @@ -324,8 +324,10 @@ References ========== * Wireless Medium Access Control (MAC) and Physical Layer (PHY) Specifications for Low-Rate Wireless Personal Area Networks (WPANs), IEEE Computer Society, IEEE Std 802.15.4-2006, 8 September 2006. +* IEEE Standard for Local and metropolitan area networks--Part 15.4: Low-Rate Wireless Personal Area Networks (LR-WPANs)," in IEEE Std 802.15.4-2011 (Revision of IEEE Std 802.15.4-2006) , vol., no., pp.1-314, 5 Sept. 2011, doi: 10.1109/IEEESTD.2011.6012487. * J. Zheng and Myung J. Lee, "A comprehensive performance study of IEEE 802.15.4," Sensor Network Operations, IEEE Press, Wiley Interscience, Chapter 4, pp. 218-237, 2006. * Alberto Gallegos Ramonet and Taku Noguchi. 2020. LR-WPAN: Beacon Enabled Direct Transmissions on Ns-3. In 2020 the 6th International Conference on Communication and Information Processing (ICCIP 2020). Association for Computing Machinery, New York, NY, USA, 115–122. https://doi.org/10.1145/3442555.3442574. +* Gallegos Ramonet, A.; Noguchi, T. Performance Analysis of IEEE 802.15.4 Bootstrap Process. Electronics 2022, 11, 4090. https://doi.org/10.3390/electronics11244090. Usage ***** @@ -362,6 +364,7 @@ The following examples have been written, which can be found in ``src/lr-wpan/ex * ``lr-wpan-active-scan.cc``: A simple example showing the use of an active scan in the MAC. * ``lr-wpan-mlme.cc``: Demonstrates the use of lr-wpan beacon mode. Nodes use a manual association (i.e. No bootstrap) in this example. * ``lr-wpan-bootstrap.cc``: Demonstrates the use of scanning and association working together to initiate a PAN. +* ``lr-wpan-orphan-scan.cc``: Demonstrates the use of an orphan scanning in a simple network joining procedure. In particular, the module enables a very simplified end-to-end data diff --git a/src/lr-wpan/examples/CMakeLists.txt b/src/lr-wpan/examples/CMakeLists.txt index c23e715e9..9122f66af 100644 --- a/src/lr-wpan/examples/CMakeLists.txt +++ b/src/lr-wpan/examples/CMakeLists.txt @@ -5,6 +5,7 @@ set(base_examples lr-wpan-phy-test lr-wpan-ed-scan lr-wpan-active-scan + lr-wpan-orphan-scan ) foreach( diff --git a/src/lr-wpan/examples/lr-wpan-orphan-scan.cc b/src/lr-wpan/examples/lr-wpan-orphan-scan.cc new file mode 100644 index 000000000..a094df01a --- /dev/null +++ b/src/lr-wpan/examples/lr-wpan-orphan-scan.cc @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2023 Tokushima University, Japan. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Author: Alberto Gallegos Ramonet + */ + +/* + * [00:00:00:00:00:00:00:01 | 00:01] [00:00:00:00:00:00:00:02 | ff:ff] + * PAN Coordinator 1 (PAN: 5) End Device + * |---------------------100m-----------------------| + * Channel 12 (Orphan Scan channels 11-14) + * + * + * This example demonstrate the usage of the MAC MLME-SCAN.request (ORPHAN scan) primitive as + * described by IEEE 802.15.4-2011 (See Figures 14 and 15). + * + * Orphan scan is used typically on devices as a result of repeated communication failures + * (For example, lossing too many ACK). An orphan scan represents the attempt of a device to + * relocate its coordinator. In some situations, it can be used by devices higher layers to not only + * rejoin a network but also join a network for the first time (Like in the joining through + * orphaning mechanism described in Zigbee networks). + * + * In this example, the end device is set to scan 4 channels (11~14) for a period of + * macResponseWaitTime until it finally gets in contact with the coordinator. + * On contact, the coordinator responds to the device (via coordinator realignment command) + * an assign it a short address. The detailed sequence of events is as following: + * + * 1) [Time 2s] The coordinator start a network in channel 12. + * 2) [Time 3s] The end device start orphan scan and transmits a orphan + * notification cmd on channel 11. + * 3) No response is received in channel 11, therefore, the device ends scanning on + * channel 11 after macResponseWaitTime and repeats step 2 in channel 12. + * 4) [Time 3.00269s] The orphan notification command is received by the coordinator in + * channel 12. The coordinator verify the requesting device and replies to the device + * with a coordinator realignment command containing the assigned short address [DE:AF]. + * 5) [Time 3.00646s] The device receives the coordinator realignment command, update its + * macPanId, macShortAddress, macCoordShortAddress and macCoordExtAddress. + * 6) Scanning of the remaining channels 13 and 14 is cancelled. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ns3; + +static void +ScanConfirm(Ptr device, MlmeScanConfirmParams params) +{ + if (params.m_status == MLMESCAN_SUCCESS) + { + std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " [" + << device->GetMac()->GetShortAddress() << " | " + << device->GetMac()->GetExtendedAddress() + << "] MLME-SCAN.confirm: Active scan status SUCCESSFUL " + << "(Coordinator found and address assigned) \n"; + } + else if (params.m_status == MLMESCAN_NO_BEACON) + { + std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " [" + << device->GetMac()->GetShortAddress() << " | " + << device->GetMac()->GetExtendedAddress() + << "] MLME-SCAN.confirm: Could not locate coordinator " + << "(Coord realignment command not received) " + << "status: " << params.m_status << "\n"; + } + else + { + std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " [" + << device->GetMac()->GetShortAddress() << " | " + << device->GetMac()->GetExtendedAddress() + << "] MLME-SCAN.confirm: An error occurred during scanning, " + << "status: " << params.m_status << "\n"; + } +} + +static void +OrphanIndication(Ptr device, MlmeOrphanIndicationParams params) +{ + // The steps taken by the coordinator on the event of an orphan indication + // are meant to be implemented by the next higher layer and are out of the scope of the + // standard. In this example, we simply accept the request , assign a fixed short address + // [DE:AF] and respond to the requesting device using a MLME-ORPHAN.response. + + std::cout << Simulator::Now().As(Time::S) << " Node " << device->GetNode()->GetId() << " [" + << device->GetMac()->GetShortAddress() << " | " + << device->GetMac()->GetExtendedAddress() + << "] MLME-ORPHAN.indication: Orphan Notification received, processing...\n"; + + MlmeOrphanResponseParams respParams; + respParams.m_assocMember = true; + respParams.m_orphanAddr = params.m_orphanAddr; + respParams.m_shortAddr = Mac16Address("DE:AF"); + + Simulator::ScheduleNow(&LrWpanMac::MlmeOrphanResponse, device->GetMac(), respParams); +} + +int +main(int argc, char* argv[]) +{ + LogComponentEnableAll(LogLevel(LOG_PREFIX_TIME | LOG_PREFIX_FUNC)); + + // Create 2 PAN coordinator nodes, and 1 end device + Ptr coord1 = CreateObject(); + Ptr endNode = CreateObject(); + + Ptr coord1NetDevice = CreateObject(); + Ptr endNodeNetDevice = CreateObject(); + + // PAN Coordinators configurations require to set both, the EUI-64 (extended address) + // and to assign their own short address. + coord1NetDevice->GetMac()->SetExtendedAddress(Mac64Address("00:00:00:00:00:00:00:01")); + coord1NetDevice->GetMac()->SetShortAddress(Mac16Address("00:01")); + + // Other devices must have only its EUI-64 and later on, their short address is + // potentially assigned by the coordinator. + endNodeNetDevice->GetMac()->SetExtendedAddress(Mac64Address("00:00:00:00:00:00:00:02")); + + // Configure Spectrum channel + Ptr channel = CreateObject(); + Ptr propModel = + CreateObject(); + Ptr delayModel = + CreateObject(); + channel->AddPropagationLossModel(propModel); + channel->SetPropagationDelayModel(delayModel); + + coord1NetDevice->SetChannel(channel); + endNodeNetDevice->SetChannel(channel); + + coord1->AddDevice(coord1NetDevice); + endNode->AddDevice(endNodeNetDevice); + + // Mobility + Ptr coord1Mobility = + CreateObject(); + coord1Mobility->SetPosition(Vector(0, 0, 0)); + coord1NetDevice->GetPhy()->SetMobility(coord1Mobility); + + Ptr endNodeMobility = + CreateObject(); + endNodeMobility->SetPosition(Vector(100, 0, 0)); + endNodeNetDevice->GetPhy()->SetMobility(endNodeMobility); + + // MAC layer Callbacks hooks + endNodeNetDevice->GetMac()->SetMlmeScanConfirmCallback( + MakeBoundCallback(&ScanConfirm, endNodeNetDevice)); + + coord1NetDevice->GetMac()->SetMlmeOrphanIndicationCallback( + MakeBoundCallback(&OrphanIndication, coord1NetDevice)); + + ///////////////// + // ORPHAN SCAN // + ///////////////// + + // PAN coordinator N0 (PAN 5) is set to channel 12 in non-beacon mode + // but answer to beacon request and orphan notification commands. + MlmeStartRequestParams params; + params.m_panCoor = true; + params.m_PanId = 5; + params.m_bcnOrd = 15; + params.m_sfrmOrd = 15; + params.m_logCh = 12; + Simulator::ScheduleWithContext(1, + Seconds(2.0), + &LrWpanMac::MlmeStartRequest, + coord1NetDevice->GetMac(), + params); + + // End device N1 is set to scan 4 channels looking for the presence of a coordinator. + // On each channel, a single orphan notification command is sent and a response is + // waited for a maximum time of macResponseWaitTime. If a reply is received from a + // coordinator within this time (coordinator realignment command), the programmed scans on + // other channels is suspended. + // Scan Channels are represented by bits 0-26 (27 LSB) + // ch 14 ch 11 + // | | + // 0x7800 = 0000000000000000111100000000000 + MlmeScanRequestParams scanParams; + scanParams.m_chPage = 0; + scanParams.m_scanChannels = 0x7800; + scanParams.m_scanType = MLMESCAN_ORPHAN; + Simulator::ScheduleWithContext(1, + Seconds(3.0), + &LrWpanMac::MlmeScanRequest, + endNodeNetDevice->GetMac(), + scanParams); + + Simulator::Stop(Seconds(2000)); + Simulator::Run(); + + Simulator::Destroy(); + return 0; +} diff --git a/src/lr-wpan/model/lr-wpan-csmaca.cc b/src/lr-wpan/model/lr-wpan-csmaca.cc index 7e3863b58..9975a9613 100644 --- a/src/lr-wpan/model/lr-wpan-csmaca.cc +++ b/src/lr-wpan/model/lr-wpan-csmaca.cc @@ -31,7 +31,9 @@ #include #undef NS_LOG_APPEND_CONTEXT -#define NS_LOG_APPEND_CONTEXT std::clog << "[address " << m_mac->GetShortAddress() << "] "; +#define NS_LOG_APPEND_CONTEXT \ + std::clog << "[address " << m_mac->GetShortAddress() << " | " << m_mac->GetExtendedAddress() \ + << "] "; namespace ns3 { diff --git a/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc b/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc index b6e6bfdb5..bc24c3c64 100644 --- a/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc +++ b/src/lr-wpan/model/lr-wpan-mac-pl-headers.cc @@ -182,6 +182,7 @@ CommandPayloadHeader::GetSerializedSize() const case BEACON_REQ: break; case COOR_REALIGN: + size += 8; break; case GTS_REQ: break; @@ -217,6 +218,11 @@ CommandPayloadHeader::Serialize(Buffer::Iterator start) const case BEACON_REQ: break; case COOR_REALIGN: + i.WriteU16(m_panid); + WriteTo(i, m_coordShortAddr); + i.WriteU8(m_logCh); + WriteTo(i, m_shortAddr); + i.WriteU8(m_logChPage); break; case GTS_REQ: break; @@ -251,6 +257,11 @@ CommandPayloadHeader::Deserialize(Buffer::Iterator start) case BEACON_REQ: break; case COOR_REALIGN: + m_panid = i.ReadU16(); + ReadFrom(i, m_coordShortAddr); + m_logCh = i.ReadU8(); + ReadFrom(i, m_shortAddr); + m_logChPage = i.ReadU8(); break; case GTS_REQ: break; @@ -264,7 +275,7 @@ CommandPayloadHeader::Deserialize(Buffer::Iterator start) void CommandPayloadHeader::Print(std::ostream& os) const { - os << "| MAC Command Frame ID | = " << (uint32_t)m_cmdFrameId; + os << "| MAC Command Frame ID | = " << static_cast(m_cmdFrameId); switch (m_cmdFrameId) { case ASSOCIATION_REQ: @@ -289,6 +300,11 @@ CommandPayloadHeader::Print(std::ostream& os) const case BEACON_REQ: break; case COOR_REALIGN: + os << "| PAN identifier| = " << m_panid + << "| PAN Coord Short address| = " << m_coordShortAddr + << "| Channel Num.| = " << static_cast(m_logCh) + << "| Short address| = " << m_shortAddr + << "| Page Num.| = " << static_cast(m_logChPage); break; case GTS_REQ: break; @@ -310,6 +326,34 @@ CommandPayloadHeader::SetCapabilityField(CapabilityField cap) m_capabilityInfo = cap; } +void +CommandPayloadHeader::SetCoordShortAddr(Mac16Address addr) +{ + NS_ASSERT(m_cmdFrameId == COOR_REALIGN); + m_coordShortAddr = addr; +} + +void +CommandPayloadHeader::SetChannel(uint8_t channel) +{ + NS_ASSERT(m_cmdFrameId == COOR_REALIGN); + m_logCh = channel; +} + +void +CommandPayloadHeader::SetPage(uint8_t page) +{ + NS_ASSERT(m_cmdFrameId == COOR_REALIGN); + m_logChPage = page; +} + +void +CommandPayloadHeader::SetPanId(uint16_t id) +{ + NS_ASSERT(m_cmdFrameId == COOR_REALIGN); + m_panid = id; +} + CommandPayloadHeader::MacCommand CommandPayloadHeader::GetCommandFrameType() const { @@ -350,7 +394,7 @@ CommandPayloadHeader::GetCommandFrameType() const void CommandPayloadHeader::SetShortAddr(Mac16Address shortAddr) { - NS_ASSERT(m_cmdFrameId == ASSOCIATION_RESP); + NS_ASSERT(m_cmdFrameId == ASSOCIATION_RESP || m_cmdFrameId == COOR_REALIGN); m_shortAddr = shortAddr; } @@ -364,7 +408,6 @@ CommandPayloadHeader::SetAssociationStatus(AssocStatus status) Mac16Address CommandPayloadHeader::GetShortAddr() const { - NS_ASSERT(m_cmdFrameId == ASSOCIATION_RESP); return m_shortAddr; } @@ -382,4 +425,32 @@ CommandPayloadHeader::GetCapabilityField() const return m_capabilityInfo; } +Mac16Address +CommandPayloadHeader::GetCoordShortAddr() const +{ + NS_ASSERT(m_cmdFrameId == COOR_REALIGN); + return m_coordShortAddr; +} + +uint8_t +CommandPayloadHeader::GetChannel() const +{ + NS_ASSERT(m_cmdFrameId == COOR_REALIGN); + return m_logCh; +} + +uint8_t +CommandPayloadHeader::GetPage() const +{ + NS_ASSERT(m_cmdFrameId == COOR_REALIGN); + return m_logChPage; +} + +uint16_t +CommandPayloadHeader::GetPanId() const +{ + NS_ASSERT(m_cmdFrameId == COOR_REALIGN); + return m_panid; +} + } // namespace ns3 diff --git a/src/lr-wpan/model/lr-wpan-mac-pl-headers.h b/src/lr-wpan/model/lr-wpan-mac-pl-headers.h index d426ca95b..fbb1df272 100644 --- a/src/lr-wpan/model/lr-wpan-mac-pl-headers.h +++ b/src/lr-wpan/model/lr-wpan-mac-pl-headers.h @@ -98,6 +98,9 @@ class BeaconPayloadHeader : public Header * \ingroup lr-wpan * Implements the header for the MAC payload command frame according to * the IEEE 802.15.4-2011 Std. + * - Association Response Command (See 5.3.2.2.) + * - Coordinator Realigment Command (See 5.3.8.) + * - Association Request Command (See 5.3.1.) */ class CommandPayloadHeader : public Header { @@ -160,7 +163,28 @@ class CommandPayloadHeader : public Header */ void SetCapabilityField(CapabilityField cap); /** - * Set the Short Address Assigned by the coordinator (Association Response Command). + * Set the coordinator short address (16 bit address). + * \param addr The coordinator short address. + */ + void SetCoordShortAddr(Mac16Address addr); + /** + * Set the logical channel number. + * \param channel The channel number. + */ + void SetChannel(uint8_t channel); + /** + * Set the logical channel page number. + * \param page The page number. + */ + void SetPage(uint8_t page); + /** + * Get the PAN identifier. + * \param id The PAN identifier. + */ + void SetPanId(uint16_t id); + /** + * Set the Short Address Assigned by the coordinator + * (Association Response and Coordinator Realigment Commands). * \param shortAddr The short address assigned by the coordinator */ void SetShortAddr(Mac16Address shortAddr); @@ -170,7 +194,8 @@ class CommandPayloadHeader : public Header */ void SetAssociationStatus(AssocStatus status); /** - * Get the Short address assigned by the coordinator (Association Response Command). + * Get the Short address assigned by the coordinator + * (Association Response and Coordinator Realigment commands). * \return The Mac16Address assigned by the coordinator */ Mac16Address GetShortAddr() const; @@ -185,19 +210,44 @@ class CommandPayloadHeader : public Header */ MacCommand GetCommandFrameType() const; /** - * Get the Capability Information Field from the command payload header. (Association Request - * Command) + * Get the Capability Information Field from the command payload header. + * (Association Request Command) * \return The Capability Information Field */ CapabilityField GetCapabilityField() const; + /** + * Get the coordinator short address. + * \return The coordinator short address (16 bit address) + */ + Mac16Address GetCoordShortAddr() const; + /** + * Get the logical channel number. + * \return The channel number + */ + uint8_t GetChannel() const; + /** + * Get the logical channel page number. + * \return The page number. + */ + uint8_t GetPage() const; + /** + * Get the PAN identifier. + * \return The PAN Identifier + */ + uint16_t GetPanId() const; private: - MacCommand m_cmdFrameId; //!< The command Frame Identifier - CapabilityField - m_capabilityInfo; //!< Capability Information Field (Association Request Command) - Mac16Address m_shortAddr; //!< Contains the short address assigned by the coordinator - //!< (Association Response Command) See IEEE 802.15.4-2011 5.3.2.2. - AssocStatus m_assocStatus; //!< Association Status (Association Response Command) + MacCommand m_cmdFrameId; //!< The command Frame Identifier (Used by all commands) + CapabilityField m_capabilityInfo; //!< Capability Information Field + //!< (Association Request Command) + Mac16Address m_shortAddr; //!< Contains the short address assigned by the coordinator + //!< (Association Response and Coordinator Realiagment Command) + Mac16Address m_coordShortAddr; //!< The coordinator short address + //!< (Coordinator realigment command) + uint16_t m_panid; //!< The PAN identifier (Coordinator realigment command) + uint8_t m_logCh; //!< The channel number (Coordinator realigment command) + uint8_t m_logChPage; //!< The channel page number (Coordinator realigment command) + AssocStatus m_assocStatus; //!< Association Status (Association Response Command) }; } // namespace ns3 diff --git a/src/lr-wpan/model/lr-wpan-mac.cc b/src/lr-wpan/model/lr-wpan-mac.cc index 79f8736ec..95653b64e 100644 --- a/src/lr-wpan/model/lr-wpan-mac.cc +++ b/src/lr-wpan/model/lr-wpan-mac.cc @@ -39,7 +39,8 @@ #include #undef NS_LOG_APPEND_CONTEXT -#define NS_LOG_APPEND_CONTEXT std::clog << "[address " << m_shortAddress << "] "; +#define NS_LOG_APPEND_CONTEXT \ + std::clog << "[address " << m_shortAddress << " | " << m_selfExt << "] "; namespace ns3 { @@ -276,7 +277,15 @@ LrWpanMac::DoDispose() m_mlmeAssociateConfirmCallback = MakeNullCallback(); m_mlmeAssociateIndicationCallback = MakeNullCallback(); m_mlmeCommStatusIndicationCallback = MakeNullCallback(); + m_mlmeOrphanIndicationCallback = MakeNullCallback(); + m_panDescriptorList.clear(); + m_energyDetectList.clear(); + m_unscannedChannels.clear(); + + m_scanEvent.Cancel(); + m_scanEnergyEvent.Cancel(); + m_scanOrphanEvent.Cancel(); m_beaconEvent.Cancel(); Object::DoDispose(); @@ -495,7 +504,7 @@ LrWpanMac::McpsDataRequest(McpsDataRequestParams params, Ptr p) p->AddHeader(macHdr); LrWpanMacTrailer macTrailer; - // Calculate FCS if the global attribute ChecksumEnable is set. + // Calculate FCS if the global attribute ChecksumEnabled is set. if (Node::ChecksumEnabled()) { macTrailer.EnableFcs(true); @@ -520,7 +529,7 @@ LrWpanMac::McpsDataRequest(McpsDataRequestParams params, Ptr p) p->AddHeader(macHdr); LrWpanMacTrailer macTrailer; - // Calculate FCS if the global attribute ChecksumEnable is set. + // Calculate FCS if the global attribute ChecksumEnabled is set. if (Node::ChecksumEnabled()) { macTrailer.EnableFcs(true); @@ -584,7 +593,7 @@ LrWpanMac::MlmeScanRequest(MlmeScanRequestParams params) confirmParams.m_scanType = params.m_scanType; confirmParams.m_chPage = params.m_chPage; - if (m_scanEvent.IsRunning() || m_scanEnergyEvent.IsRunning()) + if ((m_scanEvent.IsRunning() || m_scanEnergyEvent.IsRunning()) || m_scanOrphanEvent.IsRunning()) { if (!m_mlmeScanConfirmCallback.IsNull()) { @@ -595,7 +604,7 @@ LrWpanMac::MlmeScanRequest(MlmeScanRequestParams params) return; } - if (params.m_scanDuration > 14 || params.m_scanType > MLMESCAN_PASSIVE) + if (params.m_scanDuration > 14 || params.m_scanType > MLMESCAN_ORPHAN) { if (!m_mlmeScanConfirmCallback.IsNull()) { @@ -611,6 +620,7 @@ LrWpanMac::MlmeScanRequest(MlmeScanRequestParams params) m_panDescriptorList.clear(); m_energyDetectList.clear(); + m_unscannedChannels.clear(); // TODO: stop beacon transmission @@ -758,7 +768,7 @@ LrWpanMac::MlmeAssociateResponse(MlmeAssociateResponseParams params) commandPacket->AddHeader(macPayload); commandPacket->AddHeader(macHdr); - // Calculate FCS if the global attribute ChecksumEnable is set. + // Calculate FCS if the global attribute ChecksumEnabled is set. if (Node::ChecksumEnabled()) { macTrailer.EnableFcs(true); @@ -771,6 +781,66 @@ LrWpanMac::MlmeAssociateResponse(MlmeAssociateResponseParams params) EnqueueInd(commandPacket); } +void +LrWpanMac::MlmeOrphanResponse(MlmeOrphanResponseParams params) +{ + NS_LOG_FUNCTION(this); + // Mac header Coordinator realigment Command + // See 802.15.4-2011 (Section 6.2.7.2) + LrWpanMacHeader macHdr(LrWpanMacHeader::LRWPAN_MAC_COMMAND, m_macDsn.GetValue()); + m_macDsn++; + LrWpanMacTrailer macTrailer; + Ptr commandPacket = Create(); + macHdr.SetPanIdComp(); + macHdr.SetDstAddrMode(LrWpanMacHeader::EXTADDR); + macHdr.SetDstAddrFields(0xffff, params.m_orphanAddr); + + macHdr.SetSrcAddrMode(LrWpanMacHeader::EXTADDR); + macHdr.SetSrcAddrFields(m_macPanId, GetExtendedAddress()); + macHdr.SetSrcAddrFields(m_macPanId, Mac16Address("FF:FF")); + + macHdr.SetFrameVer(0x01); + macHdr.SetSecDisable(); + macHdr.SetAckReq(); + + CommandPayloadHeader macPayload(CommandPayloadHeader::COOR_REALIGN); + macPayload.SetPanId(m_macPanId); + macPayload.SetCoordShortAddr(GetShortAddress()); + macPayload.SetChannel(m_phy->GetCurrentChannelNum()); + macPayload.SetPage(m_phy->GetCurrentPage()); + + if (params.m_assocMember) + { + // The orphan device was associated with the coordinator + + // Either FF:FE for extended address mode + // or the short address assigned by the coord. + macPayload.SetShortAddr(params.m_shortAddr); + } + else + { + // The orphan device was NOT associated with the coordinator + macPayload.SetShortAddr(Mac16Address("FF:FF")); + } + + commandPacket->AddHeader(macPayload); + commandPacket->AddHeader(macHdr); + + // Calculate FCS if the global attribute ChecksumEnabled is set. + if (Node::ChecksumEnabled()) + { + macTrailer.EnableFcs(true); + macTrailer.SetFcs(commandPacket); + } + + commandPacket->AddTrailer(macTrailer); + + Ptr txQElement = Create(); + txQElement->txQPkt = commandPacket; + EnqueueTxQElement(txQElement); + CheckQueue(); +} + void LrWpanMac::MlmeSyncRequest(MlmeSyncRequestParams params) { @@ -906,7 +976,7 @@ LrWpanMac::SendOneBeacon() beaconPacket->AddHeader(macPayload); beaconPacket->AddHeader(macHdr); - // Calculate FCS if the global attribute ChecksumEnable is set. + // Calculate FCS if the global attribute ChecksumEnabled is set. if (Node::ChecksumEnabled()) { macTrailer.EnableFcs(true); @@ -944,8 +1014,8 @@ LrWpanMac::SendBeaconRequestCommand() macHdr.SetDstAddrMode(LrWpanMacHeader::SHORTADDR); macHdr.SetSrcAddrMode(LrWpanMacHeader::NOADDR); - macHdr.SetDstAddrFields(0xFFFF, - Mac16Address("FF:FF")); // Not associated PAN, broadcast dst address + // Not associated PAN, broadcast dst address + macHdr.SetDstAddrFields(0xFFFF, Mac16Address("FF:FF")); macHdr.SetSecDisable(); macHdr.SetNoAckReq(); @@ -956,7 +1026,48 @@ LrWpanMac::SendBeaconRequestCommand() commandPacket->AddHeader(macPayload); commandPacket->AddHeader(macHdr); - // Calculate FCS if the global attribute ChecksumEnable is set. + // Calculate FCS if the global attribute ChecksumEnabled is set. + if (Node::ChecksumEnabled()) + { + macTrailer.EnableFcs(true); + macTrailer.SetFcs(commandPacket); + } + + commandPacket->AddTrailer(macTrailer); + + Ptr txQElement = Create(); + txQElement->txQPkt = commandPacket; + EnqueueTxQElement(txQElement); + CheckQueue(); +} + +void +LrWpanMac::SendOrphanNotificationCommand() +{ + LrWpanMacHeader macHdr(LrWpanMacHeader::LRWPAN_MAC_COMMAND, m_macDsn.GetValue()); + m_macDsn++; + LrWpanMacTrailer macTrailer; + Ptr commandPacket = Create(); + + // See IEEE 802.15.4-2011 (5.3.6) + macHdr.SetPanIdComp(); + + macHdr.SetSrcAddrMode(LrWpanMacHeader::EXTADDR); + macHdr.SetSrcAddrFields(0xFFFF, GetExtendedAddress()); + + macHdr.SetDstAddrMode(LrWpanMacHeader::SHORTADDR); + macHdr.SetDstAddrFields(0xFFFF, Mac16Address("FF:FF")); + + macHdr.SetSecDisable(); + macHdr.SetNoAckReq(); + + CommandPayloadHeader macPayload; + macPayload.SetCommandFrameType(CommandPayloadHeader::ORPHAN_NOTIF); + + commandPacket->AddHeader(macPayload); + commandPacket->AddHeader(macHdr); + + // Calculate FCS if the global attribute ChecksumEnabled is set. if (Node::ChecksumEnabled()) { macTrailer.EnableFcs(true); @@ -1005,7 +1116,7 @@ LrWpanMac::SendAssocRequestCommand() commandPacket->AddHeader(macPayload); commandPacket->AddHeader(macHdr); - // Calculate FCS if the global attribute ChecksumEnable is set. + // Calculate FCS if the global attribute ChecksumEnabled is set. if (Node::ChecksumEnabled()) { macTrailer.EnableFcs(true); @@ -1063,7 +1174,7 @@ LrWpanMac::SendDataRequestCommand() commandPacket->AddHeader(macPayload); commandPacket->AddHeader(macHdr); - // Calculate FCS if the global attribute ChecksumEnable is set. + // Calculate FCS if the global attribute ChecksumEnabled is set. if (Node::ChecksumEnabled()) { macTrailer.EnableFcs(true); @@ -1160,6 +1271,7 @@ LrWpanMac::EndStartRequest() m_incCfpEvent.Cancel(); m_trackingEvent.Cancel(); m_scanEvent.Cancel(); + m_scanOrphanEvent.Cancel(); m_scanEnergyEvent.Cancel(); m_csmaCa->SetUnSlottedCsmaCa(); @@ -1227,21 +1339,59 @@ LrWpanMac::EndChannelScan() } else { - // All scans on the channel list completed - // Return to the MAC values previous to start of the first scan. + // All channels in the list scan completed. + // Return variables to the values before the scan and return the status to the next layer. m_macPanId = m_macPanIdScan; m_macPanIdScan = 0; // TODO: restart beacon transmissions that were active before the beginning of the scan // (i.e when a coordinator perform a scan and it was already transmitting beacons) - - // All channels scanned, report success MlmeScanConfirmParams confirmParams; - confirmParams.m_status = MLMESCAN_SUCCESS; confirmParams.m_chPage = m_scanParams.m_chPage; confirmParams.m_scanType = m_scanParams.m_scanType; confirmParams.m_energyDetList = {}; - confirmParams.m_panDescList = m_panDescriptorList; + confirmParams.m_unscannedCh = m_unscannedChannels; + confirmParams.m_resultListSize = m_panDescriptorList.size(); + + // See IEEE 802.15.4-2011, Table 31 (panDescriptorList value on macAutoRequest) + // and Section 6.2.10.2 + switch (confirmParams.m_scanType) + { + case MLMESCAN_PASSIVE: + if (m_macAutoRequest) + { + confirmParams.m_panDescList = m_panDescriptorList; + } + confirmParams.m_status = MLMESCAN_SUCCESS; + break; + case MLMESCAN_ACTIVE: + if (m_panDescriptorList.empty()) + { + confirmParams.m_status = MLMESCAN_NO_BEACON; + } + else + { + if (m_macAutoRequest) + { + confirmParams.m_panDescList = m_panDescriptorList; + } + confirmParams.m_status = MLMESCAN_SUCCESS; + } + break; + case MLMESCAN_ORPHAN: + confirmParams.m_panDescList = {}; + confirmParams.m_status = MLMESCAN_NO_BEACON; + confirmParams.m_resultListSize = 0; + // The device lost track of the coordinator and was unable + // to locate it, disassociate from the network. + m_macPanId = 0xffff; + m_shortAddress = Mac16Address("FF:FF"); + m_macCoordShortAddress = Mac16Address("ff:ff"); + m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed"); + break; + default: + NS_LOG_ERROR(this << " Invalid scan type"); + } if (!m_mlmeScanConfirmCallback.IsNull()) { @@ -1259,7 +1409,7 @@ LrWpanMac::EndChannelEnergyScan() { NS_LOG_FUNCTION(this); // Add the results of channel energy scan to the detectList - m_energyDetectList.push_back(m_maxEnergyLevel); + m_energyDetectList.emplace_back(m_maxEnergyLevel); m_maxEnergyLevel = 0; m_channelScanIndex++; @@ -1300,6 +1450,7 @@ LrWpanMac::EndChannelEnergyScan() confirmParams.m_chPage = m_phy->GetCurrentPage(); confirmParams.m_scanType = m_scanParams.m_scanType; confirmParams.m_energyDetList = m_energyDetectList; + confirmParams.m_resultListSize = m_energyDetectList.size(); m_mlmeScanConfirmCallback(confirmParams); } m_pendPrimitive = MLME_NONE; @@ -1596,6 +1747,12 @@ LrWpanMac::SetMlmeCommStatusIndicationCallback(MlmeCommStatusIndicationCallback m_mlmeCommStatusIndicationCallback = c; } +void +LrWpanMac::SetMlmeOrphanIndicationCallback(MlmeOrphanIndicationCallback c) +{ + m_mlmeOrphanIndicationCallback = c; +} + void LrWpanMac::SetMcpsDataConfirmCallback(McpsDataConfirmCallback c) { @@ -1805,15 +1962,23 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr p, uint8_t lqi) acceptFrame = (receivedMacHdr.GetExtDstAddr() == m_selfExt); } - // When PASSIVE or ACTIVE scan is running, reject any frames other than BEACON frames - if (acceptFrame && (!receivedMacHdr.IsBeacon() && m_scanEvent.IsRunning())) + if (acceptFrame && m_scanEvent.IsRunning()) { - acceptFrame = false; + if (!receivedMacHdr.IsBeacon()) + { + acceptFrame = false; + } } - - // Energy Scan is running, reject any frames - if (m_scanEnergyEvent.IsRunning()) + else if (acceptFrame && m_scanOrphanEvent.IsRunning()) { + if (!receivedMacHdr.IsCommand()) + { + acceptFrame = false; + } + } + else if (m_scanEnergyEvent.IsRunning()) + { + // Reject any frames if energy scan is running acceptFrame = false; } @@ -2073,7 +2238,7 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr p, uint8_t lqi) if (!descriptorExists) { - m_panDescriptorList.push_back(panDescriptor); + m_panDescriptorList.emplace_back(panDescriptor); } return; } @@ -2130,13 +2295,14 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr p, uint8_t lqi) } else if (receivedMacHdr.IsCommand()) { - // Handle the reception of frame commands that do not require ACK (i.e. Beacon - // Request Command) + // Handle the reception of frame commands that do not require ACK + // (i.e. Beacon Request, Orphan notification, Coordinator Realigment) CommandPayloadHeader receivedMacPayload; p->PeekHeader(receivedMacPayload); - if (receivedMacPayload.GetCommandFrameType() == - CommandPayloadHeader::BEACON_REQ) + + switch (receivedMacPayload.GetCommandFrameType()) { + case CommandPayloadHeader::BEACON_REQ: // TODO: check that node is any coordinator not just pan coordinator if (m_csmaCa->IsUnSlottedCsmaCa() && m_panCoor) { @@ -2146,6 +2312,48 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr p, uint8_t lqi) { m_macRxDropTrace(originalPkt); } + break; + case CommandPayloadHeader::ORPHAN_NOTIF: + if (!m_mlmeOrphanIndicationCallback.IsNull()) + { + MlmeOrphanIndicationParams orphanParams; + orphanParams.m_orphanAddr = receivedMacHdr.GetExtSrcAddr(); + m_mlmeOrphanIndicationCallback(orphanParams); + } + break; + case CommandPayloadHeader::COOR_REALIGN: + if (m_scanOrphanEvent.IsRunning()) + { + // Coordinator located, no need to keep scanning other channels + m_scanOrphanEvent.Cancel(); + + m_macPanIdScan = 0; + m_pendPrimitive = MLME_NONE; + m_channelScanIndex = 0; + + // Update the device information with the received information + // from the Coordinator Realigment command. + m_macPanId = receivedMacPayload.GetPanId(); + m_shortAddress = receivedMacPayload.GetShortAddr(); + m_macCoordExtendedAddress = receivedMacHdr.GetExtSrcAddr(); + m_macCoordShortAddress = receivedMacPayload.GetCoordShortAddr(); + + if (!m_mlmeScanConfirmCallback.IsNull()) + { + MlmeScanConfirmParams confirmParams; + confirmParams.m_scanType = m_scanParams.m_scanType; + confirmParams.m_chPage = m_scanParams.m_chPage; + confirmParams.m_status = MLMESCAN_SUCCESS; + m_mlmeScanConfirmCallback(confirmParams); + } + m_scanParams = {}; + } + // TODO: handle Coordinator realignment when not + // used during an orphan scan. + break; + default: + m_macRxDropTrace(originalPkt); + break; } } else if (receivedMacHdr.IsData() && !m_mcpsDataIndicationCallback.IsNull()) @@ -2316,7 +2524,7 @@ LrWpanMac::SendAck(uint8_t seqno) LrWpanMacTrailer macTrailer; Ptr ackPacket = Create(0); ackPacket->AddHeader(macHdr); - // Calculate FCS if the global attribute ChecksumEnable is set. + // Calculate FCS if the global attribute ChecksumEnabled is set. if (Node::ChecksumEnabled()) { macTrailer.EnableFcs(true); @@ -2834,8 +3042,38 @@ LrWpanMac::PdDataConfirm(LrWpanPhyEnumeration status) } else if (macHdr.IsCommand()) { - // We handle commands that do not require ACK (e.g. BeaconReq command) - // other command are handle by the previous if statement. + // We handle commands that do not require ACK + // (e.g. Coordinator realigment command in an orphan response) + // Other command with ACK required are handle by the previous if statement. + + // Check the transmitted packet command type and issue the appropriate indication. + Ptr txOriginalPkt = m_txPkt->Copy(); + LrWpanMacHeader txMacHdr; + txOriginalPkt->RemoveHeader(txMacHdr); + CommandPayloadHeader txMacPayload; + txOriginalPkt->RemoveHeader(txMacPayload); + + if (txMacPayload.GetCommandFrameType() == CommandPayloadHeader::COOR_REALIGN) + { + if (!m_mlmeCommStatusIndicationCallback.IsNull()) + { + MlmeCommStatusIndicationParams commStatusParams; + commStatusParams.m_panId = m_macPanId; + + commStatusParams.m_srcAddrMode = macHdr.GetSrcAddrMode(); + commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr(); + commStatusParams.m_srcShortAddr = macHdr.GetShortSrcAddr(); + + commStatusParams.m_dstAddrMode = macHdr.GetDstAddrMode(); + commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr(); + commStatusParams.m_dstShortAddr = macHdr.GetShortDstAddr(); + + commStatusParams.m_status = LrWpanMlmeCommStatus::MLMECOMMSTATUS_SUCCESS; + m_mlmeCommStatusIndicationCallback(commStatusParams); + } + } + + ifsWaitTime = Seconds(static_cast(GetIfsSize()) / symbolRate); RemoveFirstTxQElement(); } else @@ -3115,9 +3353,19 @@ LrWpanMac::PlmeSetAttributeConfirm(LrWpanPhyEnumeration status, LrWpanPibAttribu if (status == LrWpanPhyEnumeration::IEEE_802_15_4_PHY_SUCCESS) { uint64_t symbolRate = static_cast(m_phy->GetDataOrSymbolRate(false)); - uint64_t scanDuration = lrwpan::aBaseSuperframeDuration * - ((static_cast(1 << m_scanParams.m_scanDuration)) + 1); - Time nextScanTime = Seconds(static_cast(scanDuration / symbolRate)); + Time nextScanTime; + + if (m_scanParams.m_scanType == MLMESCAN_ORPHAN) + { + nextScanTime = Seconds(static_cast(m_macResponseWaitTime) / symbolRate); + } + else + { + uint64_t scanDuration = + lrwpan::aBaseSuperframeDuration * + ((static_cast(1 << m_scanParams.m_scanDuration)) + 1); + nextScanTime = Seconds(static_cast(scanDuration / symbolRate)); + } switch (m_scanParams.m_scanType) { @@ -3138,8 +3386,9 @@ LrWpanMac::PlmeSetAttributeConfirm(LrWpanPhyEnumeration status, LrWpanPibAttribu m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON); break; case MLMESCAN_ORPHAN: - // TODO: add orphan scan support - NS_LOG_ERROR("Scan Type currently not supported"); + m_scanOrphanEvent = + Simulator::Schedule(nextScanTime, &LrWpanMac::EndChannelScan, this); + SendOrphanNotificationCommand(); break; default: @@ -3378,8 +3627,41 @@ LrWpanMac::SetLrWpanMacState(LrWpanMacState macState) } break; } + case CommandPayloadHeader::COOR_REALIGN: { + if (!m_mlmeCommStatusIndicationCallback.IsNull()) + { + MlmeCommStatusIndicationParams commStatusParams; + commStatusParams.m_panId = m_macPanId; + commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR; + commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr(); + commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR; + commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr(); + commStatusParams.m_status = + LrWpanMlmeCommStatus::MLMECOMMSTATUS_CHANNEL_ACCESS_FAILURE; + m_mlmeCommStatusIndicationCallback(commStatusParams); + } + break; + } + case CommandPayloadHeader::ORPHAN_NOTIF: { + if (m_scanOrphanEvent.IsRunning()) + { + m_unscannedChannels.emplace_back(m_phy->GetCurrentChannelNum()); + } + // TODO: Handle orphan notification command during a + // channel access failure when not is not scanning. + break; + } + case CommandPayloadHeader::BEACON_REQ: { + if (m_scanEvent.IsRunning()) + { + m_unscannedChannels.emplace_back(m_phy->GetCurrentChannelNum()); + } + // TODO: Handle beacon request command during a + // channel access failure when not scanning. + break; + } default: { - // TODO: Other commands(e.g. Orphan Request) + // TODO: Other commands(e.g. Disassociation notification, etc) break; } } diff --git a/src/lr-wpan/model/lr-wpan-mac.h b/src/lr-wpan/model/lr-wpan-mac.h index 29c432488..a1024106f 100644 --- a/src/lr-wpan/model/lr-wpan-mac.h +++ b/src/lr-wpan/model/lr-wpan-mac.h @@ -455,11 +455,11 @@ struct MlmeAssociateResponseParams */ struct MlmeStartRequestParams { - uint16_t m_PanId{0}; //!< Pan Identifier used by the device. - uint8_t m_logCh{ - 11}; //!< Logical channel on which to start using the new superframe configuration. - uint32_t m_logChPage{ - 0}; //!< Logical channel page on which to start using the new superframe configuration. + uint16_t m_PanId{0}; //!< Pan Identifier used by the device. + uint8_t m_logCh{11}; //!< Logical channel on which to start using the + //!< new superframe configuration. + uint32_t m_logChPage{0}; //!< Logical channel page on which to start using the + //!< new superframe configuration. uint32_t m_startTime{0}; //!< Time at which to begin transmitting beacons (Used by Coordinator //!< not PAN Coordinators). The time is specified in symbols. uint8_t m_bcnOrd{15}; //!< Beacon Order, Used to calculate the beacon interval, a value of 15 @@ -507,7 +507,9 @@ struct MlmeScanRequestParams { LrWpanMlmeScanType m_scanType{MLMESCAN_PASSIVE}; //!< Indicates the type of scan performed as //!< described in IEEE 802.15.4-2011 (5.1.2.1). - uint32_t m_scanChannels{0x7FFFFFF}; //!< The channel numbers to be scanned. + uint32_t m_scanChannels{0x7FFF800}; //!< The channel numbers to be scanned. + //!< Default: (0x7FFF800 = Ch11-Ch26) + //!< 27 LSB (b0,b1,...,b26) = channels uint8_t m_scanDuration{14}; //!< A value used to calculate the length of time to spend scanning //!< [aBaseSuperframeDuration * (2^m_scanDuration +)]. uint32_t m_chPage{0}; //!< The channel page on which to perform scan. @@ -520,16 +522,17 @@ struct MlmeScanRequestParams */ struct MlmeScanConfirmParams { - LrWpanMlmeScanConfirmStatus m_status{ - MLMESCAN_INVALID_PARAMETER}; //!< The status of the scan request. - LrWpanMlmeScanType m_scanType{ - MLMESCAN_PASSIVE}; //!< Indicates the type of scan performed (ED,ACTIVE,PASSIVE,ORPHAN). - uint32_t m_chPage{0}; //!< The channel page on which the scan was performed. - std::vector m_unscannedCh; //!< A list of channels given in the request which were not - //!< scanned (Not valid for ED scans). - std::vector - m_energyDetList; //!< A list of energy measurements, one for each channel searched during ED - //!< scan (Not valid for Active, Passive or Orphan Scans) + LrWpanMlmeScanConfirmStatus m_status{MLMESCAN_INVALID_PARAMETER}; //!< The status the request. + LrWpanMlmeScanType m_scanType{MLMESCAN_PASSIVE}; //!< Indicates the type of scan + //!< performed (ED,ACTIVE,PASSIVE,ORPHAN). + uint32_t m_chPage{0}; //!< The channel page on which the scan was performed. + std::vector m_unscannedCh; //!< A list of channels given in the request which + //!< were not scanned (Not valid for ED scans). + uint8_t m_resultListSize{0}; //!< The number of elements returned in the appropriate + //!< result list. (Not valid for Orphan scan). + std::vector m_energyDetList; //!< A list of energy measurements, one for each + //!< channel searched during ED scan + //!< (Not valid for Active, Passive or Orphan Scans) std::vector m_panDescList; //!< A list of PAN descriptor, one for each beacon //!< found (Not valid for ED and Orphan scans). }; @@ -620,13 +623,35 @@ struct MlmeCommStatusIndicationParams Mac64Address m_srcExtAddr; //!< The extended address of the entity from which the frame causing //!< the error originated. uint8_t m_dstAddrMode{SHORT_ADDR}; //!< The destination addressing mode for this primitive. - Mac16Address - m_dstShortAddr; //!< The short address of the device for which the frame was intended. - Mac64Address - m_dstExtAddr; //!< The extended address of the device for which the frame was intended. + Mac16Address m_dstShortAddr; //!< The short address of the device for + //!< which the frame was intended. + Mac64Address m_dstExtAddr; //!< The extended address of the device for + //!< which the frame was intended. LrWpanMlmeCommStatus m_status{MLMECOMMSTATUS_INVALID_PARAMETER}; //!< The communication status }; +/** + * \ingroup lr-wpan + * + * MLME-ORPHAN.indication params. See 802.15.4-2011 Section 6.2.7.1 + */ +struct MlmeOrphanIndicationParams +{ + Mac64Address m_orphanAddr; //!< The address of the orphaned device. +}; + +/** + * \ingroup lr-wpan + * + * MLME-ORPHAN.response params. See 802.15.4-2011 Section 6.2.7.2 + */ +struct MlmeOrphanResponseParams +{ + Mac64Address m_orphanAddr; //!< The address of the orphaned device. + Mac16Address m_shortAddr; //!< The short address allocated. + bool m_assocMember{false}; //!< T = allocated with this coord | F = otherwise +}; + /** * \ingroup lr-wpan * @@ -751,6 +776,17 @@ typedef Callback MlmeAssociateIndicationCal */ typedef Callback MlmeCommStatusIndicationCallback; +/** + * \ingroup lr-wpan + * + * This callback is called by the MLME and issued to its next higher layer following + * the reception of a orphan notification. + * + * Security related parameters and not handle. + * See 802.15.4-2011 6.2.7.1 + */ +typedef Callback MlmeOrphanIndicationCallback; + /** * \ingroup lr-wpan * @@ -901,6 +937,16 @@ class LrWpanMac : public Object */ void MlmeAssociateResponse(MlmeAssociateResponseParams params); + /** + * IEEE 802.15.4-2011, section 6.2.7.2 + * MLME-ORPHAN.response + * Primitive used to initiatte a response to an MLME-ORPHAN.indication + * primitive. + * + * \param params the orphan response parameters + */ + void MlmeOrphanResponse(MlmeOrphanResponseParams params); + /** * IEEE 802.15.4-2011, section 6.2.13.1 * MLME-SYNC.request @@ -978,6 +1024,15 @@ class LrWpanMac : public Object */ void SetMlmeCommStatusIndicationCallback(MlmeCommStatusIndicationCallback c); + /** + * Set the callback for the indication to the reception of an orphan notification. + * The callback implements MLME-ORPHAN.indication SAP of IEEE 802.15.4-2011, + * section 6.2.7.1. + * + * \param c the callback + */ + void SetMlmeOrphanIndicationCallback(MlmeOrphanIndicationCallback c); + /** * Set the callback for the confirmation of a data transmission request. * The callback implements MCPS-DATA.confirm SAP of IEEE 802.15.4-2006, @@ -1563,6 +1618,13 @@ class LrWpanMac : public Object */ void SendBeaconRequestCommand(); + /** + * Called to send a orphan notification command. This is used by an associated device that + * has lost synchronization with its coordinator. + * As described in IEEE 802.15.4-2011 (Section 5.3.6) + */ + void SendOrphanNotificationCommand(); + /** * Called to end a MLME-START.request after changing the page and channel number. */ @@ -1960,6 +2022,12 @@ class LrWpanMac : public Object */ MlmeCommStatusIndicationCallback m_mlmeCommStatusIndicationCallback; + /** + * This callback is used to indicate the reception of a orphan notification command. + * See IEEE 802.15.4-2011, section 6.2.7.1 + */ + MlmeOrphanIndicationCallback m_mlmeOrphanIndicationCallback; + /** * This callback is used to report data transmission request status to the * upper layers. @@ -2042,9 +2110,14 @@ class LrWpanMac : public Object */ std::vector m_energyDetectList; + /** + * The list of unscanned channels during a scan operation. + */ + std::vector m_unscannedChannels; + /** * The parameters used during a MLME-SCAN.request. These parameters are stored here while - * PLME-SET operations (set channel page, set channel number) and multiple ed scans take place. + * PLME-SET (set channel page, set channel number) and other operations take place. */ MlmeScanRequestParams m_scanParams; @@ -2139,10 +2212,15 @@ class LrWpanMac : public Object EventId m_trackingEvent; /** - * Scheduler event for the end of a channel scan. + * Scheduler event for the end of an ACTIVE or PASSIVE channel scan. */ EventId m_scanEvent; + /** + * Scheduler event for the end of an ORPHAN channel scan. + */ + EventId m_scanOrphanEvent; + /** * Scheduler event for the end of a ED channel scan. */ diff --git a/src/lr-wpan/test/lr-wpan-mac-test.cc b/src/lr-wpan/test/lr-wpan-mac-test.cc index 6e78d04fd..9f77df6f8 100644 --- a/src/lr-wpan/test/lr-wpan-mac-test.cc +++ b/src/lr-wpan/test/lr-wpan-mac-test.cc @@ -488,27 +488,216 @@ TestActiveScanPanDescriptors::DoRun() NS_TEST_EXPECT_MSG_EQ(m_panDescriptorList.size(), 2, "Error, Beacons not received or PAN descriptors not found"); - NS_TEST_ASSERT_MSG_LT(m_panDescriptorList[0].m_linkQuality, - 255, - "Error, Coordinator 1 (PAN 5) LQI value should be less than 255."); - NS_TEST_ASSERT_MSG_LT(m_panDescriptorList[1].m_linkQuality, - 255, - "Error, Coordinator 2 (PAN 7) LQI value should be less than 255."); - NS_TEST_ASSERT_MSG_GT(m_panDescriptorList[0].m_linkQuality, - 0, - "Error, Coordinator 1 (PAN 5) LQI value should be greater than 0."); - NS_TEST_ASSERT_MSG_GT(m_panDescriptorList[1].m_linkQuality, - 0, - "Error, Coordinator 2 (PAN 7) LQI value should be greater than 0."); - NS_TEST_ASSERT_MSG_LT( - m_panDescriptorList[1].m_linkQuality, - m_panDescriptorList[0].m_linkQuality, - "Error, Coordinator 2 (PAN 7) LQI value should be less than Coordinator 1 (PAN 5)."); + if (m_panDescriptorList.size() == 2) + { + NS_TEST_ASSERT_MSG_LT(m_panDescriptorList[0].m_linkQuality, + 255, + "Error, Coordinator 1 (PAN 5) LQI value should be less than 255."); + NS_TEST_ASSERT_MSG_LT(m_panDescriptorList[1].m_linkQuality, + 255, + "Error, Coordinator 2 (PAN 7) LQI value should be less than 255."); + NS_TEST_ASSERT_MSG_GT(m_panDescriptorList[0].m_linkQuality, + 0, + "Error, Coordinator 1 (PAN 5) LQI value should be greater than 0."); + NS_TEST_ASSERT_MSG_GT(m_panDescriptorList[1].m_linkQuality, + 0, + "Error, Coordinator 2 (PAN 7) LQI value should be greater than 0."); - NS_TEST_EXPECT_MSG_EQ(g_beaconPayloadSize, - 25, - "Error, Beacon Payload not received or incorrect size (25 bytes)"); + NS_TEST_ASSERT_MSG_LT(m_panDescriptorList[1].m_linkQuality, + m_panDescriptorList[0].m_linkQuality, + "Error, Coordinator 2 (PAN 7) LQI value should" + " be less than Coordinator 1 (PAN 5)."); + + NS_TEST_EXPECT_MSG_EQ(g_beaconPayloadSize, + 25, + "Error, Beacon Payload not received or incorrect size (25 bytes)"); + } + + Simulator::Destroy(); +} + +/** + * \ingroup lr-wpan-test + * \ingroup tests + * + * \brief Test MAC Orphan Scan Coordinator Realignment command reception and its values. + */ +class TestOrphanScan : public TestCase +{ + public: + TestOrphanScan(); + ~TestOrphanScan() override; + + private: + /** + * Function called in response to a MAC scan request. + * + * \param params MLME scan confirm parameters + */ + void ScanConfirm(MlmeScanConfirmParams params); + + /** + * Function called as a result of receiving an orphan notification command + * on the coordinator + * + * \param params MLME orphan indication parameters + */ + void OrphanIndicationCoord(MlmeOrphanIndicationParams params); + + void DoRun() override; + + Ptr coord1NetDevice; //!< The LrWpanNetDevice of coordinator 1 + Ptr endNodeNetDevice; //!< The LrWpanNetDevice of the end device + bool m_orphanScanSuccess; //!< Indicates a successful orphan scan +}; + +TestOrphanScan::TestOrphanScan() + : TestCase("Test an orphan scan and the reception of the commands involved") +{ + m_orphanScanSuccess = false; +} + +TestOrphanScan::~TestOrphanScan() +{ +} + +void +TestOrphanScan::ScanConfirm(MlmeScanConfirmParams params) +{ + if (params.m_status == MLMESCAN_SUCCESS) + { + m_orphanScanSuccess = true; + } +} + +void +TestOrphanScan::OrphanIndicationCoord(MlmeOrphanIndicationParams params) +{ + // The steps taken by the coordinator on the event of an orphan indication + // are meant to be implemented by the next higher layer and are out of the scope of the + // standard. In this test, we assume that coordinator 2 already has + // the endDevice [00:00:00:00:00:00:00:03] registered and therefore reply to this device + // a with a coordidinator realignment command. + + if (params.m_orphanAddr == Mac64Address("00:00:00:00:00:00:00:02")) + { + MlmeOrphanResponseParams respParams; + respParams.m_assocMember = true; + respParams.m_orphanAddr = params.m_orphanAddr; + respParams.m_shortAddr = Mac16Address("00:02"); + + Simulator::ScheduleNow(&LrWpanMac::MlmeOrphanResponse, + coord1NetDevice->GetMac(), + respParams); + } +} + +void +TestOrphanScan::DoRun() +{ + // Create 2 PAN coordinator nodes, and 1 end device + Ptr coord1 = CreateObject(); + Ptr endNode = CreateObject(); + + coord1NetDevice = CreateObject(); + endNodeNetDevice = CreateObject(); + + // PAN Coordinators configurations require to set both, the EUI-64 (extended address) + // and to assign their own short address. + coord1NetDevice->GetMac()->SetExtendedAddress(Mac64Address("00:00:00:00:00:00:00:01")); + coord1NetDevice->GetMac()->SetShortAddress(Mac16Address("00:01")); + + // Other devices must have only its EUI-64 and later on, their short address is + // potentially assigned by the coordinator. + endNodeNetDevice->GetMac()->SetExtendedAddress(Mac64Address("00:00:00:00:00:00:00:02")); + + // Configure Spectrum channel + Ptr channel = CreateObject(); + Ptr propModel = + CreateObject(); + Ptr delayModel = + CreateObject(); + channel->AddPropagationLossModel(propModel); + channel->SetPropagationDelayModel(delayModel); + + coord1NetDevice->SetChannel(channel); + endNodeNetDevice->SetChannel(channel); + + coord1->AddDevice(coord1NetDevice); + endNode->AddDevice(endNodeNetDevice); + + // Mobility + Ptr coord1Mobility = + CreateObject(); + coord1Mobility->SetPosition(Vector(0, 0, 0)); + coord1NetDevice->GetPhy()->SetMobility(coord1Mobility); + + Ptr endNodeMobility = + CreateObject(); + endNodeMobility->SetPosition(Vector(100, 0, 0)); + endNodeNetDevice->GetPhy()->SetMobility(endNodeMobility); + + // MAC layer Callbacks hooks + MlmeScanConfirmCallback cb1; + cb1 = MakeCallback(&TestOrphanScan::ScanConfirm, this); + endNodeNetDevice->GetMac()->SetMlmeScanConfirmCallback(cb1); + + MlmeOrphanIndicationCallback cb2; + cb2 = MakeCallback(&TestOrphanScan::OrphanIndicationCoord, this); + coord1NetDevice->GetMac()->SetMlmeOrphanIndicationCallback(cb2); + ///////////////// + // ORPHAN SCAN // + ///////////////// + + // PAN coordinator N0 (PAN 5) is set to channel 12 in non-beacon mode + // but answer to beacon request and orphan notification commands. + MlmeStartRequestParams params; + params.m_panCoor = true; + params.m_PanId = 5; + params.m_bcnOrd = 15; + params.m_sfrmOrd = 15; + params.m_logCh = 12; + Simulator::ScheduleWithContext(1, + Seconds(2.0), + &LrWpanMac::MlmeStartRequest, + coord1NetDevice->GetMac(), + params); + + // End device N1 is set to scan 4 channels looking for the presence of a coordinator. + // On each channel, a single orphan notification command is sent and a response is + // waited for a maximum time of macResponseWaitTime. If a reply is received from a + // coordinator within this time (coordinator realignment command), the programmed scans on + // other channels is suspended. + // Scan Channels are represented by bits 0-26 (27 LSB) + // ch 14 ch 11 + // | | + // 0x7800 = 0000000000000000111100000000000 + MlmeScanRequestParams scanParams; + scanParams.m_chPage = 0; + scanParams.m_scanChannels = 0x7800; + scanParams.m_scanType = MLMESCAN_ORPHAN; + Simulator::ScheduleWithContext(1, + Seconds(3.0), + &LrWpanMac::MlmeScanRequest, + endNodeNetDevice->GetMac(), + scanParams); + + Simulator::Stop(Seconds(4000)); + NS_LOG_DEBUG("----------- Start of TestOrphanScan -------------------"); + Simulator::Run(); + + NS_TEST_EXPECT_MSG_EQ(m_orphanScanSuccess, + true, + "Error, no coordinator realignment commands" + " received during orphan scan"); + if (m_orphanScanSuccess) + { + NS_TEST_EXPECT_MSG_EQ(endNodeNetDevice->GetMac()->GetShortAddress(), + Mac16Address("00:02"), + "Error, end device did not receive short address" + " during orphan scan"); + } Simulator::Destroy(); } @@ -530,6 +719,7 @@ LrWpanMacTestSuite::LrWpanMacTestSuite() { AddTestCase(new TestRxOffWhenIdleAfterCsmaFailure, TestCase::QUICK); AddTestCase(new TestActiveScanPanDescriptors, TestCase::QUICK); + AddTestCase(new TestOrphanScan, TestCase::QUICK); } static LrWpanMacTestSuite g_lrWpanMacTestSuite; //!< Static variable for test initialization