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"
19#include "lr-wpan-mac-trailer.h"
20
21#include "ns3/double.h"
22#include "ns3/log.h"
23#include "ns3/node.h"
24#include "ns3/packet.h"
25#include "ns3/random-variable-stream.h"
26#include "ns3/simulator.h"
27#include "ns3/uinteger.h"
28
29#undef NS_LOG_APPEND_CONTEXT
30#define NS_LOG_APPEND_CONTEXT \
31 std::clog << "[" << m_shortAddress << " | " << m_macExtendedAddress << "] ";
32
33namespace ns3
34{
35namespace lrwpan
36{
37
38NS_LOG_COMPONENT_DEFINE("LrWpanMac");
40
41std::ostream&
42operator<<(std::ostream& os, const MacState& state)
43{
44 switch (state)
45 {
47 os << "MAC IDLE";
48 break;
50 os << "CSMA";
51 break;
53 os << "SENDING";
54 break;
56 os << "ACK PENDING";
57 break;
59 os << "CHANNEL_ACCESS_FAILURE";
60 break;
62 os << "CHANNEL IDLE";
63 break;
65 os << "SET PHY to TX ON";
66 break;
68 os << "MAC GTS PERIOD";
69 break;
71 os << "SUPERFRAME INACTIVE PERIOD";
72 break;
74 os << "CSMA DEFERRED TO NEXT PERIOD";
75 break;
76 }
77 return os;
78}
79
82{
83 static TypeId tid =
84 TypeId("ns3::lrwpan::LrWpanMac")
85 .AddDeprecatedName("ns3::LrWpanMac")
87 .SetGroupName("LrWpan")
88 .AddConstructor<LrWpanMac>()
89 .AddAttribute("PanId",
90 "16-bit identifier of the associated PAN",
94 .AddTraceSource("MacTxEnqueue",
95 "Trace source indicating a packet has been "
96 "enqueued in the transaction queue",
98 "ns3::Packet::TracedCallback")
99 .AddTraceSource("MacTxDequeue",
100 "Trace source indicating a packet has was "
101 "dequeued from the transaction queue",
103 "ns3::Packet::TracedCallback")
104 .AddTraceSource("MacIndTxEnqueue",
105 "Trace source indicating a packet has been "
106 "enqueued in the indirect transaction queue",
108 "ns3::Packet::TracedCallback")
109 .AddTraceSource("MacIndTxDequeue",
110 "Trace source indicating a packet has was "
111 "dequeued from the indirect transaction queue",
113 "ns3::Packet::TracedCallback")
114 .AddTraceSource("MacTx",
115 "Trace source indicating a packet has "
116 "arrived for transmission by this device",
118 "ns3::Packet::TracedCallback")
119 .AddTraceSource("MacTxOk",
120 "Trace source indicating a packet has been "
121 "successfully sent",
123 "ns3::Packet::TracedCallback")
124 .AddTraceSource("MacTxDrop",
125 "Trace source indicating a packet has been "
126 "dropped during transmission",
128 "ns3::Packet::TracedCallback")
129 .AddTraceSource("MacIndTxDrop",
130 "Trace source indicating a packet has been "
131 "dropped from the indirect transaction queue"
132 "(The pending transaction list)",
134 "ns3::Packet::TracedCallback")
135 .AddTraceSource("MacPromiscRx",
136 "A packet has been received by this device, "
137 "has been passed up from the physical layer "
138 "and is being forwarded up the local protocol stack. "
139 "This is a promiscuous trace,",
141 "ns3::Packet::TracedCallback")
142 .AddTraceSource("MacRx",
143 "A packet has been received by this device, "
144 "has been passed up from the physical layer "
145 "and is being forwarded up the local protocol stack. "
146 "This is a non-promiscuous trace,",
148 "ns3::Packet::TracedCallback")
149 .AddTraceSource("MacRxDrop",
150 "Trace source indicating a packet was received, "
151 "but dropped before being forwarded up the stack",
153 "ns3::Packet::TracedCallback")
154 .AddTraceSource("Sniffer",
155 "Trace source simulating a non-promiscuous "
156 "packet sniffer attached to the device",
158 "ns3::Packet::TracedCallback")
159 .AddTraceSource("PromiscSniffer",
160 "Trace source simulating a promiscuous "
161 "packet sniffer attached to the device",
163 "ns3::Packet::TracedCallback")
164 .AddTraceSource("MacStateValue",
165 "The state of LrWpan Mac",
167 "ns3::TracedValueCallback::LrWpanMacState")
168 .AddTraceSource("MacIncSuperframeStatus",
169 "The period status of the incoming superframe",
171 "ns3::TracedValueCallback::SuperframeState")
172 .AddTraceSource("MacOutSuperframeStatus",
173 "The period status of the outgoing superframe",
175 "ns3::TracedValueCallback::SuperframeState")
176 .AddTraceSource("MacState",
177 "The state of LrWpan Mac",
179 "ns3::lrwpan::LrWpanMac::StateTracedCallback")
180 .AddTraceSource("MacSentPkt",
181 "Trace source reporting some information about "
182 "the sent packet",
184 "ns3::lrwpan::LrWpanMac::SentTracedCallback")
185 .AddTraceSource("IfsEnd",
186 "Trace source reporting the end of an "
187 "Interframe space (IFS)",
189 "ns3::Packet::TracedCallback");
190 return tid;
191}
192
194{
195 // First set the state to a known value, call ChangeMacState to fire trace source.
197
199
202
203 m_macRxOnWhenIdle = true;
204 m_macPanId = 0xffff;
206 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
209 m_macPromiscuousMode = false;
213 m_txPkt = nullptr;
214 m_rxPkt = nullptr;
216 m_ifs = 0;
217
218 m_macLIFSPeriod = 40;
219 m_macSIFSPeriod = 12;
220
221 m_panCoor = false;
222 m_coor = false;
223 m_macBeaconOrder = 15;
225 m_macTransactionPersistenceTime = 500; // 0x01F5
227 m_macAutoRequest = true;
228
231 m_beaconTrackingOn = false;
233
237
240
241 m_maxTxQueueSize = m_txQueue.max_size();
243
247 m_shortAddress = Mac16Address("FF:FF"); // FF:FF = The address is not assigned.
248}
249
254
255void
257{
258 NS_LOG_FUNCTION(this);
259
260 m_macDsn = SequenceNumber8(m_uniformVar->GetInteger(0, 255));
261 m_macBsn = SequenceNumber8(m_uniformVar->GetInteger(0, 255));
263 {
264 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
265 }
266 else
267 {
268 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
269 }
270
272}
273
274void
276{
277 NS_LOG_FUNCTION(this);
278
279 if (m_csmaCa)
280 {
281 m_csmaCa->Dispose();
282 m_csmaCa = nullptr;
283 }
284 m_txPkt = nullptr;
285
286 for (uint32_t i = 0; i < m_txQueue.size(); i++)
287 {
288 m_txQueue[i]->txQPkt = nullptr;
289 }
290 m_txQueue.clear();
291
292 for (uint32_t i = 0; i < m_indTxQueue.size(); i++)
293 {
294 m_indTxQueue[i]->txQPkt = nullptr;
295 }
296 m_indTxQueue.clear();
297
298 m_uniformVar = nullptr;
299 m_phy = nullptr;
312
313 m_panDescriptorList.clear();
314 m_energyDetectList.clear();
315 m_unscannedChannels.clear();
316
317 m_scanEvent.Cancel();
318 m_scanEnergyEvent.Cancel();
319 m_scanOrphanEvent.Cancel();
320 m_beaconEvent.Cancel();
322
324}
325
326bool
328{
329 return m_macRxOnWhenIdle;
330}
331
332void
334{
335 NS_LOG_FUNCTION(this << rxOnWhenIdle);
336 m_macRxOnWhenIdle = rxOnWhenIdle;
337
338 if (m_macState == MAC_IDLE)
339 {
341 {
342 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
343 }
344 else
345 {
346 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
347 }
348 }
349}
350
351void
356
357void
362
365{
366 return m_shortAddress;
367}
368
374
375void
377{
378 NS_LOG_FUNCTION(this << p);
379
380 McpsDataConfirmParams confirmParams;
381 confirmParams.m_msduHandle = params.m_msduHandle;
382
383 // TODO: We need a drop trace for the case that the packet is too large or the request
384 // parameters are maleformed.
385 // The current tx drop trace is not suitable, because packets dropped using this trace
386 // carry the mac header and footer, while packets being dropped here do not have them.
387
389 m_macDsn++;
390
392 {
393 // Note, this is just testing maximum theoretical frame size per the spec
394 // The frame could still be too large once headers are put on
395 // in which case the phy will reject it instead
396 NS_LOG_ERROR(this << " packet too big: " << p->GetSize());
397 confirmParams.m_status = MacStatus::FRAME_TOO_LONG;
398 if (!m_mcpsDataConfirmCallback.IsNull())
399 {
400 m_mcpsDataConfirmCallback(confirmParams);
401 }
402 return;
403 }
404
405 if ((params.m_srcAddrMode == NO_PANID_ADDR) && (params.m_dstAddrMode == NO_PANID_ADDR))
406 {
407 NS_LOG_ERROR(this << " Can not send packet with no Address field");
408 confirmParams.m_status = MacStatus::INVALID_ADDRESS;
409 if (!m_mcpsDataConfirmCallback.IsNull())
410 {
411 m_mcpsDataConfirmCallback(confirmParams);
412 }
413 return;
414 }
415 switch (params.m_srcAddrMode)
416 {
417 case NO_PANID_ADDR:
418 macHdr.SetSrcAddrMode(params.m_srcAddrMode);
419 macHdr.SetNoPanIdComp();
420 break;
422 NS_ABORT_MSG("Can not set source address type to ADDR_MODE_RESERVED. Aborting.");
423 break;
424 case SHORT_ADDR:
425 macHdr.SetSrcAddrMode(params.m_srcAddrMode);
427 break;
428 case EXT_ADDR:
429 macHdr.SetSrcAddrMode(params.m_srcAddrMode);
431 break;
432 default:
433 NS_LOG_ERROR(this << " Can not send packet with incorrect Source Address mode = "
434 << params.m_srcAddrMode);
435 confirmParams.m_status = MacStatus::INVALID_ADDRESS;
436 if (!m_mcpsDataConfirmCallback.IsNull())
437 {
438 m_mcpsDataConfirmCallback(confirmParams);
439 }
440 return;
441 }
442 switch (params.m_dstAddrMode)
443 {
444 case NO_PANID_ADDR:
445 macHdr.SetDstAddrMode(params.m_dstAddrMode);
446 macHdr.SetNoPanIdComp();
447 break;
449 NS_ABORT_MSG("Can not set destination address type to ADDR_MODE_RESERVED. Aborting.");
450 break;
451 case SHORT_ADDR:
452 macHdr.SetDstAddrMode(params.m_dstAddrMode);
453 macHdr.SetDstAddrFields(params.m_dstPanId, params.m_dstAddr);
454 break;
455 case EXT_ADDR:
456 macHdr.SetDstAddrMode(params.m_dstAddrMode);
457 macHdr.SetDstAddrFields(params.m_dstPanId, params.m_dstExtAddr);
458 break;
459 default:
460 NS_LOG_ERROR(this << " Can not send packet with incorrect Destination Address mode = "
461 << params.m_dstAddrMode);
462 confirmParams.m_status = MacStatus::INVALID_ADDRESS;
463 if (!m_mcpsDataConfirmCallback.IsNull())
464 {
465 m_mcpsDataConfirmCallback(confirmParams);
466 }
467 return;
468 }
469
470 // IEEE 802.15.4-2006 (7.5.6.1)
471 // Src & Dst PANs are identical, PAN compression is ON
472 // only the dst PAN is serialized making the MAC header 2 bytes smaller
473 if ((params.m_dstAddrMode != NO_PANID_ADDR && params.m_srcAddrMode != NO_PANID_ADDR) &&
474 (macHdr.GetDstPanId() == macHdr.GetSrcPanId()))
475 {
476 macHdr.SetPanIdComp();
477 }
478
479 macHdr.SetSecDisable();
480 // extract the first 3 bits in TxOptions
481 int b0 = params.m_txOptions & TX_OPTION_ACK;
482 int b1 = params.m_txOptions & TX_OPTION_GTS;
483 int b2 = params.m_txOptions & TX_OPTION_INDIRECT;
484
485 if (b0 == TX_OPTION_ACK)
486 {
487 // Set AckReq bit only if the destination is not the broadcast address.
488 if (macHdr.GetDstAddrMode() == SHORT_ADDR)
489 {
490 // short address and ACK requested.
491 Mac16Address shortAddr = macHdr.GetShortDstAddr();
492 if (shortAddr.IsBroadcast() || shortAddr.IsMulticast())
493 {
494 NS_LOG_LOGIC("LrWpanMac::McpsDataRequest: requested an ACK on broadcast or "
495 "multicast destination ("
496 << shortAddr << ") - forcefully removing it.");
497 macHdr.SetNoAckReq();
498 params.m_txOptions &= ~uint8_t(TX_OPTION_ACK);
499 }
500 else
501 {
502 macHdr.SetAckReq();
503 }
504 }
505 else
506 {
507 // other address (not short) and ACK requested
508 macHdr.SetAckReq();
509 }
510 }
511 else
512 {
513 macHdr.SetNoAckReq();
514 }
515
516 if (b1 == TX_OPTION_GTS)
517 {
518 // TODO:GTS Transmission
519 }
520 else if (b2 == TX_OPTION_INDIRECT)
521 {
522 // Indirect Tx
523 // A COORDINATOR will save the packet in the pending queue and await for data
524 // requests from its associated devices. The devices are aware of pending data,
525 // from the pending bit information extracted from the received beacon.
526 // A DEVICE must be tracking beacons (MLME-SYNC.request is running) before attempting
527 // request data from the coordinator.
528
529 // Indirect Transmission can only be done by PAN coordinator or coordinators.
531 p->AddHeader(macHdr);
532
533 LrWpanMacTrailer macTrailer;
534 // Calculate FCS if the global attribute ChecksumEnabled is set.
536 {
537 macTrailer.EnableFcs(true);
538 macTrailer.SetFcs(p);
539 }
540 p->AddTrailer(macTrailer);
541
542 NS_LOG_ERROR(this << " Indirect transmissions not currently supported");
543 // Note: The current Pending transaction list should work for indirect transmissions.
544 // However, this is not tested yet. For now, we block the use of indirect transmissions.
545 // TODO: Save packet in the Pending Transaction list.
546 // EnqueueInd (p);
547 }
548 else
549 {
550 // Direct Tx
551 // From this point the packet will be pushed to a Tx queue and immediately
552 // use a slotted (beacon-enabled) or unslotted (nonbeacon-enabled) version of CSMA/CA
553 // before sending the packet, depending on whether it has previously
554 // received a valid beacon or not.
555
556 p->AddHeader(macHdr);
557
558 LrWpanMacTrailer macTrailer;
559 // Calculate FCS if the global attribute ChecksumEnabled is set.
561 {
562 macTrailer.EnableFcs(true);
563 macTrailer.SetFcs(p);
564 }
565 p->AddTrailer(macTrailer);
566
567 auto txQElement = std::make_shared<TxQueueElement>();
568 txQElement->txQMsduHandle = params.m_msduHandle;
569 txQElement->txQPkt = p;
570 EnqueueTxQElement(txQElement);
571 CheckQueue();
572 }
573}
574
575void
577{
578 NS_LOG_FUNCTION(this);
580
581 MlmeStartConfirmParams confirmParams;
582
583 if (GetShortAddress() == Mac16Address("ff:ff"))
584 {
585 NS_LOG_ERROR(this << " Invalid MAC short address");
587 if (!m_mlmeStartConfirmCallback.IsNull())
588 {
589 m_mlmeStartConfirmCallback(confirmParams);
590 }
591 return;
592 }
593
594 if ((params.m_bcnOrd > 15) || (params.m_sfrmOrd > params.m_bcnOrd))
595 {
597 if (!m_mlmeStartConfirmCallback.IsNull())
598 {
599 m_mlmeStartConfirmCallback(confirmParams);
600 }
601 NS_LOG_ERROR(this << "Incorrect superframe order or beacon order.");
602 return;
603 }
604
605 // Mark primitive as pending and save the start params while the new page and channel is set.
607 m_startParams = params;
608
610 pibAttr->phyCurrentPage = m_startParams.m_logChPage;
611 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
612}
613
614void
616{
617 NS_LOG_FUNCTION(this);
618
619 MlmeScanConfirmParams confirmParams;
620 confirmParams.m_scanType = params.m_scanType;
621 confirmParams.m_chPage = params.m_chPage;
622
623 if ((m_scanEvent.IsPending() || m_scanEnergyEvent.IsPending()) || m_scanOrphanEvent.IsPending())
624 {
625 if (!m_mlmeScanConfirmCallback.IsNull())
626 {
628 m_mlmeScanConfirmCallback(confirmParams);
629 }
630 NS_LOG_ERROR(this << " A channel scan is already in progress");
631 return;
632 }
633
634 if (params.m_scanDuration > 14 || params.m_scanType > MLMESCAN_ORPHAN)
635 {
636 if (!m_mlmeScanConfirmCallback.IsNull())
637 {
639 m_mlmeScanConfirmCallback(confirmParams);
640 }
641 NS_LOG_ERROR(this << "Invalid scan duration or unsupported scan type");
642 return;
643 }
644 // Temporary store macPanId and set macPanId to 0xFFFF to accept all beacons.
646 m_macPanId = 0xFFFF;
647
648 m_panDescriptorList.clear();
649 m_energyDetectList.clear();
650 m_unscannedChannels.clear();
651
652 // TODO: stop beacon transmission
653
654 // Cancel any ongoing CSMA/CA operations and set to unslotted mode for scan
655 m_csmaCa->Cancel();
656 m_capEvent.Cancel();
657 m_cfpEvent.Cancel();
658 m_incCapEvent.Cancel();
659 m_incCfpEvent.Cancel();
660 m_trackingEvent.Cancel();
661 m_csmaCa->SetUnSlottedCsmaCa();
662
664
665 // Mark primitive as pending and save the scan params while the new page and/or channel is set.
666 m_scanParams = params;
668
670 pibAttr->phyCurrentPage = params.m_chPage;
671 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
672}
673
674void
676{
677 NS_LOG_FUNCTION(this);
678
679 // Association is typically preceded by beacon reception and a MLME-SCAN.request, therefore,
680 // the values of the Associate.request params usually come from the information
681 // obtained from those operations.
683 m_associateParams = params;
684 m_ignoreDataCmdAck = false;
685
686 bool invalidRequest = false;
687
688 if (params.m_coordPanId == 0xffff)
689 {
690 invalidRequest = true;
691 }
692
693 if (!invalidRequest && params.m_coordAddrMode == SHORT_ADDR)
694 {
695 if (params.m_coordShortAddr == Mac16Address("ff:ff") ||
696 params.m_coordShortAddr == Mac16Address("ff:fe"))
697 {
698 invalidRequest = true;
699 }
700 }
701 else if (!invalidRequest && params.m_coordAddrMode == EXT_ADDR)
702 {
703 if (params.m_coordExtAddr == Mac64Address("ff:ff:ff:ff:ff:ff:ff:ff") ||
704 params.m_coordExtAddr == Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed"))
705 {
706 invalidRequest = true;
707 }
708 }
709
710 if (invalidRequest)
711 {
714 NS_LOG_ERROR(this << " Invalid PAN id in Association request");
715 if (!m_mlmeAssociateConfirmCallback.IsNull())
716 {
717 MlmeAssociateConfirmParams confirmParams;
718 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
720 m_mlmeAssociateConfirmCallback(confirmParams);
721 }
722 }
723 else
724 {
726 pibAttr->phyCurrentPage = params.m_chPage;
727 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
728 }
729}
730
731void
733{
734 // the primitive is no longer pending (channel & page are set)
736 // As described in IEEE 802.15.4-2011 (Section 5.1.3.1)
737 m_macPanId = m_associateParams.m_coordPanId;
738 if (m_associateParams.m_coordAddrMode == SHORT_ADDR)
739 {
740 m_macCoordShortAddress = m_associateParams.m_coordShortAddr;
741 }
742 else
743 {
746 }
747
749}
750
751void
753{
754 // Associate Short Address (m_assocShortAddr)
755 // FF:FF = Association Request failed
756 // FF:FE = The association request is accepted, but the device should use its extended address
757 // Other = The assigned short address by the coordinator
758
759 NS_LOG_FUNCTION(this);
760
762 m_macDsn++;
763 LrWpanMacTrailer macTrailer;
764 Ptr<Packet> commandPacket = Create<Packet>();
765
766 // Mac header Assoc. Response Comm. See 802.15.4-2011 (Section 5.3.2.1)
769 macHdr.SetPanIdComp();
770 macHdr.SetDstAddrFields(m_macPanId, params.m_extDevAddr);
771 macHdr.SetSrcAddrFields(0xffff, GetExtendedAddress());
772
774 macPayload.SetShortAddr(params.m_assocShortAddr);
775 macPayload.SetAssociationStatus(static_cast<uint8_t>(params.m_status));
776
777 macHdr.SetSecDisable();
778 macHdr.SetAckReq();
779
780 commandPacket->AddHeader(macPayload);
781 commandPacket->AddHeader(macHdr);
782
783 // Calculate FCS if the global attribute ChecksumEnabled is set.
785 {
786 macTrailer.EnableFcs(true);
787 macTrailer.SetFcs(commandPacket);
788 }
789
790 commandPacket->AddTrailer(macTrailer);
791
792 // Save packet in the Pending Transaction list.
793 EnqueueInd(commandPacket);
794}
795
796void
798{
799 NS_LOG_FUNCTION(this);
800 // Mac header Coordinator realigment Command
801 // See 802.15.4-2011 (Section 6.2.7.2)
803 m_macDsn++;
804 LrWpanMacTrailer macTrailer;
805 Ptr<Packet> commandPacket = Create<Packet>();
806 macHdr.SetPanIdComp();
808 macHdr.SetDstAddrFields(0xffff, params.m_orphanAddr);
809
812 macHdr.SetSrcAddrFields(m_macPanId, Mac16Address("FF:FF"));
813
814 macHdr.SetFrameVer(0x01);
815 macHdr.SetSecDisable();
816 macHdr.SetAckReq();
817
819 macPayload.SetPanId(m_macPanId);
821 macPayload.SetChannel(m_phy->GetCurrentChannelNum());
822 macPayload.SetPage(m_phy->GetCurrentPage());
823
824 if (params.m_assocMember)
825 {
826 // The orphan device was associated with the coordinator
827
828 // Either FF:FE for extended address mode
829 // or the short address assigned by the coord.
830 macPayload.SetShortAddr(params.m_shortAddr);
831 }
832 else
833 {
834 // The orphan device was NOT associated with the coordinator
835 macPayload.SetShortAddr(Mac16Address("FF:FF"));
836 }
837
838 commandPacket->AddHeader(macPayload);
839 commandPacket->AddHeader(macHdr);
840
841 // Calculate FCS if the global attribute ChecksumEnabled is set.
843 {
844 macTrailer.EnableFcs(true);
845 macTrailer.SetFcs(commandPacket);
846 }
847
848 commandPacket->AddTrailer(macTrailer);
849
850 auto txQElement = std::make_shared<TxQueueElement>();
851 txQElement->txQPkt = commandPacket;
852 EnqueueTxQElement(txQElement);
853 CheckQueue();
854}
855
856void
858{
859 NS_LOG_FUNCTION(this);
860 NS_ASSERT(params.m_logCh <= 26 && m_macPanId != 0xffff);
861
862 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
863 // change phy current logical channel
865 pibAttr->phyCurrentChannel = params.m_logCh;
866 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
867
868 // Enable Phy receiver
869 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
870
871 uint64_t searchSymbols;
872 Time searchBeaconTime;
873
874 if (m_trackingEvent.IsPending())
875 {
876 m_trackingEvent.Cancel();
877 }
878
879 if (params.m_trackBcn)
880 {
882 // search for a beacon for a time = incomingSuperframe symbols + 960 symbols
883 searchSymbols =
885 searchBeaconTime = Seconds((double)searchSymbols / symbolRate);
886 m_beaconTrackingOn = true;
888 Simulator::Schedule(searchBeaconTime, &LrWpanMac::BeaconSearchTimeout, this);
889 }
890 else
891 {
892 m_beaconTrackingOn = false;
893 }
894}
895
896void
898{
899 NS_LOG_FUNCTION(this);
900
902 m_macBsn++;
903
905
906 Ptr<Packet> beaconPacket = Create<Packet>();
907 // TODO: complete poll request (part of indirect transmissions)
908 NS_FATAL_ERROR(this << " Poll request currently not supported");
909}
910
911void
913{
914 MlmeSetConfirmParams confirmParams;
915 confirmParams.m_status = MacStatus::SUCCESS;
916
917 switch (id)
918 {
920 m_macAssociationPermit = attribute->macAssociationPermit;
921 break;
922 case macBeaconPayload:
923 if (attribute->macBeaconPayload.size() > aMaxBeaconPayloadLength)
924 {
926 }
927 else
928 {
929 m_macBeaconPayload = attribute->macBeaconPayload;
930 }
931 break;
933 if (attribute->macBeaconPayloadLength > aMaxBeaconPayloadLength)
934 {
936 }
937 else
938 {
939 m_macBeaconPayloadLength = attribute->macBeaconPayloadLength;
940 }
941 break;
942 case macShortAddress:
943 m_shortAddress = attribute->macShortAddress;
944 break;
946 confirmParams.m_status = MacStatus::READ_ONLY;
947 break;
948 case macPanId:
950 break;
952 m_macPromiscuousMode = attribute->macPromiscuousMode;
953 break;
954 case macRxOnWhenIdle:
955 m_macRxOnWhenIdle = attribute->macRxOnWhenIdle;
956 break;
957 case pCurrentChannel: {
959 pibAttr->phyCurrentChannel = attribute->pCurrentChannel;
960 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
961 break;
962 }
963 case pCurrentPage: {
965 pibAttr->phyCurrentPage = attribute->pCurrentPage;
966 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentPage, pibAttr);
967 break;
968 }
969 default:
970 // TODO: Add support for setting other attributes
972 break;
973 }
974
975 if (!m_mlmeSetConfirmCallback.IsNull())
976 {
977 confirmParams.id = id;
978 m_mlmeSetConfirmCallback(confirmParams);
979 }
980}
981
982void
984{
987
988 switch (id)
989 {
991 attributes->macAssociationPermit = m_macAssociationPermit;
992 break;
993 case macBeaconPayload:
994 attributes->macBeaconPayload = m_macBeaconPayload;
995 break;
997 attributes->macBeaconPayloadLength = m_macBeaconPayloadLength;
998 break;
1000 attributes->macPromiscuousMode = m_macPromiscuousMode;
1001 break;
1002 case macRxOnWhenIdle:
1003 attributes->macRxOnWhenIdle = m_macRxOnWhenIdle;
1004 break;
1005 case macShortAddress:
1006 attributes->macShortAddress = m_shortAddress;
1007 break;
1008 case macExtendedAddress:
1009 attributes->macExtendedAddress = m_macExtendedAddress;
1010 break;
1011 case macPanId:
1012 attributes->macPanId = m_macPanId;
1013 break;
1014 case pCurrentChannel:
1015 attributes->pCurrentChannel = m_phy->GetCurrentChannelNum();
1016 break;
1017 case pCurrentPage:
1018 attributes->pCurrentPage = m_phy->GetCurrentPage();
1019 break;
1020 default:
1022 break;
1023 }
1024
1025 if (!m_mlmeGetConfirmCallback.IsNull())
1026 {
1027 m_mlmeGetConfirmCallback(status, id, attributes);
1028 }
1029}
1030
1031void
1033 int8_t rssi,
1034 const LrWpanMacHeader& receivedMacHdr,
1035 Ptr<Packet> p)
1036{
1037 NS_LOG_FUNCTION(this);
1038
1039 NS_LOG_DEBUG("promiscuous mode, forwarding up");
1040
1041 // TODO: Fix here, this should trigger different Indication Callbacks
1042 // depending the type of frame received (data,command, beacon)
1043 if (!m_mcpsDataIndicationCallback.IsNull())
1044 {
1046 params.m_dsn = receivedMacHdr.GetSeqNum();
1047 params.m_mpduLinkQuality = lqi;
1048 params.m_srcPanId = receivedMacHdr.GetSrcPanId();
1049 params.m_srcAddrMode = receivedMacHdr.GetSrcAddrMode();
1050 params.m_rssi = rssi;
1051
1052 switch (params.m_srcAddrMode)
1053 {
1054 case SHORT_ADDR:
1055 params.m_srcAddr = receivedMacHdr.GetShortSrcAddr();
1056 break;
1057 case EXT_ADDR:
1058 params.m_srcExtAddr = receivedMacHdr.GetExtSrcAddr();
1059 break;
1060 default:
1061 break;
1062 }
1063
1064 params.m_dstPanId = receivedMacHdr.GetDstPanId();
1065 params.m_dstAddrMode = receivedMacHdr.GetDstAddrMode();
1066
1067 switch (params.m_dstAddrMode)
1068 {
1069 case SHORT_ADDR:
1070 params.m_dstAddr = receivedMacHdr.GetShortDstAddr();
1071 break;
1072 case EXT_ADDR:
1073 params.m_dstExtAddr = receivedMacHdr.GetExtDstAddr();
1074 break;
1075 default:
1076 break;
1077 }
1079 }
1080}
1081
1082void
1084{
1085 NS_LOG_FUNCTION(this);
1087
1088 m_macBsn++;
1089
1090 Ptr<Packet> beaconPacket;
1091 if (m_macBeaconPayload.empty())
1092 {
1093 beaconPacket = Create<Packet>();
1094 }
1095 else
1096 {
1097 // Extract the octets from m_macBeaconPayload and place them in a packet
1098 beaconPacket = Create<Packet>(m_macBeaconPayload.data(), m_macBeaconPayload.size());
1099 }
1100
1103 macHdr.SetDstAddrFields(GetPanId(), Mac16Address("ff:ff"));
1104
1105 // see IEEE 802.15.4-2011 Section 5.1.2.4
1106 if (GetShortAddress() == Mac16Address("ff:fe"))
1107 {
1110 }
1111 else
1112 {
1115 }
1116
1117 macHdr.SetSecDisable();
1118 macHdr.SetNoAckReq();
1119
1120 BeaconPayloadHeader macPayload;
1122 macPayload.SetGtsFields(GetGtsFields());
1124
1125 beaconPacket->AddHeader(macPayload);
1126 beaconPacket->AddHeader(macHdr);
1127
1128 // Calculate FCS if the global attribute ChecksumEnabled is set.
1129 LrWpanMacTrailer macTrailer;
1131 {
1132 macTrailer.EnableFcs(true);
1133 macTrailer.SetFcs(beaconPacket);
1134 }
1135
1136 beaconPacket->AddTrailer(macTrailer);
1137
1138 if (m_csmaCa->IsSlottedCsmaCa())
1139 {
1140 // Beacon in beacon-enabled mode
1141 // Transmit beacon immediately (i.e. Without CSMA/CA)
1142 m_txPkt = beaconPacket;
1144 NS_LOG_DEBUG("Outgoing superframe Active Portion (Beacon + CAP + CFP): "
1145 << m_superframeDuration << " symbols");
1146
1148 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TX_ON);
1149 }
1150 else
1151 {
1152 // Beacon as a result of a beacon request
1153 // The beacon shall be transmitted using CSMA/CA
1154 // IEEE 802.15.4-2011 (Section 5.1.2.1.2)
1155 auto txQElement = std::make_shared<TxQueueElement>();
1156 txQElement->txQPkt = beaconPacket;
1157 EnqueueTxQElement(txQElement);
1158 CheckQueue();
1159 }
1160}
1161
1162void
1164{
1165 NS_LOG_FUNCTION(this);
1166
1168 m_macDsn++;
1169 LrWpanMacTrailer macTrailer;
1170 Ptr<Packet> commandPacket = Create<Packet>();
1171
1172 // Beacon Request Command Mac header values See IEEE 802.15.4-2011 (Section 5.3.7)
1173 macHdr.SetNoPanIdComp();
1176
1177 // Not associated PAN, broadcast dst address
1178 macHdr.SetDstAddrFields(0xFFFF, Mac16Address("FF:FF"));
1179
1180 macHdr.SetSecDisable();
1181 macHdr.SetNoAckReq();
1182
1183 CommandPayloadHeader macPayload;
1185
1186 commandPacket->AddHeader(macPayload);
1187 commandPacket->AddHeader(macHdr);
1188
1189 // Calculate FCS if the global attribute ChecksumEnabled is set.
1191 {
1192 macTrailer.EnableFcs(true);
1193 macTrailer.SetFcs(commandPacket);
1194 }
1195
1196 commandPacket->AddTrailer(macTrailer);
1197
1198 auto txQElement = std::make_shared<TxQueueElement>();
1199 txQElement->txQPkt = commandPacket;
1200 EnqueueTxQElement(txQElement);
1201 CheckQueue();
1202}
1203
1204void
1206{
1208 m_macDsn++;
1209 LrWpanMacTrailer macTrailer;
1210 Ptr<Packet> commandPacket = Create<Packet>();
1211
1212 // See IEEE 802.15.4-2011 (5.3.6)
1213 macHdr.SetPanIdComp();
1214
1216 macHdr.SetSrcAddrFields(0xFFFF, GetExtendedAddress());
1217
1219 macHdr.SetDstAddrFields(0xFFFF, Mac16Address("FF:FF"));
1220
1221 macHdr.SetSecDisable();
1222 macHdr.SetNoAckReq();
1223
1224 CommandPayloadHeader macPayload;
1226
1227 commandPacket->AddHeader(macPayload);
1228 commandPacket->AddHeader(macHdr);
1229
1230 // Calculate FCS if the global attribute ChecksumEnabled is set.
1232 {
1233 macTrailer.EnableFcs(true);
1234 macTrailer.SetFcs(commandPacket);
1235 }
1236
1237 commandPacket->AddTrailer(macTrailer);
1238
1239 auto txQElement = std::make_shared<TxQueueElement>();
1240 txQElement->txQPkt = commandPacket;
1241 EnqueueTxQElement(txQElement);
1242 CheckQueue();
1243}
1244
1245void
1247{
1248 NS_LOG_FUNCTION(this);
1249
1251 m_macDsn++;
1252 LrWpanMacTrailer macTrailer;
1253 Ptr<Packet> commandPacket = Create<Packet>();
1254
1255 // Assoc. Req. Comm. Mac header values See IEEE 802.15.4-2011 (Section 5.3.1.1)
1257 macHdr.SetSrcAddrFields(0xffff, GetExtendedAddress());
1258
1259 if (m_associateParams.m_coordAddrMode == SHORT_ADDR)
1260 {
1262 macHdr.SetDstAddrFields(m_associateParams.m_coordPanId, m_associateParams.m_coordShortAddr);
1263 }
1264 else
1265 {
1267 macHdr.SetDstAddrFields(m_associateParams.m_coordPanId, m_associateParams.m_coordExtAddr);
1268 }
1269
1270 macHdr.SetSecDisable();
1271 macHdr.SetAckReq();
1272
1274 macPayload.SetCapabilityField(m_associateParams.m_capabilityInfo);
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 auto txQElement = std::make_shared<TxQueueElement>();
1289 txQElement->txQPkt = commandPacket;
1290 EnqueueTxQElement(txQElement);
1291 CheckQueue();
1292}
1293
1294void
1296{
1297 // See IEEE 802.15.4-2011 (Section 5.3.5)
1298 // This command can be sent for 3 different situations:
1299 // a) In response to a beacon indicating that there is data for the device.
1300 // b) Triggered by MLME-POLL.request.
1301 // c) To follow an ACK of an Association Request command and continue the associate process.
1302
1303 // TODO: Implementation of a) and b) will be done when Indirect transmissions are fully
1304 // supported.
1305 // for now, only case c) is considered.
1306
1307 NS_LOG_FUNCTION(this);
1308
1310 m_macDsn++;
1311 LrWpanMacTrailer macTrailer;
1312 Ptr<Packet> commandPacket = Create<Packet>();
1313
1314 // Mac Header values (Section 5.3.5)
1316 macHdr.SetSrcAddrFields(0xffff, m_macExtendedAddress);
1317
1318 if (m_macCoordShortAddress == Mac16Address("ff:fe"))
1319 {
1322 }
1323 else
1324 {
1327 }
1328
1329 macHdr.SetSecDisable();
1330 macHdr.SetAckReq();
1331
1333
1334 commandPacket->AddHeader(macPayload);
1335 commandPacket->AddHeader(macHdr);
1336
1337 // Calculate FCS if the global attribute ChecksumEnabled is set.
1339 {
1340 macTrailer.EnableFcs(true);
1341 macTrailer.SetFcs(commandPacket);
1342 }
1343
1344 commandPacket->AddTrailer(macTrailer);
1345
1346 // Set the Command packet to be transmitted
1347 auto txQElement = std::make_shared<TxQueueElement>();
1348 txQElement->txQPkt = commandPacket;
1349 EnqueueTxQElement(txQElement);
1350 CheckQueue();
1351}
1352
1353void
1355{
1356 LrWpanMacHeader receivedMacHdr;
1357 rxDataReqPkt->RemoveHeader(receivedMacHdr);
1358 CommandPayloadHeader receivedMacPayload;
1359 rxDataReqPkt->RemoveHeader(receivedMacPayload);
1360
1362
1363 auto indTxQElement = std::make_shared<IndTxQueueElement>();
1364 bool elementFound;
1365 elementFound = DequeueInd(receivedMacHdr.GetExtSrcAddr(), indTxQElement);
1366 if (elementFound)
1367 {
1368 auto txQElement = std::make_shared<TxQueueElement>();
1369 txQElement->txQPkt = indTxQElement->txQPkt;
1370 m_txQueue.emplace_back(txQElement);
1371 }
1372 else
1373 {
1374 NS_LOG_DEBUG("Requested element not found in pending list");
1375 }
1376}
1377
1378void
1380{
1381 // Association response command was not received, return to default values.
1382 m_macPanId = 0xffff;
1384 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
1385
1386 if (!m_mlmeAssociateConfirmCallback.IsNull())
1387 {
1388 MlmeAssociateConfirmParams confirmParams;
1389 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
1390 confirmParams.m_status = MacStatus::NO_DATA;
1391 m_mlmeAssociateConfirmCallback(confirmParams);
1392 }
1393}
1394
1395void
1397{
1398 NS_LOG_FUNCTION(this);
1399 // The primitive is no longer pending (Channel & Page have been set)
1401
1402 if (m_startParams.m_coorRealgn) // Coordinator Realignment
1403 {
1404 // TODO: Send realignment request command frame in CSMA/CA
1405 NS_LOG_ERROR(this << " Coordinator realignment request not supported");
1406 return;
1407 }
1408 else
1409 {
1410 if (m_startParams.m_panCoor)
1411 {
1412 m_panCoor = true;
1413 }
1414
1415 m_coor = true;
1416 m_macPanId = m_startParams.m_PanId;
1417
1418 NS_ASSERT(m_startParams.m_PanId != 0xffff);
1419
1421 if (m_macBeaconOrder == 15)
1422 {
1423 // Non-beacon enabled PAN
1424 // Cancel any ongoing events and CSMA-CA process
1426 m_fnlCapSlot = 15;
1427 m_beaconInterval = 0;
1428
1429 m_csmaCa->Cancel();
1430 m_capEvent.Cancel();
1431 m_cfpEvent.Cancel();
1432 m_incCapEvent.Cancel();
1433 m_incCfpEvent.Cancel();
1434 m_trackingEvent.Cancel();
1435 m_scanEvent.Cancel();
1436 m_scanOrphanEvent.Cancel();
1437 m_scanEnergyEvent.Cancel();
1438
1439 m_csmaCa->SetUnSlottedCsmaCa();
1440
1441 if (!m_mlmeStartConfirmCallback.IsNull())
1442 {
1443 MlmeStartConfirmParams confirmParams;
1444 confirmParams.m_status = MacStatus::SUCCESS;
1445 m_mlmeStartConfirmCallback(confirmParams);
1446 }
1447
1448 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
1449 }
1450 else
1451 {
1453 m_csmaCa->SetBatteryLifeExtension(m_startParams.m_battLifeExt);
1454
1455 m_csmaCa->SetSlottedCsmaCa();
1456
1457 // TODO: Calculate the real Final CAP slot (requires GTS implementation)
1458 // FinalCapSlot = Superframe duration slots - CFP slots.
1459 // In the current implementation the value of the final cap slot is equal to
1460 // the total number of possible slots in the superframe (15).
1461 m_fnlCapSlot = 15;
1462
1465 m_superframeDuration = (static_cast<uint32_t>(1 << m_macSuperframeOrder)) *
1467
1468 // TODO: change the beacon sending according to the startTime parameter (if not PAN
1469 // coordinator)
1470
1472 }
1473 }
1474}
1475
1476void
1478{
1479 NS_LOG_FUNCTION(this);
1480
1482
1483 bool channelFound = false;
1484
1485 for (int i = m_channelScanIndex; i <= 26; i++)
1486 {
1487 if ((m_scanParams.m_scanChannels & (1 << m_channelScanIndex)) != 0)
1488 {
1489 channelFound = true;
1490 break;
1491 }
1493 }
1494
1495 if (channelFound)
1496 {
1497 // Switch to the next channel in the list and restart scan
1499 pibAttr->phyCurrentChannel = m_channelScanIndex;
1500 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
1501 }
1502 else
1503 {
1504 // All channels in the list scan completed.
1505 // Return variables to the values before the scan and return the status to the next layer.
1507 m_macPanIdScan = 0;
1508
1509 // TODO: restart beacon transmissions that were active before the beginning of the scan
1510 // (i.e when a coordinator perform a scan and it was already transmitting beacons)
1511 MlmeScanConfirmParams confirmParams;
1512 confirmParams.m_chPage = m_scanParams.m_chPage;
1513 confirmParams.m_scanType = m_scanParams.m_scanType;
1514 confirmParams.m_energyDetList = {};
1515 confirmParams.m_unscannedCh = m_unscannedChannels;
1516 confirmParams.m_resultListSize = m_panDescriptorList.size();
1517
1518 // See IEEE 802.15.4-2011, Table 31 (panDescriptorList value on macAutoRequest)
1519 // and Section 6.2.10.2
1520 switch (confirmParams.m_scanType)
1521 {
1522 case MLMESCAN_PASSIVE:
1523 if (m_macAutoRequest)
1524 {
1525 confirmParams.m_panDescList = m_panDescriptorList;
1526 }
1527 confirmParams.m_status = MacStatus::SUCCESS;
1528 break;
1529 case MLMESCAN_ACTIVE:
1530 if (m_panDescriptorList.empty())
1531 {
1532 confirmParams.m_status = MacStatus::NO_BEACON;
1533 }
1534 else
1535 {
1536 if (m_macAutoRequest)
1537 {
1538 confirmParams.m_panDescList = m_panDescriptorList;
1539 }
1540 confirmParams.m_status = MacStatus::SUCCESS;
1541 }
1542 break;
1543 case MLMESCAN_ORPHAN:
1544 confirmParams.m_panDescList = {};
1545 confirmParams.m_status = MacStatus::NO_BEACON;
1546 confirmParams.m_resultListSize = 0;
1547 // The device lost track of the coordinator and was unable
1548 // to locate it, disassociate from the network.
1549 m_macPanId = 0xffff;
1550 m_shortAddress = Mac16Address("FF:FF");
1552 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
1553 break;
1554 default:
1555 NS_LOG_ERROR(this << " Invalid scan type");
1556 }
1557
1560 m_scanParams = {};
1561
1562 if (!m_mlmeScanConfirmCallback.IsNull())
1563 {
1564 m_mlmeScanConfirmCallback(confirmParams);
1565 }
1566 }
1567}
1568
1569void
1571{
1572 NS_LOG_FUNCTION(this);
1573 // Add the results of channel energy scan to the detectList
1575 m_maxEnergyLevel = 0;
1576
1578
1579 bool channelFound = false;
1580 for (int i = m_channelScanIndex; i <= 26; i++)
1581 {
1582 if ((m_scanParams.m_scanChannels & (1 << m_channelScanIndex)) != 0)
1583 {
1584 channelFound = true;
1585 break;
1586 }
1588 }
1589
1590 if (channelFound)
1591 {
1592 // switch to the next channel in the list and restart scan
1594 pibAttr->phyCurrentChannel = m_channelScanIndex;
1595 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
1596 }
1597 else
1598 {
1599 // Scan on all channels on the list completed
1600 // Return to the MAC values previous to start of the first scan.
1602 m_macPanIdScan = 0;
1603
1604 // TODO: restart beacon transmissions that were active before the beginning of the scan
1605 // (i.e when a coordinator perform a scan and it was already transmitting beacons)
1606
1607 // All channels scanned, report success
1608 MlmeScanConfirmParams confirmParams;
1609 confirmParams.m_status = MacStatus::SUCCESS;
1610 confirmParams.m_chPage = m_phy->GetCurrentPage();
1611 confirmParams.m_scanType = m_scanParams.m_scanType;
1612 confirmParams.m_energyDetList = m_energyDetectList;
1613 confirmParams.m_resultListSize = m_energyDetectList.size();
1614
1617 m_scanParams = {};
1618
1619 if (!m_mlmeScanConfirmCallback.IsNull())
1620 {
1621 m_mlmeScanConfirmCallback(confirmParams);
1622 }
1623 }
1624}
1625
1626void
1628{
1629 uint32_t activeSlot;
1630 uint64_t capDuration;
1631 Time endCapTime;
1632 uint64_t symbolRate;
1633
1634 symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1635
1636 if (superframeType == OUTGOING)
1637 {
1639 activeSlot = m_superframeDuration / 16;
1640 capDuration = activeSlot * (m_fnlCapSlot + 1);
1641 endCapTime = Seconds((double)capDuration / symbolRate);
1642 // Obtain the end of the CAP by adjust the time it took to send the beacon
1643 endCapTime -= (Simulator::Now() - m_macBeaconTxTime);
1644
1645 NS_LOG_DEBUG("Outgoing superframe CAP duration " << (endCapTime.GetSeconds() * symbolRate)
1646 << " symbols (" << endCapTime.As(Time::S)
1647 << ")");
1648 NS_LOG_DEBUG("Active Slots duration " << activeSlot << " symbols");
1649
1650 m_capEvent =
1652 }
1653 else
1654 {
1656 activeSlot = m_incomingSuperframeDuration / 16;
1657 capDuration = activeSlot * (m_incomingFnlCapSlot + 1);
1658 endCapTime = Seconds((double)capDuration / symbolRate);
1659 // Obtain the end of the CAP by adjust the time it took to receive the beacon
1660 endCapTime -= (Simulator::Now() - m_macBeaconRxTime);
1661
1662 NS_LOG_DEBUG("Incoming superframe CAP duration " << (endCapTime.GetSeconds() * symbolRate)
1663 << " symbols (" << endCapTime.As(Time::S)
1664 << ")");
1665 NS_LOG_DEBUG("Active Slots duration " << activeSlot << " symbols");
1666
1667 m_capEvent =
1669 }
1670
1671 CheckQueue();
1672}
1673
1674void
1676{
1677 uint32_t activeSlot;
1678 uint64_t cfpDuration;
1679 Time endCfpTime;
1680 uint64_t symbolRate;
1681
1682 symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1683
1684 if (superframeType == INCOMING)
1685 {
1686 activeSlot = m_incomingSuperframeDuration / 16;
1687 cfpDuration = activeSlot * (15 - m_incomingFnlCapSlot);
1688 endCfpTime = Seconds((double)cfpDuration / symbolRate);
1689 if (cfpDuration > 0)
1690 {
1692 }
1693
1694 NS_LOG_DEBUG("Incoming superframe CFP duration " << cfpDuration << " symbols ("
1695 << endCfpTime.As(Time::S) << ")");
1696
1699 this,
1701 }
1702 else
1703 {
1704 activeSlot = m_superframeDuration / 16;
1705 cfpDuration = activeSlot * (15 - m_fnlCapSlot);
1706 endCfpTime = Seconds((double)cfpDuration / symbolRate);
1707
1708 if (cfpDuration > 0)
1709 {
1711 }
1712
1713 NS_LOG_DEBUG("Outgoing superframe CFP duration " << cfpDuration << " symbols ("
1714 << endCfpTime.As(Time::S) << ")");
1715
1716 m_cfpEvent = Simulator::Schedule(endCfpTime,
1718 this,
1720 }
1721 // TODO: Start transmit or receive GTS here.
1722}
1723
1724void
1726{
1727 uint64_t inactiveDuration;
1728 Time endInactiveTime;
1729 uint64_t symbolRate;
1730
1731 symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1732
1733 if (superframeType == INCOMING)
1734 {
1736 endInactiveTime = Seconds((double)inactiveDuration / symbolRate);
1737
1738 if (inactiveDuration > 0)
1739 {
1741 }
1742
1743 NS_LOG_DEBUG("Incoming superframe Inactive Portion duration "
1744 << inactiveDuration << " symbols (" << endInactiveTime.As(Time::S) << ")");
1745 m_beaconEvent = Simulator::Schedule(endInactiveTime, &LrWpanMac::AwaitBeacon, this);
1746 }
1747 else
1748 {
1749 inactiveDuration = m_beaconInterval - m_superframeDuration;
1750 endInactiveTime = Seconds((double)inactiveDuration / symbolRate);
1751
1752 if (inactiveDuration > 0)
1753 {
1755 }
1756
1757 NS_LOG_DEBUG("Outgoing superframe Inactive Portion duration "
1758 << inactiveDuration << " symbols (" << endInactiveTime.As(Time::S) << ")");
1760 }
1761}
1762
1763void
1765{
1767
1768 // TODO: If the device waits more than the expected time to receive the beacon (wait = 46
1769 // symbols for default beacon size)
1770 // it should continue with the start of the incoming CAP even if it did not receive the
1771 // beacon. At the moment, the start of the incoming CAP is only triggered if the beacon is
1772 // received. See MLME-SyncLoss for details.
1773}
1774
1775void
1777{
1778 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1779
1781 {
1782 MlmeSyncLossIndicationParams syncLossParams;
1783 // syncLossParams.m_logCh =
1784 syncLossParams.m_lossReason = MacStatus::BEACON_LOSS;
1785 syncLossParams.m_panId = m_macPanId;
1786 m_mlmeSyncLossIndicationCallback(syncLossParams);
1787
1788 m_beaconTrackingOn = false;
1789 m_numLostBeacons = 0;
1790 }
1791 else
1792 {
1794
1795 // Search for one more beacon
1796 uint64_t searchSymbols;
1797 Time searchBeaconTime;
1798 searchSymbols =
1800 searchBeaconTime = Seconds((double)searchSymbols / symbolRate);
1802 Simulator::Schedule(searchBeaconTime, &LrWpanMac::BeaconSearchTimeout, this);
1803 }
1804}
1805
1806void
1807LrWpanMac::ReceiveBeacon(uint8_t lqi, const LrWpanMacHeader& receivedMacHdr, Ptr<Packet> p)
1808{
1809 NS_LOG_FUNCTION(this << lqi << p);
1810 // The received beacon size in symbols
1811 // Beacon = Sync Header (SHR)[5 bytes] +
1812 // PHY header (PHR) [1 byte] +
1813 // PSDU (MAC header + beacon payload) [default 17 bytes]
1814 m_rxBeaconSymbols = m_phy->GetPhySHRDuration() + 1 * m_phy->GetPhySymbolsPerOctet() +
1815 (p->GetSize() * m_phy->GetPhySymbolsPerOctet());
1816
1817 // The start of Rx beacon time and start of the Incoming superframe Active Period
1818 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
1819 m_macBeaconRxTime = Simulator::Now() - Seconds(double(m_rxBeaconSymbols) / symbolRate);
1820
1821 NS_LOG_DEBUG("Beacon Received; forwarding up (m_macBeaconRxTime: "
1822 << m_macBeaconRxTime.As(Time::S) << ")");
1823
1824 // Strip the Beacon Payload
1825 BeaconPayloadHeader receivedMacPayload;
1826 p->RemoveHeader(receivedMacPayload);
1827
1828 // Fill the PAN descriptor
1829 PanDescriptor panDescriptor;
1830
1831 if (receivedMacHdr.GetSrcAddrMode() == SHORT_ADDR)
1832 {
1833 panDescriptor.m_coorAddrMode = SHORT_ADDR;
1834 panDescriptor.m_coorShortAddr = receivedMacHdr.GetShortSrcAddr();
1835 }
1836 else
1837 {
1838 panDescriptor.m_coorAddrMode = EXT_ADDR;
1839 panDescriptor.m_coorExtAddr = receivedMacHdr.GetExtSrcAddr();
1840 }
1841
1842 panDescriptor.m_coorPanId = receivedMacHdr.GetSrcPanId();
1843 panDescriptor.m_gtsPermit = receivedMacPayload.GetGtsFields().GetGtsPermit();
1844 panDescriptor.m_linkQuality = lqi;
1845 panDescriptor.m_logChPage = m_phy->GetCurrentPage();
1846 panDescriptor.m_logCh = m_phy->GetCurrentChannelNum();
1847 panDescriptor.m_superframeSpec = receivedMacPayload.GetSuperframeSpecField();
1848 panDescriptor.m_timeStamp = m_macBeaconRxTime;
1849
1850 // Process beacon when device belongs to a PAN (associated device)
1851 if (!m_scanEvent.IsPending() && m_macPanId == receivedMacHdr.GetDstPanId())
1852 {
1853 // We need to make sure to cancel any possible ongoing unslotted CSMA/CA
1854 // operations when receiving a beacon (e.g. Those taking place at the
1855 // beginning of an Association).
1856 m_csmaCa->Cancel();
1857
1858 SuperframeField incomingSuperframe(receivedMacPayload.GetSuperframeSpecField());
1859
1860 m_incomingBeaconOrder = incomingSuperframe.GetBeaconOrder();
1861 m_incomingSuperframeOrder = incomingSuperframe.GetFrameOrder();
1862 m_incomingFnlCapSlot = incomingSuperframe.GetFinalCapSlot();
1863
1864 if (m_incomingBeaconOrder < 15)
1865 {
1866 // Start Beacon-enabled mode
1867 m_csmaCa->SetSlottedCsmaCa();
1871 (static_cast<uint32_t>(1 << m_incomingSuperframeOrder));
1872
1873 if (incomingSuperframe.IsBattLifeExt())
1874 {
1875 m_csmaCa->SetBatteryLifeExtension(true);
1876 }
1877 else
1878 {
1879 m_csmaCa->SetBatteryLifeExtension(false);
1880 }
1881
1882 // TODO: get Incoming frame GTS Fields here
1883
1884 // Begin CAP on the current device using info from
1885 // the Incoming superframe
1886 NS_LOG_DEBUG("Incoming superframe Active Portion "
1887 << "(Beacon + CAP + CFP): " << m_incomingSuperframeDuration << " symbols");
1888
1891 }
1892 else
1893 {
1894 // Start non-beacon enabled mode
1895 m_csmaCa->SetUnSlottedCsmaCa();
1896 }
1897
1899 }
1900 else if (!m_scanEvent.IsPending() && m_macPanId == 0xFFFF)
1901 {
1902 NS_LOG_DEBUG(this << " Device not associated, cannot process beacon");
1903 }
1904
1905 if (m_macAutoRequest)
1906 {
1907 if (p->GetSize() > 0)
1908 {
1910 {
1911 // The beacon contains payload, send the beacon notification.
1913 beaconParams.m_bsn = receivedMacHdr.GetSeqNum();
1914 beaconParams.m_panDescriptor = panDescriptor;
1915 beaconParams.m_sduLength = p->GetSize();
1916 beaconParams.m_sdu = p;
1918 }
1919 }
1920
1921 if (m_scanEvent.IsPending())
1922 {
1923 // Channel scanning is taking place, save only unique PAN descriptors
1924 bool descriptorExists = false;
1925
1926 for (const auto& descriptor : m_panDescriptorList)
1927 {
1928 if (descriptor.m_coorAddrMode == SHORT_ADDR)
1929 {
1930 // Found a coordinator in PAN descriptor list with the same
1931 // registered short address
1932 descriptorExists =
1933 (descriptor.m_coorShortAddr == panDescriptor.m_coorShortAddr &&
1934 descriptor.m_coorPanId == panDescriptor.m_coorPanId);
1935 }
1936 else
1937 {
1938 // Found a coordinator in PAN descriptor list with the same
1939 // registered extended address
1940 descriptorExists = (descriptor.m_coorExtAddr == panDescriptor.m_coorExtAddr &&
1941 descriptor.m_coorPanId == panDescriptor.m_coorPanId);
1942 }
1943
1944 if (descriptorExists)
1945 {
1946 break;
1947 }
1948 }
1949
1950 if (!descriptorExists)
1951 {
1952 m_panDescriptorList.emplace_back(panDescriptor);
1953 }
1954 return;
1955 }
1956 else if (m_trackingEvent.IsPending())
1957 {
1958 // check if MLME-SYNC.request was previously issued and running
1959 // Sync. is necessary to handle pending messages (indirect
1960 // transmissions)
1961 m_trackingEvent.Cancel();
1962 m_numLostBeacons = 0;
1963
1965 {
1966 // if tracking option is on keep tracking the next beacon
1967 uint64_t searchSymbols;
1968 Time searchBeaconTime;
1969
1970 searchSymbols = (static_cast<uint64_t>(1 << m_incomingBeaconOrder)) +
1972 searchBeaconTime = Seconds(static_cast<double>(searchSymbols / symbolRate));
1974 Simulator::Schedule(searchBeaconTime, &LrWpanMac::BeaconSearchTimeout, this);
1975 }
1976
1977 PendingAddrFields pndAddrFields;
1978 pndAddrFields = receivedMacPayload.GetPndAddrFields();
1979
1980 // TODO: Ignore pending data, and do not send data command request if
1981 // the address is in the GTS list.
1982 // If the address is not in the GTS list, then check if the
1983 // address is in the short address pending list or in the extended
1984 // address pending list and send a data command request.
1985 }
1986 }
1987 else
1988 {
1989 // m_macAutoRequest is FALSE
1990 // Data command request are not send, only the beacon notification.
1991 // see IEEE 802.15.4-2011 Section 6.2.4.1
1993 {
1995 beaconParams.m_bsn = receivedMacHdr.GetSeqNum();
1996 beaconParams.m_panDescriptor = panDescriptor;
1997 beaconParams.m_sduLength = p->GetSize();
1998 beaconParams.m_sdu = p;
2000 }
2001 }
2002}
2003
2004void
2005LrWpanMac::ReceiveCommand(uint8_t lqi, const LrWpanMacHeader& receivedMacHdr, Ptr<Packet> p)
2006{
2007 NS_LOG_FUNCTION(this << lqi << p);
2008
2009 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
2010
2011 CommandPayloadHeader receivedMacPayload;
2012 p->RemoveHeader(receivedMacPayload);
2013
2014 switch (receivedMacPayload.GetCommandFrameType())
2015 {
2017 if (m_csmaCa->IsUnSlottedCsmaCa() && m_coor)
2018 {
2019 // Jitter = Between 0 and 2 aUnitBackoffPeriods
2020 // (0, 320us or 640us in 2.4Ghz O-QPSK)
2021 // While this jitter is not described by the standard,
2022 // it reduces the probability of collisions in beacons
2023 // transmitted as a result of a beacon request
2024 Time jitter =
2025 Seconds(static_cast<double>(m_uniformVar->GetInteger(0, 3) * aUnitBackoffPeriod) /
2026 symbolRate);
2027
2029 }
2030 else
2031 {
2032 NS_LOG_DEBUG("Beacon Request command received in beacon mode: Ignore");
2033 }
2034 break;
2036 if (m_coor)
2037 {
2038 if (!m_mlmeOrphanIndicationCallback.IsNull())
2039 {
2040 MlmeOrphanIndicationParams orphanParams;
2041 orphanParams.m_orphanAddr = receivedMacHdr.GetExtSrcAddr();
2042 m_mlmeOrphanIndicationCallback(orphanParams);
2043 }
2044 }
2045 break;
2047 if (m_scanOrphanEvent.IsPending())
2048 {
2049 // Coordinator located, no need to keep scanning other channels
2050 m_scanOrphanEvent.Cancel();
2051
2052 m_macPanIdScan = 0;
2055
2056 // Update the device information with the received information
2057 // from the Coordinator Realigment command.
2058 m_macPanId = receivedMacPayload.GetPanId();
2059 m_shortAddress = receivedMacPayload.GetShortAddr();
2060 m_macCoordExtendedAddress = receivedMacHdr.GetExtSrcAddr();
2061 m_macCoordShortAddress = receivedMacPayload.GetCoordShortAddr();
2062
2063 if (!m_mlmeScanConfirmCallback.IsNull())
2064 {
2065 MlmeScanConfirmParams confirmParams;
2066 confirmParams.m_scanType = m_scanParams.m_scanType;
2067 confirmParams.m_chPage = m_scanParams.m_chPage;
2068 confirmParams.m_status = MacStatus::SUCCESS;
2069 m_mlmeScanConfirmCallback(confirmParams);
2070 }
2071 m_scanParams = {};
2072 }
2073 // TODO: handle Coordinator realignment when not
2074 // used during an orphan scan.
2075 break;
2076 default:
2077 break;
2078 }
2079}
2080
2081void
2083 int8_t rssi,
2084 const LrWpanMacHeader& receivedMacHdr,
2085 Ptr<Packet> p)
2086{
2087 NS_LOG_FUNCTION(this << lqi << p);
2088
2089 NS_LOG_DEBUG("Data Packet is for me; forwarding up");
2090
2091 if (!m_mcpsDataIndicationCallback.IsNull())
2092 {
2094 params.m_dsn = receivedMacHdr.GetSeqNum();
2095 params.m_mpduLinkQuality = lqi;
2096 params.m_srcPanId = receivedMacHdr.GetSrcPanId();
2097 params.m_srcAddrMode = receivedMacHdr.GetSrcAddrMode();
2098 params.m_rssi = rssi;
2099
2100 switch (params.m_srcAddrMode)
2101 {
2102 case SHORT_ADDR:
2103 params.m_srcAddr = receivedMacHdr.GetShortSrcAddr();
2104 break;
2105 case EXT_ADDR:
2106 params.m_srcExtAddr = receivedMacHdr.GetExtSrcAddr();
2107 break;
2108 default:
2109 break;
2110 }
2111
2112 params.m_dstPanId = receivedMacHdr.GetDstPanId();
2113 params.m_dstAddrMode = receivedMacHdr.GetDstAddrMode();
2114
2115 switch (params.m_dstAddrMode)
2116 {
2117 case SHORT_ADDR:
2118 params.m_dstAddr = receivedMacHdr.GetShortDstAddr();
2119 break;
2120 case EXT_ADDR:
2121 params.m_dstExtAddr = receivedMacHdr.GetExtDstAddr();
2122 break;
2123 default:
2124 break;
2125 }
2126
2128 }
2129}
2130
2131void
2133{
2134 NS_LOG_FUNCTION(this << p);
2135
2136 // Make a copy of the original transmitted packet that required ACK and
2137 // extract its MAC header.
2138 Ptr<Packet> txPkt = m_txPkt->Copy();
2139 LrWpanMacHeader txMacHdr;
2140 txPkt->RemoveHeader(txMacHdr);
2141
2142 // If it is an ACK with an unexpected sequence number, mark the current
2143 // transmission as failed and start a retransmit. (cf 7.5.6.4.3)
2144 if (receivedMacHdr.GetSeqNum() != txMacHdr.GetSeqNum())
2145 {
2146 m_ackWaitTimeout.Cancel();
2147 if (!PrepareRetransmission())
2148 {
2149 m_setMacState.Cancel();
2151 }
2152 else
2153 {
2154 m_setMacState.Cancel();
2156 }
2157
2158 return;
2159 }
2160
2161 // If it is an ACK with the expected sequence number, finish the transmission
2162 m_ackWaitTimeout.Cancel();
2164
2165 // TODO: check if the IFS is the correct size after ACK.
2166 double symbolRate = m_phy->GetDataOrSymbolRate(false);
2167 Time ifsWaitTime = Seconds((double)GetIfsSize() / symbolRate);
2168
2169 if (txMacHdr.IsCommand())
2170 {
2171 // We received an ACK to a command, we need to take actions depending on the
2172 // transmitted command.
2173
2174 // Extract the command payload of the originally transmitted packet to know
2175 // what command we transmitted.
2176 CommandPayloadHeader txCmdPayload;
2177 txPkt->RemoveHeader(txCmdPayload);
2178
2179 switch (txCmdPayload.GetCommandFrameType())
2180 {
2182 Time waitTime = Seconds(static_cast<double>(m_macResponseWaitTime) / symbolRate);
2183 if (!m_beaconTrackingOn)
2184 {
2187 }
2188 else
2189 {
2190 // TODO: The data must be extracted by the coordinator within
2191 // macResponseWaitTime on timeout, MLME-ASSOCIATE.confirm is set
2192 // with status NO_DATA, and this should trigger the cancellation
2193 // of the beacon tracking (MLME-SYNC.request trackBeacon
2194 // =FALSE)
2195 }
2196 break;
2197 }
2198
2200 // MLME-comm-status.Indication generated as a result of an
2201 // association response command, therefore src and dst address use
2202 // extended mode (see 5.3.2.1)
2204 {
2205 MlmeCommStatusIndicationParams commStatusParams;
2206 commStatusParams.m_panId = m_macPanId;
2207 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2208 commStatusParams.m_srcExtAddr = txMacHdr.GetExtSrcAddr();
2209 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2210 commStatusParams.m_dstExtAddr = txMacHdr.GetExtDstAddr();
2211 commStatusParams.m_status = MacStatus::SUCCESS;
2212 m_mlmeCommStatusIndicationCallback(commStatusParams);
2213 }
2214 // Remove element from Pending Transaction List
2216 break;
2217 }
2218
2220 if (!m_ignoreDataCmdAck)
2221 {
2222 // Schedule an event in case the Association Response Command
2223 // never reached this device during an association process.
2224 Time waitTime = Seconds(static_cast<double>(m_assocRespCmdWaitTime) / symbolRate);
2227 }
2228
2229 if (!m_mlmePollConfirmCallback.IsNull())
2230 {
2231 MlmePollConfirmParams pollConfirmParams;
2232 pollConfirmParams.m_status = MacStatus::SUCCESS;
2233 m_mlmePollConfirmCallback(pollConfirmParams);
2234 }
2235 break;
2236 }
2237
2239 // ACK of coordinator realigment commands is not specified in the
2240 // standard, in here, we assume they are required as in other
2241 // commands.
2243 {
2244 MlmeCommStatusIndicationParams commStatusParams;
2245 commStatusParams.m_panId = m_macPanId;
2246 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2247 commStatusParams.m_srcExtAddr = txMacHdr.GetExtSrcAddr();
2248 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2249 commStatusParams.m_dstExtAddr = txMacHdr.GetExtDstAddr();
2250 commStatusParams.m_status = MacStatus::SUCCESS;
2251 m_mlmeCommStatusIndicationCallback(commStatusParams);
2252 }
2253 break;
2254 }
2255
2256 default: {
2257 // TODO: add response to other request commands (e.g. Orphan)
2258 break;
2259 }
2260 }
2261 }
2262 else
2263 {
2264 // Receive ACK to data packet
2265 if (!m_mcpsDataConfirmCallback.IsNull())
2266 {
2267 std::shared_ptr<TxQueueElement> txQElement = m_txQueue.front();
2268 McpsDataConfirmParams confirmParams;
2269 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
2270 confirmParams.m_status = MacStatus::SUCCESS;
2271 m_mcpsDataConfirmCallback(confirmParams);
2272 }
2273 }
2274
2275 // Ack was successfully received, wait for the Interframe Space (IFS) and
2276 // then proceed
2278 m_setMacState.Cancel();
2280 m_ifsEvent = Simulator::Schedule(ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this, ifsWaitTime);
2281}
2282
2283void
2285{
2286 if (receivedMacHdr.GetSrcAddrMode() == SHORT_ADDR &&
2287 receivedMacHdr.GetDstAddrMode() == SHORT_ADDR)
2288 {
2289 NS_LOG_DEBUG("Packet from [" << receivedMacHdr.GetShortSrcAddr() << "] to ["
2290 << receivedMacHdr.GetShortDstAddr() << "]");
2291 }
2292 else if (receivedMacHdr.GetSrcAddrMode() == EXT_ADDR &&
2293 receivedMacHdr.GetDstAddrMode() == EXT_ADDR)
2294 {
2295 NS_LOG_DEBUG("Packet from [" << receivedMacHdr.GetExtSrcAddr() << "] to ["
2296 << receivedMacHdr.GetExtDstAddr() << "]");
2297 }
2298 else if (receivedMacHdr.GetSrcAddrMode() == SHORT_ADDR &&
2299 receivedMacHdr.GetDstAddrMode() == EXT_ADDR)
2300 {
2301 NS_LOG_DEBUG("Packet from [" << receivedMacHdr.GetShortSrcAddr() << "] to ["
2302 << receivedMacHdr.GetExtDstAddr() << "]");
2303 }
2304 else if (receivedMacHdr.GetSrcAddrMode() == EXT_ADDR &&
2305 receivedMacHdr.GetDstAddrMode() == SHORT_ADDR)
2306 {
2307 NS_LOG_DEBUG("Packet from [" << receivedMacHdr.GetExtSrcAddr() << "] to ["
2308 << receivedMacHdr.GetShortDstAddr() << "]");
2309 }
2310}
2311
2312void
2314{
2315 NS_LOG_FUNCTION(this);
2316 // Pull a packet from the queue and start sending if we are not already sending.
2317 if (m_macState == MAC_IDLE && !m_txQueue.empty() && !m_setMacState.IsPending())
2318 {
2319 if (m_csmaCa->IsUnSlottedCsmaCa() || (m_outSuperframeStatus == CAP && m_coor) ||
2321 {
2322 // check MAC is not in a IFS
2323 if (!m_ifsEvent.IsPending())
2324 {
2325 std::shared_ptr<TxQueueElement> txQElement = m_txQueue.front();
2326 m_txPkt = txQElement->txQPkt;
2327
2330 }
2331 }
2332 }
2333}
2334
2335uint16_t
2337{
2338 SuperframeField sfrmSpec;
2339
2342 sfrmSpec.SetFinalCapSlot(m_fnlCapSlot);
2343
2344 if (m_csmaCa->GetBatteryLifeExtension())
2345 {
2346 sfrmSpec.SetBattLifeExt(true);
2347 }
2348
2349 if (m_panCoor)
2350 {
2351 sfrmSpec.SetPanCoor(true);
2352 }
2353
2354 // used to associate devices via Beacons
2356 {
2357 sfrmSpec.SetAssocPermit(true);
2358 }
2359
2360 return sfrmSpec.GetSuperframe();
2361}
2362
2365{
2366 GtsFields gtsFields;
2367
2368 // TODO: Logic to populate the GTS Fields from local information here
2369
2370 return gtsFields;
2371}
2372
2375{
2376 PendingAddrFields pndAddrFields;
2377
2378 // TODO: Logic to populate the Pending Address Fields from local information here
2379 return pndAddrFields;
2380}
2381
2382void
2384{
2385 m_csmaCa = csmaCa;
2386}
2387
2388void
2390{
2391 m_phy = phy;
2392}
2393
2396{
2397 return m_phy;
2398}
2399
2400void
2402{
2404 NS_LOG_FUNCTION(this << psduLength << p << (uint16_t)lqi);
2405
2406 Ptr<Packet> originalPkt = p->Copy();
2407
2408 // If active, pass the complete packet to the traces
2409 if (!m_promiscSnifferTrace.IsEmpty())
2410 {
2411 m_promiscSnifferTrace(p->Copy());
2412 }
2413 else if (!m_macPromiscRxTrace.IsEmpty())
2414 {
2415 m_macPromiscRxTrace(p->Copy());
2416 }
2417
2418 // Extract the MAC trailer
2419 LrWpanMacTrailer receivedMacTrailer;
2420 p->RemoveTrailer(receivedMacTrailer);
2421
2422 // Extract the MAC Header from the packet
2423 LrWpanMacHeader receivedMacHdr;
2424 p->RemoveHeader(receivedMacHdr);
2425
2427 {
2428 receivedMacTrailer.EnableFcs(true);
2429 }
2430
2431 // From section 7.5.6.2 Reception and rejection, IEEE 802.15.4-2006
2432 // - Level 1 filtering: Test FCS field and reject if frame fails.
2433 // - Level 2 filtering: If promiscuous mode pass frame to higher layer
2434 // otherwise perform Level 3 filtering.
2435 // - Level 3 filtering: Accept frame if Frame type and version is not reserved, and if
2436 // there is a dstPanId then dstPanId=m_macPanId or broadcastPanId, and if there is a
2437 // shortDstAddr then shortDstAddr=shortMacAddr or broadcastAddr, and if beacon frame then
2438 // srcPanId = m_macPanId if only srcAddr field in Data or Command frame,accept frame if
2439 // srcPanId=m_macPanId.
2440
2441 // Level 1 filtering
2442 if (!receivedMacTrailer.CheckFcs(p))
2443 {
2444 m_macRxDropTrace(originalPkt);
2445 return;
2446 }
2447
2448 // Level 2 filtering
2450 {
2451 PrintReceivedPacket(receivedMacHdr);
2452 ReceiveInPromiscuousMode(lqi, rssi, receivedMacHdr, p);
2453 return;
2454 }
2455
2456 // Level 3 frame filtering
2457 bool acceptFrame;
2458 acceptFrame = (receivedMacHdr.GetType() != LrWpanMacHeader::LRWPAN_MAC_RESERVED);
2459
2460 if (acceptFrame)
2461 {
2462 acceptFrame = (receivedMacHdr.GetFrameVer() <= 1);
2463 }
2464
2465 if (acceptFrame && (receivedMacHdr.GetDstAddrMode() > 1))
2466 {
2467 // Accept frame if one of the following is true:
2468
2469 // 1) Have the same macPanId
2470 // 2) Is Message to all PANs
2471 // 3) Is a beacon or command frame and the macPanId is not present (bootstrap)
2472 acceptFrame = ((receivedMacHdr.GetDstPanId() == m_macPanId ||
2473 receivedMacHdr.GetDstPanId() == 0xffff) ||
2474 (m_macPanId == 0xffff && receivedMacHdr.IsBeacon())) ||
2475 (m_macPanId == 0xffff && receivedMacHdr.IsCommand());
2476 }
2477
2478 if (acceptFrame && (receivedMacHdr.GetDstAddrMode() == SHORT_ADDR))
2479 {
2480 if (receivedMacHdr.GetShortDstAddr() == m_shortAddress)
2481 {
2482 // unicast, for me
2483 acceptFrame = true;
2484 }
2485 else if (receivedMacHdr.GetShortDstAddr().IsBroadcast() ||
2486 receivedMacHdr.GetShortDstAddr().IsMulticast())
2487 {
2488 // Broadcast or multicast.
2489 // Discard broadcast/multicast with the ACK bit set.
2490 acceptFrame = !receivedMacHdr.IsAckReq();
2491 }
2492 else
2493 {
2494 acceptFrame = false;
2495 }
2496 }
2497
2498 if (acceptFrame && (receivedMacHdr.GetDstAddrMode() == EXT_ADDR))
2499 {
2500 acceptFrame = (receivedMacHdr.GetExtDstAddr() == m_macExtendedAddress);
2501 }
2502
2503 if (acceptFrame && m_scanEvent.IsPending())
2504 {
2505 if (!receivedMacHdr.IsBeacon())
2506 {
2507 acceptFrame = false;
2508 }
2509 }
2510 else if (acceptFrame && m_scanOrphanEvent.IsPending())
2511 {
2512 if (!receivedMacHdr.IsCommand())
2513 {
2514 acceptFrame = false;
2515 }
2516 }
2517 else if (m_scanEnergyEvent.IsPending())
2518 {
2519 // Reject any frames if energy scan is running
2520 acceptFrame = false;
2521 }
2522
2523 // Check device is panCoor with association permit when receiving Association Request
2524 // Commands.
2525 if (acceptFrame && (receivedMacHdr.IsCommand() && receivedMacHdr.IsAckReq()))
2526 {
2527 CommandPayloadHeader receivedMacPayload;
2528 p->PeekHeader(receivedMacPayload);
2529
2530 if (receivedMacPayload.GetCommandFrameType() == CommandPayloadHeader::ASSOCIATION_REQ &&
2532 {
2533 acceptFrame = false;
2534 }
2535
2536 // Although ACKs do not use CSMA to to be transmitted, we need to make sure
2537 // that the transmitted ACK will not collide with the transmission of a beacon
2538 // when beacon-enabled mode is running in the coordinator.
2539 if (acceptFrame && (m_csmaCa->IsSlottedCsmaCa() && m_capEvent.IsPending()))
2540 {
2541 Time timeLeftInCap = Simulator::GetDelayLeft(m_capEvent);
2542 uint64_t ackSymbols = lrwpan::aTurnaroundTime + m_phy->GetPhySHRDuration() +
2543 ceil(6 * m_phy->GetPhySymbolsPerOctet());
2544 auto symbolRate = m_phy->GetDataOrSymbolRate(false); // symbols per second
2545 Time ackTime = Seconds((double)ackSymbols / symbolRate);
2546
2547 if (ackTime >= timeLeftInCap)
2548 {
2549 NS_LOG_DEBUG("Command frame received but not enough time to transmit ACK "
2550 "before the end of CAP ");
2551 acceptFrame = false;
2552 }
2553 }
2554 }
2555
2556 if (!acceptFrame)
2557 {
2558 m_macRxDropTrace(originalPkt);
2559 return;
2560 }
2561
2562 m_macRxTrace(originalPkt);
2563 // \todo: What should we do if we receive a frame while waiting for an ACK?
2564 // Especially if this frame has the ACK request bit set, should we reply with
2565 // an ACK, possibly missing the pending ACK?
2566
2567 // If the received frame is a frame with the ACK request bit set, we immediately
2568 // send back an ACK. If we are currently waiting for a pending ACK, we assume the
2569 // ACK was lost and trigger a retransmission after sending the ACK.
2570 if ((receivedMacHdr.IsData() || receivedMacHdr.IsCommand()) && receivedMacHdr.IsAckReq() &&
2571 !(receivedMacHdr.GetDstAddrMode() == SHORT_ADDR &&
2572 (receivedMacHdr.GetShortDstAddr().IsBroadcast() ||
2573 receivedMacHdr.GetShortDstAddr().IsMulticast())))
2574 {
2575 // If this is a data or mac command frame, which is not a broadcast or
2576 // multicast, with ack req set, generate and send an ack frame. If there is a
2577 // CSMA medium access in progress we cancel the medium access for sending the
2578 // ACK frame. A new transmission attempt will be started after the ACK was send.
2580 {
2581 m_ackWaitTimeout.Cancel();
2583 }
2584 else if (m_macState == MAC_CSMA)
2585 {
2586 // \todo: If we receive a packet while doing CSMA/CA, should we drop the
2587 // packet because of channel busy,
2588 // or should we restart CSMA/CA for the packet after sending the ACK?
2589 // Currently we simply restart CSMA/CA after sending the ACK.
2590 NS_LOG_DEBUG("Received a packet with ACK required while in CSMA. Cancel "
2591 "current CSMA-CA");
2592 m_csmaCa->Cancel();
2593 }
2594 // Cancel any pending MAC state change, ACKs have higher priority.
2595 m_setMacState.Cancel();
2597
2598 // save received packet and LQI to process the appropriate indication/response
2599 // after sending ACK (PD-DATA.confirm)
2600 m_rxPkt = originalPkt;
2601 m_lastRxFrameLqi = lqi;
2602
2603 // LOG Commands with ACK required.
2604 CommandPayloadHeader receivedMacPayload;
2605 p->PeekHeader(receivedMacPayload);
2606 switch (receivedMacPayload.GetCommandFrameType())
2607 {
2609 NS_LOG_DEBUG("Data Request Command Received; processing ACK");
2610 break;
2612 NS_LOG_DEBUG("Association Request Command Received; processing ACK");
2613 break;
2615 if (m_assocResCmdWaitTimeout.IsPending())
2616 {
2617 m_assocResCmdWaitTimeout.Cancel(); // cancel event to a lost assoc resp cmd.
2618 NS_LOG_DEBUG("Association Response Command Received; processing ACK");
2619 }
2620 else
2621 {
2622 // Association response command was received before (or never received)
2623 // a Data request command ACK. This is an extreme case and it is
2624 // essentially caused by saturation in the network.
2625 // We turn a flag ON to not react once
2626 // we finally receive the Data request command ACK. This behavior is not
2627 // standard, but necessary to address this flaw in design of the
2628 // original association process.
2629 m_ignoreDataCmdAck = true;
2630 NS_LOG_DEBUG("Assoc. Resp Cmd received before Data Req. Cmd. in "
2631 "Association request");
2632 }
2633 break;
2634 }
2635 default:
2636 break;
2637 }
2638
2640 Simulator::ScheduleNow(&LrWpanMac::SendAck, this, receivedMacHdr.GetSeqNum());
2641 }
2642
2643 PrintReceivedPacket(receivedMacHdr);
2644
2645 if (receivedMacHdr.IsBeacon())
2646 {
2647 ReceiveBeacon(lqi, receivedMacHdr, p);
2648 }
2649 else if (receivedMacHdr.IsCommand())
2650 {
2651 ReceiveCommand(lqi, receivedMacHdr, p);
2652 }
2653 else if (receivedMacHdr.IsData())
2654 {
2655 ReceiveData(lqi, rssi, receivedMacHdr, p);
2656 }
2657 else if (receivedMacHdr.IsAcknowledgment() && m_txPkt && m_macState == MAC_ACK_PENDING)
2658 {
2659 ReceiveAcknowledgment(receivedMacHdr, p);
2660 }
2661}
2662
2663void
2665{
2666 NS_LOG_FUNCTION(this << static_cast<uint32_t>(seqno));
2667
2669
2670 // Generate a corresponding ACK Frame.
2672 LrWpanMacTrailer macTrailer;
2673 Ptr<Packet> ackPacket = Create<Packet>(0);
2674 ackPacket->AddHeader(macHdr);
2675 // Calculate FCS if the global attribute ChecksumEnabled is set.
2677 {
2678 macTrailer.EnableFcs(true);
2679 macTrailer.SetFcs(ackPacket);
2680 }
2681 ackPacket->AddTrailer(macTrailer);
2682
2683 // Enqueue the ACK packet for further processing
2684 // when the transmitter is activated.
2685 m_txPkt = ackPacket;
2686
2687 // Switch transceiver to TX mode. Proceed sending the Ack on confirm.
2689 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TX_ON);
2690}
2691
2692void
2693LrWpanMac::EnqueueTxQElement(std::shared_ptr<TxQueueElement> txQElement)
2694{
2695 if (m_txQueue.size() < m_maxTxQueueSize)
2696 {
2697 m_txQueue.emplace_back(txQElement);
2698 m_macTxEnqueueTrace(txQElement->txQPkt);
2699 }
2700 else
2701 {
2702 if (!m_mcpsDataConfirmCallback.IsNull())
2703 {
2704 McpsDataConfirmParams confirmParams;
2705 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
2707 m_mcpsDataConfirmCallback(confirmParams);
2708 }
2709 NS_LOG_DEBUG("TX Queue with size " << m_txQueue.size() << " is full, dropping packet");
2710 m_macTxDropTrace(txQElement->txQPkt);
2711 }
2712}
2713
2714void
2716{
2717 std::shared_ptr<TxQueueElement> txQElement = m_txQueue.front();
2718 Ptr<const Packet> p = txQElement->txQPkt;
2719 m_numCsmacaRetry += m_csmaCa->GetNB() + 1;
2720
2721 Ptr<Packet> pkt = p->Copy();
2722 LrWpanMacHeader hdr;
2723 pkt->RemoveHeader(hdr);
2724 if (!hdr.GetShortDstAddr().IsBroadcast() && !hdr.GetShortDstAddr().IsMulticast())
2725 {
2727 }
2728
2729 txQElement->txQPkt = nullptr;
2730 txQElement = nullptr;
2731 m_txQueue.pop_front();
2732 m_txPkt = nullptr;
2733 m_retransmission = 0;
2734 m_numCsmacaRetry = 0;
2736}
2737
2738void
2740{
2741 NS_LOG_FUNCTION(this);
2742
2743 // TODO: If we are a PAN coordinator and this was an indirect transmission,
2744 // we will not initiate a retransmission. Instead we wait for the data
2745 // being extracted after a new data request command.
2746 if (!PrepareRetransmission())
2747 {
2749 }
2750 else
2751 {
2753 }
2754}
2755
2756void
2758{
2759 auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false);
2760 Time lifsTime = Seconds((double)m_macLIFSPeriod / symbolRate);
2761 Time sifsTime = Seconds((double)m_macSIFSPeriod / symbolRate);
2762
2763 if (ifsTime == lifsTime)
2764 {
2765 NS_LOG_DEBUG("LIFS of " << m_macLIFSPeriod << " symbols (" << ifsTime.As(Time::S)
2766 << ") completed ");
2767 }
2768 else if (ifsTime == sifsTime)
2769 {
2770 NS_LOG_DEBUG("SIFS of " << m_macSIFSPeriod << " symbols (" << ifsTime.As(Time::S)
2771 << ") completed ");
2772 }
2773 else
2774 {
2775 NS_LOG_DEBUG("Unknown IFS size (" << ifsTime.As(Time::S) << ") completed ");
2776 }
2777
2778 m_macIfsEndTrace(ifsTime);
2779 CheckQueue();
2780}
2781
2782bool
2784{
2785 NS_LOG_FUNCTION(this);
2786
2787 // Max retransmissions reached without receiving ACK,
2788 // send the proper indication/confirmation
2789 // according to the frame type and call drop trace.
2791 {
2792 LrWpanMacHeader peekedMacHdr;
2793 m_txPkt->PeekHeader(peekedMacHdr);
2794
2795 if (peekedMacHdr.IsCommand())
2796 {
2798
2799 Ptr<Packet> pkt = m_txPkt->Copy();
2800 LrWpanMacHeader macHdr;
2801 CommandPayloadHeader cmdPayload;
2802 pkt->RemoveHeader(macHdr);
2803 pkt->RemoveHeader(cmdPayload);
2804
2805 switch (cmdPayload.GetCommandFrameType())
2806 {
2808 m_macPanId = 0xffff;
2810 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
2811 m_incCapEvent.Cancel();
2812 m_incCfpEvent.Cancel();
2813 m_csmaCa->SetUnSlottedCsmaCa();
2816
2817 if (!m_mlmeAssociateConfirmCallback.IsNull())
2818 {
2819 MlmeAssociateConfirmParams confirmParams;
2820 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
2821 confirmParams.m_status = MacStatus::NO_ACK;
2822 m_mlmeAssociateConfirmCallback(confirmParams);
2823 }
2824 break;
2825 }
2827 // IEEE 802.15.4-2006 (Section 7.1.3.3.3 and 7.1.8.2.3)
2829 {
2830 MlmeCommStatusIndicationParams commStatusParams;
2831 commStatusParams.m_panId = m_macPanId;
2832 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2833 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
2834 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2835 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
2836 commStatusParams.m_status = MacStatus::NO_ACK;
2837 m_mlmeCommStatusIndicationCallback(commStatusParams);
2838 }
2840 break;
2841 }
2843 // IEEE 802.15.4-2006 (Section 7.1.16.1.3)
2844 m_macPanId = 0xffff;
2846 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
2847 m_incCapEvent.Cancel();
2848 m_incCfpEvent.Cancel();
2849 m_csmaCa->SetUnSlottedCsmaCa();
2852
2853 if (!m_mlmePollConfirmCallback.IsNull())
2854 {
2855 MlmePollConfirmParams pollConfirmParams;
2856 pollConfirmParams.m_status = MacStatus::NO_ACK;
2857 m_mlmePollConfirmCallback(pollConfirmParams);
2858 }
2859 break;
2860 }
2861 default: {
2862 // TODO: Specify other indications according to other commands
2863 break;
2864 }
2865 }
2866 }
2867 else
2868 {
2869 // Maximum number of retransmissions has been reached.
2870 // remove the copy of the DATA packet that was just sent
2871 std::shared_ptr<TxQueueElement> txQElement = m_txQueue.front();
2872 m_macTxDropTrace(txQElement->txQPkt);
2873 if (!m_mcpsDataConfirmCallback.IsNull())
2874 {
2875 McpsDataConfirmParams confirmParams;
2876 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
2877 confirmParams.m_status = MacStatus::NO_ACK;
2878 m_mcpsDataConfirmCallback(confirmParams);
2879 }
2880 }
2881
2883 return false;
2884 }
2885 else
2886 {
2888 m_numCsmacaRetry += m_csmaCa->GetNB() + 1;
2889 // Start next CCA process for this packet.
2890 return true;
2891 }
2892}
2893
2894void
2896{
2897 auto indTxQElement = std::make_shared<IndTxQueueElement>();
2898 LrWpanMacHeader peekedMacHdr;
2899 p->PeekHeader(peekedMacHdr);
2900
2901 PurgeInd();
2902
2903 NS_ASSERT(peekedMacHdr.GetDstAddrMode() == SHORT_ADDR ||
2904 peekedMacHdr.GetDstAddrMode() == EXT_ADDR);
2905
2906 if (peekedMacHdr.GetDstAddrMode() == SHORT_ADDR)
2907 {
2908 indTxQElement->dstShortAddress = peekedMacHdr.GetShortDstAddr();
2909 }
2910 else
2911 {
2912 indTxQElement->dstExtAddress = peekedMacHdr.GetExtDstAddr();
2913 }
2914
2915 indTxQElement->seqNum = peekedMacHdr.GetSeqNum();
2916
2917 // See IEEE 802.15.4-2006, Table 86
2918 uint32_t unit = 0; // The persistence time in symbols
2919 if (m_macBeaconOrder == 15)
2920 {
2921 // Non-beacon enabled mode
2923 }
2924 else
2925 {
2926 // Beacon-enabled mode
2927 unit = ((static_cast<uint32_t>(1) << m_macBeaconOrder) * lrwpan::aBaseSuperframeDuration) *
2929 }
2930
2931 if (m_indTxQueue.size() < m_maxIndTxQueueSize)
2932 {
2933 double symbolRate = m_phy->GetDataOrSymbolRate(false);
2934 Time expireTime = Seconds(unit / symbolRate);
2935 expireTime += Simulator::Now();
2936 indTxQElement->expireTime = expireTime;
2937 indTxQElement->txQPkt = p;
2938 m_indTxQueue.emplace_back(indTxQElement);
2940 }
2941 else
2942 {
2944 {
2945 LrWpanMacHeader peekedMacHdr;
2946 indTxQElement->txQPkt->PeekHeader(peekedMacHdr);
2947 MlmeCommStatusIndicationParams commStatusParams;
2948 commStatusParams.m_panId = m_macPanId;
2949 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2950 commStatusParams.m_srcExtAddr = peekedMacHdr.GetExtSrcAddr();
2951 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2952 commStatusParams.m_dstExtAddr = peekedMacHdr.GetExtDstAddr();
2953 commStatusParams.m_status = MacStatus::TRANSACTION_OVERFLOW;
2954 m_mlmeCommStatusIndicationCallback(commStatusParams);
2955 }
2957 }
2958}
2959
2960bool
2961LrWpanMac::DequeueInd(Mac64Address dst, std::shared_ptr<IndTxQueueElement> entry)
2962{
2963 PurgeInd();
2964
2965 for (auto iter = m_indTxQueue.begin(); iter != m_indTxQueue.end(); iter++)
2966 {
2967 if ((*iter)->dstExtAddress == dst)
2968 {
2969 *entry = **iter;
2970 m_macIndTxDequeueTrace((*iter)->txQPkt->Copy());
2971 m_indTxQueue.erase(iter);
2972 return true;
2973 }
2974 }
2975 return false;
2976}
2977
2978void
2980{
2981 for (uint32_t i = 0; i < m_indTxQueue.size();)
2982 {
2983 if (Simulator::Now() > m_indTxQueue[i]->expireTime)
2984 {
2985 // Transaction expired, remove and send proper confirmation/indication to a higher layer
2986 LrWpanMacHeader peekedMacHdr;
2987 m_indTxQueue[i]->txQPkt->PeekHeader(peekedMacHdr);
2988
2989 if (peekedMacHdr.IsCommand())
2990 {
2991 // IEEE 802.15.4-2006 (Section 7.1.3.3.3)
2993 {
2994 MlmeCommStatusIndicationParams commStatusParams;
2995 commStatusParams.m_panId = m_macPanId;
2996 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
2997 commStatusParams.m_srcExtAddr = peekedMacHdr.GetExtSrcAddr();
2998 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
2999 commStatusParams.m_dstExtAddr = peekedMacHdr.GetExtDstAddr();
3000 commStatusParams.m_status = MacStatus::TRANSACTION_EXPIRED;
3001 m_mlmeCommStatusIndicationCallback(commStatusParams);
3002 }
3003 }
3004 else if (peekedMacHdr.IsData())
3005 {
3006 // IEEE 802.15.4-2006 (Section 7.1.1.1.3)
3007 if (!m_mcpsDataConfirmCallback.IsNull())
3008 {
3009 McpsDataConfirmParams confParams;
3011 m_mcpsDataConfirmCallback(confParams);
3012 }
3013 }
3014 m_macIndTxDropTrace(m_indTxQueue[i]->txQPkt->Copy());
3015 m_indTxQueue.erase(m_indTxQueue.begin() + i);
3016 }
3017 else
3018 {
3019 i++;
3020 }
3021 }
3022}
3023
3024void
3025LrWpanMac::PrintPendingTxQueue(std::ostream& os) const
3026{
3027 LrWpanMacHeader peekedMacHdr;
3028
3029 os << "Pending Transaction List [" << GetShortAddress() << " | " << GetExtendedAddress()
3030 << "] | CurrentTime: " << Simulator::Now().As(Time::S) << "\n"
3031 << " Destination |"
3032 << " Sequence Number |"
3033 << " Frame type |"
3034 << " Expire time\n";
3035
3036 for (const auto& transaction : m_indTxQueue)
3037 {
3038 transaction->txQPkt->PeekHeader(peekedMacHdr);
3039 os << transaction->dstExtAddress << " "
3040 << static_cast<uint32_t>(transaction->seqNum) << " ";
3041
3042 if (peekedMacHdr.IsCommand())
3043 {
3044 os << " Command Frame ";
3045 }
3046 else if (peekedMacHdr.IsData())
3047 {
3048 os << " Data Frame ";
3049 }
3050 else
3051 {
3052 os << " Unknown Frame ";
3053 }
3054
3055 os << transaction->expireTime.As(Time::S) << "\n";
3056 }
3057}
3058
3059void
3060LrWpanMac::PrintTxQueue(std::ostream& os) const
3061{
3062 LrWpanMacHeader peekedMacHdr;
3063
3064 os << "\nTx Queue [" << GetShortAddress() << " | " << GetExtendedAddress()
3065 << "] | CurrentTime: " << Simulator::Now().As(Time::S) << "\n"
3066 << " Destination |"
3067 << " Sequence Number |"
3068 << " Dst PAN id |"
3069 << " Frame type |\n";
3070
3071 for (const auto& transaction : m_txQueue)
3072 {
3073 transaction->txQPkt->PeekHeader(peekedMacHdr);
3074
3075 os << "[" << peekedMacHdr.GetShortDstAddr() << "]"
3076 << ", [" << peekedMacHdr.GetExtDstAddr() << "] "
3077 << static_cast<uint32_t>(peekedMacHdr.GetSeqNum()) << " "
3078 << peekedMacHdr.GetDstPanId() << " ";
3079
3080 if (peekedMacHdr.IsCommand())
3081 {
3082 os << " Command Frame ";
3083 }
3084 else if (peekedMacHdr.IsData())
3085 {
3086 os << " Data Frame ";
3087 }
3088 else
3089 {
3090 os << " Unknown Frame ";
3091 }
3092
3093 os << "\n";
3094 }
3095 os << "\n";
3096}
3097
3098int64_t
3100{
3101 NS_LOG_FUNCTION(this);
3102 m_uniformVar->SetStream(stream);
3103 m_csmaCa->AssignStreams(stream + 1);
3104 return 2;
3105}
3106
3107void
3109{
3110 LrWpanMacHeader peekedMacHdr;
3111 p->PeekHeader(peekedMacHdr);
3112
3113 for (auto it = m_indTxQueue.begin(); it != m_indTxQueue.end(); it++)
3114 {
3115 if (peekedMacHdr.GetDstAddrMode() == EXT_ADDR)
3116 {
3117 if (((*it)->dstExtAddress == peekedMacHdr.GetExtDstAddr()) &&
3118 ((*it)->seqNum == peekedMacHdr.GetSeqNum()))
3119 {
3121 m_indTxQueue.erase(it);
3122 break;
3123 }
3124 }
3125 else if (peekedMacHdr.GetDstAddrMode() == SHORT_ADDR)
3126 {
3127 if (((*it)->dstShortAddress == peekedMacHdr.GetShortDstAddr()) &&
3128 ((*it)->seqNum == peekedMacHdr.GetSeqNum()))
3129 {
3131 m_indTxQueue.erase(it);
3132 break;
3133 }
3134 }
3135 }
3136
3137 p = nullptr;
3138}
3139
3140void
3142{
3144 NS_LOG_FUNCTION(this << status << m_txQueue.size());
3145
3146 LrWpanMacHeader macHdr;
3147 Time ifsWaitTime;
3148 double symbolRate;
3149
3150 symbolRate = m_phy->GetDataOrSymbolRate(false); // symbols per second
3151
3152 m_txPkt->PeekHeader(macHdr);
3153
3154 if (status == IEEE_802_15_4_PHY_SUCCESS)
3155 {
3156 if (!macHdr.IsAcknowledgment())
3157 {
3158 if (macHdr.IsBeacon())
3159 {
3160 // Start CAP only if we are in beacon mode (i.e. if slotted csma-ca is running)
3161 if (m_csmaCa->IsSlottedCsmaCa())
3162 {
3163 // The Tx Beacon in symbols
3164 // Beacon = 5 bytes Sync Header (SHR) + 1 byte PHY header (PHR) + PSDU (default
3165 // 17 bytes)
3166 uint64_t beaconSymbols = m_phy->GetPhySHRDuration() +
3167 1 * m_phy->GetPhySymbolsPerOctet() +
3168 (m_txPkt->GetSize() * m_phy->GetPhySymbolsPerOctet());
3169
3170 // The beacon Tx time and start of the Outgoing superframe Active Period
3172 Simulator::Now() - Seconds(static_cast<double>(beaconSymbols) / symbolRate);
3173
3175 this,
3177 NS_LOG_DEBUG("Beacon Sent (m_macBeaconTxTime: " << m_macBeaconTxTime.As(Time::S)
3178 << ")");
3179
3180 if (!m_mlmeStartConfirmCallback.IsNull())
3181 {
3182 MlmeStartConfirmParams mlmeConfirmParams;
3183 mlmeConfirmParams.m_status = MacStatus::SUCCESS;
3184 m_mlmeStartConfirmCallback(mlmeConfirmParams);
3185 }
3186 }
3187
3188 ifsWaitTime = Seconds(static_cast<double>(GetIfsSize()) / symbolRate);
3189
3190 if (m_csmaCa->IsSlottedCsmaCa())
3191 {
3192 // The beacon was sent immediately in beacon-enabled mode
3193 m_txPkt = nullptr;
3194 }
3195 else
3196 {
3197 // The beacon was sent using CSMA/CA as a result of a beacon request
3198 // therefore, remove it from TX Queue
3200 }
3201 }
3202 else if (macHdr.IsAckReq()) // We have sent a regular data packet, check if we have to
3203 // wait for an ACK.
3204 {
3205 // we sent a regular data frame or command frame (e.g. AssocReq command) that
3206 // require ACK wait for the ack or the next retransmission timeout start
3207 // retransmission timer
3208 Time waitTime = Seconds(static_cast<double>(GetMacAckWaitDuration()) / symbolRate);
3209 NS_ASSERT(m_ackWaitTimeout.IsExpired());
3211 m_setMacState.Cancel();
3214 return;
3215 }
3216 else if (macHdr.IsCommand())
3217 {
3218 // We handle commands that do not require ACK
3219 // (e.g. Coordinator realigment command in an orphan response)
3220 // Other command with ACK required are handle by the previous if statement.
3221
3222 // Check the transmitted packet command type and issue the appropriate indication.
3223 Ptr<Packet> txOriginalPkt = m_txPkt->Copy();
3224 LrWpanMacHeader txMacHdr;
3225 txOriginalPkt->RemoveHeader(txMacHdr);
3226 CommandPayloadHeader txMacPayload;
3227 txOriginalPkt->RemoveHeader(txMacPayload);
3228
3230 {
3232 {
3233 MlmeCommStatusIndicationParams commStatusParams;
3234 commStatusParams.m_panId = m_macPanId;
3235
3236 commStatusParams.m_srcAddrMode = macHdr.GetSrcAddrMode();
3237 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
3238 commStatusParams.m_srcShortAddr = macHdr.GetShortSrcAddr();
3239
3240 commStatusParams.m_dstAddrMode = macHdr.GetDstAddrMode();
3241 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
3242 commStatusParams.m_dstShortAddr = macHdr.GetShortDstAddr();
3243
3244 commStatusParams.m_status = MacStatus::SUCCESS;
3245 m_mlmeCommStatusIndicationCallback(commStatusParams);
3246 }
3247 }
3248
3249 ifsWaitTime = Seconds(static_cast<double>(GetIfsSize()) / symbolRate);
3251 }
3252 else
3253 {
3255 // remove the copy of the packet that was just sent
3256 if (!m_mcpsDataConfirmCallback.IsNull())
3257 {
3258 McpsDataConfirmParams confirmParams;
3259 NS_ASSERT_MSG(!m_txQueue.empty(), "TxQsize = 0");
3260 std::shared_ptr<TxQueueElement> txQElement = m_txQueue.front();
3261 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
3262 confirmParams.m_status = MacStatus::SUCCESS;
3263 m_mcpsDataConfirmCallback(confirmParams);
3264 }
3265 ifsWaitTime = Seconds(static_cast<double>(GetIfsSize()) / symbolRate);
3267 }
3268 }
3269 else
3270 {
3271 // The packet sent was a successful ACK
3272
3273 // Check the received frame before the transmission of the ACK,
3274 // and send the appropriate Indication or Confirmation
3275 Ptr<Packet> recvOriginalPkt = m_rxPkt->Copy();
3276 LrWpanMacHeader receivedMacHdr;
3277 recvOriginalPkt->RemoveHeader(receivedMacHdr);
3278
3279 if (receivedMacHdr.IsCommand())
3280 {
3281 CommandPayloadHeader receivedMacPayload;
3282 recvOriginalPkt->RemoveHeader(receivedMacPayload);
3283
3284 if (receivedMacPayload.GetCommandFrameType() ==
3286 {
3288 {
3289 // NOTE: The LQI parameter is not part of the standard but found
3290 // in some implementations as is required for higher layers (See Zboss
3291 // implementation).
3292 MlmeAssociateIndicationParams associateParams;
3293 associateParams.capabilityInfo = receivedMacPayload.GetCapabilityField();
3294 associateParams.m_extDevAddr = receivedMacHdr.GetExtSrcAddr();
3295 associateParams.lqi = m_lastRxFrameLqi;
3296 m_mlmeAssociateIndicationCallback(associateParams);
3297 }
3298
3299 // Clear the packet buffer for the packet request received.
3300 m_rxPkt = nullptr;
3301 }
3302 else if (receivedMacPayload.GetCommandFrameType() ==
3304 {
3305 MlmeAssociateConfirmParams confirmParams;
3306
3307 switch (static_cast<MacStatus>(receivedMacPayload.GetAssociationStatus()))
3308 {
3309 case MacStatus::SUCCESS:
3310 // The assigned short address by the coordinator
3311 SetShortAddress(receivedMacPayload.GetShortAddr());
3312 m_macPanId = receivedMacHdr.GetSrcPanId();
3313
3314 confirmParams.m_status = MacStatus::SUCCESS;
3315 confirmParams.m_assocShortAddr = GetShortAddress();
3316 break;
3318 confirmParams.m_status = MacStatus::FULL_CAPACITY;
3319 m_macPanId = 0xffff;
3321 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3322 m_incCapEvent.Cancel();
3323 m_incCfpEvent.Cancel();
3324 m_csmaCa->SetUnSlottedCsmaCa();
3327 break;
3329 default:
3330 confirmParams.m_status = MacStatus::ACCESS_DENIED;
3331 m_macPanId = 0xffff;
3333 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3334 m_incCapEvent.Cancel();
3335 m_incCfpEvent.Cancel();
3336 m_csmaCa->SetUnSlottedCsmaCa();
3339 break;
3340 }
3341
3342 if (!m_mlmeAssociateConfirmCallback.IsNull())
3343 {
3344 m_mlmeAssociateConfirmCallback(confirmParams);
3345 }
3346 }
3347 else if (receivedMacPayload.GetCommandFrameType() == CommandPayloadHeader::DATA_REQ)
3348 {
3349 // We enqueue the the Assoc Response command frame in the Tx queue
3350 // and the packet is transmitted as soon as the PHY is free and the IFS have
3351 // taken place.
3353 }
3354 }
3355
3356 // Clear the packet buffer for the ACK packet sent.
3357 m_txPkt = nullptr;
3358 }
3359 }
3360 else if (status == IEEE_802_15_4_PHY_UNSPECIFIED)
3361 {
3362 if (!macHdr.IsAcknowledgment())
3363 {
3364 NS_ASSERT_MSG(!m_txQueue.empty(), "TxQsize = 0");
3365 std::shared_ptr<TxQueueElement> txQElement = m_txQueue.front();
3366 m_macTxDropTrace(txQElement->txQPkt);
3367 if (!m_mcpsDataConfirmCallback.IsNull())
3368 {
3369 McpsDataConfirmParams confirmParams;
3370 confirmParams.m_msduHandle = txQElement->txQMsduHandle;
3371 confirmParams.m_status = MacStatus::FRAME_TOO_LONG;
3372 m_mcpsDataConfirmCallback(confirmParams);
3373 }
3375 }
3376 else
3377 {
3378 NS_LOG_ERROR("Unable to send ACK");
3379 }
3380 }
3381 else
3382 {
3383 // Something went really wrong. The PHY is not in the correct state for
3384 // data transmission.
3385 NS_FATAL_ERROR("Transmission attempt failed with PHY status " << status);
3386 }
3387
3388 if (!ifsWaitTime.IsZero())
3389 {
3390 m_ifsEvent =
3391 Simulator::Schedule(ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this, ifsWaitTime);
3392 }
3393
3394 m_setMacState.Cancel();
3396}
3397
3398void
3400{
3401 NS_LOG_FUNCTION(this << status);
3402 // Direct this call through the csmaCa object
3403 m_csmaCa->PlmeCcaConfirm(status);
3404}
3405
3406void
3407LrWpanMac::PlmeEdConfirm(PhyEnumeration status, uint8_t energyLevel)
3408{
3409 NS_LOG_FUNCTION(this << status << energyLevel);
3410
3411 if (energyLevel > m_maxEnergyLevel)
3412 {
3413 m_maxEnergyLevel = energyLevel;
3414 }
3415
3417 Seconds(8.0 / m_phy->GetDataOrSymbolRate(false)))
3418 {
3419 m_phy->PlmeEdRequest();
3420 }
3421}
3422
3423void
3426 Ptr<PhyPibAttributes> attribute)
3427{
3428 NS_LOG_FUNCTION(this << status << id << attribute);
3429}
3430
3431void
3433{
3434 NS_LOG_FUNCTION(this << status << m_macState);
3435
3436 if (m_macState == MAC_SENDING &&
3437 (status == IEEE_802_15_4_PHY_TX_ON || status == IEEE_802_15_4_PHY_SUCCESS))
3438 {
3440
3441 // Start sending if we are in state SENDING and the PHY transmitter was enabled.
3445 m_phy->PdDataRequest(m_txPkt->GetSize(), m_txPkt);
3446 }
3447 else if (m_macState == MAC_CSMA &&
3448 (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS))
3449 {
3450 // Start the CSMA algorithm as soon as the receiver is enabled.
3451 m_csmaCa->Start();
3452 }
3453 else if (m_macState == MAC_IDLE)
3454 {
3456 status == IEEE_802_15_4_PHY_TRX_OFF);
3457
3458 if (status == IEEE_802_15_4_PHY_RX_ON && m_scanEnergyEvent.IsPending())
3459 {
3460 // Kick start Energy Detection Scan
3461 m_phy->PlmeEdRequest();
3462 }
3463 else if (status == IEEE_802_15_4_PHY_RX_ON || status == IEEE_802_15_4_PHY_SUCCESS)
3464 {
3465 // Check if there is not messages to transmit when going idle
3466 CheckQueue();
3467 }
3468 }
3469 else if (m_macState == MAC_ACK_PENDING)
3470 {
3472 }
3473 else
3474 {
3475 // TODO: What to do when we receive an error?
3476 // If we want to transmit a packet, but switching the transceiver on results
3477 // in an error, we have to recover somehow (and start sending again).
3478 NS_FATAL_ERROR("Error changing transceiver state");
3479 }
3480}
3481
3482void
3484{
3485 NS_LOG_FUNCTION(this << status << id);
3487 {
3489 {
3490 // get the first channel to scan from scan channel list
3491 bool channelFound = false;
3492 for (int i = m_channelScanIndex; i <= 26; i++)
3493 {
3494 if ((m_scanParams.m_scanChannels & (1 << m_channelScanIndex)) != 0)
3495 {
3496 channelFound = true;
3497 break;
3498 }
3500 }
3501
3502 if (channelFound)
3503 {
3505 pibAttr->phyCurrentChannel = m_channelScanIndex;
3506 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel,
3507 pibAttr);
3508 }
3509 }
3510 else
3511 {
3512 if (!m_mlmeScanConfirmCallback.IsNull())
3513 {
3514 MlmeScanConfirmParams confirmParams;
3515 confirmParams.m_scanType = m_scanParams.m_scanType;
3516 confirmParams.m_chPage = m_scanParams.m_chPage;
3517 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3518 m_mlmeScanConfirmCallback(confirmParams);
3519 }
3520 NS_LOG_ERROR(this << "Channel Scan: Invalid channel page");
3521 }
3522 }
3524 {
3526 {
3527 auto symbolRate = static_cast<uint64_t>(m_phy->GetDataOrSymbolRate(false));
3528 Time nextScanTime;
3529
3530 if (m_scanParams.m_scanType == MLMESCAN_ORPHAN)
3531 {
3532 nextScanTime = Seconds(static_cast<double>(m_macResponseWaitTime) / symbolRate);
3533 }
3534 else
3535 {
3536 uint64_t scanDurationSym =
3537 lrwpan::aBaseSuperframeDuration * (pow(2, m_scanParams.m_scanDuration) + 1);
3538
3539 nextScanTime = Seconds(static_cast<double>(scanDurationSym) / symbolRate);
3540 }
3541
3542 switch (m_scanParams.m_scanType)
3543 {
3544 case MLMESCAN_ED:
3545 m_maxEnergyLevel = 0;
3548 // set phy to RX_ON and kick start the first PLME-ED.request
3549 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3550 break;
3551 case MLMESCAN_ACTIVE:
3554 break;
3555 case MLMESCAN_PASSIVE:
3557 // turn back the phy to RX_ON after setting Page/channel
3558 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3559 break;
3560 case MLMESCAN_ORPHAN:
3562 Simulator::Schedule(nextScanTime, &LrWpanMac::EndChannelScan, this);
3564 break;
3565
3566 default:
3567 MlmeScanConfirmParams confirmParams;
3568 confirmParams.m_scanType = m_scanParams.m_scanType;
3569 confirmParams.m_chPage = m_scanParams.m_chPage;
3570 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3571 if (!m_mlmeScanConfirmCallback.IsNull())
3572 {
3573 m_mlmeScanConfirmCallback(confirmParams);
3574 }
3575 NS_LOG_ERROR("Scan Type currently not supported");
3576 return;
3577 }
3578 }
3579 else
3580 {
3581 if (!m_mlmeScanConfirmCallback.IsNull())
3582 {
3583 MlmeScanConfirmParams confirmParams;
3584 confirmParams.m_scanType = m_scanParams.m_scanType;
3585 confirmParams.m_chPage = m_scanParams.m_chPage;
3586 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3587 m_mlmeScanConfirmCallback(confirmParams);
3588 }
3589 NS_LOG_ERROR("Channel " << m_channelScanIndex
3590 << " could not be set in the current page");
3591 }
3592 }
3594 {
3596 {
3598 pibAttr->phyCurrentChannel = m_startParams.m_logCh;
3599 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
3600 }
3601 else
3602 {
3603 if (!m_mlmeStartConfirmCallback.IsNull())
3604 {
3605 MlmeStartConfirmParams confirmParams;
3606 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3607 m_mlmeStartConfirmCallback(confirmParams);
3608 }
3609 NS_LOG_ERROR("Invalid page parameter in MLME-start");
3610 }
3611 }
3614 {
3616 {
3618 }
3619 else
3620 {
3621 if (!m_mlmeStartConfirmCallback.IsNull())
3622 {
3623 MlmeStartConfirmParams confirmParams;
3624 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3625 m_mlmeStartConfirmCallback(confirmParams);
3626 }
3627 NS_LOG_ERROR("Invalid channel parameter in MLME-start");
3628 }
3629 }
3631 {
3633 {
3635 pibAttr->phyCurrentChannel = m_associateParams.m_chNum;
3636 m_phy->PlmeSetAttributeRequest(PhyPibAttributeIdentifier::phyCurrentChannel, pibAttr);
3637 }
3638 else
3639 {
3640 m_macPanId = 0xffff;
3642 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3643 m_incCapEvent.Cancel();
3644 m_incCfpEvent.Cancel();
3645 m_csmaCa->SetUnSlottedCsmaCa();
3648
3649 if (!m_mlmeAssociateConfirmCallback.IsNull())
3650 {
3651 MlmeAssociateConfirmParams confirmParams;
3652 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
3653 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3654 m_mlmeAssociateConfirmCallback(confirmParams);
3655 }
3656 NS_LOG_ERROR("Invalid page parameter in MLME-associate");
3657 }
3658 }
3661 {
3663 {
3665 }
3666 else
3667 {
3668 m_macPanId = 0xffff;
3670 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3671 m_incCapEvent.Cancel();
3672 m_incCfpEvent.Cancel();
3673 m_csmaCa->SetUnSlottedCsmaCa();
3676
3677 if (!m_mlmeAssociateConfirmCallback.IsNull())
3678 {
3679 MlmeAssociateConfirmParams confirmParams;
3680 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
3681 confirmParams.m_status = MacStatus::INVALID_PARAMETER;
3682 m_mlmeAssociateConfirmCallback(confirmParams);
3683 }
3684 NS_LOG_ERROR("Invalid channel parameter in MLME-associate");
3685 }
3686 }
3687 else
3688 {
3689 if (!m_mlmeSetConfirmCallback.IsNull())
3690 {
3691 MlmeSetConfirmParams confirmParams;
3693 {
3694 confirmParams.m_status = MacStatus::SUCCESS;
3695 }
3696 else
3697 {
3699 }
3700
3702 {
3704 }
3706 {
3708 }
3709
3710 m_mlmeSetConfirmCallback(confirmParams);
3711 }
3712 }
3713}
3714
3715void
3717{
3718 NS_LOG_FUNCTION(this << "mac state = " << macState);
3719
3720 if (macState == MAC_IDLE)
3721 {
3724 {
3725 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3726 }
3727 else
3728 {
3729 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
3730 }
3731 }
3732 else if (macState == MAC_ACK_PENDING)
3733 {
3735 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3736 }
3737 else if (macState == MAC_CSMA)
3738 {
3741 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3742 }
3743 else if (m_macState == MAC_CSMA && macState == CHANNEL_IDLE)
3744 {
3745 // Channel is idle, set transmitter to TX_ON
3747 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TX_ON);
3748 }
3749 else if (m_macState == MAC_CSMA && macState == CHANNEL_ACCESS_FAILURE)
3750 {
3752
3753 // Cannot find a clear channel, drop the current packet
3754 // and send the proper confirm/indication according to the packet type
3755 NS_LOG_DEBUG(this << " cannot find clear channel");
3756
3758
3759 Ptr<Packet> pkt = m_txPkt->Copy();
3760 LrWpanMacHeader macHdr;
3761 pkt->RemoveHeader(macHdr);
3762
3763 if (macHdr.IsCommand())
3764 {
3765 CommandPayloadHeader cmdPayload;
3766 pkt->RemoveHeader(cmdPayload);
3767
3768 switch (cmdPayload.GetCommandFrameType())
3769 {
3771 m_macPanId = 0xffff;
3773 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3774 m_incCapEvent.Cancel();
3775 m_incCfpEvent.Cancel();
3776 m_csmaCa->SetUnSlottedCsmaCa();
3779
3780 if (!m_mlmeAssociateConfirmCallback.IsNull())
3781 {
3782 MlmeAssociateConfirmParams confirmParams;
3783 confirmParams.m_assocShortAddr = Mac16Address("FF:FF");
3785 m_mlmeAssociateConfirmCallback(confirmParams);
3786 }
3787 break;
3788 }
3791 {
3792 MlmeCommStatusIndicationParams commStatusParams;
3793 commStatusParams.m_panId = m_macPanId;
3794 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
3795 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
3796 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
3797 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
3799 m_mlmeCommStatusIndicationCallback(commStatusParams);
3800 }
3802 break;
3803 }
3805 m_macPanId = 0xffff;
3807 m_macCoordExtendedAddress = Mac64Address("ff:ff:ff:ff:ff:ff:ff:ed");
3808 m_incCapEvent.Cancel();
3809 m_incCfpEvent.Cancel();
3810 m_csmaCa->SetUnSlottedCsmaCa();
3813
3814 if (!m_mlmePollConfirmCallback.IsNull())
3815 {
3816 MlmePollConfirmParams pollConfirmParams;
3817 pollConfirmParams.m_status = MacStatus::CHANNEL_ACCESS_FAILURE;
3818 m_mlmePollConfirmCallback(pollConfirmParams);
3819 }
3820 break;
3821 }
3824 {
3825 MlmeCommStatusIndicationParams commStatusParams;
3826 commStatusParams.m_panId = m_macPanId;
3827 commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
3828 commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
3829 commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
3830 commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
3832 m_mlmeCommStatusIndicationCallback(commStatusParams);
3833 }
3834 break;
3835 }
3837 if (m_scanOrphanEvent.IsPending())
3838 {
3839 m_unscannedChannels.emplace_back(m_phy->GetCurrentChannelNum());
3840 }
3841 // TODO: Handle orphan notification command during a
3842 // channel access failure when not is not scanning.
3843 break;
3844 }
3846 if (m_scanEvent.IsPending())
3847 {
3848 m_unscannedChannels.emplace_back(m_phy->GetCurrentChannelNum());
3849 }
3850 // TODO: Handle beacon request command during a
3851 // channel access failure when not scanning.
3852 break;
3853 }
3854 default: {
3855 // TODO: Other commands(e.g. Disassociation notification, etc)
3856 break;
3857 }
3858 }
3860 }
3861 else if (macHdr.IsData())
3862 {
3863 if (!m_mcpsDataConfirmCallback.IsNull())
3864 {
3865 McpsDataConfirmParams confirmParams;
3866 confirmParams.m_msduHandle = m_txQueue.front()->txQMsduHandle;
3868 m_mcpsDataConfirmCallback(confirmParams);
3869 }
3870 // remove the copy of the packet that was just sent
3872 }
3873 else
3874 {
3875 // TODO:: specify behavior for other packets
3876 m_txPkt = nullptr;
3877 m_retransmission = 0;
3878 m_numCsmacaRetry = 0;
3879 }
3880
3883 {
3884 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_RX_ON);
3885 }
3886 else
3887 {
3888 m_phy->PlmeSetTRXStateRequest(IEEE_802_15_4_PHY_TRX_OFF);
3889 }
3890 }
3891 else if (m_macState == MAC_CSMA && macState == MAC_CSMA_DEFERRED)
3892 {
3894 m_txPkt = nullptr;
3895 // The MAC is running on beacon mode and the current packet could not be sent in the
3896 // current CAP. The packet will be send on the next CAP after receiving the beacon.
3897 // The PHY state does not change from its current form. The PHY change (RX_ON) will be
3898 // triggered by the scheduled beacon event.
3899
3900 NS_LOG_DEBUG("****** PACKET DEFERRED to the next superframe *****");
3901 }
3902}
3903
3904void
3909
3910void
3915
3916uint16_t
3918{
3919 return m_macPanId;
3920}
3921
3927
3933
3934void
3935LrWpanMac::SetPanId(uint16_t panId)
3936{
3937 m_macPanId = panId;
3938}
3939
3940void
3942{
3943 NS_LOG_LOGIC(this << " change lrwpan mac state from " << m_macState << " to " << newState);
3944 m_macStateLogger(m_macState, newState);
3945 m_macState = newState;
3946}
3947
3948uint64_t
3950{
3951 return lrwpan::aUnitBackoffPeriod + lrwpan::aTurnaroundTime + m_phy->GetPhySHRDuration() +
3952 ceil(6 * m_phy->GetPhySymbolsPerOctet());
3953}
3954
3955uint8_t
3960
3961void
3963{
3964 NS_LOG_DEBUG("Transmit Queue Size: " << m_txQueue.size());
3965}
3966
3967void
3969{
3970 m_macMaxFrameRetries = retries;
3971}
3972
3973bool
3975{
3977 LrWpanMacHeader macHdr;
3978 m_txPkt->PeekHeader(macHdr);
3979
3980 if (m_coor)
3981 {
3982 // The device is its coordinator and the packet is not to itself
3983 return false;
3984 }
3985 else if (m_macCoordShortAddress == macHdr.GetShortDstAddr() ||
3987 {
3988 return true;
3989 }
3990 else
3991 {
3992 NS_LOG_DEBUG("ERROR: Packet not for the coordinator!");
3993 return false;
3994 }
3995}
3996
3999{
4001
4002 if (m_txPkt->GetSize() <= lrwpan::aMaxSIFSFrameSize)
4003 {
4004 return m_macSIFSPeriod;
4005 }
4006 else
4007 {
4008 return m_macLIFSPeriod;
4009 }
4010}
4011
4012void
4017
4018void
4023
4024uint64_t
4026{
4028 // Sync Header (SHR) + 8 bits PHY header (PHR) + PSDU
4029 return (m_phy->GetPhySHRDuration() + 1 * m_phy->GetPhySymbolsPerOctet() +
4030 (m_txPkt->GetSize() * m_phy->GetPhySymbolsPerOctet()));
4031}
4032
4033bool
4035{
4037 LrWpanMacHeader macHdr;
4038 m_txPkt->PeekHeader(macHdr);
4039
4040 return macHdr.IsAckReq();
4041}
4042
4043} // namespace lrwpan
4044} // namespace ns3
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:437
virtual void DoDispose()
Destructor implementation.
Definition object.cc:430
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:580
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:191
static EventId ScheduleNow(FUNC f, Ts &&... args)
Schedule an event to expire Now.
Definition simulator.h:614
static Time GetDelayLeft(const EventId &id)
Get the remaining time until this event will execute.
Definition simulator.cc:200
Simulation virtual time values and global simulation resolution.
Definition nstime.h:95
TimeWithUnit As(const Unit unit=Time::AUTO) const
Attach a unit to a Time, to facilitate output in a specific unit.
Definition time.cc:408
@ S
second
Definition nstime.h:106
bool IsZero() const
Exactly equivalent to t == 0.
Definition nstime.h:305
a unique identifier for an interface.
Definition type-id.h:50
TypeId AddDeprecatedName(const std::string &name)
Add an deprecated name for a TypeId.
Definition type-id.cc:860
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
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.
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
Temporarily 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.
void ReceiveData(uint8_t lqi, int8_t rssi, const LrWpanMacHeader &receivedMacHdr, Ptr< Packet > p)
Used to process the reception of data.
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 ...
void ReceiveInPromiscuousMode(uint8_t lqi, int8_t rssi, const LrWpanMacHeader &receivedMacHdr, Ptr< Packet > p)
Process a frame when promiscuous mode is active.
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).
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.
bool DequeueInd(Mac64Address dst, std::shared_ptr< IndTxQueueElement > entry)
Extracts a packet from pending transactions list (Indirect transmissions).
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.
void PrintReceivedPacket(const LrWpanMacHeader &receivedMacHdr)
Display the MAC header contents of a successfully received packet when logs are active.
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.
void ReceiveBeacon(uint8_t lqi, const LrWpanMacHeader &receivedMacHdr, Ptr< Packet > p)
Used to process the reception of a beacon packet.
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.
void ReceiveAcknowledgment(const LrWpanMacHeader &receivedMacHdr, Ptr< Packet > p)
Used to process an acknowledgment packet.
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 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.
std::deque< std::shared_ptr< IndTxQueueElement > > m_indTxQueue
The indirect transmit queue used by the MAC pending messages (The pending transaction list).
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 PdDataIndication(uint32_t psduLength, Ptr< Packet > p, uint8_t lqi, int8_t rssi)
IEEE 802.15.4-2006 section 6.2.1.3 PD-DATA.indication Indicates the transfer of an MPDU from PHY to M...
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 ReceiveCommand(uint8_t lqi, const LrWpanMacHeader &receivedMacHdr, Ptr< Packet > p)
Used to process the reception of a command packet.
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.
uint8_t m_macMaxFrameRetries
The maximum number of retries allowed after a transmission failure.
PendingPrimitiveStatus m_pendPrimitive
Indicates the pending primitive when PLME.SET operation (page or channel switch) is called from withi...
EventId m_respWaitTimeout
Scheduler event for a response to a request command frame.
uint16_t GetSuperframeField()
Constructs a Superframe specification field from the local information, the superframe Specification ...
bool IsCoordDest()
Check if the packet destination is its coordinator.
EventId m_ackWaitTimeout
Scheduler event for the ACK timeout of the currently transmitted data packet.
void StartCAP(SuperframeType superframeType)
Called to begin the Contention Access Period (CAP) in a beacon-enabled mode.
Mac64Address m_macCoordExtendedAddress
The extended address of the coordinator through which the device is associated.
void McpsDataRequest(McpsDataRequestParams params, Ptr< Packet > p) override
IEEE 802.15.4-2006, section 7.1.1.1 MCPS-DATA.request Request to transfer a MSDU.
void EnqueueTxQElement(std::shared_ptr< TxQueueElement > txQElement)
Add an element to the transmission queue.
EventId m_incCapEvent
Scheduler event for the end of the incoming superframe CAP.
Mac16Address GetCoordShortAddress() const
Get the coordinator short address currently associated to this device.
std::deque< std::shared_ptr< TxQueueElement > > m_txQueue
The transmit queue used by the MAC.
void SendDataRequestCommand()
Used to send a data request command (i.e.
EventId m_trackingEvent
Scheduler event to track the incoming beacons.
uint64_t GetTxPacketSymbols()
Obtain the number of symbols in the packet which is currently being sent by the MAC layer.
uint32_t m_beaconInterval
Indication of the Interval used by the coordinator to transmit beacon frames expressed in symbols.
Mac16Address m_shortAddress
The short address (16 bit address) used by this MAC.
EventId m_assocResCmdWaitTimeout
Scheduler event for the lost of a association response command frame.
void PlmeGetAttributeConfirm(PhyEnumeration status, PhyPibAttributeIdentifier id, Ptr< PhyPibAttributes > attribute)
IEEE 802.15.4-2006 section 6.2.2.6 PLME-GET.confirm Get attributes per definition from Table 23 in se...
uint8_t m_macBeaconOrder
Used by a PAN coordinator or coordinator.
void SetPhy(Ptr< LrWpanPhy > phy)
Set the underlying PHY for the MAC.
void MlmePollRequest(MlmePollRequestParams params) override
IEEE 802.15.4-2011, section 6.2.14.2 MLME-POLL.request Prompts the device to request data from the co...
void RemoveFirstTxQElement()
Remove the tip of the transmission queue, including clean up related to the last packet transmission.
TracedValue< SuperframeStatus > m_outSuperframeStatus
The current period of the outgoing superframe.
void SetRxOnWhenIdle(bool rxOnWhenIdle)
Set if the receiver should be enabled when the MAC is idle.
void PlmeCcaConfirm(PhyEnumeration status)
IEEE 802.15.4-2006 section 6.2.2.2 PLME-CCA.confirm status.
void PlmeSetAttributeConfirm(PhyEnumeration status, PhyPibAttributeIdentifier id)
IEEE 802.15.4-2006 section 6.2.2.10 PLME-SET.confirm Set attributes per definition from Table 23 in s...
EventId m_scanOrphanEvent
Scheduler event for the end of an ORPHAN channel scan.
void StartInactivePeriod(SuperframeType superframeType)
Start the Inactive Period in a beacon-enabled mode.
uint32_t GetIfsSize()
Get the size of the Interframe Space according to MPDU size (m_txPkt).
EventId m_capEvent
Scheduler event for the end of the outgoing superframe CAP.
void PlmeSetTRXStateConfirm(PhyEnumeration status)
IEEE 802.15.4-2006 section 6.2.2.8 PLME-SET-TRX-STATE.confirm Set PHY state.
TracedValue< MacState > m_macState
The current state of the MAC layer.
void EndChannelEnergyScan()
Called at the end of one ED channel scan.
uint8_t m_incomingFnlCapSlot
Indication of the Slot where the CAP portion of the INCOMING Superframe ends.
bool m_ignoreDataCmdAck
This flag informs the MAC that an association response command was received before the acknowledgment...
TracedCallback< Ptr< const Packet > > m_macTxEnqueueTrace
The trace source fired when packets come into the "top" of the device at the L3/L2 transition,...
uint8_t m_numLostBeacons
The number of consecutive loss beacons in a beacon tracking operation.
uint8_t GetMacMaxFrameRetries() const
Get the macMaxFrameRetries attribute value.
bool IsTxAckReq()
Check if the packet to transmit requires acknowledgment.
void SendOneBeacon()
Called to send a single beacon frame.
void LostAssocRespCommand()
Called after m_assocRespCmdWaitTime timeout while waiting for an association response command.
void PlmeEdConfirm(PhyEnumeration status, uint8_t energyLevel)
IEEE 802.15.4-2006 section 6.2.2.4 PLME-ED.confirm status and energy level.
bool m_coor
Indicates if the current device is a coordinator type.
uint8_t m_lastRxFrameLqi
Keep track of the last received frame Link Quality Indicator.
void EndChannelScan()
Called at the end of the current channel scan (Active or Passive) for a given duration.
void EndAssociateRequest()
Called to end an MLME-ASSOCIATE.request after changing the page and channel number.
uint64_t m_macResponseWaitTime
The maximum time, in multiples of aBaseSuperframeDuration, a device shall wait for a response command...
void DoInitialize() override
Initialize() implementation.
Represent the Mac Trailer with the Frame Check Sequence field.
void EnableFcs(bool enable)
Enable or disable FCS calculation for this trailer.
void SetFcs(Ptr< const Packet > p)
Calculate and set the FCS value based on the given packet.
bool CheckFcs(Ptr< const Packet > p)
Check the FCS of a given packet against the FCS value stored in the trailer.
Represent the Pending Address Specification field.
Represent the Superframe Specification information field.
void SetPanCoor(bool panCoor)
Set the Superframe Specification PAN coordinator field.
uint8_t GetFinalCapSlot() const
Get the the Final CAP Slot.
void SetAssocPermit(bool assocPermit)
Set the Superframe Specification Association Permit field.
void SetBattLifeExt(bool battLifeExt)
Set the Superframe Specification Battery Life Extension (BLE).
bool IsBattLifeExt() const
Check if the Battery Life Extension bit is enabled.
uint8_t GetBeaconOrder() const
Get the Superframe Specification Beacon Order field.
uint8_t GetFrameOrder() const
Get the Superframe Specification Frame Order field.
uint16_t GetSuperframe() const
Get the Superframe specification information field.
void SetFinalCapSlot(uint8_t capSlot)
Set the superframe specification Final CAP slot field.
void SetBeaconOrder(uint8_t bcnOrder)
Set the superframe specification Beacon Order field.
void SetSuperframeOrder(uint8_t frmOrder)
Set the superframe specification Superframe Order field.
constexpr uint32_t aMaxSIFSFrameSize
The maximum size of an MPDU, in octets, that can be followed by a Short InterFrame Spacing (SIFS) per...
constexpr uint32_t aMaxLostBeacons
The number of consecutive lost beacons that will cause the MAC sublayer of a receiving device to decl...
constexpr uint32_t aMaxBeaconPayloadLength
The maximum size, in octets, of a beacon payload.
constexpr uint32_t aMaxPhyPacketSize
The maximum packet size accepted by the PHY.
constexpr uint32_t aUnitBackoffPeriod
Number of symbols per CSMA/CA time unit, default 20 symbols.
constexpr uint32_t aTurnaroundTime
The turnaround time in symbol periods for switching the transceiver from RX to TX or vice-versa.
constexpr uint32_t aBaseSuperframeDuration
Length of a superframe in symbols.
constexpr uint32_t aMinMPDUOverhead
The minimum number of octets added by the MAC sublayer to the PSDU.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
Callback< R, Args... > MakeNullCallback()
Build null Callbacks which take no arguments, for varying number of template arguments,...
Definition callback.h:734
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition log.h:246
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:260
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:274
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
MacPibAttributeIdentifier
IEEE 802.15.4-2006 PHY and MAC PIB Attribute Identifiers Table 23 and Table 86.
MacState
MAC states.
Definition lr-wpan-mac.h:65
SuperframeType
Superframe type.
PhyEnumeration
IEEE802.15.4-2006 PHY Emumerations Table 18 in section 6.2.3.
MacStatus
The status of a confirm or an indication primitive as a result of a previous request.
PhyPibAttributeIdentifier
IEEE802.15.4-2006 PHY PIB Attribute Identifiers Table 23 in section 6.4.2.
@ macPanId
The 16-bit identifier of the Personal Area Network (PAN).
@ pCurrentChannel
RF channel used for transmissions and receptions.
@ macShortAddress
The short address of the device (16 bit address).
@ macRxOnWhenIdle
Indication of whether the MAC is enabled during idle periods.
@ macBeaconPayloadLength
The length in octets of the beacon payload.
@ macPromiscuousMode
Indication of whether the MAC sublayer is in a promiscuous mode.
@ pCurrentPage
The current channel page.
@ macExtendedAddress
The extended address of the device (64 bit address).
@ macAssociationPermit
Indication of whether a coordinator is allowing association.
@ macBeaconPayload
The contents of the beacon payload.
@ MAC_CSMA
MAC_CSMA.
Definition lr-wpan-mac.h:67
@ MAC_GTS
MAC_GTS.
Definition lr-wpan-mac.h:73
@ CHANNEL_ACCESS_FAILURE
CHANNEL_ACCESS_FAILURE.
Definition lr-wpan-mac.h:70
@ CHANNEL_IDLE
CHANNEL_IDLE.
Definition lr-wpan-mac.h:71
@ SET_PHY_TX_ON
SET_PHY_TX_ON.
Definition lr-wpan-mac.h:72
@ MAC_CSMA_DEFERRED
MAC_CSMA_DEFERRED.
Definition lr-wpan-mac.h:75
@ MAC_IDLE
MAC_IDLE.
Definition lr-wpan-mac.h:66
@ MAC_INACTIVE
MAC_INACTIVE.
Definition lr-wpan-mac.h:74
@ MAC_SENDING
MAC_SENDING.
Definition lr-wpan-mac.h:68
@ MAC_ACK_PENDING
MAC_ACK_PENDING.
Definition lr-wpan-mac.h:69
@ BEACON
The Beacon transmission or reception Period.
Definition lr-wpan-mac.h:94
@ INACTIVE
Inactive Period or unslotted CSMA-CA.
Definition lr-wpan-mac.h:97
@ CAP
Contention Access Period.
Definition lr-wpan-mac.h:95
@ CFP
Contention Free Period.
Definition lr-wpan-mac.h:96
@ MLME_SCAN_REQ
Pending MLME-SCAN.request primitive.
@ MLME_NONE
No pending primitive.
@ MLME_START_REQ
Pending MLME-START.request primitive.
@ MLME_ASSOC_REQ
Pending MLME-ASSOCIATION.request primitive.
@ FFD
Full Functional Device (FFD).
@ INCOMING
Incoming Superframe.
@ OUTGOING
Outgoing Superframe.
@ IEEE_802_15_4_PHY_RX_ON
@ IEEE_802_15_4_PHY_TRX_OFF
@ IEEE_802_15_4_PHY_TX_ON
@ IEEE_802_15_4_PHY_SUCCESS
@ IEEE_802_15_4_PHY_UNSPECIFIED
@ TX_OPTION_GTS
TX_OPTION_GTS.
Definition lr-wpan-mac.h:55
@ TX_OPTION_ACK
TX_OPTION_ACK.
Definition lr-wpan-mac.h:54
@ TX_OPTION_INDIRECT
TX_OPTION_INDIRECT.
Definition lr-wpan-mac.h:56
@ TRANSACTION_OVERFLOW
There is no capacity to store the transaction.
@ NO_BEACON
A scan operation failed to find any network beacons.
@ UNSUPPORTED_ATTRIBUTE
SET/GET request issued with a non supported ID.
@ NO_SHORT_ADDRESS
Failure due to unallocated 16-bit short address.
@ ACCESS_DENIED
PAN access denied.
@ BEACON_LOSS
The beacon was lost following a synchronization request.
@ CHANNEL_ACCESS_FAILURE
A Tx could not take place due to activity in the CH.
@ READ_ONLY
SET/GET request issued for a read only attribute.
@ TRANSACTION_EXPIRED
The transaction expired and its information discarded.
@ SCAN_IN_PROGRESS
Scan failed because already performing another scan.
@ FRAME_TOO_LONG
Frame more than aMaxPHYPacketSize or too large for CAP or GTS.
@ INVALID_ADDRESS
Invalid source or destination address.
@ FULL_CAPACITY
PAN at capacity.
@ SUCCESS
The operation was completed successfully.
@ NO_ACK
No acknowledgment was received after macMaxFrameRetries.
@ NO_DATA
No response data were available following a request.
@ INVALID_PARAMETER
Primitive parameter not supported or out of range.
Ptr< T > CreateObject(Args &&... args)
Create an object by type, with varying number of constructor parameters.
Definition object.h:627
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:454
SequenceNumber< uint8_t, int8_t > SequenceNumber8
8 bit Sequence number.
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1273
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
std::ostream & operator<<(std::ostream &os, const SuperframeField &superframeField)
Stream insertion operator.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
MacStatus m_status
The status of the last MSDU transmission.
MLME-ASSOCIATE.confirm params.
Mac16Address m_assocShortAddr
The short address used in the association request.
MacStatus m_status
The status of a MLME-associate.request.
MLME-ASSOCIATE.indication params.
uint8_t lqi
The link quality indicator of the received associate request command (Not officially supported in the...
Mac64Address m_extDevAddr
The extended address of the device requesting association.
uint8_t capabilityInfo
The operational capabilities of the device requesting association.
MLME-ASSOCIATE.request params.
MLME-ASSOCIATE.response params.
MLME-BEACON-NOTIFY.indication params.
PanDescriptor m_panDescriptor
The PAN descriptor for the received beacon.
uint32_t m_sduLength
The number of octets contained in the beacon payload.
uint8_t m_bsn
The beacon sequence number.
Ptr< Packet > m_sdu
The set of octets comprising the beacon payload.
MLME-COMM-STATUS.indication params.
uint8_t m_dstAddrMode
The destination addressing mode for this primitive.
uint16_t m_panId
The PAN identifier of the device from which the frame was received or to which the frame was being se...
Mac64Address m_srcExtAddr
The extended address of the entity from which the frame causing the error originated.
MacStatus m_status
The communication status.
Mac16Address m_srcShortAddr
The short address of the entity from which the frame causing the error originated.
Mac16Address m_dstShortAddr
The short address of the device for which the frame was intended.
uint8_t m_srcAddrMode
The source addressing mode for this primitive.
Mac64Address m_dstExtAddr
The extended address of the device for which the frame was intended.
MLME-ORPHAN.indication params.
Mac64Address m_orphanAddr
The address of the orphaned device.
MacStatus m_status
The confirmation status resulting from a MLME-poll.request.
std::vector< uint8_t > m_unscannedCh
A list of channels given in the request which were not scanned (Not valid for ED scans).
uint32_t m_chPage
The channel page on which the scan was performed.
std::vector< uint8_t > m_energyDetList
A list of energy measurements, one for each channel searched during ED scan (Not valid for Active,...
MacStatus m_status
The status of the scan request.
std::vector< PanDescriptor > m_panDescList
A list of PAN descriptor, one for each beacon found (Not valid for ED and Orphan scans).
uint8_t m_resultListSize
The number of elements returned in the appropriate result list.
uint8_t m_scanType
Indicates the type of scan performed (ED,ACTIVE,PASSIVE,ORPHAN).
MacStatus m_status
The result of the request to write the PIB attribute.
MacPibAttributeIdentifier id
The id of the PIB attribute that was written.
MacStatus m_status
The status of a MLME-start.request.
MLME-SYNC-LOSS.indication params.
uint16_t m_panId
The PAN identifier with which the device lost synchronization or to which it was realigned.
MacStatus m_lossReason
The reason for the lost of synchronization.
PAN Descriptor, Table 17 IEEE 802.15.4-2011.
uint16_t m_coorPanId
The PAN ID of the coordinator as specified in the received beacon frame.
uint8_t m_logCh
The current channel number occupied by the network.
Time m_timeStamp
Beacon frame reception time.
bool m_gtsPermit
TRUE if the beacon is from the PAN coordinator that is accepting GTS requests.
Mac16Address m_coorShortAddr
The coordinator short address as specified in the coordinator address mode.
uint16_t m_superframeSpec
The superframe specification as specified in the received beacon frame.
AddressMode m_coorAddrMode
The coordinator addressing mode corresponding to the received beacon frame.
uint8_t m_linkQuality
The LQI at which the network beacon was received.
uint8_t m_logChPage
The current channel page occupied by the network.
Mac64Address m_coorExtAddr
The coordinator extended address as specified in the coordinator address mode.
std::ofstream queueSize