handle block ack and block ack request frames in MacLow

This commit is contained in:
Mirko Banchi
2010-02-03 20:34:51 +01:00
parent 414f6292b8
commit 353ba8c46f
2 changed files with 321 additions and 2 deletions

View File

@@ -695,6 +695,51 @@ MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiMode txMode, WifiPreamb
&MacLow::WaitSifsAfterEndTx, this);
}
}
else if (hdr.IsBlockAck () && hdr.GetAddr1 () == m_self &&
(m_txParams.MustWaitBasicBlockAck () || m_txParams.MustWaitCompressedBlockAck ()))
//m_blockAckTimeoutEvent.IsRunning ())
{
NS_LOG_DEBUG ("got block ack from "<<hdr.GetAddr2 ());
CtrlBAckResponseHeader blockAck;
packet->RemoveHeader (blockAck);
//m_blockAckTimeoutEvent.Cancel ();
m_listener->GotBlockAck (&blockAck, hdr.GetAddr2 ());
}
else if (hdr.IsBlockAckReq () && hdr.GetAddr1 () == m_self)
{
CtrlBAckRequestHeader blockAckReq;
packet->RemoveHeader (blockAckReq);
if (!blockAckReq.IsMultiTid ())
{
AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), blockAckReq.GetTidInfo ()));
if (it != m_bAckAgreements.end ())
{
NS_ASSERT (m_sendAckEvent.IsExpired ());
if ((*it).second.first.IsImmediateBlockAck ())
{
NS_LOG_DEBUG ("rx blockAckRequest/sendImmediateBlockAck from="<< hdr.GetAddr2 ());
m_sendAckEvent = Simulator::Schedule (GetSifs (),
&MacLow::SendBlockAckAfterBlockAckRequest, this,
blockAckReq,
hdr.GetAddr2 (),
hdr.GetDuration (),
txMode);
}
else
{
NS_FATAL_ERROR ("Delayed block ack not supported.");
}
}
else
{
NS_LOG_DEBUG ("There's not a valid agreement for this block ack request.");
}
}
else
{
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
}
}
else if (hdr.IsCtl ())
{
NS_LOG_DEBUG ("rx drop " << hdr.GetTypeString ());
@@ -704,7 +749,41 @@ MacLow::ReceiveOk (Ptr<Packet> packet, double rxSnr, WifiMode txMode, WifiPreamb
WifiRemoteStation *station = GetStation (hdr.GetAddr2 ());
station->ReportRxOk (rxSnr, txMode);
if (hdr.IsQosData () && hdr.IsQosNoAck ())
if (hdr.IsQosData () && StoreMpduIfNeeded (packet, hdr))
{
/* From section 9.10.4 in IEEE802.11:
Upon the receipt of a QoS data frame from the originator for which
the Block Ack agreement exists, the recipient shall buffer the MSDU
regardless of the value of the Ack Policy subfield within the
QoS Control field of the QoS data frame. */
if (hdr.IsQosAck ())
{
AgreementsI it = m_bAckAgreements.find (std::make_pair (hdr.GetAddr2 (), hdr.GetQosTid ()));
RxCompleteBufferedPacketsWithSmallerSequence (it->second.first.GetStartingSequence (),
hdr.GetAddr2 (), hdr.GetQosTid ());
RxCompleteBufferedPackets (hdr.GetAddr2 (), hdr.GetQosTid ());
NS_ASSERT (m_sendAckEvent.IsExpired ());
m_sendAckEvent = Simulator::Schedule (GetSifs (),
&MacLow::SendAckAfterData, this,
hdr.GetAddr2 (),
hdr.GetDuration (),
txMode,
rxSnr);
}
return;
}
else if (hdr.IsQosData () && hdr.IsQosBlockAck ())
{
/* This happens if a packet with ack policy Block Ack is received and a block ack
agreement for that packet doesn't exist.
From section 11.5.3 in IEEE802.11e:
When a recipient does not have an active Block ack for a TID, but receives
data MPDUs with the Ack Policy subfield set to Block Ack, it shall discard
them [...]. */
return;
}
else if (hdr.IsQosData () && hdr.IsQosNoAck ())
{
NS_LOG_DEBUG ("rx unicast/noAck from="<<hdr.GetAddr2 ());
}
@@ -752,6 +831,27 @@ MacLow::GetAckSize (void) const
ack.SetType (WIFI_MAC_CTL_ACK);
return ack.GetSize () + 4;
}
uint32_t
MacLow::GetBlockAckSize (enum BlockAckType type) const
{
WifiMacHeader hdr;
hdr.SetType (WIFI_MAC_CTL_BACKRESP);
CtrlBAckResponseHeader blockAck;
if (type == BASIC_BLOCK_ACK)
{
blockAck.SetType (BASIC_BLOCK_ACK);
}
else if (type == COMPRESSED_BLOCK_ACK)
{
blockAck.SetType (COMPRESSED_BLOCK_ACK);
}
else if (type == MULTI_TID_BLOCK_ACK)
{
//Not implemented
NS_ASSERT (false);
}
return hdr.GetSize () + blockAck.GetSerializedSize () + 4;
}
uint32_t
MacLow::GetRtsSize (void) const
{
@@ -766,6 +866,12 @@ MacLow::GetAckDuration (Mac48Address to, WifiMode dataTxMode) const
return m_phy->CalculateTxDuration (GetAckSize (), ackMode, WIFI_PREAMBLE_LONG);
}
Time
MacLow::GetBlockAckDuration (Mac48Address to, WifiMode blockAckReqTxMode, enum BlockAckType type) const
{
//WifiMode blockAckMode = GetBlockAckTxModeForBlockAckReq (to, blockAckReqTxMode);
return m_phy->CalculateTxDuration (GetBlockAckSize (type), blockAckReqTxMode, WIFI_PREAMBLE_LONG);
}
Time
MacLow::GetCtsDuration (Mac48Address to, WifiMode rtsTxMode) const
{
WifiMode ctsMode = GetCtsTxModeForRts (to, rtsTxMode);
@@ -1144,7 +1250,17 @@ MacLow::SendDataPacket (void)
}
else
{
if (m_txParams.MustWaitAck ())
if (m_txParams.MustWaitBasicBlockAck ())
{
duration += GetSifs ();
duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxMode, BASIC_BLOCK_ACK);
}
else if (m_txParams.MustWaitCompressedBlockAck ())
{
duration += GetSifs ();
duration += GetBlockAckDuration (m_currentHdr.GetAddr1 (), dataTxMode, COMPRESSED_BLOCK_ACK);
}
else if (m_txParams.MustWaitAck ())
{
duration += GetSifs ();
duration += GetAckDuration (m_currentHdr.GetAddr1 (), dataTxMode);
@@ -1435,4 +1551,193 @@ MacLow::RxCompleteBufferedPackets (Mac48Address originator, uint8_t tid)
}
}
void
MacLow::SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Address originator, bool immediate,
Time duration, WifiMode blockAckReqTxMode)
{
Ptr<Packet> packet = Create<Packet> ();
packet->AddHeader (*blockAck);
WifiMacHeader hdr;
hdr.SetType (WIFI_MAC_CTL_BACKRESP);
hdr.SetAddr1 (originator);
hdr.SetAddr2 (GetAddress ());
hdr.SetDsNotFrom ();
hdr.SetDsNotTo ();
hdr.SetNoRetry ();
hdr.SetNoMoreFragments ();
m_currentPacket = packet;
m_currentHdr = hdr;
if (immediate)
{
m_txParams.DisableAck ();
duration -= GetSifs ();
/* from section 9.6 in IEEE802.11e:
The BlockAck control frame shall be sent at the same rate and modulation class as
the BlockAckReq frame if it is sent in response to a BlockAckReq frame.*/
if (blockAck->IsBasic ())
{
duration -= GetBlockAckDuration (originator, blockAckReqTxMode, BASIC_BLOCK_ACK);
}
else if (blockAck->IsCompressed ())
{
duration -= GetBlockAckDuration (originator, blockAckReqTxMode, COMPRESSED_BLOCK_ACK);
}
else if (blockAck->IsMultiTid ())
{
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
}
}
else
{
m_txParams.EnableAck ();
duration += GetSifs ();
duration += GetAckDuration (originator, blockAckReqTxMode);
}
m_txParams.DisableNextData ();
StartDataTxTimers ();
NS_ASSERT (duration >= MicroSeconds (0));
hdr.SetDuration (duration);
//here should be present a control about immediate or delayed block ack
//for now we assume immediate
packet->AddHeader (hdr);
WifiMacTrailer fcs;
packet->AddTrailer (fcs);
ForwardDown (packet, &hdr, blockAckReqTxMode);
m_currentPacket = 0;
}
void
MacLow::SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator,
Time duration, WifiMode blockAckReqTxMode)
{
NS_LOG_FUNCTION (this);
CtrlBAckResponseHeader blockAck;
uint8_t tid;
bool immediate = false;
if (!reqHdr.IsMultiTid ())
{
blockAck.SetStartingSequence (reqHdr.GetStartingSequence ());
blockAck.SetTidInfo (reqHdr.GetTidInfo ());
tid = reqHdr.GetTidInfo ();
AgreementsI it;
it = m_bAckAgreements.find (std::make_pair (originator, tid));
if (it != m_bAckAgreements.end ())
{
immediate = (*it).second.first.IsImmediateBlockAck ();
uint16_t startingSeqCtrl = reqHdr.GetStartingSequenceControl ();
/* All packets with smaller sequence than starting sequence control must be passed up to Wifimac
* See 9.10.3 in IEEE8022.11e standard.
*/
RxCompleteBufferedPacketsWithSmallerSequence ((startingSeqCtrl>>4)&0xfff0, originator, tid);
std::list<BufferedPacket>::iterator i = (*it).second.second.begin ();
/* For more details about next operations see section 9.10.4 of IEEE802.11e standard */
if (reqHdr.IsBasic ())
{
blockAck.SetType (BASIC_BLOCK_ACK);
uint16_t guard = startingSeqCtrl;
std::list<BufferedPacket>::iterator lastComplete = (*it).second.second.begin ();
for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++)
{
blockAck.SetReceivedFragment ((*i).second.GetSequenceNumber (),
(*i).second.GetFragmentNumber ());
/* Section 9.10.4 in IEEE802.11n: the recipient shall pass up to WifiMac the
* MSDUs and A-MSDUs starting with the starting sequence number
* sequentially until there is an incomplete MSDU or A-MSDU in the buffer */
if (!(*i).second.IsMoreFragments ())
{
while (lastComplete != i)
{
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
lastComplete++;
}
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
lastComplete++;
}
guard = (*i).second.IsMoreFragments () ? (guard + 1) : (guard + 16) & 0xfff0;
}
(*it).second.first.SetStartingSequence ((guard>>4)&0x0fff);
/* All packets already forwarded to WifiMac must be removed from buffer:
[begin (), lastComplete) */
(*it).second.second.erase ((*it).second.second.begin (), lastComplete);
for (i = lastComplete; i != (*it).second.second.end (); i++)
{
blockAck.SetReceivedFragment ((*i).second.GetSequenceNumber (),
(*i).second.GetFragmentNumber ());
}
}
else if (reqHdr.IsCompressed ())
{
blockAck.SetType (COMPRESSED_BLOCK_ACK);
uint16_t guard = startingSeqCtrl;
std::list<BufferedPacket>::iterator lastComplete = (*it).second.second.begin ();
for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++)
{
if (!(*i).second.IsMoreFragments ())
{
blockAck.SetReceivedPacket ((*i).second.GetSequenceNumber ());
while (lastComplete != i)
{
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
lastComplete++;
}
m_rxCallback ((*lastComplete).first, &(*lastComplete).second);
lastComplete++;
}
guard = (*i).second.IsMoreFragments () ? (guard + 1) : (guard + 16) & 0xfff0;
}
(*it).second.first.SetStartingSequence ((guard>>4)&0x0fff);
/* All packets already forwarded to WifiMac must be removed from buffer:
[begin (), lastcomplete) */
(*it).second.second.erase ((*it).second.second.begin (), lastComplete);
i = lastComplete;
if (i != (*it).second.second.end ())
{
guard = (*i).second.GetSequenceControl () & 0xfff0;
}
for (; i != (*it).second.second.end ();)
{
for (; i != (*it).second.second.end () && guard == (*i).second.GetSequenceControl (); i++)
{
if (!(*i).second.IsMoreFragments ())
{
guard = (guard + 16) & 0xfff0;
blockAck.SetReceivedPacket ((*i).second.GetSequenceNumber ());
}
else
{
guard += 1;
}
}
while (i != (*it).second.second.end () && ((guard >> 4) & 0x0fff) == (*i).second.GetSequenceNumber ())
{
i++;
}
if (i != (*it).second.second.end ())
{
guard = (*i).second.GetSequenceControl () & 0xfff0;
}
}
}
}
else
{
NS_LOG_DEBUG ("there's not a valid block ack agreement with "<<originator);
}
}
else
{
NS_FATAL_ERROR ("Multi-tid block ack is not supported.");
}
SendBlockAckResponse (&blockAck, originator, immediate, duration, blockAckReqTxMode);
}
} // namespace ns3

View File

@@ -440,6 +440,7 @@ public:
private:
void CancelAllEvents (void);
uint32_t GetAckSize (void) const;
uint32_t GetBlockAckSize (enum BlockAckType type) const;
uint32_t GetRtsSize (void) const;
uint32_t GetCtsSize (void) const;
uint32_t GetSize (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
@@ -454,8 +455,10 @@ private:
WifiMode GetDataTxMode (Ptr<const Packet> packet, const WifiMacHeader *hdr) const;
WifiMode GetCtsTxModeForRts (Mac48Address to, WifiMode rtsTxMode) const;
WifiMode GetAckTxModeForData (Mac48Address to, WifiMode dataTxMode) const;
Time GetCtsDuration (Mac48Address to, WifiMode rtsTxMode) const;
Time GetAckDuration (Mac48Address to, WifiMode dataTxMode) const;
Time GetBlockAckDuration (Mac48Address to, WifiMode blockAckReqTxMode, enum BlockAckType type) const;
void NotifyNav (const WifiMacHeader &hdr, WifiMode txMode, WifiPreamble preamble);
void DoNavResetNow (Time duration);
bool DoNavStartNow (Time duration);
@@ -511,6 +514,17 @@ private:
* circularly modulo 2^12.
*/
bool StoreMpduIfNeeded (Ptr<Packet> packet, WifiMacHeader hdr);
/*
* Invoked after that a block ack request has been received. Looks for corresponding
* block ack agreement and creates block ack bitmap on a received packets basis.
*/
void SendBlockAckAfterBlockAckRequest (const CtrlBAckRequestHeader reqHdr, Mac48Address originator,
Time duration, WifiMode blockAckReqTxMode);
/*
* This method creates block ack frame with header equals to <i>blockAck</i> and start its transmission.
*/
void SendBlockAckResponse (const CtrlBAckResponseHeader* blockAck, Mac48Address originator, bool immediate,
Time duration, WifiMode blockAckReqTxMode);
void SetupPhyMacLowListener (Ptr<WifiPhy> phy);