Repository navigation
ieee80211: fix MAC cancellation and lifecycle reset - #1286
mgonzalezlopezudc wants to merge 3 commits into
Conversation
MAC callbacks can cancel or replace delayed transmissions. Record request identity, callback lifetime, and lifecycle reset contracts. Explain Block Ack expiry, buffer retirement, and replacement preservation. Define direct verification for the two functional changes. Plan: plan/pending/ieee80211-mac-cancellation-lifecycle.md Change: plan | behavior.add | - | ieee80211-mac-cancellation-lifecycle
A synchronous callback can cancel a delayed frame or start another sequence. An old callback must not advance the replacement sequence. The MAC allocates a request identity before it submits the frame to Tx. Tx checks that identity after each permission callback, including zero interframe space (IFS). The sequence handler defers disposal until nested callbacks return. Tx callback guards preserve borrowed sequence objects during that scope. The contention module detaches its callback before channel-grant notification. This permits a synchronous callback to request channel access again. Response timeouts retain their order relative to equal-time network allocation vector (NAV) events. Hypothetical: request A waits for IFS. Its permission callback replaces A with B. Tx detects the changed identity and cannot transmit A. B retains its own request identity. Tx and its callback consumers require the same request contract. A partial interface migration cannot compile or preserve cancellation across synchronous calls. External Tx modules and handlers require source changes and a rebuild. Plan: plan/pending/ieee80211-mac-cancellation-lifecycle.md Change: src.ieee80211.mac | behavior.add+change | test whatsnew migration | ieee80211-mac-cancellation-lifecycle
Stop and crash can leave a delayed or on-air request alive in the medium access control (MAC) transmission module (Tx). The hybrid coordination function (HCF) can also retain Block Ack agreements without an inactivity timer after resume. Block Ack reports reception status for multiple frames. An expired recipient agreement can leave an old reorder buffer or admit late Block Ack data. MAC resets Tx before the coordination functions retire their exchanges. A new lifecycle epoch rejects old requests. Group, Block Ack, and No Ack transmissions do not enter Normal Ack failure processing. Normal Ack uses an acknowledgment (ACK) frame for each required response. Add block acknowledgment (ADDBA) establishes an agreement. Recipient setup has no inactivity deadline until its first matching ADDBA response transmission completes. Each response carries a local setup identity. HCF rejects stale queued responses before transmission. Late response completion cannot activate or renew a replacement agreement. Response retries preserve the first deadline. HCF retains each active agreement's absolute deadline across downtime. Resume retires overdue agreements before channel access. Each handler detaches expired state before deletion callbacks. Recipient retirement clears only the corresponding peer and traffic identifier (TID)'s buffer. HCF discards late Block Ack data and queues a delete block acknowledgment (DELBA) frame. Delayed timeout or UNKNOWN_BA completion preserves a replacement agreement. For example, an agreement starts at sequence 19 and buffers sequence 20. After expiry, replacement ADDBA starts at sequence 100. The cleared buffer lets HCF deliver sequence 100. Late Block Ack data without an agreement instead causes discard and UNKNOWN_BA DELBA. The reset, deadline, buffer, and deletion contracts form one lifecycle change. Their callers require the same interfaces before stop or resume can use them. External Tx modules, handlers, ACK owners, agreement handlers, callbacks, and recipient data services require source changes. The module tests cover both expiry event orders, stop/crash restart, zero timeout, buffer isolation, and replacement preservation. A queued response survives two seconds of downtime with a one-second inactivity timeout. Its first transmission starts the deadline. The unit test verifies pending setup and duplicate, expired, and replacement response identities. The production restart fixture also verifies stale response refusal and replacement transmission. IEEE Std 802.11-2024, 11.5.4 defines expiry and late-data discard. Table 9-79 defines the DELBA reason codes. Plan: plan/pending/ieee80211-mac-cancellation-lifecycle.md Change: src.ieee80211.mac | behavior.add+change.fix | test whatsnew migration | ieee80211-mac-cancellation-lifecycle
| if (agreement->getExpirationTime() <= simTime()) { | ||
| callback->expireBlockAckAgreements(); | ||
| return; |
There was a problem hiding this comment.
🔴 Late Block Ack acknowledges expired frames
If Block Ack arrives at its deadline before the timer, processReceivedBlockAck retires the agreement too late. HCF's receive path already marked and removed acknowledged frames.
Learn more
A Block Ack bitmap identifies transmitted frames the peer says it received. When its arrival event precedes the inactivity timer at the same deadline, HCF's receive path applies the bitmap to the ACK handler before calling this expiry check. This handler then retires the overdue agreement, but cannot undo the acknowledgments or the frame removals.
Example: An agreement expires at 5 s. A Block Ack event at 5 s executes before the timeout event. Its acknowledged frames are dropped from the originator queue, although this code rejects renewal of the agreement.
Recommended fix: Check and retire overdue originator agreements before QosAckHandler::processReceivedBlockAck and InProgressFrames::dropFrames run. Gate bitmap processing on an active agreement; preserve normal handling of other control responses.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if (auto dataHeader = dynamicPtrCast<const Ieee80211DataHeader>(header)) { | ||
| if (dataHeader->getType() == ST_DATA_WITH_QOS && recipientBlockAckAgreementHandler) | ||
| recipientBlockAckAgreementHandler->qosFrameReceived(dataHeader, this); | ||
| if (dataHeader->getType() == ST_DATA_WITH_QOS && recipientBlockAckAgreementHandler && | ||
| !recipientBlockAckAgreementHandler->qosFrameReceived(dataHeader, this, this)) { | ||
| delete packet; |
There was a problem hiding this comment.
🔴 Expired agreement answers Block Ack requests
When a Block Ack Request precedes the timer at its deadline, recipientProcessReceivedControlFrame still uses the overdue agreement. Its reorder buffer can release frames, and the recipient sends a Block Ack response.
Learn more
The new receive guard applies only to QoS data. A Block Ack Request is a control frame, so it enters controlFrameReceived and processReceivedBlockAckReq. Both read the agreement without checking its deadline. A request processed before the timer at the same simulation time therefore reorders buffered data and produces a response based on expired state.
Example: A recipient agreement expires at 5 s with sequence 20 buffered. A Block Ack Request at 5 s runs first and requests sequences starting at 21. The old buffer is processed and a Block Ack is sent; expiry only clears it afterward.
Recommended fix: Retire overdue agreements before control-frame processing can access the recipient agreement, including the Block Ack Request path. Prevent expired state from driving reordering or response construction.
Was this helpful? React with 👍 or 👎 to provide feedback.
| addbaResponsePacket->addTag<Ieee80211MgmtTransactionTag>()->setTransactionId(agreement->getAgreementId()); | ||
| callback->processMgmtFrame(addbaResponsePacket, addbaResponse); |
There was a problem hiding this comment.
🟡 ADDBA renewal loses its response
If an ADDBA request precedes expiry processing at its deadline, addAgreement reuses the overdue setup. The response carries its old identity; the timer retires it, so transmission rejects the response.
Learn more
A recipient agreement remains in addAgreement until the timer runs. An ADDBA request arriving first at the deadline gets that old agreement rather than a new setup. Its response is tagged with the old identity. The timer then removes that agreement, and isTransmissionPermitted rejects the queued response.
Example: Agreement A expires at 5 s. A new request from the same peer and TID executes at 5 s before the timeout event. Its response receives A's ID; after timeout, the response cannot transmit, and no replacement agreement exists.
Recommended fix: Expire overdue agreements before processing incoming ADDBA requests, then allocate a fresh setup and tag its response with the fresh identity.
Was this helpful? React with 👍 or 👎 to provide feedback.
| for (auto frame : retained) { | ||
| ackHandler->dropFrame(frame->peekAtFront<Ieee80211DataOrMgmtHeader>()); | ||
| dropFrame(frame); | ||
| } | ||
| // A synchronous callback can still borrow a dropped frame. Normal deferred cleanup owns disposal. | ||
| } |
There was a problem hiding this comment.
🟡 Restart retains abandoned transmit frames
After stop, resetForLifecycle moves remaining in-progress packets into droppedFrames without clearing them. disposeRetired has already run, so restarts without another completed sequence retain every abandoned packet.
Learn more
The MAC resets its frame-sequence handler before resetting in-progress frames in resetForLifecycle and resetForLifecycle. A completed sequence normally invokes disposeRetired, which calls clearDroppedFrames. Here, remaining frames move into the dropped list afterward. Nothing clears that list until another sequence ends or the module is destroyed.
Example: Stop a station with two queued in-progress frames, restart it without sending new traffic, and stop it again after another transmission. The obsolete dropped packets stay allocated between stops and can accumulate with repeated cycles.
Recommended fix: Provide a reset cleanup boundary after callbacks release borrowed frames; clear newly dropped frames there when the callback depth reaches zero. Keep frames alive through any active synchronous callback.
Was this helpful? React with 👍 or 👎 to provide feedback.
Cancellation, stop, and crash can leave an old medium access control (MAC) transmission request active. A late callback can advance a replacement frame sequence. Block Ack agreements can also lose their inactivity timer after restart. Their expired receive state can admit late data or retain an old reorder buffer.
The MAC now assigns each transmission request an identity before Tx accepts it. Tx checks that identity after permission callbacks. Callback guards retain borrowed sequence objects until the callbacks return. Stop and crash reset Tx before the distributed coordination function (DCF) or hybrid coordination function (HCF) retires its exchange. Group, No Ack, and Block Ack transmissions do not enter Normal Ack failure processing during reset.
Hypothetical: a permission callback cancels request A and submits B. Tx rejects A after that callback and preserves B.
Block Ack reports reception status for multiple frames under an agreement. HCF preserves active agreements' absolute deadlines across downtime. Restart retires overdue agreements before channel access. Retirement clears only the affected peer and traffic identifier's reorder buffer. Late Block Ack data requires discard and delete block acknowledgment (DELBA), which ends an agreement. Delayed timeout or UNKNOWN_BA DELBA completion preserves replacement state.
Add block acknowledgment (ADDBA) establishes a Block Ack agreement. Pending recipient setup has no inactivity deadline until its first response with the same identity completes transmission. A local setup identity prevents stale responses from changing replacement state. HCF rejects stale queued responses before transmission. Response retries preserve the first deadline.
For example, the restart test queues an ADDBA response with a one-second inactivity timeout. The recipient stops for two seconds. Restart preserves pending setup, and the first response transmission starts the one-second deadline. The replacement cases also verify that HCF refuses an old queued response before it transmits the replacement response.
Tx owns the accepted transmission copy. Sequence handlers own callback disposal. Agreement handlers own protocol state; HCF coordinates retirement and recipient buffer cleanup. Custom Tx modules, sequence handlers, acknowledgment (ACK) handlers, agreement handlers, callbacks, and recipient data services require source changes and a rebuild. The migration guide describes the new interfaces.
This PR supplies general MAC prerequisites for the TXOP admission work. Exchange-duration admission remains in that separate PR.
The three commits record the plan, add request identity and cancellation, and add lifecycle reset with agreement retirement.
Validation