EMANE  1.0.1
models/mac/ieee80211abg/maclayer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013-2016 - Adjacent Link LLC, Bridgewater, New Jersey
3  * Copyright (c) 2008-2012 - DRS CenGen, LLC, Columbia, Maryland
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * * Neither the name of DRS CenGen, LLC nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "maclayer.h"
35 #include "macstatistics.h"
36 #include "idletxstate.h"
37 #include "utils.h"
40 #include "configurationvalidator.h"
41 
50 
52 #include "emane/startexception.h"
53 #include "emane/controlmessage.h"
54 #include "emane/event.h"
55 #include "emane/constants.h"
57 
61 
62 #include <sstream>
63 
64 #include <cmath>
65 
66 namespace
67 {
68  const char *pzLayerName{"IEEEMACLayer"};
69 
70  // undocumented test params
71  // tx retry logic enable
72  const bool ENABLE_TX_RETRY{false};
73 
74  // wmm overhead enable
75  const bool ENABLE_WMM_OVERHEAD{false};
76 
77  const std::uint16_t DROP_CODE_SINR = 1;
78  const std::uint16_t DROP_CODE_REGISTRATION_ID = 2;
79  const std::uint16_t DROP_CODE_DST_MAC = 3;
80  const std::uint16_t DROP_CODE_QUEUE_OVERFLOW = 4;
81  const std::uint16_t DROP_CODE_BAD_CONTROL_INFO = 5;
82  const std::uint16_t DROP_CODE_BAD_SPECTRUM_QUERY = 6;
83  const std::uint16_t DROP_CODE_FLOW_CONTROL_ERROR = 7;
84  const std::uint16_t DROP_CODE_DUPLICATE = 8;
85  const std::uint16_t DROP_CODE_RX_DURING_TX = 9;
86  const std::uint16_t DROP_CODE_RX_HIDDEN_BUSY = 10;
87 
88  EMANE::StatisticTableLabels STATISTIC_TABLE_LABELS
89  { "SINR",
90  "Reg Id",
91  "Dst MAC",
92  "Queue Overflow",
93  "Bad Control",
94  "Bad Spectrum Query",
95  "Flow Control",
96  "Duplicate",
97  "Rx During Tx",
98  "Hidden Busy"
99  };
100 }
101 
102 
103 
105  PlatformServiceProvider * pPlatformServiceProvider,
106  RadioServiceProvider * pRadioServiceProvider):
107  MACLayerImplementor{id, pPlatformServiceProvider, pRadioServiceProvider},
108  id_{id},
109  macConfig_{pPlatformServiceProvider->logService(), id},
110  macStatistics_{id},
111  downstreamQueue_{id},
112  pTxState_{IdleTxStateSingleton::instance()},
113  pcrManager_{id_, pPlatformService_},
114  neighborManager_{id_, pPlatformService_, this},
115  neighborMetricManager_{id},
116  queueMetricManager_{id},
117  flowControlManager_{*this},
118  u64SequenceNumber_{},
119  u16EntrySequenceNumber_{},
120  modeTiming_{macConfig_},
121  channelUsageTimedEventId_{},
122  radioMetricTimedEventId_{},
123  downstreamQueueTimedEventId_{},
124  bHasPendingDownstreamQueueEntry_{},
125  RNDZeroToOne_{0.0f, 1.0f},
126  commonLayerStatistics_(MAX_ACCESS_CATEGORIES),
127  currentEndOfTransmissionTime_{}
128 {
129  commonLayerStatistics_[0].reset(
130  new Utils::CommonLayerStatistics{STATISTIC_TABLE_LABELS,
131  STATISTIC_TABLE_LABELS, "0"});
132  commonLayerStatistics_[1].reset(
133  new Utils::CommonLayerStatistics{STATISTIC_TABLE_LABELS,
134  STATISTIC_TABLE_LABELS, "1"});
135  commonLayerStatistics_[2].reset(
136  new Utils::CommonLayerStatistics{STATISTIC_TABLE_LABELS,
137  STATISTIC_TABLE_LABELS, "2"});
138  commonLayerStatistics_[3].reset(
139  new Utils::CommonLayerStatistics{STATISTIC_TABLE_LABELS,
140  STATISTIC_TABLE_LABELS, "3"});
141 }
142 
143 
145 { }
146 
147 
148 void
150 {
152  DEBUG_LEVEL,
153  "MACI %03hu %s::%s",
154  id_, pzLayerName, __func__);
155 
158  auto & configRegistrar = registrar.configurationRegistrar();
159 
160  macConfig_.registerConfiguration(configRegistrar);
161 
162  configRegistrar.registerValidator(&configurationValidator);
163 
166  auto & statisticRegistrar = registrar.statisticRegistrar();
167 
168  macStatistics_.registerStatistics(statisticRegistrar);
169 
170  downstreamQueue_.registerStatistics(statisticRegistrar);
171 
172  neighborManager_.registerStatistics(statisticRegistrar);
173 
174  for(auto & iter : commonLayerStatistics_)
175  {
176  iter->registerStatistics(statisticRegistrar);
177  }
178 
179  neighborMetricManager_.registerStatistics(statisticRegistrar);
180 
181  auto & eventRegistrar = registrar.eventRegistrar();
182 
184 }
185 
186 
187 
188 void
190 {
192  DEBUG_LEVEL,
193  "MACI %03hu %s::%s",
194  id_, pzLayerName, __func__);
195 
196  if(!macConfig_.configure(update))
197  {
198  throw(ConfigureException{"IEEE80211ABG MACLayer configuration failure"});
199  }
200 
201  // load pcr curve
202  pcrManager_.load(macConfig_.getPcrUri());
203 }
204 
205 
206 
207 void
209 {
211  DEBUG_LEVEL,
212  "MACI %03hu %s::%s",
213  id_, pzLayerName, __func__);
214 
215  // number of access categories (queues)
216  std::uint8_t u8NumCategories{macConfig_.getNumAccessCategories()};
217 
218  // set downstream queue categories and sizes
219  downstreamQueue_.setCategories(u8NumCategories);
220 
221  for(std::uint8_t u8Category = 0; u8Category < u8NumCategories; ++u8Category)
222  {
223  size_t maxCapacity{macConfig_.getQueueSize(u8Category)};
224 
225  size_t maxEntrySize{macConfig_.getQueueEntrySize(u8Category)};
226 
227  downstreamQueue_.setMaxCapacity(maxCapacity, u8Category);
228 
229  downstreamQueue_.setMaxEntrySize(maxEntrySize, u8Category);
230 
231  queueMetricManager_.addQueueMetric(u8Category, maxCapacity);
232  }
233 
234  // set neighbor timeout and num categories
235  neighborManager_.setNeighborTimeoutMicroseconds(macConfig_.getNeighborTimeoutMicroseconds());
236 
237  neighborManager_.setCategories(u8NumCategories);
238 
239  // the the neighbor delete time (age)
240  neighborMetricManager_.setNeighborDeleteTimeMicroseconds(
242 }
243 
244 
245 
246 void
248 {
249  auto timeNow = Clock::now();
250 
251  if(macConfig_.getFlowControlEnable())
252  {
253  flowControlManager_.start(macConfig_.getFlowControlTokens());
254 
256  DEBUG_LEVEL,
257  "MACI %03hu %s::%s sent a flow control token update,"
258  " a handshake response is required to process packets",
259  id_,
260  pzLayerName,
261  __func__);
262  }
263 
264  neighborManager_.start();
265 
266  channelUsageTimedEventId_ =
268  schedule(std::bind(&NeighborManager::resetStatistics,
269  &neighborManager_),
270  timeNow +
273 
274 
276  DEBUG_LEVEL,
277  "MACI %03hu %s::%s: added channel activity timed eventId %zu",
278  id_,
279  pzLayerName,
280  __func__,
281  channelUsageTimedEventId_);
282 
283  radioMetricTimedEventId_ =
285  schedule([this](const TimePoint &,
286  const TimePoint &,
287  const TimePoint &)
288  {
289  if(!macConfig_.getRadioMetricEnable())
290  {
291  neighborMetricManager_.updateNeighborStatus();
292  }
293  else
294  {
297  macConfig_.getBroadcastDataRateKbps() * 1000ULL,
298  macConfig_.getMaxDataRateKbps() * 1000ULL,
302  }
303  },
304  timeNow + macConfig_.getRadioMetricReportIntervalMicroseconds(),
306 
308  DEBUG_LEVEL,
309  "MACI %03hu %s::%s: added radio metric timed eventId %zu",
310  id_,
311  pzLayerName,
312  __func__,
313  radioMetricTimedEventId_);
314 }
315 
316 
317 void
319 {
321  DEBUG_LEVEL,
322  "MACI %03hu %s::%s",
323  id_, pzLayerName, __func__);
324 
325  macConfig_.processConfiguration(update);
326 }
327 
328 
329 void
331 {
333  DEBUG_LEVEL,
334  "MACI %03hu %s::%s",
335  id_,
336  pzLayerName,
337  __func__);
338 
339  pPlatformService_->timerService().cancelTimedEvent(channelUsageTimedEventId_);
340 
341  channelUsageTimedEventId_ = 0;
342 
343  pPlatformService_->timerService().cancelTimedEvent(radioMetricTimedEventId_);
344 
345  radioMetricTimedEventId_ = 0;
346 
347  pPlatformService_->timerService().cancelTimedEvent(downstreamQueueTimedEventId_);
348 
349  downstreamQueueTimedEventId_ = 0;
350 
351  if(macConfig_.getFlowControlEnable())
352  {
353  flowControlManager_.stop();
354  }
355 }
356 
357 
358 
359 void
361  throw()
362 {
364  DEBUG_LEVEL,
365  "MACI %03hu %s::%s",
366  id_,
367  pzLayerName,
368  __func__);
369 }
370 
371 
372 
373 void
375 {
377  DEBUG_LEVEL,
378  "MACI %03hu %s::%s",
379  id_,
380  pzLayerName,
381  __func__);
382 }
383 
384 
385 
386 void
388 {
389  for(const auto & pMessage : msgs)
390  {
392  DEBUG_LEVEL,
393  "MACI %03hu %s::%s downstream control message id %hu",
394  id_,
395  pzLayerName,
396  __func__,
397  pMessage->getId());
398 
399  switch(pMessage->getId())
400  {
402  {
403  const auto pFlowControlControlMessage =
404  static_cast<const Controls::FlowControlControlMessage *>(pMessage);
405 
406 
407  if(macConfig_.getFlowControlEnable())
408  {
410  DEBUG_LEVEL,
411  "MACI %03hu %s::%s received a flow control token request/response",
412  id_,
413  pzLayerName,
414  __func__);
415 
416  flowControlManager_.processFlowControlMessage(pFlowControlControlMessage);
417  }
418  else
419  {
421  ERROR_LEVEL,
422  "MACI %03hu %s::%s received a flow control token request but"
423  " flow control is not enabled",
424  id_,
425  pzLayerName,
426  __func__);
427  }
428  }
429 
430  break;
431 
433  {
434  const auto pSerializedControlMessage =
435  static_cast<const Controls::SerializedControlMessage *>(pMessage);
436 
437  switch(pSerializedControlMessage->getSerializedId())
438  {
440  {
441  std::unique_ptr<Controls::FlowControlControlMessage>
442  pFlowControlControlMessage{Controls::FlowControlControlMessage::create
443  (pSerializedControlMessage->getSerialization())};
444 
445  if(macConfig_.getFlowControlEnable())
446  {
448  DEBUG_LEVEL,
449  "MACI %03hu %s::%s received a flow control token request/response",
450  id_,
451  pzLayerName,
452  __func__);
453 
454  flowControlManager_.processFlowControlMessage(pFlowControlControlMessage.get());
455  }
456  else
457  {
459  ERROR_LEVEL,
460  "MACI %03hu %s::%s received a flow control token request but"
461  " flow control is not enabled",
462  id_,
463  pzLayerName,
464  __func__);
465  }
466  }
467 
468  break;
469  }
470  }
471  }
472  }
473 }
474 
475 
476 
477 void
479  UpstreamPacket & pkt,
480  const ControlMessages & msgs)
481 {
482  // get current time
483  TimePoint timeNow{Clock::now()};
484 
485  const PacketInfo & pktInfo{pkt.getPacketInfo()};
486 
487  std::uint8_t u8Category{dscpToCategory(pktInfo.getPriority())};
488 
489  commonLayerStatistics_[u8Category]->processInbound(pkt);
490 
491 
493  DEBUG_LEVEL,
494  "MACI %03hu %s::%s: src %hu, dst %hu",
495  id_,
496  pzLayerName,
497  __func__,
498  pktInfo.getSource(),
499  pktInfo.getDestination());
500 
501  // check mac header registration id(ieee80211abg)
502  if(commonMACHeader.getRegistrationId() != registrationId_)
503  {
505  ERROR_LEVEL, "MACI %03hu %s::%s: src %hu, dst %hu, "
506  "MAC registration id %hu does not match our id %hu, drop.",
507  id_,
508  pzLayerName,
509  __func__,
510  pktInfo.getSource(),
511  pktInfo.getDestination(),
512  commonMACHeader.getRegistrationId(),
513  registrationId_);
514 
515  commonLayerStatistics_[u8Category]->processOutbound(
516  pkt,
517  std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
518  DROP_CODE_REGISTRATION_ID);
519 
520  // drop
521  return;
522  }
523 
524  const Controls::ReceivePropertiesControlMessage * pReceivePropertiesControlMessage{};
525 
526  const Controls::FrequencyControlMessage * pFrequencyControlMessage{};
527 
528  for(auto & pControlMessage : msgs)
529  {
530  switch(pControlMessage->getId())
531  {
533  {
534  pReceivePropertiesControlMessage =
535  static_cast<const Controls::ReceivePropertiesControlMessage *>(pControlMessage);
536 
538  DEBUG_LEVEL,
539  Controls::ReceivePropertiesControlMessageFormatter(pReceivePropertiesControlMessage),
540  "MACI %03hu %s::%s Receiver Properties Control Message",
541  id_,
542  pzLayerName,
543  __func__);
544  }
545  break;
546 
548  {
549  pFrequencyControlMessage =
550  static_cast<const Controls::FrequencyControlMessage *>(pControlMessage);
551 
553  DEBUG_LEVEL,
554  Controls::FrequencyControlMessageFormatter(pFrequencyControlMessage),
555  "MACI %03hu %s::%s Frequency Control Message",
556  id_,
557  pzLayerName,
558  __func__);
559 
560  }
561 
562  break;
563  }
564  }
565 
566  if(!pReceivePropertiesControlMessage || !pFrequencyControlMessage ||
567  pFrequencyControlMessage->getFrequencySegments().empty())
568  {
570  ERROR_LEVEL,
571  "MACI %03hu %s::%s: phy control message not"
572  " provided from src %hu, drop",
573  id_,
574  pzLayerName,
575  __func__,
576  pktInfo.getSource());
577 
578  commonLayerStatistics_[u8Category]->processOutbound(pkt,
579  std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
580  DROP_CODE_BAD_CONTROL_INFO);
581 
582  //drop
583  return;
584  }
585  else
586  {
587  const auto & frequencySegments = pFrequencyControlMessage->getFrequencySegments();
588 
589  TimePoint startOfReception{pReceivePropertiesControlMessage->getTxTime() +
590  pReceivePropertiesControlMessage->getPropagationDelay() +
591  frequencySegments.begin()->getOffset()};
592 
593  Microseconds span{pReceivePropertiesControlMessage->getSpan()};
594 
595  auto callback =std::bind([this,
596  startOfReception,
597  frequencySegments,
598  span,
599  timeNow](UpstreamPacket & pkt,
600  std::uint64_t u64SequenceNumber,
601  std::uint8_t u8Category)
602  {
603  const PacketInfo & pktInfo{pkt.getPacketInfo()};
604 
605  const FrequencySegment & frequencySegment{*frequencySegments.begin()};
606 
608  DEBUG_LEVEL,
609  "MACI %03hu %s upstream EOR processing: src %hu, dst %hu, len %zu, freq %ju, offset %ju, duration %ju",
610  id_,
611  pzLayerName,
612  pktInfo.getSource(),
613  pktInfo.getDestination(),
614  pkt.length(),
615  frequencySegment.getFrequencyHz(),
616  frequencySegment.getOffset().count(),
617  frequencySegment.getDuration().count());
618 
619 
620  double dNoiseFloordB{};
621 
622  try
623  {
624  // get the spectrum info for the entire span, where a span
625  // is the total time between the start of the signal of the
626  // earliest segment and the end of the signal of the latest
627  // segment. This is not necessarily the signal duration.
628  auto window = pRadioService_->spectrumService().request(frequencySegment.getFrequencyHz(),
629  span,
630  startOfReception);
631 
632  // since we only have a single segment the span will equal the segment duration.
633  // For simple noise processing we will just pull out the max noise segment, we can
634  // use the maxBinNoiseFloor utility function for this. More elaborate noise window analysis
635  // will require a more complex algorithm, although you should get a lot of mileage out of
636  // this utility function.
637  bool bSignalInNoise{};
638 
639  std::tie(dNoiseFloordB,bSignalInNoise) =
640  Utils::maxBinNoiseFloor(window,frequencySegment.getRxPowerdBm());
641 
642  if(bSignalInNoise)
643  {
645  ERROR_LEVEL,
646  "MACI %03hu %s upstream EOR processing: spectrum service reporting signal in noise."
647  " This is an unallowable noise mode. Valid PHY noise modes are: none and outofband.",
648  id_,
649  pzLayerName);
650 
651  commonLayerStatistics_[u8Category]->processOutbound(pkt,
652  std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
653  DROP_CODE_BAD_CONTROL_INFO);
654 
655  return true;
656 
657  }
658 
659  }
660  catch(SpectrumServiceException & exp)
661  {
663  ERROR_LEVEL,
664  "MACI %03hu %s upstream EOR processing: spectrum service request error: %s",
665  id_,
666  pzLayerName,
667  exp.what());
668  commonLayerStatistics_[u8Category]->processOutbound(pkt,
669  std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
670  DROP_CODE_BAD_SPECTRUM_QUERY);
671  // drop
672  return true;
673  }
674 
675  handleUpstreamPacket(pkt,
676  frequencySegment.getRxPowerdBm(),
677  dNoiseFloordB,
678  u64SequenceNumber,
679  timeNow,
680  u8Category);
681 
682  return true;
683 
684  },pkt,commonMACHeader.getSequenceNumber(),u8Category);
685 
686 
687  auto eor = startOfReception + frequencySegments.begin()->getDuration();
688 
689  if(eor > timeNow)
690  {
691  // wait for end of reception to complete processing
692  pPlatformService_->timerService().schedule(callback,eor);
693  }
694  else
695  {
696  // we can process now, end of reception has past
697  callback();
698  }
699  }
700 }
701 
702 
703 void
704 EMANE::Models::IEEE80211ABG::MACLayer::handleUpstreamPacket(UpstreamPacket & pkt,
705  double dRxPowerdBm,
706  double dNoiseFloordBm,
707  std::uint64_t u64SequenceNumber,
708  const TimePoint & timeNow,
709  std::uint8_t u8Category)
710 {
711  size_t len{pkt.stripLengthPrefixFraming()};
712 
713  const PacketInfo & pktInfo{pkt.getPacketInfo()};
714 
715  if(len && pkt.length() >= len)
716  {
717  MACHeaderMessage ieeeMACHeader{pkt.get(), len};
718 
719  pkt.strip(len);
720 
721  MACHeaderParams macHeaderParams{ieeeMACHeader};
722 
723  double dRxPowermW{Utils::DB_TO_MILLIWATT(dRxPowerdBm)};
724 
725  // unicast cts ctrl
726  if(macHeaderParams.getMessageType() == MSG_TYPE_UNICAST_CTS_CTRL)
727  {
729  DEBUG_LEVEL,
730  "MACI %03hu %s::%s: cts pkt from %hu, mac seq %ju entry seq %hu",
731  id_,
732  pzLayerName,
733  __func__,
734  macHeaderParams.getSrcNEM(),
735  u64SequenceNumber,
736  macHeaderParams.getSequenceNumber());
737 
738  // update ctrl channel activity
739  neighborManager_.updateCtrlChannelActivity(macHeaderParams.getSrcNEM(), // src
740  macHeaderParams.getDstNEM(), // dst (origin)
741  macHeaderParams.getMessageType(), // msg type
742  dRxPowermW, // rx power
743  timeNow, // time
744  macHeaderParams.getDurationMicroseconds(), // duration
745  u8Category); // category
746 
747 
748  neighborMetricManager_.updateNeighborRxMetric(pktInfo.getSource(), // nbr (src)
749  u64SequenceNumber, // seq
750  pktInfo.getUUID(), // uuid
751  timeNow); // rx time
752 
753  // bump counter
754  macStatistics_.incrementUpstreamUnicastCtsRxFromPhy();
755 
756  // done with this cts pkt
757  return;
758  }
759  // unicast rts-cts data
760  else if((macHeaderParams.getMessageType() == MSG_TYPE_UNICAST_RTS_CTS_DATA))
761  {
762  // for this nem
763  if(macHeaderParams.getDstNEM() == id_)
764  {
765  // cts pkt info src is us, dst is broadcast, dscp is 0
766  PacketInfo ctsinfo{id_, NEM_BROADCAST_MAC_ADDRESS, 0, Clock::now()};
767 
768  DownstreamPacket ctsPkt{ctsinfo, nullptr, 0};
769 
770  DownstreamQueueEntry entry{ctsPkt,
771  timeNow,
772  macConfig_.getTxOpMicroseconds(0),
773  0,
774  0};
775 
776  entry.durationMicroseconds_ = macHeaderParams.getDurationMicroseconds();
777 
778  sendDownstreamUnicastCts(entry, macHeaderParams.getSrcNEM());
779  }
780 
781  // bump counter
783  }
784 
785  // get overhead if enabled
786  Microseconds overheadMicroseconds{ENABLE_WMM_OVERHEAD ?
787  modeTiming_.getOverheadMicroseconds(u8Category) :
788  Microseconds::zero()};
789 
790  // update data channel activity
791  neighborManager_.updateDataChannelActivity(macHeaderParams.getSrcNEM(), // src
792  macHeaderParams.getMessageType(), // msg type
793  dRxPowermW, // rx power
794  timeNow, // time
795  macHeaderParams.getDurationMicroseconds() + // duration
796  overheadMicroseconds,
797  u8Category); // categroy
798 
799 
800  if(ENABLE_TX_RETRY)
801  {
802  // check reception for collision and sinr
803  if(!checkUpstremReception(pkt,
804  timeNow,
805  u64SequenceNumber,
806  dRxPowerdBm,
807  dNoiseFloordBm,
808  macHeaderParams,
809  macHeaderParams.getNumRetries(),
810  u8Category).first)
811  {
813  DEBUG_LEVEL,
814  "MACI %03hu %s::%s: src %hu, dst %hu, reception failed, drop",
815  id_,
816  pzLayerName,
817  __func__,
818  macHeaderParams.getSrcNEM(),
819  macHeaderParams.getDstNEM());
820 
821  // drop
822  return;
823  }
824  }
825  else
826  {
827  // check for duplicate packet based on previous sender
828  if(isDuplicate(macHeaderParams.getSrcNEM(), macHeaderParams.getSequenceNumber()))
829  {
831  DEBUG_LEVEL,
832  "MACI %03hu %s::%s: duplicate pkt from %hu, entry seq %hu, drop",
833  id_,
834  pzLayerName,
835  __func__,
836  macHeaderParams.getSrcNEM(),
837  macHeaderParams.getSequenceNumber());
838 
839  commonLayerStatistics_[u8Category]->processOutbound(pkt,
840  std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
841  DROP_CODE_DUPLICATE);
842 
843  // drop
844  return;
845  }
846 
847  // assume failed
848  std::pair <bool, std::uint16_t> result{};
849 
850  int tryNum{};
851 
852  // check until retry limit reached or pkt passes
853  for(tryNum = 0; (tryNum <= macHeaderParams.getNumRetries()) && !result.first; ++tryNum)
854  {
855  // did the pkt pass
856  result = checkUpstremReception(pkt,
857  timeNow,
858  u64SequenceNumber,
859  dRxPowerdBm,
860  dNoiseFloordBm,
861  macHeaderParams,
862  tryNum,
863  u8Category);
864  if(result.first)
865  {
867  DEBUG_LEVEL, "MACI %03hu %s::%s: src %hu, dst %hu, reception passed, retires %d",
868  id_,
869  pzLayerName,
870  __func__,
871  macHeaderParams.getSrcNEM(),
872  macHeaderParams.getDstNEM(),
873  tryNum);
874  }
875  }
876 
877  if(!result.first)
878  {
880  DEBUG_LEVEL, "MACI %03hu %s::%s: src %hu, dst %hu, reception failed in %d tries",
881  id_,
882  pzLayerName,
883  __func__,
884  macHeaderParams.getSrcNEM(),
885  macHeaderParams.getDstNEM(),
886  tryNum);
887 
888  commonLayerStatistics_[u8Category]->processOutbound(pkt,
889  std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
890  result.second);
891 
892  // drop
893  return;
894  }
895  }
896 
897 
898 
899  // check dst
900  if(macHeaderParams.getDstNEM() != id_ && !isBroadcast(macHeaderParams.getDstNEM()))
901  {
902  if(!macConfig_.getPromiscuosEnable())
903  {
905  DEBUG_LEVEL,
906  "MACI %03hu %s::%s: nexthop %hu, not this nem, promiscous mode disabled, drop",
907  id_,
908  pzLayerName,
909  __func__,
910  macHeaderParams.getDstNEM());
911 
912  commonLayerStatistics_[u8Category]->processOutbound(
913  pkt,
914  std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
915  DROP_CODE_DST_MAC);
916 
917  // drop
918  return;
919  }
920  }
921 
922  commonLayerStatistics_[dscpToCategory(pkt.getPacketInfo().getPriority())]->
923  processOutbound(pkt,std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow));
924 
925  sendUpstreamPacket(pkt);
926 
928  DEBUG_LEVEL,
929  MACHeaderParamsFormatter(&macHeaderParams),
930  "MACI %03hu %s::%s: send upsream packet tx state %s",
931  id_,
932  pzLayerName,
933  __func__,
934  pTxState_->statename());
935 
936  }
937  else
938  {
940  ERROR_LEVEL,
941  "MACI %03hu %s::%s, malformed pkt, len %zd, prefix len %zd",
942  id_,
943  __func__,
944  pzLayerName,
945  pkt.length(),
946  len);
947  }
948 }
949 
950 
951 
952 std::pair<bool, std::uint16_t>
953 EMANE::Models::IEEE80211ABG::MACLayer::checkUpstremReception(UpstreamPacket & pkt,
954  const TimePoint & timeNow,
955  std::uint64_t u64SequenceNumber,
956  double dRxPowerdBm,
957  double dNoiseFloordBm,
958  const MACHeaderParams & rMACHeaderParams,
959  int tryNum,
960  std::uint8_t u8Category)
961 {
962  // get the noise floor in milli watts
963  double dNoiseFloorMilliWatts{Utils::DB_TO_MILLIWATT(dNoiseFloordBm)};
964 
965  double dNoiseFloorAdjustmentMilliWatts{};
966 
967  const PacketInfo & pktInfo{pkt.getPacketInfo()};
968 
969  // check for rx collision, use num retries from pkt
970  COLLISION_TYPE collisionType {checkForRxCollision(rMACHeaderParams.getSrcNEM(),
971  u8Category,
972  tryNum)};
973 
974  // clobbered rx during tx
975  if(collisionType & COLLISION_TYPE_CLOBBER_RX_DURING_TX)
976  {
978  DEBUG_LEVEL,
979  "MACI %03hu %s::%s: clobber rx during tx, drop",
980  id_,
981  pzLayerName,
982  __func__);
983 
984  // bump counter
985  isBroadcast(rMACHeaderParams.getDstNEM()) ?
988 
989  // drop
990  return std::pair<bool, std::uint16_t>(false, DROP_CODE_RX_DURING_TX);
991  }
992 
993  // clobbered rx hidden busy
994  if(collisionType & COLLISION_TYPE_CLOBBER_RX_HIDDEN_BUSY)
995  {
997  DEBUG_LEVEL,
998  "MACI %03hu %s::%s: clobber rx hidden busy, drop",
999  id_,
1000  pzLayerName,
1001  __func__);
1002 
1003  // bump counter
1004  isBroadcast(rMACHeaderParams.getDstNEM()) ?
1007 
1008  // drop
1009  return std::pair<bool, std::uint16_t>(false, DROP_CODE_RX_HIDDEN_BUSY);
1010  }
1011 
1012  // noise common rx
1013  if(collisionType & COLLISION_TYPE_NOISE_COMMON_RX)
1014  {
1015  // get random rx power common
1016  double dRandomNoiseMilliWatts{neighborManager_.getRandomRxPowerCommonNodesMilliWatts(pktInfo.getSource())};
1017 
1019  DEBUG_LEVEL,
1020  "MACI %03hu %s::%s: common rx noise, avg %3.2f, random %3.2f dBm of "
1021  "noise to noise floor %3.2f dBm",
1022  id_,
1023  pzLayerName,
1024  __func__,
1026  Utils::MILLIWATT_TO_DB(dRandomNoiseMilliWatts),
1027  Utils::MILLIWATT_TO_DB(dNoiseFloorMilliWatts));
1028 
1029  // adjust noise floor
1030  dNoiseFloorAdjustmentMilliWatts += dRandomNoiseMilliWatts;
1031 
1032  // bump counter
1033  isBroadcast(rMACHeaderParams.getDstNEM()) ?
1034  macStatistics_.incrementUpstreamBroadcastNoiseRxCommon() :
1035  macStatistics_.incrementUpstreamUnicastNoiseRxCommon();
1036  }
1037 
1038  // noise hidden rx
1039  if(collisionType & COLLISION_TYPE_NOISE_HIDDEN_RX)
1040  {
1041  // get random rx power hidden
1042  double dRandomNoiseMilliWatts{neighborManager_.getRandomRxPowerHiddenNodesMilliWatts(pktInfo.getSource())};
1043 
1045  DEBUG_LEVEL,
1046  "MACI %03hu %s::%s: hidden rx noise, avg %3.2f, random %3.2f, dBm of "
1047  "noise to noise floor %3.2f dBm",
1048  id_,
1049  pzLayerName,
1050  __func__,
1052  Utils::MILLIWATT_TO_DB(dRandomNoiseMilliWatts),
1053  Utils::MILLIWATT_TO_DB(dNoiseFloorMilliWatts));
1054  // adjust noise floor
1055  dNoiseFloorAdjustmentMilliWatts += dRandomNoiseMilliWatts;
1056 
1057  // bump counter
1058  isBroadcast(rMACHeaderParams.getDstNEM()) ?
1059  macStatistics_.incrementUpstreamBroadcastNoiseHiddenRx() :
1060  macStatistics_.incrementUpstreamUnicastNoiseHiddenRx();
1061  }
1062 
1063  double dNoiseFloorAdjusteddBm{Utils::MILLIWATT_TO_DB(dNoiseFloorMilliWatts + dNoiseFloorAdjustmentMilliWatts)};
1064 
1065  // check sinr for this pkt
1066  if(!checkPOR(dRxPowerdBm - dNoiseFloorAdjusteddBm, pkt.length(), rMACHeaderParams.getDataRateIndex()))
1067  {
1069  DEBUG_LEVEL,
1070  "MACI %03hu %s::%s: rxpwr %3.2f dBm, adjusted noise floor %3.2f dBm, datarate %hu, drop",
1071  id_,
1072  pzLayerName,
1073  __func__,
1074  dRxPowerdBm,
1075  dNoiseFloorAdjusteddBm,
1076  rMACHeaderParams.getDataRateIndex());
1077 
1078  // bump counter
1079  isBroadcast(rMACHeaderParams.getDstNEM()) ?
1082 
1083  // drop
1084  return std::pair<bool, std::uint16_t>(false, DROP_CODE_SINR);
1085  }
1086  else
1087  {
1088  double dSINR{dRxPowerdBm - dNoiseFloorAdjusteddBm};
1089 
1091  DEBUG_LEVEL,
1092  "MACI %03hu %s::%s: rxpwr %3.2f dBm, adjusted noise floor %3.2f dBm, sinr %3.2f, datarate %hu, pass",
1093  id_,
1094  pzLayerName,
1095  __func__,
1096  dRxPowerdBm,
1097  dNoiseFloorAdjusteddBm,
1098  dSINR,
1099  rMACHeaderParams.getDataRateIndex());
1100 
1101  neighborMetricManager_.updateNeighborRxMetric(
1102  pktInfo.getSource(), // nbr (src)
1103  u64SequenceNumber, // seq
1104  pktInfo.getUUID(), // uuid
1105  dSINR, // sinr
1106  dNoiseFloorAdjusteddBm, // noise floor in dBm
1107  timeNow, // rx time
1108  rMACHeaderParams.getDurationMicroseconds(), // duration
1109  rMACHeaderParams.getMessageType() == MSG_TYPE_BROADCAST_DATA ? // data rate bps
1110  macConfig_.getBroadcastDataRateKbps(rMACHeaderParams.getDataRateIndex()) * 1000ULL :
1111  macConfig_.getUnicastDataRateKbps(rMACHeaderParams.getDataRateIndex()) * 1000ULL);
1112 
1113  // pass
1114  return std::pair<bool, std::uint16_t>(true, {});
1115  }
1116 }
1117 
1118 
1119 
1120 void
1122  const ControlMessages &)
1123 {
1124  TimePoint timeNow{Clock::now()};
1125 
1126  const PacketInfo & pktInfo{pkt.getPacketInfo()};
1127 
1128  std::uint8_t u8Category{dscpToCategory(pktInfo.getPriority())};
1129 
1130  commonLayerStatistics_[u8Category]->processInbound(pkt);
1131 
1132  if(!removeToken())
1133  {
1134  commonLayerStatistics_[u8Category]->processOutbound(
1135  pkt,
1136  std::chrono::duration_cast<Microseconds>(Clock::now() - timeNow),
1137  DROP_CODE_FLOW_CONTROL_ERROR);
1138 
1139  // drop
1140  return;
1141  }
1142 
1143  std::uint8_t u8Retries{isBroadcast(pktInfo.getDestination()) ?
1144  std::uint8_t{} : macConfig_.getRetryLimit(u8Category)};
1145 
1146  // this moves pkt, making it invalid, use entry.pkt_ from now on
1147  DownstreamQueueEntry entry{pkt,
1148  timeNow,
1149  macConfig_.getTxOpMicroseconds(u8Category),
1150  u8Category,
1151  u8Retries};
1152 
1153  // check rts cts enable
1154  if((macConfig_.getRtsThreshold() != 0) &&(macConfig_.getRtsThreshold() <= entry.pkt_.length()))
1155  {
1156  // set rts cts flag
1157  entry.bRtsCtsEnable_ = true;
1158  }
1159 
1160  if(bHasPendingDownstreamQueueEntry_)
1161  {
1162  std::vector<DownstreamQueueEntry> result{downstreamQueue_.enqueue(entry)};
1163 
1164  // check for discarded
1165  for(auto & iter : result)
1166  {
1167  commonLayerStatistics_[u8Category]->
1168  processOutbound(iter.pkt_,
1169  std::chrono::duration_cast<Microseconds>(Clock::now() - iter.acquireTime_),
1170  DROP_CODE_QUEUE_OVERFLOW);
1171 
1172  // drop, replace token
1173  addToken();
1174  }
1175 
1176  // check to see if a packet can be sent
1177  if(currentEndOfTransmissionTime_ <= Clock::now())
1178  {
1179  handleDownstreamQueueEntry(u64SequenceNumber_);
1180  }
1181  }
1182  else
1183  {
1184  bHasPendingDownstreamQueueEntry_ = true;
1185 
1186  pendingDownstreamQueueEntry_ = std::move(entry);
1187 
1188  auto optionalWait = pTxState_->getWaitTime(pendingDownstreamQueueEntry_);
1189 
1190  if(optionalWait.second)
1191  {
1192  downstreamQueueTimedEventId_ =
1194  schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1195  this,
1196  u64SequenceNumber_),
1197  optionalWait.first);
1198  }
1199  else
1200  {
1201  handleDownstreamQueueEntry(u64SequenceNumber_);
1202  }
1203  }
1204 }
1205 
1206 
1207 
1208 
1209 void
1211  const Serialization & serialization)
1212 {
1214  DEBUG_LEVEL,
1215  "MACI %03hu %s::%s: event id %hu",
1216  id_,
1217  pzLayerName,
1218  __func__,
1219  eventId);
1220 
1221  // check event id
1222  switch(eventId)
1223  {
1225  {
1226  // the nbr manager knows how to handle these
1227  neighborManager_.handleOneHopNeighborsEvent(serialization);
1228  }
1229  break;
1230  }
1231 
1232  // no other events to be handled
1233 }
1234 
1235 
1236 void
1238 {
1239  setEntrySequenceNumber(entry);
1240 
1241  // check retry logic enable
1242  std::uint8_t numRetries{ENABLE_TX_RETRY ? entry.numRetries_ : std::uint8_t{}};
1243 
1244  MACHeaderParams macHeaderParams{MSG_TYPE_BROADCAST_DATA, // msg type
1245  numRetries, // num retries
1246  macConfig_.getBroadcastDataRateIndex(), // data rate
1247  entry.u16Seq_, // sequence number
1248  id_, // src
1249  entry.pkt_.getPacketInfo().getDestination(), // dst
1250  entry.durationMicroseconds_}; // duration
1251 
1252 
1253  entry.u64DataRatebps_ = macConfig_.getBroadcastDataRateKbps() * 1000ULL;
1254 
1255  sendDownstreamMessage(entry, macHeaderParams);
1256 }
1257 
1258 
1259 
1260 
1261 void
1263 {
1264  setEntrySequenceNumber(entry);
1265 
1266  // check retry logic enable
1267  std::uint8_t numRetries{ENABLE_TX_RETRY ? entry.numRetries_ : entry.maxRetries_};
1268 
1269  MACHeaderParams macHeaderParams{entry.bRtsCtsEnable_ ?
1271  MSG_TYPE_UNICAST_DATA, // msg type
1272  numRetries, // num retries
1273  macConfig_.getUnicastDataRateIndex(), // data rate index
1274  entry.u16Seq_, // sequence number
1275  id_, // src
1276  entry.pkt_.getPacketInfo().getDestination(), // dst
1277  entry.durationMicroseconds_}; // duration
1278 
1279  entry.u64DataRatebps_ = macConfig_.getUnicastDataRateKbps() * 1000ULL;
1280 
1281  // send msg
1282  sendDownstreamMessage(entry, macHeaderParams);
1283 }
1284 
1285 
1286 
1287 void
1289 {
1290  setEntrySequenceNumber(entry);
1291 
1292  // check retry logic enable
1293  std::uint8_t numRetries{ENABLE_TX_RETRY ? entry.numRetries_ : entry.maxRetries_};
1294 
1295  MACHeaderParams macHeaderParams{MSG_TYPE_UNICAST_CTS_CTRL, // msg type
1296  numRetries, // num retries
1297  macConfig_.getUnicastDataRateIndex(), // data rate index
1298  entry.u16Seq_, // sequence number
1299  id_, // src
1300  origin, // dst is the origin
1301  entry.durationMicroseconds_}; // duration
1302 
1303  // reset duration for cts message
1304  entry.durationMicroseconds_ = Microseconds::zero();
1305 
1306  entry.u64DataRatebps_ = macConfig_.getUnicastDataRateKbps() * 1000ULL;
1307 
1309  DEBUG_LEVEL,
1310  MACHeaderParamsFormatter(&macHeaderParams),
1311  "MACI %03hu %s::%s",
1312  id_,
1313  pzLayerName,
1314  __func__);
1315 
1316  // send msg
1317  sendDownstreamMessage(entry, macHeaderParams);
1318 }
1319 
1320 
1321 
1322 void
1324  MACHeaderParams & rMACHeaderParams)
1325 {
1326  TimePoint currentTime{Clock::now()};
1327 
1328  // get overhead if enabled
1329  Microseconds overheadMicroseconds{ENABLE_WMM_OVERHEAD ?
1330  modeTiming_.getOverheadMicroseconds(entry.u8Category_) :
1331  Microseconds::zero()};
1332 
1333 
1334  // update channel activity(self nem)
1335  neighborManager_.updateDataChannelActivity(id_, // id
1336  rMACHeaderParams.getMessageType(), // msg type
1337  0.0f, // rx power (don't include our pwr)
1338  currentTime, // current time
1339  entry.durationMicroseconds_ + overheadMicroseconds, // duration
1340  entry.u8Category_); // category
1341 
1342 
1343 
1344  // update queue metrics
1345  queueMetricManager_.updateQueueMetric(entry.u8Category_, // queue id
1346  downstreamQueue_.getMaxCapacity(entry.u8Category_), // max queue size
1347  downstreamQueue_.getDepth(entry.u8Category_), // current queue depth
1348  downstreamQueue_.getNumOverFlow(entry.u8Category_, true), // queue discards (clear counter)
1349  std::chrono::duration_cast<Microseconds>
1350  (currentTime - entry.acquireTime_)); // time in queue
1351 
1352  // update nbr tx metrics
1353  neighborMetricManager_.updateNeighborTxMetric(entry.pkt_.getPacketInfo().getDestination(), // dst
1354  entry.u64DataRatebps_, // data rate bps
1355  currentTime); // current time
1356 
1357 
1358  MACHeaderMessage ieeeMACHeader{rMACHeaderParams.getMessageType(), // msg type
1359  rMACHeaderParams.getNumRetries(), // num retries
1360  rMACHeaderParams.getDataRateIndex(), // data rate
1361  rMACHeaderParams.getSequenceNumber(), // sequence number
1362  rMACHeaderParams.getSrcNEM(), // src
1363  rMACHeaderParams.getDstNEM(), // dst
1364  rMACHeaderParams.getDurationMicroseconds()}; // duration
1365 
1366  Serialization serialization{ieeeMACHeader.serialize()};
1367 
1368  // prepend mac header to outgoing packet
1369  entry.pkt_.prepend(serialization.c_str(), serialization.size());
1370 
1371  // next prepend the serialization length
1372  entry.pkt_.prependLengthPrefixFraming(serialization.size());
1373 
1374  commonLayerStatistics_[entry.u8Category_]->
1375  processOutbound(entry.pkt_,
1376  std::chrono::duration_cast<Microseconds>(Clock::now() - entry.acquireTime_),
1377  rMACHeaderParams.getMessageType() == MSG_TYPE_UNICAST_CTS_CTRL);
1378 
1379  // send the packet
1380  sendDownstreamPacket(CommonMACHeader{registrationId_, u64SequenceNumber_++},
1381  entry.pkt_,
1383  0, // bandwidth (0 uses phy default)
1384  {{0,rMACHeaderParams.getDurationMicroseconds()}}), // freq (0 uses phy default)
1386 
1387  currentEndOfTransmissionTime_ = currentTime + entry.durationMicroseconds_ + overheadMicroseconds;
1388 }
1389 
1390 
1391 
1392 
1400 void
1401 EMANE::Models::IEEE80211ABG::MACLayer::changeDownstreamState(TransmissionTxState * pState)
1402 {
1404  DEBUG_LEVEL,
1405  "MACI %03hu %s::%s: %s => %s",
1406  id_,
1407  pzLayerName,
1408  __func__,
1409  pTxState_->statename(),
1410  pState->statename());
1411 
1412  // change state
1413  pTxState_ = pState;
1414 }
1415 
1416 
1417 
1418 
1421 {
1422  return id_;
1423 }
1424 
1425 
1426 
1427 
1428 void
1430 {
1431  // get current time
1432  TimePoint timeNow{Clock::now()};
1433 
1434  // estimated number of one hop nbrs
1435  float fNumEstimatedOneHopNeighbors{neighborManager_.getNumberOfEstimatedOneHopNeighbors()};
1436 
1437  // estimated number of two hop nbrs
1438  float fNumEstimatedTwoHopNeighbors{neighborManager_.getNumberOfEstimatedTwoHopNeighbors()};
1439 
1440  // estimated number of one and two hop nbrs
1441  float fNumEstimatedOneAndTwoHopNeighbors{fNumEstimatedOneHopNeighbors + fNumEstimatedTwoHopNeighbors};
1442 
1443  // total one and two hop utilization
1444  Microseconds totalOneAndTwoHopUtilizationMicroseconds {neighborManager_.getTotalOneHopUtilizationMicroseconds() +
1445  neighborManager_.getTotalTwoHopUtilizationMicroseconds()};
1446 
1447  // get hidden channel activity
1448  float fHiddenChannelActivity{neighborManager_.getHiddenChannelActivity(entry.pkt_.getPacketInfo().getDestination())};
1449 
1450  // avg msg duration this is for one hops nbrs
1451  Microseconds averageMessageDurationMicroseconds{neighborManager_.getAverageMessageDurationMicroseconds()};
1452 
1453  // activity timer interval
1455 
1456  // amount of additional delay(if required)
1457  float X2{RNDZeroToOne_()};
1458 
1459  // get the contention window
1460  int iCW{modeTiming_.getContentionWindow(entry.u8Category_, entry.numRetries_)};
1461 
1462  // set initial pre delay
1463  Microseconds preDelayMicroseconds{};
1464 
1465  // set the initial post delay
1466  Microseconds postDelayMicroseconds{};
1467 
1468  // check number of estimated one and two hop nbrs
1469  if(fNumEstimatedOneAndTwoHopNeighbors > 1)
1470  {
1471  // calcuating excess overhead per neighbor in excess of 2 for the estimated average message duration
1472  Microseconds messageDurationOverheadExtraMicroseconds{
1473  static_cast<Microseconds::rep>((fNumEstimatedOneAndTwoHopNeighbors - 2.0f) *
1474  ((iCW * modeTiming_.getSlotSizeMicroseconds().count()) / 2.0f))};
1475 
1476  // probability of additional deley required
1477  float X1{RNDZeroToOne_()};
1478 
1479  float fDelayTimeFactor{getRatio(totalOneAndTwoHopUtilizationMicroseconds, deltaT)};
1480 
1481  if(fDelayTimeFactor > 1)
1482  {
1483  fDelayTimeFactor = 1;
1484  }
1485 
1486  if(X1 <= fDelayTimeFactor)
1487  {
1488  // get pre delay
1489  auto nodeDelayMicroseconds =
1490  Microseconds{static_cast<Microseconds::rep>(floorf(X2 * fNumEstimatedOneAndTwoHopNeighbors))};
1491 
1492  // add to the pre dealy
1493  preDelayMicroseconds +=
1494  Microseconds{nodeDelayMicroseconds.count() * averageMessageDurationMicroseconds.count()};
1495 
1496  if(preDelayMicroseconds > messageDurationOverheadExtraMicroseconds)
1497  {
1498  // remove the overhead
1499  preDelayMicroseconds -= messageDurationOverheadExtraMicroseconds;
1500  }
1501  }
1502 
1503  // set post delay
1504  postDelayMicroseconds =
1505  Microseconds{static_cast<Microseconds::rep>(powf(fDelayTimeFactor, 2.0f) *
1506  (fNumEstimatedOneAndTwoHopNeighbors - 1.0f) *
1507  averageMessageDurationMicroseconds.count())};
1508 
1509  if(postDelayMicroseconds > preDelayMicroseconds)
1510  {
1511  postDelayMicroseconds -= preDelayMicroseconds;
1512  }
1513  else
1514  {
1515  postDelayMicroseconds = Microseconds::zero();
1516  }
1517 
1518  postDelayMicroseconds += averageMessageDurationMicroseconds;
1519  }
1520 
1521  // add defer time to pre delay
1522  preDelayMicroseconds += modeTiming_.getDeferIntervalMicroseconds(entry.u8Category_);
1523 
1524  // initial set flag that collision will not occur
1525  entry.bCollisionOccured_ = false;
1526 
1527  // check tx retry enable
1528  if(!ENABLE_TX_RETRY)
1529  {
1530  // probability of tx collision
1531  float X3{RNDZeroToOne_()};
1532 
1533  float A{neighborManager_.getLocalNodeTx()};
1534 
1535  Microseconds totalOneHopUtilizationMicroseconds{neighborManager_.getTotalOneHopUtilizationMicroseconds()};
1536 
1537  Microseconds localUtilizationMicroseconds{neighborManager_.getAllUtilizationMicroseconds(id_)};
1538 
1539  Microseconds remoteUtilizationMicroseconds{neighborManager_.getAllUtilizationMicroseconds(
1540  entry.pkt_.getPacketInfo().getDestination())};
1541 
1543 
1544  float fUtilizationFactorAdjusted{getRatio((totalOneHopUtilizationMicroseconds -
1545  localUtilizationMicroseconds -
1546  remoteUtilizationMicroseconds), deltaT)};
1547 
1548  // bump adjusted utilization
1549  if(fUtilizationFactorAdjusted > 1.0f)
1550  {
1551  fUtilizationFactorAdjusted = 1.0f;
1552  }
1553 
1554  float fPreTran = (fUtilizationFactorAdjusted * fUtilizationFactorAdjusted) *
1555  (1.0 - A) * (fNumEstimatedOneHopNeighbors / iCW);
1556 
1557  // check probability
1558  if(X3 < fPreTran)
1559  {
1560  // set flag that collision will occur
1561  entry.bCollisionOccured_ = true;
1562  }
1563  else
1564  {
1565  // probability of hidden collision
1566  float X4{RNDZeroToOne_()};
1567 
1568  // C2
1569  float C2{0.1f};
1570 
1571  float H{fHiddenChannelActivity - C2};
1572 
1573  // clamp low
1574  if(H < 0.0f)
1575  {
1576  H = 0.0f;
1577  }
1578  // clamp high
1579  else if(H >(1.0f - C2))
1580  {
1581  H =(1.0f - C2);
1582  }
1583 
1584  // check probability
1585  if(X4 < H)
1586  {
1587  // set flag that collision will occur
1588  entry.bCollisionOccured_ = true;
1589  }
1590  }
1591  }
1592 
1593  // set pre delay time
1594  entry.preTxDelayTime_ = timeNow + preDelayMicroseconds;
1595 
1596  // set post delay duration
1597  entry.postTxDelayMicroseconds_ = postDelayMicroseconds;
1598 
1600  DEBUG_LEVEL,
1601  "MACI %03hu %s::%s: est nbrs 1 hop %3.2f, "
1602  "2 hop %3.2f, bw %lf, avg duration %lf,"
1603  " pre delay %lf, post delay %lf, tx collision %s",
1604  id_,
1605  pzLayerName,
1606  __func__,
1607  fNumEstimatedOneHopNeighbors,
1608  fNumEstimatedTwoHopNeighbors,
1609  std::chrono::duration_cast<DoubleSeconds>(totalOneAndTwoHopUtilizationMicroseconds).count(),
1610  std::chrono::duration_cast<DoubleSeconds>(averageMessageDurationMicroseconds).count(),
1611  std::chrono::duration_cast<DoubleSeconds>(preDelayMicroseconds).count(),
1612  std::chrono::duration_cast<DoubleSeconds>(postDelayMicroseconds).count(),
1613  entry.bCollisionOccured_ ? "true" : "false");
1614 }
1615 
1616 
1617 
1618 
1620 EMANE::Models::IEEE80211ABG::MACLayer::checkForRxCollision(NEMId src, std::uint8_t u8Category, std::uint8_t u8Retries)
1621 {
1622  int collisionStatus{COLLISION_TYPE_NONE};
1623 
1624  WMMManager::UtilizationRatioVector utilizationRatioVector{neighborManager_.getUtilizationRatios()};
1625 
1626  CWRatioVector cwMinVector{macConfig_.getCWMinRatioVector(u8Category)};
1627 
1628  float fNumEstimatedOneHopNeighbors{neighborManager_.getNumberOfEstimatedOneHopNeighbors()};
1629 
1630  float fNumEstimatedCommonNeighbors{neighborManager_.getNumberOfEstimatedCommonNeighbors(src)};
1631 
1632  float fHiddenChannelActivity{neighborManager_.getHiddenChannelActivity(src)};
1633 
1634  Microseconds totalOneHopUtilizationMicroseconds{neighborManager_.getTotalOneHopUtilizationMicroseconds()};
1635 
1636  Microseconds localUtilizationMicroseconds{neighborManager_.getAllUtilizationMicroseconds(id_)};
1637 
1638  Microseconds remoteUtilizationMicroseconds{neighborManager_.getAllUtilizationMicroseconds(src)};
1639 
1641 
1642  float fUtilizationFactorAdjusted{getRatio((totalOneHopUtilizationMicroseconds -
1643  localUtilizationMicroseconds -
1644  remoteUtilizationMicroseconds), deltaT)};
1645 
1646  float fUtilizationFactorActual{getRatio(totalOneHopUtilizationMicroseconds, deltaT)};
1647 
1648  float A{neighborManager_.getLocalNodeTx()};
1649 
1650  float X1{RNDZeroToOne_()};
1651 
1652  float X2{RNDZeroToOne_()};
1653 
1654  float X3{RNDZeroToOne_()};
1655 
1656  int iCW{modeTiming_.getContentionWindow(u8Category, u8Retries)};
1657 
1658  float C1{};
1659 
1660  float P1{}, P2{}, P3{}, P4{}, PP1{}, PP2{};
1661 
1662  // bump adjusted utilization
1663  if(fUtilizationFactorAdjusted > 1.0f)
1664  {
1665  fUtilizationFactorAdjusted = 1.0f;
1666  }
1667 
1668  // cap actual utilization
1669  if(fUtilizationFactorActual > 1.0f)
1670  {
1671  fUtilizationFactorActual = 1.0f;
1672  }
1673 
1674  // check for estimated nbrs
1675  if(fNumEstimatedOneHopNeighbors > 0.0f)
1676  {
1677  P1 = fUtilizationFactorAdjusted * fUtilizationFactorAdjusted * A *(fNumEstimatedOneHopNeighbors / iCW);
1678 
1679  if(X1 < P1)
1680  {
1681  // set rx during tx collision clobber, no need to continue
1683  }
1684  }
1685 
1686  // check for estimated nbrs
1687  if(fNumEstimatedOneHopNeighbors > 0.0f)
1688  {
1689  for(size_t u8Category = 0; u8Category < macConfig_.getNumAccessCategories(); ++u8Category)
1690  {
1691  // sum the products of local_bw_utilization * cw_min_ratio / cw_min
1692  PP1 += utilizationRatioVector[u8Category].second * cwMinVector[u8Category] / macConfig_.getCWMin(u8Category);
1693 
1695  DEBUG_LEVEL,
1696  "MACI %03hu %s::%s: idx %zu, PP1 %4.3f, LBWU %4.3f, CWMINR %3.2f, CWMIN %hhu",
1697  id_,
1698  pzLayerName,
1699  __func__,
1700  u8Category,
1701  PP1,
1702  utilizationRatioVector[u8Category].second,
1703  cwMinVector[u8Category],
1704  macConfig_.getCWMin(u8Category));
1705  }
1706 
1707  P1 = fUtilizationFactorActual * fUtilizationFactorActual * PP1;
1708 
1709  if(X1 < P1)
1710  {
1711  // set rx during tx collision clobber, no need to continue
1713  }
1714  }
1715 
1716 
1717  // check for hidden channel activity
1718  if(fHiddenChannelActivity > 0.0f)
1719  {
1720  fUtilizationFactorActual = 1.0f + log10f(fUtilizationFactorActual);
1721 
1722  float fBWDelta{fUtilizationFactorActual - (2.0f * fHiddenChannelActivity)};
1723 
1724  if(fBWDelta < 0.0f)
1725  {
1726  fBWDelta = 0.0f;
1727  }
1728 
1729  P3 = 1.0f - fUtilizationFactorActual + fBWDelta + C1;
1730 
1731  if(X2 > P3)
1732  {
1733  P4 = 0.5f;
1734 
1735  if(X3 < P4)
1736  {
1737  // set hidden rx noise
1738  collisionStatus |= COLLISION_TYPE_NOISE_HIDDEN_RX;
1739  }
1740  else
1741  {
1742  // set rx hidden busy clobber, no need to continue
1744  }
1745  }
1746  }
1747 
1748 
1749  // check for estimated common nbrs
1750  if(fNumEstimatedCommonNeighbors > 2.0f)
1751  {
1752  if(iCW > fNumEstimatedCommonNeighbors)
1753  {
1754  for(size_t u8Category = 0; u8Category < macConfig_.getNumAccessCategories(); ++u8Category)
1755  {
1756  // sum the products of total_bw_utilization * cw_min_ratio / cw_min
1757  PP2 += utilizationRatioVector[u8Category].first * cwMinVector[u8Category] / macConfig_.getCWMin(u8Category);
1758 
1760  DEBUG_LEVEL,
1761  "MACI %03hu %s::%s: idx %zu, PP2 %4.3f, TBWU %4.3f, CWMINR %3.2f, CWMIN %hhu",
1762  id_,
1763  pzLayerName,
1764  __func__,
1765  u8Category,
1766  PP2,
1767  utilizationRatioVector[u8Category].first,
1768  cwMinVector[u8Category],
1769  macConfig_.getCWMin(u8Category));
1770  }
1771 
1772  P2 = fUtilizationFactorAdjusted * fUtilizationFactorAdjusted * (fNumEstimatedCommonNeighbors - 2) * PP2;
1773  }
1774  else
1775  {
1776  P2 = 1.0f;
1777  }
1778 
1779  if(P2 >= X1)
1780  {
1781  // set common rx noise
1782  collisionStatus |= COLLISION_TYPE_NOISE_COMMON_RX;
1783  }
1784  }
1785 
1786 
1788  DEBUG_LEVEL, "MACI %03hu %s::%s: src %hu, nbrs [active %zd, est %5.3f, common %5.3f, hidden %5.3f]"
1789  " hidden activity %5.3f, utilization factor [actual %5.3f, adjusted %5.3f "
1790  "utilization [one hop %lf, local %lf, remote %lf] "
1791  "CW %d, X1 %5.3f, X2 %5.3f, X3 %5.3f, C1 %5.3f, P1 %5.3f, P2 %5.3f, P3 %5.3f P4 %5.3f, "
1792  "PP1 %5.3f, PP2 %5.3f, 0x%02X",
1793  id_, pzLayerName, __func__,
1794  src,
1795  neighborManager_.getTotalActiveOneHopNeighbors(),
1796  fNumEstimatedOneHopNeighbors,
1797  fNumEstimatedCommonNeighbors,
1798  neighborManager_.getNumberOfEstimatedHiddenNeighbors(src),
1799  fHiddenChannelActivity,
1800  fUtilizationFactorActual,
1801  fUtilizationFactorAdjusted,
1802  std::chrono::duration_cast<DoubleSeconds>(totalOneHopUtilizationMicroseconds).count(),
1803  std::chrono::duration_cast<DoubleSeconds>(localUtilizationMicroseconds).count(),
1804  std::chrono::duration_cast<DoubleSeconds>(remoteUtilizationMicroseconds).count(),
1805  iCW, X1, X2, X3, C1, P1, P2, P3, P4, PP1, PP2, collisionStatus);
1806 
1807  return static_cast<COLLISION_TYPE>(collisionStatus);
1808 }
1809 
1810 
1811 bool EMANE::Models::IEEE80211ABG::MACLayer::handleDownstreamQueueEntry(std::uint64_t u64SequenceNumber)
1812 {
1813  if(u64SequenceNumber == u64SequenceNumber_)
1814  {
1815  // there are two ways to end processing: schedule a timer or have no
1816  // other packets in the downstream queue once you finish processing
1817  // the pending packet
1818  while(bHasPendingDownstreamQueueEntry_)
1819  {
1820  // if there is no further processing for the pending packet
1821  // update the state and see if there is another packet
1822  // pending
1823  if(!pTxState_->process(this,pendingDownstreamQueueEntry_))
1824  {
1825  pTxState_->update(this,pendingDownstreamQueueEntry_);
1826 
1827  std::tie(pendingDownstreamQueueEntry_,bHasPendingDownstreamQueueEntry_) =
1828  downstreamQueue_.dequeue();
1829 
1830  addToken();
1831  }
1832 
1833  // if something is pending we need to schedule it - this could be the
1834  // same packet entry that we began with
1835  if(bHasPendingDownstreamQueueEntry_)
1836  {
1837  auto optionalWait = pTxState_->getWaitTime(pendingDownstreamQueueEntry_);
1838 
1839  if(optionalWait.second && optionalWait.first > Clock::now())
1840  {
1841  downstreamQueueTimedEventId_ =
1843  schedule(std::bind(&MACLayer::handleDownstreamQueueEntry,
1844  this,
1845  u64SequenceNumber_),
1846  optionalWait.first);
1847 
1848  // we are finished handling the queue entry (for now)
1849  break;
1850  }
1851  }
1852  }
1853  }
1854 
1855  // delete after executing
1856  return true;
1857 }
1858 
1859 
1860 bool
1862 {
1863  TimePoint timeNow {Clock::now()};
1864 
1865  size_t historySize{16};
1866 
1867  // entry valid interval 5 seconds
1868  Microseconds vaildIntervalMicroseconds{std::chrono::seconds{5}};
1869 
1870  auto dupIter = duplicateMap_.find(src);
1871 
1872  if(dupIter == duplicateMap_.end())
1873  {
1874  SequenceVector v{};
1875 
1876  v.reserve(historySize);
1877 
1878  v.push_back(SequenceEntry(seq, timeNow));
1879 
1880  duplicateMap_.insert(std::make_pair(src, v));
1881 
1882  // not a duplicate
1883  return false;
1884  }
1885  else
1886  {
1887  // oldest index
1888  size_t oldestIndex{};
1889 
1890  // oldest time starts as current time
1891  TimePoint oldestTime{timeNow};
1892 
1893  for(size_t idx = 0; idx < dupIter->second.size(); ++idx)
1894  {
1895  if(dupIter->second.at(idx).seq_ == seq)
1896  {
1897  // within the time window
1898  if((dupIter->second.at(idx).tp_ + vaildIntervalMicroseconds) >= timeNow)
1899  {
1900  // is duplicate
1901  return true;
1902  }
1903  else
1904  {
1905  // update entry
1906  dupIter->second.at(idx) = SequenceEntry(seq, timeNow);
1907 
1908  // not a duplicate
1909  return false;
1910  }
1911  }
1912  // no match
1913  else
1914  {
1915  // check entry age
1916  if(dupIter->second.at(idx).tp_ < oldestTime)
1917  {
1918  // new oldest time
1919  oldestTime = dupIter->second.at(idx).tp_;
1920 
1921  // new oldest index
1922  oldestIndex = idx;
1923  }
1924  }
1925  }
1926 
1927  if(dupIter->second.size() < historySize)
1928  {
1929  // add entry
1930  dupIter->second.push_back(SequenceEntry(seq, timeNow));
1931  }
1932  else
1933  {
1934  // replace entry
1935  dupIter->second.at(oldestIndex) = SequenceEntry(seq, timeNow);
1936  }
1937 
1938  // not a duplicate
1939  return false;
1940  }
1941 }
1942 
1943 
1944 
1945 bool
1947 {
1948  if(macConfig_.getFlowControlEnable())
1949  {
1950  auto status = flowControlManager_.addToken();
1951 
1952  if(!status.second)
1953  {
1955  ERROR_LEVEL,
1956  "MACI %03hu %s::%s: failed to add token (tokens:%hu)",
1957  id_,
1958  pzLayerName,
1959  __func__,
1960  status.first);
1961 
1962  // failed
1963  return false;
1964  }
1965  }
1966 
1967  // success
1968  return true;
1969 }
1970 
1971 
1972 
1973 bool
1975 {
1976  if(macConfig_.getFlowControlEnable())
1977  {
1978  auto status = flowControlManager_.removeToken();
1979 
1980  if(!status.second)
1981  {
1983  ERROR_LEVEL,
1984  "MACI %03hu %s::%s: failed to remove token (tokens:%hu)",
1985  id_,
1986  pzLayerName,
1987  __func__,
1988  status.first);
1989 
1990 
1991  // failed
1992  return false;
1993  }
1994  }
1995 
1996  // success
1997  return true;
1998 }
1999 
2000 
2001 
2002 bool
2003 EMANE::Models::IEEE80211ABG::MACLayer::checkPOR(float fSINR, size_t packetSize, std::uint16_t u16DataRateIndex)
2004 {
2005  // find pcr
2006  float fPCR{pcrManager_.getPCR(fSINR, packetSize, u16DataRateIndex)};
2007 
2008  // random value from 0.0 to 1.0 inclusive
2009  float fRandom{RNDZeroToOne_()};
2010 
2011  // pcr >= random value
2012  bool bResult{fPCR >= fRandom};
2013 
2015  DEBUG_LEVEL,
2016  "MACI %03hu %s::%s: sinr %3.2f, pcr %3.2f %s rand %3.3f",
2017  id_,
2018  pzLayerName,
2019  __func__,
2020  fSINR,
2021  fPCR,
2022  bResult ? ">=" : "<",
2023  fRandom);
2024 
2025  // return result
2026  return bResult;
2027 }
2028 
2029 
2030 
2031 std::uint8_t
2032 EMANE::Models::IEEE80211ABG::MACLayer::dscpToCategory(std::uint8_t dscp) const
2033 {
2034  // default value is 0
2035  std::uint8_t u8Category{};
2036 
2037  if(macConfig_.getWmmEnable())
2038  {
2039  // with WMM, map the 4 access categories to different queues
2040  if(dscp >= 8 && dscp <= 23)
2041  {
2042  u8Category = 1;
2043  }
2044  else if(dscp >= 32 && dscp <= 47)
2045  {
2046  u8Category = 2;
2047  }
2048  else if(dscp >= 48 && dscp <= 63)
2049  {
2050  u8Category = 3;
2051  }
2052  }
2053 
2055  DEBUG_LEVEL,
2056  "MACI %03hu %s::%s: wmm %s, dscp %hhu, category %hhu",
2057  id_,
2058  pzLayerName,
2059  __func__,
2060  (macConfig_.getWmmEnable() ? "on" : "off"),
2061  dscp,
2062  u8Category);
2063 
2064  return u8Category;
2065 }
2066 
2067 
2068 
2071 {
2072  return macStatistics_;
2073 }
2074 
2075 
2076 
2079 {
2080  return modeTiming_;
2081 }
2082 
2083 void
2084 EMANE::Models::IEEE80211ABG::MACLayer::setEntrySequenceNumber(DownstreamQueueEntry &entry)
2085 {
2086  // set sequence number on first try, else retain current seq number
2087  if(entry.numRetries_ == 0)
2088  {
2089  entry.u16Seq_ = u16EntrySequenceNumber_++;
2090  }
2091 }
2092 
bool configure(const ConfigurationUpdate &update)
Definition: macconfig.cc:1008
void sendDownstreamUnicastData(DownstreamQueueEntry &entry)
void incrementUpstreamUnicastDataDiscardDueToSinr()
increment unicast data discard due to sinr
double MILLIWATT_TO_DB(double dMillWatt)
std::uint8_t getQueueSize(std::uint8_t) const
get the queue size for a given queue index
Definition: macconfig.cc:621
std::string Serialization
Definition: serializable.h:42
const std::uint8_t MSG_TYPE_UNICAST_CTS_CTRL
Definition: msgtypes.h:48
A Packet class that allows upstream processing to strip layer headers as the packet travels up the st...
const PacketInfo & getPacketInfo() const
void processConfiguration(const ConfigurationUpdate &update) override
void incrementUpstreamBroadcastDataDiscardDueToSinr()
increment braodcast data discard due to sinr
The Registrar interface provides access to all of the emulator registrars.
Definition: registrar.h:50
A Serialized Control Message is used to encapsulate Serializable control messages as they traverse pr...
std::uint16_t getRtsThreshold() const
Definition: macconfig.cc:946
std::uint32_t getBroadcastDataRateKbps() const
get the broadcast datarate
Definition: macconfig.cc:548
void handleOneHopNeighborsEvent(const Serialization &serialization)
Microseconds getNeighborTimeoutMicroseconds() const
Definition: macconfig.cc:931
virtual ConfigurationRegistrar & configurationRegistrar()=0
void updateNeighborRxMetric(NEMId src, std::uint64_t u64SeqNum, const uuid_t &uuid, const TimePoint &rxTime)
class used to define timing parameters
#define LOGGER_VERBOSE_LOGGING(logger, level, fmt, args...)
void registerStatistics(StatisticRegistrar &statisticRegistrar)
Controls::R2RIQueueMetrics getQueueMetrics()
Controls::R2RINeighborMetrics getNeighborMetrics()
std::uint8_t getNumAccessCategories() const
get the number of access categories (queues)
Definition: macconfig.cc:605
virtual StatisticRegistrar & statisticRegistrar()=0
Recieve Properties Control Message is sent from the emulator physical layer with every upstream packe...
Holds the frequency, offset and duration of a frequency segment.
void setNeighborTimeoutMicroseconds(const Microseconds &timeOutMicroseconds)
std::list< const ControlMessage * > ControlMessages
int getContentionWindow(std::uint8_t, std::uint8_t) const
get the contention window
std::pair< std::uint16_t, bool > addToken(std::uint16_t u16Tokens=1)
void incrementUpstreamUnicastDataDiscardDueToClobberRxDuringTx()
increment unicast data discard due to collision rx during tx
std::uint8_t getBroadcastDataRateIndex() const
get the broadcast datarate index
Definition: macconfig.cc:509
static TimeStampControlMessage * create(const TimePoint &timestamp)
std::vector< UtilizationRatioPair > UtilizationRatioVector
Definition: wmmmanager.h:61
Microseconds getAllUtilizationMicroseconds(NEMId src) const
void setDelayTime(IEEE80211ABG::DownstreamQueueEntry &entry)
RegistrationId getRegistrationId() const
std::vector< SequenceEntry > SequenceVector
void incrementUpstreamBroadcastNoiseHiddenRx()
increment braodcastcast data collision due to hidden rx
NEMId getDestination() const
Definition: packetinfo.inl:70
structure defines the mac downstream packet queue entry
Microseconds getTxOpMicroseconds(std::uint8_t) const
get the txop for a given queue index
Definition: macconfig.cc:836
std::uint16_t stripLengthPrefixFraming()
constexpr NEMId NEM_BROADCAST_MAC_ADDRESS
Definition: types.h:69
Common NEM layer statistics and drop reason tables.
const std::uint8_t MAX_ACCESS_CATEGORIES
Definition: macconfig.h:63
size_t strip(size_t size)
SpectrumServiceException is thrown when an exception occurs during spectrum service processing...
void prepend(const void *buf, size_t size)
void sendDownstreamUnicastCts(DownstreamQueueEntry &entry, NEMId origin)
void start(std::uint16_t u16TotalTokensAvailable)
size_t getDepth()
get the number of entries for all active queues
RadioServiceProvider * pRadioService_
Exception thrown when failures in configuration occur.
std::uint16_t EventId
Definition: types.h:53
The PlatformServiceProvider interface provides access to emulator services.
virtual EventRegistrar & eventRegistrar()=0
static FlowControlControlMessage * create(const Serialization &serialization)
void updateNeighborTxMetric(NEMId dst, std::uint64_t u64DataRatebps, const TimePoint &txTime)
Store source, destination, creation time and priority information for a packet.
Definition: packetinfo.h:50
static FrequencyControlMessage * create(std::uint64_t u64BandwidthHz, const FrequencySegments &frequencySegments)
void processUpstreamControl(const ControlMessages &msgs) override
std::pair< DownstreamQueueEntry, bool > dequeue()
blocking dequeue, returns highest priority item first
float getNumberOfEstimatedCommonNeighbors(NEMId src) const
DECLARE_MAC_LAYER(EMANE::Models::IEEE80211ABG::MACLayer)
base class used to define the transitions for the mac tx states
void setMaxEntrySize(size_t)
set the max entry size for all queues
void updateCtrlChannelActivity(NEMId src, NEMId origin, std::uint8_t type, float fRxPowerMilliWatts, const TimePoint &tvTime, const Microseconds &duration, std::uint8_t u8Category)
const char * what() const
Definition: exception.h:62
std::uint16_t getCWMin(std::uint8_t) const
get the min contention window size for a given queue index
Definition: macconfig.cc:680
The Frequency Control Message is sent to the emulator physical layer to specify the frequency segment...
std::pair< std::string, bool > configurationValidator(const ConfigurationUpdate &updates) noexcept
Microseconds getOverheadMicroseconds(std::uint8_t u8Category) const
get the overhead time
void processFlowControlMessage(const Controls::FlowControlControlMessage *pMsg)
#define LOGGER_VERBOSE_LOGGING_FN_VARGS(logger, level, fn, fmt, args...)
std::vector< std::string > StatisticTableLabels
const PacketInfo & getPacketInfo() const
void incrementUpstreamBroadcastNoiseRxCommon()
increment unicastcast data collision due to rx common
Specialized packet the allows downstream processing to add layer specific headers as the packet trave...
void processDownstreamPacket(DownstreamPacket &pkt, const ControlMessages &msgs) override
Microseconds getChannelActivityIntervalMicroseconds() const
Definition: macconfig.cc:939
virtual bool process(MACLayer *, DownstreamQueueEntry &)=0
#define EMANE_EVENT_IEEE80211ABG_ONEHOP_NEIGHBORS
Definition: eventids.h:44
const std::uint8_t MSG_TYPE_BROADCAST_DATA
Definition: msgtypes.h:45
void setCategories(std::uint8_t u8NumCategories)
COLLISION_TYPE checkForRxCollision(NEMId src, std::uint8_t u8Category, std::uint8_t retries)
std::uint32_t getUnicastDataRateKbps() const
get the unicast datarate
Definition: macconfig.cc:523
std::uint16_t getFlowControlTokens() const
get the number of flow control tokens
Definition: macconfig.cc:909
std::chrono::microseconds Microseconds
Definition: types.h:45
virtual void update(MACLayer *, DownstreamQueueEntry &)
class used to define the mac layer statistic items
Definition: macstatistics.h:57
void incrementUpstreamUnicastNoiseRxCommon()
increment braodcastcast data collision due to rx common
std::chrono::duration< double > DoubleSeconds
Definition: types.h:47
std::string getPcrUri() const
get the pcr uri
Definition: macconfig.cc:923
std::uint16_t NEMId
Definition: types.h:52
Callable formatter object for ReceivePropertiesControlMessage instances.
Microseconds getTotalOneHopUtilizationMicroseconds() const
bool processConfiguration(const ConfigurationUpdate &update)
Definition: macconfig.cc:1033
static R2RISelfMetricControlMessage * create(const Serialization &serialization)
float getRatio(const EMANE::Microseconds &d1, const EMANE::Microseconds d2)
Definition: utils.h:65
float getNumberOfEstimatedHiddenNeighbors(NEMId src) const
Flow Control Control Messages are sent between a MAC layer and a transport in order to communicate da...
void updateQueueMetric(std::uint16_t u16QueueId, std::uint32_t u32QueueSize, std::uint32_t u32QueueDepth, std::uint32_t u32NumDiscards, const Microseconds &queueDelay)
PlatformServiceProvider * pPlatformService_
The RadioServiceProvider interface provides access to radio (RF) model specific services.
std::pair< double, bool > maxBinNoiseFloor(const SpectrumWindow &window, double dRxPowerdBm, const TimePoint &startTime=TimePoint::min())
Microseconds getNeighborMetricDeleteTimeMicroseconds() const
Definition: macconfig.cc:960
void sendDownstreamPacket(const CommonMACHeader &hdr, DownstreamPacket &pkt, const ControlMessages &msgs=DownstreamTransport::empty)
void incrementUpstreamUnicastDataDiscardDueToClobberRxHiddenBusy()
increment unicast data discard due to collision rx busy hidden
const std::uint8_t MSG_TYPE_UNICAST_DATA
Definition: msgtypes.h:46
TimerEventId schedule(Function fn, const TimePoint &timePoint, const Duration &interval=Duration::zero())
void sendUpstreamControl(const ControlMessages &msgs)
std::uint8_t getRetryLimit(std::uint8_t) const
get the retry limit for a given queue index
Definition: macconfig.cc:865
std::uint64_t getSequenceNumber() const
void registerStatistics(StatisticRegistrar &statisticRegistrar)
bool getPromiscuosEnable() const
get the promiscuous mode
Definition: macconfig.cc:439
void setNeighborDeleteTimeMicroseconds(const Microseconds &ageMicroseconds)
Priority getPriority() const
Definition: packetinfo.inl:76
const void * get() const
virtual LogServiceProvider & logService()=0
Callable formatter object for FrequencyControlMessage instances.
structure used to define parameters to detect duplicate frames
void incrementUpstreamUnicastNoiseHiddenRx()
increment unicastcast data collision due to hidden rx
Microseconds getTotalTwoHopUtilizationMicroseconds() const
std::vector< ConfigurationNameAnyValues > ConfigurationUpdate
static R2RINeighborMetricControlMessage * create(const Serialization &serialization)
void registerConfiguration(ConfigurationRegistrar &configRegistrar)
Definition: macconfig.cc:86
virtual std::pair< TimePoint, bool > getWaitTime(DownstreamQueueEntry &)=0
Microseconds getSlotSizeMicroseconds() const
get the slot duration for a given mode and distance
void sendDownstreamMessage(DownstreamQueueEntry &entry, MACHeaderParams &macHeaderParams)
double DB_TO_MILLIWATT(double ddB)
Microseconds getRadioMetricReportIntervalMicroseconds() const
Definition: macconfig.cc:967
std::uint8_t getUnicastDataRateIndex() const
get the unicast datarate index
Definition: macconfig.cc:495
MACLayer(NEMId id, PlatformServiceProvider *pPlatformServiceProvider, RadioServiceProvider *pRadioServiceProvider)
void processEvent(const EventId &, const Serialization &)
bool getWmmEnable() const
get the wmm mode
Definition: macconfig.cc:454
std::pair< std::uint16_t, bool > removeToken()
void registerStatistics(StatisticRegistrar &statisticRegistrar)
void incrementUpstreamBroadcastDataDiscardDueToClobberRxHiddenBusy()
increment braodcast data discard due to collision rx busy hidden
virtual void registerEvent(EventId eventId)=0
union EtherAddr src
Definition: netutils.h:391
std::vector< DownstreamQueueEntry > enqueue(DownstreamQueueEntry &entry)
enqueue, inserts items by priority, signals on success.
Microseconds getAverageMessageDurationMicroseconds() const
std::uint32_t getMaxDataRateKbps() const
Definition: macconfig.cc:530
std::vector< float > CWRatioVector
Definition: macconfig.h:75
Clock::time_point TimePoint
Definition: types.h:50
virtual bool cancelTimedEvent(TimerEventId eventId)=0
void incrementUpstreamUnicastCtsRxFromPhy()
increment unicast cts recv from phy
void updateDataChannelActivity(NEMId src, std::uint8_t type, float fRxPowerMilliWatts, const TimePoint &timePoint, const Microseconds &duration, std::uint8_t u8Category)
void sendUpstreamPacket(UpstreamPacket &pkt, const ControlMessages &msgs=empty)
void setMaxCapacity(size_t)
set the max number of entries for all queues
void processUpstreamPacket(const CommonMACHeader &hdr, UpstreamPacket &pkt, const ControlMessages &msgs) override
void prependLengthPrefixFraming(std::uint16_t u16Length)
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
void processDownstreamControl(const ControlMessages &msgs) override
static IdleTxState * instance()
Definition: singleton.h:56
size_t getMaxCapacity()
get the max number of entries for all queues
Microseconds getDeferIntervalMicroseconds(std::uint8_t) const
get the defer time
virtual SpectrumServiceProvider & spectrumService()=0
virtual SpectrumWindow request(std::uint64_t u64FrequencyHz, const Microseconds &duration=Microseconds::zero(), const TimePoint &startTime=TimePoint::min()) const =0
void setCategories(std::uint8_t u8Category)
set the number of categories (queues)
float getPCR(float fSinr, size_t size, std::uint16_t DataRateIndex)
void registerStatistics(StatisticRegistrar &statisticRegistrar)
void incrementUpstreamBroadcastDataDiscardDueToClobberRxDuringTx()
increment braodcast data discard due to collision rx during tx
std::uint16_t getQueueEntrySize(std::uint8_t) const
get the queue entry size for a given queue index
Definition: macconfig.cc:650
CWRatioVector getCWMinRatioVector(std::uint8_t) const
Definition: macconfig.cc:953
static R2RIQueueMetricControlMessage * create(const Serialization &serialization)
bool getFlowControlEnable() const
get the flow control enable status
Definition: macconfig.cc:894
bool addQueueMetric(std::uint16_t u16QueueId, std::uint32_t u32QueueSize)
const std::uint8_t MSG_TYPE_UNICAST_RTS_CTS_DATA
Definition: msgtypes.h:47
void configure(const ConfigurationUpdate &update) override
void incrementUpstreamUnicastRtsCtsDataRxFromPhy()
increment unicast rts/ctsdata recv from phy
Interface used to create a MAC layer plugin implementation.
Definition: maclayerimpl.h:48
virtual TimerServiceProvider & timerService()=0
WMMManager::UtilizationRatioVector getUtilizationRatios()