22 #include "ns3/abort.h"
25 #include "ns3/recipient-block-ack-agreement.h"
26 #include "ns3/ap-wifi-mac.h"
27 #include "ns3/sta-wifi-mac.h"
29 #include "ns3/snr-tag.h"
34 #undef NS_LOG_APPEND_CONTEXT
35 #define NS_LOG_APPEND_CONTEXT std::clog << "[mac=" << m_self << "] "
46 static TypeId tid =
TypeId (
"ns3::HeFrameExchangeManager")
48 .AddConstructor<HeFrameExchangeManager> ()
49 .SetGroupName (
"Wifi")
55 : m_triggerFrameInAmpdu (false)
69 if (
m_mac->GetHeConfiguration ()->GetMpduBufferSize () > 64)
102 "A Multi-User Scheduler can only be aggregated to an AP");
104 "A Multi-User Scheduler can only be aggregated to an HE AP");
126 || (mpdu->GetHeader ().IsQosData ()
127 && !mpdu->GetHeader ().GetAddr1 ().IsGroup ()
130 txFormat =
m_muScheduler->NotifyAccessGranted (edca, availableTime, initialFrame);
142 NS_LOG_DEBUG (
"The Multi-user Scheduler returned DL_MU_TX with empty psduMap, do not transmit");
155 NS_LOG_DEBUG (
"The Multi-user Scheduler returned UL_MU_TX with empty Trigger Frame, do not transmit");
179 NS_LOG_DEBUG (
"Block Ack Manager returned no frame to send");
183 if (peekedItem->GetHeader ().IsBlockAckReq ())
189 NS_ASSERT (peekedItem->GetHeader ().IsTrigger ());
204 #ifdef NS3_BUILD_PROFILE_DEBUG
209 for (
const auto& psdu : psduMap)
211 for (
const auto& mpdu : *
PeekPointer (psdu.second))
213 NS_ASSERT (mpdu->GetHeader ().IsCtl () || !mpdu->GetHeader ().HasData () || mpdu->IsQueued ());
247 auto it = std::find_if (psduMap.begin (), psduMap.end (),
249 { return psdu.second->GetAddr1 () == to; });
250 if (it != psduMap.end ())
287 std::set<uint8_t> tids = psdu.second->
GetTids ();
288 NS_ABORT_MSG_IF (tids.size () > 1,
"Acknowledgment method incompatible with a Multi-TID A-MPDU");
289 uint8_t tid = *tids.begin ();
303 mpdu = *psdu->
begin ();
326 std::map<uint16_t, CtrlBAckRequestHeader> recipients;
334 uint16_t staId =
m_apMac->GetAssociationId (staIt->first);
336 txVector.
SetHeMuUserInfo (staId, staIt->second.blockAckTxVector.GetHeMuUserInfo (staId));
337 recipients.emplace (staId, staIt->second.barHeader);
396 { return psdu.second->GetAddr1 () == station.first; });
400 std::vector<Ptr<WifiMacQueueItem>> mpduList (psduMapIt->second->begin (), psduMapIt->second->end ());
401 NS_ASSERT (mpduList.size () == psduMapIt->second->GetNMpdus ());
404 station.second.blockAckTxVector.SetLength (acknowledgment->
ulLength);
405 mpduList.push_back (
PrepareMuBar (station.second.blockAckTxVector,
406 {{psduMapIt->first, station.second.barHeader}}));
407 psduMapIt->second = Create<WifiPsdu> (std::move (mpduList));
411 responseTxVector = &acknowledgment->stationsReplyingWithBlockAck.begin ()->second.blockAckTxVector;
420 && (mpdu = *m_psduMap.begin ()->second->begin ())->GetHeader ().IsTrigger ());
425 m_staExpectTbPpduFrom.clear ();
429 m_staExpectTbPpduFrom.insert (station.first.first);
441 + m_muScheduler->GetUlMuInfo ().tbPpduDuration;
450 && !m_txParams.m_txVector.IsUlMu ()
451 && m_psduMap.size () == 1 && m_psduMap.begin ()->first ==
SU_STA_ID
452 && (mpdu = *m_psduMap.begin ()->second->begin ())->GetHeader ().IsTrigger ())
454 CtrlTriggerHeader trigger;
455 mpdu->GetPacket ()->PeekHeader (trigger);
460 m_staExpectTbPpduFrom.clear ();
462 for (
const auto& userInfo : trigger)
464 auto staIt = m_apMac->GetStaList ().find (userInfo.GetAid12 ());
465 NS_ASSERT (staIt != m_apMac->GetStaList ().end ());
466 m_staExpectTbPpduFrom.insert (staIt->second);
471 WifiNoAck* acknowledgment =
static_cast<WifiNoAck*
> (m_txParams.m_acknowledgment.get ());
472 txVector = trigger.GetHeTbTxVector (trigger.begin ()->GetAid12 ());
476 m_phy->GetPhyBand ());
479 responseTxVector = &txVector;
484 else if (m_txParams.m_txVector.IsUlMu ()
489 NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
490 txVector = m_mac->GetWifiRemoteStationManager ()->GetBlockAckTxVector (m_psduMap.begin ()->second->GetAddr1 (),
491 m_txParams.m_txVector);
492 responseTxVector = &txVector;
497 else if (m_txParams.m_txVector.IsUlMu ()
504 NS_ABORT_MSG (
"Unable to handle the selected acknowledgment method ("
505 << m_txParams.m_acknowledgment.get () <<
")");
510 for (
const auto& psdu : m_psduMap)
512 psduMap.emplace (psdu.first, psdu.second);
516 if (m_txParams.m_txVector.IsUlMu ())
519 m_txParams.m_txVector,
520 m_phy->GetPhyBand ());
524 txDuration = m_phy->CalculateTxDuration (psduMap, m_txParams.m_txVector, m_phy->GetPhyBand ());
527 Time durationId = GetPsduDurationId (txDuration, m_txParams);
528 for (
auto& psdu : m_psduMap)
530 psdu.second->SetDuration (durationId);
536 if (!m_txParams.m_txVector.IsUlMu ())
543 Time timeout = txDuration + m_phy->GetSifs () + m_phy->GetSlot ()
544 + m_phy->CalculatePhyPreambleAndHeaderDuration (*responseTxVector);
545 m_channelAccessManager->NotifyAckTimeoutStartNow (
timeout);
553 this, mpdu, m_txParams.m_txVector);
558 this, psdu, m_txParams.m_txVector);
562 &m_psduMap, &m_staExpectTbPpduFrom, m_staExpectTbPpduFrom.size ());
567 &m_psduMap, &m_staExpectTbPpduFrom, m_staExpectTbPpduFrom.size ());
571 this, m_psduMap.begin ()->second, m_txParams.m_txVector);
580 ForwardPsduMapDown (psduMap, m_txParams.m_txVector);
588 for (
const auto& psdu : psduMap)
590 NS_LOG_DEBUG (
"Transmitting: [STAID=" << psdu.first <<
", " << *psdu.second <<
"]");
593 for (
const auto& psdu : psduMap)
595 NotifyTxToEdca (psdu.second);
598 DequeuePsdu (psdu.second);
600 if (psduMap.size () > 1 || psduMap.begin ()->second->IsAggregate () || psduMap.begin ()->second->IsSingle ())
605 m_phy->Send (psduMap, txVector);
609 HeFrameExchangeManager::PrepareMuBar (
const WifiTxVector& responseTxVector,
610 std::map<uint16_t, CtrlBAckRequestHeader> recipients)
const
617 SetTargetRssi (muBar);
621 for (
auto& userInfo : muBar)
623 auto recipientIt = recipients.find (userInfo.GetAid12 ());
624 NS_ASSERT (recipientIt != recipients.end ());
627 userInfo.SetMuBarTriggerDepUserInfo (recipientIt->second);
638 rxAddress = Mac48Address::GetBroadcast ();
643 rxAddress = m_apMac->GetStaList ().at (recipients.begin ()->first);
655 return Create<WifiMacQueueItem> (bar, hdr);
667 if (acknowledgment->
method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE)
680 duration += m_phy->GetSifs ()
681 + m_phy->CalculateTxDuration (
GetAckSize (), info.ackTxVector, m_phy->GetPhyBand ());
687 duration += m_phy->GetSifs ()
689 info.blockAckTxVector, m_phy->GetPhyBand ());
694 const auto& info = stations.second;
695 duration += m_phy->GetSifs ()
697 info.blockAckReqTxVector, m_phy->GetPhyBand ())
700 info.blockAckTxVector, m_phy->GetPhyBand ());
708 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_TF_MU_BAR)
717 const auto& info = stations.second;
718 NS_ASSERT (info.blockAckTxVector.GetHeMuUserInfoMap ().size () == 1);
719 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap ().begin ()->first;
721 info.blockAckTxVector,
722 m_phy->GetPhyBand (),
725 if (currBlockAckDuration > duration)
727 duration = currBlockAckDuration;
733 dlMuTfMuBarAcknowledgment->
ulLength = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, m_phy->GetPhyBand ());
735 duration = HePhy::ConvertLSigLengthToHeTbPpduDuration (dlMuTfMuBarAcknowledgment->
ulLength,
736 txVector, m_phy->GetPhyBand ());
740 + m_phy->CalculateTxDuration (muBarSize,
742 m_phy->GetPhyBand ())
743 + m_phy->GetSifs () + duration;
748 else if (acknowledgment->
method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
757 const auto& info = stations.second;
758 NS_ASSERT (info.blockAckTxVector.GetHeMuUserInfoMap ().size () == 1);
759 uint16_t staId = info.blockAckTxVector.GetHeMuUserInfoMap ().begin ()->first;
761 info.blockAckTxVector,
762 m_phy->GetPhyBand (),
765 if (currBlockAckDuration > duration)
767 duration = currBlockAckDuration;
773 dlMuAggrTfAcknowledgment->
ulLength = HePhy::ConvertHeTbPpduDurationToLSigLength (duration, m_phy->GetPhyBand ());
775 duration = HePhy::ConvertLSigLengthToHeTbPpduDuration (dlMuAggrTfAcknowledgment->
ulLength,
776 txVector, m_phy->GetPhyBand ());
783 else if (acknowledgment->
method == WifiAcknowledgment::UL_MU_MULTI_STA_BA)
789 m_phy->GetPhyBand ());
795 else if (acknowledgment->
method == WifiAcknowledgment::ACK_AFTER_TB_PPDU)
804 VhtFrameExchangeManager::CalculateAcknowledgmentTime (acknowledgment);
809 HeFrameExchangeManager::GetTxDuration (uint32_t ppduPayloadSize,
Mac48Address receiver,
814 return VhtFrameExchangeManager::GetTxDuration (ppduPayloadSize, receiver, txParams);
821 && txParams.
m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF)
829 ppduPayloadSize = MpduAggregator::GetSizeIfAggregated (info->second.muBarSize, ppduPayloadSize);
832 uint16_t staId = (txParams.
m_txVector.
IsDlMu () ? m_apMac->GetAssociationId (receiver)
833 : m_staMac->GetAssociationId ());
834 Time psduDuration = m_phy->CalculateTxDuration (ppduPayloadSize, txParams.
m_txVector,
835 m_phy->GetPhyBand (), staId);
842 const std::set<Mac48Address>* staMissedTbPpduFrom,
843 std::size_t nSolicitedStations)
845 NS_LOG_FUNCTION (
this << psduMap << staMissedTbPpduFrom->size () << nSolicitedStations);
849 && psduMap->begin ()->second->GetHeader (0).IsTrigger ());
852 NS_ASSERT (!staMissedTbPpduFrom->empty ());
855 if (staMissedTbPpduFrom->size () == nSolicitedStations)
858 m_edca->UpdateFailedCw ();
860 TransmissionFailed ();
862 else if (!m_multiStaBaEvent.IsRunning ())
865 TransmissionSucceeded ();
872 HeFrameExchangeManager::BlockAcksInTbPpduTimeout (
WifiPsduMap* psduMap,
873 const std::set<Mac48Address>* staMissedBlockAckFrom,
874 std::size_t nSolicitedStations)
880 && (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_AGGREGATE_TF
881 || m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_TF_MU_BAR));
884 NS_ASSERT (!staMissedBlockAckFrom->empty ());
888 if (staMissedBlockAckFrom->size () == nSolicitedStations)
892 m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psduMap->begin ()->second->begin ());
901 m_triggerFrame =
nullptr;
903 for (
const auto& sta : *staMissedBlockAckFrom)
912 MissedBlockAck (psdu, m_txParams.m_txVector, psduResetCw);
913 resetCw = resetCw || psduResetCw;
924 m_edca->UpdateFailedCw ();
927 if (staMissedBlockAckFrom->size () == nSolicitedStations)
930 TransmissionFailed ();
934 TransmissionSucceeded ();
947 m_mac->GetWifiRemoteStationManager ()->ReportDataFailed (*psdu->
begin ());
949 MissedBlockAck (psdu, m_txParams.m_txVector, resetCw);
964 uint16_t staId = m_staMac->GetAssociationId ();
971 NS_ASSERT_MSG (heConfiguration != 0,
"This STA has to be an HE station to send an HE TB PPDU");
974 uint8_t powerLevel = m_mac->GetWifiRemoteStationManager ()->GetDefaultTxPowerLevel ();
992 int8_t pathLossDb = trigger.
GetApTxPower () -
static_cast<int8_t
> (m_mac->GetWifiRemoteStationManager ()->GetMostRecentRssi (triggerSender));
993 double reqTxPowerDbm =
static_cast<double> (userInfoIt->GetUlTargetRssi () + pathLossDb);
996 uint8_t numPowerLevels = m_phy->GetNTxPower ();
997 if (numPowerLevels > 1)
999 double stepDbm = (m_phy->GetTxPowerEnd () - m_phy->GetTxPowerStart ()) / (numPowerLevels - 1);
1000 powerLevel =
static_cast<uint8_t
> (ceil ((reqTxPowerDbm - m_phy->GetTxPowerStart ()) / stepDbm));
1001 if (powerLevel > numPowerLevels)
1003 powerLevel = numPowerLevels;
1006 if (reqTxPowerDbm > m_phy->GetPowerDbm (powerLevel))
1008 NS_LOG_WARN (
"The requested power level (" << reqTxPowerDbm <<
"dBm) cannot be satisfied (max: " << m_phy->GetTxPowerEnd () <<
"dBm)");
1012 <<
"input {pathLoss=" << pathLossDb <<
"dB, reqTxPower=" << reqTxPowerDbm <<
"dBm}"
1013 <<
" output {powerLevel=" << +powerLevel <<
" -> " << m_phy->GetPowerDbm (powerLevel) <<
"dBm}"
1014 <<
" PHY power capa {min=" << m_phy->GetTxPowerStart () <<
"dBm, max=" << m_phy->GetTxPowerEnd () <<
"dBm, levels:" << +numPowerLevels <<
"}");
1025 trigger.
SetApTxPower (
static_cast<int8_t
> (m_phy->GetPowerDbm (m_mac->GetWifiRemoteStationManager ()->GetDefaultTxPowerLevel ())));
1026 for (
auto& userInfo : trigger)
1028 const auto staList = m_apMac->GetStaList ();
1029 auto itAidAddr = staList.find (userInfo.GetAid12 ());
1030 NS_ASSERT (itAidAddr != staList.end ());
1031 int8_t rssi =
static_cast<int8_t
> (m_mac->GetWifiRemoteStationManager ()->GetMostRecentRssi (itAidAddr->second));
1032 rssi = (rssi >= -20) ? -20 : ((rssi <= -110) ? -110 : rssi);
1033 userInfo.SetUlTargetRssi (rssi);
1044 && txParams.
m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1056 receiver = staInfo.first.first;
1057 uint8_t tid = staInfo.first.second;
1058 std::size_t index = staInfo.second;
1060 blockAck.
SetAid11 (m_apMac->GetAssociationId (receiver), index);
1066 NS_LOG_DEBUG (
"Multi-STA Block Ack: Sending All-ack to=" << receiver);
1074 NS_LOG_DEBUG (
"Multi-STA Block Ack: Sending Ack to=" << receiver);
1082 auto addressTidPair = staInfo.first;
1083 auto agreementIt = m_agreements.find (addressTidPair);
1084 NS_ASSERT (agreementIt != m_agreements.end ());
1085 agreementIt->second.FillBlockAckBitmap (&blockAck, index);
1087 <<
" to=" << receiver <<
" tid=" << +tid);
1100 Ptr<WifiPsdu> psdu = GetWifiPsdu (Create<WifiMacQueueItem> (packet, hdr),
1108 m_phy->GetPhyBand ());
1113 psdu->
SetDuration (GetPsduDurationId (txDuration, params));
1122 m_muSnrTag.Reset ();
1123 Simulator::Schedule (txDuration, &HeFrameExchangeManager::TransmissionSucceeded,
this);
1131 NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
1133 NS_LOG_DEBUG (
"Received a Trigger Frame (basic variant) soliciting a transmission");
1137 NS_LOG_DEBUG (
"Carrier Sensing required and channel busy, do nothing");
1147 std::vector<uint8_t> tids;
1148 uint16_t staId = m_staMac->GetAssociationId ();
1151 for (uint8_t i = 0; i < 4; i++)
1154 tids.push_back (acIt->second.GetHighTid ());
1155 tids.push_back (acIt->second.GetLowTid ());
1168 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration (trigger.
GetUlLength (),
1170 m_phy->GetPhyBand ());
1172 for (
const auto& tid : tids)
1187 && TryAddMpdu (mpdu, txParams, ppduDuration))
1203 std::vector<Ptr<WifiMacQueueItem>> mpduList = m_mpduAggregator->GetNextAmpdu (item, txParams,
1206 psdu = (mpduList.size () > 1 ? Create<WifiPsdu> (std::move (mpduList))
1207 : Create<WifiPsdu> (item,
true));
1216 SendPsduMapWithProtection (
WifiPsduMap {{staId, psdu}}, txParams);
1221 SendQosNullFramesInTbPpdu (trigger, hdr);
1230 NS_ASSERT (m_staMac != 0 && m_staMac->IsAssociated ());
1236 NS_LOG_DEBUG (
"Carrier Sensing required and channel busy, do nothing");
1258 Time ppduDuration = HePhy::ConvertLSigLengthToHeTbPpduDuration (trigger.
GetUlLength (),
1260 m_phy->GetPhyBand ());
1264 std::vector<Ptr<WifiMacQueueItem>> mpduList;
1269 && IsWithinSizeAndTimeLimits (txParams.
GetSizeIfAddMpdu (mpdu = Create<WifiMacQueueItem> (Create<Packet> (),
1271 hdr.
GetAddr2 (), txParams, ppduDuration))
1273 NS_LOG_DEBUG (
"Aggregating a QoS Null frame with tid=" << +tid);
1282 mpduList.push_back (mpdu);
1286 if (mpduList.empty ())
1288 NS_LOG_DEBUG (
"Not enough time to send a QoS Null frame");
1292 Ptr<WifiPsdu> psdu = (mpduList.size () > 1 ? Create<WifiPsdu> (std::move (mpduList))
1293 : Create<WifiPsdu> (mpduList.front (),
true));
1294 uint16_t staId = m_staMac->GetAssociationId ();
1295 SendPsduMapWithProtection (
WifiPsduMap {{staId, psdu}}, txParams);
1308 if (txVector.
IsUlMu () && m_txTimer.IsRunning ()
1309 && m_txTimer.GetReason () == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1313 && m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1317 if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1319 NS_LOG_WARN (
"Received a TB PPDU from an unexpected station: " << sender);
1325 NS_LOG_DEBUG (
"Received a BlockAckReq in a TB PPDU from " << sender);
1331 auto agreementIt = m_agreements.find ({sender, tid});
1332 NS_ASSERT (agreementIt != m_agreements.end ());
1337 acknowledgment->
baType.
m_bitmapLen.push_back (GetBlockAckType (sender, tid).m_bitmapLen.at (0));
1339 m_muSnrTag.Set (staId, rxSignalInfo.
snr);
1343 NS_LOG_DEBUG (
"Received an S-MPDU in a TB PPDU from " << sender <<
" (" << *mpdu <<
")");
1346 auto agreementIt = m_agreements.find ({sender, tid});
1347 NS_ASSERT (agreementIt != m_agreements.end ());
1348 agreementIt->second.NotifyReceivedMpdu (mpdu);
1354 m_muSnrTag.Set (staId, rxSignalInfo.
snr);
1363 VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1370 m_multiStaBaEvent = Simulator::Schedule (m_phy->GetSifs (),
1371 &HeFrameExchangeManager::SendMultiStaBlockAck,
1372 this, std::cref (m_txParams));
1376 m_staExpectTbPpduFrom.erase (sender);
1378 if (m_staExpectTbPpduFrom.empty ())
1381 m_txTimer.Cancel ();
1382 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1384 if (!m_multiStaBaEvent.IsRunning ())
1390 TransmissionSucceeded ();
1400 if (hdr.
IsAck () && m_txTimer.IsRunning ()
1401 && m_txTimer.GetReason () == WifiTxTimer::WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU)
1404 NS_ASSERT (m_txParams.m_acknowledgment);
1405 NS_ASSERT (m_txParams.m_acknowledgment->method == WifiAcknowledgment::DL_MU_BAR_BA_SEQUENCE);
1411 auto it = m_psduMap.find (staId);
1416 ReceivedNormalAck (*it->second->begin (), m_txParams.m_txVector, txVector, rxSignalInfo, tag.
Get ());
1418 else if (hdr.
IsBlockAck () && m_txTimer.IsRunning ()
1419 && m_txTimer.GetReason () == WifiTxTimer::WAIT_BLOCK_ACKS_IN_TB_PPDU)
1422 NS_LOG_DEBUG (
"Received BlockAck in TB PPDU from=" << sender);
1431 GetBaManager (tid)->NotifyGotBlockAck (blockAck, hdr.
GetAddr2 (), {tid}, rxSignalInfo.
snr,
1432 tag.
Get (), m_txParams.m_txVector);
1435 if (m_staExpectTbPpduFrom.erase (sender) == 0)
1437 NS_LOG_WARN (
"Received a BlockAck from an unexpected stations: " << sender);
1441 if (m_staExpectTbPpduFrom.empty ())
1444 m_txTimer.Cancel ();
1445 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1446 m_triggerFrame =
nullptr;
1450 TransmissionSucceeded ();
1453 else if (hdr.
IsBlockAck () && m_txTimer.IsRunning ()
1454 && m_txTimer.GetReason () == WifiTxTimer::WAIT_BLOCK_ACK_AFTER_TB_PPDU)
1460 "A Multi-STA BlockAck is expected after a TB PPDU");
1463 NS_ASSERT (m_staMac !=
nullptr && m_staMac->IsAssociated ());
1464 uint16_t staId = m_staMac->GetAssociationId ();
1467 if (indices.empty ())
1469 NS_LOG_DEBUG (
"No Per AID TID Info subfield intended for me");
1477 for (
const auto& index : indices)
1484 NS_ABORT_IF (m_psduMap.empty () || m_psduMap.begin ()->first != staId);
1485 GetBaManager (tid)->NotifyGotAck (*m_psduMap.at (staId)->begin ());
1490 if (blockAck.
GetAckType (index) && tid == 14)
1494 NS_ABORT_IF (m_psduMap.empty () || m_psduMap.begin ()->first != staId);
1495 std::set<uint8_t> tids = m_psduMap.at (staId)->GetTids ();
1496 NS_ABORT_MSG_IF (tids.size () > 1,
"Multi-TID A-MPDUs not supported yet");
1497 tid = *tids.begin ();
1500 GetBaManager (tid)->NotifyGotBlockAck (blockAck, hdr.
GetAddr2 (), {tid},
1501 rxSignalInfo.
snr, tag.
Get (staId),
1502 m_txParams.m_txVector, index);
1507 m_txTimer.Cancel ();
1508 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1514 if (m_staMac ==
nullptr)
1522 m_triggerFrameInAmpdu =
true;
1531 || !m_staMac->IsAssociated ()
1539 uint16_t staId = m_staMac->GetAssociationId ();
1544 NS_LOG_DEBUG (
"Received MU-BAR Trigger Frame from=" << sender);
1545 m_mac->GetWifiRemoteStationManager ()->ReportRxOk (sender, rxSignalInfo, txVector);
1553 auto agreementIt = m_agreements.find ({sender, tid});
1555 if (agreementIt == m_agreements.end ())
1557 NS_LOG_DEBUG (
"There's not a valid agreement for this BlockAckReq");
1564 Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::SendBlockAck,
this,
1566 GetHeTbTxVector (trigger, hdr.
GetAddr2 ()), rxSignalInfo.
snr);
1570 Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::ReceiveBasicTrigger,
1571 this, trigger, hdr);
1573 else if (trigger.
IsBsrp ())
1575 Simulator::Schedule (m_phy->GetSifs (), &HeFrameExchangeManager::SendQosNullFramesInTbPpdu,
1576 this, trigger, hdr);
1582 VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);
1590 VhtFrameExchangeManager::ReceiveMpdu (mpdu, rxSignalInfo, txVector, inAmpdu);;
1595 const WifiTxVector& txVector,
const std::vector<bool>& perMpduStatus)
1597 std::set<uint8_t> tids = psdu->
GetTids ();
1599 if (txVector.
IsUlMu () && m_txTimer.IsRunning ()
1600 && m_txTimer.GetReason () == WifiTxTimer::WAIT_TB_PPDU_AFTER_BASIC_TF)
1604 && m_txParams.m_acknowledgment->method == WifiAcknowledgment::UL_MU_MULTI_STA_BA);
1608 if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1610 NS_LOG_WARN (
"Received a TB PPDU from an unexpected station: " << sender);
1614 NS_LOG_DEBUG (
"Received an A-MPDU in a TB PPDU from " << sender <<
" (" << *psdu <<
")");
1616 if (std::any_of (tids.begin (), tids.end (),
1617 [&psdu](uint8_t tid)
1618 { return psdu->GetAckPolicyForTid (tid) == WifiMacHeader::NORMAL_ACK; }))
1620 if (std::all_of (perMpduStatus.cbegin (), perMpduStatus.cend (), [](
bool v) { return v; }))
1630 for (
const auto& tid : tids)
1633 acknowledgment->
baType.
m_bitmapLen.push_back (GetBlockAckType (sender, tid).m_bitmapLen.at (0));
1637 m_muSnrTag.Set (staId, rxSignalInfo.
snr);
1643 m_multiStaBaEvent = Simulator::Schedule (m_phy->GetSifs (),
1644 &HeFrameExchangeManager::SendMultiStaBlockAck,
1645 this, std::cref (m_txParams));
1649 m_staExpectTbPpduFrom.erase (sender);
1651 if (m_staExpectTbPpduFrom.empty ())
1654 m_txTimer.Cancel ();
1655 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1657 if (!m_multiStaBaEvent.IsRunning ())
1663 TransmissionSucceeded ();
1671 if (txVector.
IsUlMu () && m_txTimer.IsRunning ()
1672 && m_txTimer.GetReason () == WifiTxTimer::WAIT_QOS_NULL_AFTER_BSRP_TF)
1676 if (m_staExpectTbPpduFrom.find (sender) == m_staExpectTbPpduFrom.end ())
1678 NS_LOG_WARN (
"Received a TB PPDU from an unexpected station: " << sender);
1682 { return mpdu->GetHeader ().IsQosData ()
1683 && !mpdu->GetHeader ().HasData ();
1686 NS_LOG_WARN (
"No QoS Null frame in the received PSDU");
1690 NS_LOG_DEBUG (
"Received QoS Null frames in a TB PPDU from " << sender);
1693 m_staExpectTbPpduFrom.erase (sender);
1695 if (m_staExpectTbPpduFrom.empty ())
1698 m_txTimer.Cancel ();
1699 m_channelAccessManager->NotifyAckTimeoutResetNow ();
1704 TransmissionSucceeded ();
1711 if (m_triggerFrameInAmpdu)
1714 auto psduIt = psdu->
begin ();
1715 while (psduIt != psdu->
end ())
1717 if ((*psduIt)->GetHeader ().IsTrigger ())
1719 ReceiveMpdu (*psduIt, rxSignalInfo, txVector,
false);
1724 m_triggerFrameInAmpdu =
false;
1729 VhtFrameExchangeManager::EndReceiveAmpdu (psdu, rxSignalInfo, txVector, perMpduStatus);
void Cancel(void)
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Ptr< RegularWifiMac > m_mac
the MAC layer on this station
WifiTxTimer m_txTimer
the timer set upon frame transmission
Ptr< WifiPhy > m_phy
the PHY layer on this station
Ptr< ChannelAccessManager > m_channelAccessManager
the channel access manager
void NormalAckTimeout(Ptr< WifiMacQueueItem > mpdu, const WifiTxVector &txVector)
Called when the Ack timeout expires.
Ptr< ApWifiMac > m_apMac
MAC pointer (null if not an AP)
bool SendMpduFromBaManager(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
If the Block Ack Manager associated with the given EDCA has a BlockAckReq frame to transmit (the dura...
void DoDispose() override
Destructor implementation.
WifiTxParameters m_txParams
the TX parameters for the current PPDU
Ptr< WifiMacQueueItem > m_triggerFrame
Trigger Frame being sent.
void CalculateAcknowledgmentTime(WifiAcknowledgment *acknowledgment) const override
Calculate the time required to acknowledge a frame according to the given acknowledgment method.
void SetMultiUserScheduler(const Ptr< MultiUserScheduler > muScheduler)
Set the Multi-user Scheduler associated with this Frame Exchange Manager.
virtual void TbPpduTimeout(WifiPsduMap *psduMap, const std::set< Mac48Address > *staMissedTbPpduFrom, std::size_t nSolicitedStations)
Take the necessary actions after that some TB PPDUs are missing in response to Trigger Frame.
Ptr< MultiUserScheduler > m_muScheduler
Multi-user Scheduler (HE APs only)
static Ptr< WifiPsdu > GetPsduTo(Mac48Address to, const WifiPsduMap &psduMap)
Get the PSDU in the given PSDU map that is addressed to the given MAC address, if any,...
Ptr< StaWifiMac > m_staMac
MAC pointer (null if not a STA)
static TypeId GetTypeId(void)
Get the type ID.
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
std::set< Mac48Address > m_staExpectTbPpduFrom
set of stations expected to send a TB PPDU
virtual void BlockAckAfterTbPpduTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Take the necessary actions after that a Block Ack is missing after a TB PPDU solicited through a Trig...
void SendPsduMap(void)
Send the current PSDU map as a DL MU PPDU.
uint16_t GetSupportedBaBufferSize(void) const override
Get the maximum supported buffer size for a Block Ack agreement.
void SetWifiMac(const Ptr< RegularWifiMac > mac) override
Set the MAC layer to use.
WifiPsduMap m_psduMap
the A-MPDU being transmitted
virtual void BlockAcksInTbPpduTimeout(WifiPsduMap *psduMap, const std::set< Mac48Address > *staMissedBlockAckFrom, std::size_t nSolicitedStations)
Take the necessary actions after that some BlockAck frames are missing in response to a DL MU PPDU.
EventId m_multiStaBaEvent
Sending a Multi-STA BlockAck event.
void SendPsduMapWithProtection(WifiPsduMap psduMap, WifiTxParameters &txParams)
Send a map of PSDUs as a DL MU PPDU.
virtual ~HeFrameExchangeManager()
Ptr< WifiMacQueueItem > PrepareMuBar(const WifiTxVector &responseTxVector, std::map< uint16_t, CtrlBAckRequestHeader > recipients) const
Build a MU-BAR Trigger Frame starting from the TXVECTOR used to respond to the MU-BAR (in case of mul...
static Time ConvertLSigLengthToHeTbPpduDuration(uint16_t length, const WifiTxVector &txVector, WifiPhyBand band)
virtual bool SendMpduFromBaManager(Ptr< QosTxop > edca, Time availableTime, bool initialFrame)
If the Block Ack Manager associated with the given EDCA has a BlockAckReq frame to transmit (the dura...
void ForwardMpduDown(Ptr< WifiMacQueueItem > mpdu, WifiTxVector &txVector) override
Forward an MPDU down to the PHY layer.
virtual void BlockAckTimeout(Ptr< WifiPsdu > psdu, const WifiTxVector &txVector)
Called when the BlockAck timeout expires.
virtual Time GetPsduDurationId(Time txDuration, const WifiTxParameters &txParams) const
Compute how to set the Duration/ID field of PSDUs that do not include fragments.
void DoDispose() override
Destructor implementation.
bool StartFrameExchange(Ptr< QosTxop > edca, Time availableTime, bool initialFrame) override
Start a frame exchange (including protection frames and acknowledgment frames as needed) that fits wi...
void SetWifiMac(const Ptr< RegularWifiMac > mac) override
Set the MAC layer to use.
void TransmissionSucceeded(void) override
Take necessary actions upon a transmission success.
bool IsBroadcast(void) const
A tag to be attached to a response to a multi-user UL frame, that carries the SNR values with which t...
double Get(uint16_t staId) const
Return the SNR value for the given sender.
TxFormat
Enumeration of the possible transmission formats.
void AddHeader(const Header &header)
Add header to this packet.
void AddPacketTag(const Tag &tag) const
Add a packet tag.
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Smart pointer class similar to boost::intrusive_ptr.
Ptr< QosTxop > m_edca
the EDCAF that gained channel access
Ptr< const WifiMacQueueItem > PeekNextMpdu(uint8_t tid=8, Mac48Address recipient=Mac48Address::GetBroadcast())
Peek the next frame to transmit to the given receiver and of the given TID from the block ack manager...
Ptr< const WifiMacQueueItem > PrepareBlockAckRequest(Mac48Address recipient, uint8_t tid) const
bool GetBaAgreementEstablished(Mac48Address address, uint8_t tid) const
Ptr< BlockAckManager > GetBaManager(void)
Get the Block Ack Manager associated with this QosTxop.
Ptr< WifiMacQueueItem > GetNextMpdu(Ptr< const WifiMacQueueItem > peekedItem, WifiTxParameters &txParams, Time availableTime, bool initialFrame, WifiMacQueueItem::QueueIteratorPair &queueIt)
Prepare the frame to transmit starting from the MPDU that has been previously peeked by calling PeekN...
void ScheduleBar(Ptr< const WifiMacQueueItem > bar, bool skipIfNoDataQueued=false)
static EventId Schedule(Time const &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Introspection did not find any typical Config paths.
double Get(void) const
Return the SNR value.
Simulation virtual time values and global simulation resolution.
static Time Min()
Minimum representable Time Not to be confused with Min(Time,Time).
a unique identifier for an interface.
TypeId SetParent(TypeId tid)
Set the parent TypeId.
VhtFrameExchangeManager handles the frame exchange sequences for VHT stations.
Ptr< WifiPsdu > GetWifiPsdu(Ptr< WifiMacQueueItem > mpdu, const WifiTxVector &txVector) const override
Get a PSDU containing the given MPDU.
static void SetQosAckPolicy(Ptr< WifiMacQueueItem > item, const WifiAcknowledgment *acknowledgment)
Set the QoS Ack policy for the given MPDU, which must be a QoS data frame.
Ptr< const Packet > GetPacket(void) const
Get the packet stored in this item.
uint32_t GetSize(void) const
Return the size of the packet stored by this item, including header size and trailer size.
const WifiMacHeader & GetHeader(void) const
Get the header stored in this item.
WifiPhyBand GetPhyBand(void) const
Get the configured Wi-Fi band.
Time GetSlot(void) const
Return the slot duration for this PHY.
static Time CalculateTxDuration(uint32_t size, const WifiTxVector &txVector, WifiPhyBand band, uint16_t staId=SU_STA_ID)
Time GetSifs(void) const
Return the Short Interframe Space (SIFS) for this PHY.
static Time CalculatePhyPreambleAndHeaderDuration(const WifiTxVector &txVector)
std::vector< Ptr< WifiMacQueueItem > >::const_iterator begin(void) const
Return a const iterator to the first MPDU.
std::size_t GetNMpdus(void) const
Return the number of MPDUs constituting the PSDU.
std::vector< Ptr< WifiMacQueueItem > >::const_iterator end(void) const
Return a const iterator to past-the-last MPDU.
Ptr< const Packet > GetPayload(std::size_t i) const
Get the payload of the i-th MPDU.
Mac48Address GetAddr2(void) const
Get the Transmitter Address (TA), which is common to all the MPDUs.
void SetDuration(Time duration)
Set the Duration/ID field on all the MPDUs.
Mac48Address GetAddr1(void) const
Get the Receiver Address (RA), which is common to all the MPDUs.
std::set< uint8_t > GetTids(void) const
Get the set of TIDs of the QoS Data frames included in the PSDU.
This class stores the TX parameters (TX vector, protection mechanism, acknowledgment mechanism,...
void Clear(void)
Reset the TX parameters.
std::unique_ptr< WifiProtection > m_protection
protection method
uint32_t GetSizeIfAddMpdu(Ptr< const WifiMacQueueItem > mpdu) const
Get the size in bytes of the frame in case the given MPDU is added.
std::unique_ptr< WifiAcknowledgment > m_acknowledgment
acknowledgment method
Time m_txDuration
TX duration of the frame.
WifiTxVector m_txVector
TXVECTOR of the frame being prepared.
void AddMpdu(Ptr< const WifiMacQueueItem > mpdu)
Record that an MPDU is being added to the current frame.
void Set(Reason reason, const Time &delay, MEM mem_ptr, OBJ obj, Args... args)
This method is called when a frame soliciting a response is transmitted.
bool IsRunning(void) const
Return true if the timer is running.
Reason
The reason why the timer was started.
@ WAIT_BLOCK_ACK_AFTER_TB_PPDU
@ WAIT_NORMAL_ACK_AFTER_DL_MU_PPDU
@ WAIT_QOS_NULL_AFTER_BSRP_TF
@ WAIT_TB_PPDU_AFTER_BASIC_TF
@ WAIT_BLOCK_ACKS_IN_TB_PPDU
This class mimics the TXVECTOR which is to be passed to the PHY in order to define the parameters whi...
bool IsDlMu(void) const
Return true if this TX vector is used for a downlink multi-user transmission.
void SetTxPowerLevel(uint8_t powerlevel)
Sets the selected transmission power level.
void SetHeMuUserInfo(uint16_t staId, HeMuUserInfo userInfo)
Set the HE MU user-specific transmission information for the given STA-ID.
void SetAggregation(bool aggregation)
Sets if PSDU contains A-MPDU.
void SetLength(uint16_t length)
Set the LENGTH field of the L-SIG.
const HeMuUserInfoMap & GetHeMuUserInfoMap(void) const
Get a const reference to the map HE MU user-specific transmission information indexed by STA-ID.
bool IsMu(void) const
Return true if this TX vector is used for a multi-user transmission.
void SetBssColor(uint8_t color)
Set the BSS color.
bool IsUlMu(void) const
Return true if this TX vector is used for an uplink multi-user transmission.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Time Now(void)
create an ns3::Time instance which contains the current simulation time.
Time Seconds(double value)
Construct a Time in the indicated unit.
AcIndex
This enumeration defines the Access Categories as an enumeration with values corresponding to the AC ...
Declaration of ns3::HePhy class and ns3::HeSigAParameters struct.
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::unordered_map< uint16_t, Ptr< const WifiPsdu > > WifiConstPsduMap
Map of const PSDUs indexed by STA-ID.
uint32_t GetAckSize(void)
Return the total Ack size (including FCS trailer).
uint32_t GetBlockAckRequestSize(BlockAckReqType type)
Return the total BlockAckRequest size (including FCS trailer).
uint32_t GetMuBarSize(std::list< BlockAckReqType > types)
Return the total MU-BAR size (including FCS trailer).
const std::map< AcIndex, WifiAc > wifiAcList
Map containing the four ACs in increasing order of priority (according to Table 10-1 "UP-to-AC Mappin...
Ptr< T > Copy(Ptr< T > object)
Return a deep copy of a Ptr.
uint32_t GetBlockAckSize(BlockAckType type)
Return the total BlockAck size (including FCS trailer).
std::unordered_map< uint16_t, Ptr< WifiPsdu > > WifiPsduMap
Map of PSDUs indexed by STA-ID.
U * PeekPointer(const Ptr< U > &p)
std::vector< uint8_t > m_bitmapLen
Length (bytes) of included bitmaps.
RxSignalInfo structure containing info on the received signal.
double snr
SNR in linear scale.
WifiAcknowledgment is an abstract base struct.
Time acknowledgmentTime
time required by the acknowledgment method
const Method method
acknowledgment method
WifiDlMuAggregateTf specifies that a DL MU PPDU made of PSDUs including each a MU-BAR Trigger Frame i...
uint16_t ulLength
the UL Length field of the MU-BAR Trigger Frames
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
WifiDlMuBarBaSequence specifies that a DL MU PPDU is acknowledged through a sequence of BlockAckReq a...
std::map< Mac48Address, BlockAckReqInfo > stationsSendBlockAckReqTo
Set of stations receiving a BlockAckReq frame and replying with a BlockAck frame.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame (no more than one)
std::map< Mac48Address, AckInfo > stationsReplyingWithNormalAck
Set of stations replying with an Ack frame (no more than one)
WifiDlMuTfMuBar specifies that a DL MU PPDU is followed after a SIFS duration by a MU-BAR Trigger Fra...
std::list< BlockAckReqType > barTypes
BAR types.
std::map< Mac48Address, BlockAckInfo > stationsReplyingWithBlockAck
Set of stations replying with a BlockAck frame.
uint16_t ulLength
the UL Length field of the MU-BAR Trigger Frame
WifiTxVector muBarTxVector
TXVECTOR used to transmit the MU-BAR Trigger Frame.
Information needed to remove an MSDU from the queue.
WifiNoAck specifies that no acknowledgment is required.
WifiNoProtection specifies that no protection method is used.
WifiUlMuMultiStaBa specifies that a Basic Trigger Frame is being sent to solicit TB PPDUs that will b...
BlockAckType baType
BlockAck type.
WifiTxVector tbPpduTxVector
TXVECTOR for a TB PPDU.
WifiTxVector multiStaBaTxVector
TXVECTOR for the Multi-STA BlockAck.
std::map< std::pair< Mac48Address, uint8_t >, std::size_t > stationsReceivingMultiStaBa
Map (originator, tid) pairs to the their index in baType.