Skip to content

IEEE 802.11: fix Block Ack ADDBA transaction and agreement lifecycle - #1148

Open
mgonzalezlopezudc wants to merge 16 commits into
inet-framework:masterfrom
mgonzalezlopezudc:cleanup/fix-ieee80211-addba-transaction-minimal
Open

IEEE 802.11: fix Block Ack ADDBA transaction and agreement lifecycle#1148
mgonzalezlopezudc wants to merge 16 commits into
inet-framework:masterfrom
mgonzalezlopezudc:cleanup/fix-ieee80211-addba-transaction-minimal

Conversation

@mgonzalezlopezudc

@mgonzalezlopezudc mgonzalezlopezudc commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Fix the Block Ack agreement lifecycle by making ADDBA transactions, teardown, inactivity, reordering, and reassembly generation-safe.


Summary

This series closes the correctness gaps in the IEEE 802.11 Block Ack exchange, fragmented action frame reassembly, management transaction cancellation, agreement lifetime and teardown handling, and supporting queueing infrastructure.

Selective packet extraction (queueing)

Introduce IPacketExtractor so queues, gates, and schedulers can locate and remove a specific packet without bypassing the scheduling policy that owns it. Replace the drop-only callback with DEQUEUED, REMOVED, and DROPPED reasons, and propagate each logical departure exactly once through leaf queues, shared buffers, and compound boundaries (ff486eb62e, cdd5026dde).

Explicit originator ADDBA transactions

Represent an originator ADDBA exchange as explicit state keyed by peer and TID, with a transaction identity carried by Ieee80211AddbaTransactionTag. Start the exchange only after the final trigger MPDU fragment is acknowledged, so the advertised starting sequence number is valid. Match responses by dialog token, keep same-TID traffic ineligible while a request is pending, and handle response timeout, retry backoff, DELBA, and terminal cancellation without allowing stale fragments to affect a newer exchange (e4f08f3e84).

Recipient renegotiation and reset

Treat an accepted ADDBA request for an existing peer and TID as a replacement agreement. Cancel teardown state belonging to the old agreement, install the negotiated parameters, and reset the receive reordering window before frames are admitted under the new agreement (96773078e6).

Fragmented action frame reassembly and management fragmentation

Carry action-frame-specific context in a local Ieee80211FragmentedActionContextTag while transmitting fragments with a generic management header. Route fragmented management frames through recipient reassembly and call ADDBA or DELBA handlers only with the complete header, preventing a partial fragment from starting, changing, or tearing down an agreement (32b0dd7b44). Generalize embedded body extraction to management headers during fragmentation so that only the common MAC header is repeated (c632762b9a).

Management transaction cancellation

Add an end-to-end cancellation contract (IManagementFrameTransactionHandler) from the AP through Ieee80211Mac to DCF or HCF. A terminal failure removes queued and in-progress sibling fragments and retires retry, delayed-IFS, and pending-transmission state exactly once (74283b1742).

Generation-safe teardown

Tag each locally generated DELBA with Ieee80211BlockAckAgreementTag (agreement role, peer, TID, and generation). Route acknowledgement, retry exhaustion, cancellation, and abort handling back to that exact agreement instance. A delayed or retried DELBA from an older agreement can no longer delete a replacement agreement that reused the same peer and TID (d9ba185a93).

Absolute inactivity deadlines

Make originator and recipient agreement handlers report absolute, role-specific inactivity deadlines. Refresh the correct role on QoS data, BAR, and Block Ack activity, and retire the matching generation once when inactivity expires or teardown is aborted (3d72fefd40).

Generation-aware reassembly

Replace the fragment-zero reset heuristic with generation-aware reassembly state per receive flow in BasicReassembly. Preserve later-only fragments, sort completed fragments by fragment number, and reject completion when contradictory terminal markers were observed (d8bc79ba8d).

Receive lifetime enforcement

Record an immutable receive deadline when the first fragment is retained in a Block Ack receive buffer. Drive reordering and scalar reassembly from one receive-lifetime timer. Expired late fragments remain visible to Block Ack bookkeeping but cannot seed a new reassembly context (5e0f87102b).

Quarantine expired Block Ack agreements

Separate raw lifecycle lookup from active agreement lookup and use the active form throughout originator and recipient data paths. An inactivity-expired agreement remains installed until its generation-matched DELBA teardown completes, while the data plane falls back to Normal Ack, suppresses BAR and Block Ack processing, and discards Block-Ack-policy data without corrupting reorder state (cfe1c02351).

Recipient BAR and ADDBA timeout handling

Ignore null defragmentation results when a BAR releases buffered fragments, preventing reassembly rejections from reaching A-MSDU deaggregation and crashing the recipient data path (resolves Devin review finding). Resolve recipient Block Ack timeout according to the policy contract: inherit the originator request when recipient policy is zero, or apply the configured recipient override (8dbee7ba32).

Enforce valid A-MSDU fragmentation and sizing

Keep A-MSDUs intact in BasicFragmentationPolicy rather than illegally splitting them (dynamic fragmentation is HE-only). In BasicMsduAggregationPolicy, track the exact serialized A-MSDU body length including 4-octet alignment padding added after non-final subframes, while leaving the final subframe unpadded (47e01bff0d).

Robust association ID deserialization

Handle malformed association and reassociation response AIDs (missing marker bits or invalid ranges) during peer frame deserialization in Ieee80211MacHeaderSerializer by safely returning AID 0 with an EV_WARN instead of aborting the simulation with cRuntimeError (88eac86941).


Reading order (C01–C16)

The 16 commits form five logical groups on top of upstream master (8ac5675c9cbcd6135890e90ec02bf10bd2efd9c2):

  1. Selective packet extraction (C01–C02):
    • ff486eb62e queueing: support selective extraction and departure signals
    • cdd5026dde ieee80211: track pending queue departures through signals
  2. ADDBA negotiation and agreement lifecycle (C03–C08):
    • e4f08f3e84 ieee80211: make originator ADDBA transactions explicit
    • 96773078e6 ieee80211: reset recipient Block Ack state on renegotiation
    • 32b0dd7b44 ieee80211: reassemble fragmented action frames before dispatch
    • 74283b1742 ieee80211: cancel superseded management transactions
    • d9ba185a93 ieee80211: protect Block Ack teardown generations
    • 3d72fefd40 ieee80211: schedule Block Ack inactivity with absolute deadlines
  3. Reassembly, reordering, and agreement quarantine (C09–C12):
    • d8bc79ba8d ieee80211: make fragment reassembly generation-safe
    • 5e0f87102b ieee80211: enforce receive lifetime during Block Ack reordering
    • cfe1c02351 ieee80211: quarantine expired Block Ack agreements
    • 8dbee7ba32 ieee80211: fix recipient BAR and ADDBA timeout handling
  4. Aggregation, management formatting, and robustness (C13, C15–C16):
    • 47e01bff0d ieee80211: enforce valid A-MSDU fragmentation and sizing
    • c632762b9a ieee80211: preserve management bodies during fragmentation
    • 88eac86941 ieee80211: flag malformed peer association IDs without throwing
  5. Fingerprint baselines (C14):
    • 43a47efaed tests: record wireless fingerprints for the ADDBA rework

Architectural surface

Contracts

  • Adds IPacketExtractor contract in queueing for selective packet extraction without bypassing scheduling policy.
  • Adds PacketQueueRemovalDetails and departure notifications (DEQUEUED, REMOVED, DROPPED).
  • Adds IManagementFrameTransactionHandler for cascading transaction cancellation from AP management down through MAC to coordination functions.
  • Formalizes IOriginatorBlockAckAgreementHandler and IRecipientBlockAckAgreementHandler interfaces for active vs raw lifecycle lookup and absolute inactivity deadlines.
  • Returns frame ownership explicitly from IReassembly::purge().

Packet representation

  • Adds Ieee80211AddbaTransactionTag carrying sender-local transaction ID.
  • Adds Ieee80211BlockAckAgreementTag carrying agreement role, peer, TID, and generation.
  • Adds Ieee80211FragmentedActionContextTag to preserve action frame details across fragment boundaries.
  • Enforces 4-octet alignment padding rules in BasicMsduAggregationPolicy.
  • Gracefully handles malformed peer association ID elements in Ieee80211MacHeaderSerializer.

State and ownership

  • Explicit originator ADDBA transactions keyed by peer and TID; queues held ineligible during pending requests.
  • Agreement generation numbers prevent delayed or retried DELBA frames from destroying replacement agreements.
  • Receive lifetime is bound at first fragment arrival; scalar reassembly and reordering drive from one timer.
  • Recipient services retain explicit ownership of inserted, released, and expired frames.

Configuration and observability

  • Exposes packet departure signals (packetRemovedSignal, packetDroppedSignal, packetDequeuedSignal).
  • Configures addbaResponseTimeout on originator Block Ack agreement policy.
  • Adds MacQosWithTransactionalBlockAck example configuration in examples/wireless/qos/omnetpp.ini.

No touched source path is sealed. No new architecture or naming exceptions are required.


Validation

The topic branch builds cleanly in debug mode and passes all focused unit, module, queueing, and fingerprint regression tests.

Build commands

make MODE=debug -j$(nproc) LN='cp -f'
make -C tests/unit/lib MODE=debug -j$(nproc)
make -C tests/module/lib MODE=debug -j$(nproc)

Result: PASS.

Focused unit tests

UNIT_FILTER='Ieee80211AddbaTransaction_1|Ieee80211MgmtFrameSerializer_1|Ieee80211MgmtTransactionTag_1'

printf "run_opp_tests(test_folder='tests/unit', filter='$UNIT_FILTER', mode='debug', build=False)\nexit\n" |
  env INET_ROOT="$PWD" PATH="$PWD/bin:$PATH" opp_repl --load @opp -p inet

Result: 3/3 PASS (Ieee80211AddbaTransaction_1.test, Ieee80211MgmtFrameSerializer_1.test, Ieee80211MgmtTransactionTag_1.test).

Focused module tests

MODULE_FILTER='Ieee80211BlockAckInactivityTimer_1|Ieee80211MgmtApCancellation_1|Ieee80211MgmtApHcfQueueDrop_1|Ieee80211MgmtApQueueDrop_1'

printf "run_opp_tests(test_folder='tests/module', filter='$MODULE_FILTER', mode='debug', build=False)\nexit\n" |
  env INET_ROOT="$PWD" PATH="$PWD/bin:$PATH" opp_repl --load @opp -p inet

Result: 4/4 PASS (Ieee80211BlockAckInactivityTimer_1.test, Ieee80211MgmtApCancellation_1.test, Ieee80211MgmtApHcfQueueDrop_1.test, Ieee80211MgmtApQueueDrop_1.test).

Focused queueing test

printf "run_opp_tests(test_folder='tests/queueing', filter='PacketQueueDepartureSignal_1', mode='debug', build=False)\nexit\n" |
  env INET_ROOT="$PWD" PATH="$PWD/bin:$PATH" opp_repl --load @opp -p inet

Result: 1/1 PASS (PacketQueueDepartureSignal_1.test).

Fingerprint regression tests

Reproduces the 18 fingerprint rows changed/added by this topic relative to upstream/master:

fingerprint_rows=$(mktemp)

git diff --unified=0 \
  8ac5675c9cbcd6135890e90ec02bf10bd2efd9c2..HEAD -- \
  tests/fingerprint/examples.csv \
  tests/fingerprint/showcases.csv |
  sed -n '/^+++ /d; /^+/s/^+//p' > "$fingerprint_rows"

test "$(wc -l < "$fingerprint_rows")" -eq 18

(
  cd tests/fingerprint
  ./fingerprinttest \
    -d \
    -q \
    -m '.*' \
    -f tplx \
    -f '~tNl' \
    "$fingerprint_rows"
)

rm "$fingerprint_rows"

Result: 18/18 PASS (both with -f tplx and -f '~tNl').

Source and history checks

git diff --check 8ac5675c9cbcd6135890e90ec02bf10bd2efd9c2..HEAD
doc/project/enforcement/check-source-seals.sh \
  --base 8ac5675c9cbcd6135890e90ec02bf10bd2efd9c2 \
  --head HEAD
doc/project/enforcement/check-architecture.sh src/inet/linklayer/ieee80211
doc/project/enforcement/check-architecture.sh src/inet/queueing
doc/project/enforcement/check-commits.sh 8ac5675c9cbcd6135890e90ec02bf10bd2efd9c2..HEAD

Result: All checks pass clean. The branch is linear with exactly 16 topic commits and no merge commits.


Review feedback resolution

  • Devin review (BAR delivery crash on rejected fragments): In commit 8dbee7ba32, RecipientQosMacDataService::controlFrameReceived checks for null defragmentation results before forwarding to A-MSDU deaggregation, safely handling generation-ambiguous fragments released by a BAR. Regression test coverage was added to Ieee80211AddbaTransaction_1.test.

Scope limits

  • Dynamic fragmentation remains HE-only; non-HE A-MSDUs are kept unfragmented.
  • Originator ADDBA transaction model covers single-link station-to-station and station-to-AP Block Ack negotiation; multi-link and EHT TID-to-link negotiation is outside this PR.

Devin Review

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Devin Review

Comment on lines +209 to +213
if (hasOtherGeneration) {
expiredSequenceNumbersMap[contextKey].insert(key.extendedSequenceNumber);
pruneExpiredSequenceNumbers(sequenceSpaceKey);
delete packet;
return nullptr;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 BAR delivery crashes on rejected fragments

When addFragment rejects BAR-released fragments as generation-ambiguous, the delivery path stores null and dereferences it. The simulation aborts instead of dropping them.

Prompt for agents
BasicReassembly::addFragment can now reject and delete a fragment when another generation with the same raw sequence number exists, returning nullptr. RecipientQosMacDataService::controlFrameReceived unconditionally appends defragment(fragments) to defragmentedFrames and later dereferences every entry while handling a BAR. Update the BAR release path to treat a null reassembly result as a dropped/incomplete frame, mirroring dataFrameReceived, and preserve packet ownership and drop signaling correctly. Add coverage where BAR releases a complete reorder-buffer entry while BasicReassembly has conflicting generation state.
Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@mgonzalezlopezudc
mgonzalezlopezudc force-pushed the cleanup/fix-ieee80211-addba-transaction-minimal branch from 9b1f54c to 449a91a Compare September 5, 2026 21:18
@mgonzalezlopezudc
mgonzalezlopezudc force-pushed the cleanup/fix-ieee80211-addba-transaction-minimal branch 5 times, most recently from caaed40 to 6f0f1f5 Compare September 9, 2026 20:35
Allow consumers to select packets through the owning provider while preserving priority, WRR, label, gate, and compound-queue scheduling. Publish logical departures through packetQueueDeparture with typed dequeue, removal, and drop reasons so consumers can distinguish ownership transfer from terminal disposal.

Detach shared-buffer overflow victims before notification and forward logical departures once across compound boundaries. Cover borrowed packet lifetime during external-buffer eviction.
Subscribe DCF and HCF to logical queue departure signals so destructive queue removal reports a management transmission outcome while the packet is still alive. Filter descendant emissions to avoid duplicate logical notifications.

Exercise provider-directed extraction, queue accounting, shared buffers, nested notifications, and reentrant removal using signal listeners.
Represent an originator ADDBA exchange as explicit state keyed by peer and TID, with a transaction identity carried by every request fragment. Start the exchange only after the final trigger MPDU fragment is acknowledged, so the advertised starting sequence number is valid.

Match responses by dialog token, keep same-TID traffic ineligible while a request is pending, and handle response timeout, retry backoff, DELBA, and terminal cancellation without allowing stale fragments to affect a newer exchange. Keep A-MSDU selection and HCF continuation aligned with that state.

Cover trigger acknowledgement, fragmented requests and teardowns, timeout and retry paths, cancellation ownership, queue eligibility, and provider-aware A-MSDU extraction.
Treat an accepted ADDBA request for an existing peer and TID as a replacement agreement. Cancel teardown state belonging to the old agreement, install the negotiated parameters, and reset the receive reordering window before frames are admitted under the new agreement.

Replay the cached response for a duplicate request without resetting receive state, and preserve the current agreement when renegotiation is rejected. Emit distinct agreement-added, changed, and deleted events so the HCF lifecycle remains observable.

Add recipient lifecycle coverage together with a transactional QoS example and its focused fingerprint entry.
Carry Action-frame-specific context in a local tag while transmitting fragments with a generic management header and a serialized body. Extend the serializer, dissector, fragmentation, and defragmentation paths so the original Action header can be reconstructed after all fragments arrive.

Route fragmented management frames through recipient reassembly and call ADDBA or DELBA handlers only with the complete header. This prevents a partial fragment from starting, changing, or tearing down a Block Ack agreement.

Cover on-air representation, out-of-order fragments, duplicates, expiration, and both QoS and non-QoS recipient dispatch.
Add an end-to-end management transaction cancellation contract from the AP through Ieee80211Mac to DCF or HCF. A terminal failure removes queued and in-progress sibling fragments across access categories and retires retry, delayed-IFS, and pending-transmission state exactly once.

Keep a frame borrowed by the active frame sequence alive until a safe sequence boundary, then abort or release it through the owning component. Clear AP association state before cancellation so reentrant callbacks cannot observe or revive the superseded response.

Cover DCF and HCF supersession, queue removal and overflow, delayed IFS, RTS protection, active frame sequences, and successful replacement.
Tag each locally generated DELBA with its agreement role, peer, TID, and generation. Route acknowledgement, retry exhaustion, cancellation, and abort handling back to that exact agreement instance.

Track pending teardowns by generation and cancel only the matching transaction. A delayed or retried DELBA from an older agreement can no longer delete a replacement agreement that reused the same peer and TID.

Cover originator and recipient teardown, replacement during an in-flight DELBA, retry and abort paths, and stale completion callbacks.
Make originator and recipient agreement handlers report absolute, role-specific inactivity deadlines. Have HCF schedule the earliest one with rescheduleAt() and expire only agreements whose recorded deadline has actually elapsed.

Refresh the correct role on QoS data, BAR, and Block Ack activity, and retire the matching generation once when inactivity expires or teardown is aborted. This avoids treating an absolute timestamp as a relative delay and repeatedly rearming an already expired agreement.

Cover independent originator and recipient deadlines, activity refresh, simultaneous expiry, stale generations, and terminal cleanup.
Replace the fragment-zero reset heuristic with generation-aware reassembly state. Track extended sequence generations per receive flow, preserve later-only fragments, and sort completed fragments by fragment number instead of arrival order.

Quarantine half-space ambiguity, retain tombstones for retired sequences, recover when a raw sequence number is reused after wrap, and reject completion when contradictory terminal fragment numbers were observed. Stale fragments therefore cannot corrupt a newer MSDU.

Cover out-of-order delivery, duplicates, ambiguous generations, sequence-number wrap, delayed stale fragments, and contradictory terminal markers.
Record an immutable receive deadline when the first fragment is retained in a Block Ack receive buffer. Return inserted, released, and expired frames explicitly so recipient services, rather than the reorder buffer, own every final drop, signal, and deletion.

Drive reordering and scalar reassembly from one receive-lifetime timer. Expired late fragments remain visible to Block Ack bookkeeping but cannot seed a new reassembly context, while peer and TID reset purges every owned fragment without leaking or deleting it twice.

Return ownership from IReassembly::purge(), reject negative maxReceiveLifetime values while keeping zero valid, and cover expiry, reset, wrap recovery, fragmented sequences, and timer rescheduling.
An inactivity-expired Block Ack agreement must remain installed until its generation-matched DELBA teardown completes. Previously, data-plane users treated that retained object as active, so they could continue selecting Block Ack, sending BARs, buffering frames, and producing Block Ack responses after expiry.

Separate raw lifecycle lookup from active agreement lookup and use the active form throughout originator and recipient data paths. Fall back to Normal Ack, suppress BAR and Block Ack processing, discard Block-Ack-policy data without mutating reorder state, and ignore late responses once an agreement is unavailable.

Release matching originator acknowledgement state for retry when an agreement expires or is removed. Also cover the race where a frame finishes transmission after expiry, while preserving the retained agreement object for generation-safe DELBA handling.

Extend the ADDBA transaction tests with active-versus-expired policy, selection, teardown, reordering, late-frame, and transmission-completion cases. Remove the trailing blank line from the QoS example configuration.

Validation completed in debug mode with the full build, the focused ADDBA unit test, the Block Ack inactivity-timer module test, and git diff --check.
Ignore null defragmentation results when a BAR releases buffered fragments. This prevents half-sequence-space reassembly rejections from reaching A-MSDU deaggregation and crashing the recipient data path.

Resolve the recipient Block Ack timeout according to the policy contract: inherit the originator request when the recipient policy is zero, otherwise use the configured recipient override. The negotiated response value continues to drive agreement state and inactivity deadlines.

Add focused production-path coverage for the exact 2048 sequence boundary, subsequent reorder progress, timeout inheritance and override, the zero/no-timeout case, expiration timing, and cached ADDBA responses.
Keep A-MSDUs intact in BasicFragmentationPolicy even when their MPDU length exceeds the configured fragmentation threshold. The basic policy does not implement the capability-gated HE dynamic fragmentation procedure, so splitting these aggregates would produce an invalid fragment sequence.

Track the exact serialized A-MSDU body length in BasicMsduAggregationPolicy. Account for the 4-octet alignment padding added after each subframe that becomes non-final, leave the final subframe unpadded, accept an aggregate exactly at the configured maximum, and preserve -1 as the unlimited setting.

Add focused regression coverage for oversized A-MSDUs versus ordinary QoS frames, one-, two-, and three-octet padding boundaries, exact-limit acceptance, final-subframe layout, and the unlimited size configuration.
Record the existing expected fingerprints for the combined ADDBA, Block Ack, reassembly, aggregation, and HCF changes. These wireless QoS configurations exercise several preceding changes together, so this commit records their combined expectations.

The affected configurations cover adhoc and wireless QoS, Block Ack, aggregation, fragmentation, and TXOP. Preserve the previously recorded values; no new baseline values are generated during history cleanup.
Generalize embedded body extraction to management headers so fragmentation repeats only the common MAC header. Keep local action context specific to action frames.

Exercise a typed association response with a 32-byte fragmentation threshold and verify the reconstructed body bytes and fragment headers.
Malformed association and reassociation response AIDs must be represented as incorrect peer input instead of escaping deserialization as cRuntimeError. Return a safe zero AID while allowing subsequent elements to decode.

Cover missing marker bits, invalid successful AIDs, and nonzero unsuccessful AIDs for both response types. Retain strict validation of locally serialized AIDs.
@mgonzalezlopezudc
mgonzalezlopezudc force-pushed the cleanup/fix-ieee80211-addba-transaction-minimal branch from 6f0f1f5 to 88eac86 Compare September 10, 2026 09:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant