A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lr-wpan-mac.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 The Boeing Company
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors:
7 * Gary Pei <guangyu.pei@boeing.com>
8 * kwong yin <kwong-sang.yin@boeing.com>
9 * Tom Henderson <thomas.r.henderson@boeing.com>
10 * Sascha Alexander Jopen <jopen@cs.uni-bonn.de>
11 * Erwan Livolant <erwan.livolant@inria.fr>
12 * Alberto Gallegos Ramonet <ramonet@fc.ritsumei.ac.jp>
13 */
14#include "lr-wpan-mac.h"
15
16#include "lr-wpan-constants.h"
17#include "lr-wpan-csmaca.h"
18#include "lr-wpan-mac-header.h"
20#include "lr-wpan-mac-trailer.h"
21
22#include <ns3/double.h>
23#include <ns3/log.h>
24#include <ns3/node.h>
25#include <ns3/packet.h>
26#include <ns3/random-variable-stream.h>
27#include <ns3/simulator.h>
28#include <ns3/uinteger.h>
29
30#undef NS_LOG_APPEND_CONTEXT
31#define NS_LOG_APPEND_CONTEXT \
32 std::clog << "[" << m_shortAddress << " | " << m_macExtendedAddress << "] ";
33
34namespace ns3
35{
36namespace lrwpan
37{
38
39NS_LOG_COMPONENT_DEFINE("LrWpanMac");
41
42std::ostream&
43operator<<(std::ostream& os, const MacState& state)
44{
45 switch (state)
46 {
48 os << "MAC IDLE";
49 break;
51 os << "CSMA";
52 break;
54 os << "SENDING";
55 break;
57 os << "ACK PENDING";
58 break;
60 os << "CHANNEL_ACCESS_FAILURE";
61 break;
63 os << "CHANNEL IDLE";
64 break;
66 os << "SET PHY to TX ON";
67 break;
69 os << "MAC GTS PERIOD";
70 break;
72 os << "SUPERFRAME INACTIVE PERIOD";
73 break;
75 os << "CSMA DEFERRED TO NEXT PERIOD";
76 break;
77 }
78 return os;
79}
80
83{
84 static TypeId tid =
85 TypeId("ns3::lrwpan::LrWpanMac")
86 .AddDeprecatedName("ns3::LrWpanMac")
88 .SetGroupName("LrWpan")
89 .AddConstructor<LrWpanMac>()
90 .AddAttribute("PanId",
91 "16-bit identifier of the associated PAN",
95 .AddTraceSource("MacTxEnqueue",
96 "Trace source indicating a packet has been "
97 "enqueued in the transaction queue",
99 "ns3::Packet::TracedCallback")
100 .AddTraceSource("MacTxDequeue",
101 "Trace source indicating a packet has was "
102 "dequeued from the transaction queue",
104 "ns3::Packet::TracedCallback")
105 .AddTraceSource("MacIndTxEnqueue",
106 "Trace source indicating a packet has been "
107 "enqueued in the indirect transaction queue",
109 "ns3::Packet::TracedCallback")
110 .AddTraceSource("MacIndTxDequeue",
111 "Trace source indicating a packet has was "
112 "dequeued from the indirect transaction queue",
114 "ns3::Packet::TracedCallback")
115 .AddTraceSource("MacTx",
116 "Trace source indicating a packet has "
117 "arrived for transmission by this device",
119 "ns3::Packet::TracedCallback")
120 .AddTraceSource("MacTxOk",
121 "Trace source indicating a packet has been "
122 "successfully sent",
124 "ns3::Packet::TracedCallback")
125 .AddTraceSource("MacTxDrop",
126 "Trace source indicating a packet has been "
127 "dropped during transmission",
129 "ns3::Packet::TracedCallback")
130 .AddTraceSource("MacIndTxDrop",
131 "Trace source indicating a packet has been "
132 "dropped from the indirect transaction queue"
133 "(The pending transaction list)",
135 "ns3::Packet::TracedCallback")
136 .AddTraceSource("MacPromiscRx",
137 "A packet has been received by this device, "
138 "has been passed up from the physical layer "
139 "and is being forwarded up the local protocol stack. "
140 "This is a promiscuous trace,",
142 "ns3::Packet::TracedCallback")
143 .AddTraceSource("MacRx",
144 "A packet has been received by this device, "
145 "has been passed up from the physical layer "
146 "and is being forwarded up the local protocol stack. "
147 "This is a non-promiscuous trace,",
149 "ns3::Packet::TracedCallback")
150 .AddTraceSource("MacRxDrop",
151 "Trace source indicating a packet was received, "
152 "but dropped before being forwarded up the stack",
154 "ns3::Packet::TracedCallback")
155 .AddTraceSource("Sniffer",
156 "Trace source simulating a non-promiscuous "
157 "packet sniffer attached to the device",
159 "ns3::Packet::TracedCallback")
160 .AddTraceSource("PromiscSniffer",
161 "Trace source simulating a promiscuous "
162 "packet sniffer attached to the device",
164 "ns3::Packet::TracedCallback")
165 .AddTraceSource("MacStateValue",
166 "The state of LrWpan Mac",
168 "ns3::TracedValueCallback::LrWpanMacState")
169 .AddTraceSource("MacIncSuperframeStatus",
170 "The period status of the incoming superframe",
172 "ns3::TracedValueCallback::SuperframeState")
173 .AddTraceSource("MacOutSuperframeStatus",
174 "The period status of the outgoing superframe",
176 "ns3::TracedValueCallback::SuperframeState")
177 .AddTraceSource("MacState",
178 "The state of LrWpan Mac",
180 "ns3::lrwpan::LrWpanMac::StateTracedCallback")
181 .AddTraceSource("MacSentPkt",
182 "Trace source reporting some information about "
183 "the sent packet",
185 "ns3::lrwpan::LrWpanMac::SentTracedCallback")
186 .AddTraceSource("IfsEnd",
187 "Trace source reporting the end of an "
188 "Interframe space (IFS)",
190 "ns3::Packet::TracedCallback");
191 return tid;
192}
193
195{
196 // First set the state to a known value, call ChangeMacState to fire trace source.
198
200
203
204 m_macRxOnWhenIdle = true;
205 m_macPanId = 0xffff;
207 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
210 m_macPromiscuousMode = false;
214 m_txPkt = nullptr;
215 m_rxPkt = nullptr;
217 m_ifs = 0;
218
219 m_macLIFSPeriod = 40;
220 m_macSIFSPeriod = 12;
221
222 m_panCoor = false;
223 m_coor = false;
224 m_macBeaconOrder = 15;
226 m_macTransactionPersistenceTime = 500; // 0x01F5
228 m_macAutoRequest = true;
229
232 m_beaconTrackingOn = false;
234
238
241
242 m_maxTxQueueSize = m_txQueue.max_size();
244
246 m_macDsn = SequenceNumber8(m_uniformVar->GetInteger(0, 255));
247 m_macBsn = SequenceNumber8(m_uniformVar->GetInteger(0, 255));
250 m_shortAddress = Mac16Address("FF:FF"); // FF:FF = The address is not assigned.
251}
252
256
257void
259{
261 {
262 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
263 }
264 else
265 {
266 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
267 }
268
270}
271
272void
274{
275 if (m_csmaCa)
276 {
277 m_csmaCa->Dispose();
278 m_csmaCa = nullptr;
279 }
280 m_txPkt = nullptr;
281
282 for (uint32_t i = 0; i < m_txQueue.size(); i++)
283 {
284 m_txQueue[i]->txQPkt = nullptr;
285 }
286 m_txQueue.clear();
287
288 for (uint32_t i = 0; i < m_indTxQueue.size(); i++)
289 {
290 m_indTxQueue[i]->txQPkt = nullptr;
291 }
292 m_indTxQueue.clear();
293
294 m_phy = nullptr;
307
308 m_panDescriptorList.clear();
309 m_energyDetectList.clear();
310 m_unscannedChannels.clear();
311
316
318}
319
320bool
322{
323 return m_macRxOnWhenIdle;
324}
325
326void
328{
329 NS_LOG_FUNCTION(this << rxOnWhenIdle);
330 m_macRxOnWhenIdle = rxOnWhenIdle;
331
332 if (m_macState == MAC_IDLE)
333 {
335 {
336 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
337 }
338 else
339 {
340 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
341 }
342 }
343}
344
345void
350
351void
356
359{
360 return m_shortAddress;
361}
362
368
369void
371{
372 NS_LOG_FUNCTION(this << p);
373
374 McpsDataConfirmParams confirmParams;
375 confirmParams.m_msduHandle = params.m_msduHandle;
376
377 // TODO: We need a drop trace for the case that the packet is too large or the request
378 // parameters are maleformed.
379 // The current tx drop trace is not suitable, because packets dropped using this trace
380 // carry the mac header and footer, while packets being dropped here do not have them.
381
383 m_macDsn++;
384
386 {
387 // Note, this is just testing maximum theoretical frame size per the spec
388 // The frame could still be too large once headers are put on
389 // in which case the phy will reject it instead
390 NS_LOG_ERROR(this << " packet too big: " << p->GetSize());
391 confirmParams.m_status = MacStatus::FRAME_TOO_LONG;
393 {
394 m_mcpsDataConfirmCallback(confirmParams);
395 }
396 return;
397 }
398
399 if ((params.m_srcAddrMode == NO_PANID_ADDR) && (params.m_dstAddrMode == NO_PANID_ADDR))
400 {
401 NS_LOG_ERROR(this << " Can not send packet with no Address field");
402 confirmParams.m_status = MacStatus::INVALID_ADDRESS;
404 {
405 m_mcpsDataConfirmCallback(confirmParams);
406 }
407 return;
408 }
409 switch (params.m_srcAddrMode)
410 {
411 case NO_PANID_ADDR:
412 macHdr.SetSrcAddrMode(params.m_srcAddrMode);
413 macHdr.SetNoPanIdComp();
414 break;
416 NS_ABORT_MSG("Can not set source address type to ADDR_MODE_RESERVED. Aborting.");
417 break;
418 case SHORT_ADDR:
419 macHdr.SetSrcAddrMode(params.m_srcAddrMode);
421 break;
422 case EXT_ADDR:
423 macHdr.SetSrcAddrMode(params.m_srcAddrMode);
425 break;
426 default:
427 NS_LOG_ERROR(this << " Can not send packet with incorrect Source Address mode = "
428 << params.m_srcAddrMode);
429 confirmParams.m_status = MacStatus::INVALID_ADDRESS;
431 {
432 m_mcpsDataConfirmCallback(confirmParams);
433 }
434 return;
435 }
436 switch (params.m_dstAddrMode)
437 {
438 case NO_PANID_ADDR:
439 macHdr.SetDstAddrMode(params.m_dstAddrMode);
440 macHdr.SetNoPanIdComp();
441 break;
443 NS_ABORT_MSG("Can not set destination address type to ADDR_MODE_RESERVED. Aborting.");
444 break;
445 case SHORT_ADDR:
446 macHdr.SetDstAddrMode(params.m_dstAddrMode);
447 macHdr.SetDstAddrFields(params.m_dstPanId, params.m_dstAddr);
448 break;
449 case EXT_ADDR:
450 macHdr.SetDstAddrMode(params.m_dstAddrMode);
451 macHdr.SetDstAddrFields(params.m_dstPanId, params.m_dstExtAddr);
452 break;
453 default:
454 NS_LOG_ERROR(this << " Can not send packet with incorrect Destination Address mode = "
455 << params.m_dstAddrMode);
456 confirmParams.m_status = MacStatus::INVALID_ADDRESS;
458 {
459 m_mcpsDataConfirmCallback(confirmParams);
460 }
461 return;
462 }
463
464 // IEEE 802.15.4-2006 (7.5.6.1)
465 // Src & Dst PANs are identical, PAN compression is ON
466 // only the dst PAN is serialized making the MAC header 2 bytes smaller
467 if ((params.m_dstAddrMode != NO_PANID_ADDR && params.m_srcAddrMode != NO_PANID_ADDR) &&
468 (macHdr.GetDstPanId() == macHdr.GetSrcPanId()))
469 {
470 macHdr.SetPanIdComp();
471 }
472
473 macHdr.SetSecDisable();
474 // extract the first 3 bits in TxOptions
475 int b0 = params.m_txOptions & TX_OPTION_ACK;
476 int b1 = params.m_txOptions & TX_OPTION_GTS;
477 int b2 = params.m_txOptions & TX_OPTION_INDIRECT;
478
479 if (b0 == TX_OPTION_ACK)
480 {
481 // Set AckReq bit only if the destination is not the broadcast address.
482 if (macHdr.GetDstAddrMode() == SHORT_ADDR)
483 {
484 // short address and ACK requested.
485 Mac16Address shortAddr = macHdr.GetShortDstAddr();
486 if (shortAddr.IsBroadcast() || shortAddr.IsMulticast())
487 {
488 NS_LOG_LOGIC("LrWpanMac::McpsDataRequest: requested an ACK on broadcast or "
489 "multicast destination ("
490 << shortAddr << ") - forcefully removing it.");
491 macHdr.SetNoAckReq();
492 params.m_txOptions &= ~uint8_t(TX_OPTION_ACK);
493 }
494 else
495 {
496 macHdr.SetAckReq();
497 }
498 }
499 else
500 {
501 // other address (not short) and ACK requested
502 macHdr.SetAckReq();
503 }
504 }
505 else
506 {
507 macHdr.SetNoAckReq();
508 }
509
510 if (b1 == TX_OPTION_GTS)
511 {
512 // TODO:GTS Transmission
513 }
514 else if (b2 == TX_OPTION_INDIRECT)
515 {
516 // Indirect Tx
517 // A COORDINATOR will save the packet in the pending queue and await for data
518 // requests from its associated devices. The devices are aware of pending data,
519 // from the pending bit information extracted from the received beacon.
520 // A DEVICE must be tracking beacons (MLME-SYNC.request is running) before attempting
521 // request data from the coordinator.
522
523 // Indirect Transmission can only be done by PAN coordinator or coordinators.
525 p->AddHeader(macHdr);
526
527 LrWpanMacTrailer macTrailer;
528 // Calculate FCS if the global attribute ChecksumEnabled is set.
530 {
531 macTrailer.EnableFcs(true);
532 macTrailer.SetFcs(p);
533 }
534 p->AddTrailer(macTrailer);
535
536 NS_LOG_ERROR(this << " Indirect transmissions not currently supported");
537 // Note: The current Pending transaction list should work for indirect transmissions.
538 // However, this is not tested yet. For now, we block the use of indirect transmissions.
539 // TODO: Save packet in the Pending Transaction list.
540 // EnqueueInd (p);
541 }
542 else
543 {
544 // Direct Tx
545 // From this point the packet will be pushed to a Tx queue and immediately
546 // use a slotted (beacon-enabled) or unslotted (nonbeacon-enabled) version of CSMA/CA
547 // before sending the packet, depending on whether it has previously
548 // received a valid beacon or not.
549
550 p->AddHeader(macHdr);
551
552 LrWpanMacTrailer macTrailer;
553 // Calculate FCS if the global attribute ChecksumEnabled is set.
555 {
556 macTrailer.EnableFcs(true);
557 macTrailer.SetFcs(p);
558 }
559 p->AddTrailer(macTrailer);
560
562 txQElement->txQMsduHandle = params.m_msduHandle;
563 txQElement->txQPkt = p;
564 EnqueueTxQElement(txQElement);
565 CheckQueue();
566 }
567}
568
569void
571{
572 NS_LOG_FUNCTION(this);
574
575 MlmeStartConfirmParams confirmParams;
576
577 if (GetShortAddress() == Mac16Address("ff:ff"))
578 {
579 NS_LOG_ERROR(this << " Invalid MAC short address");
582 {
583 m_mlmeStartConfirmCallback(confirmParams);
584 }
585 return;
586 }
587
588 if ((params.m_bcnOrd > 15) || (params.m_sfrmOrd > params.m_bcnOrd))
589 {
592 {
593 m_mlmeStartConfirmCallback(confirmParams);
594 }
595 NS_LOG_ERROR(this << "Incorrect superframe order or beacon order.");
596 return;
597 }
598
599 // Mark primitive as pending and save the start params while the new page and channel is set.
601 m_startParams = params;
602
604 pibAttr->phyCurrentPage = m_startParams.m_logChPage;
605 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
606}
607
608void
610{
611 NS_LOG_FUNCTION(this);
612
613 MlmeScanConfirmParams confirmParams;
614 confirmParams.m_scanType = params.m_scanType;
615 confirmParams.m_chPage = params.m_chPage;
616
618 {
620 {
622 m_mlmeScanConfirmCallback(confirmParams);
623 }
624 NS_LOG_ERROR(this << " A channel scan is already in progress");
625 return;
626 }
627
628 if (params.m_scanDuration > 14 || params.m_scanType > MLMESCAN_ORPHAN)
629 {
631 {
633 m_mlmeScanConfirmCallback(confirmParams);
634 }
635 NS_LOG_ERROR(this << "Invalid scan duration or unsupported scan type");
636 return;
637 }
638 // Temporary store macPanId and set macPanId to 0xFFFF to accept all beacons.
640 m_macPanId = 0xFFFF;
641
642 m_panDescriptorList.clear();
643 m_energyDetectList.clear();
644 m_unscannedChannels.clear();
645
646 // TODO: stop beacon transmission
647
648 // Cancel any ongoing CSMA/CA operations and set to unslotted mode for scan
649 m_csmaCa->Cancel();
655 m_csmaCa->SetUnSlottedCsmaCa();
656
658
659 // Mark primitive as pending and save the scan params while the new page and/or channel is set.
660 m_scanParams = params;
662
664 pibAttr->phyCurrentPage = params.m_chPage;
665 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
666}
667
668void
670{
671 NS_LOG_FUNCTION(this);
672
673 // Association is typically preceded by beacon reception and a MLME-SCAN.request, therefore,
674 // the values of the Associate.request params usually come from the information
675 // obtained from those operations.
677 m_associateParams = params;
678 bool invalidRequest = false;
679
680 if (params.m_coordPanId == 0xffff)
681 {
682 invalidRequest = true;
683 }
684
685 if (!invalidRequest && params.m_coordAddrMode == SHORT_ADDR)
686 {
687 if (params.m_coordShortAddr == Mac16Address("ff:ff") ||
688 params.m_coordShortAddr == Mac16Address("ff:fe"))
689 {
690 invalidRequest = true;
691 }
692 }
693 else if (!invalidRequest && params.m_coordAddrMode == EXT_ADDR)
694 {
695 if (params.m_coordExtAddr == Mac64Address("ff:ff:ff:ff:ff:ff:ff:ff") ||
696 params.m_coordExtAddr == Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed"))
697 {
698 invalidRequest = true;
699 }
700 }
701
702 if (invalidRequest)
703 {
706 NS_LOG_ERROR(this << " Invalid PAN id in Association request");
708 {
709 MlmeAssociateConfirmParams confirmParams;
710 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
712 m_mlmeAssociateConfirmCallback(confirmParams);
713 }
714 }
715 else
716 {
718 pibAttr->phyCurrentPage = params.m_chPage;
719 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
720 }
721}
722
723void
725{
726 // the primitive is no longer pending (channel & page are set)
728 // As described in IEEE 802.15.4-2011 (Section 5.1.3.1)
731 {
733 }
734 else
735 {
738 }
739
741}
742
743void
745{
746 // Associate Short Address (m_assocShortAddr)
747 // FF:FF = Association Request failed
748 // FF:FE = The association request is accepted, but the device should use its extended address
749 // Other = The assigned short address by the coordinator
750
751 NS_LOG_FUNCTION(this);
752
754 m_macDsn++;
755 LrWpanMacTrailer macTrailer;
756 Ptr<Packet> commandPacket = Create<Packet>();
757
758 // Mac header Assoc. Response Comm. See 802.15.4-2011 (Section 5.3.2.1)
761 macHdr.SetPanIdComp();
762 macHdr.SetDstAddrFields(m_macPanId, params.m_extDevAddr);
763 macHdr.SetSrcAddrFields(0xffff, GetExtendedAddress());
764
766 macPayload.SetShortAddr(params.m_assocShortAddr);
767 macPayload.SetAssociationStatus(static_cast<uint8_t>(params.m_status));
768
769 macHdr.SetSecDisable();
770 macHdr.SetAckReq();
771
772 commandPacket->AddHeader(macPayload);
773 commandPacket->AddHeader(macHdr);
774
775 // Calculate FCS if the global attribute ChecksumEnabled is set.
777 {
778 macTrailer.EnableFcs(true);
779 macTrailer.SetFcs(commandPacket);
780 }
781
782 commandPacket->AddTrailer(macTrailer);
783
784 // Save packet in the Pending Transaction list.
785 EnqueueInd(commandPacket);
786}
787
788void
790{
791 NS_LOG_FUNCTION(this);
792 // Mac header Coordinator realigment Command
793 // See 802.15.4-2011 (Section 6.2.7.2)
795 m_macDsn++;
796 LrWpanMacTrailer macTrailer;
797 Ptr<Packet> commandPacket = Create<Packet>();
798 macHdr.SetPanIdComp();
800 macHdr.SetDstAddrFields(0xffff, params.m_orphanAddr);
801
804 macHdr.SetSrcAddrFields(m_macPanId, Mac16Address("FF:FF"));
805
806 macHdr.SetFrameVer(0x01);
807 macHdr.SetSecDisable();
808 macHdr.SetAckReq();
809
811 macPayload.SetPanId(m_macPanId);
813 macPayload.SetChannel(m_phy->GetCurrentChannelNum());
814 macPayload.SetPage(m_phy->GetCurrentPage());
815
816 if (params.m_assocMember)
817 {
818 // The orphan device was associated with the coordinator
819
820 // Either FF:FE for extended address mode
821 // or the short address assigned by the coord.
822 macPayload.SetShortAddr(params.m_shortAddr);
823 }
824 else
825 {
826 // The orphan device was NOT associated with the coordinator
827 macPayload.SetShortAddr(Mac16Address("FF:FF"));
828 }
829
830 commandPacket->AddHeader(macPayload);
831 commandPacket->AddHeader(macHdr);
832
833 // Calculate FCS if the global attribute ChecksumEnabled is set.
835 {
836 macTrailer.EnableFcs(true);
837 macTrailer.SetFcs(commandPacket);
838 }
839
840 commandPacket->AddTrailer(macTrailer);
841
843 txQElement->txQPkt = commandPacket;
844 EnqueueTxQElement(txQElement);
845 CheckQueue();
846}
847
848void
850{
851 NS_LOG_FUNCTION(this);
852 NS_ASSERT(params.m_logCh <= 26 && m_macPanId != 0xffff);
853
854 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
855 // change phy current logical channel
857 pibAttr->phyCurrentChannel = params.m_logCh;
858 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
859
860 // Enable Phy receiver
861 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
862
863 uint64_t searchSymbols;
864 Time searchBeaconTime;
865
867 {
869 }
870
871 if (params.m_trackBcn)
872 {
874 // search for a beacon for a time = incomingSuperframe symbols + 960 symbols
875 searchSymbols =
877 searchBeaconTime = Seconds((double)searchSymbols / symbolRate);
878 m_beaconTrackingOn = true;
880 Simulator::Schedule(searchBeaconTime, &LrWpanMac::BeaconSearchTimeout, this);
881 }
882 else
883 {
884 m_beaconTrackingOn = false;
885 }
886}
887
888void
890{
891 NS_LOG_FUNCTION(this);
892
894 m_macBsn++;
895
897
898 Ptr<Packet> beaconPacket = Create<Packet>();
899 // TODO: complete poll request (part of indirect transmissions)
900 NS_FATAL_ERROR(this << " Poll request currently not supported");
901}
902
903void
905{
906 MlmeSetConfirmParams confirmParams;
907 confirmParams.m_status = MacStatus::SUCCESS;
908
909 switch (id)
910 {
912 m_macAssociationPermit = attribute->macAssociationPermit;
913 break;
914 case macBeaconPayload:
915 if (attribute->macBeaconPayload.size() > aMaxBeaconPayloadLength)
916 {
918 }
919 else
920 {
921 m_macBeaconPayload = attribute->macBeaconPayload;
922 }
923 break;
925 if (attribute->macBeaconPayloadLength > aMaxBeaconPayloadLength)
926 {
928 }
929 else
930 {
931 m_macBeaconPayloadLength = attribute->macBeaconPayloadLength;
932 }
933 break;
934 case macShortAddress:
935 m_shortAddress = attribute->macShortAddress;
936 break;
938 confirmParams.m_status = MacStatus::READ_ONLY;
939 break;
940 case macPanId:
942 break;
944 m_macPromiscuousMode = attribute->macPromiscuousMode;
945 break;
946 case macRxOnWhenIdle:
947 m_macRxOnWhenIdle = attribute->macRxOnWhenIdle;
948 break;
949 case pCurrentChannel: {
951 pibAttr->phyCurrentChannel = attribute->pCurrentChannel;
952 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
953 break;
954 }
955 case pCurrentPage: {
957 pibAttr->phyCurrentPage = attribute->pCurrentPage;
958 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
959 break;
960 }
961 default:
962 // TODO: Add support for setting other attributes
964 break;
965 }
966
968 {
969 confirmParams.id = id;
970 m_mlmeSetConfirmCallback(confirmParams);
971 }
972}
973
974void
976{
979
980 switch (id)
981 {
983 attributes->macAssociationPermit = m_macAssociationPermit;
984 break;
985 case macBeaconPayload:
986 attributes->macBeaconPayload = m_macBeaconPayload;
987 break;
989 attributes->macBeaconPayloadLength = m_macBeaconPayloadLength;
990 break;
992 attributes->macPromiscuousMode = m_macPromiscuousMode;
993 break;
994 case macRxOnWhenIdle:
995 attributes->macRxOnWhenIdle = m_macRxOnWhenIdle;
996 break;
997 case macShortAddress:
998 attributes->macShortAddress = m_shortAddress;
999 break;
1000 case macExtendedAddress:
1001 attributes->macExtendedAddress = m_macExtendedAddress;
1002 break;
1003 case macPanId:
1004 attributes->macPanId = m_macPanId;
1005 break;
1006 case pCurrentChannel:
1007 attributes->pCurrentChannel = m_phy->GetCurrentChannelNum();
1008 break;
1009 case pCurrentPage:
1010 attributes->pCurrentPage = m_phy->GetCurrentPage();
1011 break;
1012 default:
1014 break;
1015 }
1016
1018 {
1019 m_mlmeGetConfirmCallback(status, id, attributes);
1020 }
1021}
1022
1023void
1025{
1026 NS_LOG_FUNCTION(this);
1028
1029 m_macBsn++;
1030
1031 Ptr<Packet> beaconPacket;
1032 if (m_macBeaconPayload.empty())
1033 {
1034 beaconPacket = Create<Packet>();
1035 }
1036 else
1037 {
1038 // Extract the octets from m_macBeaconPayload and place them in a packet
1039 uint8_t* octets = &m_macBeaconPayload[0];
1040 beaconPacket = Create<Packet>(octets, m_macBeaconPayload.size());
1041 }
1042
1045 macHdr.SetDstAddrFields(GetPanId(), Mac16Address("ff:ff"));
1046
1047 // see IEEE 802.15.4-2011 Section 5.1.2.4
1048 if (GetShortAddress() == Mac16Address("ff:fe"))
1049 {
1052 }
1053 else
1054 {
1057 }
1058
1059 macHdr.SetSecDisable();
1060 macHdr.SetNoAckReq();
1061
1062 BeaconPayloadHeader macPayload;
1064 macPayload.SetGtsFields(GetGtsFields());
1066
1067 beaconPacket->AddHeader(macPayload);
1068 beaconPacket->AddHeader(macHdr);
1069
1070 // Calculate FCS if the global attribute ChecksumEnabled is set.
1071 LrWpanMacTrailer macTrailer;
1073 {
1074 macTrailer.EnableFcs(true);
1075 macTrailer.SetFcs(beaconPacket);
1076 }
1077
1078 beaconPacket->AddTrailer(macTrailer);
1079
1080 if (m_csmaCa->IsSlottedCsmaCa())
1081 {
1082 // Beacon in beacon-enabled mode
1083 // Transmit beacon immediately (i.e. Without CSMA/CA)
1084 m_txPkt = beaconPacket;
1086 NS_LOG_DEBUG("Outgoing superframe Active Portion (Beacon + CAP + CFP): "
1087 << m_superframeDuration << " symbols");
1088
1090 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TX_ON);
1091 }
1092 else
1093 {
1094 // Beacon as a result of a beacon request
1095 // The beacon shall be transmitted using CSMA/CA
1096 // IEEE 802.15.4-2011 (Section 5.1.2.1.2)
1098 txQElement->txQPkt = beaconPacket;
1099 EnqueueTxQElement(txQElement);
1100 CheckQueue();
1101 }
1102}
1103
1104void
1106{
1107 NS_LOG_FUNCTION(this);
1108
1110 m_macDsn++;
1111 LrWpanMacTrailer macTrailer;
1112 Ptr<Packet> commandPacket = Create<Packet>();
1113
1114 // Beacon Request Command Mac header values See IEEE 802.15.4-2011 (Section 5.3.7)
1115 macHdr.SetNoPanIdComp();
1118
1119 // Not associated PAN, broadcast dst address
1120 macHdr.SetDstAddrFields(0xFFFF, Mac16Address("FF:FF"));
1121
1122 macHdr.SetSecDisable();
1123 macHdr.SetNoAckReq();
1124
1125 CommandPayloadHeader macPayload;
1127
1128 commandPacket->AddHeader(macPayload);
1129 commandPacket->AddHeader(macHdr);
1130
1131 // Calculate FCS if the global attribute ChecksumEnabled is set.
1133 {
1134 macTrailer.EnableFcs(true);
1135 macTrailer.SetFcs(commandPacket);
1136 }
1137
1138 commandPacket->AddTrailer(macTrailer);
1139
1141 txQElement->txQPkt = commandPacket;
1142 EnqueueTxQElement(txQElement);
1143 CheckQueue();
1144}
1145
1146void
1148{
1150 m_macDsn++;
1151 LrWpanMacTrailer macTrailer;
1152 Ptr<Packet> commandPacket = Create<Packet>();
1153
1154 // See IEEE 802.15.4-2011 (5.3.6)
1155 macHdr.SetPanIdComp();
1156
1158 macHdr.SetSrcAddrFields(0xFFFF, GetExtendedAddress());
1159
1161 macHdr.SetDstAddrFields(0xFFFF, Mac16Address("FF:FF"));
1162
1163 macHdr.SetSecDisable();
1164 macHdr.SetNoAckReq();
1165
1166 CommandPayloadHeader macPayload;
1168
1169 commandPacket->AddHeader(macPayload);
1170 commandPacket->AddHeader(macHdr);
1171
1172 // Calculate FCS if the global attribute ChecksumEnabled is set.
1174 {
1175 macTrailer.EnableFcs(true);
1176 macTrailer.SetFcs(commandPacket);
1177 }
1178
1179 commandPacket->AddTrailer(macTrailer);
1180
1182 txQElement->txQPkt = commandPacket;
1183 EnqueueTxQElement(txQElement);
1184 CheckQueue();
1185}
1186
1187void
1189{
1190 NS_LOG_FUNCTION(this);
1191
1193 m_macDsn++;
1194 LrWpanMacTrailer macTrailer;
1195 Ptr<Packet> commandPacket = Create<Packet>();
1196
1197 // Assoc. Req. Comm. Mac header values See IEEE 802.15.4-2011 (Section 5.3.1.1)
1199 macHdr.SetSrcAddrFields(0xffff, GetExtendedAddress());
1200
1202 {
1205 }
1206 else
1207 {
1210 }
1211
1212 macHdr.SetSecDisable();
1213 macHdr.SetAckReq();
1214
1217
1218 commandPacket->AddHeader(macPayload);
1219 commandPacket->AddHeader(macHdr);
1220
1221 // Calculate FCS if the global attribute ChecksumEnabled is set.
1223 {
1224 macTrailer.EnableFcs(true);
1225 macTrailer.SetFcs(commandPacket);
1226 }
1227
1228 commandPacket->AddTrailer(macTrailer);
1229
1231 txQElement->txQPkt = commandPacket;
1232 EnqueueTxQElement(txQElement);
1233 CheckQueue();
1234}
1235
1236void
1238{
1239 // See IEEE 802.15.4-2011 (Section 5.3.5)
1240 // This command can be sent for 3 different situations:
1241 // a) In response to a beacon indicating that there is data for the device.
1242 // b) Triggered by MLME-POLL.request.
1243 // c) To follow an ACK of an Association Request command and continue the associate process.
1244
1245 // TODO: Implementation of a) and b) will be done when Indirect transmissions are fully
1246 // supported.
1247 // for now, only case c) is considered.
1248
1249 NS_LOG_FUNCTION(this);
1250
1252 m_macDsn++;
1253 LrWpanMacTrailer macTrailer;
1254 Ptr<Packet> commandPacket = Create<Packet>();
1255
1256 // Mac Header values (Section 5.3.5)
1258 macHdr.SetSrcAddrFields(0xffff, m_macExtendedAddress);
1259
1260 if (m_macCoordShortAddress == Mac16Address("ff:fe"))
1261 {
1264 }
1265 else
1266 {
1269 }
1270
1271 macHdr.SetSecDisable();
1272 macHdr.SetAckReq();
1273
1275
1276 commandPacket->AddHeader(macPayload);
1277 commandPacket->AddHeader(macHdr);
1278
1279 // Calculate FCS if the global attribute ChecksumEnabled is set.
1281 {
1282 macTrailer.EnableFcs(true);
1283 macTrailer.SetFcs(commandPacket);
1284 }
1285
1286 commandPacket->AddTrailer(macTrailer);
1287
1288 // Set the Command packet to be transmitted
1290 txQElement->txQPkt = commandPacket;
1291 EnqueueTxQElement(txQElement);
1292 CheckQueue();
1293}
1294
1295void
1297{
1298 LrWpanMacHeader receivedMacHdr;
1299 rxDataReqPkt->RemoveHeader(receivedMacHdr);
1300 CommandPayloadHeader receivedMacPayload;
1301 rxDataReqPkt->RemoveHeader(receivedMacPayload);
1302
1304
1306 bool elementFound;
1307 elementFound = DequeueInd(receivedMacHdr.GetExtSrcAddr(), indTxQElement);
1308 if (elementFound)
1309 {
1311 txQElement->txQPkt = indTxQElement->txQPkt;
1312 m_txQueue.emplace_back(txQElement);
1313 }
1314 else
1315 {
1316 NS_LOG_DEBUG("Requested element not found in pending list");
1317 }
1318}
1319
1320void
1322{
1323 // Association response command was not received, return to default values.
1324 m_macPanId = 0xffff;
1326 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
1327
1329 {
1330 MlmeAssociateConfirmParams confirmParams;
1331 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
1332 confirmParams.m_status = MacStatus::NO_DATA;
1333 m_mlmeAssociateConfirmCallback(confirmParams);
1334 }
1335}
1336
1337void
1339{
1340 NS_LOG_FUNCTION(this);
1341 // The primitive is no longer pending (Channel & Page have been set)
1343
1344 if (m_startParams.m_coorRealgn) // Coordinator Realignment
1345 {
1346 // TODO: Send realignment request command frame in CSMA/CA
1347 NS_LOG_ERROR(this << " Coordinator realignment request not supported");
1348 return;
1349 }
1350 else
1351 {
1353 {
1354 m_panCoor = true;
1355 }
1356
1357 m_coor = true;
1359
1360 NS_ASSERT(m_startParams.m_PanId != 0xffff);
1361
1363 if (m_macBeaconOrder == 15)
1364 {
1365 // Non-beacon enabled PAN
1366 // Cancel any ongoing events and CSMA-CA process
1368 m_fnlCapSlot = 15;
1369 m_beaconInterval = 0;
1370
1371 m_csmaCa->Cancel();
1380
1381 m_csmaCa->SetUnSlottedCsmaCa();
1382
1384 {
1385 MlmeStartConfirmParams confirmParams;
1386 confirmParams.m_status = MacStatus::SUCCESS;
1387 m_mlmeStartConfirmCallback(confirmParams);
1388 }
1389
1390 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
1391 }
1392 else
1393 {
1395 m_csmaCa->SetBatteryLifeExtension(m_startParams.m_battLifeExt);
1396
1397 m_csmaCa->SetSlottedCsmaCa();
1398
1399 // TODO: Calculate the real Final CAP slot (requires GTS implementation)
1400 // FinalCapSlot = Superframe duration slots - CFP slots.
1401 // In the current implementation the value of the final cap slot is equal to
1402 // the total number of possible slots in the superframe (15).
1403 m_fnlCapSlot = 15;
1404
1407 m_superframeDuration = (static_cast<uint32_t>(1 << m_macSuperframeOrder)) *
1409
1410 // TODO: change the beacon sending according to the startTime parameter (if not PAN
1411 // coordinator)
1412
1414 }
1415 }
1416}
1417
1418void
1420{
1421 NS_LOG_FUNCTION(this);
1422
1424
1425 bool channelFound = false;
1426
1427 for (int i = m_channelScanIndex; i <= 26; i++)
1428 {
1430 {
1431 channelFound = true;
1432 break;
1433 }
1435 }
1436
1437 if (channelFound)
1438 {
1439 // Switch to the next channel in the list and restart scan
1441 pibAttr->phyCurrentChannel = m_channelScanIndex;
1442 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
1443 }
1444 else
1445 {
1446 // All channels in the list scan completed.
1447 // Return variables to the values before the scan and return the status to the next layer.
1449 m_macPanIdScan = 0;
1450
1451 // TODO: restart beacon transmissions that were active before the beginning of the scan
1452 // (i.e when a coordinator perform a scan and it was already transmitting beacons)
1453 MlmeScanConfirmParams confirmParams;
1454 confirmParams.m_chPage = m_scanParams.m_chPage;
1455 confirmParams.m_scanType = m_scanParams.m_scanType;
1456 confirmParams.m_energyDetList = {};
1457 confirmParams.m_unscannedCh = m_unscannedChannels;
1458 confirmParams.m_resultListSize = m_panDescriptorList.size();
1459
1460 // See IEEE 802.15.4-2011, Table 31 (panDescriptorList value on macAutoRequest)
1461 // and Section 6.2.10.2
1462 switch (confirmParams.m_scanType)
1463 {
1464 case MLMESCAN_PASSIVE:
1465 if (m_macAutoRequest)
1466 {
1467 confirmParams.m_panDescList = m_panDescriptorList;
1468 }
1469 confirmParams.m_status = MacStatus::SUCCESS;
1470 break;
1471 case MLMESCAN_ACTIVE:
1472 if (m_panDescriptorList.empty())
1473 {
1474 confirmParams.m_status = MacStatus::NO_BEACON;
1475 }
1476 else
1477 {
1478 if (m_macAutoRequest)
1479 {
1480 confirmParams.m_panDescList = m_panDescriptorList;
1481 }
1482 confirmParams.m_status = MacStatus::SUCCESS;
1483 }
1484 break;
1485 case MLMESCAN_ORPHAN:
1486 confirmParams.m_panDescList = {};
1487 confirmParams.m_status = MacStatus::NO_BEACON;
1488 confirmParams.m_resultListSize = 0;
1489 // The device lost track of the coordinator and was unable
1490 // to locate it, disassociate from the network.
1491 m_macPanId = 0xffff;
1492 m_shortAddress = Mac16Address("FF:FF");
1494 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
1495 break;
1496 default:
1497 NS_LOG_ERROR(this << " Invalid scan type");
1498 }
1499
1502 m_scanParams = {};
1503
1505 {
1506 m_mlmeScanConfirmCallback(confirmParams);
1507 }
1508 }
1509}
1510
1511void
1513{
1514 NS_LOG_FUNCTION(this);
1515 // Add the results of channel energy scan to the detectList
1517 m_maxEnergyLevel = 0;
1518
1520
1521 bool channelFound = false;
1522 for (int i = m_channelScanIndex; i <= 26; i++)
1523 {
1525 {
1526 channelFound = true;
1527 break;
1528 }
1530 }
1531
1532 if (channelFound)
1533 {
1534 // switch to the next channel in the list and restart scan
1536 pibAttr->phyCurrentChannel = m_channelScanIndex;
1537 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
1538 }
1539 else
1540 {
1541 // Scan on all channels on the list completed
1542 // Return to the MAC values previous to start of the first scan.
1544 m_macPanIdScan = 0;
1545
1546 // TODO: restart beacon transmissions that were active before the beginning of the scan
1547 // (i.e when a coordinator perform a scan and it was already transmitting beacons)
1548
1549 // All channels scanned, report success
1550 MlmeScanConfirmParams confirmParams;
1551 confirmParams.m_status = MacStatus::SUCCESS;
1552 confirmParams.m_chPage = m_phy->GetCurrentPage();
1553 confirmParams.m_scanType = m_scanParams.m_scanType;
1554 confirmParams.m_energyDetList = m_energyDetectList;
1555 confirmParams.m_resultListSize = m_energyDetectList.size();
1556
1559 m_scanParams = {};
1560
1562 {
1563 m_mlmeScanConfirmCallback(confirmParams);
1564 }
1565 }
1566}
1567
1568void
1570{
1571 uint32_t activeSlot;
1572 uint64_t capDuration;
1573 Time endCapTime;
1574 uint64_t symbolRate;
1575
1576 symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1577
1578 if (superframeType == OUTGOING)
1579 {
1581 activeSlot = m_superframeDuration / 16;
1582 capDuration = activeSlot * (m_fnlCapSlot + 1);
1583 endCapTime = Seconds((double)capDuration / symbolRate);
1584 // Obtain the end of the CAP by adjust the time it took to send the beacon
1585 endCapTime -= (Simulator::Now() - m_macBeaconTxTime);
1586
1587 NS_LOG_DEBUG("Outgoing superframe CAP duration " << (endCapTime.GetSeconds() * symbolRate)
1588 << " symbols (" << endCapTime.As(Time::S)
1589 << ")");
1590 NS_LOG_DEBUG("Active Slots duration " << activeSlot << " symbols");
1591
1592 m_capEvent =
1594 }
1595 else
1596 {
1598 activeSlot = m_incomingSuperframeDuration / 16;
1599 capDuration = activeSlot * (m_incomingFnlCapSlot + 1);
1600 endCapTime = Seconds((double)capDuration / symbolRate);
1601 // Obtain the end of the CAP by adjust the time it took to receive the beacon
1602 endCapTime -= (Simulator::Now() - m_macBeaconRxTime);
1603
1604 NS_LOG_DEBUG("Incoming superframe CAP duration " << (endCapTime.GetSeconds() * symbolRate)
1605 << " symbols (" << endCapTime.As(Time::S)
1606 << ")");
1607 NS_LOG_DEBUG("Active Slots duration " << activeSlot << " symbols");
1608
1609 m_capEvent =
1611 }
1612
1613 CheckQueue();
1614}
1615
1616void
1618{
1619 uint32_t activeSlot;
1620 uint64_t cfpDuration;
1621 Time endCfpTime;
1622 uint64_t symbolRate;
1623
1624 symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1625
1626 if (superframeType == INCOMING)
1627 {
1628 activeSlot = m_incomingSuperframeDuration / 16;
1629 cfpDuration = activeSlot * (15 - m_incomingFnlCapSlot);
1630 endCfpTime = Seconds((double)cfpDuration / symbolRate);
1631 if (cfpDuration > 0)
1632 {
1634 }
1635
1636 NS_LOG_DEBUG("Incoming superframe CFP duration " << cfpDuration << " symbols ("
1637 << endCfpTime.As(Time::S) << ")");
1638
1641 this,
1643 }
1644 else
1645 {
1646 activeSlot = m_superframeDuration / 16;
1647 cfpDuration = activeSlot * (15 - m_fnlCapSlot);
1648 endCfpTime = Seconds((double)cfpDuration / symbolRate);
1649
1650 if (cfpDuration > 0)
1651 {
1653 }
1654
1655 NS_LOG_DEBUG("Outgoing superframe CFP duration " << cfpDuration << " symbols ("
1656 << endCfpTime.As(Time::S) << ")");
1657
1658 m_cfpEvent = Simulator::Schedule(endCfpTime,
1660 this,
1662 }
1663 // TODO: Start transmit or receive GTS here.
1664}
1665
1666void
1668{
1669 uint64_t inactiveDuration;
1670 Time endInactiveTime;
1671 uint64_t symbolRate;
1672
1673 symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1674
1675 if (superframeType == INCOMING)
1676 {
1678 endInactiveTime = Seconds((double)inactiveDuration / symbolRate);
1679
1680 if (inactiveDuration > 0)
1681 {
1683 }
1684
1685 NS_LOG_DEBUG("Incoming superframe Inactive Portion duration "
1686 << inactiveDuration << " symbols (" << endInactiveTime.As(Time::S) << ")");
1687 m_beaconEvent = Simulator::Schedule(endInactiveTime, &LrWpanMac::AwaitBeacon, this);
1688 }
1689 else
1690 {
1691 inactiveDuration = m_beaconInterval - m_superframeDuration;
1692 endInactiveTime = Seconds((double)inactiveDuration / symbolRate);
1693
1694 if (inactiveDuration > 0)
1695 {
1697 }
1698
1699 NS_LOG_DEBUG("Outgoing superframe Inactive Portion duration "
1700 << inactiveDuration << " symbols (" << endInactiveTime.As(Time::S) << ")");
1702 }
1703}
1704
1705void
1707{
1709
1710 // TODO: If the device waits more than the expected time to receive the beacon (wait = 46
1711 // symbols for default beacon size)
1712 // it should continue with the start of the incoming CAP even if it did not receive the
1713 // beacon. At the moment, the start of the incoming CAP is only triggered if the beacon is
1714 // received. See MLME-SyncLoss for details.
1715}
1716
1717void
1719{
1720 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1721
1723 {
1724 MlmeSyncLossIndicationParams syncLossParams;
1725 // syncLossParams.m_logCh =
1726 syncLossParams.m_lossReason = MacStatus::BEACON_LOSS;
1727 syncLossParams.m_panId = m_macPanId;
1728 m_mlmeSyncLossIndicationCallback(syncLossParams);
1729
1730 m_beaconTrackingOn = false;
1731 m_numLostBeacons = 0;
1732 }
1733 else
1734 {
1736
1737 // Search for one more beacon
1738 uint64_t searchSymbols;
1739 Time searchBeaconTime;
1740 searchSymbols =
1742 searchBeaconTime = Seconds((double)searchSymbols / symbolRate);
1744 Simulator::Schedule(searchBeaconTime, &LrWpanMac::BeaconSearchTimeout, this);
1745 }
1746}
1747
1748void
1750{
1751 NS_LOG_FUNCTION(this << lqi << p);
1752 // The received beacon size in symbols
1753 // Beacon = Sync Header (SHR)[5 bytes] +
1754 // PHY header (PHR) [1 byte] +
1755 // PSDU (MAC header + beacon payload) [default 17 bytes]
1756 m_rxBeaconSymbols = m_phy->GetPhySHRDuration() + 1 * m_phy->GetPhySymbolsPerOctet() +
1757 (p->GetSize() * m_phy->GetPhySymbolsPerOctet());
1758
1759 // The start of Rx beacon time and start of the Incoming superframe Active Period
1760 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1761 m_macBeaconRxTime = Simulator::Now() - Seconds(double(m_rxBeaconSymbols) / symbolRate);
1762
1763 NS_LOG_DEBUG("Beacon Received; forwarding up (m_macBeaconRxTime: "
1764 << m_macBeaconRxTime.As(Time::S) << ")");
1765
1766 // Strip the MAC header, the trailer and the Beacon Payload
1767 LrWpanMacTrailer receivedMacTrailer;
1768 p->RemoveTrailer(receivedMacTrailer);
1769
1770 LrWpanMacHeader receivedMacHdr;
1771 p->RemoveHeader(receivedMacHdr);
1772
1773 BeaconPayloadHeader receivedMacPayload;
1774 p->RemoveHeader(receivedMacPayload);
1775
1776 // Fill the PAN descriptor
1777 PanDescriptor panDescriptor;
1778
1779 if (receivedMacHdr.GetSrcAddrMode() == SHORT_ADDR)
1780 {
1781 panDescriptor.m_coorAddrMode = SHORT_ADDR;
1782 panDescriptor.m_coorShortAddr = receivedMacHdr.GetShortSrcAddr();
1783 }
1784 else
1785 {
1786 panDescriptor.m_coorAddrMode = EXT_ADDR;
1787 panDescriptor.m_coorExtAddr = receivedMacHdr.GetExtSrcAddr();
1788 }
1789
1790 panDescriptor.m_coorPanId = receivedMacHdr.GetSrcPanId();
1791 panDescriptor.m_gtsPermit = receivedMacPayload.GetGtsFields().GetGtsPermit();
1792 panDescriptor.m_linkQuality = lqi;
1793 panDescriptor.m_logChPage = m_phy->GetCurrentPage();
1794 panDescriptor.m_logCh = m_phy->GetCurrentChannelNum();
1795 panDescriptor.m_superframeSpec = receivedMacPayload.GetSuperframeSpecField();
1796 panDescriptor.m_timeStamp = m_macBeaconRxTime;
1797
1798 // Process beacon when device belongs to a PAN (associated device)
1799 if (!m_scanEvent.IsPending() && m_macPanId == receivedMacHdr.GetDstPanId())
1800 {
1801 // We need to make sure to cancel any possible ongoing unslotted CSMA/CA
1802 // operations when receiving a beacon (e.g. Those taking place at the
1803 // beginning of an Association).
1804 m_csmaCa->Cancel();
1805
1806 SuperframeField incomingSuperframe(receivedMacPayload.GetSuperframeSpecField());
1807
1808 m_incomingBeaconOrder = incomingSuperframe.GetBeaconOrder();
1809 m_incomingSuperframeOrder = incomingSuperframe.GetFrameOrder();
1810 m_incomingFnlCapSlot = incomingSuperframe.GetFinalCapSlot();
1811
1812 if (m_incomingBeaconOrder < 15)
1813 {
1814 // Start Beacon-enabled mode
1815 m_csmaCa->SetSlottedCsmaCa();
1819 (static_cast<uint32_t>(1 << m_incomingSuperframeOrder));
1820
1821 if (incomingSuperframe.IsBattLifeExt())
1822 {
1823 m_csmaCa->SetBatteryLifeExtension(true);
1824 }
1825 else
1826 {
1827 m_csmaCa->SetBatteryLifeExtension(false);
1828 }
1829
1830 // TODO: get Incoming frame GTS Fields here
1831
1832 // Begin CAP on the current device using info from
1833 // the Incoming superframe
1834 NS_LOG_DEBUG("Incoming superframe Active Portion "
1835 << "(Beacon + CAP + CFP): " << m_incomingSuperframeDuration << " symbols");
1836
1839 }
1840 else
1841 {
1842 // Start non-beacon enabled mode
1843 m_csmaCa->SetUnSlottedCsmaCa();
1844 }
1845
1847 }
1848 else if (!m_scanEvent.IsPending() && m_macPanId == 0xFFFF)
1849 {
1850 NS_LOG_DEBUG(this << " Device not associated, cannot process beacon");
1851 }
1852
1853 if (m_macAutoRequest)
1854 {
1855 if (p->GetSize() > 0)
1856 {
1858 {
1859 // The beacon contains payload, send the beacon notification.
1861 beaconParams.m_bsn = receivedMacHdr.GetSeqNum();
1862 beaconParams.m_panDescriptor = panDescriptor;
1863 beaconParams.m_sduLength = p->GetSize();
1864 beaconParams.m_sdu = p;
1866 }
1867 }
1868
1869 if (m_scanEvent.IsPending())
1870 {
1871 // Channel scanning is taking place, save only unique PAN descriptors
1872 bool descriptorExists = false;
1873
1874 for (const auto& descriptor : m_panDescriptorList)
1875 {
1876 if (descriptor.m_coorAddrMode == SHORT_ADDR)
1877 {
1878 // Found a coordinator in PAN descriptor list with the same
1879 // registered short address
1880 descriptorExists =
1881 (descriptor.m_coorShortAddr == panDescriptor.m_coorShortAddr &&
1882 descriptor.m_coorPanId == panDescriptor.m_coorPanId);
1883 }
1884 else
1885 {
1886 // Found a coordinator in PAN descriptor list with the same
1887 // registered extended address
1888 descriptorExists = (descriptor.m_coorExtAddr == panDescriptor.m_coorExtAddr &&
1889 descriptor.m_coorPanId == panDescriptor.m_coorPanId);
1890 }
1891
1892 if (descriptorExists)
1893 {
1894 break;
1895 }
1896 }
1897
1898 if (!descriptorExists)
1899 {
1900 m_panDescriptorList.emplace_back(panDescriptor);
1901 }
1902 return;
1903 }
1904 else if (m_trackingEvent.IsPending())
1905 {
1906 // check if MLME-SYNC.request was previously issued and running
1907 // Sync. is necessary to handle pending messages (indirect
1908 // transmissions)
1910 m_numLostBeacons = 0;
1911
1913 {
1914 // if tracking option is on keep tracking the next beacon
1915 uint64_t searchSymbols;
1916 Time searchBeaconTime;
1917
1918 searchSymbols = (static_cast<uint64_t>(1 << m_incomingBeaconOrder)) +
1920 searchBeaconTime = Seconds(static_cast<double>(searchSymbols / symbolRate));
1922 Simulator::Schedule(searchBeaconTime, &LrWpanMac::BeaconSearchTimeout, this);
1923 }
1924
1925 PendingAddrFields pndAddrFields;
1926 pndAddrFields = receivedMacPayload.GetPndAddrFields();
1927
1928 // TODO: Ignore pending data, and do not send data command request if
1929 // the address is in the GTS list.
1930 // If the address is not in the GTS list, then check if the
1931 // address is in the short address pending list or in the extended
1932 // address pending list and send a data command request.
1933 }
1934 }
1935 else
1936 {
1937 // m_macAutoRequest is FALSE
1938 // Data command request are not send, only the beacon notification.
1939 // see IEEE 802.15.4-2011 Section 6.2.4.1
1941 {
1943 beaconParams.m_bsn = receivedMacHdr.GetSeqNum();
1944 beaconParams.m_panDescriptor = panDescriptor;
1945 beaconParams.m_sduLength = p->GetSize();
1946 beaconParams.m_sdu = p;
1948 }
1949 }
1950}
1951
1952void
1954{
1955 NS_LOG_FUNCTION(this);
1956 // Pull a packet from the queue and start sending if we are not already sending.
1957 if (m_macState == MAC_IDLE && !m_txQueue.empty() && !m_setMacState.IsPending())
1958 {
1959 if (m_csmaCa->IsUnSlottedCsmaCa() || (m_outSuperframeStatus == CAP && m_coor) ||
1961 {
1962 // check MAC is not in a IFS
1963 if (!m_ifsEvent.IsPending())
1964 {
1965 Ptr<TxQueueElement> txQElement = m_txQueue.front();
1966 m_txPkt = txQElement->txQPkt;
1967
1970 }
1971 }
1972 }
1973}
1974
1975uint16_t
1977{
1978 SuperframeField sfrmSpec;
1979
1982 sfrmSpec.SetFinalCapSlot(m_fnlCapSlot);
1983
1984 if (m_csmaCa->GetBatteryLifeExtension())
1985 {
1986 sfrmSpec.SetBattLifeExt(true);
1987 }
1988
1989 if (m_panCoor)
1990 {
1991 sfrmSpec.SetPanCoor(true);
1992 }
1993
1994 // used to associate devices via Beacons
1996 {
1997 sfrmSpec.SetAssocPermit(true);
1998 }
1999
2000 return sfrmSpec.GetSuperframe();
2001}
2002
2005{
2006 GtsFields gtsFields;
2007
2008 // TODO: Logic to populate the GTS Fields from local information here
2009
2010 return gtsFields;
2011}
2012
2015{
2016 PendingAddrFields pndAddrFields;
2017
2018 // TODO: Logic to populate the Pending Address Fields from local information here
2019 return pndAddrFields;
2020}
2021
2022void
2024{
2025 m_csmaCa = csmaCa;
2026}
2027
2028void
2030{
2031 m_phy = phy;
2032}
2033
2036{
2037 return m_phy;
2038}
2039
2040void
2042{
2044 NS_LOG_FUNCTION(this << psduLength << p << (uint16_t)lqi);
2045
2046 bool acceptFrame;
2047
2048 // from sec 7.5.6.2 Reception and rejection, Std802.15.4-2006
2049 // level 1 filtering, test FCS field and reject if frame fails
2050 // level 2 filtering if promiscuous mode pass frame to higher layer otherwise perform level 3
2051 // filtering level 3 filtering accept frame if Frame type and version is not reserved, and if
2052 // there is a dstPanId then dstPanId=m_macPanId or broadcastPanId, and if there is a
2053 // shortDstAddr then shortDstAddr =shortMacAddr or broadcastAddr, and if beacon frame then
2054 // srcPanId = m_macPanId if only srcAddr field in Data or Command frame,accept frame if
2055 // srcPanId=m_macPanId
2056
2057 Ptr<Packet> originalPkt = p->Copy(); // because we will strip headers
2058 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
2059 m_promiscSnifferTrace(originalPkt);
2060
2061 m_macPromiscRxTrace(originalPkt);
2062 // XXX no rejection tracing (to macRxDropTrace) being performed below
2063
2064 LrWpanMacTrailer receivedMacTrailer;
2065 p->RemoveTrailer(receivedMacTrailer);
2067 {
2068 receivedMacTrailer.EnableFcs(true);
2069 }
2070
2071 // level 1 filtering
2072 if (!receivedMacTrailer.CheckFcs(p))
2073 {
2074 m_macRxDropTrace(originalPkt);
2075 }
2076 else
2077 {
2078 LrWpanMacHeader receivedMacHdr;
2079 p->RemoveHeader(receivedMacHdr);
2080
2082 params.m_dsn = receivedMacHdr.GetSeqNum();
2083 params.m_mpduLinkQuality = lqi;
2084 params.m_srcPanId = receivedMacHdr.GetSrcPanId();
2085 params.m_srcAddrMode = receivedMacHdr.GetSrcAddrMode();
2086 switch (params.m_srcAddrMode)
2087 {
2088 case SHORT_ADDR:
2089 params.m_srcAddr = receivedMacHdr.GetShortSrcAddr();
2090 break;
2091 case EXT_ADDR:
2092 params.m_srcExtAddr = receivedMacHdr.GetExtSrcAddr();
2093 break;
2094 default:
2095 break;
2096 }
2097 params.m_dstPanId = receivedMacHdr.GetDstPanId();
2098 params.m_dstAddrMode = receivedMacHdr.GetDstAddrMode();
2099 switch (params.m_dstAddrMode)
2100 {
2101 case SHORT_ADDR:
2102 params.m_dstAddr = receivedMacHdr.GetShortDstAddr();
2103 break;
2104 case EXT_ADDR:
2105 params.m_dstExtAddr = receivedMacHdr.GetExtDstAddr();
2106 break;
2107 default:
2108 break;
2109 }
2110
2112 {
2113 // level 2 filtering
2114 if (receivedMacHdr.GetSrcAddrMode() == SHORT_ADDR &&
2115 receivedMacHdr.GetDstAddrMode() == SHORT_ADDR)
2116 {
2117 NS_LOG_DEBUG("Packet from [" << params.m_srcAddr << "] to [" << params.m_dstAddr
2118 << "]");
2119 }
2120 else if (receivedMacHdr.GetSrcAddrMode() == EXT_ADDR &&
2121 receivedMacHdr.GetDstAddrMode() == EXT_ADDR)
2122 {
2123 NS_LOG_DEBUG("Packet from [" << params.m_srcExtAddr << "] to ["
2124 << params.m_dstExtAddr << "]");
2125 }
2126 else if (receivedMacHdr.GetSrcAddrMode() == SHORT_ADDR &&
2127 receivedMacHdr.GetDstAddrMode() == EXT_ADDR)
2128 {
2129 NS_LOG_DEBUG("Packet from [" << params.m_srcAddr << "] to [" << params.m_dstExtAddr
2130 << "]");
2131 }
2132 else if (receivedMacHdr.GetSrcAddrMode() == EXT_ADDR &&
2133 receivedMacHdr.GetDstAddrMode() == SHORT_ADDR)
2134 {
2135 NS_LOG_DEBUG("Packet from [" << params.m_srcExtAddr << "] to [" << params.m_dstAddr
2136 << "]");
2137 }
2138
2139 // TODO: Fix here, this should trigger different Indication Callbacks
2140 // depending the type of frame received (data,command, beacon)
2142 {
2143 NS_LOG_DEBUG("promiscuous mode, forwarding up");
2145 }
2146 else
2147 {
2148 NS_LOG_ERROR(this << " Data Indication Callback not initialized");
2149 }
2150 }
2151 else
2152 {
2153 // level 3 frame filtering
2154 acceptFrame = (receivedMacHdr.GetType() != LrWpanMacHeader::LRWPAN_MAC_RESERVED);
2155
2156 if (acceptFrame)
2157 {
2158 acceptFrame = (receivedMacHdr.GetFrameVer() <= 1);
2159 }
2160
2161 if (acceptFrame && (receivedMacHdr.GetDstAddrMode() > 1))
2162 {
2163 // Accept frame if one of the following is true:
2164
2165 // 1) Have the same macPanId
2166 // 2) Is Message to all PANs
2167 // 3) Is a beacon or command frame and the macPanId is not present (bootstrap)
2168 acceptFrame = ((receivedMacHdr.GetDstPanId() == m_macPanId ||
2169 receivedMacHdr.GetDstPanId() == 0xffff) ||
2170 (m_macPanId == 0xffff && receivedMacHdr.IsBeacon())) ||
2171 (m_macPanId == 0xffff && receivedMacHdr.IsCommand());
2172 }
2173
2174 if (acceptFrame && (receivedMacHdr.GetDstAddrMode() == SHORT_ADDR))
2175 {
2176 if (receivedMacHdr.GetShortDstAddr() == m_shortAddress)
2177 {
2178 // unicast, for me
2179 acceptFrame = true;
2180 }
2181 else if (receivedMacHdr.GetShortDstAddr().IsBroadcast() ||
2182 receivedMacHdr.GetShortDstAddr().IsMulticast())
2183 {
2184 // Broadcast or multicast.
2185 // Discard broadcast/multicast with the ACK bit set.
2186 acceptFrame = !receivedMacHdr.IsAckReq();
2187 }
2188 else
2189 {
2190 acceptFrame = false;
2191 }
2192 }
2193
2194 if (acceptFrame && (receivedMacHdr.GetDstAddrMode() == EXT_ADDR))
2195 {
2196 acceptFrame = (receivedMacHdr.GetExtDstAddr() == m_macExtendedAddress);
2197 }
2198
2199 if (acceptFrame && m_scanEvent.IsPending())
2200 {
2201 if (!receivedMacHdr.IsBeacon())
2202 {
2203 acceptFrame = false;
2204 }
2205 }
2206 else if (acceptFrame && m_scanOrphanEvent.IsPending())
2207 {
2208 if (!receivedMacHdr.IsCommand())
2209 {
2210 acceptFrame = false;
2211 }
2212 }
2213 else if (m_scanEnergyEvent.IsPending())
2214 {
2215 // Reject any frames if energy scan is running
2216 acceptFrame = false;
2217 }
2218
2219 // Check device is panCoor with association permit when receiving Association Request
2220 // Commands.
2221 // TODO:: Simple coordinators should also be able to receive it (currently only Pan
2222 // Coordinators are checked)
2223 if (acceptFrame && (receivedMacHdr.IsCommand() && receivedMacHdr.IsAckReq()))
2224 {
2225 CommandPayloadHeader receivedMacPayload;
2226 p->PeekHeader(receivedMacPayload);
2227
2228 if (receivedMacPayload.GetCommandFrameType() ==
2231 {
2232 acceptFrame = false;
2233 }
2234
2235 // Although ACKs do not use CSMA to to be transmitted, we need to make sure
2236 // that the transmitted ACK will not collide with the transmission of a beacon
2237 // when beacon-enabled mode is running in the coordinator.
2238 if (acceptFrame && (m_csmaCa->IsSlottedCsmaCa() && m_capEvent.IsPending()))
2239 {
2240 Time timeLeftInCap = Simulator::GetDelayLeft(m_capEvent);
2241 uint64_t ackSymbols = lrwpan::aTurnaroundTime + m_phy->GetPhySHRDuration() +
2242 ceil(6 * m_phy->GetPhySymbolsPerOctet());
2243 Time ackTime = Seconds((double)ackSymbols / symbolRate);
2244
2245 if (ackTime >= timeLeftInCap)
2246 {
2247 NS_LOG_DEBUG("Command frame received but not enough time to transmit ACK "
2248 "before the end of CAP ");
2249 acceptFrame = false;
2250 }
2251 }
2252 }
2253
2254 if (acceptFrame)
2255 {
2256 m_macRxTrace(originalPkt);
2257 // \todo: What should we do if we receive a frame while waiting for an ACK?
2258 // Especially if this frame has the ACK request bit set, should we reply with
2259 // an ACK, possibly missing the pending ACK?
2260
2261 // If the received frame is a frame with the ACK request bit set, we immediately
2262 // send back an ACK. If we are currently waiting for a pending ACK, we assume the
2263 // ACK was lost and trigger a retransmission after sending the ACK.
2264 if ((receivedMacHdr.IsData() || receivedMacHdr.IsCommand()) &&
2265 receivedMacHdr.IsAckReq() &&
2266 !(receivedMacHdr.GetDstAddrMode() == SHORT_ADDR &&
2267 (receivedMacHdr.GetShortDstAddr().IsBroadcast() ||
2268 receivedMacHdr.GetShortDstAddr().IsMulticast())))
2269 {
2270 // If this is a data or mac command frame, which is not a broadcast or
2271 // multicast, with ack req set, generate and send an ack frame. If there is a
2272 // CSMA medium access in progress we cancel the medium access for sending the
2273 // ACK frame. A new transmission attempt will be started after the ACK was send.
2275 {
2278 }
2279 else if (m_macState == MAC_CSMA)
2280 {
2281 // \todo: If we receive a packet while doing CSMA/CA, should we drop the
2282 // packet because of channel busy,
2283 // or should we restart CSMA/CA for the packet after sending the ACK?
2284 // Currently we simply restart CSMA/CA after sending the ACK.
2285 NS_LOG_DEBUG("Received a packet with ACK required while in CSMA. Cancel "
2286 "current CSMA-CA");
2287 m_csmaCa->Cancel();
2288 }
2289 // Cancel any pending MAC state change, ACKs have higher priority.
2292
2293 // save received packet and LQI to process the appropriate indication/response
2294 // after sending ACK (PD-DATA.confirm)
2295 m_rxPkt = originalPkt->Copy();
2296 m_lastRxFrameLqi = lqi;
2297
2298 // LOG Commands with ACK required.
2299 CommandPayloadHeader receivedMacPayload;
2300 p->PeekHeader(receivedMacPayload);
2301 switch (receivedMacPayload.GetCommandFrameType())
2302 {
2304 NS_LOG_DEBUG("Data Request Command Received; processing ACK");
2305 break;
2307 NS_LOG_DEBUG("Association Request Command Received; processing ACK");
2308 break;
2310 m_assocResCmdWaitTimeout.Cancel(); // cancel event to a lost assoc resp cmd.
2311 NS_LOG_DEBUG("Association Response Command Received; processing ACK");
2312 break;
2313 default:
2314 break;
2315 }
2316
2318 this,
2319 receivedMacHdr.GetSeqNum());
2320 }
2321
2322 if (receivedMacHdr.GetSrcAddrMode() == SHORT_ADDR &&
2323 receivedMacHdr.GetDstAddrMode() == SHORT_ADDR)
2324 {
2325 NS_LOG_DEBUG("Packet from [" << params.m_srcAddr << "] to [" << params.m_dstAddr
2326 << "]");
2327 }
2328 else if (receivedMacHdr.GetSrcAddrMode() == EXT_ADDR &&
2329 receivedMacHdr.GetDstAddrMode() == EXT_ADDR)
2330 {
2331 NS_LOG_DEBUG("Packet from [" << params.m_srcExtAddr << "] to ["
2332 << params.m_dstExtAddr << "]");
2333 }
2334 else if (receivedMacHdr.GetSrcAddrMode() == SHORT_ADDR &&
2335 receivedMacHdr.GetDstAddrMode() == EXT_ADDR)
2336 {
2337 NS_LOG_DEBUG("Packet from [" << params.m_srcAddr << "] to ["
2338 << params.m_dstExtAddr << "]");
2339 }
2340 else if (receivedMacHdr.GetSrcAddrMode() == EXT_ADDR &&
2341 receivedMacHdr.GetDstAddrMode() == SHORT_ADDR)
2342 {
2343 NS_LOG_DEBUG("Packet from [" << params.m_srcExtAddr << "] to ["
2344 << params.m_dstAddr << "]");
2345 }
2346
2347 if (receivedMacHdr.IsBeacon())
2348 {
2349 ReceiveBeacon(lqi, originalPkt);
2350 }
2351 else if (receivedMacHdr.IsCommand())
2352 {
2353 // Handle the reception of frame commands that do not require ACK
2354 // (i.e. Beacon Request, Orphan notification, Coordinator Realigment)
2355 CommandPayloadHeader receivedMacPayload;
2356 p->PeekHeader(receivedMacPayload);
2357
2358 switch (receivedMacPayload.GetCommandFrameType())
2359 {
2361 if (m_csmaCa->IsUnSlottedCsmaCa() && m_coor)
2362 {
2363 // Jitter = Between 0 and 2 aUnitBackoffPeriods
2364 // (0, 320us or 640us in 2.4Ghz O-QPSK)
2365 // While this jitter is not described by the standard,
2366 // it reduces the probability of collisions in beacons
2367 // transmitted as a result of a beacon request
2368 Time jitter =
2369 Seconds(static_cast<double>(m_uniformVar->GetInteger(0, 3) *
2371 symbolRate);
2372
2374 }
2375 else
2376 {
2377 m_macRxDropTrace(originalPkt);
2378 }
2379 break;
2382 {
2383 if (m_coor)
2384 {
2385 MlmeOrphanIndicationParams orphanParams;
2386 orphanParams.m_orphanAddr = receivedMacHdr.GetExtSrcAddr();
2387 m_mlmeOrphanIndicationCallback(orphanParams);
2388 }
2389 }
2390 break;
2393 {
2394 // Coordinator located, no need to keep scanning other channels
2396
2397 m_macPanIdScan = 0;
2400
2401 // Update the device information with the received information
2402 // from the Coordinator Realigment command.
2403 m_macPanId = receivedMacPayload.GetPanId();
2404 m_shortAddress = receivedMacPayload.GetShortAddr();
2405 m_macCoordExtendedAddress = receivedMacHdr.GetExtSrcAddr();
2406 m_macCoordShortAddress = receivedMacPayload.GetCoordShortAddr();
2407
2409 {
2410 MlmeScanConfirmParams confirmParams;
2411 confirmParams.m_scanType = m_scanParams.m_scanType;
2412 confirmParams.m_chPage = m_scanParams.m_chPage;
2413 confirmParams.m_status = MacStatus::SUCCESS;
2414 m_mlmeScanConfirmCallback(confirmParams);
2415 }
2416 m_scanParams = {};
2417 }
2418 // TODO: handle Coordinator realignment when not
2419 // used during an orphan scan.
2420 break;
2421 default:
2422 m_macRxDropTrace(originalPkt);
2423 break;
2424 }
2425 }
2426 else if (receivedMacHdr.IsData() && !m_mcpsDataIndicationCallback.IsNull())
2427 {
2428 // If it is a data frame, push it up the stack.
2429 NS_LOG_DEBUG("Data Packet is for me; forwarding up");
2431 }
2432 else if (receivedMacHdr.IsAcknowledgment() && m_txPkt &&
2434 {
2435 LrWpanMacHeader peekedMacHdr;
2436 m_txPkt->PeekHeader(peekedMacHdr);
2437 // If it is an ACK with the expected sequence number, finish the transmission
2438 if (receivedMacHdr.GetSeqNum() == peekedMacHdr.GetSeqNum())
2439 {
2442
2443 // TODO: check if the IFS is the correct size after ACK.
2444 Time ifsWaitTime = Seconds((double)GetIfsSize() / symbolRate);
2445
2446 // We received an ACK to a command
2447 if (peekedMacHdr.IsCommand())
2448 {
2449 // check the original sent command frame which belongs to this received
2450 // ACK
2451 Ptr<Packet> pkt = m_txPkt->Copy();
2452 LrWpanMacHeader macHdr;
2453 CommandPayloadHeader cmdPayload;
2454 pkt->RemoveHeader(macHdr);
2455 pkt->RemoveHeader(cmdPayload);
2456
2457 switch (cmdPayload.GetCommandFrameType())
2458 {
2460 double symbolRate = m_phy->GetDataOrSymbolRate(false);
2461 Time waitTime = Seconds(static_cast<double>(m_macResponseWaitTime) /
2462 symbolRate);
2463 if (!m_beaconTrackingOn)
2464 {
2466 Simulator::Schedule(waitTime,
2468 this);
2469 }
2470 else
2471 {
2472 // TODO: The data must be extracted by the coordinator within
2473 // macResponseWaitTime on timeout, MLME-ASSOCIATE.confirm is set
2474 // with status NO_DATA, and this should trigger the cancellation
2475 // of the beacon tracking (MLME-SYNC.request trackBeacon
2476 // =FALSE)
2477 }
2478 break;
2479 }
2480
2482 // MLME-comm-status.Indication generated as a result of an
2483 // association response command, therefore src and dst address use
2484 // extended mode (see 5.3.2.1)
2486 {
2487 MlmeCommStatusIndicationParams commStatusParams;
2488 commStatusParams.m_panId = m_macPanId;
2489 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2490 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
2491 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2492 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
2493 commStatusParams.m_status = MacStatus::SUCCESS;
2494 m_mlmeCommStatusIndicationCallback(commStatusParams);
2495 }
2496 // Remove element from Pending Transaction List
2498 break;
2499 }
2500
2502 // Schedule an event in case the Association Response Command never
2503 // reached this device during an association process.
2504 double symbolRate = m_phy->GetDataOrSymbolRate(false);
2505 Time waitTime = Seconds(
2506 static_cast<double>(m_assocRespCmdWaitTime) / symbolRate);
2508 Simulator::Schedule(waitTime,
2510 this);
2511
2513 {
2514 MlmePollConfirmParams pollConfirmParams;
2515 pollConfirmParams.m_status = MacStatus::SUCCESS;
2516 m_mlmePollConfirmCallback(pollConfirmParams);
2517 }
2518 break;
2519 }
2520
2522 // ACK of coordinator realigment commands is not specified in the
2523 // standard, in here, we assume they are required as in other
2524 // commands.
2526 {
2527 MlmeCommStatusIndicationParams commStatusParams;
2528 commStatusParams.m_panId = m_macPanId;
2529 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2530 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
2531 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2532 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
2533 commStatusParams.m_status = MacStatus::SUCCESS;
2534 m_mlmeCommStatusIndicationCallback(commStatusParams);
2535 }
2536 }
2537
2538 default: {
2539 // TODO: add response to other request commands (e.g. Orphan)
2540 break;
2541 }
2542 }
2543 }
2544 else
2545 {
2547 {
2548 Ptr<TxQueueElement> txQElement = m_txQueue.front();
2549 McpsDataConfirmParams confirmParams;
2550 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
2551 confirmParams.m_status = MacStatus::SUCCESS;
2552 m_mcpsDataConfirmCallback(confirmParams);
2553 }
2554 }
2555
2556 // Ack was successfully received, wait for the Interframe Space (IFS) and
2557 // then proceed
2562 m_ifsEvent = Simulator::Schedule(ifsWaitTime,
2564 this,
2565 ifsWaitTime);
2566 }
2567 else
2568 {
2569 // If it is an ACK with an unexpected sequence number, mark the current
2570 // transmission as failed and start a retransmit. (cf 7.5.6.4.3)
2572 if (!PrepareRetransmission())
2573 {
2576 this,
2577 MAC_IDLE);
2578 }
2579 else
2580 {
2583 this,
2584 MAC_CSMA);
2585 }
2586 }
2587 }
2588 }
2589 else
2590 {
2591 m_macRxDropTrace(originalPkt);
2592 }
2593 }
2594 }
2595}
2596
2597void
2599{
2600 NS_LOG_FUNCTION(this << static_cast<uint32_t>(seqno));
2601
2603
2604 // Generate a corresponding ACK Frame.
2606 LrWpanMacTrailer macTrailer;
2607 Ptr<Packet> ackPacket = Create<Packet>(0);
2608 ackPacket->AddHeader(macHdr);
2609 // Calculate FCS if the global attribute ChecksumEnabled is set.
2611 {
2612 macTrailer.EnableFcs(true);
2613 macTrailer.SetFcs(ackPacket);
2614 }
2615 ackPacket->AddTrailer(macTrailer);
2616
2617 // Enqueue the ACK packet for further processing
2618 // when the transmitter is activated.
2619 m_txPkt = ackPacket;
2620
2621 // Switch transceiver to TX mode. Proceed sending the Ack on confirm.
2623 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TX_ON);
2624}
2625
2626void
2628{
2629 if (m_txQueue.size() < m_maxTxQueueSize)
2630 {
2631 m_txQueue.emplace_back(txQElement);
2632 m_macTxEnqueueTrace(txQElement->txQPkt);
2633 }
2634 else
2635 {
2637 {
2638 McpsDataConfirmParams confirmParams;
2639 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
2641 m_mcpsDataConfirmCallback(confirmParams);
2642 }
2643 NS_LOG_DEBUG("TX Queue with size " << m_txQueue.size() << " is full, dropping packet");
2644 m_macTxDropTrace(txQElement->txQPkt);
2645 }
2646}
2647
2648void
2650{
2651 Ptr<TxQueueElement> txQElement = m_txQueue.front();
2652 Ptr<const Packet> p = txQElement->txQPkt;
2653 m_numCsmacaRetry += m_csmaCa->GetNB() + 1;
2654
2655 Ptr<Packet> pkt = p->Copy();
2656 LrWpanMacHeader hdr;
2657 pkt->RemoveHeader(hdr);
2658 if (!hdr.GetShortDstAddr().IsBroadcast() && !hdr.GetShortDstAddr().IsMulticast())
2659 {
2661 }
2662
2663 txQElement->txQPkt = nullptr;
2664 txQElement = nullptr;
2665 m_txQueue.pop_front();
2666 m_txPkt = nullptr;
2667 m_retransmission = 0;
2668 m_numCsmacaRetry = 0;
2670}
2671
2672void
2674{
2675 NS_LOG_FUNCTION(this);
2676
2677 // TODO: If we are a PAN coordinator and this was an indirect transmission,
2678 // we will not initiate a retransmission. Instead we wait for the data
2679 // being extracted after a new data request command.
2680 if (!PrepareRetransmission())
2681 {
2683 }
2684 else
2685 {
2687 }
2688}
2689
2690void
2692{
2693 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false);
2694 Time lifsTime = Seconds((double)m_macLIFSPeriod / symbolRate);
2695 Time sifsTime = Seconds((double)m_macSIFSPeriod / symbolRate);
2696
2697 if (ifsTime == lifsTime)
2698 {
2699 NS_LOG_DEBUG("LIFS of " << m_macLIFSPeriod << " symbols (" << ifsTime.As(Time::S)
2700 << ") completed ");
2701 }
2702 else if (ifsTime == sifsTime)
2703 {
2704 NS_LOG_DEBUG("SIFS of " << m_macSIFSPeriod << " symbols (" << ifsTime.As(Time::S)
2705 << ") completed ");
2706 }
2707 else
2708 {
2709 NS_LOG_DEBUG("Unknown IFS size (" << ifsTime.As(Time::S) << ") completed ");
2710 }
2711
2712 m_macIfsEndTrace(ifsTime);
2713 CheckQueue();
2714}
2715
2716bool
2718{
2719 NS_LOG_FUNCTION(this);
2720
2721 // Max retransmissions reached without receiving ACK,
2722 // send the proper indication/confirmation
2723 // according to the frame type and call drop trace.
2725 {
2726 LrWpanMacHeader peekedMacHdr;
2727 m_txPkt->PeekHeader(peekedMacHdr);
2728
2729 if (peekedMacHdr.IsCommand())
2730 {
2732
2733 Ptr<Packet> pkt = m_txPkt->Copy();
2734 LrWpanMacHeader macHdr;
2735 CommandPayloadHeader cmdPayload;
2736 pkt->RemoveHeader(macHdr);
2737 pkt->RemoveHeader(cmdPayload);
2738
2739 switch (cmdPayload.GetCommandFrameType())
2740 {
2742 m_macPanId = 0xffff;
2744 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
2747 m_csmaCa->SetUnSlottedCsmaCa();
2750
2752 {
2753 MlmeAssociateConfirmParams confirmParams;
2754 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
2755 confirmParams.m_status = MacStatus::NO_ACK;
2756 m_mlmeAssociateConfirmCallback(confirmParams);
2757 }
2758 break;
2759 }
2761 // IEEE 802.15.4-2006 (Section 7.1.3.3.3 and 7.1.8.2.3)
2763 {
2764 MlmeCommStatusIndicationParams commStatusParams;
2765 commStatusParams.m_panId = m_macPanId;
2766 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2767 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
2768 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2769 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
2770 commStatusParams.m_status = MacStatus::NO_ACK;
2771 m_mlmeCommStatusIndicationCallback(commStatusParams);
2772 }
2774 break;
2775 }
2777 // IEEE 802.15.4-2006 (Section 7.1.16.1.3)
2778 m_macPanId = 0xffff;
2780 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
2783 m_csmaCa->SetUnSlottedCsmaCa();
2786
2788 {
2789 MlmePollConfirmParams pollConfirmParams;
2790 pollConfirmParams.m_status = MacStatus::NO_ACK;
2791 m_mlmePollConfirmCallback(pollConfirmParams);
2792 }
2793 break;
2794 }
2795 default: {
2796 // TODO: Specify other indications according to other commands
2797 break;
2798 }
2799 }
2800 }
2801 else
2802 {
2803 // Maximum number of retransmissions has been reached.
2804 // remove the copy of the DATA packet that was just sent
2805 Ptr<TxQueueElement> txQElement = m_txQueue.front();
2806 m_macTxDropTrace(txQElement->txQPkt);
2808 {
2809 McpsDataConfirmParams confirmParams;
2810 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
2811 confirmParams.m_status = MacStatus::NO_ACK;
2812 m_mcpsDataConfirmCallback(confirmParams);
2813 }
2814 }
2815
2817 return false;
2818 }
2819 else
2820 {
2822 m_numCsmacaRetry += m_csmaCa->GetNB() + 1;
2823 // Start next CCA process for this packet.
2824 return true;
2825 }
2826}
2827
2828void
2830{
2832 LrWpanMacHeader peekedMacHdr;
2833 p->PeekHeader(peekedMacHdr);
2834
2835 PurgeInd();
2836
2837 NS_ASSERT(peekedMacHdr.GetDstAddrMode() == SHORT_ADDR ||
2838 peekedMacHdr.GetDstAddrMode() == EXT_ADDR);
2839
2840 if (peekedMacHdr.GetDstAddrMode() == SHORT_ADDR)
2841 {
2842 indTxQElement->dstShortAddress = peekedMacHdr.GetShortDstAddr();
2843 }
2844 else
2845 {
2846 indTxQElement->dstExtAddress = peekedMacHdr.GetExtDstAddr();
2847 }
2848
2849 indTxQElement->seqNum = peekedMacHdr.GetSeqNum();
2850
2851 // See IEEE 802.15.4-2006, Table 86
2852 uint32_t unit = 0; // The persistence time in symbols
2853 if (m_macBeaconOrder == 15)
2854 {
2855 // Non-beacon enabled mode
2857 }
2858 else
2859 {
2860 // Beacon-enabled mode
2861 unit = ((static_cast<uint32_t>(1) << m_macBeaconOrder) * lrwpan::aBaseSuperframeDuration) *
2863 }
2864
2865 if (m_indTxQueue.size() < m_maxIndTxQueueSize)
2866 {
2867 double symbolRate = m_phy->GetDataOrSymbolRate(false);
2868 Time expireTime = Seconds(unit / symbolRate);
2869 expireTime += Simulator::Now();
2870 indTxQElement->expireTime = expireTime;
2871 indTxQElement->txQPkt = p;
2872 m_indTxQueue.emplace_back(indTxQElement);
2874 }
2875 else
2876 {
2878 {
2879 LrWpanMacHeader peekedMacHdr;
2880 indTxQElement->txQPkt->PeekHeader(peekedMacHdr);
2881 MlmeCommStatusIndicationParams commStatusParams;
2882 commStatusParams.m_panId = m_macPanId;
2883 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2884 commStatusParams.m_srcExtAddr = peekedMacHdr.GetExtSrcAddr();
2885 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2886 commStatusParams.m_dstExtAddr = peekedMacHdr.GetExtDstAddr();
2887 commStatusParams.m_status = MacStatus::TRANSACTION_OVERFLOW;
2888 m_mlmeCommStatusIndicationCallback(commStatusParams);
2889 }
2891 }
2892}
2893
2894bool
2896{
2897 PurgeInd();
2898
2899 for (auto iter = m_indTxQueue.begin(); iter != m_indTxQueue.end(); iter++)
2900 {
2901 if ((*iter)->dstExtAddress == dst)
2902 {
2903 *entry = **iter;
2904 m_macIndTxDequeueTrace((*iter)->txQPkt->Copy());
2905 m_indTxQueue.erase(iter);
2906 return true;
2907 }
2908 }
2909 return false;
2910}
2911
2912void
2914{
2915 for (uint32_t i = 0; i < m_indTxQueue.size();)
2916 {
2917 if (Simulator::Now() > m_indTxQueue[i]->expireTime)
2918 {
2919 // Transaction expired, remove and send proper confirmation/indication to a higher layer
2920 LrWpanMacHeader peekedMacHdr;
2921 m_indTxQueue[i]->txQPkt->PeekHeader(peekedMacHdr);
2922
2923 if (peekedMacHdr.IsCommand())
2924 {
2925 // IEEE 802.15.4-2006 (Section 7.1.3.3.3)
2927 {
2928 MlmeCommStatusIndicationParams commStatusParams;
2929 commStatusParams.m_panId = m_macPanId;
2930 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2931 commStatusParams.m_srcExtAddr = peekedMacHdr.GetExtSrcAddr();
2932 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2933 commStatusParams.m_dstExtAddr = peekedMacHdr.GetExtDstAddr();
2934 commStatusParams.m_status = MacStatus::TRANSACTION_EXPIRED;
2935 m_mlmeCommStatusIndicationCallback(commStatusParams);
2936 }
2937 }
2938 else if (peekedMacHdr.IsData())
2939 {
2940 // IEEE 802.15.4-2006 (Section 7.1.1.1.3)
2942 {
2943 McpsDataConfirmParams confParams;
2945 m_mcpsDataConfirmCallback(confParams);
2946 }
2947 }
2948 m_macIndTxDropTrace(m_indTxQueue[i]->txQPkt->Copy());
2949 m_indTxQueue.erase(m_indTxQueue.begin() + i);
2950 }
2951 else
2952 {
2953 i++;
2954 }
2955 }
2956}
2957
2958void
2959LrWpanMac::PrintPendingTxQueue(std::ostream& os) const
2960{
2961 LrWpanMacHeader peekedMacHdr;
2962
2963 os << "Pending Transaction List [" << GetShortAddress() << " | " << GetExtendedAddress()
2964 << "] | CurrentTime: " << Simulator::Now().As(Time::S) << "\n"
2965 << " Destination |"
2966 << " Sequence Number |"
2967 << " Frame type |"
2968 << " Expire time\n";
2969
2970 for (auto transaction : m_indTxQueue)
2971 {
2972 transaction->txQPkt->PeekHeader(peekedMacHdr);
2973 os << transaction->dstExtAddress << " "
2974 << static_cast<uint32_t>(transaction->seqNum) << " ";
2975
2976 if (peekedMacHdr.IsCommand())
2977 {
2978 os << " Command Frame ";
2979 }
2980 else if (peekedMacHdr.IsData())
2981 {
2982 os << " Data Frame ";
2983 }
2984 else
2985 {
2986 os << " Unknown Frame ";
2987 }
2988
2989 os << transaction->expireTime.As(Time::S) << "\n";
2990 }
2991}
2992
2993void
2994LrWpanMac::PrintTxQueue(std::ostream& os) const
2995{
2996 LrWpanMacHeader peekedMacHdr;
2997
2998 os << "\nTx Queue [" << GetShortAddress() << " | " << GetExtendedAddress()
2999 << "] | CurrentTime: " << Simulator::Now().As(Time::S) << "\n"
3000 << " Destination |"
3001 << " Sequence Number |"
3002 << " Dst PAN id |"
3003 << " Frame type |\n";
3004
3005 for (auto transaction : m_txQueue)
3006 {
3007 transaction->txQPkt->PeekHeader(peekedMacHdr);
3008
3009 os << "[" << peekedMacHdr.GetShortDstAddr() << "]"
3010 << ", [" << peekedMacHdr.GetExtDstAddr() << "] "
3011 << static_cast<uint32_t>(peekedMacHdr.GetSeqNum()) << " "
3012 << peekedMacHdr.GetDstPanId() << " ";
3013
3014 if (peekedMacHdr.IsCommand())
3015 {
3016 os << " Command Frame ";
3017 }
3018 else if (peekedMacHdr.IsData())
3019 {
3020 os << " Data Frame ";
3021 }
3022 else
3023 {
3024 os << " Unknown Frame ";
3025 }
3026
3027 os << "\n";
3028 }
3029 os << "\n";
3030}
3031
3032int64_t
3034{
3035 NS_LOG_FUNCTION(this);
3036 m_uniformVar->SetStream(stream);
3037 m_csmaCa->AssignStreams(stream + 1);
3038 return 2;
3039}
3040
3041void
3043{
3044 LrWpanMacHeader peekedMacHdr;
3045 p->PeekHeader(peekedMacHdr);
3046
3047 for (auto it = m_indTxQueue.begin(); it != m_indTxQueue.end(); it++)
3048 {
3049 if (peekedMacHdr.GetDstAddrMode() == EXT_ADDR)
3050 {
3051 if (((*it)->dstExtAddress == peekedMacHdr.GetExtDstAddr()) &&
3052 ((*it)->seqNum == peekedMacHdr.GetSeqNum()))
3053 {
3055 m_indTxQueue.erase(it);
3056 break;
3057 }
3058 }
3059 else if (peekedMacHdr.GetDstAddrMode() == SHORT_ADDR)
3060 {
3061 if (((*it)->dstShortAddress == peekedMacHdr.GetShortDstAddr()) &&
3062 ((*it)->seqNum == peekedMacHdr.GetSeqNum()))
3063 {
3065 m_indTxQueue.erase(it);
3066 break;
3067 }
3068 }
3069 }
3070
3071 p = nullptr;
3072}
3073
3074void
3076{
3078 NS_LOG_FUNCTION(this << status << m_txQueue.size());
3079
3080 LrWpanMacHeader macHdr;
3081 Time ifsWaitTime;
3082 double symbolRate;
3083
3084 symbolRate = m_phy->GetDataOrSymbolRate(false); // symbols per second
3085
3086 m_txPkt->PeekHeader(macHdr);
3087
3088 if (status == IEEE_802_15_4_PHY_SUCCESS)
3089 {
3090 if (!macHdr.IsAcknowledgment())
3091 {
3092 if (macHdr.IsBeacon())
3093 {
3094 // Start CAP only if we are in beacon mode (i.e. if slotted csma-ca is running)
3095 if (m_csmaCa->IsSlottedCsmaCa())
3096 {
3097 // The Tx Beacon in symbols
3098 // Beacon = 5 bytes Sync Header (SHR) + 1 byte PHY header (PHR) + PSDU (default
3099 // 17 bytes)
3100 uint64_t beaconSymbols = m_phy->GetPhySHRDuration() +
3101 1 * m_phy->GetPhySymbolsPerOctet() +
3102 (m_txPkt->GetSize() * m_phy->GetPhySymbolsPerOctet());
3103
3104 // The beacon Tx time and start of the Outgoing superframe Active Period
3106 Simulator::Now() - Seconds(static_cast<double>(beaconSymbols) / symbolRate);
3107
3109 this,
3111 NS_LOG_DEBUG("Beacon Sent (m_macBeaconTxTime: " << m_macBeaconTxTime.As(Time::S)
3112 << ")");
3113
3115 {
3116 MlmeStartConfirmParams mlmeConfirmParams;
3117 mlmeConfirmParams.m_status = MacStatus::SUCCESS;
3118 m_mlmeStartConfirmCallback(mlmeConfirmParams);
3119 }
3120 }
3121
3122 ifsWaitTime = Seconds(static_cast<double>(GetIfsSize()) / symbolRate);
3123
3124 if (m_csmaCa->IsSlottedCsmaCa())
3125 {
3126 // The beacon was sent immediately in beacon-enabled mode
3127 m_txPkt = nullptr;
3128 }
3129 else
3130 {
3131 // The beacon was sent using CSMA/CA as a result of a beacon request
3132 // therefore, remove it from TX Queue
3134 }
3135 }
3136 else if (macHdr.IsAckReq()) // We have sent a regular data packet, check if we have to
3137 // wait for an ACK.
3138 {
3139 // we sent a regular data frame or command frame (e.g. AssocReq command) that
3140 // require ACK wait for the ack or the next retransmission timeout start
3141 // retransmission timer
3142 Time waitTime = Seconds(static_cast<double>(GetMacAckWaitDuration()) / symbolRate);
3148 return;
3149 }
3150 else if (macHdr.IsCommand())
3151 {
3152 // We handle commands that do not require ACK
3153 // (e.g. Coordinator realigment command in an orphan response)
3154 // Other command with ACK required are handle by the previous if statement.
3155
3156 // Check the transmitted packet command type and issue the appropriate indication.
3157 Ptr<Packet> txOriginalPkt = m_txPkt->Copy();
3158 LrWpanMacHeader txMacHdr;
3159 txOriginalPkt->RemoveHeader(txMacHdr);
3160 CommandPayloadHeader txMacPayload;
3161 txOriginalPkt->RemoveHeader(txMacPayload);
3162
3164 {
3166 {
3167 MlmeCommStatusIndicationParams commStatusParams;
3168 commStatusParams.m_panId = m_macPanId;
3169
3170 commStatusParams.m_srcAddrMode = macHdr.GetSrcAddrMode();
3171 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
3172 commStatusParams.m_srcShortAddr = macHdr.GetShortSrcAddr();
3173
3174 commStatusParams.m_dstAddrMode = macHdr.GetDstAddrMode();
3175 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
3176 commStatusParams.m_dstShortAddr = macHdr.GetShortDstAddr();
3177
3178 commStatusParams.m_status = MacStatus::SUCCESS;
3179 m_mlmeCommStatusIndicationCallback(commStatusParams);
3180 }
3181 }
3182
3183 ifsWaitTime = Seconds(static_cast<double>(GetIfsSize()) / symbolRate);
3185 }
3186 else
3187 {
3189 // remove the copy of the packet that was just sent
3191 {
3192 McpsDataConfirmParams confirmParams;
3193 NS_ASSERT_MSG(!m_txQueue.empty(), "TxQsize = 0");
3194 Ptr<TxQueueElement> txQElement = m_txQueue.front();
3195 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
3196 confirmParams.m_status = MacStatus::SUCCESS;
3197 m_mcpsDataConfirmCallback(confirmParams);
3198 }
3199 ifsWaitTime = Seconds(static_cast<double>(GetIfsSize()) / symbolRate);
3201 }
3202 }
3203 else
3204 {
3205 // The packet sent was a successful ACK
3206
3207 // Check the received frame before the transmission of the ACK,
3208 // and send the appropriate Indication or Confirmation
3209 Ptr<Packet> recvOriginalPkt = m_rxPkt->Copy();
3210 LrWpanMacHeader receivedMacHdr;
3211 recvOriginalPkt->RemoveHeader(receivedMacHdr);
3212
3213 if (receivedMacHdr.IsCommand())
3214 {
3215 CommandPayloadHeader receivedMacPayload;
3216 recvOriginalPkt->RemoveHeader(receivedMacPayload);
3217
3218 if (receivedMacPayload.GetCommandFrameType() ==
3220 {
3222 {
3223 // NOTE: The LQI parameter is not part of the standard but found
3224 // in some implementations as is required for higher layers (See Zboss
3225 // implementation).
3226 MlmeAssociateIndicationParams associateParams;
3227 associateParams.capabilityInfo = receivedMacPayload.GetCapabilityField();
3228 associateParams.m_extDevAddr = receivedMacHdr.GetExtSrcAddr();
3229 associateParams.lqi = m_lastRxFrameLqi;
3230 m_mlmeAssociateIndicationCallback(associateParams);
3231 }
3232
3233 // Clear the packet buffer for the packet request received.
3234 m_rxPkt = nullptr;
3235 }
3236 else if (receivedMacPayload.GetCommandFrameType() ==
3238 {
3239 MlmeAssociateConfirmParams confirmParams;
3240
3241 switch (static_cast<MacStatus>(receivedMacPayload.GetAssociationStatus()))
3242 {
3243 case MacStatus::SUCCESS:
3244 // The assigned short address by the coordinator
3245 SetShortAddress(receivedMacPayload.GetShortAddr());
3246 m_macPanId = receivedMacHdr.GetSrcPanId();
3247
3248 confirmParams.m_status = MacStatus::SUCCESS;
3249 confirmParams.m_assocShortAddr = GetShortAddress();
3250 break;
3252 confirmParams.m_status = MacStatus::FULL_CAPACITY;
3253 m_macPanId = 0xffff;
3255 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3258 m_csmaCa->SetUnSlottedCsmaCa();
3261 break;
3263 default:
3264 confirmParams.m_status = MacStatus::ACCESS_DENIED;
3265 m_macPanId = 0xffff;
3267 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3270 m_csmaCa->SetUnSlottedCsmaCa();
3273 break;
3274 }
3275
3277 {
3278 m_mlmeAssociateConfirmCallback(confirmParams);
3279 }
3280 }
3281 else if (receivedMacPayload.GetCommandFrameType() == CommandPayloadHeader::DATA_REQ)
3282 {
3283 // We enqueue the the Assoc Response command frame in the Tx queue
3284 // and the packet is transmitted as soon as the PHY is free and the IFS have
3285 // taken place.
3287 }
3288 }
3289
3290 // Clear the packet buffer for the ACK packet sent.
3291 m_txPkt = nullptr;
3292 }
3293 }
3294 else if (status == IEEE_802_15_4_PHY_UNSPECIFIED)
3295 {
3296 if (!macHdr.IsAcknowledgment())
3297 {
3298 NS_ASSERT_MSG(!m_txQueue.empty(), "TxQsize = 0");
3299 Ptr<TxQueueElement> txQElement = m_txQueue.front();
3300 m_macTxDropTrace(txQElement->txQPkt);
3302 {
3303 McpsDataConfirmParams confirmParams;
3304 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
3305 confirmParams.m_status = MacStatus::FRAME_TOO_LONG;
3306 m_mcpsDataConfirmCallback(confirmParams);
3307 }
3309 }
3310 else
3311 {
3312 NS_LOG_ERROR("Unable to send ACK");
3313 }
3314 }
3315 else
3316 {
3317 // Something went really wrong. The PHY is not in the correct state for
3318 // data transmission.
3319 NS_FATAL_ERROR("Transmission attempt failed with PHY status " << status);
3320 }
3321
3322 if (!ifsWaitTime.IsZero())
3323 {
3324 m_ifsEvent =
3325 Simulator::Schedule(ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this, ifsWaitTime);
3326 }
3327
3330}
3331
3332void
3334{
3335 NS_LOG_FUNCTION(this << status);
3336 // Direct this call through the csmaCa object
3337 m_csmaCa->PlmeCcaConfirm(status);
3338}
3339
3340void
3341LrWpanMac::PlmeEdConfirm(PhyEnumeration status, uint8_t energyLevel)
3342{
3343 NS_LOG_FUNCTION(this << status << energyLevel);
3344
3345 if (energyLevel > m_maxEnergyLevel)
3346 {
3347 m_maxEnergyLevel = energyLevel;
3348 }
3349
3351 Seconds(8.0 / m_phy->GetDataOrSymbolRate(false)))
3352 {
3353 m_phy->PlmeEdRequest();
3354 }
3355}
3356
3357void
3360 Ptr<PhyPibAttributes> attribute)
3361{
3362 NS_LOG_FUNCTION(this << status << id << attribute);
3363}
3364
3365void
3367{
3368 NS_LOG_FUNCTION(this << status);
3369
3370 if (m_macState == MAC_SENDING &&
3371 (status == IEEE_802_15_4_PHY_TX_ON || status == IEEE_802_15_4_PHY_SUCCESS))
3372 {
3374
3375 // Start sending if we are in state SENDING and the PHY transmitter was enabled.
3379 m_phy->PdDataRequest(m_txPkt->GetSize(), m_txPkt);
3380 }
3381 else if (m_macState == MAC_CSMA &&
3382 (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS))
3383 {
3384 // Start the CSMA algorithm as soon as the receiver is enabled.
3385 m_csmaCa->Start();
3386 }
3387 else if (m_macState == MAC_IDLE)
3388 {
3390 status == IEEE_802_15_4_PHY_TRX_OFF);
3391
3393 {
3394 // Kick start Energy Detection Scan
3395 m_phy->PlmeEdRequest();
3396 }
3397 else if (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS)
3398 {
3399 // Check if there is not messages to transmit when going idle
3400 CheckQueue();
3401 }
3402 }
3403 else if (m_macState == MAC_ACK_PENDING)
3404 {
3406 }
3407 else
3408 {
3409 // TODO: What to do when we receive an error?
3410 // If we want to transmit a packet, but switching the transceiver on results
3411 // in an error, we have to recover somehow (and start sending again).
3412 NS_FATAL_ERROR("Error changing transceiver state");
3413 }
3414}
3415
3416void
3418{
3419 NS_LOG_FUNCTION(this << status << id);
3421 {
3423 {
3424 // get the first channel to scan from scan channel list
3425 bool channelFound = false;
3426 for (int i = m_channelScanIndex; i <= 26; i++)
3427 {
3429 {
3430 channelFound = true;
3431 break;
3432 }
3434 }
3435
3436 if (channelFound)
3437 {
3439 pibAttr->phyCurrentChannel = m_channelScanIndex;
3440 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel,
3441 pibAttr);
3442 }
3443 }
3444 else
3445 {
3447 {
3448 MlmeScanConfirmParams confirmParams;
3449 confirmParams.m_scanType = m_scanParams.m_scanType;
3450 confirmParams.m_chPage = m_scanParams.m_chPage;
3451 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3452 m_mlmeScanConfirmCallback(confirmParams);
3453 }
3454 NS_LOG_ERROR(this << "Channel Scan: Invalid channel page");
3455 }
3456 }
3458 {
3460 {
3461 auto symbolRate = static_cast<uint64_t>(m_phy->GetDataOrSymbolRate(false));
3462 Time nextScanTime;
3463
3465 {
3466 nextScanTime = Seconds(static_cast<double>(m_macResponseWaitTime) / symbolRate);
3467 }
3468 else
3469 {
3470 uint64_t scanDurationSym =
3472
3473 nextScanTime = Seconds(static_cast<double>(scanDurationSym) / symbolRate);
3474 }
3475
3476 switch (m_scanParams.m_scanType)
3477 {
3478 case MLMESCAN_ED:
3479 m_maxEnergyLevel = 0;
3482 // set phy to RX_ON and kick start the first PLME-ED.request
3483 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3484 break;
3485 case MLMESCAN_ACTIVE:
3488 break;
3489 case MLMESCAN_PASSIVE:
3491 // turn back the phy to RX_ON after setting Page/channel
3492 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3493 break;
3494 case MLMESCAN_ORPHAN:
3496 Simulator::Schedule(nextScanTime, &LrWpanMac::EndChannelScan, this);
3498 break;
3499
3500 default:
3501 MlmeScanConfirmParams confirmParams;
3502 confirmParams.m_scanType = m_scanParams.m_scanType;
3503 confirmParams.m_chPage = m_scanParams.m_chPage;
3504 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3506 {
3507 m_mlmeScanConfirmCallback(confirmParams);
3508 }
3509 NS_LOG_ERROR("Scan Type currently not supported");
3510 return;
3511 }
3512 }
3513 else
3514 {
3516 {
3517 MlmeScanConfirmParams confirmParams;
3518 confirmParams.m_scanType = m_scanParams.m_scanType;
3519 confirmParams.m_chPage = m_scanParams.m_chPage;
3520 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3521 m_mlmeScanConfirmCallback(confirmParams);
3522 }
3523 NS_LOG_ERROR("Channel " << m_channelScanIndex
3524 << " could not be set in the current page");
3525 }
3526 }
3528 {
3530 {
3532 pibAttr->phyCurrentChannel = m_startParams.m_logCh;
3533 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
3534 }
3535 else
3536 {
3538 {
3539 MlmeStartConfirmParams confirmParams;
3540 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3541 m_mlmeStartConfirmCallback(confirmParams);
3542 }
3543 NS_LOG_ERROR("Invalid page parameter in MLME-start");
3544 }
3545 }
3548 {
3550 {
3552 }
3553 else
3554 {
3556 {
3557 MlmeStartConfirmParams confirmParams;
3558 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3559 m_mlmeStartConfirmCallback(confirmParams);
3560 }
3561 NS_LOG_ERROR("Invalid channel parameter in MLME-start");
3562 }
3563 }
3565 {
3567 {
3569 pibAttr->phyCurrentChannel = m_associateParams.m_chNum;
3570 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
3571 }
3572 else
3573 {
3574 m_macPanId = 0xffff;
3576 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3579 m_csmaCa->SetUnSlottedCsmaCa();
3582
3584 {
3585 MlmeAssociateConfirmParams confirmParams;
3586 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
3587 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3588 m_mlmeAssociateConfirmCallback(confirmParams);
3589 }
3590 NS_LOG_ERROR("Invalid page parameter in MLME-associate");
3591 }
3592 }
3595 {
3597 {
3599 }
3600 else
3601 {
3602 m_macPanId = 0xffff;
3604 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3607 m_csmaCa->SetUnSlottedCsmaCa();
3610
3612 {
3613 MlmeAssociateConfirmParams confirmParams;
3614 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
3615 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3616 m_mlmeAssociateConfirmCallback(confirmParams);
3617 }
3618 NS_LOG_ERROR("Invalid channel parameter in MLME-associate");
3619 }
3620 }
3621 else
3622 {
3624 {
3625 MlmeSetConfirmParams confirmParams;
3627 {
3628 confirmParams.m_status = MacStatus::SUCCESS;
3629 }
3630 else
3631 {
3633 }
3634
3636 {
3638 }
3640 {
3642 }
3643
3644 m_mlmeSetConfirmCallback(confirmParams);
3645 }
3646 }
3647}
3648
3649void
3651{
3652 NS_LOG_FUNCTION(this << "mac state = " << macState);
3653
3654 if (macState == MAC_IDLE)
3655 {
3658 {
3659 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3660 }
3661 else
3662 {
3663 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
3664 }
3665 }
3666 else if (macState == MAC_ACK_PENDING)
3667 {
3669 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3670 }
3671 else if (macState == MAC_CSMA)
3672 {
3675 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3676 }
3677 else if (m_macState == MAC_CSMA && macState == CHANNEL_IDLE)
3678 {
3679 // Channel is idle, set transmitter to TX_ON
3681 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TX_ON);
3682 }
3683 else if (m_macState == MAC_CSMA && macState == CHANNEL_ACCESS_FAILURE)
3684 {
3686
3687 // Cannot find a clear channel, drop the current packet
3688 // and send the proper confirm/indication according to the packet type
3689 NS_LOG_DEBUG(this << " cannot find clear channel");
3690
3692
3693 Ptr<Packet> pkt = m_txPkt->Copy();
3694 LrWpanMacHeader macHdr;
3695 pkt->RemoveHeader(macHdr);
3696
3697 if (macHdr.IsCommand())
3698 {
3699 CommandPayloadHeader cmdPayload;
3700 pkt->RemoveHeader(cmdPayload);
3701
3702 switch (cmdPayload.GetCommandFrameType())
3703 {
3705 m_macPanId = 0xffff;
3707 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3710 m_csmaCa->SetUnSlottedCsmaCa();
3713
3715 {
3716 MlmeAssociateConfirmParams confirmParams;
3717 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
3719 m_mlmeAssociateConfirmCallback(confirmParams);
3720 }
3721 break;
3722 }
3725 {
3726 MlmeCommStatusIndicationParams commStatusParams;
3727 commStatusParams.m_panId = m_macPanId;
3728 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
3729 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
3730 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
3731 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
3733 m_mlmeCommStatusIndicationCallback(commStatusParams);
3734 }
3736 break;
3737 }
3739 m_macPanId = 0xffff;
3741 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3744 m_csmaCa->SetUnSlottedCsmaCa();
3747
3749 {
3750 MlmePollConfirmParams pollConfirmParams;
3751 pollConfirmParams.m_status = MacStatus::CHANNEL_ACCESS_FAILURE;
3752 m_mlmePollConfirmCallback(pollConfirmParams);
3753 }
3754 break;
3755 }
3758 {
3759 MlmeCommStatusIndicationParams commStatusParams;
3760 commStatusParams.m_panId = m_macPanId;
3761 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
3762 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
3763 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
3764 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
3766 m_mlmeCommStatusIndicationCallback(commStatusParams);
3767 }
3768 break;
3769 }
3772 {
3773 m_unscannedChannels.emplace_back(m_phy->GetCurrentChannelNum());
3774 }
3775 // TODO: Handle orphan notification command during a
3776 // channel access failure when not is not scanning.
3777 break;
3778 }
3780 if (m_scanEvent.IsPending())
3781 {
3782 m_unscannedChannels.emplace_back(m_phy->GetCurrentChannelNum());
3783 }
3784 // TODO: Handle beacon request command during a
3785 // channel access failure when not scanning.
3786 break;
3787 }
3788 default: {
3789 // TODO: Other commands(e.g. Disassociation notification, etc)
3790 break;
3791 }
3792 }
3794 }
3795 else if (macHdr.IsData())
3796 {
3798 {
3799 McpsDataConfirmParams confirmParams;
3800 confirmParams.m_msduHandle = m_txQueue.front()->txQMsduHandle;
3802 m_mcpsDataConfirmCallback(confirmParams);
3803 }
3804 // remove the copy of the packet that was just sent
3806 }
3807 else
3808 {
3809 // TODO:: specify behavior for other packets
3810 m_txPkt = nullptr;
3811 m_retransmission = 0;
3812 m_numCsmacaRetry = 0;
3813 }
3814
3817 {
3818 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3819 }
3820 else
3821 {
3822 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
3823 }
3824 }
3825 else if (m_macState == MAC_CSMA && macState == MAC_CSMA_DEFERRED)
3826 {
3828 m_txPkt = nullptr;
3829 // The MAC is running on beacon mode and the current packet could not be sent in the
3830 // current CAP. The packet will be send on the next CAP after receiving the beacon.
3831 // The PHY state does not change from its current form. The PHY change (RX_ON) will be
3832 // triggered by the scheduled beacon event.
3833
3834 NS_LOG_DEBUG("****** PACKET DEFERRED to the next superframe *****");
3835 }
3836}
3837
3838void
3843
3844void
3849
3850uint16_t
3852{
3853 return m_macPanId;
3854}
3855
3861
3867
3868void
3869LrWpanMac::SetPanId(uint16_t panId)
3870{
3871 m_macPanId = panId;
3872}
3873
3874void
3876{
3877 NS_LOG_LOGIC(this << " change lrwpan mac state from " << m_macState << " to " << newState);
3878 m_macStateLogger(m_macState, newState);
3879 m_macState = newState;
3880}
3881
3882uint64_t
3884{
3885 return lrwpan::aUnitBackoffPeriod + lrwpan::aTurnaroundTime + m_phy->GetPhySHRDuration() +
3886 ceil(6 * m_phy->GetPhySymbolsPerOctet());
3887}
3888
3889uint8_t
3894
3895void
3897{
3898 NS_LOG_DEBUG("Transmit Queue Size: " << m_txQueue.size());
3899}
3900
3901void
3903{
3904 m_macMaxFrameRetries = retries;
3905}
3906
3907bool
3909{
3911 LrWpanMacHeader macHdr;
3912 m_txPkt->PeekHeader(macHdr);
3913
3914 if (m_coor)
3915 {
3916 // The device is its coordinator and the packet is not to itself
3917 return false;
3918 }
3919 else if (m_macCoordShortAddress == macHdr.GetShortDstAddr() ||
3921 {
3922 return true;
3923 }
3924 else
3925 {
3926 NS_LOG_DEBUG("ERROR: Packet not for the coordinator!");
3927 return false;
3928 }
3929}
3930
3933{
3935
3937 {
3938 return m_macSIFSPeriod;
3939 }
3940 else
3941 {
3942 return m_macLIFSPeriod;
3943 }
3944}
3945
3946void
3951
3952void
3957
3958uint64_t
3960{
3962 // Sync Header (SHR) + 8 bits PHY header (PHR) + PSDU
3963 return (m_phy->GetPhySHRDuration() + 1 * m_phy->GetPhySymbolsPerOctet() +
3964 (m_txPkt->GetSize() * m_phy->GetPhySymbolsPerOctet()));
3965}
3966
3967bool
3969{
3971 LrWpanMacHeader macHdr;
3972 m_txPkt->PeekHeader(macHdr);
3973
3974 return macHdr.IsAckReq();
3975}
3976
3977} // namespace lrwpan
3978} // namespace ns3
bool IsNull() const
Check for null implementation.
Definition callback.h:555
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
bool IsExpired() const
This method is syntactic sugar for the ns3::Simulator::IsExpired method.
Definition event-id.cc:58
This class can contain 16 bit addresses.
bool IsMulticast() const
Checks if the address is a multicast address according to RFC 4944 Section 9 (i.e....
bool IsBroadcast() const
Checks if the address is a broadcast address according to 802.15.4 scheme (i.e., 0xFFFF).
an EUI-64 address
static Mac64Address Allocate()
Allocate a new Mac64Address.
static bool ChecksumEnabled()
Definition node.cc:267
virtual void DoInitialize()
Initialize() implementation.
Definition object.cc:440
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition packet.h:850
Ptr< Packet > Copy() const
performs a COW copy of the packet.
Definition packet.cc:120
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition packet.cc:294
Smart pointer class similar to boost::intrusive_ptr.
NUMERIC_TYPE GetValue() const
Extracts the numeric value of the sequence number.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:594
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:206
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:404
@ S
second
Definition nstime.h:105
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:304
a unique identifier for an interface.
Definition type-id.h:48
TypeId AddDeprecatedName(const std::string &name)
Add an deprecated name for a TypeId.
Definition type-id.cc:862
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
Implements the header for the MAC payload beacon frame according to the IEEE 802.15....
void SetSuperframeSpecField(uint16_t sfrmField)
Set the superframe specification field to the beacon payload header.
uint16_t GetSuperframeSpecField() const
Get the superframe specification field from the beacon payload header.
GtsFields GetGtsFields() const
Get the Guaranteed Time Slots (GTS) fields from the beacon payload header.
void SetGtsFields(GtsFields gtsFields)
Set the superframe Guaranteed Time Slot (GTS) fields to the beacon payload header.
PendingAddrFields GetPndAddrFields() const
Get the pending address fields from the beacon payload header.
void SetPndAddrFields(PendingAddrFields pndAddrFields)
Set the superframe Pending Address fields to the beacon payload header.
Implements the header for the MAC payload command frame according to the IEEE 802....
MacCommand GetCommandFrameType() const
Get the command frame type ID.
Mac16Address GetShortAddr() const
Get the Short address assigned by the coordinator (Association Response and Coordinator Realigment co...
uint16_t GetPanId() const
Get the PAN identifier.
void SetPage(uint8_t page)
Set the logical channel page number.
void SetShortAddr(Mac16Address shortAddr)
Set the Short Address Assigned by the coordinator (Association Response and Coordinator Realigment Co...
uint8_t GetCapabilityField() const
Get the Capability Information Field from the command payload header.
void SetCommandFrameType(MacCommand macCmd)
Set the command frame type.
Mac16Address GetCoordShortAddr() const
Get the coordinator short address.
void SetCapabilityField(uint8_t cap)
Set the Capability Information Field to the command payload header (Association Request Command).
void SetCoordShortAddr(Mac16Address addr)
Set the coordinator short address (16 bit address).
@ ASSOCIATION_RESP
Association response (RFD true: Rx)
@ DATA_REQ
Data Request (RFD true: Tx)
@ COOR_REALIGN
Coordinator Realignment (RFD true: Rx)
@ ORPHAN_NOTIF
Orphan Notification (RFD true: Tx)
@ ASSOCIATION_REQ
Association request (RFD true: Tx)
@ BEACON_REQ
Beacon Request (RFD true: none )
void SetAssociationStatus(uint8_t status)
Set status resulting from the association attempt (Association Response Command).
uint8_t GetAssociationStatus() const
Get the status resulting from an association request (Association Response Command).
void SetPanId(uint16_t id)
Get the PAN identifier.
void SetChannel(uint8_t channel)
Set the logical channel number.
Represent the GTS information fields.
bool GetGtsPermit() const
Get the GTS Specification Permit.
Lr-wpan MAC layer abstraction.
MlmeOrphanIndicationCallback m_mlmeOrphanIndicationCallback
This callback is used to indicate the reception of a orphan notification command.
MlmeGetConfirmCallback m_mlmeGetConfirmCallback
This callback is used to report the result of an attribute read request to the upper layers.
MlmeAssociateIndicationCallback m_mlmeAssociateIndicationCallback
This callback is used to indicate the reception of an association request command.
MlmeSetConfirmCallback m_mlmeSetConfirmCallback
This callback is used to report the result of an attribute writing request to the upper layers.
MlmePollConfirmCallback m_mlmePollConfirmCallback
This callback is used to report the status after a device send data command request to the coordinato...
MlmeCommStatusIndicationCallback m_mlmeCommStatusIndicationCallback
This callback is instigated through a response primitive.
McpsDataConfirmCallback m_mcpsDataConfirmCallback
This callback is used to report data transmission request status to the upper layers.
McpsDataIndicationCallback m_mcpsDataIndicationCallback
This callback is used to notify incoming packets to the upper layers.
MlmeScanConfirmCallback m_mlmeScanConfirmCallback
This callback is used to report the result of a scan on a group of channels for the selected channel ...
MlmeAssociateConfirmCallback m_mlmeAssociateConfirmCallback
This callback is used to report the status after a device request an association with a coordinator.
MlmeSyncLossIndicationCallback m_mlmeSyncLossIndicationCallback
This callback is used to indicate the loss of synchronization with a coordinator.
MlmeBeaconNotifyIndicationCallback m_mlmeBeaconNotifyIndicationCallback
This callback is used to notify incoming beacon packets to the upper layers.
MlmeStartConfirmCallback m_mlmeStartConfirmCallback
This callback is used to report the start of a new PAN or the begin of a new superframe configuration...
Represent the Mac Header with the Frame Control and Sequence Number fields.
LrWpanMacType GetType() const
Get the header type.
Mac16Address GetShortSrcAddr() const
Get the Source Short address.
void SetDstAddrMode(uint8_t addrMode)
Set the Destination address mode.
void SetNoAckReq()
Set the Frame Control field "Ack. Request" bit to false.
void SetDstAddrFields(uint16_t panId, Mac16Address addr)
Set Destination address fields.
Mac64Address GetExtSrcAddr() const
Get the Source Extended address.
bool IsData() const
Returns true if the header is a data.
bool IsBeacon() const
Returns true if the header is a beacon.
@ LRWPAN_MAC_ACKNOWLEDGMENT
LRWPAN_MAC_ACKNOWLEDGMENT.
@ LRWPAN_MAC_RESERVED
LRWPAN_MAC_RESERVED.
@ LRWPAN_MAC_COMMAND
LRWPAN_MAC_COMMAND.
@ LRWPAN_MAC_BEACON
LRWPAN_MAC_BEACON.
void SetPanIdComp()
Set the Frame Control field "PAN ID Compression" bit to true.
Mac16Address GetShortDstAddr() const
Get the Destination Short address.
void SetSrcAddrMode(uint8_t addrMode)
Set the Source address mode.
bool IsCommand() const
Returns true if the header is a command.
uint8_t GetSeqNum() const
Get the frame Sequence number.
void SetFrameVer(uint8_t ver)
Set the Frame version.
uint8_t GetFrameVer() const
Get the Frame Version of Frame control field.
void SetSrcAddrFields(uint16_t panId, Mac16Address addr)
Set Source address fields.
uint16_t GetSrcPanId() const
Get the Source PAN ID.
void SetNoPanIdComp()
Set the Frame Control field "PAN ID Compression" bit to false.
uint16_t GetDstPanId() const
Get the Destination PAN ID.
void SetAckReq()
Set the Frame Control field "Ack. Request" bit to true.
bool IsAckReq() const
Check if Ack.
uint8_t GetDstAddrMode() const
Get the Dest.
void SetSecDisable()
Set the Frame Control field "Security Enabled" bit to false.
Mac64Address GetExtDstAddr() const
Get the Destination Extended address.
bool IsAcknowledgment() const
Returns true if the header is an ack.
uint8_t GetSrcAddrMode() const
Get the Source Addressing Mode of Frame control field.
Class that implements the LR-WPAN MAC state machine.
Ptr< Packet > m_rxPkt
The command request packet received.
TracedCallback< Ptr< const Packet > > m_macTxDequeueTrace
The trace source fired when packets are dequeued from the L3/l2 transmission queue.
void RemovePendTxQElement(Ptr< Packet > p)
Remove an element from the pending transaction list.
TracedCallback< Ptr< const Packet > > m_macRxDropTrace
The trace source fired for packets successfully received by the device but dropped before being forwa...
uint8_t m_deviceCapability
Indication of current device capability (FFD or RFD)
std::vector< uint8_t > m_macBeaconPayload
The set with the contents of the beacon payload.
void SetExtendedAddress(Mac64Address address)
Set the extended address of this MAC.
TracedCallback< Ptr< const Packet > > m_macIndTxDequeueTrace
The trace source fired when packets are dequeued from the L3/l2 indirect transmission queue (Pending ...
Ptr< LrWpanPhy > GetPhy()
Get the underlying PHY of the MAC.
uint32_t m_superframeDuration
Indication of the superframe duration in symbols.
void AwaitBeacon()
Called after the end of an INCOMING superframe to start the moment a device waits for a new incoming ...
void EndStartRequest()
Called to end a MLME-START.request after changing the page and channel number.
void MlmeAssociateResponse(MlmeAssociateResponseParams params) override
IEEE 802.15.4-2011, section 6.2.2.3 MLME-ASSOCIATE.response Primitive used to initiate a response to ...
bool m_macPromiscuousMode
Indicates if MAC sublayer is in receive all mode.
Ptr< LrWpanCsmaCa > m_csmaCa
The CSMA/CA implementation used by this MAC.
void SendAck(uint8_t seqno)
Send an acknowledgment packet for the given sequence number.
uint8_t m_numCsmacaRetry
The number of CSMA/CA retries used for sending the current packet.
Ptr< Packet > m_txPkt
The packet which is currently being sent by the MAC layer.
MlmeStartRequestParams m_startParams
The parameters used during a MLME-START.request.
void PurgeInd()
Purge expired transactions from the pending transactions list.
void SetCsmaCa(Ptr< LrWpanCsmaCa > csmaCa)
Set the CSMA/CA implementation to be used by the MAC.
EventId m_scanEvent
Scheduler event for the end of an ACTIVE or PASSIVE channel scan.
void PdDataConfirm(PhyEnumeration status)
IEEE 802.15.4-2006 section 6.2.1.2 Confirm the end of transmission of an MPDU to MAC.
void SendOrphanNotificationCommand()
Called to send a orphan notification command.
Mac64Address m_macExtendedAddress
The extended 64 address (IEEE EUI-64) used by this MAC.
EventId m_scanEnergyEvent
Scheduler event for the end of a ED channel scan.
uint16_t m_macPanIdScan
Temporally stores the value of the current m_macPanId when a MLME-SCAN.request is performed.
EventId m_setMacState
Scheduler event for a deferred MAC state change.
uint32_t m_macBeaconPayloadLength
The length, in octets, of the beacon payload.
TracedCallback< Ptr< const Packet > > m_promiscSnifferTrace
A trace source that emulates a promiscuous mode protocol sniffer connected to the device.
TracedCallback< Ptr< const Packet >, uint8_t, uint8_t > m_sentPktTrace
The trace source fired when packets are considered as successfully sent or the transmission has been ...
uint64_t m_assocRespCmdWaitTime
The maximum wait time for an association response command after the reception of data request command...
GtsFields GetGtsFields()
Constructs the Guaranteed Time Slots (GTS) Fields from local information.
void SetIndTxQMaxSize(uint32_t queueSize)
Set the max size of the indirect transmit queue (Pending Transaction list)
std::deque< Ptr< IndTxQueueElement > > m_indTxQueue
The indirect transmit queue used by the MAC pending messages (The pending transaction list).
uint8_t m_incomingSuperframeOrder
Used by all devices that have a parent.
TracedCallback< Ptr< const Packet > > m_macPromiscRxTrace
The trace source fired for packets successfully received by the device immediately before being forwa...
uint32_t m_macLIFSPeriod
The minimum time forming a Long InterFrame Spacing (LIFS) period.
TracedCallback< Ptr< const Packet > > m_macRxTrace
The trace source fired for packets successfully received by the device immediately before being forwa...
std::vector< uint8_t > m_unscannedChannels
The list of unscanned channels during a scan operation.
bool m_macRxOnWhenIdle
Indication of whether the MAC sublayer is to enable its receiver during idle periods.
void PrintTransmitQueueSize()
Print the number of elements in the packet transmit queue.
uint16_t m_channelScanIndex
The channel list index used to obtain the current scanned channel.
void SendAssocRequestCommand()
Called to send an associate request command.
EventId m_beaconEvent
Scheduler event for generation of one beacon.
void BeaconSearchTimeout()
Called if the device is unable to locate a beacon in the time set by MLME-SYNC.request.
uint32_t m_macSIFSPeriod
The minimum time forming a Short InterFrame Spacing (SIFS) period.
TracedCallback< Ptr< const Packet > > m_macTxTrace
The trace source fired when packets are being sent down to L1.
void MlmeSyncRequest(MlmeSyncRequestParams params) override
IEEE 802.15.4-2011, section 6.2.13.1 MLME-SYNC.request Request to synchronize with the coordinator by...
SequenceNumber8 m_macDsn
Sequence number added to transmitted data or MAC command frame, 00-ff.
void ChangeMacState(MacState newState)
Change the current MAC state to the given new state.
Mac16Address m_macCoordShortAddress
The short address of the coordinator through which the device is associated.
Mac64Address GetCoordExtAddress() const
Get the coordinator extended address currently associated to this device.
void MlmeGetRequest(MacPibAttributeIdentifier id) override
IEEE 802.15.4-2006, section 7.1.6.1 MLME-GET.request Request information about a given PIB attribute.
std::deque< Ptr< TxQueueElement > > m_txQueue
The transmit queue used by the MAC.
uint8_t m_macSuperframeOrder
Used by a PAN coordinator or coordinator.
TracedValue< SuperframeStatus > m_incSuperframeStatus
The current period of the incoming superframe.
void SetPanId(uint16_t panId)
Set the PAN id used by this MAC.
void MlmeStartRequest(MlmeStartRequestParams params) override
IEEE 802.15.4-2006, section 7.1.14.1 MLME-START.request Request to allow a PAN coordinator to initiat...
MlmeScanRequestParams m_scanParams
The parameters used during a MLME-SCAN.request.
void SetLrWpanMacState(MacState macState)
CSMA-CA algorithm calls back the MAC after executing channel assessment.
void SetShortAddress(Mac16Address address)
Set the short address of this MAC.
uint8_t m_incomingBeaconOrder
The beaconOrder value of the INCOMING frame.
void PrintTxQueue(std::ostream &os) const
Print the Transmit Queue.
void CheckQueue()
Check the transmission queue.
uint32_t m_incomingSuperframeDuration
Indication of the superframe duration in symbols (e.g.
TracedCallback< Ptr< const Packet > > m_macIndTxEnqueueTrace
The trace source fired when packets come into the "top" of the device at the L3/L2 transition,...
TracedCallback< Ptr< const Packet > > m_macTxDropTrace
The trace source fired when packets are dropped due to missing ACKs or because of transmission failur...
void SetMacMaxFrameRetries(uint8_t retries)
Set the macMaxFrameRetries attribute value.
uint16_t m_macTransactionPersistenceTime
The maximum time (in UNIT periods) that a transaction is stored by a coordinator and indicated in its...
void MlmeOrphanResponse(MlmeOrphanResponseParams params) override
IEEE 802.15.4-2011, section 6.2.7.2 MLME-ORPHAN.response Primitive used to initiatte a response to an...
void AckWaitTimeout()
Handle an ACK timeout with a packet retransmission, if there are retransmission left,...
uint32_t m_maxTxQueueSize
The maximum size of the transmit queue.
TracedCallback< Ptr< const Packet > > m_macIndTxDropTrace
The trace source fired when packets are dropped due to indirect Tx queue overflows or expiration.
uint8_t m_retransmission
The number of already used retransmission for the currently transmitted packet.
LrWpanMac()
Default constructor.
EventId m_incCfpEvent
Scheduler event for the end of the incoming superframe CFP.
std::vector< uint8_t > m_energyDetectList
The list of energy measurements, one for each channel searched during an ED scan.
SequenceNumber8 m_macBsn
Sequence number added to transmitted beacon frame, 00-ff.
TracedCallback< MacState, MacState > m_macStateLogger
A trace source that fires when the MAC changes states.
TracedCallback< Ptr< const Packet > > m_snifferTrace
A trace source that emulates a non-promiscuous protocol sniffer connected to the device.
Mac64Address GetExtendedAddress() const
Get the extended address of this MAC.
void DoDispose() override
Destructor implementation.
uint8_t m_fnlCapSlot
Indication of the Slot where the CAP portion of the OUTGOING Superframe ends.
MlmeAssociateRequestParams m_associateParams
The parameters used during a MLME-ASSOCIATE.request.
uint32_t m_incomingBeaconInterval
Indication of the interval a node should receive a superframe expressed in symbols.
bool m_macAssociationPermit
Indication of whether a coordinator is currently allowing association.
static TypeId GetTypeId()
Get the type ID.
uint64_t GetMacAckWaitDuration() const
Get the macAckWaitDuration attribute value.
void SetTxQMaxSize(uint32_t queueSize)
Set the max size of the transmit queue.
TracedCallback< Time > m_macIfsEndTrace
The trace source is fired at the end of any Interframe Space (IFS).
void MlmeAssociateRequest(MlmeAssociateRequestParams params) override
IEEE 802.15.4-2011, section 6.2.2.1 MLME-ASSOCIATE.request Request primitive used by a device to requ...
bool GetRxOnWhenIdle() const
Check if the receiver will be enabled when the MAC is idle.
void ReceiveBeacon(uint8_t lqi, Ptr< Packet > p)
Used to process the reception of a beacon packet.
void EnqueueInd(Ptr< Packet > p)
Adds a packet to the pending transactions list (Indirect transmissions).
Time m_macBeaconTxTime
The time that the device transmitted its last beacon frame.
std::vector< PanDescriptor > m_panDescriptorList
The list of PAN descriptors accumulated during channel scans, used to select a PAN to associate.
uint8_t m_maxEnergyLevel
The maximum energy level detected during ED scan on the current channel.
Mac16Address GetShortAddress() const
Get the short address of this MAC.
bool m_macAutoRequest
Indication of whether a device automatically sends data request command if its address is listed in t...
PendingAddrFields GetPendingAddrFields()
Constructs Pending Address Fields from the local information, the Pending Address Fields are part of ...
uint64_t m_rxBeaconSymbols
The total size of the received beacon in symbols.
int64_t AssignStreams(int64_t stream)
Assign a fixed random variable stream number to the random variables used by this model.
Ptr< LrWpanPhy > m_phy
The PHY associated with this MAC.
EventId m_cfpEvent
Scheduler event for the end of the outgoing superframe CFP.
uint16_t GetPanId() const
Get the PAN id used by this MAC.
TracedCallback< Ptr< const Packet > > m_macTxOkTrace
The trace source fired when packets where successfully transmitted, that is an acknowledgment was rec...
bool m_panCoor
Indication of whether the current device is the PAN coordinator.
void SendAssocResponseCommand(Ptr< Packet > rxDataReqPkt)
Called to send an associate response command.
Time m_macBeaconRxTime
The time that the device received its last bit of the beacon frame.
void SetAssociatedCoor(Mac16Address mac)
Check if the packet destination is its coordinator.
void StartCFP(SuperframeType superframeType)
Called to begin the Contention Free Period (CFP) in a beacon-enabled mode.
uint16_t m_macPanId
16 bits id of PAN on which this device is operating.
bool PrepareRetransmission()
Check for remaining retransmissions for the packet currently being sent.
void PrintPendingTxQueue(std::ostream &os) const
Print the Pending transaction list.
uint32_t m_ifs
The value of the necessary InterFrame Space after the transmission of a packet.
void MlmeSetRequest(MacPibAttributeIdentifier id, Ptr< MacPibAttributes > attribute) override
IEEE 802.15.4-2011, section 6.2.11.1 MLME-SET.request Attempts to write the given value to the indica...
bool m_beaconTrackingOn
Indication of whether the current device is tracking incoming beacons.
void SendBeaconRequestCommand()
Called to send a beacon request command.
uint32_t m_maxIndTxQueueSize
The maximum size of the indirect transmit queue (The pending transaction list).
void IfsWaitTimeout(Time ifsTime)
After a successful transmission of a frame (beacon, data) or an ack frame reception,...
EventId m_ifsEvent
Scheduler event for Interframe spacing wait time.
void MlmeScanRequest(MlmeScanRequestParams params) override
IEEE 802.15.4-2011, section 6.2.10.1 MLME-SCAN.request Request primitive used to initiate a channel s...
Ptr< UniformRandomVariable > m_uniformVar
The uniform random variable used in this mac layer.
void PdDataIndication(uint32_t psduLength, Ptr< Packet > p, uint8_t lqi)
IEEE 802.15.4-2006 section 6.2.1.3 PD-DATA.indication Indicates the transfer of an MPDU from PHY to M...