From a0d3f50f59c7b5855d5e71e1f0843dfab2e6fbf3 Mon Sep 17 00:00:00 2001 From: Alberto Gallegos Ramonet Date: Mon, 16 Jun 2025 17:28:35 +0900 Subject: [PATCH] lr-wpan: Simplify PD-DATA.indication (ACK handle) --- src/lr-wpan/model/lr-wpan-mac.cc | 333 ++++++++++++++++--------------- src/lr-wpan/model/lr-wpan-mac.h | 7 + 2 files changed, 181 insertions(+), 159 deletions(-) diff --git a/src/lr-wpan/model/lr-wpan-mac.cc b/src/lr-wpan/model/lr-wpan-mac.cc index eae2a8fba..87bd416de 100644 --- a/src/lr-wpan/model/lr-wpan-mac.cc +++ b/src/lr-wpan/model/lr-wpan-mac.cc @@ -1034,10 +1034,6 @@ LrWpanMac::ReceiveInPromiscuousMode(uint8_t lqi, Ptr 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 p) } } +void +LrWpanMac::ReceiveAcknowledgment(Ptr p) +{ + NS_LOG_FUNCTION(this << p); + + // Make a copy of the original transmitted packet that required ACK and + // extract its MAC header. + Ptr 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(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(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 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 p) { @@ -2270,14 +2425,17 @@ LrWpanMac::PdDataIndication(uint32_t psduLength, Ptr 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 originalPkt = p->Copy(); - Ptr 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 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 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 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 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 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(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(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 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); } } diff --git a/src/lr-wpan/model/lr-wpan-mac.h b/src/lr-wpan/model/lr-wpan-mac.h index 80521f16a..cc6d37677 100644 --- a/src/lr-wpan/model/lr-wpan-mac.h +++ b/src/lr-wpan/model/lr-wpan-mac.h @@ -887,6 +887,13 @@ class LrWpanMac : public LrWpanMacBase */ void ReceiveData(uint8_t lqi, Ptr p); + /** + * Used to process an acknowledgment packet. + * + * @param p The packet containing the MAC header and the data payload. + */ + void ReceiveAcknowledgment(Ptr p); + /** * Display the MAC header contents of a successfully received packet when * logs are active.