lr-wpan: Simplify PD-DATA.indication (ACK handle)

This commit is contained in:
Alberto Gallegos Ramonet
2025-06-16 17:28:35 +09:00
parent 5cc5c00619
commit a0d3f50f59
2 changed files with 181 additions and 159 deletions

View File

@@ -1034,10 +1034,6 @@ LrWpanMac::ReceiveInPromiscuousMode(uint8_t lqi, Ptr<Packet> p)
{
NS_LOG_FUNCTION(this);
// Strip the MAC header and MAC trailer
LrWpanMacTrailer receivedMacTrailer;
p->RemoveTrailer(receivedMacTrailer);
LrWpanMacHeader receivedMacHdr;
p->RemoveHeader(receivedMacHdr);
@@ -2146,6 +2142,165 @@ LrWpanMac::ReceiveData(uint8_t lqi, Ptr<Packet> p)
}
}
void
LrWpanMac::ReceiveAcknowledgment(Ptr<Packet> p)
{
NS_LOG_FUNCTION(this << p);
// Make a copy of the original transmitted packet that required ACK and
// extract its MAC header.
Ptr<Packet> txPkt = m_txPkt->Copy();
LrWpanMacHeader txMacHdr;
txPkt->RemoveHeader(txMacHdr);
// Extract the MAC header of the ACK packet.
LrWpanMacHeader rxMacHdr;
p->RemoveHeader(rxMacHdr);
LrWpanMacTrailer receivedMacTrailer;
p->RemoveTrailer(receivedMacTrailer);
// If it is an ACK with an unexpected sequence number, mark the current
// transmission as failed and start a retransmit. (cf 7.5.6.4.3)
if (rxMacHdr.GetSeqNum() != txMacHdr.GetSeqNum())
{
m_ackWaitTimeout.Cancel();
if (!PrepareRetransmission())
{
m_setMacState.Cancel();
m_setMacState = Simulator::ScheduleNow(&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE);
}
else
{
m_setMacState.Cancel();
m_setMacState = Simulator::ScheduleNow(&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA);
}
return;
}
// If it is an ACK with the expected sequence number, finish the transmission
m_ackWaitTimeout.Cancel();
m_macTxOkTrace(m_txPkt);
// TODO: check if the IFS is the correct size after ACK.
double symbolRate = m_phy->GetDataOrSymbolRate(false);
Time ifsWaitTime = Seconds((double)GetIfsSize() / symbolRate);
if (txMacHdr.IsCommand())
{
// We received an ACK to a command, we need to take actions depending on the
// transmitted command.
// Extract the command payload of the originally transmitted packet to know
// what command we transmitted.
CommandPayloadHeader txCmdPayload;
txPkt->RemoveHeader(txCmdPayload);
switch (txCmdPayload.GetCommandFrameType())
{
case CommandPayloadHeader::ASSOCIATION_REQ: {
Time waitTime = Seconds(static_cast<double>(m_macResponseWaitTime) / symbolRate);
if (!m_beaconTrackingOn)
{
m_respWaitTimeout =
Simulator::Schedule(waitTime, &LrWpanMac::SendDataRequestCommand, this);
}
else
{
// TODO: The data must be extracted by the coordinator within
// macResponseWaitTime on timeout, MLME-ASSOCIATE.confirm is set
// with status NO_DATA, and this should trigger the cancellation
// of the beacon tracking (MLME-SYNC.request trackBeacon
// =FALSE)
}
break;
}
case CommandPayloadHeader::ASSOCIATION_RESP: {
// MLME-comm-status.Indication generated as a result of an
// association response command, therefore src and dst address use
// extended mode (see 5.3.2.1)
if (!m_mlmeCommStatusIndicationCallback.IsNull())
{
MlmeCommStatusIndicationParams commStatusParams;
commStatusParams.m_panId = m_macPanId;
commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
commStatusParams.m_srcExtAddr = txMacHdr.GetExtSrcAddr();
commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
commStatusParams.m_dstExtAddr = txMacHdr.GetExtDstAddr();
commStatusParams.m_status = MacStatus::SUCCESS;
m_mlmeCommStatusIndicationCallback(commStatusParams);
}
// Remove element from Pending Transaction List
RemovePendTxQElement(m_txPkt->Copy());
break;
}
case CommandPayloadHeader::DATA_REQ: {
if (!m_ignoreDataCmdAck)
{
// Schedule an event in case the Association Response Command
// never reached this device during an association process.
Time waitTime = Seconds(static_cast<double>(m_assocRespCmdWaitTime) / symbolRate);
m_assocResCmdWaitTimeout =
Simulator::Schedule(waitTime, &LrWpanMac::LostAssocRespCommand, this);
}
if (!m_mlmePollConfirmCallback.IsNull())
{
MlmePollConfirmParams pollConfirmParams;
pollConfirmParams.m_status = MacStatus::SUCCESS;
m_mlmePollConfirmCallback(pollConfirmParams);
}
break;
}
case CommandPayloadHeader::COOR_REALIGN: {
// ACK of coordinator realigment commands is not specified in the
// standard, in here, we assume they are required as in other
// commands.
if (!m_mlmeCommStatusIndicationCallback.IsNull())
{
MlmeCommStatusIndicationParams commStatusParams;
commStatusParams.m_panId = m_macPanId;
commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
commStatusParams.m_srcExtAddr = txMacHdr.GetExtSrcAddr();
commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
commStatusParams.m_dstExtAddr = txMacHdr.GetExtDstAddr();
commStatusParams.m_status = MacStatus::SUCCESS;
m_mlmeCommStatusIndicationCallback(commStatusParams);
}
break;
}
default: {
// TODO: add response to other request commands (e.g. Orphan)
break;
}
}
}
else
{
// Receive ACK to data packet
if (!m_mcpsDataConfirmCallback.IsNull())
{
Ptr<TxQueueElement> txQElement = m_txQueue.front();
McpsDataConfirmParams confirmParams;
confirmParams.m_msduHandle = txQElement->txQMsduHandle;
confirmParams.m_status = MacStatus::SUCCESS;
m_mcpsDataConfirmCallback(confirmParams);
}
}
// Ack was successfully received, wait for the Interframe Space (IFS) and
// then proceed
RemoveFirstTxQElement();
m_setMacState.Cancel();
m_setMacState = Simulator::ScheduleNow(&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE);
m_ifsEvent = Simulator::Schedule(ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this, ifsWaitTime);
}
void
LrWpanMac::PrintPacket(Ptr<Packet> p)
{
@@ -2270,14 +2425,17 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr<Packet> p, uint8_t lqi)
NS_ASSERT(m_macState == MAC_IDLE || m_macState == MAC_ACK_PENDING || m_macState == MAC_CSMA);
NS_LOG_FUNCTION(this << psduLength << p << (uint16_t)lqi);
bool acceptFrame;
Ptr<Packet> originalPkt = p->Copy();
Ptr<Packet> originalPkt = p->Copy(); // because we will strip headers
auto symbolRate = (uint64_t)m_phy->GetDataOrSymbolRate(false); // symbols per second
m_promiscSnifferTrace(originalPkt);
m_macPromiscRxTrace(originalPkt);
// XXX no rejection tracing (to macRxDropTrace) being performed below
// If active, pass the packet to the traces
if (!m_promiscSnifferTrace.IsEmpty())
{
m_promiscSnifferTrace(p->Copy());
}
else if (!m_macPromiscRxTrace.IsEmpty())
{
m_macPromiscRxTrace(p->Copy());
}
LrWpanMacTrailer receivedMacTrailer;
p->RemoveTrailer(receivedMacTrailer);
@@ -2311,11 +2469,12 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr<Packet> p, uint8_t lqi)
if (m_macPromiscuousMode)
{
PrintPacket(originalPkt);
ReceiveInPromiscuousMode(lqi, originalPkt);
ReceiveInPromiscuousMode(lqi, p);
return;
}
// Level 3 frame filtering
bool acceptFrame;
acceptFrame = (receivedMacHdr.GetType() != LrWpanMacHeader::LRWPAN_MAC_RESERVED);
if (acceptFrame)
@@ -2402,6 +2561,7 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr<Packet> p, uint8_t lqi)
Time timeLeftInCap = Simulator::GetDelayLeft(m_capEvent);
uint64_t ackSymbols = lrwpan::aTurnaroundTime + m_phy->GetPhySHRDuration() +
ceil(6 * m_phy->GetPhySymbolsPerOctet());
auto symbolRate = m_phy->GetDataOrSymbolRate(false); // symbols per second
Time ackTime = Seconds((double)ackSymbols / symbolRate);
if (ackTime >= timeLeftInCap)
@@ -2457,7 +2617,7 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr<Packet> p, uint8_t lqi)
// save received packet and LQI to process the appropriate indication/response
// after sending ACK (PD-DATA.confirm)
m_rxPkt = originalPkt->Copy();
m_rxPkt = originalPkt;
m_lastRxFrameLqi = lqi;
// LOG Commands with ACK required.
@@ -2516,152 +2676,7 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr<Packet> p, uint8_t lqi)
}
else if (receivedMacHdr.IsAcknowledgment() && m_txPkt && m_macState == MAC_ACK_PENDING)
{
LrWpanMacHeader peekedMacHdr;
m_txPkt->PeekHeader(peekedMacHdr);
// If it is an ACK with the expected sequence number, finish the transmission
if (receivedMacHdr.GetSeqNum() == peekedMacHdr.GetSeqNum())
{
m_ackWaitTimeout.Cancel();
m_macTxOkTrace(m_txPkt);
// TODO: check if the IFS is the correct size after ACK.
Time ifsWaitTime = Seconds((double)GetIfsSize() / symbolRate);
// We received an ACK to a command
if (peekedMacHdr.IsCommand())
{
// check the original sent command frame which belongs to this received
// ACK
Ptr<Packet> pkt = m_txPkt->Copy();
LrWpanMacHeader macHdr;
CommandPayloadHeader cmdPayload;
pkt->RemoveHeader(macHdr);
pkt->RemoveHeader(cmdPayload);
switch (cmdPayload.GetCommandFrameType())
{
case CommandPayloadHeader::ASSOCIATION_REQ: {
double symbolRate = m_phy->GetDataOrSymbolRate(false);
Time waitTime =
Seconds(static_cast<double>(m_macResponseWaitTime) / symbolRate);
if (!m_beaconTrackingOn)
{
m_respWaitTimeout =
Simulator::Schedule(waitTime, &LrWpanMac::SendDataRequestCommand, this);
}
else
{
// TODO: The data must be extracted by the coordinator within
// macResponseWaitTime on timeout, MLME-ASSOCIATE.confirm is set
// with status NO_DATA, and this should trigger the cancellation
// of the beacon tracking (MLME-SYNC.request trackBeacon
// =FALSE)
}
break;
}
case CommandPayloadHeader::ASSOCIATION_RESP: {
// MLME-comm-status.Indication generated as a result of an
// association response command, therefore src and dst address use
// extended mode (see 5.3.2.1)
if (!m_mlmeCommStatusIndicationCallback.IsNull())
{
MlmeCommStatusIndicationParams commStatusParams;
commStatusParams.m_panId = m_macPanId;
commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
commStatusParams.m_status = MacStatus::SUCCESS;
m_mlmeCommStatusIndicationCallback(commStatusParams);
}
// Remove element from Pending Transaction List
RemovePendTxQElement(m_txPkt->Copy());
break;
}
case CommandPayloadHeader::DATA_REQ: {
if (!m_ignoreDataCmdAck)
{
// Schedule an event in case the Association Response Command
// never reached this device during an association process.
double symbolRate = m_phy->GetDataOrSymbolRate(false);
Time waitTime =
Seconds(static_cast<double>(m_assocRespCmdWaitTime) / symbolRate);
m_assocResCmdWaitTimeout =
Simulator::Schedule(waitTime, &LrWpanMac::LostAssocRespCommand, this);
}
if (!m_mlmePollConfirmCallback.IsNull())
{
MlmePollConfirmParams pollConfirmParams;
pollConfirmParams.m_status = MacStatus::SUCCESS;
m_mlmePollConfirmCallback(pollConfirmParams);
}
break;
}
case CommandPayloadHeader::COOR_REALIGN: {
// ACK of coordinator realigment commands is not specified in the
// standard, in here, we assume they are required as in other
// commands.
if (!m_mlmeCommStatusIndicationCallback.IsNull())
{
MlmeCommStatusIndicationParams commStatusParams;
commStatusParams.m_panId = m_macPanId;
commStatusParams.m_srcAddrMode = LrWpanMacHeader::EXTADDR;
commStatusParams.m_srcExtAddr = macHdr.GetExtSrcAddr();
commStatusParams.m_dstAddrMode = LrWpanMacHeader::EXTADDR;
commStatusParams.m_dstExtAddr = macHdr.GetExtDstAddr();
commStatusParams.m_status = MacStatus::SUCCESS;
m_mlmeCommStatusIndicationCallback(commStatusParams);
}
}
default: {
// TODO: add response to other request commands (e.g. Orphan)
break;
}
}
}
else
{
if (!m_mcpsDataConfirmCallback.IsNull())
{
Ptr<TxQueueElement> txQElement = m_txQueue.front();
McpsDataConfirmParams confirmParams;
confirmParams.m_msduHandle = txQElement->txQMsduHandle;
confirmParams.m_status = MacStatus::SUCCESS;
m_mcpsDataConfirmCallback(confirmParams);
}
}
// Ack was successfully received, wait for the Interframe Space (IFS) and
// then proceed
RemoveFirstTxQElement();
m_setMacState.Cancel();
m_setMacState = Simulator::ScheduleNow(&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE);
m_ifsEvent =
Simulator::Schedule(ifsWaitTime, &LrWpanMac::IfsWaitTimeout, this, ifsWaitTime);
}
else
{
// If it is an ACK with an unexpected sequence number, mark the current
// transmission as failed and start a retransmit. (cf 7.5.6.4.3)
m_ackWaitTimeout.Cancel();
if (!PrepareRetransmission())
{
m_setMacState.Cancel();
m_setMacState =
Simulator::ScheduleNow(&LrWpanMac::SetLrWpanMacState, this, MAC_IDLE);
}
else
{
m_setMacState.Cancel();
m_setMacState =
Simulator::ScheduleNow(&LrWpanMac::SetLrWpanMacState, this, MAC_CSMA);
}
}
ReceiveAcknowledgment(originalPkt);
}
}

View File

@@ -887,6 +887,13 @@ class LrWpanMac : public LrWpanMacBase
*/
void ReceiveData(uint8_t lqi, Ptr<Packet> p);
/**
* Used to process an acknowledgment packet.
*
* @param p The packet containing the MAC header and the data payload.
*/
void ReceiveAcknowledgment(Ptr<Packet> p);
/**
* Display the MAC header contents of a successfully received packet when
* logs are active.