diff --git a/doc/project/evidence/model/wifi/tests/blockack-bar-without-agreement.md b/doc/project/evidence/model/wifi/tests/blockack-bar-without-agreement.md index 29a02dff021..f3da37311b8 100644 --- a/doc/project/evidence/model/wifi/tests/blockack-bar-without-agreement.md +++ b/doc/project/evidence/model/wifi/tests/blockack-bar-without-agreement.md @@ -43,7 +43,7 @@ Both runs use real association, production transmission, and the wireless medium | 0 | No agreement for station `sta1` and TID 5 | Recipient-role DELBA for that station and TID | | 1 | Real ADDBA establishes an agreement for `sta1` and TID 6 | Basic Block Ack for that station and TID | -Run 0 starts application traffic after the simulation's time limit. Run 1 supplies a short traffic batch before the crafted BAR. Read-only queries check the required agreement state at both endpoints before transmission. The control must establish its agreement before the response assertion can test normal behavior. +Run 0 starts application traffic after the simulation's time limit. Run 1 supplies a short traffic batch before the crafted BAR. At 1.002 seconds, the fixture blocks station contention while queued DATA remains. This control retains the agreement until the crafted BAR, despite S4's completion teardown. It changes no agreement state. Read-only queries check the required agreement state at both endpoints before transmission. ```mermaid sequenceDiagram diff --git a/doc/project/evidence/model/wifi/tests/blockack-data-retry-comparison.md b/doc/project/evidence/model/wifi/tests/blockack-data-retry-comparison.md new file mode 100644 index 00000000000..faab29d07a1 --- /dev/null +++ b/doc/project/evidence/model/wifi/tests/blockack-data-retry-comparison.md @@ -0,0 +1,44 @@ +# DATA Retry: before and after the correction + +> **Kind:** measurement · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [guide](blockack-data-retry.md) + +Both feedback cases fail at the Retry assertion on the parent. Both pass when the control adds only HCF's Retry branch. The final S4 source also passes both cases. + +## Exact inputs and source controls + +| Control | Production source | +| --- | --- | +| Parent | Commit `02f24a3a4d519511cf24731e25d926068b11d24d`; source tree `2a26acc1bd1d8d5ccac42c509cbfced219554175`. | +| Isolated correction | The same parent plus HCF's eleven-line Retry branch; source tree `5a58b7601444e9872312112e6f6e8ffc86207f67`. | +| Integrated S4 | Source tree `20aade533739a1877a87391909da7dd2a91c79c7`. | + +All controls use the same `WifiBlockAckDataRetry.test` input. Its SHA-256 is `271696667cf84e675683c6e146d66fd0bd57fed144cf3221caefd7e18e2c14bf`. The fixture and shared lifecycle support build on both sides. No expected-failure declaration applies. + +## Observed results + +| Run | Parent | Isolated correction | Integrated S4 | +| --- | --- | --- | --- | +| 0: lost Block Ack | FAIL at the Retry predicate. | PASS. | PASS. | +| 1: cleared bitmap | FAIL at the Retry predicate. | PASS. | PASS. | + +The parent reaches the retransmission of the captured sequence and TID. It fails because Retry remains clear. These failures are runtime assertion results, not setup or compilation errors. The isolated source changes only that transmitted header branch. + +## Commands and artifacts + +Build each source with `make MODE=debug -j12` before the test. From each checkout root, run: + +```sh +inet_run_protocol_tests -p inet -m debug -w '^tests/protocol/wifi$' -f 'WifiBlockAckDataRetry\.test$' +``` + +The parent run uses `/tmp/pr1344-controls-20261022`. Its combined control command also selects the completion and two existing lifecycle fixtures. The parent log is `/tmp/pr1344-control-base-protocol.log`. Preserved outputs are under `/tmp/pr1344-parent-protocol-artifacts/WifiBlockAckDataRetry/`. + +The isolated run uses the same retained worktree after the source patch. Its log is `/tmp/pr1344-control-retry-protocol.log`. The integrated log is `/tmp/pr1344-correction-final-protocol-regression.log`. Both integrated Retry cases pass. The combined parent runner returns 1 for the two new failing fixtures. + +All runs use General configuration, runs 0 and 1, seed 0, and a 1.1-second limit. The protocol program stops each run when it reaches its verdict. No additional seed or loss campaign follows from these results. + +## Fingerprint scope + +The isolated correction completes seven existing fingerprint cases. Five `~tND` values differ. Every selected event and packet-length fingerprint remains equal to its parent baseline. The detailed calculation is `/tmp/pr1344-retry-fingerprints.out`. + +The user approved the five intermediate values on 2026-10-22. They apply only before transfer completion enters the series. The final S4 source retains its seven previously accepted baseline rows. These measurements do not establish aggregate retransmission behavior or complete Basic conformance. diff --git a/doc/project/evidence/model/wifi/tests/blockack-data-retry.md b/doc/project/evidence/model/wifi/tests/blockack-data-retry.md new file mode 100644 index 00000000000..343f1134bc9 --- /dev/null +++ b/doc/project/evidence/model/wifi/tests/blockack-data-retry.md @@ -0,0 +1,52 @@ +# Standalone DATA Retry after Block Ack failure + +> **Kind:** reference · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [test](../../../../../../tests/protocol/wifi/common/WifiBlockAckDataRetry.test), [comparison](blockack-data-retry-comparison.md) + +The originator must set Retry when it retransmits standalone DATA after failed Block Ack feedback. The test observes the production transmitted header. It requires the retransmission to retain the captured sequence and TID. + +## Scenario and requirement + +The infrastructure network contains an AP and two stations. A UDP stream starts at sta1 after association. The AP relays its traffic to sta2. Production ADDBA establishes the uplink agreement. Seed 0 and a 0.1 ms send interval make the selected exchange deterministic. + +The test selects INET's Basic compatibility profile and disables A-MSDU aggregation. It inherits the lifecycle configuration and its inactive inactivity timer. The continuous stream reaches threshold five without a final-transfer requirement. + +IEEE Std 802.11-2024, 9.2.4.1.6 requires Retry for retransmitted standalone DATA. Lost feedback can occur between compliant peers. The cleared bitmap is a controlled negative-feedback input. It tests the originator's response; it does not model the physical cause of every failed DATA reception. + +## Faults and assertions + +| Run | Fault at sta1 | Required result | +| --- | --- | --- | +| 0 | The radio tap drops the first Block Ack. | The same DATA sequence and TID return with Retry set after timeout. | +| 1 | The radio tap clears all bits in the first Block Ack. | The same DATA identity returns with Retry set after negative feedback. | + +The first observed Block Ack DATA must have Retry clear. The test captures its identity before BAR. It next observes BAR, then the retransmission of that identity. Typed header queries avoid an ambiguous field lookup through the packet trailer. + +The radio tap changes only received feedback. Association, agreement setup, DATA selection, timeout, ACK status, and retransmission remain production operations. + +```mermaid +sequenceDiagram + participant O as Originator + participant R as Recipient + O->>R: Standalone DATA, Retry = 0 + O->>R: BAR + alt Run 0: feedback loss + R--xO: Block Ack lost at the radio tap + else Run 1: negative feedback + R-->>O: Block Ack with cleared bitmap + end + alt Before P2 + O->>R: Same sequence and TID, Retry = 0 + else After P2 + O->>R: Same sequence and TID, Retry = 1 + end +``` + +## Cause and correction + +The parent ACK handler already makes missing-feedback and negative-feedback DATA eligible. HCF previously forwarded that frame without setting Retry. The independent correction changes the header before Tx receives the retransmission. No candidate preview or completion DELBA is necessary for this path. + +The [reviewer document](../../../../../../tests/protocol/wifi/blockack-data-retry.md) associates this fixture with plan P2. The [comparison record](blockack-data-retry-comparison.md) separates executed evidence from expected behavior. + +## Limits + +Two fixed-seed cases check header identity and Retry. They do not estimate loss probability, cover aggregates, or establish complete Basic conformance. The tap's cleared bitmap is test stimulus. It is not evidence of a particular physical error pattern. diff --git a/doc/project/evidence/model/wifi/tests/blockack-same-ap-reassociation.md b/doc/project/evidence/model/wifi/tests/blockack-same-ap-reassociation.md index 12b4a8b815d..a02457f892d 100644 --- a/doc/project/evidence/model/wifi/tests/blockack-same-ap-reassociation.md +++ b/doc/project/evidence/model/wifi/tests/blockack-same-ap-reassociation.md @@ -40,7 +40,9 @@ The fixture creates these roles through real ADDBA exchanges. It never inserts a ## Test sequence -The initial uplink batch starts at `1 s`. The reverse batch starts at `1.01 s`. Both batches end before replacement. At `1.1 s`, the station agent requires all four roles and saves the peer rate sets and advertised HT capabilities at both endpoints. +The initial uplink batch starts at `1 s`. The reverse batch starts one microsecond later. Both batches end before replacement. At `1.008 s`, the station agent requires all four roles and saves the peer rate sets and advertised HT capabilities at both endpoints. This early probe precedes S4's completion teardown. + +The fixture uses 6 Mbit/s and disables A-MSDU aggregation. It disables Block Ack on sta2 and uses 100-byte downlink packets. The AP's Block Ack length limit excludes its larger forwarded uplink packets. These controls isolate agreements on the target link. Coincident transmissions produce a warning; this diagnostic setting changes no reception calculation. The agent requests reassociation with its current AP without another authentication exchange. This condition matters because authentication could clear the old association before the test reaches the replacement path. The request's receiver and Current AP field must both identify the current AP. @@ -50,7 +52,7 @@ sequenceDiagram participant G as Station test agent participant A as AP management and HCF Note over S,A: Real traffic establishes both agreement directions - G->>G: Require four roles and save peer parameters at 1.1 s + G->>G: Require four roles and save peer parameters at 1.008 s G->>S: Request reassociation with current AP S->>A: Reassociation Request A-->>S: Successful Reassociation Response @@ -61,7 +63,7 @@ sequenceDiagram Note over S,A: New traffic starts at 1.3 s and 1.31 s S->>A: Fresh uplink ADDBA setup A->>S: Fresh downlink ADDBA setup - G->>G: Require four fresh roles at 1.4 s + G->>G: Require four fresh roles at 1.38 s ``` The one-millisecond delay follows station reassociation confirmation. It permits the AP to receive the response ACK and commit replacement before the joint query. Inactivity expiration remains disabled, so it cannot explain removal of the agreements. @@ -70,7 +72,7 @@ The one-millisecond delay follows station reassociation confirmation. It permits The first state assertion requires four old roles. The next frame assertion checks same-AP reassociation. After completion, the fixture requires equal peer rate sets and advertised HT capabilities. It then requires zero old roles before the new traffic batches start. -The later batches must trigger fresh ADDBA Requests in both directions. Concurrent observations require new traffic at UDP on both destination stations. At `1.4 s`, the fixture requires four fresh agreement roles. This final condition excludes a repair that clears state but prevents later setup. +The later batches must trigger fresh ADDBA Requests in both directions. Concurrent observations require new traffic at UDP on both destination stations. The batches continue until `1.4 s` to retain useful transfer context. At `1.38 s`, the fixture requires four fresh agreement roles. This final condition excludes a repair that clears state but prevents later setup. The test agent, `BlockAckReassociationAgent`, supplies only the reassociation request, state queries, and observation times. Production management performs the association transitions. Production HCF and its agreement handlers perform setup and cleanup. The agent never calls the peer reset operation. @@ -93,7 +95,7 @@ inet_run_protocol_tests -p inet -m debug -w '^tests/protocol/wifi$' \ The file contains one simulation run with seed 0. Its required result is `PROTOCOLTEST wifi_block_ack_same_ap_reassociation: PASS`. -This test uses the Basic profile and successful same-AP reassociation. It does not cover another AP, refused reassociation, association loss, or replacement during an active DATA exchange. The state queries complement the frame trace. They do not establish full standards conformance. +This test uses the Basic profile and successful same-AP reassociation. It does not cover another AP, refused reassociation, or association loss. The state queries complement the frame trace. They do not establish full standards conformance. ## Profile limits diff --git a/doc/project/evidence/model/wifi/tests/blockack-transfer-completion-comparison.md b/doc/project/evidence/model/wifi/tests/blockack-transfer-completion-comparison.md new file mode 100644 index 00000000000..fca2a4dc976 --- /dev/null +++ b/doc/project/evidence/model/wifi/tests/blockack-transfer-completion-comparison.md @@ -0,0 +1,59 @@ +# Basic transfer completion: before and after the change + +> **Kind:** measurement · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [guide](blockack-transfer-completion.md) + +Both completion cases fail before S4 and pass on its final production source. The queue-exhaustion case misses BAR. The one-position-window case observes DATA where BAR is required. + +## Exact source and fixture inputs + +The parent is `02f24a3a4d519511cf24731e25d926068b11d24d`, with source tree `2a26acc1bd1d8d5ccac42c509cbfced219554175`. The final S4 source tree is `20aade533739a1877a87391909da7dd2a91c79c7`. + +The recorded controls use `WifiBlockAckTransferCompletion.test` with SHA-256 `e46b8804822747bc1558a802d0d7054aadf04b445370992bd5b5714b9864b0fa`. The shared topology and lifecycle inputs remain equal. No fixture supplies agreement state or injected feedback. + +The current fixture also rejects the program's FAIL line. This output guard changes no runtime scenario or protocol assertion. It prevents one successful run from hiding the other run's failure. + +## Verification of the output guard + +The corrected fixture has SHA-256 `7d526bcf8c213ebe7fdb4e4e5182393d546ef60e79feb4e044c97c3372d08156`. Both normal runs pass through the integrated debug protocol runner. Separate diagnostic INI files delay traffic beyond the protocol deadline in either run or both runs. Each simulation batch returns status 0, even when a protocol verdict is FAIL. + +The checks compare the same captured output against the previous fixture and the corrected fixture: + +| Run 0 | Run 1 | Previous aggregate | Corrected aggregate | +| --- | --- | --- | --- | +| PASS | PASS | PASS | PASS | +| FAIL | PASS | PASS | FAIL | +| PASS | FAIL | PASS | FAIL | +| FAIL | FAIL | FAIL | FAIL | + +These diagnostic failures are intentional controls, not failures of the normal completion scenarios. `opp_test check` returns 0 for PASS and 2 for FAIL, with zero harness errors. The guard rejects both mixed-result orders while it preserves the valid two-PASS result. + +The debug build log is `/tmp/pr1344-r1-debug.log`. The normal protocol log is `/tmp/pr1344-r1-protocol.log`. The verdict matrix is `/tmp/pr1344-r1-verdict-matrix.json`. Detailed checker logs use `/tmp/pr1344-r1--.log`. These local artifacts can be absent in another checkout. + +## Observed results + +| Run | Before S4 | After S4 | +| --- | --- | --- | +| 0: two packets, window 64 | FAIL: BAR deadline at step 3 expires. | PASS through matched feedback, DELBA, and ACK. | +| 1: four packets, window one | FAIL: the next DATA-or-BAR event fails the BAR predicate. | PASS through matched feedback, DELBA, and ACK. | + +Both parent failures occur after real association, successful ADDBA, and the first Block Ack DATA. They reach the intended protocol boundary. They do not arise from a build or initialization error. + +After S4, the policy selects BAR below threshold five. HCF permits BAR-only contention. The frame sequence receives matching feedback. Completion DELBA follows when no DATA remains. Zero inactivity timeout excludes inactivity teardown as an explanation. + +## Commands and evidence + +Build debug artifacts with `make MODE=debug -j12`. From each checkout root, run: + +```sh +inet_run_protocol_tests -p inet -m debug -w '^tests/protocol/wifi$' -f 'WifiBlockAckTransferCompletion\.test$' +``` + +The parent command uses `/tmp/pr1344-controls-20261022`. Its combined selection also includes the Retry fixture and two existing lifecycle controls. Its log is `/tmp/pr1344-control-base-protocol.log`. Preserved outputs are under `/tmp/pr1344-parent-protocol-artifacts/WifiBlockAckTransferCompletion/`. + +The integrated run uses `/home/user/omnetpp_ws/inet-compressed-blockack-s4`. Its log is `/tmp/pr1344-correction-final-protocol-regression.log`. The completion fixture passes both runs. That wider selection also exposes two pre-existing lifecycle fixture assumptions; its aggregate failure is not a completion-test failure. + +General configuration runs 0 and 1 use seed 0 and a 1.1-second limit. The program stops when it reaches its verdict. The parent runner returns 1. The isolated final completion selection returns 0. + +## Limits + +These controls establish the two stated exchange sequences. The independent Retry correction does not create BAR-only access or completion DELBA. The exact reconstructed parent comparison receives its own verification record. No general performance, NAV, admission, or additional-seed claim follows from these results. diff --git a/doc/project/evidence/model/wifi/tests/blockack-transfer-completion.md b/doc/project/evidence/model/wifi/tests/blockack-transfer-completion.md new file mode 100644 index 00000000000..55450a7b0cf --- /dev/null +++ b/doc/project/evidence/model/wifi/tests/blockack-transfer-completion.md @@ -0,0 +1,53 @@ +# Basic transfer completion without further DATA + +> **Kind:** reference · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [test](../../../../../../tests/protocol/wifi/common/WifiBlockAckTransferCompletion.test), [comparison](blockack-transfer-completion-comparison.md) + +A short Basic transfer must request its final feedback and end with DELBA. The test observes this sequence through production MAC signals. It covers queue exhaustion and a transmit window smaller than the BAR threshold. + +## Scenario and requirement + +The network uses real infrastructure association and production ADDBA. A finite UDP burst starts at sta1 after association. The AP receives its uplink DATA. The test selects seed 0, threshold five, no A-MSDU aggregation, and zero inactivity timeout. + +IEEE Std 802.11-2024, 10.25.4 requires DELBA when the originator has no DATA and the final Block Ack exchange completes. The low-count BAR trigger is INET policy. Basic remains a compatibility profile rather than a current-standard Block Ack format claim. + +| Run | Application input | Accepted window | Trigger | +| --- | --- | --- | --- | +| 0 | Two UDP packets at 0.1 ms intervals. | 64 positions. | Initial Normal Ack DATA precedes one Block Ack DATA; the queue then empties. | +| 1 | Four UDP packets at 0.1 ms intervals. | One position. | One Block Ack DATA fills the window before another sequence can proceed. | + +## Assertions and production path + +The test observes ADDBA Request and successful Response. It captures the requested TID. It then observes the first DATA with Block Ack policy and captures its sequence. + +The next selected DATA-or-BAR transmission must be BAR for that TID and AP. Its starting sequence must equal the captured sequence. This assertion detects further DATA before required feedback. A later matching Block Ack must reach sta1. Completion then requires originator-role DELBA for the same TID and its ACK. + +The file requires a PASS line and rejects any FAIL line from this protocol program. A successful run cannot hide the other run's failure. Protocol verdicts end each simulation normally, so the process exit status alone cannot establish success. + +```mermaid +sequenceDiagram + participant O as Originator + participant R as Recipient + Note over O,R: Outstanding DATA below threshold five + Note over O: Queue empty or transmit window full + alt Before P4 + Note over O,R: No final feedback, transfer cannot complete + else After P4 + O->>R: BAR for the selected peer and TID + R-->>O: Matched Block Ack + Note over O: After all DATA resolves and none remains + O->>R: Completion DELBA + R-->>O: ACK + end +``` + +The fixture supplies no agreement, injected response, or production state edit. HCF, EDCA, the frame sequence, radio medium, and recipient execute the exchange. Inactivity cannot supply the required DELBA because its timeout is zero. + +## Cause and correction + +The parent policy requires the threshold before BAR. Its channel access also depends on DATA eligibility. The correction groups outstanding DATA by peer and TID, selects BAR before extraction, and permits BAR-only contention. Feedback resolves the group. HCF starts completion DELBA at the accepted boundary. + +The [reviewer document](../../../../../../tests/protocol/wifi/blockack-transfer-completion.md) associates this fixture with plan P4. The [comparison](blockack-transfer-completion-comparison.md) records actual outcomes. + +## Limits + +The test checks an observed exchange sequence. Existing module and unit fixtures check other peers, expiry, negative feedback, cyclic arithmetic, and timing boundaries. This fixture does not establish those additional properties, general Basic admission, full NAV correctness, or throughput. diff --git a/doc/src/migration-guide/development/ieee80211-basic-block-ack-extension-points.rst b/doc/src/migration-guide/development/ieee80211-basic-block-ack-extension-points.rst new file mode 100644 index 00000000000..af9b1193673 --- /dev/null +++ b/doc/src/migration-guide/development/ieee80211-basic-block-ack-extension-points.rst @@ -0,0 +1,14 @@ +IEEE 802.11 Basic Block Ack extension points +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +HCF previews the next eligible DATA before BAR selection. Preview must preserve queue ownership and the next sequence number. Custom QoS data services must implement ``IOriginatorQosMacDataService``. This contract extends ``IOriginatorMacDataService`` with ``peekEligibleFrame()``, ``getNextSequenceNumber()``, and ``hasAMsduAggregation()``. + +Basic single protection reserves only an already prepared successor. HCF ends the TXOP before further DATA extraction. A queued unit can change size or require agreement setup before transmission. Custom frame sequences must preserve this boundary when they use the same forecast. + +Custom QoS ACK policies must add ``IOriginatorBlockAckAgreementHandler *agreements`` to ``isBlockAckReqNeeded()`` and ``computeBlockAckReqParameters()``. The argument supplies current agreement windows. Policies must keep peer and TID identities separate. The supplied policy can request BAR without a DATA candidate. + +Callers must supply the agreement handler explicitly through both the interface and concrete policy types. An omitted argument fails compilation. Pass ``nullptr`` explicitly when no agreement handler is available; the supplied policy then requests no BAR. Custom overrides must also require the argument. + +Calls to ``QosAckHandler::processTransmittedBlockAckReq()`` must supply the originator agreement explicitly. The agreement restricts processing to the negotiated window. An explicit ``nullptr`` retains bitmap-only coverage without that restriction. Production HCF always supplies the active agreement. + +Custom ``InProgressFrames`` classes must add ``bool extract = true`` to their ``getPendingFrameFor()`` override. When ``extract`` is false, the method must return a borrowed candidate without extraction or sequence assignment. The default value preserves ordinary extraction. Custom candidate sources must also implement ``peekFrameToTransmit()`` without extraction. diff --git a/doc/src/users-guide/ch-80211.rst b/doc/src/users-guide/ch-80211.rst index f4569882f96..b526cdbf248 100644 --- a/doc/src/users-guide/ch-80211.rst +++ b/doc/src/users-guide/ch-80211.rst @@ -700,9 +700,13 @@ station then sets up an agreement with its peer automatically (with ADDBA frames) when it sends a QoS data frame shorter than :par:`maxBlockAckPolicyFrameLength` (default 1000 bytes). After that, the frames of that traffic class go out without an immediate acknowledgement, -and the station sends a Block Ack Request after :par:`blockAckReqThreshold` -(default 5) unacknowledged frames. Both parameters are on -``mac.hcf.originatorAckPolicy``. +and the station normally sends BAR after :par:`blockAckReqThreshold` unacknowledged frames. The default threshold is five. Both parameters are on ``mac.hcf.originatorAckPolicy``. + +The station applies the threshold separately to each peer and TID. It sends BAR below the threshold when the next eligible DATA belongs to another agreement or cannot fit the transmit window. The station also sends BAR when no eligible DATA remains. For example, a burst of four frames ends with BAR even with the default threshold of five. A negotiated buffer size of one requires BAR before the second sequence number. + +BAR can obtain channel access without a queued DATA frame. A later BAR within a TXOP must fit the applicable TXOP and TXNAV bounds with its response. If BAR cannot fit, the station retains that work for another contention. + +After the final exchange, the originator sends DELBA when its agreement has no queued DATA, in-progress DATA, or active BAR exchange. A zero inactivity timeout does not disable this transfer-completion rule. DATA that arrives after this boundary waits for DELBA completion. A later transfer can require another ADDBA exchange. If the last unresolved DATA expires, the originator uses the same teardown path. Ordinary recipient teardown releases complete units behind a receive gap before it releases agreement resources. The agreement policies, ``mac.hcf.originatorBlockAckAgreementPolicy`` and ``mac.hcf.recipientBlockAckAgreementPolicy``, set the buffer size diff --git a/doc/whatsnew/fixes/ieee80211-block-ack-data-retry.txt b/doc/whatsnew/fixes/ieee80211-block-ack-data-retry.txt new file mode 100644 index 00000000000..2b9e15600c4 --- /dev/null +++ b/doc/whatsnew/fixes/ieee80211-block-ack-data-retry.txt @@ -0,0 +1,3 @@ +IEEE 802.11 DATA Retry after Block Ack failure + +HCF now sets Retry when it retransmits standalone QoS DATA after lost or negative Block Ack feedback. The retransmission retains its sequence number and TID. Configurations with these retransmissions can produce different network-data fingerprints, including computed FCS values. The correction changes no packet length or transmission schedule by itself. diff --git a/doc/whatsnew/incompatible/ieee80211-basic-block-ack-transfer-completion.txt b/doc/whatsnew/incompatible/ieee80211-basic-block-ack-transfer-completion.txt new file mode 100644 index 00000000000..fa8e84be6c7 --- /dev/null +++ b/doc/whatsnew/incompatible/ieee80211-basic-block-ack-transfer-completion.txt @@ -0,0 +1,9 @@ +IEEE 802.11 Basic Block Ack transfer completion + +Callers must supply agreement arguments explicitly for BAR selection and transmitted-BAR processing. An omitted argument now fails compilation instead of silently selecting behavior without agreement state. + +Basic BAR selection now separates each peer and TID. Short bursts and small negotiated windows can cause BAR below the configured threshold. BAR can obtain channel access without queued DATA. After final completion or final DATA expiration, the originator sends DELBA even with zero inactivity timeout. Later bursts can require another ADDBA exchange. These changes affect exchange order, airtime, simulation results, and fingerprints for Basic Block Ack configurations. + +Basic single protection now reserves only an already prepared successor. Further DATA extraction starts a new TXOP and can require more contention. Final DATA in a zero-limit TXOP reserves only its immediate response. These corrections can change Duration fields, airtime, and fingerprints. + +Custom QoS ACK policies must accept the agreement-handler argument in isBlockAckReqNeeded() and computeBlockAckReqParameters(). Custom in-progress queues must preserve the extract argument in getPendingFrameFor(). QoS data services must implement IOriginatorQosMacDataService for candidate preview without extraction. diff --git a/doc/whatsnew/incompatible/ieee80211-qos-data-preview.txt b/doc/whatsnew/incompatible/ieee80211-qos-data-preview.txt new file mode 100644 index 00000000000..512010e21ac --- /dev/null +++ b/doc/whatsnew/incompatible/ieee80211-qos-data-preview.txt @@ -0,0 +1,3 @@ +IEEE 802.11 QoS DATA preview contract + +The QoS data service now exposes candidate preview through IOriginatorQosMacDataService. The in-progress queue can preview DATA without extraction or sequence assignment. Ordinary successor queries retain extraction as their default. Custom in-progress queues must accept the extract argument in getPendingFrameFor(). The migration guide describes this interface change. diff --git a/plan/pending/ieee80211-blockack-agreement-lifecycle.md b/plan/pending/ieee80211-blockack-agreement-lifecycle.md index 1880650dcbb..432d2b1bf42 100644 --- a/plan/pending/ieee80211-blockack-agreement-lifecycle.md +++ b/plan/pending/ieee80211-blockack-agreement-lifecycle.md @@ -1,404 +1,140 @@ -# Implementation plan: repair Block Ack agreement lifecycle +# Basic Block Ack agreement lifecycle -Original source observation revision: `feat/ieee80211-txop-single-protection` at `b06e8768b0e9c78b7a3665b9c69b0e0da9f30e41`. -Current integration source: local `master` at `633b071e213b825ce6019ff3e344ae49f52791ff`, with S1, R1, and S3a merged. -Plan revision: 2026-10-15, revision 21. -Source basis: IEEE Std 802.11-2024 and the revisions above. Source observations do not establish runtime results. +> **Kind:** reference · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [HCF](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc), [implementation status](ieee80211-compressed-blockack-replacement.md) -This plan follows [Compressed plan revision 31](ieee80211-compressed-blockack-replacement.md). The maintainer accepted the transfer-completion predicate in an earlier decision. On 14 October 2026, the maintainer requested a 100 ms ADDBA response timeout and fatal termination for active profile conflict. These decisions authorize this plan update, not implementation, recorded expectation changes, or publication. Revision 21 accounts for merged R1 and S3a under the current review request. The accepted lifecycle policy and strict individual-MPDU release requirement remain unchanged. +HCF keeps each Basic Block Ack agreement consistent with its role, peer, and traffic identifier (TID). This document describes implemented setup, DATA deferral, Action handling, teardown, and peer reset. Production Compressed selection fails initialization. No Compressed lifecycle behavior is claimed. -Lifecycle observations retain their original `b06e8768` pin and require a separate review against each selected stage parent. The integration source contains S1 from merged [PR #1320](https://github.com/inet-framework/inet/pull/1320). Original S1 runtime evidence retains its feature-head boundary; this update supplies no fresh runtime result for main. The A5 transfer-completion predicate is accepted. The A4 default is 100 ms. C2 will stop the simulation on a valid BAR that conflicts with an active agreement's profile. The [umbrella decision table](ieee80211-compressed-blockack-replacement.md#maintainer-decisions) records their status and dependent boundaries. +## Previous PRs and S4 scope -## 1. Core intended behavior +Most of this lifecycle contract is inherited from master. Merged [PR #1343](https://github.com/inet-framework/inet/pull/1343) supplies setup validation, Action dispatch, response waits, DATA deferral, and directional teardown. It also supplies recipient delivery of complete buffered units at ordinary teardown. Merged [PR #1368](https://github.com/inet-framework/inet/pull/1368) supplies explicit peer cleanup at association replacement. Merged [PR #1331](https://github.com/inet-framework/inet/pull/1331) supplies the finite DATA deadline consumed during setup and recovery. -HCF, the hybrid coordination function, will keep each Block Ack agreement consistent with its peer and traffic identifier (TID). A TID identifies a traffic class or stream. ADDBA establishes an agreement. DELBA ends an agreement. A Block acknowledgment request (BAR) requests reception status. +This S4 branch, [PR #1344](https://github.com/inet-framework/inet/pull/1344), adds the final-transfer path. HCF can contend for a due BAR without another DATA candidate. Matched feedback or lifetime disposal permits window progress. At a safe exchange boundary, HCF starts completion DELBA when first DATA was transmitted and no queued or numbered DATA remains. -The agreement handlers will accept only matching successful setup responses. HCF will preserve the negotiated first sequence number through deferred DATA extraction. Teardown will remove only the selected direction's state and prevent obsolete Actions from changing a later agreement. +S4 also isolates BAR state by peer and TID, separates control failure from DATA retry feedback, and centralizes agreement-window calculations. It does not add a second lifecycle owner or replace inherited teardown disposition. The [main scope table](ieee80211-compressed-blockack-replacement.md#previous-prs-and-s4-scope) separates the production commits. -Hypothetical example: ADDBA specifies sequence number 100, but its response is lost after recipient acceptance. HCF keeps that peer and TID's DATA deferred. It sends DELBA after setup failure before Normal Ack DATA can resume. Another peer remains eligible throughout this recovery. +For example, ordinary recipient teardown already releases complete DATA behind a gap. S4 supplies the completion trigger after the originator's final unresolved DATA expires. The recipient then uses its inherited delivery and cleanup path. The sections below describe the full contract available to that exchange. -This prerequisite retains Basic throughout the final [Compressed addition](ieee80211-compressed-blockack-replacement.md). Basic originated in IEEE Std 802.11e-2005 and is unsupported by IEEE Std 802.11-2024. The umbrella's [standards boundary](ieee80211-compressed-blockack-replacement.md#2-standard-support-and-model-boundary) supplies the historical clauses and online references. This prerequisite changes neither bitmap encoding nor profile-specific response rates. The [EDCA lifetime prerequisite](ieee80211-edca-data-lifetime.md) supplies the finite DATA deadline for deferred setup and recovery. +## 1. Core behavior -## 2. Current source and required evidence +The originator and recipient agreement handlers own separate role-specific records. HCF coordinates the exchange and DATA eligibility. ADDBA establishes an agreement; DELBA ends it. A Block acknowledgment request (BAR) requests reception status for DATA within the agreement. -[Hcf](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) dispatches duplicate ADDBA Actions and sends unexpected Actions into an active response step. The frame sequence can delete that Action without agreement dispatch. Queue disposal currently reaches management ownership through the tagged transaction path, which does not cover every Block Ack Action. +HCF defers new sequence assignment while setup or teardown makes the peer state uncertain. Another peer remains eligible. An accepted transmission retains its frame context until safe exchange completion. Logical retirement does not permit deletion of a frame that Tx still references. -The agreement policies do not validate the complete accepted response contract. For received DELBA, HCF uses the local receiver address for both roles' agreement lookups before deletion-signal emission. The [recipient handler](../../src/inet/linklayer/ieee80211/mac/blockack/RecipientBlockAckAgreementHandler.cc) also uses that wrong address for agreement removal. The [originator handler](../../src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.cc) correctly uses the peer transmitter address for removal. Reorder cleanup lacks the required direction check. +Hypothetical example: the recipient accepts an ADDBA Request, but the originator receives no successful response. The originator keeps that peer/TID's DATA deferred. Response timeout starts DELBA recovery. Confirmed teardown permits surviving unsent DATA to resume with Normal Ack. -Both handlers supply absolute inactivity deadlines, but HCF schedules them as relative delays. Both handlers also select expired agreements only when the deadline equals the current time. Hypothetical example: at 5 seconds, a deadline of 7 seconds schedules an event at 12 seconds through `rescheduleAfter`. The equality check then misses that overdue agreement. The repair must schedule absolute deadlines and retire agreements whose deadlines are at or before the current time. +## 2. Current owners -AP reassociation can retain identical peer capability state. A signal that reports only changed capability values therefore cannot identify every association reset. Tx also provides no cancellation operation for a frame that it already accepted. - -These are source observations. Each implementation stage must supply a direct production reproduction for the old path it changes. The required original and corrected outcomes appear in the stage table and verification cases below. Runtime reachability and performance remain unverified until those cases run. +| Component | Responsibility | +| --- | --- | +| [HCF](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) | Coordinates eligibility, Action dispatch, timers, teardown, and transfer completion. | +| [Originator handler](../../src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.cc) | Owns originator agreements, dialog tokens, and transient procedures. | +| [Recipient handler](../../src/inet/linklayer/ieee80211/mac/blockack/RecipientBlockAckAgreementHandler.cc) | Owns accepted recipient agreements and negotiated receive values. | +| [Originator data service](../../src/inet/linklayer/ieee80211/mac/originator/OriginatorQosMacDataService.cc) | Previews and extracts eligible DATA with aggregation permission checks. | +| [Recipient data service](../../src/inet/linklayer/ieee80211/mac/recipient/RecipientQosMacDataService.cc) | Applies duplicate, reassembly, receive-state, and teardown disposition rules. | +| [Reorder owner](../../src/inet/linklayer/ieee80211/mac/blockackreordering/BlockAckReordering.cc) | Releases complete units in cyclic order and owns reorder records. | ## 3. Agreement behavior -The originator and recipient policies will use HCF's immutable typed profile and their existing MIB paths. HCF resolves the parameter once; policies do not reread it or infer a profile from PHY mode. Compressed setup requires local HT operation and valid peer HT state. Explicit Basic setup retains existing capability assumptions; absent HT state does not prohibit it. Basic is a historical INET profile, not current-standard operation. - -The originator agreement owner will retain the request dialog token until a response arrives. It will accept a response only for its pending peer, TID, and token, with success status, immediate policy, and positive buffer size. It will choose a new dialog token for each request to that peer and TID. - -The recipient will apply the HT requirement only to the Compressed profile. Basic acceptance still validates peer, TID, token, immediate policy, and supported parameters, without a new HT capability requirement. Its built-in policy will reject a modification request while the peer and TID have an active agreement. The existing agreement will remain unchanged after that rejection, as Clause 10.25.2 requires. A rejected delayed, unsupported, or modification request will receive an ADDBA Response with `SC_UNSPECIFIED` status. The response will copy the request dialog token and create no agreement. - -HCF will dispatch an ADDBA or DELBA Action only after the recipient data service accepts it as a nonduplicate complete management frame. The service will return that accepted Action to HCF instead of deleting it before dispatch. HCF will retain the existing immediate ACK behavior for a valid duplicate, but it will suppress duplicate agreement actions. The existing management sequence cache will identify MAC retries; no second duplicate cache is necessary. The dialog token identifies the setup transaction and does not replace MAC duplicate detection. - -During an active response wait, HCF will recognize a valid addressed Block Ack Action before it transfers frame ownership to the response step. HCF will cancel the response timer and use the existing receive-timeout operation to end the unsuccessful exchange without that Action. After sequence cleanup, HCF will pass the retained Action through normal recipient processing, including its immediate ACK and duplicate check. The existing failure path supplies recovery feedback for the interrupted exchange. HCF will not suspend and later resume that exchange. A frame accepted by Tx still follows the completion rule below; this receive rule applies only to an active receive step. - -Hypothetical example: DELBA arrives while HCF awaits Block Ack. HCF ends the unsuccessful BAR exchange, then acknowledges and dispatches DELBA through the recipient path. The agreement owner retires the selected role before deferred contention can select another DATA attempt. - -Hypothetical example: the recipient accepts ADDBA, but its request ACK and successful response are lost. A request retransmission receives its ACK without a new modification decision. The existing response transmission follows its retry procedure. If that response never arrives, the originator's response timeout starts teardown. A genuine new modification request remains subject to rejection without a change to the active agreement. - -For acceptance, the built-in recipient policy will select `min(64, maximumAllowedBufferSize)` as its response buffer size. The request size gives guidance but does not cap that choice under Clause 10.25.2. This INET policy uses the configured allocation and ignores the advisory request size. A request size of zero gives no size guidance under Clause 9.4.1.13. The built-in policy will reject a nonpositive configured maximum at initialization. The recipient will build the successful response before it creates the agreement. - -Its agreement and reorder buffer will use the accepted response size and the request starting sequence number. Hypothetical example: request size 8 and configured maximum 64 produce response size 64. Tests with a synthetic recipient will separately check other legal response choices and their effect on the originator window. - -The [completed S1 prerequisite](ieee80211-compressed-blockack-replacement.md#completed-s1-and-recorded-verification) supplies reorder record creation and window updates through Basic reception. `BlockAckReordering` creates its record on the first valid related DATA or Basic BAR from the supplied agreement values. A Basic BAR can advance that record before DATA reception. S1's fixture supplies agreements and proves no ADDBA negotiation. A2 must verify that negotiated values reach this current owner. C2 must verify Compressed integration; neither stage needs a second reorder record. - -The recipient will use its configured `blockAckTimeoutValue` as the response inactivity value. The request value is advisory. Both agreement owners will use the response value, including zero, which disables inactivity expiration. The recipient will start its deadline when it creates the agreement. The originator will start its deadline when it accepts the response. This rule replaces the current request-based recipient deadline. - -HCF will emit `blockAckAgreementAdded` when the recipient accepts and creates that active agreement. The originator will emit it only after it accepts the response. Pending and rejected records will produce no added event. If response delivery fails, the recipient agreement remains active until DELBA, inactivity expiration, or peer cleanup. - -The ACK policy will select Block Ack only for an active agreement and a frame supported by its selected profile. Compressed selection will recheck peer HT state and use Normal Ack when usable state is absent. Basic selection will preserve its historical capability and fragment behavior. The [umbrella model boundary](ieee80211-compressed-blockack-replacement.md#2-standard-support-and-model-boundary) owns the Compressed fragmentation restriction. Normal Ack cannot bypass that restriction. Local HT operation alone does not convert a Basic compatibility agreement into a Compressed agreement. - -The ADDBA request A-MSDU flag will reflect the originator's active A-MSDU aggregation policy. An accepted agreement will retain the response A-MSDU flag. Before aggregation, `OriginatorQosMacDataService` will check both negotiated A-MSDU flags for that peer and TID. If either flag denies A-MSDU, the service will extract individual DATA frames for that peer and TID. Plain DATA can then use Block Ack under the accepted agreement. - -The ACK policy will also reject any already-built A-MSDU that lacks permission; it will not use Normal Ack to bypass that restriction. Pending ADDBA and DELBA deferral will prevent new A-MSDU construction while the recipient's agreement state remains uncertain. A rejected initial request with no possible earlier agreement will release DATA under Normal Ack. A rejection of modification does not establish that the peer has no agreement. Association teardown will clear the request record. - -Keep the existing ADDBA trigger after the first eligible DATA transmission, provided more unnumbered DATA exists for that peer and TID. The agreement owner will record setup intent and defer further extraction for that peer and TID. Already numbered frames for that peer and TID will finish or drop under their existing ACK policy. Before request creation, HCF will cancel setup intent if no unexpired unnumbered DATA remains. Otherwise, HCF will query the QoS data service for the next unassigned number for that peer and TID. The data service alone will read `QoSSequenceNumberAssignment`; this query will not consume the number. - -HCF will pass the number to the agreement owner as the request starting sequence number. The fixed HCF NED composition permits this narrow QoS data-service operation without a DCF interface change. HCF will send the request after those numbered frames resolve. - -If all deferred DATA disappears during pending setup, HCF will cancel an ADDBA Request that Tx never accepted. If Tx accepted any request attempt, HCF will instead enter serialized teardown because peer agreement state remains uncertain. If a successful response leaves no DATA, HCF will immediately enter that teardown path. No final Block Ack exchange is necessary for this unused-agreement policy. Hypothetical example: one Normal Ack DATA frame with no successor causes no ADDBA. If deferred DATA expires during an existing setup, HCF cancels untouched setup or sends DELBA after possible peer acceptance. - -During setup intent, already numbered DATA remains eligible until it resolves; only further extraction is deferred. While the request or a needed DELBA remains pending, `InProgressFrames` will skip that peer and TID's DATA. HCF will supply an eligibility check from the agreement owner's current state; queue components will retain no duplicate agreement state. - -The QoS data service will scan its existing queue with `getPacket` and select the first eligible frame before it considers A-MSDU aggregation. If that frame is queue head, the service will check A-MSDU permission before it calls the prefix aggregation policy. With no agreement, the existing Normal Ack aggregation policy will apply. With an accepted agreement, both negotiated flags must permit A-MSDU. If that frame follows deferred DATA, the service will extract it individually with `removePacket`. It will preserve order within each peer and TID; other peers, TIDs, and management frames remain eligible. - -The QoS data service will expose the first eligible queue frame's receiver without extraction. For DATA, it will also report its TID and the next sequence number without consuming that number. `InProgressFrames` will expose eligible frames that it already owns without extracting another frame. HCF will check those frames first, then ask the QoS data service about its queue. Both queries will be read-only. BAR selection will use their result before any extraction or sequence assignment. - -The existing extraction path will run only after HCF selects DATA or management work instead of BAR. The queue preview and extraction will use the same eligibility check. HCF's fixed QoS data-service path needs no DCF interface change. - -HCF will not request contention for an access category with only deferred DATA and no eligible BAR. It will request access again when an accepted response, rejected response, or confirmed DELBA releases that DATA. The accepted response will release the deferred DATA, so its first extracted frame receives the request number. This eligibility path is necessary because the current extractor assigns sequence numbers before transmission. - -The originator policy will implement its existing `computeAddbaFailureTimeout` contract with a positive, finite, configurable INET timeout. The accepted default is 100 ms, as explained in [Response timeout and DATA lifetime](#response-timeout-and-data-lifetime). This value is INET policy, not an IEEE time limit. - -The agreement owner will hold one response deadline for each pending peer and TID. HCF will use one separate timer for the earliest of those deadlines. It will start the deadline after the ADDBA Request receives its Normal Ack. A response accepted before that ACK will prevent a later ACK callback from creating a response deadline. - -The owner will clear the deadline on a matched response, teardown, or peer cleanup. Invalid responses will not clear it. A request retry callback cannot replace an accepted agreement with setup failure. HCF will identify each pending Action by its retained frame identity and agreement role. A terminal callback will act only on the record that still owns that Action. - -HCF will also route queue rejection and eviction to that Action owner before the queue deletes the frame. It will use its existing queue-drop subscription and the retained identity to recognize owned Block Ack Actions. This route does not require an association-transaction tag. The owner will process one terminal outcome per Action; duplicate notifications have no further effect. +### Setup and negotiated values -For intentional invalidation, the owner will detach the obsolete Action identity before HCF removes the queued frame. The resulting queue notification cannot trigger a second recovery transition. An accepted transmission retains its separate completion context, even after that detachment. Hypothetical example: an accepted response retires a queued request retry. Disposal of that retry cannot turn the newly active agreement into teardown. +After initial eligible DATA, HCF waits for a successor before setup. HCF resolves already numbered DATA before it obtains the next sequence number without consumption. The ADDBA Request therefore names the first DATA sequence for the new agreement. DATA extraction remains deferred through the uncertain setup interval. -For an ADDBA Request, disposal before Tx accepts any attempt permits local cancellation and Normal Ack fallback. Disposal after Tx accepts an attempt requires teardown unless a matched response already resolved setup. For a successful ADDBA Response, disposal leaves the recipient agreement active until ordinary teardown, inactivity expiration, or peer cleanup. Disposal of a rejection response creates no agreement. DELBA disposal follows the failed-DELBA rule, even if the frame never transmits. Thus, queue loss cannot leave teardown-pending state without an owned exchange. +The originator accepts success only for the pending peer, TID, and nonzero dialog token. The response must select immediate policy, a positive buffer size no greater than 64, and a nonnegative inactivity value. The originator uses a new token for each request to that peer and TID. The [originator policy](../../src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementPolicy.cc) applies these checks. -A response can arrive after request ACK timeout while that request awaits another attempt. Acceptance will remove any queued request retry before DATA resumes. A request already accepted by Tx follows the retained-context rule below. This is the relevant response-before-request-completion case; no concurrent callback inside an ordinary synchronous call is assumed. +The recipient validates request fields and rejects delayed or unsupported requests. It rejects a modification request while the agreement is active, without replacement of that agreement. A rejected request produces an unsuccessful response with the request token and creates no agreement. -An explicit rejection permits immediate Normal Ack fallback only for initial setup without possible earlier recipient state. A request discarded before Tx accepts any attempt permits the same fallback. If a transmitted request reaches its retry limit without an accepted response, HCF will queue DELBA and keep DATA deferred. It will do the same when an acknowledged request gets no response before its deadline. The agreement owner will retain one teardown-pending state for that peer and TID. HCF will ignore a late ADDBA Response after this transition. +The recipient selects `min(64, maximumAllowedBufferSize)` and its configured inactivity value. The request buffer size and timeout are advisory. The agreement uses the response capacity and inactivity value with the request starting sequence. Zero inactivity disables inactivity expiration; it does not disable DATA lifetime or completion DELBA. -HCF will treat a DELBA Normal Ack as teardown completion for this INET profile. The ACK confirms frame reception; this policy assumes that the peer processes a valid DELBA. HCF will then release unsent DATA under the ordinary no-agreement ACK and aggregation policies. If originator-role DELBA reaches its retry limit or suffers queue disposal, HCF will drop that peer and TID's currently deferred DATA. The originator owner will retain a recovery-needed record with no scheduled retry. HCF will emit `packetDroppedSignal` for each dropped frame. +Both negotiated A-MSDU flags must permit aggregation for that peer and TID. The data service otherwise extracts individual DATA. The ACK policy rejects an already-built A-MSDU without permission; Normal Ack cannot bypass that restriction. Setup and teardown deferral prevent new aggregation while peer state remains uncertain. -HCF will emit `linkBrokenSignal` for retry-limit failure through the existing recovery path. Queue disposal alone does not establish link failure and will not emit that signal. +### Action dispatch and response waits -A failed recipient-role DELBA clears its teardown-pending record without an originator recovery-needed record. A later valid BAR or Block Ack-policy DATA can trigger another recipient-role DELBA. This outcome does not discard DATA from the opposite-direction agreement. Hypothetical example: a full management queue drops originator DELBA before transmission. HCF drops the deferred batch and retains recovery-needed state, so later DATA can trigger a fresh exchange. +The recipient data service checks complete management frames and MAC duplicates before HCF dispatches accepted ADDBA or DELBA Actions. Valid duplicates retain immediate ACK behavior but produce no repeated agreement action. The existing management duplicate cache supplies this check. -New DATA in originator recovery-needed state will trigger one new DELBA exchange through the existing management retry procedure. HCF will defer that DATA until success, terminal Action failure, or DATA lifetime expiration. Frames that arrive during that exchange will share its result; they will not start parallel DELBA exchanges. Another failure drops that deferred batch and returns to recovery-needed state. Thus, transient ACK loss does not permanently prohibit future DATA. This INET policy cannot guarantee delivery while communication remains unsuccessful. +During a response wait, HCF retains an addressed Block Ack Action outside the response step. A matching ADDBA Response or directional DELBA can resolve the procedure before obsolete terminal failure feedback occurs. The frame-sequence owner then cleans the interrupted exchange without obsolete retries, batch disposal, or a second terminal outcome. An unrelated Action retains ordinary exchange failure behavior. -Hypothetical example: the peer processes DELBA, but every ACK is lost. HCF drops the deferred batch and retains only recovery-needed state. A later DATA arrival triggers a fresh DELBA exchange. Its ACK releases the new DATA under Normal Ack. No periodic retry timer or permanent peer blacklist is necessary. +HCF acknowledges the accepted frame after cleanup and avoids repeated dispatch or duplicate-cache updates. Tx-accepted outgoing Actions retain their context until safe completion. Replacement setup waits for obsolete accepted Actions to finish. -HCF will subscribe to `rateStateChangedSignal` and check current HT state for Compressed agreements. Loss of required HT state will retire the affected Compressed state. Absent HT state or a rate-only notification will not retire Basic compatibility state. At retirement, HCF will emit one `blockAckAgreementDeleted` event for each active agreement before removal. Pending, teardown, and recovery records will produce no deleted event. The same rule applies to DELBA and explicit association reset. +Hypothetical example: a successful ADDBA Response arrives during the request's final ACK wait. The originator accepts the matching response before failure notification. Cleanup starts neither request retry nor teardown for that resolved request. -At successful reassociation, management must retire old agreement state for either profile before new DATA selection. Merged R1 changes the AP commit path: it installs related HT and rate state together before notification. Identical committed state can produce no notification. The STA path clears its current association before replacement, but that alone does not establish agreement cleanup. A3b must supply an association-reset handoff for both profiles, including Basic peers without HT records. +### Directional teardown and recovery -A3b will trace the existing AP association notifications, which carry peer addresses, and the STA association and association-loss paths. Management must pass the old peer key to HCF's retirement operation before replacement or loss of that identity. Reuse existing notifications where their order and payload meet this contract. A path without a suitable notification needs an explicit synchronous retirement handoff from management. This handoff must cover Basic peers without HT records. +Received DELBA uses its transmitter address as the peer key. `Initiator=1` ends the local recipient agreement; `Initiator=0` ends the local originator agreement. The opposite role remains unchanged. Transmitted DELBA uses its receiver address as the peer key. -The handoff must preserve the public boolean MIB signal and create no synthetic HT state. Failed reassociation follows its existing disposition; capability refresh alone does not reset an agreement. +HCF retires the selected active agreement once and retains the required teardown procedure. For the originator role, surviving unsent DATA waits for confirmation. ACK reception, retry-limit failure, or queue disposal completes the DELBA exchange. Transmission completion alone does not release that procedure. -The [consumer assessment](#reassociation-consumers-and-callback-order) defines the signal observations and direct MIB readers that A3b must preserve. R1's combined commits expose coherent HT and rate state to callbacks. A3b must preserve that contract and complete agreement cleanup before new DATA selection. It must not create a temporary HT gap solely to trigger a rate notification. Trace the current callback and reset paths before a guard or another transaction mechanism becomes necessary. +Originator teardown selects discard-all for transmitted unresolved DATA, including the highest transmitted MPDU. It preserves sequence continuity for surviving unsent DATA beyond that transmission boundary. It neither reuses discarded sequence numbers nor moves allocation backwards. Inactivity teardown can therefore remove unresolved DATA before its lifetime deadline. -When either role decides to send DELBA, HCF will retire its active agreement and emit its deletion event once. The role owner will retain one teardown-pending record before HCF queues DELBA. For the originator role, HCF will defer unsent DATA until DELBA receives an ACK. A transmission-complete callback will not erase that record. ACK reception, retry-limit failure, or queue disposal completes the exchange. An unknown-agreement DELBA will use the recipient role and create no active agreement. +Confirmed teardown releases surviving unsent DATA under Normal Ack. Failed originator DELBA drops its deferred batch and leaves recovery needed. New DATA triggers one fresh DELBA recovery attempt. Failed recipient-role DELBA clears its procedure without disposal of opposite-direction DATA. -For received DELBA, the peer key is the transmitter address. `Initiator=1` ends the local recipient agreement and its reorder state. `Initiator=0` ends the local originator agreement and its transmit state. HCF will apply the role decision before either data service clears state. A transmitted DELBA uses the receiver address as its peer key. The opposite-direction agreement for the same peer and TID will remain unchanged. +A valid Basic BAR or Block Ack-policy DATA without an active recipient agreement causes recipient-role DELBA. The DATA does not reach upper delivery. The BAR creates no scoreboard or reorder record and receives no Block Ack. Malformed input does not trigger this recovery action. -A received DELBA also resolves uncertain setup or teardown for its selected role because it confirms peer teardown. HCF will remove that role's queued Actions, clear its response deadline, and release surviving unsent originator DATA under Normal Ack. It will send no DELBA in response. An Action already accepted by Tx still requires safe completion without retries; replacement setup waits for that completion. +### Recipient buffer disposition at teardown -This profile selects the discard-all option in Clause 11.5.3.4 at originator teardown. HCF will discard every transmitted, unacknowledged MPDU in that agreement, including the highest transmitted MPDU. The data service will preserve sequence continuity for unsent DATA beyond the highest transmitted number. It will not reuse a discarded number or move the counter backwards. This avoids a special retry across agreement boundaries. The same rule applies to local DELBA, received DELBA, and inactivity expiration. +Ordinary recipient teardown delivers complete buffered MSDUs or A-MSDUs before resource release. The recipient data service preserves required duplicate state. The reorder owner detaches the record and collects complete units in cyclic order. Incomplete Basic units follow teardown disposal. HCF delivers complete units before the agreement deletion event. -Inactivity expiration can therefore discard transmitted, unacknowledged DATA whose lifetime has not expired. User documentation must state that consequence alongside the discard-all choice. Hypothetical example: DATA 100 remains unacknowledged when inactivity expires, but its lifetime deadline is later. Teardown discards DATA 100 and records inactivity as the teardown cause. A5's completed-transfer predicate leaves no unresolved DATA for discard-all; its cost concerns management exchanges and later setup. Unsent DATA does not enter discard-all solely because inactivity expires. +This release across gaps is an INET policy choice. It applies to ordinary DELBA and inactivity retirement while the association remains valid. Detachment prevents repeated delivery. The opposite agreement and unrelated peers retain their state. -At recipient teardown, the recipient data service will update its duplicate cache under Clause 11.5.3.5 before it releases agreement resources. It will use the highest received sequence number in modulo-4096 order, regardless of ACK policy. The agreement owner will retain that value because scoreboard movement and delivery can remove its earlier receipt evidence. Hypothetical example: DATA 100, 101, and 102 remain unacknowledged when teardown starts. The originator drops all three; new DATA starts after 102. The recipient retains duplicate state for its highest received sequence number. +Hypothetical example: DATA 100 is absent, while complete DATA 101 and 102 remain behind that gap. The originator resolves its final outstanding DATA through lifetime expiry and sends DELBA. The recipient releases 101 and 102 in order before cleanup. Their earlier acknowledgment alone did not establish delivery. -The Block Ack owners will remove that peer's agreements and receive records on peer cleanup. The recipient data service will clear peer reorder and duplicate state for association reset. HCF will discard old transmitted DATA and clear its matching ACK and recovery records. This association reset differs from ordinary DELBA, which preserves the required recipient duplicate state. These operations will not change another peer's state. The MIB remains the capability owner; the agreement handlers remain the agreement owners. - -Before a role accepts replacement setup, its previous outgoing DELBA must reach a terminal result. The recipient will reject new ADDBA while its outgoing teardown remains pending. The originator will not start new ADDBA during its own teardown or recovery-needed state. One pending DELBA per role, peer, and TID is sufficient. Repeated unknown-agreement frames will reuse that pending teardown work. This prevents an obsolete queued DELBA from reaching a newly established agreement. - -Peer cleanup will also remove that peer's queued ADDBA Requests, Responses, and DELBA frames through the existing queue owners. HCF will invalidate matching in-progress Actions before another transmission attempt. HCF will check validity at frame selection and before it submits a frame to Tx. A frame that Tx already accepted must finish; `ITx` provides no cancellation operation. Its context must remain alive through completion, and HCF must suppress any subsequent retry or setup transition from that old work. - -Every agreement retirement will invalidate its owned ADDBA work, including ordinary DELBA, inactivity expiration, unused setup, and the first-DATA failure rule below. A response that announces the retired agreement must leave the queue before another transmission attempt. A response already accepted by Tx may finish, but its completion cannot restore the retired agreement or start another retry. Serialized teardown follows that accepted exchange before replacement setup becomes eligible. Hypothetical example: recipient inactivity expires while a successful response remains queued. HCF removes that response and sends DELBA; the originator cannot subsequently accept obsolete queued success. - -HCF will defer replacement setup until such an accepted transmission and its existing response wait reach a terminal result. It will retain the Action's ownership identity only for that interval. It will not use a generation counter as a substitute for queue removal or transmission eligibility. Hypothetical example: inactivity expiration queues recipient DELBA just before a new ADDBA arrives. The recipient rejects setup until the old DELBA completes. A later request can establish an agreement that no old DELBA can subsequently tear down. - -HCF will own one inactivity timer for both agreement roles. The recipient owner will refresh its deadline after valid matching Block Ack-policy DATA or BAR. Duplicate DATA with that policy also refreshes inactivity, before duplicate discard. Normal Ack DATA and another peer or TID will not refresh it. The originator owner will refresh its deadline after a matched Block Ack response. A zero accepted timeout will remain disabled after every refresh. - -After each agreement state change, HCF will find the earliest active absolute expiration across both owners. It will schedule that absolute time and cancel the timer when no finite deadline remains. Hypothetical example: matching BAR arrives just before expiration. The recipient sends Block Ack and moves its deadline forward by the accepted timeout. A BAR for another TID leaves the original deadline unchanged. - -At expiration, each owner will retire every agreement with a deadline at or before the current time. HCF will apply the directional disposal rule and emit one deletion event per retired active agreement. It will queue DELBA with the TIMEOUT reason code through the same serialized teardown path. It will then schedule the next future deadline. This reuses the existing HCF timer and repairs its current absolute-time error. - -HCF will create its response timer during initialization and delete it at module destruction. Peer cleanup will cancel the matching response deadline. The accepted 100 ms default bounds the response wait after an acknowledged request, not contention or teardown duration. DATA lifetime separately bounds retained DATA. The current MAC stop and crash handlers do not reset HCF timers, queues, or frame sequences. This plan makes no stop/start recovery claim; a later lifecycle change must handle those owners together. - -HCF will check for an active recipient agreement before it passes a valid BAR to the recipient data service. Without that agreement, HCF will queue recipient-role DELBA through ordinary management contention. It will create no scoreboard or reorder buffer and send no immediate ACK or Block Ack. The replacement plan owns Compressed format validation before this agreement check. - -HCF will similarly discard valid Block Ack-policy DATA without an active recipient agreement before the data service can deliver it. It will queue DELBA for that peer and TID. Malformed frames and unsupported variants will follow the invalid-frame path without protocol recovery actions. Hypothetical example: the recipient loses its agreement while the originator retains DATA 100. BAR causes DELBA, which ends the originator's obsolete agreement. DATA 100 then follows the teardown disposal rule. +Association reset uses the separate discard rule below. It does not deliver old buffered units into a replacement association. ### First DATA and final transfer -The agreement owner will retain whether its first DATA transmission occurred. Extraction alone does not satisfy that condition. If the DATA with the request number suffers terminal disposal before transmission, HCF will retire the agreement and enter serialized teardown. This rule includes lifetime expiration and terminal RTS failure that discards the protected DATA. Surviving unsent DATA will wait; sequence assignment will not reuse the discarded number. The first accepted DATA attempt can finish across its deadline under the safe-completion rule; expiration cannot cancel that accepted attempt. - -Hypothetical example: request number 100 becomes DATA 100, which expires after unsuccessful RTS attempts. DATA 101 remains available, but HCF sends DELBA before it can transmit 101. DATA 101 can later use Normal Ack; a later agreement obtains a fresh request number. Thus, 101 cannot become the first DATA transmission under the agreement that specified 100. +The originator agreement records actual DATA transmission. Extraction alone does not satisfy that condition. If the requested first DATA suffers terminal disposal before transmission, HCF retires the agreement and starts serialized teardown. Surviving unsent DATA waits; it cannot become the first transmission under the obsolete starting sequence. -Under the accepted predicate, HCF will consider a transfer complete at an exchange boundary for that agreement. The agreement must have no queued DATA, in-progress DATA, or pending BAR exchange. Clause 10.25.4 requires DELBA when the originator has no DATA and its final Block Ack exchange completes. The clause does not specify this queue predicate. HCF will retire the agreement and queue DELBA when the accepted condition holds. Zero inactivity timeout does not disable that separate requirement. +HCF completes an active transfer only after first DATA transmission, with no numbered or queued DATA for that peer and TID. Completion occurs at a safe exchange boundary. HCF retires the agreement and queues originator DELBA. Zero inactivity timeout does not suppress this path. -If lifetime expiration removes all unresolved DATA, HCF will end the agreement through the same teardown path as an INET policy. Later DATA does not cancel queued DELBA; it waits for teardown before a new transfer. Hypothetical example: the fourth DATA receives a positive final bitmap and no fifth DATA exists at that exchange boundary. HCF sends DELBA even if another burst arrives shortly afterward. This interpretation can cause repeated setup and teardown across idle gaps. Section 7 measures that cost without an assumed acceptable threshold. - -#### Transfer-completion decision - -On 14 October 2026, the maintainer explicitly accepted the proposed queue predicate above. The decision condition before A5 in S4 is satisfied. The accepted interpretation preserves conditional DELBA and can cause repeated setup and teardown across idle gaps. Measurements must still establish that cost. S4 retains its source, recipient-progress, teardown, and timing requirements. +Lifetime expiry of the final unresolved DATA can trigger the same completion policy. Later DATA does not cancel queued DELBA. Repeated bursts can therefore require new contention and setup. No general performance bound follows from that policy. ### Agreement transitions -This table summarizes the rules above and the first-DATA rule above. Each agreement owner retains its role's state for one peer and TID. The table adds no scheduler or second agreement store. Terminal Action outcomes include queue disposal. Any frame already accepted by Tx retains its exchange context until safe completion. - -| Role and current state | Event | Next state | Owned Action | DATA eligibility and disposal | -| --- | --- | --- | --- | --- | -| Originator has no agreement. | Eligible DATA transmits with more queued DATA. | Setup intent. | None exists yet. | Numbered DATA resolves; extraction for this peer and TID stops. | -| Originator has setup intent. | Numbered DATA resolves. | Request pending, or no agreement if no DATA remains. | HCF queues one request only if DATA remains. | Unnumbered DATA stays deferred during the request. | -| Originator has a pending request. | Initial rejection arrives, or untouched request suffers disposal or cancellation. | No agreement. | HCF retires the request. | Surviving DATA uses Normal Ack. | -| Originator has a pending request. | Success arrives with DATA available. | Active agreement before its first DATA transmission. | HCF retires the request retry. | DATA resumes with the request sequence number. | -| Originator has uncertain setup. | Response timeout, terminal request failure, or loss of all deferred DATA occurs. | Teardown pending. | HCF retires request work and queues DELBA. | DATA remains deferred; expired DATA leaves the queue. | -| Originator accepts unused setup. | Success arrives with no DATA. | Teardown pending. | HCF queues DELBA. | No DATA exists; later DATA waits. | -| Originator has an active agreement. | First DATA suffers terminal disposal before transmission, transfer completes, or local teardown occurs. | Teardown pending. | HCF queues DELBA. | Transmitted unacknowledged DATA follows discard-all; surviving unsent DATA waits. | -| Originator has teardown pending. | DELBA receives an ACK. | No agreement. | HCF retires DELBA. | Surviving unsent DATA uses Normal Ack. | -| Originator has teardown pending. | DELBA reaches its retry limit or suffers queue disposal. | Recovery needed. | No Action remains. | HCF drops the deferred batch. | -| Originator needs recovery. | New DATA arrives. | Teardown pending. | HCF queues one new DELBA. | The new batch waits for the exchange outcome. | -| Recipient has no agreement. | A supported request arrives. | Active agreement. | HCF queues its successful response. | Related received DATA uses the new scoreboard and reorder state. | -| Recipient has an active agreement. | Its response receives an ACK or suffers terminal failure. | Active agreement. | HCF retires the response. | Agreement reception continues until a separate teardown event. | -| Recipient has an active agreement. | Local teardown or inactivity expiration occurs. | Teardown pending. | HCF invalidates success responses and queues DELBA. | HCF releases agreement resources; later Block Ack-policy DATA cannot reach delivery. | -| Recipient has no agreement. | Valid BAR or Block Ack-policy DATA arrives. | Teardown pending. | HCF queues one DELBA. | DATA is discarded; BAR creates no receive state. | -| Recipient has teardown pending. | DELBA receives an ACK or suffers terminal failure. | No agreement. | HCF retires DELBA. | New setup can proceed; the opposite role remains unchanged. | -| Either role has a record. | A received DELBA selects that role. | No agreement. | HCF retires that role's obsolete Actions. | Directional disposal applies; surviving unsent originator DATA can resume. | -| Either role has a record. | Peer association reset occurs. | No agreement or recovery record. | HCF retires that peer's Actions. | HCF drops old transmitted DATA and clears peer receive state. | +The role owners retain setup intent, pending request, active agreement, teardown, and recovery state as separate conditions. A matching response resolves setup. Uncertain setup requires teardown before DATA resumes. Directional DELBA affects one role. Peer reset clears both roles for the selected peer before callbacks. -### Profile conflict detection and termination +The [verification record](ieee80211-compressed-blockack-s4-execution.md) identifies the current runtime selection. Source behavior outside that selection remains a source observation rather than a new test result. -A valid BAR that conflicts with an active agreement's profile will cause a fatal configuration error. The maintainer accepted this policy on 14 October 2026. It replaces recipient-role DELBA and continued operation for this specific conflict. ADDBA does not negotiate Basic versus Compressed, so repeated setup cannot correct unchanged profiles. - -HCF will classify the BAR through the production control-frame reception path. All three conditions must hold: - -- The BAR is a well-formed Basic or Compressed frame addressed to this recipient. -- The recipient has an active agreement for the BAR's peer and TID. -- The received variant differs from that agreement's resolved profile. - -At C2, HCF will raise `cRuntimeError` before scoreboard, reorder, response, or inactivity-success updates. The diagnostic will identify local and peer addresses, TID, expected profile, and received variant. HCF will not send conflict-triggered DELBA or change agreement state before the error. This policy adds no retry timer, suppression record, blacklist, or variant-negotiation field. - -Malformed frames and unknown variants remain invalid-frame cases. A valid BAR without an active agreement follows A3c's absent-agreement recovery, including its required DELBA. A response that differs from the pending BAR variant follows response validation, not this BAR-specific fatal rule. Clause 11.5.4 covers absent agreements; it does not require this active-conflict configuration error. - -Hypothetical example: two HT stations select Basic and Compressed, but accept ADDBA. The recipient can deliver DATA before it receives the first incompatible BAR. HCF then reports the mismatch and stops the simulation. The user must correct the endpoint settings and start a new run. The stopped run does not establish successful compatibility or a valid completed performance comparison. - -Detection occurs at the first qualifying BAR, not necessarily during initialization. The MAC will not inspect another module's configuration to discover the remote profile. Fatal termination stops all traffic, including unrelated peers and valid Normal Ack traffic. The accepted policy replaces the earlier requirement for continued traffic after this conflict. Compatible runs must preserve those traffic paths. +### Profile conflict detection and termination -C2 owns the classification and fatal diagnostic because it introduces both production variants. The lifecycle owner retains ordinary teardown, disposal, absent-agreement recovery, and peer-reset ownership. Tests must verify both mismatch directions and a separately initialized compatible run. No same-run recovery, in-place profile change, or new MAC stop/start support is claimed. +HCF accepts only Basic as an operational profile in this checkout. Compressed selection fails initialization. The checkout therefore supplies no end-to-end active Basic/Compressed conflict diagnostic or recovery claim. Helper admission predicates do not enable a second production profile. ## 4. Standard requirements and INET choices -Clause 10.25.2 requires the first frame under an accepted agreement to use the request sequence number. Deferred extraction is the proposed INET mechanism for that requirement. Clause 10.25.4 supplies the conditional DELBA requirement. The [transfer-completion section](#first-data-and-final-transfer) defines INET's interpretation of its trigger and separates expiration-driven teardown. +The current Basic format is a compatibility profile. IEEE Std 802.11-2024 reserves its type value. The [standards boundary](ieee80211-compressed-blockack-replacement.md#2-standard-support-and-model-boundary) separates that profile from current-standard Compressed operation. -Clause 11.5.3.4 permits one narrower alternative to discard-all. The originator can retry the highest transmitted unacknowledged MPDU outside the agreement, with its sequence number retained. It must first discard earlier unacknowledged MPDUs. It cannot retry that MPDU within a new agreement. - -Hypothetical example: DATA 100 through 102 remain unacknowledged at teardown. The proposed policy discards all three. The permitted alternative can retain only 102 for the first retry outside the agreement. Comparison with that alternative therefore concerns one additional eligible MPDU, not unrestricted retry of the batch. - -The plan retains discard-all to avoid retry across agreement boundaries. A comparison can use an isolated experimental implementation of the permitted alternative. This comparison does not add a second production policy or configuration parameter. - -| Choice | Classification and configuration | -| --- | --- | -| ADDBA response timeout | `addbaFailureTimeout` is a positive, finite NED parameter with an accepted default of 100 ms. The value is INET policy. | -| DATA lifetime | The [lifetime plan](ieee80211-edca-data-lifetime.md#3-proposed-ownership-and-behavior) owns the parameter, default, and finite disposal bound. | -| DELBA after transfer completion | Clause 10.25.4 requires DELBA under its stated condition. INET selects the queue predicate in the transfer-completion section. | -| Discard-all at teardown | This is an explicitly selected option under Clause 11.5.3.4. User documentation must explain its disposal effect. | -| Recovery after uncertain setup | HCF waits for acknowledged local DELBA or received peer DELBA for the selected role. This is INET policy. | -| Valid profile-conflict BAR | C2 raises a fatal configuration error before state updates. Clause 11.5.4 still controls absent-agreement recovery. | -| Repeated setup after profile conflict | The simulation stops at the first qualifying conflict. Corrected profiles require a new run; no same-run recovery is supported. | +The source cites IEEE Std 802.11-2024 for shared lifecycle requirements. Clause 10.25.2 supplies setup and first-sequence conditions. Clause 10.25.4 covers completion DELBA. Clause 11.5.3.4 supplies teardown disposal alternatives; this implementation selects discard-all. Clause 11.5.3.5 covers recipient duplicate-state retention. These shared rules do not establish complete conformance for Basic. ### Response timeout and DATA lifetime -The accepted defaults are 100 ms for `addbaFailureTimeout` and 0.512 seconds for DATA lifetime. The maintainer selected 100 ms on 14 October 2026 to leave more lifetime available for teardown and subsequent DATA transmission. This is an INET policy choice, not an IEEE response deadline or a measured delivery guarantee. The parameter must remain positive, finite, and configurable; no unlimited mode is included. - -The response timeout starts after request acknowledgment; DATA lifetime starts earlier at MAC acceptance. Pending setup prohibits aggregation that could restart an A-MSDU deadline. Equal timeout durations would therefore not produce equal deadlines. The response timeout bounds only the response wait, not earlier contention or later DELBA recovery. - -Hypothetical example: DATA arrives at 0 s, and the ADDBA Request receives its ACK at 0.1 s. Without a successful response, the response deadline occurs at 0.2 s and HCF queues DELBA. The DATA deadline remains 0.512 s. This leaves 312 ms for teardown and transmission, but neither operation has a delivery guarantee. A successful response at 0.15 s instead releases deferred DATA under the accepted agreement. +`addbaFailureTimeout` defaults to 100 ms after request acknowledgment. It bounds the wait for a response, not channel contention or DELBA recovery. The originator policy requires a positive finite timeout. -Prior queue delay can reverse that order. If the request receives its ACK at 0.45 s, the response deadline is 0.55 s. The original DATA expires at 0.512 s. If all deferred DATA disappears, unused-setup teardown clears the pending response deadline. Newer DATA can keep setup pending until the response timeout. +The response inactivity value controls both active roles. Each handler uses an absolute deadline. HCF schedules that absolute time and retires due or overdue agreements. Zero disables inactivity expiry. -An unlimited response wait would remove the independent setup bound. Repeated arrivals could keep deferred DATA available while each older frame expires. Setup could then remain pending without a response or another cleanup event. Finite DATA lifetime alone does not prevent that outcome. +The separate [QoS DATA lifetime](ieee80211-edca-data-lifetime.md) defaults to 0.512 seconds. Setup deferral, retries, and ACK-policy changes consume that deadline. Agreement activity cannot extend it. An accepted transmission can finish safely across its DATA deadline, but another attempt cannot start at or after that deadline. -The default decision is satisfied; A4 still requires its source review, prerequisites, and direct verification. Tests must measure request contention, response wait, DELBA completion, delivery, and disposal separately. Compare the accepted 100 ms default with a longer positive value, such as 200 ms, under identical controlled contention and response loss. Shorter values can provide additional sensitivity checks. Report unnecessary teardown after delayed responses and any resulting DATA loss. User documentation must explain these limits; document approval supplies no runtime evidence. +## 5. Queue and association integration -The accepted 100 ms default remains unchanged. No measured acceptable-loss threshold is claimed. A specific performance guarantee would require an explicit acceptance threshold; the present comparison measures costs without such a guarantee. +### Selected-extraction contract -Hypothetical controlled-contention case: the request receives its ACK at 0.1 s, and the recipient's response requires another 150 ms for channel access. With 100 ms, timeout starts DELBA recovery at 0.2 s. With 200 ms, the originator can accept a response at 0.25 s. Produce the delay through actual contention or queue residence, not direct response injection. Keep traffic, rates, channel conditions, and seed equal across the comparison. +The originator data service uses `canPullPacket()` to inspect queue service order. If the selected DATA is the advertised next frame, individual extraction uses ordinary dequeue. Otherwise, filtered `canPullPacket()` and `pullPacket()` calls select eligible DATA behind a deferred frame. The service validates every borrowed aggregation candidate before extraction. Invalid candidates cause individual extraction of the selected eligible frame, without extraction of other sources. -Record the observed response delay, teardown exchanges, DATA delivery, lifetime disposal, and management airtime. DELBA can invalidate a queued response before transmission; distinguish that outcome from an observed late response that the originator ignores. Successful DELBA releases surviving unsent DATA under Normal Ack. A new ADDBA exchange is not required before that DATA resumes, although later traffic can trigger another setup. - -## 5. Reviewable stages and dependencies - -| Stage and purpose | Owner and proposed change | Expected result and direct verification | -| --- | --- | --- | -| A1. Deliver accepted Actions exactly once. | HCF and the recipient data service repair duplicate dispatch and reception during an active response wait. Preserve immediate ACK and frame ownership. | A retried request produces one agreement action. DELBA during a response wait reaches its handler after one failed exchange outcome. | -| A2. Use the selected profile and negotiated values. | Policies validate peer, TID, token, status, policy, and parameters. Compressed also requires local and peer HT state. Reject unsupported modification without a state change. | Explicit Basic retains legacy ad hoc and non-HT setup. Compressed admission accepts eligible HT peers and refuses capability gaps. Response size, timeout, and A-MSDU permission control both roles. | -| A3a. Repair directional teardown and inactivity. | HCF, role handlers, and data services repair peer lookup, role selection, duplicate state, and absolute inactivity scheduling. The first retirement path also supplies the Action invalidation and accepted-exchange completion operations that it needs. | Both roles emit the correct deletion payload once. Removal preserves the opposite role. Overdue agreements retire without another expired deadline. Obsolete success responses cannot survive retirement as eligible work. | -| A3b. Repair association reset for both profiles. | Management supplies the peer reset to HCF before replacement. Use existing notifications or the required synchronous handoff. HCF reuses A3a's retirement operations. Trace consumers and callback order. | Reassociation clears old state, including Basic peers without HT records. Compressed state resets with identical capabilities. New DATA sees replacement state; another peer remains unchanged. Failed reassociation retains its disposition. | -| A3c. Complete Action disposal and absent-agreement recovery. | HCF and role handlers complete queue-disposal outcomes and obsolete-Action checks through the existing retirement operations. HCF checks recipient agreement state before DATA delivery or BAR dispatch. | Queue disposal produces one terminal outcome. Accepted transmissions finish safely without obsolete retries. Valid BAR without an agreement queues recipient-role DELBA without receive-state allocation. Valid Block Ack-policy DATA without an agreement is discarded and causes recipient-role DELBA. | -| A4. Preserve sequence identity through uncertain setup. | HCF, the originator handler, and the QoS data service implement setup intent, eligible extraction, response deadlines, and serialized recovery. Connect queue disposal and first-DATA expiration. | The first transmitted DATA uses the request number. Lost responses cannot release uncertain DATA. Failed DELBA disposes of its batch; later DATA can retry recovery. | -| A5. End a completed transfer. | HCF applies the accepted queue predicate after BAR-only work becomes available in the replacement plan's channel-access stage. | Test that boundary with a finite burst and zero inactivity timeout. Later DATA waits for queued teardown. Preserve the conditional DELBA requirement. | - -A3 denotes the three review units A3a, A3b, and A3c. Review them in that order, with direct reproductions and tests beside their changes. A3b and A3c reuse A3a's retirement operations. A4 depends on S2, A1, A2, and all three A3 units. A1, A2, and the A3 units do not depend on DATA lifetime. A5 belongs with the BAR channel-access integration in S4, because final completion needs the last exchange to occur. - -Before S4 publication, its owner must verify changed Basic BAR timing against S4's pinned parent. This includes the final BAR that permits A5 transfer completion. The [umbrella airtime contract](ieee80211-compressed-blockack-replacement.md#airtime-acceptance-and-admission-dependencies) owns the observations, permitted-overrun classification, and any required correction. A future C2 result cannot replace S4's publication evidence. - -The response timeout, transfer-completion predicate, and fatal profile-conflict policy are accepted. Their decision conditions are satisfied; stage prerequisites and verification remain required. S1 and R1 retain their independent review boundaries. - -These review units do not automatically define independent publication boundaries. Action invalidation and safe completion must accompany the first retirement or reset path that requires them. A3a and A3b cannot publish unsafe intermediate behavior while those operations await A3c. Hypothetical example: inactivity retires an agreement while its successful ADDBA Response remains queued. A3a must remove that obsolete response before another attempt; A3c later extends disposal and absent-agreement coverage. S3b repeats the repaired recipient tests with the accepted response buffer size after A2 establishes that negotiation result. - -S3a's [explicit Basic settings](ieee80211-compressed-blockack-replacement.md#s3a-demonstration-migration-and-fallback-inventory) are merged. The umbrella owns the selector, consumer inventory, and separate parent evidence. S3b must select a parent that contains merged S3a and R1. A2 must replace the temporary Compressed initialization rejection and revise its selector fixture. Existing topologies, PHY modes, traffic, fragmentation cases, and parameter studies remain. Basic eligibility requires no new HT capability exchange. - -The umbrella owns the [fixture inventory and VHT contract](ieee80211-compressed-blockack-replacement.md#s3a-tracked-fixture-inventory-and-vht-scope). S3b adapts initialized handlers while Basic fixtures retain explicit Basic selection. Existing `ac` infrastructure fixtures must preserve real HT capability observations and successful Basic exchanges before C2. C2 adds matched Compressed exchanges and positive receipt bits; C4 verifies the final default. - -A2 will separately verify the Compressed profile's admission boundary. Before C2, focused policy and setup tests must not claim a complete Compressed DATA/BAR exchange. Positive setup needs usable HT state; a capability gap must refuse setup before the unsupported builder runs. This boundary must not affect explicit Basic demonstrations. - -The proposed `Ac_BlockAckFallback.test` selects Compressed and simplified AP/STA management. It removes peer HT state after initialization, before DATA. Association, local HT support, and Block Ack enablement remain. No Beacon refresh restores the removed records. Require Normal Ack DATA and no ADDBA, BAR, or Block Ack throughout the measured interval. The umbrella owns its overrides. - -Hypothetical example: the existing ad hoc QoS run 1 selects Basic and has no peer HT records. It retains Basic setup and exchanges after A2. A separate Compressed case with the same capability gap uses Normal Ack. This distinction preserves legacy demonstration coverage without a current-standard claim. - -Every proposed publication boundary must preserve a Basic path that passes direct checks. Shared lifecycle repairs also require profile-specific admission and cleanup checks. A partial recovery state machine is not publishable. If stages need one atomic change, record the concrete shared invariant before combination. - -Basic remains in independently published prerequisites and the final implementation. Each stage records its parent revision and changed fingerprint causes. R1 rate publication has its own parent comparison. C2 repeats its notification integration after the lifecycle subscriber and publication both exist. No prerequisite alone claims complete Compressed support. +The queue owner retains responsibility for ownership, residence metadata, pull events, and compound accounting. This checkout defines no separate optional selected-extraction interface. The [migration guide](../../doc/src/migration-guide/development/ieee80211-basic-block-ack-extension-points.rst) describes extension obligations. ### Reassociation consumers and callback order -The original inventory below searched `rateStateChangedSignal` and `rateStateChanged` in source, tests, configurations, and NED statistics. R1 adds production fixtures and combined MIB commits to that source. A3b must refresh the full consumer search against its selected parent. The inventory separates notification listeners from direct MIB readers; it does not establish the absence of external consumers. - -| Consumer or contract | Confirmed source behavior | A3b obligation | -| --- | --- | --- | -| Production signal listeners and NED statistics. | No current production subscription or NED statistic consumes this signal. [HCF](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) will become a new subscriber under this plan. | Repeat both searches before implementation. Verify HCF cleanup through the new callback. | -| [MIB unit-test observer](../../tests/unit/Ieee80211MibPeerTeardown_1.test) and R1 state-commit fixtures. | Test subscriptions check boolean notifications and coherent state visible from callbacks. | Preserve teardown and combined-commit assertions. Add observations for the explicit association reset, including unchanged records. | -| [QosRateSelection](../../src/inet/linklayer/ieee80211/mac/rateselection/QosRateSelection.cc) and [RateSelection](../../src/inet/linklayer/ieee80211/mac/rateselection/RateSelection.cc). | Both query `findPeerHtState` for peer-compatible mode selection. They do not subscribe to this signal. | Check final peer-compatible selection and prevent new DATA selection before reset and replacement complete. | -| [RateControlBase](../../src/inet/linklayer/ieee80211/mac/ratecontrol/RateControlBase.cc), AARF, and Onoe. | Current rate control handles mode-set changes and transmission feedback, without a subscription to this signal or direct peer HT lookup. | Verify that the reset causes no additional rate-control reset or data-rate statistic solely through the new MIB notifications. | -| [Public signal contract](../../doc/src/migration-guide/index.rst). | The boolean signal reports committed MIB changes without peer details. External consumers can subscribe. Basic peers can have no HT record. | Preserve coherent committed state. Trace a separate association-reset handoff for both profiles, including identical replacement state. | +Management calls `resetPeerAssociationContext()` before replacement of the selected peer association. The MAC passes that call to HCF's `resetPeer()`. This direct call identifies a reset even when capability values remain identical. A MIB capability-change notification cannot serve that purpose. -The merged [MIB commit operations](../../src/inet/linklayer/ieee80211/mib/Ieee80211Mib.cc) install related state before one change notification. AP successful reassociation uses that combined commit and does not require HT removal before installation. Unchanged records can produce no notification. The boolean rate signal therefore cannot identify every association reset for either profile. +Both role owners detach the peer's active agreements and transient procedures before callbacks. HCF invalidates obsolete Actions and clears transmit, acknowledgment, recovery, reorder, reassembly, duplicate, and lifetime state for the old association. Cleanup discards old buffered units without delivery. Only after cleanup does HCF emit deletion events for active agreements. Transient records produce no agreement deletion event. -Hypothetical example: an AP commits successful reassociation with unchanged HT capabilities, unchanged rate sets, and an active Compressed agreement. The MIB emits no change notification. Management must still pass the peer key through the association-reset handoff, so HCF retires the old agreement. New DATA selection occurs only after reset and replacement complete. The same reset requirement applies to Basic without an HT record. - -Before A3b implementation, trace synchronous callbacks through association reset and combined installation. Include HCF queue-disposal and channel-access calls. Add a guard only when the trace shows a reachable decision that existing control flow cannot prevent. One simulation event prevents event interleaving; it does not prevent nested callbacks. Production AP and HCF checks must establish the reset order and preserve R1's coherent notification contract. +Another peer remains unchanged. The MIB retains capability ownership and publishes coherent committed state separately. An accepted transmission retains safe completion protection through reset. ## 6. Direct verification -- Completed recipient control: Retain all eight Basic scenarios in [Ieee80211BlockAckReordering_1.test](../../tests/module/Ieee80211BlockAckReordering_1.test). Use the exact selector in the [umbrella verification section](ieee80211-compressed-blockack-replacement.md#6-verification-and-scope-limits). The fixture supplies agreements and known buffer sizes. A2 must verify negotiation through HCF without removal of these recipient assertions. C2 and C4 must verify Compressed integration separately. - -- Retained demonstrations: Repeat S3a's Basic assertions on every existing wireless hop before and after A2 and at C4. Record explicit Basic settings, peer addresses, TIDs, and positive fragment or frame receipt status. Ad hoc QoS run 1 must retain Basic without HT records; run 0 remains support-disabled. Check Compressed fallback separately. - -- Existing fixtures: Run the umbrella inventory's S3b cases through their actual handlers. Select Basic for the retained synthetic cases. Require valid capability state only for Compressed cases. Preserve header, NAV, and protection assertions. Check A-MSDU permission only after an accepted agreement, with both allowed and denied cases. Retain successful Basic setup for eligible `ac` peers through full management and real capability exchange. Record any changed failure cause in the four existing deferred protocol fixtures. - -- Absent-peer-state fallback, A2: Select Compressed in the umbrella fixture before static association and explicit peer HT removal. Require delivered Normal Ack QoS DATA with local HT support and Block Ack enablement retained. Check absent peer HT state throughout traffic at both ends of each measured hop. Require no ADDBA, BAR, or Block Ack during that interval. Repeat at C2 and C4 under the replacement plan's ownership. This test establishes fallback under the controlled gap, not a general `ac` limitation. - -- ADDBA and DATA selection: Use production HCF tests for accepted and rejected requests, including zero request size. Check the built-in response rule `min(64, maximumAllowedBufferSize)` for request sizes below and above its result. Use a synthetic recipient for other legal response sizes and check the originator window. Check the first DATA number after deferred extraction. Put deferred peer A before eligible peer B in one queue. Confirm that B sends individual DATA and A remains unnumbered. - -- Negotiated recipient window, A2: Accept an agreement with request start 100 and buffer size eight. Before any DATA reception, send a valid BAR at 104. Require record creation from the accepted values through the recipient prerequisite's reorder owner. Check reorder start 104. Receive DATA 104. Require immediate delivery. - -This check verifies negotiation integration; S1 owns the underlying recipient repair. - -- First agreement transmission: Check that A-MSDU denial prevents aggregation for the accepted peer and TID. Accept ADDBA with request number 100, then expire extracted DATA 100 before Tx accepts it while DATA 101 remains. Check teardown before 101 can transmit and absence of sequence reuse. Repeat with terminal RTS failure before DATA transmission. An accepted DATA attempt that completes across its deadline must not trigger this untransmitted-DATA rule. - -- Duplicate setup: Lose the request ACK after recipient acceptance. Retry that request before the successful response reaches the originator. Check one agreement addition and no rejection caused by that MAC retry. Test loss of the successful response through its retry limit. Test a genuine new modification request separately. Its rejection must preserve the active agreement. - -- Uncertain setup: Lose an ADDBA Response after recipient acceptance. Keep same-peer and same-TID DATA deferred until DELBA receives an ACK or DATA expires. Check the same rule after a transmitted ADDBA Request reaches its retry limit. A failed request attempt below that limit must preserve deferral. A request discarded before Tx accepts any attempt may release DATA immediately. A late response must not replace teardown state. - -- Response retry before expiry: Lose one successful ADDBA Response. Deliver its retry before both the response deadline and the deferred DATA deadline. Check acceptance and DATA release without timeout teardown. Permit channel access before expiry. Check DATA delivery. - -- Timeout and lifetime order: Suppress responses with request acknowledgment at 0.1 s after DATA acceptance at 0 s. Require response timeout at 0.2 s before the 0.512 s DATA deadline. Check serialized DELBA and DATA release only after successful teardown. In another case, delay request acknowledgment until 0.45 s. Check DATA expiration before the 0.55 s response deadline. Test both empty-setup cleanup and newer DATA that keeps the deadline reachable. Record each disposal cause. Compare the accepted default with a longer positive timeout; shorter values are optional sensitivity checks. - -- Setup completion order: After request ACK timeout, receive an accepted response before the queued request retry transmits. Check removal of that retry and absence of a new response deadline. Check that a stale request failure cannot remove the accepted agreement. Confirm that DATA already numbered before setup intent resolves before ADDBA starts. Confirm that unnumbered DATA remains deferred. - -- Reception during a response wait: Deliver valid ADDBA and DELBA Actions while HCF awaits an exchange response. Check one unsuccessful exchange outcome before recipient dispatch, immediate ACK, duplicate suppression, and safe frame ownership. Check that recipient dispatch changes the agreement before another contention attempt can select DATA. Repeat DELBA with both Initiator values. - -- Action queue disposal: Reject or evict owned ADDBA Requests, Responses, and DELBA frames. Repeat disposal before any attempt and after an earlier failed attempt. Check exactly one terminal outcome and the transition table's resulting state. A dropped successful response must leave its recipient agreement active. A dropped originator DELBA must enter recovery-needed state and dispose of its deferred batch. A dropped recipient DELBA must preserve the opposite-direction agreement. - -- Failed DELBA: Let the peer process DELBA, but lose every ACK until the retry limit. Check disposal of the current deferred batch. Check that no periodic DELBA retry occurs without new DATA. Inject later DATA and permit the fresh DELBA exchange to succeed. Confirm Normal Ack delivery without peer reset. Another failure must dispose of only the new deferred batch. - -- Profile conflict, C2: Establish an active agreement through production HCF with opposing endpoint profiles. Exercise both mismatch directions with a valid addressed BAR. Require the fatal diagnostic with both addresses, TID, expected profile, and received variant. Check no conflict-triggered DELBA, agreement mutation, or receipt, reorder, response, or inactivity-success update before termination. Verify the diagnostic cause; a generic expected failure is insufficient. - -- Persistent conflict, C2: Keep opposing settings unchanged and require termination at the first qualifying BAR, without another setup attempt. Start separate runs with matching Basic and matching Compressed settings. Check successful exchanges and Normal Ack traffic for another peer in those compatible runs. Test malformed, unknown-variant, unaddressed, and absent-agreement inputs separately to exclude false conflict errors. No traffic-continuation claim applies after fatal termination. - -- Missing agreement, A3c: Inject a valid addressed BAR without an active agreement. Check DELBA, no immediate response, and no scoreboard or reorder allocation. Inject DATA with Block Ack policy under the same condition. Check discard before delivery and recipient-role DELBA. Invalid BAR must cause neither allocation nor DELBA. Repeated valid frames must not create parallel DELBA exchanges. C2 repeats the BAR boundary after Compressed format validation exists. - -- Directional teardown: Establish both directions for one peer and TID. Test both Initiator values with local and received DELBA. Check removal of only the selected role. Teardown with unacknowledged DATA 100 through 102 must discard all three. Check that unsent DATA preserves sequence continuity beyond 102. Check recipient duplicate state after out-of-order reception and sequence wrap. - -- Deletion signals, A3a: Receive DELBA for each role with both directions active. Check one nonnull deletion payload for the selected peer, TID, and role before removal. Check removal of that agreement and preservation of the opposite role and another peer. Repeat DELBA after removal. Check that no second deletion event occurs. - -- Queued Actions: Queue DELBA after inactivity expiration, then deliver new ADDBA before DELBA transmits. Check that the recipient rejects setup until teardown completes. Establish a later agreement and check that no obsolete DELBA reaches it. Repeat peer cleanup with queued ADDBA Request, Response, and DELBA. Repeat with an Action already accepted by Tx. Check safe completion without a retry or state change from obsolete work. - -- Obsolete success response: Expire recipient inactivity before a queued successful ADDBA Response transmits. Check removal of that response, one deletion event, and serialized DELBA. Repeat after Tx accepts the response. Check safe completion without restored agreement state or another response retry. Repeat ordinary received DELBA while owned ADDBA work remains queued. - -- Association reset: Test disassociation and reassociation on both AP and station under both profiles. Include Basic peers with no HT record. Observe the explicit management reset handoff and preserved Basic state after unrelated rate notifications. Reassociate to the same AP with identical capabilities and operation values. Check removal of old agreements, duplicate state, and obsolete Action work. Preserve another peer's state. Check that failed reassociation follows the existing association disposition. Check one deletion event per active agreement and none for inactive records. - -- Reassociation consumers, A3b: Commit reassociation through production AP management with an active agreement and identical HT and rate state. Require the explicit reset handoff even when the MIB emits no change notification. Observe coherent HT and rate records in each notification callback. Instrument DATA selection and ACK-policy queries for the reset peer. Require no such production decision before reset and replacement complete. Check peer-compatible rates, preserved rate-control state, and no notification-driven data-rate statistic. Repeat with failed reassociation and no prior HT record. - -- Inactivity: Use different request and response timeout values. Check that both roles use the response value, including zero. Test expiration after nonzero simulation time with two role deadlines. Receive matching BAR just before expiration and check deadline refresh. Repeat with qualifying duplicate DATA, Normal Ack DATA, and another TID. Check one timeout DELBA and no same-time reschedule loop. - -- Inactivity disposal, A3a: Expire an agreement while transmitted DATA remains unacknowledged. Check discard-all for that agreement's transmitted DATA. Preserve unsent DATA and the opposite-direction agreement under their applicable contracts. After S2 integration, repeat with a DATA lifetime deadline in the future. Record inactivity-driven teardown disposal separately from lifetime expiry and other teardown causes. Check that A5 completion has no unresolved DATA for discard-all after A5 exists. - -- Empty setup and defaults: Send one Normal Ack DATA frame without a successor and check that no ADDBA follows. Expire all deferred DATA during setup intent, before request transmission, and after request transmission. Check local cancellation or serialized teardown according to possible peer state. Accept a response with no DATA and check immediate unused-agreement teardown, including with zero inactivity timeout. With the configured defaults, check both timeout-before-expiry and expiry-before-timeout cases through controlled request delay. Keep newer DATA available in another case to exercise the response timeout itself. - -- Final transfer: Under the accepted predicate, complete a finite burst with no queued or in-progress DATA for that agreement. Check DELBA after the final Block Ack exchange with a zero inactivity timeout. Inject DATA after DELBA enters the queue. Check that it waits for teardown rather than canceling DELBA. Expiration of the final unresolved DATA must also end the transfer. Another peer's queued DATA must not suppress this completion. - -A5's final-transfer assertions must use the accepted queue predicate at the exchange boundary. - -Use the current Basic variant for variant-independent prerequisite reproductions. Repeat the relevant cases with Compressed frames when the replacement exists. Agreement rejection and missing-agreement cases must preserve their Action and disposal results under either variant. - -Add a proposed `tests/module/Ieee80211BlockAckAgreementLifecycle_1.test` for these production paths. Partition its scenarios by A1, A2, A3a, A3b, A3c, A4, and A5. Give each review unit a precise selector. Retain prerequisite invalidation checks wherever an earlier unit consumes those operations. Confirm the actual selector syntax when the fixture exists. +Current selected module files cover Action delivery and disposal, negotiation, association reset, DATA selection, deferral, collision, lifecycle, fragment retirement, response waits, scheduling, and completion cost. The [verification record](ieee80211-compressed-blockack-s4-execution.md) gives the executed commands and counts. A fixture name alone does not establish a result for every path above. ## 7. Performance and evidence limits -Use deterministic fault injection for successful setup, lost ADDBA responses, and lost DELBA acknowledgments. Use finite bursts and traffic with idle gaps. Record the traffic definition, offered load, seed, rates, queue capacity, and relevant timeout parameters. - -Measure these results separately: - -- Measure setup deferral from the start of DATA ineligibility to release or disposal. -- Measure request contention, response wait, and DELBA completion as separate intervals. -- Measure delivered DATA, lifetime disposal, teardown disposal, and management-frame airtime. -- Separate inactivity-driven teardown disposal from other teardown causes. After S2 integration, record whether each discarded frame still had an unexpired DATA lifetime deadline. Count A5 completion separately from inactivity expiration. -- Count ADDBA and DELBA exchanges per burst, including retransmissions. -- Measure application goodput as useful bytes delivered to the destination application per unit of simulated time over a fixed measurement interval. -- Measure delivery delay for the affected TID and progress for another eligible peer or TID. -- Count the highest transmitted unacknowledged MPDU eligible for the optional retry at each teardown. - -For a performance estimate against optional final-MPDU retry, implement that alternative only in a controlled comparison. Do not infer recovered delivery from an eligible-frame count. Report the count alone when that experiment does not exist. - -For transfer completion, compare equal payload totals in continuous traffic and finite bursts separated by controlled idle gaps. Record burst size, gap duration, and the number of agreement establishments and teardowns. Attribute management airtime and DATA deferral to the observed exchanges. These measurements expose repeated setup cost; traffic-shape differences alone do not isolate the predicate's cost. - -An isolated comparison may retain agreements across idle gaps to estimate that cost, with all other inputs fixed. Such an experimental policy is not a standards exception or a second production mode. Without that experiment, report observed exchange counts, airtime, delay, and goodput without a claim about agreement-reuse performance. - -The [replacement plan's verification scope](ieee80211-compressed-blockack-replacement.md#6-verification-and-scope-limits) defines common fingerprint controls. Diagnose changed exchanges separately for each stage. No particular performance improvement or acceptable loss threshold is assumed. +Completion DELBA and a new setup can add management exchanges between bursts. Basic single protection also requires a new TXOP for unprepared DATA. Current validation supplies no general throughput, latency, or agreement-reuse cost result. MAC stop/start recovery, production Compressed exchanges, and complete NAV conformance remain outside the claim. ## 8. Standards evidence and scope limits -IEEE Std 802.11-2024 supplies the Compressed profile's normative requirements. Canonical clause identifiers use `ieee80211-2024:clause:` followed by the number. Basic is historical compatibility, unsupported by that standard. IEEE Std 802.11e-2005 Clauses 7.2.1.7, 7.2.1.8, and 9.10 introduced its format and exchange. The umbrella's [historical references](ieee80211-compressed-blockack-replacement.md#2-standard-support-and-model-boundary) link the publication record and published amendment. Shared repairs do not establish complete historical conformance. - -| Requirement | Clauses | Physical PDF pages | -| --- | --- | --- | -| Setup and accepted parameters | 10.25.2; 11.5.2.2 | 2051–2056; 2561–2562 | -| Final-transfer teardown | 10.25.4 | 2056 | -| Originator disposal and recipient duplicate state | 11.5.3.4; 11.5.3.5 | 2565–2566 | -| Inactivity and absent-agreement recovery | 11.5.4 | 2566 | - -The source review does not establish complete HT-immediate transfer support. A-MPDU, implicit BAR, and complete-cost TXOP admission remain separate work. Existing MAC stop/start limitations remain explicit; this plan does not claim their repair. - -Follow [the plan procedure](../../doc/project/guide/write-an-implementation-plan.md) and [run-the-gates.md](../../doc/project/guide/run-the-gates.md). The implementation must record exact commands, modes, selectors, and outcomes. The separate S1 record owns completed recipient verification. This plan reports no executed lifecycle test or performance result. +The clause references above identify the source requirements and current policy boundaries. The document adds no new normative interpretation or standards retrieval result. The [implementation status](ieee80211-compressed-blockack-replacement.md) states the supported profile and capability gaps. Runtime evidence remains limited to the current verification selection. diff --git a/plan/pending/ieee80211-compressed-blockack-replacement-summary.md b/plan/pending/ieee80211-compressed-blockack-replacement-summary.md index 3f5beae7321..384d192e99c 100644 --- a/plan/pending/ieee80211-compressed-blockack-replacement-summary.md +++ b/plan/pending/ieee80211-compressed-blockack-replacement-summary.md @@ -1,485 +1,67 @@ -# Compressed and retained Basic Block Ack plan summary for human review +# Basic Block Ack implementation summary -> **Kind:** reference · **Status:** snapshot 2026-10-15 · **Seal:** none · **Owns:** — · **Stands on:** [ieee80211-compressed-blockack-replacement.md](ieee80211-compressed-blockack-replacement.md) +> **Kind:** reference · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [implementation status](ieee80211-compressed-blockack-replacement.md) -**S1, R1, and S3a are merged; the remaining stages add Compressed Block Ack beside explicit Basic compatibility.** Management already publishes rates. Legacy demonstrations already select Basic explicitly. Basic originated in IEEE Std 802.11e-2005 and is unsupported by IEEE Std 802.11-2024. Further work covers DATA lifetime, agreement lifecycle, BAR channel access, and Compressed integration with its final default. +This checkout supports Basic Block Ack agreement setup, DATA deferral, BAR-only channel access, and transfer completion. Basic is the default profile. HCF rejects Compressed selection at initialization. Compressed frame classes and isolated admission policies do not establish production Compressed support. -This summary follows revision 31 of [ieee80211-compressed-blockack-replacement.md](ieee80211-compressed-blockack-replacement.md), dated 15 October 2026. Its integration source is local `master` at `633b071e213b825ce6019ff3e344ae49f52791ff`. It also follows lifetime revision 11 and lifecycle revision 21. The review checkout contains separate S2 source, test, and plan edits. The umbrella records its exact revision and the unavailable remote check. Earlier instructions accept the five policy decisions and strict individual-MPDU release; this request authorizes the corrections for merged prerequisites, without new implementation or publication authority. +## Previous PRs and S4 scope -This document update adds no runtime result. All five decisions are accepted; stage reviews, prerequisites, and verification remain required. The [decision table](ieee80211-compressed-blockack-replacement.md#maintainer-decisions) records all five statuses. +This summary covers the integrated source on `work/compressed-blockack-s4`, the branch for [PR #1344](https://github.com/inet-framework/inet/pull/1344). The current behavior combines inherited prerequisites with S4's transfer-completion changes. -S1 merged through [PR #1320](https://github.com/inet-framework/inet/pull/1320) on 14 October 2026. Its recorded verification belongs to original feature head `fcc06450355a52b9c8b0f8f2647e0654711bfaca`. The [completed S1 record](ieee80211-compressed-blockack-replacement.md#completed-s1-and-recorded-verification) preserves that source boundary and its scope. This document update supplies no fresh runtime verification of the merged source. - -The [completed R1 and S3a record](ieee80211-compressed-blockack-replacement.md#completed-r1-and-s3a) identifies their commits and evidence limits. R1 supplies management rate publication and combined MIB commits before notification. S3a supplies selector validation and explicit Basic consumers. Basic remains the default; explicit Compressed selection stops initialization until A2 replaces that temporary rejection. Neither stage supplies a complete Compressed exchange. - -S3a's recorded comparisons preserve thirteen demonstration outcomes, eight capability probes, and every calculated ingredient across nineteen fingerprint rows. Fifteen rows retain graphical `tyf` baseline mismatches; the fingerprint runner exits 1. Four protocol fixtures retain expected FAIL results. These historical results do not establish a fresh combined-master pass or complete protocol support. - -The [earlier source comparison](ieee80211-compressed-blockack-replacement.md#source-comparison-for-evidence-reuse) covers `6aefaef1` and `c15860de` before S1. Only three documentation files differ between those revisions; their `src`, `tests`, and `bin` trees match. That equality does not describe the source after S1. Earlier checks remain evidence only within their recorded limits. +| Source of the behavior | Contribution | +| --- | --- | +| Merged [PR #1320](https://github.com/inet-framework/inet/pull/1320) | Recipient capacity, cyclic delivery, gap release, and Basic BAR progress. | +| Merged [PR #1331](https://github.com/inet-framework/inet/pull/1331) | Finite QoS DATA lifetime and safe completion across expiry. | +| Merged [PR #1343](https://github.com/inet-framework/inet/pull/1343) | Agreement setup, Action dispatch, directional teardown, DATA deferral, and recipient teardown delivery. | +| Merged [PR #1368](https://github.com/inet-framework/inet/pull/1368) | Peer cleanup before association replacement, even when capability values remain identical. | +| This S4 branch, PR #1344 | Borrowed queue preview, BAR-only contention, peer/TID-specific feedback, window progress, completion DELBA, and prepared-successor reservations. | -The [EDCA DATA lifetime plan](ieee80211-edca-data-lifetime.md) owns DATA expiration. The [agreement lifecycle plan](ieee80211-blockack-agreement-lifecycle.md) owns setup, recovery, and teardown. The replacement plan owns recipient delivery repairs, independent BAR channel access, and final Compressed support. The sections below explain the intended combined behavior; the implementation section separates the changes. +S4 does not introduce the lifetime owner, filtered queue API, or recipient teardown policy. It uses those prerequisites to complete the final Basic exchange. Its preparation commit supplies shared window calculations before their callers. The [main reference](ieee80211-compressed-blockack-replacement.md#previous-prs-and-s4-scope) gives the detailed attribution and S4 commit boundaries. -## The intended exchange +Compressed exchanges and the Compressed default belong to separate S5 [PR #1345](https://github.com/inet-framework/inet/pull/1345). They are absent from this S4 source. The sections below describe the combined Basic behavior, not only the lines changed by S4. -Block Ack lets one response report reception status for several DATA frames. The **originator** sends DATA. The **recipient** receives DATA and reports its status. +## Agreement and DATA behavior -The agreement applies to one peer and one **traffic identifier (TID)**. A TID identifies a traffic class or stream. Three exchanges control its use: +HCF coordinates one agreement for each role, peer, and traffic identifier (TID). ADDBA establishes an agreement. A Block acknowledgment request (BAR) requests reception status. DELBA ends the agreement. The [lifecycle contract](ieee80211-blockack-agreement-lifecycle.md) defines setup validation, response waits, teardown, and peer reset. -- **ADDBA** establishes the agreement. -- **BAR**, a Block acknowledgment request, asks for reception status. -- **DELBA** ends the agreement. +Without an agreement, the originator sends eligible initial DATA with Normal Ack. When more eligible DATA exists, setup deferral preserves the requested first sequence number. Matching ADDBA success permits DATA under the accepted agreement. Uncertain setup holds surviving unsent DATA until teardown resolves the peer state. -The accepted scope uses individual DATA frames before an explicit BAR. It requires usable high throughput (**HT**) capability state at both stations. Its purpose is controlled study of Compressed bitmap, response, and recovery behavior in the current individual-frame MAC. On 14 October 2026, the maintainer accepted that [intermediate scope](ieee80211-compressed-blockack-replacement.md#purpose-of-the-individual-data-profile). The scope decision before C2 is satisfied. Complete HT-immediate transfer requires a separate A-MPDU design. +The ACK policy counts outstanding DATA separately for each peer and TID. Below the BAR threshold, it waits only when the next eligible DATA belongs to that group and fits its accepted window. HCF can contend for BAR when the queue is empty or the next candidate cannot proceed. -The response MPDU decreases from 152 bytes for Basic to 32 bytes for Compressed. That frame-length result does not establish lower exchange airtime or higher application goodput. Explicit BAR, control rates, contention, and repeated setup also affect performance. Direct exchange and airtime evidence must establish the supported result. +Hypothetical example: a window of one and a threshold of five permit one outstanding DATA frame. The next sequence lies outside the window. HCF sends BAR instead of waiting for five frames. Positive feedback permits window progress. With no queued or numbered DATA at the safe exchange boundary, HCF starts DELBA. -This hypothetical example uses TID 5, an accepted buffer size of 64, and sequence numbers near their wrap point: +The following sequence describes that supported Basic case. It omits management ACKs and ordinary channel-access delays. ```mermaid sequenceDiagram participant O as Originator participant R as Recipient - - O->>R: Earlier DATA with Normal Ack + O->>R: Initial DATA with Normal Ack R-->>O: ACK - Note over O: More DATA exists for TID 5.
Defer further sequence assignment. - - O->>R: ADDBA Request: first sequence 4094 - R-->>O: Successful ADDBA Response - Note over O,R: The agreement is active. - - O->>R: DATA 4094 - O--xR: DATA 4095 is lost - O->>R: DATA 0 - O->>R: DATA 1 - - O->>R: Compressed BAR: start 4094 - Note over R: Wait SIFS. - R-->>O: Compressed Block Ack: start 4094, bits 1 0 1 1... - - Note over O: Remove acknowledged DATA.
Retain DATA 4095 for retry. - O->>R: Retransmit DATA 4095 - O->>R: Compressed BAR - R-->>O: Compressed Block Ack confirms reception - - Note over O: No DATA remains for this agreement. + Note over O: More DATA exists. Defer extraction for setup. + O->>R: ADDBA Request + R-->>O: Successful ADDBA Response: window size one + O->>R: DATA under the agreement + Note over O: No further candidate fits the window. + O->>R: Basic BAR + R-->>O: Basic Block Ack confirms reception + Note over O: No queued or numbered DATA remains. O->>R: DELBA R-->>O: ACK ``` -SIFS is the short interval before the immediate response. The diagram omits the ordinary ACKs for ADDBA management frames. - -Sequence numbers wrap from 4095 to 0. In this example, bitmap positions represent 4094, 4095, 0, and 1, in that order. - -## Receipt status and delivery order - -The Compressed Block Ack contains 64 bits. Each positive bit confirms a complete data unit at one sequence position. The scoreboard retains Basic fragment status. The Compressed response derives one complete-unit bit per sequence position without removal of that Basic state. HCF rejects fragmented DATA only under the Compressed HT-immediate profile. Basic retains its fragment map and reassembly after final integration. - -The accepted buffer size limits the recipient window. The response still contains 64 bits; positions beyond that window contain zero. An empty scoreboard also produces zero bits. - -The BAR supplies a starting sequence number, **not a range length**. The recipient can return a different starting sequence number after it adjusts its receipt window. The originator must interpret each bit relative to the response start. - -The recipient therefore needs two separate mechanisms: - -```mermaid -flowchart TB - D["Valid DATA for an agreement"] --> S["Scoreboard
Records complete reception by sequence number"] - S --> B["Reorder buffer
Holds DATA until ordered delivery is possible"] - B --> U["Delivery to the next MAC process"] - - R["Valid BAR for the agreement"] --> V["Validate the BAR"] - V --> S - V --> B - S --> A["Compressed Block Ack
Response start plus 64 receipt bits"] -``` - -The **scoreboard** answers, “Which complete units did the recipient receive?” The **reorder buffer** answers, “Which units can the recipient deliver now?” - -Compressed delivery does not erase receipt status from the scoreboard. Scoreboard movement controls receipt retirement and preserves the preceding-position evidence required by the individual-MPDU rule below. The current delivery call erases earlier entries through `removeAckStates`, so C2 must change that contract for Compressed agreements. The Basic getter also infers positive status for absent earlier positions. C2 cannot use that inference for Compressed bits. The [recipient design](ieee80211-compressed-blockack-replacement.md#45-build-recipient-state-and-select-response-airtime) owns the complete contract and Basic compatibility. - -`BlockAckReordering` creates its reorder record on the first valid DATA or BAR for the accepted agreement. It uses the negotiated buffer size and request sequence number before it applies that frame's window update. A BAR can therefore advance the empty reorder window before any DATA reception. Hypothetical example: the request starts at 100 with buffer size eight, and the recipient receives BAR at 104 before any DATA. Subsequent DATA 104 must be eligible for immediate delivery. Invalid BAR and BAR without an agreement create no reorder record. - -S1 now releases every consecutive complete unit when DATA fills a gap. Its recipient fixture buffers DATA 101 and 102 behind absent DATA 100. Receipt of DATA 100 releases 100, 101, and 102 in order in the same operation. The recipient needs no later DATA reception or BAR. S1 also supplies record creation for Basic BAR before DATA; C2 must verify the same result through Compressed reception. - -C2 adds another release condition for individual MPDUs under Clause 10.25.6.6.2.1(a)(2)(v). An in-window unit beyond `WinStartB` can pass a gap when its interframe relation and receipt evidence satisfy that condition. HCF supplies the actual SIFS/RIFS relation after the previous MPDU, or SIFS after ACK completion. The agreement-owned scoreboard supplies receipt evidence at `WinStartR - 1`, even when it lies outside the response window. RIFS means reduced interframe space. The reorder owner uses these inputs without another timer or scheduler. - -Hypothetical example: an accepted agreement starts at 100 with size four. Normal Ack DATA 100 reaches delivery and receives ACK; the reorder start becomes 101. DATA 104 arrives one SIFS after ACK, and the scoreboard start becomes 101. Positive receipt evidence for 100 requires delivery of 104 despite absent positions 101–103. A false receipt bit or non-SIFS interval leaves 104 buffered. C2 tests the production relation and both controls. - -The receipt checks also cover delivery followed by BAR. DATA 100, 102, and 101 must reach delivery in order, with all three receipt bits retained for BAR at 100. A separate size-eight case receives only 115 and moves the scoreboard to 108–115. Only 115 has a positive bit; absent positions 108–114 remain zero. These checks expose the current deletion path and inferred positives. - -Hypothetical example: DATA 100 is absent, but DATA 101 is complete. The reorder buffer holds 101. A valid BAR at 101 can advance delivery past the gap. The scoreboard independently supplies the response bitmap. - -Both mechanisms must preserve cyclic sequence order. If one operation releases DATA 4095 and DATA 0, the recipient must deliver 4095 first. - -The recipient repair counts sequence positions, not individual fragments. Its Basic-path test supplies two fragments of one DATA unit to a one-position buffer. Both fragments must fit and permit complete-unit delivery. Final Basic compatibility retains that fragment case. It does not establish valid fragmentation under the Compressed HT-immediate profile. - -## Agreement setup and the first sequence number - -The agreement lifecycle prerequisite preserves the sequence number through setup. The first DATA transmission under an accepted agreement must use the sequence number from its ADDBA Request. - -The plan therefore defers further DATA extraction for that peer and TID during setup. Extraction matters because the current data service assigns sequence numbers at that point. - -Already numbered DATA resolves under its existing ACK policy before the request starts. Other peers and TIDs remain eligible. - -Hypothetical example: setup specifies sequence 100. Deferred DATA receives 100 after acceptance. If DATA 100 expires before transmission, DATA 101 cannot replace it as the agreement’s first transmission. The originator must end that agreement first. It must not reuse sequence 100. - -The accepted response controls the agreement parameters: - -| Parameter | Proposed behavior | -| --- | --- | -| Buffer size | The built-in recipient selects `min(64, maximumAllowedBufferSize)`. The request size is advisory. | -| Inactivity timeout | Both roles use the response value. Zero disables inactivity expiration. | -| A-MSDU permission | Both negotiated flags must permit A-MSDU construction. | -| Response identity | Acceptance requires the pending peer, TID, dialog token, success status, immediate policy, and positive buffer size. | - -An **A-MSDU** combines several service data units inside one DATA frame. If the agreement denies A-MSDU use, the originator sends individual DATA frames. A change to Normal Ack cannot bypass that restriction. - -For example, request size 8 and configured maximum 64 produce response size 64 under the proposed built-in policy. - -## Block Ack after a short burst - -The plan identifies two obstacles in the pinned source. BAR selection depends on a DATA candidate, and the default threshold is five outstanding frames. These paths can leave a finite burst of four frames without a BAR trigger. Production tests must reproduce that failure before the implementation changes those paths. - -The proposed selection rule considers outstanding DATA separately for each peer and TID. BAR can request channel access even when no DATA candidate exists. - -Hypothetical example: peer A has four outstanding frames, while peer B continuously supplies DATA. Before another DATA transmission to B, the policy selects BAR for A. - -The policy can defer BAR below the threshold only when the next DATA belongs to the same agreement and fits its transmit window. - -BAR selection and duration calculation must also leave queued DATA untouched. Neither operation may extract DATA or assign its sequence number. - -## Recovery after uncertain setup - -The agreement lifecycle prerequisite supplies recovery after uncertain setup. A lost ADDBA Response creates uncertainty. The recipient might hold an agreement that the originator never accepted. - -The originator cannot safely treat that uncertainty as an initial rejection. It must defer DATA until teardown confirms that the old agreement no longer applies. - -```mermaid -flowchart TD - P["ADDBA setup is pending"] --> S{"What result occurs?"} - - S -->|"Valid success; DATA remains"| A["Activate the agreement"] - S -->|"Initial rejection; no possible earlier agreement"| N["Resume DATA with Normal Ack"] - S -->|"Untouched request is discarded"| N - S -->|"A request could reach the peer;
setup fails or becomes unused"| T["Defer DATA and send DELBA"] - - A -->|"Transfer ends or teardown is necessary"| T - - T -->|"DELBA receives ACK,
or peer DELBA confirms teardown"| N - T -->|"Originator DELBA reaches retry limit
or suffers queue disposal"| R["Drop the deferred batch.
Retain recovery-needed state."] - - R -->|"New DATA arrives"| T -``` - -This diagram shows the originator’s main paths. Acceptance with no DATA also enters teardown. - -Hypothetical example: the recipient processes DELBA, but every ACK is lost. The originator drops the deferred batch and retains recovery-needed state. Later DATA triggers one fresh DELBA exchange. A successful exchange releases that new DATA under Normal Ack. - -The plan adds no periodic DELBA retry. DATA expiration alone does not prove that the peer cleared its agreement. - -## The three time limits - -| Limit | Purpose | Rule and decision status | -| --- | --- | --- | -| ADDBA response timeout | Bounds the wait for a response after the request receives its ACK. | The accepted `addbaFailureTimeout` default is 100 ms; the parameter remains positive, finite, and configurable. | -| Agreement inactivity timeout | Ends an agreement without qualifying activity. | Both roles use the accepted response value. Zero disables this timeout. | -| DATA lifetime | Bounds retention of DATA despite retries or setup delays. | The maintainer accepted the 0.512-second default per access function. The [lifetime decision](ieee80211-edca-data-lifetime.md#lifetime-compatibility-decision) before L1 is satisfied. | - -The accepted 100 ms ADDBA response timeout is an INET policy choice. The DATA lifetime matches the IEEE 802.11-2024 MIB defaults: 500 TU, or 512 milliseconds, for AP and non-AP stations. - -The standards basis does not establish the compatibility cost in current simulations. The maintainer accepted the 0.512-second lifetime default on 14 October 2026. S2 must still measure expiry with Block Ack disabled. Congestion alone does not prove that retained DATA reaches that age. An opt-in or unlimited mode needs a separate design and a disposal bound for Block Ack recovery. - -DATA lifetime starts when HCF accepts DATA from above, before queue insertion. HCF is the MAC component that coordinates these exchanges. Queue residence and setup deferral therefore consume lifetime. Retransmission does not restart the deadline. - -The lifetime owner tracks local frame identity, so equal sequence numbers at different peers cannot share a deadline. Fragments retain their source deadline. Each MSDU addition restarts the aggregate timer, as the [lifetime plan](ieee80211-edca-data-lifetime.md#3-proposed-ownership-and-behavior) specifies. The current builder adds all inputs at one simulation time. Pending setup prohibits that aggregation. - -Hypothetical example: an MSDU arrives at 0 seconds and joins an A-MSDU at 0.4 seconds under Normal Ack. This example has no active Block Ack agreement and no pending setup or teardown for that peer and TID. The default lifetime places the aggregate deadline at 0.912 seconds. The original 0.512-second deadline must not discard the aggregate. The lifetime tests must also prove that aggregation cannot revive an already expired input. - -Hypothetical example: DATA arrives at 0 seconds, and ADDBA Request acknowledgment occurs at 0.1 seconds. Without a successful response, HCF starts DELBA recovery at 0.2 seconds. DATA expires at 0.512 seconds, so 312 ms remains for teardown and transmission. A successful response at 0.15 seconds instead releases DATA under the agreement. - -The [lifecycle timeout contract](ieee80211-blockack-agreement-lifecycle.md#response-timeout-and-data-lifetime) records the accepted 100 ms default. Earlier queue delay and later DELBA recovery still consume DATA lifetime. Request acknowledgment at 0.45 seconds would place the response deadline at 0.55 seconds, after the original DATA expires. Tests must cover both orders; the selected default does not guarantee delivery. - -The lifecycle tests compare 100 ms with a longer positive timeout under identical controlled contention. They measure delayed-response teardown, delivery, disposal, and management airtime. They also distinguish a canceled queued response from a late received response. Successful DELBA permits surviving DATA to resume under Normal Ack without mandatory new setup. The accepted default remains 100 ms; no measured acceptable-loss threshold is claimed. - -No new DATA transmission may start after its deadline. An accepted transmission can finish safely after that deadline. A successful response can still acknowledge it, but expiration prohibits another attempt. - -The lifetime prerequisite applies to all QoS DATA, with either value of `isBlockAckSupported`. It includes Normal Ack DATA without an agreement. DCF and complete management-frame lifetime remain outside its scope. - -EDCA is the channel-access method for QoS traffic. An EDCAF serves one access category. Its positive, finite `msduLifetime` parameter controls DATA lifetime. This change can affect existing EDCA simulations under congestion even when Block Ack support is disabled. A finite value supplies a deadline, not a guarantee of prompt recovery or expiry within the run. - -The [lifetime plan](ieee80211-edca-data-lifetime.md#3-proposed-ownership-and-behavior) permits a larger finite value for compatibility studies. Hypothetical example: a 100-second lifetime prevents lifetime expiry for newly accepted DATA during a 10-second simulation. It does not promise unchanged fingerprints or complete legacy behavior. Earlier success, teardown, or other disposal can still resolve DATA. A recovery path that relies on lifetime expiry inherits the larger delay; the plan adds no unlimited mode. - -Hypothetical example: HCF accepts Normal Ack DATA at 0 seconds, but contention prevents transmission before 0.7 seconds. With the default lifetime, HCF discards the DATA at 0.512 seconds under either switch value. An explicit one-second setting still permits an attempt at 0.7 seconds. - -Before S2 completes, it requires [measured expiry under controlled congestion](ieee80211-edca-data-lifetime.md#5-verification-and-evidence) with Block Ack disabled. A selected QoS row without expiry cannot satisfy that requirement. If the common rows do not reach the boundary, the lifetime owner must add a controlled congestion variant. Evidence must separate lifetime disposal from queue-capacity loss and retry-limit loss. - -The response timeout does not bound earlier contention or later DELBA recovery. The lifecycle plan requires separate measurements for these intervals, delivered DATA, and disposal. The 100 ms default does not bound the complete setup and recovery procedure. - -## Response validation and retry - -The originator checks the response type, addresses, TID, fragment field, bitmap size, and frame length before it reports exchange success. - -It applies bitmap results only within the active agreement’s transmit window: - -- Positive bits can acknowledge covered, transmitted DATA, even if those frames did not await this particular BAR. -- Zero bits leave DATA unacknowledged and release the relevant frames for retry. -- DATA below the response start remains unacknowledged. -- A response without overlap, or a timeout, releases requested DATA for retransmission. - -The profile uses DATA retransmission after a failed exchange. It does not repeatedly send BAR alone to poll for status. - -Individual DATA retransmission preserves its sequence number and sets Retry to one under Clause 9.2.4.1.6. Zero bits and BAR timeout do not count as synthetic Normal Ack retry failures. DATA lifetime supplies the disposal bound; successful Block Ack responses cannot extend it. - -For example, a response for another TID cannot acknowledge DATA from the pending exchange. A malformed matching response cannot refresh inactivity or report success. - -## Teardown and obsolete work - -The two directions can hold separate agreements for the same peer and TID. DELBA must end only the selected direction. - -The [source assessment](ieee80211-blockack-agreement-lifecycle.md#2-current-source-and-required-evidence) distinguishes deletion notifications from agreement removal. HCF uses the wrong peer address for both roles' deletion-signal lookups. The recipient handler also uses the wrong address for removal, while the originator handler uses the correct transmitter address. A3a tests both signal payloads and agreement removal, with the opposite role preserved. - -At originator teardown, the proposed **discard-all policy** removes every transmitted, unacknowledged frame in that agreement. Unsent DATA retains sequence continuity. Ordinary recipient teardown preserves the required duplicate state. - -Hypothetical example: DATA 100 through 102 remain unacknowledged at teardown. The originator discards all three. New DATA uses sequence numbers after 102. - -Inactivity expiration also applies discard-all to transmitted, unacknowledged DATA, even when its lifetime deadline is later. For example, DATA 100 can remain unacknowledged when agreement inactivity expires before DATA lifetime. Teardown then discards it and records inactivity as the cause. User documentation must explain this consequence; measurements separate it from lifetime expiry and other teardown causes. A5 completion leaves no unresolved DATA for discard-all. Unsent DATA is outside this discard-all rule. - -Clause 11.5.3.4 permits a narrower alternative: retry only the highest transmitted unacknowledged frame outside the agreement, with its sequence number retained. Earlier unacknowledged frames must still be discarded. That alternative cannot retry the retained frame within a new agreement. In the example above, only DATA 102 qualifies. - -The proposed policy avoids this retry across agreement boundaries. A performance estimate requires an isolated implementation of the alternative for a controlled comparison. An eligible-frame count alone does not prove recoverable delivery. The comparison adds no second production policy or configuration switch. - -Clause 10.25.4 requires DELBA when no DATA remains after the final Block Ack exchange. Zero inactivity timeout does not disable this separate requirement. The accepted INET predicate checks for no queued DATA, in-progress DATA, or pending BAR exchange for that agreement at an exchange boundary. The clause does not prescribe this queue predicate. - -Hypothetical example: a burst completes and no DATA remains for its agreement before another burst arrives. The accepted interpretation queues DELBA during that gap. Later DATA waits for teardown and can incur another setup exchange. The [transfer-completion record](ieee80211-blockack-agreement-lifecycle.md#transfer-completion-decision) states the maintainer's acceptance of this predicate. The lifecycle plan must still measure its cost separately from inactivity expiration. - -Several event cases need explicit treatment: - -- Duplicate ADDBA frames receive the ordinary ACK but do not repeat agreement actions. -- An addressed ADDBA or DELBA during a response wait first ends that unsuccessful exchange, then enters normal recipient processing. -- Queue disposal produces one terminal outcome for each owned management Action. -- Obsolete queued Actions leave the queue before another attempt. -- An Action already accepted by Tx finishes safely, without an obsolete retry or agreement change. -- Association reset clears that peer’s agreement state, even when replacement capabilities are identical. - -A valid BAR without an agreement causes DELBA, without an immediate ACK or Block Ack. DATA with Block Ack policy under the same condition is discarded and causes DELBA. Malformed frames create neither receive state nor recovery exchanges. - -The [reassociation consumer assessment](ieee80211-blockack-agreement-lifecycle.md#reassociation-consumers-and-callback-order) found no current production subscriber or NED statistic for `rateStateChanged`. A unit-test observer subscribes, and HCF will become a new production subscriber. Both rate-selection components read peer HT state directly. The public signal contract also permits external listeners. - -Hypothetical example: a Compressed peer's successful AP reassociation retains identical HT capabilities and rate sets. R1's combined MIB commit can emit no rate notification. A3b must explicitly retire the old agreement before new DATA selection. The handoff must also cover Basic peers without HT records. A3b must preserve coherent callback state and verify final peer-compatible rates and rate statistics. - -## Frame format and compatibility - -HCF resolves `blockAckVariant` once into an immutable typed profile. Merged S3a keeps that value private and exposes no profile query. A2 and C2 must pass the value to their consumers through the smallest required interface. Compressed is the final default; legacy consumers retain explicit Basic selection. Policies must not infer the profile from PHY mode. The serializer decodes the actual wire type independently, without a variant registry or second agreement store. - -IEEE Std 802.11e-2005 introduced the mechanism and the frame format later called Basic Block Ack. Clauses 7.2.1.7 and 7.2.1.8 define BAR and Block Ack, with a 128-octet fragment bitmap. Clause 9.10 defines their operation. Direct inspection of the local PDF confirms these clauses, their frame figures, and the historical page references. The [umbrella source notes](ieee80211-compressed-blockack-replacement.md#appendix-b-standards-source-notes) record the filename, checksum, pages, and lack of corpus indexing. The [IEEE publication record](https://standards.ieee.org/ieee/802.11e/3131/) identifies the amendment. - -IEEE Std 802.11-2024 Tables 9-36 and 9-37 reserve type 0 and identify type 2 as Compressed. INET retains Basic for historical compatibility; that current standard does not support it. Existing INET studies can use later PHY modes and existing Basic response behavior. Retention does not claim complete IEEE Std 802.11e-2005 conformance. - -Keep Basic classes, serializers, builders, fillers, and fragment bitmaps. Decode type 0 as Basic and type 2 as Compressed. Other unsupported variants follow the invalid-frame path. A response must match the pending BAR variant before any success or receipt-state update. - -The old nine-bit `reserved` field overlaps the upper two bits of the complete Type field. C1 preserves Basic field round trips only when they encode Type 0. It rejects a Basic value that encodes another Type before serialization. The common fields remain available to existing callers. Figures 21b and 21e of the 2005 amendment reserve B0–B11. Retained ACK-policy fields are INET compatibility fields, not semantics from those figures. - -Both Compressed serializer producers already exist. C1 adapts their old ACK-policy and reserved-field expectations with its serializer change. Compressed writes zero in B0 and B5–B11; received values in those reserved positions are ignored. B3 and B4 remain Type bits and cannot use that ignore rule. C1 verifies both complete inventories; C4 adds remaining coverage. - -ADDBA gains no variant negotiation field. Both endpoints must select the same profile. A valid addressed BAR that conflicts with an active peer/TID agreement causes a fatal configuration error before state updates. HCF reports both addresses, TID, expected profile, and received variant. Malformed input, unknown variants, and absent agreements retain their separate validation or recovery paths. - -The accepted [profile-conflict policy](ieee80211-blockack-agreement-lifecycle.md#profile-conflict-detection-and-termination) stops the entire simulation, including unrelated traffic. It replaces conflict-triggered DELBA and continued operation after mismatch. The user must correct endpoint profiles and start a new run. DATA can reach the recipient before conflict detection; the stopped run does not establish successful compatibility or a completed performance comparison. - -Basic responses remain 152 bytes with FCS. The Compressed header chunk is 28 bytes; its FCS makes the MPDU 32 bytes. Timeouts, durations, and protection use the actual variant. Retain Basic response-mode assertions as compatibility evidence. Add non-HT Compressed cases beside them. - -Compressed responses use qualifying basic or mandatory rates. Non-HT BAR supplies the rate bound, modulation class, and preamble type. HT or VHT BAR supplies its non-HT reference rate and an OFDM or ERP-OFDM response. Legal alternate rates preserve duration; invalid overrides fail clearly. - -Originated Compressed BAR uses a non-HT PPDU. Initial BAR uses a BSS basic rate, or a mandatory rate when that set is empty. Later BAR uses the known peer operational set. Unknown peer state uses the basic or mandatory fallback. Unknown BSS state uses the documented INET mandatory-rate fallback. - -The merged [R1 stage](ieee80211-compressed-blockack-replacement.md#r1-publish-production-rate-state) publishes rate state through existing MIB operations. Full management commits advertised or accepted local, BSS, and peer rates. Simplified management publishes equivalent static state. Associated-AP Beacons refresh records; association loss clears them. Unknown sets remain distinct from known empty sets. - -Direct MIB injection does not prove production publication. R1 has its own parent comparison and production fixture. C2 consumes the completed state and repeats its lifecycle-subscriber interaction. - -HCF will classify initial and later Compressed BAR from actual frame-sequence progress before mode selection. The current initiator predicate always returns false and cannot supply that classification. Fresh channel access requires initial classification again. Retain unrelated RTS/CTS and ACK behavior. - -Rate-only notifications must preserve unchanged agreements in either profile. Missing HT state cannot retire Basic compatibility. Management must still notify HCF of real association reset for Basic peers without HT records. Lifecycle A3b owns that handoff and its callback-order checks. - -Compressed requires usable local and peer HT state; its capability-gap cases use Normal Ack. Explicit Basic retains existing ad hoc and non-HT capability assumptions. It requires no new peer HT records or IBSS capability implementation. - -Clause 10.2.7 prohibits fragmentation under the Compressed HT-immediate agreement, regardless of DATA ACK policy. Basic preserves historical fragment handling. An HT PHY mode alone does not select the Compressed profile. - -The [legacy inventory](ieee80211-compressed-blockack-replacement.md#s3a-demonstration-migration-and-fallback-inventory) preserves the Block Ack and TXOP ad hoc networks. Both QoS examples retain their modes, topology, and traffic. Preserve S3a's explicit Basic settings in the existing scopes. - -Retain `Fragmentation`, `HCFfragblockack`, `PacketSizeHCFfragblockack`, `TxPowerHCFfragblockack`, `ThresholdHCFfragblockack`, and `OnlyPacketSizeHCFfragblockack`. Keep their analysis inputs, result filters, plot series, fingerprint rows, and six speed records. Other Basic showcase records also remain. - -Hypothetical example: the Block Ack `Fragmentation` configuration selects Basic at both ad hoc hosts. It still reports fragments through its Basic bitmap. A valid Compressed agreement transmits the same MSDU without fragmentation. These profiles need different expectations. - -At each relevant description or analysis caption, state Basic's historical origin and its absence from IEEE Std 802.11-2024. Keep existing images and results when evidence still supports them. Shared repairs can change results despite unchanged topology and traffic. Regenerate only affected material after measurement. - -Every legacy demonstration must retain ADDBA, Basic BAR, Basic responses, and positive receipt status. Check fragments in the fragmentation cases. Ad hoc QoS run 1 retains Basic; run 0 remains support-disabled. Check Compressed capability-gap fallback separately. - -Infrastructure protocol fixtures supply Compressed coverage through real capability exchange. `N_CompressedBa` must require Compressed and positive bits. `Ac_BlockAck` remains positive coverage for eligible `ac` peers. The absent-peer-state fallback fixture selects Compressed and static management without Beacon refresh. - -Retain Basic NAV, multiple-protection, header, and serializer assertions. Add Compressed cases with valid HT state. Retain 152-byte Basic response-mode cases beside new 32-byte Compressed cases. Preserve directional queries, asymmetric state, peer isolation, and ACK/CTS controls. - -The four deferred protocol obligations remain distinct from successful exchanges. Explicit Basic retains `WifiQosDelayedBa` and its missing delayed behavior. A separate fixture verifies Compressed initialization rejection for delayed policy. This revision adds no new Basic initialization guard. - -Migration guidance explains the default, explicit Basic setting, and added interface obligations. HCF logs the resolved profile when support is enabled. If Compressed lacks usable local HT support, it emits one initialization warning for that interface. Basic and disabled support produce no irrelevant warning. - -That local warning cannot detect HT ad hoc management without peer HT records. The existing policy decision log must identify the capability-gap refusal. C4's external-style fixture omits the selector and tests legacy modes plus HT ad hoc operation. It must prove Normal Ack fallback and the applicable diagnostics. Explicit Basic must restore Basic exchanges. The default remains independent of the mode set. - -## Implementation order and verification - -S1, R1, and S3a are merged. The remaining stages are S2, S3b, S4, and S5. S3b must use a parent that contains R1 and S3a. A4 requires S2; earlier lifecycle units can proceed independently of S2. The arrows below show required dependencies: - -```mermaid -flowchart TD - S1["S1: Merged
Basic capacity, cyclic delivery, and BAR before DATA"] - S2["S2: DATA lifetime
All QoS DATA"] -->|"Required by A4"| S3b["S3b: Agreement lifecycle
Action, negotiation, teardown, and setup repairs"] - S3a["S3a: Merged
Explicit Basic settings and profile evidence"] -->|"Retain Basic checks and revise temporary rejection"| S3b - S3b -->|"Supplies teardown"| S4["S4: Independent BAR work
Channel access and final-transfer DELBA"] - S1 -->|"Supplies recipient progress"| S4 - S4 --> C1 - R1["R1: Merged
Management rates and combined MIB commits"] -->|"Committed rates and subscriber checks"| C2 - R1 -->|"Preserve coherent commits and add explicit reset"| S3b - subgraph S5["S5: Compressed addition beside retained Basic"] - C1["C1: Wire formats"] --> C2["C2: Complete exchanges and timing"] - C2 --> C3["C3: Response and timing verification"] - C3 --> C4["C4: Default activation and migration diagnostics"] - end -``` - -S2 implements the lifetime prerequisite. S3a already records explicit Basic settings and legacy exchange evidence against its original parent. S3b uses a parent with merged S3a and R1 and implements A1, A2, A3a through A3c, and A4. These units repair Action dispatch, negotiated values, safe teardown, and uncertain setup. A3c owns recovery for valid BAR and Block Ack-policy DATA without an agreement. A4 requires S2 and the earlier lifecycle repairs; A1, A2, and A3a through A3c do not require S2. - -The lifecycle plan separates A3 into [three review units](ieee80211-blockack-agreement-lifecycle.md#5-reviewable-stages-and-dependencies): - -| Review unit | Responsibility | -| --- | --- | -| A3a | Directional teardown, deletion signals, duplicate state, and inactivity. | -| A3b | Association reset, the AP management change, and consumer and callback verification. | -| A3c | Complete Action disposal and absent-agreement recovery. | - -The split does not establish independent publication boundaries. Action invalidation and safe completion must accompany the first retirement or reset path that needs them. Hypothetical example: A3a retires an agreement while a successful ADDBA Response remains queued. A3a must invalidate that response before another attempt; it cannot defer that protection to a later published A3c change. - -C2 must implement Clause 10.25.6.6.2.1(a)(2)(v), including its surrounding agreement, station, sequence-window, receipt-bit, and timing conditions. The [history and timing design](ieee80211-compressed-blockack-replacement.md#interframe-history-and-timing-design) is implementation work within that requirement. Its owner must resolve timestamp mapping, event observation, stored state, and invalidation before the affected implementation is complete. These details require source and standards evidence, not another policy choice or an optional omission of the rule. - -If PHY observations cannot establish the timing relation, the C2 owner records the gap and proposes the smallest correction. The code reviewer checks that correction against the standard and supported PHY model. A model approximation or reduced scope requires an explicit maintainer-approved plan revision with stated compliance limits. No such approximation is approved here. - -Local experimental code may support that investigation. The affected release path cannot be published until its design review and direct verification pass. Independent work may continue if it neither exposes nor depends on that incomplete path. No runtime switch is required solely to disable an unfinished rule. - -Tests must distinguish receipt-bit and timing conditions through separate positive and negative cases. They must include propagation delay, intervening frames, and cleanup. The implementation must not add unsupported same-peer, address, or TID restrictions. The rule can change Compressed delivery timing; Basic retains S1 behavior and needs separate evidence for any changed fingerprint. - -The [stage conditions](ieee80211-compressed-blockack-replacement.md#stage-conditions) distinguish start, continuation, completion, and publication. The lifetime review precedes S2 implementation. S2 reproduces absent queue expiration before the production change and demonstrates corrected expiry before completion. The lifecycle review and completed S3a preparation precede S3b implementation, including A1. The umbrella review does not establish either prerequisite plan's correctness or completed verification. - -The [maintainer decision table](ieee80211-compressed-blockack-replacement.md#maintainer-decisions) records all five accepted choices: - -- The maintainer accepted the 0.512-second lifetime default for S2/L1, with Block Ack enabled or disabled. -- The accepted 100 ms response timeout satisfies the A4 decision condition. -- The maintainer accepted the queue predicate for A5 in S4. -- The maintainer accepted the individual-DATA purpose and scope for C2. -- The accepted fatal configuration error satisfies C2's profile-conflict decision condition. - -S1, R1, and S3a retain their separate completed scope and recorded verification. The remaining stages are S2, S3b, S4, and S5. The explicit decision approvals select all five policy outcomes. They establish no completed implementation or verification of those remaining stages. - -Other stages follow their applicable review and prerequisites. S3b requires a parent that contains merged S3a and R1. A2 must revise S3a's temporary Compressed rejection and its selector fixture. `Ac_BlockAck` remains a positive requirement and adds no deferral approval gate. - -S1 corrects recipient delivery and capacity through Basic tests with supplied agreements and known buffer sizes. Its eight scenarios include complete gap release and BAR before DATA. Retain all eight as Basic regression checks through later stages. S3b/A2 must verify that negotiation supplies the accepted size and sequence number to the repaired recipient. C2 and C4 must verify Compressed integration separately. S1 does not establish the final Compressed bitmap representation. - -Before S4 starts, its owner confirms that S3b supplies teardown and S1 supplies recipient progress. S4 adds BAR work without DATA extraction and integrates A5 with the accepted transfer-completion predicate. S4 compares changed Basic BAR timing with its pinned parent before publication. Any new unlawful overrun requires resolution at that boundary, without a future C2 or C3 result. S4 preserves Basic fragment rules. S5 retains them beside the Compressed restriction. - -S5 consists of C1 through C4 after its required S1–S4 contracts. R1 already satisfies the publication prerequisite. C2 repeats subscriber integration and supplies actual BAR classification and Compressed response calculations. Those calculations cover response-rate selection, override validation, BAR timeout, recipient duration, and protection airtime. C2 records the selected modes, first airtime result, and admission decision before C3 or C4 proceeds. C3 verifies supported response modes and exchange boundaries; it supplies no missing runtime operation required by C2. - -The first C2 timing result is not a prerequisite for S5 to start. Each step must build: - -| Step | Change and required result | -| --- | --- | -| C1 | Define the 28-byte Compressed header chunk and complete Type decoding beside Basic. Retain Basic round trips that encode Type 0. Adapt existing Compressed producers and field expectations with the serializer change. | -| C2 | Consume R1 rates and add complete Compressed exchanges without loss of Basic fragment state. Preserve receipt truth after delivery and add the individual-MPDU interframe release condition. Supply actual BAR classification, legal control modes, durations, and profile validation. Enforce the Compressed fragmentation boundary. Record the first Compressed timing result before C3 or C4. | -| C3 | Verify initial and later BAR rates, primary and legal alternate responses, mandatory-rate fallback, and HT/VHT reference rates. Preserve directional response queries and ACK/CTS controls. Repeat timing checks across supported modes and exchange boundaries, with permitted-overrun conditions explicit. | -| C4 | Activate the final Compressed default after runtime and timing checks. Add migration diagnostics and the external-style fixture. Retain explicit Basic consumers and all legacy result rows. Add Compressed-only delayed-policy rejection. | - -Basic remains through every prerequisite and the final implementation. Each publication boundary must preserve a Basic path that passes direct checks. A partial recovery state machine is not publishable. S3a temporarily retains the Basic default; C4 activates the requested Compressed default after C2 and C3. - -Basic fragment scenarios remain after C4. Compressed fragment input must cause no receipt-state update, positive bit, or delivery. Ordinary Normal Ack fragmentation remains outside Compressed agreements. Timing evidence and any required admission correction still control S5 completion. - -A wire-only change cannot establish the required exchange behavior. Hypothetical example: an empty receive record must produce zero Compressed bits. A correct type 2 header cannot compensate for false positive receipt status. - -## Verification and performance evidence - -Verification combines both wire formats, production assertions, the full fixture inventory, and all 19 selected fingerprint rows through C4. Explicit Basic preserves the legacy scenarios. Shared repairs can still change results. Production assertions establish behavior; fingerprints expose regression effects. - -The current [Ieee80211BlockAckReordering_1.test](../../tests/module/Ieee80211BlockAckReordering_1.test) supplies the completed S1 recipient checks. Its default selects scenarios 0 through 7 with seed 0. The [umbrella verification section](ieee80211-compressed-blockack-replacement.md#6-verification-and-scope-limits) gives its exact module selector with the current NAV fixture. These checks supply no ADDBA negotiation or Compressed exchange evidence. - -The planned focused fixtures separate lifetime, agreement lifecycle, and Compressed integration. They include `Ieee80211EdcaDataLifetime_1.test`, `Ieee80211BlockAckAgreementLifecycle_1.test`, `Ieee80211CompressedBlockAck_1.test`, and `Ieee80211HcfCompressedBlockAck_1.test`. The current `N_CompressedBa.test` must assert Compressed frames and positive receipt bits. These later checks are proposed, with no completed results. - -R1's existing production fixtures compare committed MIB rates with real advertisements without direct rate injection. Their [evidence record](../../doc/project/evidence/model/wifi/r1-rate-publication.md) covers publication, callback state, cleanup, membership selectors, and nonfinite inputs. Retain `Ieee80211MgmtRatePublication_1.test` and `Ieee80211MgmtStateCommit_1.test` after affected changes. C2 must repeat subscriber effects after S3b exists. HCF checks must distinguish initial and later BAR rates, including initial classification after fresh channel access. RTS/CTS and ACK controls remain. - -The protocol selection includes eight original fixtures and the proposed absent-peer-state `ac` fallback fixture after it exists. The original module selection includes four fixtures that can enable Block Ack, five support-disabled controls, and the separate S1 recipient fixture. Add S3a's selector and Basic observation fixtures, plus R1's existing publication and state-commit fixtures, to affected regression checks. Retain HT mode-set, VHT/HT capability, response-mode, and MIB unit coverage. C1 checks existing serializer producers and inventories; C4 adds remaining serializer coverage and delayed-policy rejection. Record observed outcomes and their actual failure causes separately from deferred obligations. - -The common fingerprint selection through final C4 covers these simulation paths: - -| Path | Retain after C4: 19 rows | -| --- | --- | -| `showcases/wireless/blockack` | `NoFragmentation`, `MixedTraffic`, `Fragmentation` | -| `showcases/wireless/aggregation` | `NoAggregation`, `Aggregation`, `VoicePriorityAggregation` | -| `showcases/wireless/fragmentation` | `DCFnofrag`, `DCFfrag`, `HCFfrag`, `HCFfragblockack` | -| `showcases/wireless/qos` | `NonQos`, `Qos` | -| `showcases/wireless/txop` | `General`; run 0 | -| `examples/wireless/qos` | `MacQos`, `MacQosWithoutAggregation`, `MacQosWithRtsCts`, `MacQosWithBlockAck`; run 0 | -| `examples/adhoc/qos` | `MacQos`; runs 0 and 1 | - -Block Ack-disabled EDCA rows check the broader lifetime scope. DCF rows provide controls for shared changes. Each row retains its recorded run number, time limit, and fingerprint ingredients; the four wireless QoS rows use run 0. The TXOP row records five seconds, and both ad hoc QoS rows record ten seconds. Block Ack `General` has no separate fingerprint row; direct exchanges and its speed record cover that configuration. - -Each behavior repair must first reproduce its old failure through production code. It compares its corrected result with a pinned parent before another stage changes the same path. S3a records explicit Basic settings without topology or mode changes. Prerequisite tests retain Basic. S5 repeats integration checks with Compressed and rechecks Basic compatibility. - -Tests cover short bursts, sequence wrap, lost responses, queue disposal, uncertain setup, DATA expiration, and reassociation. Each changed fingerprint needs a cause from the stage that introduces it. The implementation must preserve raw results and comparison revisions. S1's four approved changes retain their [separate authority and exact values](../done/ieee80211-compressed-blockack-s1.md). This plan revision authorizes no additional baseline update. - -The [direct verification cases](ieee80211-compressed-blockack-replacement.md#6-verification-and-scope-limits) also cover one peer with two TIDs and buffer sizes below BAR threshold five. They check shifted responses, positive bits for transmitted frames outside the BAR wait, and retry release after a response without overlap. Positive bits must not acknowledge unsent frames or frames outside the active window. HCF module assertions establish these integration results; helper tests and fingerprints cannot replace them. - -Performance checks must separate request contention, response wait, DELBA completion, and total DATA deferral. They must measure delivery, lifetime disposal, teardown disposal, management airtime, and progress for another eligible peer or TID. Teardown measurements must separate inactivity-driven disposal from other causes and record whether discarded DATA still had an unexpired lifetime deadline. Controlled comparisons retain the same traffic, seed, rates, and channel conditions. The plans assume no performance improvement or acceptable loss threshold. - -For bursts with idle gaps, count ADDBA and DELBA exchanges, including retries. Measure application goodput as useful bytes delivered per unit of simulated time over a fixed interval. A separate experimental policy can estimate agreement-reuse effects with otherwise identical inputs. Without that experiment, report observed costs without a claim about agreement-reuse performance. - -S4 needs timing evidence before publication of its changed Basic BAR paths. Test standalone BAR, final BAR after one or four DATA frames, and late continuation near a positive TXOP limit. Exercise single and multiple protection. Compare with S4's pinned parent and apply the exact TXNAV and TXOP conditions. The [umbrella timing contract](ieee80211-compressed-blockack-replacement.md#airtime-acceptance-and-admission-dependencies) owns the required observations and correction boundary. - -Fragmentation suppression needs further airtime checks at C2. At a fixed mode, one unfragmented frame takes longer than one constituent fragment, although the complete fragment sequence can cost more. Block Ack-enabled HCF lacks complete-cost single-protection admission. A positive remaining TXOP interval does not prove that the next complete exchange fits. - -Hypothetical example: a previous DATA exchange ends with 100 microseconds left, but another DATA exchange needs 200 microseconds. The positive remaining interval does not authorize that continuation. C2 must measure the applicable TXNAV and TXOP bounds before C3 or C4 proceeds. Its checks cover Compressed infrastructure fixtures. Retained Basic showcase hops need separate regression observations. - -C3 repeats affected checks across supported response modes and exchange boundaries. No current evidence proves timing compliance for the final configurations. - -Clause 10.23.2.9 permits specific overruns when a TXOP contains at most one Data or Management frame. One permitted case is initial transmission of an unaggregated MSDU under a Block Ack agreement. The MSDU must satisfy the clause's aggregate conditions. The timing record must prove every exception condition and any independent TXNAV requirement. An initial A-MSDU does not qualify for that exception. A second DATA exchange also defeats the one-frame condition. - -Hypothetical example: the first unaggregated MSDU under an agreement needs 200 microseconds within a 100-microsecond TXOP limit. No other Data or Management frame exists in that TXOP, and the aggregate conditions hold. The TXOP exception permits that overrun. The same result for an initial A-MSDU or a second DATA exchange requires a different assessment. - -```mermaid -flowchart TD - M["Measure the complete exchange and TXOP contents"] --> X{"Applicable TXNAV bound satisfied?"} - X -->|"No"| V["Timing violation"] - X -->|"Yes"| L{"Within the TXOP limit?"} - L -->|"Yes"| P["Timing check passes"] - L -->|"No"| E{"All conditions of Clause 10.23.2.9's exception hold?"} - E -->|"Yes"| A["Permitted overrun
No admission-correction prerequisite"] - E -->|"No"| V - V --> N{"Did this stage introduce the violation?"} - N -->|"Yes"| C["Separate correction before affected-path publication"] - N -->|"No"| I["Record the inherited limitation separately"] -``` - -Each responsible stage records permitted overruns, inherited violations, and new violations against its own parent. A permitted overrun creates no admission-correction prerequisite. S4 resolves new unlawful overruns before publication of its affected Basic path. S5 waits for any correction required by Compressed integration and its direct checks. C3 repeats the classification across supported response modes and exchange boundaries. The C2 comparison cannot relabel an unresolved S4 violation as acceptable inherited behavior. - -An alternative configuration restriction needs direct evidence of timing compliance within its stated scope. A fixed MSDU cap alone cannot establish that a later exchange fits the remaining TXOP. The plan selects no automatic size cap or silent Normal Ack fallback. - -The integration source is local `master` at `633b071e213b825ce6019ff3e344ae49f52791ff`, with S1, R1, and S3a merged. Original S1 verification retains feature head `fcc0645035` and publication base `ac6344cc5bcac972012759281a11b3f8255b5d46`. Each remaining stage must pin its actual merged parent and comparison base. Shared HCF paths establish overlap but do not prove a merge conflict. The older lifetime and lifecycle observations require fresh source and caller checks against their selected parents. +## State ownership and failure behavior -S1's final-series record reports debug and release builds, eight recipient scenarios, three NAV runs, and 12 selected fingerprints as successful. Four separately approved fingerprint changes belong to its delivery commit. The [S1 evidence](ieee80211-compressed-blockack-replacement.md#completed-s1-and-recorded-verification) states the exact scope and commands. Those 12 configurations do not verify the proposed 19-row common selection. +The data service previews queued DATA without extraction or sequence assignment. Queue owners perform filtered pull operations when extraction occurs. The originator agreement owns cyclic window operations. The recipient keeps receipt status separate from the reorder buffer that controls delivery. -The earlier 13 October review passed two capability unit fixtures, `Ac_BlockAck`, and the seven-scenario VHT/HT module fixture after a debug build. Those results retain their [historical source and limits](ieee80211-compressed-blockack-replacement.md#branch-verification-record). The plan retains 19 fingerprint rows and ten speed records for later verification. Six speed records cover fragmentation configurations; four cover other Block Ack and TXOP configurations. This document update executes no runtime check. Final performance, lifetime integration, lifecycle repairs, and Compressed behavior remain unverified. +BAR failure updates contention without a DATA retry charge. Failed feedback makes later DATA retransmission set Retry. The finite [DATA lifetime](ieee80211-edca-data-lifetime.md) continues through retries and setup deferral. Final resolution or expiry can trigger completion DELBA even with zero inactivity timeout. -## Scope limits +Ordinary recipient teardown delivers complete buffered units before cleanup. Association reset instead discards old peer state without delivery into the replacement association. Acknowledgment alone does not establish delivery. -The plan excludes these features: +## Compatibility and evidence limits -- A-MPDU and implicit BAR. -- Delayed Block Ack and Multi-TID Block Ack. -- HE bitmap lengths and dynamic fragmentation. -- Groupcast Block Ack. -- New complete-cost TXOP admission and BAR forecasts. +Basic is an INET compatibility profile for the IEEE Std 802.11e-2005 format. It is not Basic support under IEEE Std 802.11-2024. Basic preserves existing fragment and ad hoc behavior. The [implementation status](ieee80211-compressed-blockack-replacement.md) defines configuration and extension contracts. -A-MPDU means several MAC frames within one aggregate. A TXOP is an interval in which a station can start frame exchanges. +Basic single protection reserves only prepared successors; unextracted DATA requires another TXOP. This can increase contention and repeated setup. General Basic DATA admission, complete NAV conformance, Compressed exchanges, A-MPDU, delayed Block Ack, and Multi-TID Block Ack remain outside the implementation claim. -The individual-DATA profile does not establish complete HT-immediate transfer coverage. The plan also makes no stop/start recovery claim. +The [current verification record](ieee80211-compressed-blockack-s4-execution.md) identifies the build, module, unit, protocol, and fingerprint results. It gives exact commands and explicit limits. This summary adds no simulation or performance result. diff --git a/plan/pending/ieee80211-compressed-blockack-replacement.md b/plan/pending/ieee80211-compressed-blockack-replacement.md index a92fbe3d43a..93ae88cae29 100644 --- a/plan/pending/ieee80211-compressed-blockack-replacement.md +++ b/plan/pending/ieee80211-compressed-blockack-replacement.md @@ -1,849 +1,106 @@ -# Implementation plan: add Compressed Block Ack and retain Basic Block Ack +# Basic and Compressed Block Ack implementation status -Integration source: local `master` at `633b071e213b825ce6019ff3e344ae49f52791ff`, with S1, R1, and S3a merged. -Plan revision: 2026-10-15, revision 31. -Review checkout: `/home/user/omnetpp_ws/inet-compressed-blockack-s2`, branch `work/compressed-blockack-s2`, at `d2fcb528b67f9be376caa06d68ea0c1c028ab145`. -Source basis: the pinned integration source and IEEE Std 802.11-2024. Earlier direct PDF inspection supplies the historical IEEE Std 802.11e-2005 evidence. Local S2 source, test, and plan edits are separate from merged master. This review preserves those edits. Remote verification failed because GitHub access was unavailable; the integration pin describes local master. +> **Kind:** reference · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [HCF](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc), [HCF parameters](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.ned) -Approval: the maintainer's 14 October 2026 instruction, "proceed", after the revision-24 review authorizes these corrections to four plan documents. The [S1 source record](../done/ieee80211-compressed-blockack-s1.md) owns its separate implementation, baseline, and publication authorization. This document approval authorizes no later implementation, recorded expectation change, or publication. The [decision table](#maintainer-decisions) records accepted choices and remaining stage requirements. +This checkout implements Basic Block Ack agreement lifecycle and transfer completion. Basic remains the default profile. Production Compressed exchanges are absent. HCF rejects `blockAckVariant = "compressed"` at initialization with `Compressed Block Ack exchanges are not implemented`. -Decision approval: on 14 October 2026, the maintainer accepted the 0.512-second DATA lifetime default, transfer-completion predicate, and individual-DATA scope. The maintainer subsequently selected a 100 ms ADDBA response timeout and a fatal configuration error for active profile conflict. The [decision table](#maintainer-decisions) records all five accepted choices. These instructions authorize their record in the plans, not implementation, baseline changes, or publication. The maintainer's subsequent instructions authorize the review corrections and strict application of the individual-MPDU release clause in revision 30. Its timestamp mapping, event observation, and state ownership are implementation design work, not additional policy decisions. +This document describes the source in this checkout. The [summary](ieee80211-compressed-blockack-replacement-summary.md) gives the main behavior. The [verification record](ieee80211-compressed-blockack-s4-execution.md) gives current results and their limits. -The earlier "proceed" for revision 30 authorizes its text corrections and explicit escalation and publication rules. The current "proceed" authorizes the remaining document corrections for merged R1 and S3a. Strict compliance remains required; no model approximation is approved. +## Previous PRs and S4 scope -S1 merged through [PR #1320](https://github.com/inet-framework/inet/pull/1320) at `1cdb362a2a4b97f564566487079d9d156a5d213d`. Its original verified head is `fcc06450355a52b9c8b0f8f2647e0654711bfaca`. [Appendix A](#completed-s1-and-recorded-verification) preserves that head's scope and recorded evidence. R1 and S3a are also merged, as the [completed prerequisite record](#completed-r1-and-s3a) explains. This revision adds no runtime verification of the combined source. The remaining stages retain their separate review and verification requirements. +The branch `work/compressed-blockack-s4` contains the changes for [PR #1344](https://github.com/inet-framework/inet/pull/1344). Its master base already contains the following merged work. Those mechanisms are prerequisites, not additions from S4. -Revision 31 follows the maintainer's request to account for merged R1 and S3a. It corrects stage status, source assumptions, and dependent verification. It grants no new implementation, baseline, or publication authority. - -This plan defines Compressed support beside retained Basic support and orders its prerequisite changes. The [EDCA lifetime plan](ieee80211-edca-data-lifetime.md) owns DATA expiration. The [agreement lifecycle plan](ieee80211-blockack-agreement-lifecycle.md) owns setup, recovery, and teardown. Section 5 defines separate review and regression boundaries. The complete design is not one implementation change. +| Previous PR | Behavior inherited by S4 | +| --- | --- | +| [#1320: recipient progress](https://github.com/inet-framework/inet/pull/1320) | Receive capacity from agreement values, cyclic delivery, consecutive gap release, and Basic BAR progress before DATA. | +| [#1331: QoS DATA lifetime](https://github.com/inet-framework/inet/pull/1331) | Identity-based deadlines, the 0.512-second default, expiry, aggregation lifetime rules, and safe completion across expiry. | +| [#1343: Basic agreement lifecycle](https://github.com/inet-framework/inet/pull/1343) | Setup validation, Action dispatch, directional teardown, DATA deferral, A-MSDU permission, and recipient teardown disposition. | +| [#1368: association replacement cleanup](https://github.com/inet-framework/inet/pull/1368) | Explicit management-to-MAC peer reset before association replacement, with cleanup before deletion callbacks. | -## 1. Core intended behavior +S4 uses those existing owners to complete outstanding Basic DATA when another DATA candidate cannot proceed. Its production changes have four commit boundaries: -INET will default to immediate Compressed Block Ack for its supported non-DMG HT stations. An explicit Basic profile will preserve the existing legacy demonstrations. An HT station supports high throughput operation. A Block Ack agreement identifies one peer and traffic identifier (TID). ADDBA establishes that agreement. A Block acknowledgment request (BAR) asks the recipient for a Block Ack response. +| S4 commit | Change relative to its parent | +| --- | --- | +| Expose DATA preview without extraction | Adds the QoS preview interface and borrowed candidate access through `InProgressFrames`, with prospective sequence lookup. The concrete data service already supports preview. | +| Mark DATA retries after failed Block Ack feedback | Sets Retry on retransmitted standalone DATA. Existing ACK status already permits that retransmission. | +| Add shared originator window operations | Adds cyclic distance, bitmap membership, and window advancement before their production callers. This preparation changes no packet trajectory. | +| Complete Basic BAR transfer resolution | Selects BAR before extraction, permits BAR-only contention, and separates outstanding groups by peer and TID. It adds matched feedback, control-failure recovery, completion DELBA, and prepared-successor reservation rules. | -The originator will send Compressed BAR only when an immediate agreement applies to the peer and TID. The recipient will send Compressed Block Ack after a valid addressed Compressed BAR for that agreement. The BAR carries a starting sequence number, not a range length. The recipient will build its 64-bit bitmap from its adjusted scoreboard window. Its response starting sequence number may differ from the BAR value. +The final S4 commit documents that integrated result and its verification. The filtered queue API, finite lifetime mechanism, and ordinary recipient teardown delivery remain inherited contracts. S4 connects final resolution or lifetime disposal to window progress and completion DELBA through those contracts. -The originator will apply bitmap outcomes only to frames that the response covers. INET will retain Basic BAR, Basic Block Ack, their C++ classes, serializers, and fragment bitmap support. Basic is a historical compatibility profile, not a variant supported by IEEE Std 802.11-2024. +For example, recipient teardown already knows how to release complete units behind a gap. S4 makes final DATA expiry trigger completion DELBA when no DATA remains. The new trigger uses the existing recipient disposition; S4 does not introduce that disposition. -Hypothetical example: two associated HT stations have an accepted agreement for TID 5 with starting sequence number 4094. The recipient's scoreboard starts at that number. The [lifecycle plan](ieee80211-blockack-agreement-lifecycle.md#3-agreement-behavior) defines setup and DATA eligibility. +Master also supplies profile validation, Basic defaults, and coherent rate-state publication. S4 preserves Basic as the default and retains Compressed initialization rejection. Production Compressed exchanges belong to the separate S5 branch and [PR #1345](https://github.com/inet-framework/inet/pull/1345), outside this checkout. -The originator sends four unfragmented QoS DATA frames with Block Ack policy. No unsent DATA remains. The originator requests channel access for a Compressed BAR with starting sequence number 4094. The recipient sends a Compressed Block Ack after SIFS. Its bits for sequence numbers 4094, 4095, 0, and 1 follow modulo-4096 order. +## 1. Supported behavior -The originator removes acknowledged frames for that peer and TID. Missing frames remain available for retry within the [lifetime contract](ieee80211-edca-data-lifetime.md#3-proposed-ownership-and-behavior). The [lifecycle plan](ieee80211-blockack-agreement-lifecycle.md#first-data-and-final-transfer) owns transfer completion and teardown. +Block Ack support is optional through `isBlockAckSupported`, which defaults to false. With support enabled, HCF coordinates immediate Basic agreements for one peer and traffic identifier (TID). Basic permits the existing non-HT and ad hoc configurations. Its compatibility profile does not require new peer HT capability records. -Under the Compressed profile, absent usable local or peer HT state selects Normal Ack and prevents agreement setup. The Basic profile retains the existing capability assumptions, including ad hoc operation without peer HT records. It does not claim current-standard conformance. The [lifecycle prerequisite](ieee80211-blockack-agreement-lifecycle.md#3-agreement-behavior) owns recovery when a valid frame arrives without an agreement. +The recipient maintains receipt status separately from its reorder buffer. Receipt status controls Block Ack feedback; the reorder buffer controls delivery. A positive acknowledgment therefore does not by itself prove upper delivery. When DATA fills a gap, the recipient releases consecutive complete units in the same operation. A valid Basic BAR can create or advance the reorder record before DATA arrives. -The current `ac` mode supplies HT operation and peer HT state through its inherited HT support. VHT means very high throughput. An associated `ac` peer with usable HT state remains eligible for this profile. The [fixture inventory](#s3a-tracked-fixture-inventory-and-vht-scope) retains `Ac_BlockAck` as a positive requirement. Normal Ack fallback requires an actual capability gap; `opMode = "ac"` alone does not establish one. +The [agreement lifecycle](ieee80211-blockack-agreement-lifecycle.md) owns setup, Action dispatch, directional teardown, and peer reset. The [DATA lifetime contract](ieee80211-edca-data-lifetime.md) owns finite QoS DATA deadlines, with Block Ack enabled or disabled. ## 2. Standard support and model boundary -IEEE Std 802.11-2024 Tables 9-36 and 9-37 assign variant type 0 to Reserved. Both tables assign type 2 to Compressed. Their corpus identifiers are `ieee80211-2024:table:9-36` and `ieee80211-2024:table:9-37`. They appear on physical PDF pages 719–720 and 722–723. - -IEEE Std 802.11e-2005 introduced the Block Ack mechanism and the frame format later called Basic Block Ack. Clauses 7.2.1.7 and 7.2.1.8 define BAR and Block Ack; Clause 9.10 defines their operation. Clause 7.2.1.8 specifies a 128-octet bitmap for 64 MSDUs, with fragment status. Direct inspection of `../inet-standards/80211e-2005.pdf`, relative to the repository root, confirms printed pages 30–32 and 96–100. These are physical PDF pages 52–54 and 118–122. The [IEEE publication record](https://standards.ieee.org/ieee/802.11e/3131/) identifies Amendment 8 and its 11 November 2005 publication. - -Retained Basic support models that historical format and preserves existing INET studies. IEEE Std 802.11-2024 does not support Basic; type 0 remains reserved in that standard. This retention does not claim complete IEEE Std 802.11e-2005 conformance. Existing Basic demonstrations can use later PHY modes and existing INET response behavior. User documentation must distinguish the historical frame format from those model choices. - -Figures 21b and 21e of IEEE Std 802.11e-2005 reserve control bits B0–B11 and assign B12–B15 to TID. INET's retained ACK-policy fields and serializer values are compatibility choices, not field semantics from those figures. C1 preserves the supported Type 0 contract below without a complete historical conformance claim. - -Table 11-8 permits the Compressed profile's immediate agreement when both non-DMG stations are HT stations and ADDBA selects immediate policy. Clause 10.25.2 requires the first DATA sequence number to equal the accepted ADDBA Request starting sequence number. Clause 10.25.6.1 requires HT-immediate Block Ack support for an HT recipient. Clause 9.3.1.7.2 sets the Compressed BAR fragment subfield to zero. Clause 9.3.1.8.2 and Table 9-38 define the Compressed Block Ack bitmap. For a non-HE station, the fragment subfield is zero and the bitmap has 64 positions. - -Clause 10.25.6.5 requires a response after SIFS for an addressed BAR during full-state or partial-state operation. It requires a zero bitmap when no matching partial state exists. This plan selects full-state operation for an established agreement. The [lifecycle standards evidence](ieee80211-blockack-agreement-lifecycle.md#8-standards-evidence-and-scope-limits) covers absent-agreement recovery. - -The [lifetime evidence](ieee80211-edca-data-lifetime.md#2-current-source-and-standard-support) covers the DATA disposal bound. The lifecycle plan separates standard requirements from its transfer-completion interpretation. Clause 9.2.5.6 defines the response Duration/ID subtraction. Clauses 10.6.6.5.2 and 10.6.6.5.4 define primary and alternate response rates. - -This change covers immediate, one-TID Compressed BAR and Compressed Block Ack in the existing non-DMG HT MAC. It uses a 64-position bitmap and an explicit BAR exchange. The Compressed recipient keeps full-state status under Clauses 10.25.6.2 and 10.25.6.3. The selected INET profile sends individual QoS DATA frames before BAR. Clause 10.25.2 describes transfer in A-MPDUs, while Clause 10.25.3 describes BAR for outstanding QoS DATA frames. This plan does not claim complete HT-immediate transfer coverage without A-MPDU. +Basic represents the frame format from IEEE Std 802.11e-2005, Clauses 7.2.1.7, 7.2.1.8, and 9.10. IEEE Std 802.11-2024 Tables 9-36 and 9-37 reserve type 0 and assign type 2 to Compressed. Basic support is an INET compatibility profile. It establishes neither complete IEEE Std 802.11e-2005 conformance nor current-standard Basic support. -### Purpose of the individual-DATA profile +Basic retains its fragment bitmap and existing PHY choices. The shared code contains Compressed frame classes and HT admission predicates. Those components do not establish a production Compressed exchange because HCF rejects that profile before operation. -The accepted user need is controlled study of Compressed bitmap, response, and recovery behavior in INET's current individual-frame MAC. C2 will supply a directly observed Compressed BAR and Block Ack exchange for that purpose. The frame and scoreboard contracts can also support a later A-MPDU design. That later design remains separate. - -The response MPDU decreases from 152 bytes for Basic to 32 bytes for Compressed. This frame-length result does not establish lower exchange airtime or higher application goodput. Control rates, explicit BAR, contention, and repeated setup also affect those results. Section 6 requires direct exchange and airtime evidence without an assumed performance gain. - -On 14 October 2026, the maintainer accepted this intermediate scope for the stated user need. The scope decision before C2 is satisfied. Complete HT-immediate transfer coverage requires a separate A-MPDU design. Wire definitions and independent prerequisite repairs do not establish that complete coverage. - -### Excluded features and fragmentation - -The plan excludes A-MPDU, implicit BAR, HE bitmap lengths, dynamic fragmentation, delayed Block Ack, Multi-TID Block Ack, and GCR. Complete-cost TXOP admission and BAR forecasts also need separate designs. - -Clause 10.2.7 prohibits MSDU fragmentation under the Compressed profile's HT-immediate agreement, even above the fragmentation threshold. Normal Ack does not bypass this restriction. C2 will suppress fragmentation only for that profile's active agreement and peer/TID. - -Basic retains historical fragment handling in the existing fragmentation showcases. Local HT support alone does not turn a Basic compatibility agreement into this Compressed agreement. Outside an agreement, fragmented DATA uses Normal Ack. The lifecycle prerequisite resolves already numbered fragments before setup; C2 tests that boundary with Compressed operation. - -Hypothetical example: the threshold is 250 bytes and a queued MSDU contains 1000 bytes. With an active HT-immediate agreement, the data service extracts it without fragmentation. Without an agreement, the existing fragmentation policy applies and each fragment uses Normal Ack. - -A positive bitmap bit in this profile will acknowledge a complete MSDU or A-MSDU. One fragment alone will not produce a positive bit. Table 9-38 assigns one bit to each unit when the Fragment Number subfield is zero. Clauses 9.4.1.13 and 10.25.6.2 apply the response's A-MSDU permission to DATA for the agreement's peer and TID. A change to Normal Ack alone does not permit A-MSDU DATA when that permission is absent. +The lifecycle document identifies the current INET teardown and recovery choices. General Basic DATA admission and complete NAV conformance remain outside the supported claim. A-MPDU, implicit BAR, delayed Block Ack, Multi-TID Block Ack, and complete VHT transfer behavior are also outside this implementation. ## 3. Current source path and evidence limits -These observations use the pinned integration source, which contains S1, R1, and S3a. The [completed prerequisite record](#completed-r1-and-s3a) separates their evidence from proposed Compressed behavior. The [earlier branch record](#branch-verification-record) reports capability and Basic exchange checks before S1. Historical source observations in the lifetime and lifecycle plans still require review against each selected parent. Each remaining behavior repair must reproduce its old failure through production code before its implementation changes that path. - -[HCF](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) already resolves `blockAckVariant` once into private typed state. Basic remains the default. Unknown values and explicit Compressed selection stop initialization, also when Block Ack support is disabled. S3b/A2 must replace the temporary Compressed rejection before its admission checks can run. C2 supplies the complete exchange path; C4 changes the default. - -Management already publishes local, BSS, and peer rates through R1. Its combined MIB operations commit related HT and rate state before notification. C2 must consume these records; A3b must preserve their callback contract. Identical AP reassociation state can produce no rate notification, so association reset requires a separate handoff for both profiles. - -`Hcf` creates the Block Ack procedures when `isBlockAckSupported` is true. [TxOpFs](../../src/inet/linklayer/ieee80211/mac/framesequence/TxOpFs.cc) chooses the BAR sequence. [BlockAckReqBlockAckFs](../../src/inet/linklayer/ieee80211/mac/framesequence/PrimitiveFrameSequences.cc) builds Basic BAR. The Compressed builder in [OriginatorBlockAckProcedure](../../src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckProcedure.cc) throws `Unsupported feature`. - -[Hcf](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) dispatches Basic BAR and Basic Block Ack only. [RecipientBlockAckProcedure](../../src/inet/linklayer/ieee80211/mac/blockack/RecipientBlockAckProcedure.cc) builds only Basic responses. [RecipientQosMacDataService](../../src/inet/linklayer/ieee80211/mac/recipient/RecipientQosMacDataService.cc) also accepts only Basic BAR. S1 removed the unusable Compressed request branch from its reorder service. C2 must add Compressed BAR support through the current recipient owners. - -[Ieee80211Frame.msg](../../src/inet/linklayer/ieee80211/mac/Ieee80211Frame.msg) defines both variants. Its Compressed Block Ack class has no fixed chunk length. Its common BAR and Block Ack bases still name reserved control bit B0 as an ACK policy. [Ieee80211MacHeaderSerializer](../../src/inet/linklayer/ieee80211/mac/Ieee80211MacHeaderSerializer.cc) can write and read Compressed fields, but it still treats variant type 0 as Basic. [RecipientQosAckPolicy](../../src/inet/linklayer/ieee80211/mac/recipient/RecipientQosAckPolicy.cc), [SingleProtectionMechanism](../../src/inet/linklayer/ieee80211/mac/protectionmechanism/SingleProtectionMechanism.cc), and HCF cost a Basic response length. - -[OriginatorQosAckPolicy](../../src/inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.cc) groups outstanding frames by receiver, without TID. [QosAckHandler](../../src/inet/linklayer/ieee80211/mac/originator/QosAckHandler.cc) can mark other peers' frames as awaiting Block Ack after a BAR. It also has a Compressed bitmap reader. The reader does not, by itself, prove that a received response matches the pending BAR. - -[BlockAckRecord](../../src/inet/linklayer/ieee80211/mac/blockack/BlockAckRecord.cc) stores per-fragment reception state. Its getter reports true for an empty map and for absent positions before its earliest retained entry. Neither inference supplies Compressed full-state receipt truth. Each delivery also calls `removeAckStates` through [BlockAckReordering](../../src/inet/linklayer/ieee80211/mac/blockackreordering/BlockAckReordering.cc). That call erases earlier entries independently of scoreboard movement. C2 must separate these Basic operations from Compressed receipt retention. - -[ReceiveBuffer](../../src/inet/linklayer/ieee80211/mac/blockackreordering/ReceiveBuffer.cc) now counts occupied sequence positions from its indexed storage. Fragments of one MSDU count once. Before insertion of newer DATA beyond the window, `BlockAckReordering` advances the window and releases older complete units. It discards incomplete units outside the new window. These S1 operations replace the former fragment capacity limit and out-of-window rejection. - -[InProgressFrames](../../src/inet/linklayer/ieee80211/mac/queue/InProgressFrames.cc) reports an in-progress frame only when that frame can transmit. [HcfFs](../../src/inet/linklayer/ieee80211/mac/framesequence/HcfFs.cc) and `TxOpFs` ask for that DATA candidate before they test whether a BAR is due. [Hcf](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) also uses this test before it requests channel access after a frame sequence. Thus, outstanding Block Ack frames alone cannot start a BAR. With the default threshold of five, a finite burst of four frames also lacks a BAR trigger. - -[BasicMsduAggregationPolicy](../../src/inet/linklayer/ieee80211/mac/aggregation/BasicMsduAggregationPolicy.cc) scans a contiguous prefix from queue index zero. [OriginatorQosMacDataService](../../src/inet/linklayer/ieee80211/mac/originator/OriginatorQosMacDataService.cc) calls that policy before it selects one queued frame. It privately owns `QoSSequenceNumberAssignment`. These paths cannot skip a deferred queue head without a change to extraction order. - -The same data service calls `fragmentIfNeeded` after sequence assignment without an agreement check. C2 will use the prerequisite's agreement-aware extraction path to check the selected peer and TID before that call. HCF supplies the current agreement state; the data service keeps no duplicate agreement store. This check prevents fragmentation before frame construction, rather than a later ACK-policy change. - -[Ieee80211Mib](../../src/inet/linklayer/ieee80211/mib/Ieee80211Mib.h) already owns local HT capability and peer HT state. Management updates that state on association changes. The Block Ack policies do not use it. The current [802.11n protocol test](../../tests/protocol/wifi/11n/N_CompressedBa.test) has a Compressed name, but it expects a Basic Block Ack. [Ieee80211RecipientNav_1.test](../../tests/module/Ieee80211RecipientNav_1.test) checks response NAV behavior with Basic Block Ack. [Ieee80211HcfMultipleProtection_2.test](../../tests/module/Ieee80211HcfMultipleProtection_2.test) checks response duration with synthetic Basic frames. - -The [agreement lifecycle plan](ieee80211-blockack-agreement-lifecycle.md#2-current-source-and-required-evidence) owns the setup, Action, inactivity, and teardown findings. The [lifetime plan](ieee80211-edca-data-lifetime.md#2-current-source-and-standard-support) owns missing lifetime integration and sequence-key collisions. - -The Block Ack-enabled single-protection path in HCF calls `InProgressFrames::getPendingFrameFor` even for BAR. That operation can extract and number DATA. BAR duration needs no successor DATA. - -[BlockAckReordering](../../src/inet/linklayer/ieee80211/mac/blockackreordering/BlockAckReordering.h) now returns complete units through `ReleasedFrames`, an ordered vector of sequence-number and fragment-group pairs. `RecipientQosMacDataService` preserves that order through reassembly, A-MSDU deaggregation, and delivery. A release across sequence wrap therefore delivers 4095 before 0. - -The [DATA reception path](../../src/inet/linklayer/ieee80211/mac/blockackreordering/BlockAckReordering.cc) now releases every consecutive complete unit after DATA fills a gap. The reorder owner creates its record on the first valid related DATA or Basic BAR from the accepted agreement. A Basic BAR before DATA can therefore advance an empty window. The S1 fixture supplies accepted agreements; it does not prove negotiated values or a Compressed exchange. - -The [response-rate method](../../src/inet/linklayer/ieee80211/mac/rateselection/QosRateSelection.cc) accepts only Basic BAR. The originator BAR timeout and recipient response duration both call it. C2 therefore needs Compressed response-rate and duration support before its first production exchange or airtime assessment. C3 cannot supply that prerequisite after C2's required evidence. - -The [IEEE 802.11 fillers](../../tests/serializer/lib/fillers/ChunkFillers_ieee80211.cc) already contain Basic and Compressed BAR and Block Ack producers. The Compressed producers set old ACK-policy fields and nonzero reserved values for field-preserving round trips. C1 must adapt those producers to its reserved-bit contract with the serializer change. [Ieee80211ResponseModeSelection_1.test](../../tests/unit/Ieee80211ResponseModeSelection_1.test) constructs Basic BAR and uses a 152-byte response length. It requires an HT Basic response mode, which Basic retention preserves. Compressed needs additional 32-byte non-HT response cases. - -## 4. Proposed design - -### 4.1 Select the current or historical profile - -HCF already resolves `blockAckVariant` once into a private typed profile value during initialization. The values remain `"compressed"` and `"basic"`; Basic is the current default and Compressed is the final default. Preserve rejection of unknown values. A2 replaces the temporary Compressed rejection; C4 changes the default after runtime verification. The resolved value remains immutable throughout each agreement's lifetime. Both endpoints must select the same profile; this plan supports no runtime profile change. - -HCF owns local profile selection. Merged S3a keeps its typed profile private and exposes no profile query. A2 must pass that value to agreement setup through the smallest interface its actual consumers require. C2 must pass it to frame exchanges and their dependent procedures. Policies, builders, records, protection, and timeouts must not independently read the parameter or infer the profile from PHY mode. The frame context supplies the expected BAR and response variant without a variant registry or second agreement store. - -The serializer independently decodes the actual wire type. It must not consult HCF configuration. Format-specific bitmap and length operations remain necessary, but they consume the decoded frame or resolved exchange context. `isBlockAckSupported` still controls procedure construction. ADDBA gains no variant negotiation field. - -Keep the common BAR and Block Ack bases, both derived variants, and the Basic length constant. Retain existing Basic builders and duration methods for their callers. Add Compressed operations where existing interfaces cannot serve both variants. HCF will supply its resolved profile to the existing policies and procedures. New callers must use the actual request variant for response length and rate selection. - -Type 0 will produce Basic typed frames for historical compatibility. Type 2 will produce Compressed typed frames. Other unsupported types will follow the invalid-frame path. - -- Decode the complete four-bit BAR Type and BA Type fields. -- For Compressed, write zero in reserved control bits. -- For Compressed, ignore received reserved-bit values. -- Preserve the common C++ fields and Basic values that encode Type 0. - -The current nine-bit `reserved` field maps to B3–B11. Its two low bits therefore overlap the expanded Type field at B3 and B4. For Basic serialization, those two bits must be zero. Preserve the other Basic field values and existing round trips within that Type 0 contract. Reject a Basic object that would encode another Type before serialization. The [BAR writer](../../src/inet/linklayer/ieee80211/mac/Ieee80211MacHeaderSerializer.cc) and Block Ack writer both encode `(getReserved() & 0x1FF) << 3`. C1 must verify this layout with direct octet assertions for both frame types. Do not guess a historical layout from frame length or local profile configuration. - -Hypothetical example: a Basic object has `reserved = 1`. The old writer places that value in B3, which a complete four-bit decoder reads as Type 4. C1 rejects that inconsistent Basic object before serialization. - -For this Compressed profile, B0 and B5–B11 are reserved. B3 and B4 remain Type bits, so they cannot use the reserved-bit ignore rule. Compressed ACK-policy and `reserved` model fields have no field-preserving wire contract. C1 sets those fields to zero in the existing Compressed round-trip producers. Separate octet checks verify zero writes and ignored received reserved bits. C1 updates both fixture inventories with its serializer change; C4 adds any remaining coverage. - -The existing Compressed branches in `QosAckHandler` do not establish a production Compressed exchange. - -The MSG generator will regenerate derived C++ files. Do not edit generated files by hand. - -Set the Compressed Block Ack chunk length to 28 bytes. Its fields contain 16 MAC-header bytes, 2 control bytes, 2 starting-sequence bytes, and 8 bitmap bytes. `Ieee80211MacTrailer` supplies the 4-byte FCS, so the transmitted MPDU is 32 bytes. Keep one source for the chunk length. Use the selected PHY mode to calculate airtime. Do not add a second duration cache. - -The Basic response remains 152 bytes with FCS; Compressed remains 32 bytes with FCS. Protection and timeouts must use the request's actual response variant. The Compressed rate rules below must not replace the retained Basic response contract. A received response must match the pending BAR variant before it can report success. - -A profile mismatch cannot silently select Basic or acknowledge DATA through the other variant. ADDBA cannot detect this configuration mismatch. The [lifecycle mismatch contract](ieee80211-blockack-agreement-lifecycle.md#profile-conflict-detection-and-termination) requires HCF to stop the simulation on a valid conflicting BAR for an active agreement. Corrected endpoint profiles require a new run. - -The prerequisite plans own eligibility queries, sequence preview, Action outcomes, lifetime operations, and duplicate-state cleanup. The recipient stage below owns ordered delivery. These changes extend beyond the Basic-specific contracts; each stage requires its own caller and compatibility checks. - -### Migration diagnostics - -After local capability initialization, HCF will log the resolved profile for each interface with Block Ack enabled. If Compressed has no usable local HT support, HCF will emit one initialization warning for that interface. The warning will state the Normal Ack result and the explicit Basic compatibility setting. Basic selection and disabled Block Ack must not produce that warning. - -The local warning cannot detect an HT ad hoc station without peer HT records. The agreement policy's existing decision log must identify a refusal caused by absent local or peer HT state. Use that log to expose the fallback reason without warnings for every DATA frame. Normal association startup and temporary peer-state loss must retain their existing protocol behavior. - -C4's migration fixture will use a user-style configuration outside the legacy override inventory. Supply a queued successor so the production setup policy actually checks eligibility. It will enable Block Ack and omit `blockAckVariant`. Test legacy `g` and `a` modes, plus HT ad hoc management without peer HT records. Require Normal Ack DATA and no ADDBA, BAR, or Block Ack. Check the resolved-profile message, applicable local warning, and policy refusal reason. - -Repeat with explicit Basic at both endpoints and require successful Basic exchanges. Repeat with Block Ack disabled and require no irrelevant warning. Documentation must explain the local warning's limit and the HT ad hoc case. The mode set must not change the selected default. - -### 4.2 Consume the agreement prerequisite - -The [agreement lifecycle plan](ieee80211-blockack-agreement-lifecycle.md#3-agreement-behavior) supplies DATA eligibility and accepted parameters for each peer and TID. HCF must obtain that state before it selects Compressed Block Ack policy. The Compressed builder consumes the current agreement; it cannot restore an agreement that its owner removed. - -Hypothetical example: the lifecycle owner retires the agreement before DATA 101 becomes eligible. The Compressed builder must not use the old agreement to transmit DATA 101. - -The Compressed addition retains the prerequisite's DATA eligibility, Action ownership, and recovery results. It does not add a second agreement store or reproduce the lifecycle state machine. - -HCF will validate a Compressed BAR before it calls `RecipientQosMacDataService::controlFrameReceived`. This profile requires Fragment Number zero and the supported frame length. An invalid BAR will reach neither the reorder service nor the response procedure. Unknown variants and malformed frames follow the invalid-frame path without protocol recovery actions. A well-formed retained BAR for the other profile is a separate conflict case. For a matching active peer/TID, HCF raises the configuration error before scoreboard, reorder, response, or inactivity updates. - -After format validation, HCF will use the absent-agreement path from lifecycle stage A3c. C2 will verify that valid Compressed BAR reaches that path and malformed BAR does not. The lifecycle plan owns DATA disposal, Action ownership, and the resulting teardown state. - -### 4.3 Keep BAR selection and response state exact - -`OriginatorBlockAckAgreement` will own `WinStartO` and `WinSizeO` under Clause 10.25.6.2. A positive accepted ADDBA Response buffer size will set `WinSizeO` to the smaller of that size and 64. The ADDBA Request starting sequence number will initialize `WinStartO`. The first DATA frame under the accepted agreement must use that request sequence number under Clause 10.25.2. - -The [agreement lifecycle plan](ieee80211-blockack-agreement-lifecycle.md#first-data-and-final-transfer) owns expiration before the first DATA transmission and its required teardown. - -The existing originator ACK policy will group outstanding Block Ack frames by peer and TID. It will choose the oldest frame that needs an initial BAR within that agreement's transmit window. The comparison will use modulo-4096 arithmetic. The BAR will carry that starting sequence number and no range length. - -The policy will apply the threshold separately to each peer and TID. It may defer BAR below that threshold only when the next selected DATA belongs to that agreement and fits its window. A candidate for another agreement or management work will not defer that group's BAR. With no DATA candidate, any nonempty eligible group can request BAR below threshold. Before outside-window DATA, the policy will request BAR for older frames with `BLOCK_ACK_NOT_YET_REQUESTED` status. It will transmit older retry-eligible frames before that outside-window candidate. - -If several groups need BAR, the policy will select the group whose oldest outstanding frame entered the in-progress queue first. Peer address and TID will resolve equal-time ties. The policy will derive this order from existing frames without a separate scheduling queue. Hypothetical example: A has four outstanding frames while B supplies continuous DATA in the same access category. Before the next DATA for B, the policy selects BAR for A despite the threshold of five. - -HCF will preview the next eligible candidate before it selects a frame sequence. For a DATA candidate, the originator ACK policy will compare its peer, TID, and sequence number with its agreement window. `HcfFs` and `TxOpFs` will select BAR without extracting DATA. They will also handle a null candidate when only BAR work remains. After older positions resolve, `TxOpFs` will extract and use the DATA candidate. - -`OriginatorBlockAckAgreement` will advance `WinStartO` past contiguous acknowledged or dropped positions before HCF removes their ACK records. This update includes resolved Normal Ack DATA within the agreement's sequence space. When no unresolved frame remains, it may move `WinStartO` to the next unsent sequence number. Clause 10.25.6.7 permits transmission beyond the old window with that advance. This reuses the existing pending queue and adds no duplicate window state in `QosAckHandler`. A BAR after the final short burst needs no new timer. - -After the final exchange, HCF will apply the [lifecycle plan's transfer-completion rule](ieee80211-blockack-agreement-lifecycle.md#first-data-and-final-transfer). The channel-access stage must make that final BAR possible before it enables completion-triggered DELBA. - -HCF will treat an eligible BAR as channel-access work for the correct access category. It will request contention after a frame sequence when only such work remains. The frame sequence will select a BAR with no DATA pointer. The internal-collision path will keep BAR work pending without giving DATA retry feedback. The existing EDCA, TXOP, and protection decisions still control when that BAR can transmit. - -When HCF transmits BAR, `QosAckHandler` will mark only transmitted frames for that BAR's peer and TID as `WAITING_FOR_BLOCK_ACK`. Those frames must have `BLOCK_ACK_NOT_YET_REQUESTED` status and lie within the active agreement window at or above the BAR number. It will leave every other peer and TID unchanged. It will also leave frames outside that window unchanged. Its current per-frame status map will identify the BAR's waiting frames; it needs no second set. - -The frame sequence will build Compressed BAR for the selected peer and TID. Its receive step will match the response type, receiver, transmitter, and TID against the active BAR. Only a matched, format-valid response can reach the success callbacks for recovery, agreement, and ACK-state handlers. The response starting sequence number may differ from the BAR value under Clause 10.25.6.5. HCF will pass the active agreement window to `QosAckHandler` for this response; the handler will keep no window copy. - -Before that success path, the receive step will also require Fragment Number zero, exactly 64 bitmap bits, and the supported frame length. The header chunk is 28 bytes; the MPDU includes the 4-byte FCS. These checks apply to deserialized input and directly supplied typed frames. An unsupported or malformed response cannot update the bitmap, refresh inactivity, or report exchange success. It ends the receive step through the existing failed-BAR path, which releases requested DATA for retry. Hypothetical example: type 2 with a dynamic-fragmentation encoding fails even when its peer and TID match. - -If teardown or peer cleanup ends that agreement during the BAR exchange, HCF will retain the exchange context until completion. A later response or timeout will not access removed agreement state or recreate it. HCF will resolve the current agreement through its owner before it applies bitmap outcomes. This guard covers an actual event boundary and requires no duplicate window state. - -Under Clause 10.25.6.8, `QosAckHandler` will accept positive bits for unacknowledged transmitted frames in that window. This includes covered frames outside the BAR's starting position and frames that did not wait for this BAR. For zero bits, it will keep covered frames unacknowledged. It will make the BAR's covered waiting frames retry eligible. It will not change the acknowledgment state of frames below the response starting sequence number. - -It will clear their wait for this BAR so later retry selection can proceed. A response with no overlap will leave all requested frames unacknowledged and eligible for DATA retransmission. A timeout will do the same. This profile selects DATA retransmission rather than repeated BAR-only polling after a failed exchange. The originator agreement window will advance from resolved frame status, not from the response starting sequence alone. - -Hypothetical example: the transmit window covers sequence numbers 100 through 163, and BAR starts at 104. A valid matched response starts at 100 and has a positive bit for transmitted DATA 102. The handler acknowledges DATA 102 because the received bitmap and transmit window cover it. The BAR's starting number does not exclude that acknowledgment. - -### 4.4 Consume the DATA lifetime prerequisite - -The [EDCA lifetime plan](ieee80211-edca-data-lifetime.md#3-proposed-ownership-and-behavior) supplies the existing DATA deadline to the Compressed consumer. A bitmap result or BAR timeout must not restart that deadline. The lifetime plan owns identity, expiration, and safe completion. - -Individual Block Ack DATA retransmission will preserve its sequence number and set Retry to one under Clause 9.2.4.1.6. Its exception does not include non-A-MPDU frames. Clause 10.23.2.12.1 alone does not establish an optional Retry bit. Zero bitmap bits and BAR timeout will not become synthetic failures in the Normal Ack retry counters. Existing EDCA recovery still owns channel-access effects; the new lifetime integration supplies the missing disposal limit. Internal collisions retain applicable recovery accounting, and no DATA counter will identify frames by TID and sequence alone across different peers. - -Hypothetical example: every Block Ack reports DATA 100 as absent but acknowledges later DATA. Successful responses refresh agreement inactivity, but they cannot extend DATA 100's lifetime. HCF eventually discards 100 and permits window progress. - -The Compressed replacement cannot omit this disposal bound while it retains the proposed retransmission behavior. - -### 4.5 Build recipient state and select response airtime - -`BlockAckRecord` will own the full-state scoreboard window for each accepted agreement. At establishment, it will set `WinStartR` from the ADDBA request. It will set `WinSizeR` to the accepted response buffer size, which this profile caps at 64. It will derive `WinEndR` from those values. - -The existing reorder buffer will use that same accepted size. For each valid related DATA frame, the scoreboard will apply Clause 10.25.6.3 before reorder insertion or duplicate rejection. This update applies regardless of that DATA frame's ACK policy. - -Retain the Basic record's fragment status. The Compressed response will derive one complete-unit receipt bit per sequence position from the same agreement-owned record. Unfragmented DATA supplies a complete MSDU or A-MSDU in that profile. A partial Basic unit cannot become a positive Compressed bit. A received Compressed BAR will advance the scoreboard under Clause 10.25.6.3, with modulo-4096 comparisons. - -Compressed receipt status remains after delivery. Scoreboard movement controls its retirement; reorder delivery must not call the Basic deletion operation for that profile. Preserve the receipt evidence at `WinStartR - 1` for the individual-MPDU delivery condition below, even outside the response window. That evidence cannot set response bits outside `WinStartR` through `WinEndR`. An empty record has no positive bit. Retain the Basic fragment representation and its existing operations. - -At C2, HCF will reject fragmented DATA for an active Compressed agreement before scoreboard or reorder processing. Nonzero Fragment Number or More Fragments set identifies that input. HCF will use the invalid-frame path without agreement recovery actions. Such input cannot allocate fragment receipt state, produce a positive bitmap bit, or cause DATA delivery. Basic agreements retain fragment receipt state and reassembly after C2 and C4. Ordinary Normal Ack reassembly outside an agreement retains its existing owner. - -The response will use the adjusted `WinStartR` as its starting sequence number. Bits beyond `WinEndR` will be zero. - -`BlockAckReordering` owns delivery order and `WinStartB`. S1 makes `WinSizeB` count MSDU or A-MSDU sequence positions. Basic `ReceiveBuffer` retains multiple fragments at one position, which counts once against the supplied agreement size. A fragment that completes that unit remains eligible when its position occupies the last available window slot. For newer DATA beyond `WinEndB`, the reorder owner moves the window, retains the new DATA, and releases eligible older complete units. C2 will reuse these operations for the Compressed profile under Clause 10.25.6.6 and retain Basic fragment behavior. - -S1 releases every consecutive complete unit from `WinStartB` when DATA fills a gap. It stops at the next absent or incomplete unit. The reorder owner advances the window after the last released unit without a later DATA reception or BAR. Its selected rule follows Clause 10.25.6.6.2.1(a)(2), with Basic retention as an INET compatibility choice. The S1 fixture buffers complete DATA 101 and 102 behind absent DATA 100. Receipt of DATA 100 releases 100, 101, and 102 in that order in the same operation. - -C2 must implement Clause 10.25.6.6.2.1(a)(2)(v) with its surrounding conditions for the supported individual-MPDU path. The received DATA must belong to an HT-immediate agreement without segmentation and reassembly. The station must be non-EDMG. - -RIFS means reduced interframe space. The sequence number must lie inside the reorder window and exceed `WinStartB`. The receipt bit at `WinStartR - 1` must be positive. The MPDU must follow the preceding MPDU by SIFS or RIFS, or follow ACK transmission by SIFS. - -When these conditions hold, the recipient must apply the clause's sequential delivery and window-update rules despite the gap. If either receipt evidence or the interframe relation is absent, this condition does not permit release. Another applicable release rule can still permit delivery. C2 must not omit this behavior or make it optional merely to avoid event history. - -The reorder owner releases eligible units in cyclic order under that clause. It continues sequentially until the next sequence position has no buffered unit. It advances `WinStartB` after the last released unit. The A-MPDU exclusion does not exclude this individual-MPDU condition. The originator retains its current SIFS frame sequences. - -HCF supplies the actual interframe relation to the reorder operation. The [receiver](../../src/inet/physicallayer/wireless/common/base/packetlevel/ReceiverBase.cc) supplies reception start and end times through `SignalTimeInd`. HCF receives ACK completion through its current transmission callback. The [mode interface](../../src/inet/physicallayer/wireless/ieee80211/mode/IIeee80211Mode.h) supplies the applicable SIFS and RIFS intervals. Those receive and completion paths retain no previous-MPDU or ACK history for this decision. C2 retains only that required event history in HCF. - -### Interframe history and timing design - -The individual-MPDU release rule adds behavior to Compressed reception. It can change delivery times and fingerprints when its conditions hold. Basic retains S1's delivery rules. A changed Basic fingerprint requires its own causal evidence; the Compressed release rule does not justify that change. - -As part of C2, its owner must derive the history and timing contract against the selected source parent. The existing callbacks identify possible inputs, but they do not establish a complete contract. Record the implementation design and its source and standards evidence: - -- Derive the qualifying previous reception or ACK transmission from the complete standard procedure. Do not impose extra same-peer, address, or TID restrictions without a standards basis. -- Specify the minimal stored timestamps and validity fields. Retain values rather than frame pointers beyond their ownership lifetime. -- Define which intervening receptions and transmissions replace or invalidate history, including unrelated traffic and failed reception. -- Clear relevant validity on agreement retirement, peer cleanup, and replacement setup. Establish invalid history at initialization; add no stop/start support claim. -- Define when HCF evaluates the current frame against previous history and when it replaces that history. Preserve the evidence needed by reorder processing. - -A per-peer last-frame timestamp alone cannot establish the immediately preceding event. An intervening frame from another peer can break the relation. The production trace must establish how HCF observes such events before the owner selects its storage layout. Do not add a history registry or new timer without a demonstrated need. - -Define the receive-side interval from previous reception end to current reception start. Define the ACK-side interval from local ACK transmission end to current reception start. `SignalTimeInd` supplies receive endpoints; the transmission callback supplies local completion. Current-frame delivery time is not its reception start. - -For a stationary sender, equal propagation delays can cancel between successive receptions. After local ACK transmission, the next DATA reception can include outward and return propagation delay. Therefore, raw equality to SIFS is not a complete rule for both paths. Map the applicable PHY timing definitions to INET timestamps, including signal extension and propagation effects. Record time resolution, supported coverage assumptions, and the applicable RIFS operation conditions. - -An available RIFS duration alone does not establish permission to transmit RIFS-separated frames. - -Clauses 10.3.2.3.2 and 10.3.2.3.3 define RIFS and SIFS timing; Clause 10.22.5 defines coverage-class behavior. These clauses constrain the implementation; they do not make timing tolerance a maintainer preference. A proposed receiver-side recognition interval must have a documented derivation from those rules and the model. No inferred interval or arbitrary epsilon is accepted by this plan update. - -The exact timestamp mapping, event observation coverage, and stored fields still need source analysis and design. The C2 owner must resolve and review them before the affected implementation is complete. These are engineering obligations within the required behavior, not new policy decisions or grounds to omit the clause. Independent R1 work remains unaffected. Tests must cover nonzero propagation delay, intervals outside the permitted relation, and intervening unrelated frames. - -If existing PHY observations cannot establish the required timing relation, the C2 owner must record the specific gap and a concrete example. The owner must propose the smallest correction to the observations or their interpretation. The code reviewer must check that proposal against the standard and the supported PHY model. Missing callback data alone does not establish that the required behavior cannot be modeled. - -If the correction requires a model approximation or reduced scope, the maintainer must approve an explicit plan revision before its implementation. The revision must state the changed behavior, evidence, and compliance limits. Approval does not make an approximation equivalent to strict compliance. Until resolution, the affected C2 path remains incomplete and cannot be published. Independent work that neither exposes nor depends on that path may continue. - -Local experimental code may support the design investigation. The affected Compressed release path must not enter a published implementation until its design review and direct verification pass. This publication boundary requires no runtime switch to disable an unfinished rule. These provisions add no implementation or publication authorization to this document-only update. - -HCF passes the interframe result with the frame. It adds no timer, scheduler, or simulation event for this relation. The agreement-owned scoreboard supplies the bit at `WinStartR - 1` before window cleanup can erase it. The reorder owner consumes that bit with the interframe result. A false receipt bit or absent interframe relation leaves an in-window gap buffered under the ordinary rule. The two conditions remain independent. - -Hypothetical example: an accepted agreement starts at 100 with buffer size four. The recipient receives and delivers Normal Ack DATA 100, then sends ACK. Its reorder start becomes 101. In this zero-propagation example, DATA 104 reception starts one SIFS after local ACK transmission ends. The scoreboard start becomes 101. Receipt evidence for 100 satisfies condition (v), so the recipient delivers 104 despite absent positions 101–103. Without that evidence or SIFS relation, it retains 104 until another applicable release condition occurs. - -S1 returns released units as an ordered sequence of fragment groups through `ReleasedFrames`. Its traversal uses modulo-4096 order relative to the old reorder window. `RecipientQosMacDataService` preserves that order through defragmentation, A-MSDU deaggregation, and delivery. The receive buffer retains its indexed storage. External callers must consume the supplied order, as the [migration guide](../../doc/src/migration-guide/index.rst) requires. C2 will preserve this contract for Compressed reception, with constituent MSDUs in order within each A-MSDU. - -S1 discards incomplete units outside the new window. Its Basic BAR path applies the selected reorder rule from Clause 10.25.6.6.3.1, also before DATA reception. `BlockAckReordering` initializes the record from the accepted agreement before it applies that frame's window update. A valid Basic BAR can advance an empty reorder window, whose new start remains available for later DATA. C2 will add validated Compressed BAR input to this current path. - -Hypothetical example: the accepted request starts at 100 with buffer size eight, but the recipient receives no DATA. A valid BAR at 104 creates the reorder record and moves its start to 104. Subsequent DATA 104 is eligible for immediate delivery. Invalid BAR and BAR without an agreement create no reorder record. The reorder window will not depend on the scoreboard's `WinStartR`; the two owners track different state. Do not add another scoreboard store or a duplicate reorder buffer. - -This profile will send the Compressed Block Ack response in a non-HT PPDU. `QosRateSelection` will use the BAR rate for a non-HT BAR. It will use the non-HT reference rate for an HT or VHT BAR. It will select the highest qualifying BSS basic rate at or below that value. If none qualifies, it will select the highest qualifying mandatory PHY rate. The MIB supplies rate-set storage, and `IIeee80211Mode` supplies the reference rate. - -For a non-HT BAR, the response will use the BAR's modulation class and preamble type. For an HT or VHT BAR, it will use the OFDM or ERP-OFDM modulation class. Rate candidates must satisfy that modulation rule. A configured response-rate override must select the primary rate or a legal alternate under Clause 10.6.6.5.4. An alternate must use the same modulation class, satisfy the basic or mandatory rate rule, and preserve response duration. `QosRateSelection` will reject an invalid override with a clear configuration error before response transmission. - -Originated Compressed BAR will use a non-HT PPDU as a fixed INET profile choice. This choice permits legal BAR transmission without new VHT capability negotiation or protected HT/VHT mode selection. `QosRateSelection` will select the highest eligible local legacy mode under the rules below. Other control frames retain their existing mode contract. A valid received HT or VHT BAR remains supported through the response rules above. - -- When BAR initiates a TXOP, Clause 10.6.6.2 requires a BSS basic rate. If that set is empty, the selected rate must be mandatory for the attached PHY. -- For a later BAR, Clause 10.6.6.4 requires a rate from the peer's known operational rate set. If that set is unknown, use a BSS basic rate, or a mandatory rate when the basic-rate set is empty. -- Mode candidates must belong to the local legacy operational set. When BSS rate state is unknown, mandatory-rate selection is the documented INET fallback. A configured `controlFrameBitrate` must satisfy the same BAR conditions; otherwise `QosRateSelection` rejects that BAR before transmission. - -At the pinned revision, [MIB rate sets](../../src/inet/linklayer/ieee80211/mib/Ieee80211Mib.h) supply storage and accessors, but no production caller populates them. The [rate-set type](../../src/inet/linklayer/ieee80211/mib/Ieee80211RateSet.h) defaults to unknown state. [Management](../../src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtBase.cc) constructs Supported Rates elements without publication to the MIB. Ordinary association therefore does not supply the rate knowledge required here. Direct MIB injection verifies consumer logic, not production publication. - -The separate [R1 stage](#r1-publish-production-rate-state) will populate the existing MIB records from advertised or accepted rate information. R1 owns full and simplified management, Beacon refresh, cleanup, and publication tests. C2 consumes the completed rate contract before its first exchange. It will repeat the subscriber interaction after S3b installs HCF's lifecycle callback. - -Rate-only publication must preserve unchanged agreements in either profile. Missing HT state must not retire Basic compatibility. R1 creates no new rate store, parameter, or negotiation mechanism. - -The current [TXOP initiator predicate](../../src/inet/linklayer/ieee80211/mac/originator/TxopProcedure.cc) always returns false. [QosRateSelection](../../src/inet/linklayer/ieee80211/mac/rateselection/QosRateSelection.cc) uses that predicate to distinguish initial and later control frames. C2 cannot reuse that result for Compressed BAR classification. [HCF](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) already has the frame-sequence context before mode selection. HCF will derive whether this BAR starts the TXOP from actual frame-sequence progress. `QosRateSelection` will receive that BAR-specific condition through the mode-selection call path. - -A BAR after fresh channel access will use the initial-BAR rule. A BAR after an earlier transmission in the same TXOP will use the later-BAR rule. This change preserves other control-frame decisions and adds no retained classification flag. The mode catalog supplies eligible local modes and mandatory-rate status. - -Hypothetical example: BSS basic rates are 6, 12, and 24 Mbps, while the peer also supports 54 Mbps. The initial Compressed BAR uses the eligible 24 Mbps non-HT mode. A later BAR can use the eligible 54 Mbps mode. Production checks must establish both rate publication and BAR position before they compare these selected modes. - -When no basic rate qualifies, Clause 10.6.6.5.2 supplies the applicable mandatory-rate rule. If the BSS basic-rate set is unknown, mandatory-rate selection is an explicit INET fallback. The response Duration/ID will use Clause 9.2.5.6 and actual Compressed airtime. The single and multiple protection paths will use the new frame length without new TXOP admission policy. - -R1 supplies committed production rates. C2 supplies BAR classification, response-rate rules, override checks, and Compressed airtime calculations before its first exchange. Its BAR timeout, recipient Duration/ID, and protection paths will all use the supported Compressed response mode and MPDU length. C2 will record the selected mode with its first timing result. C3 will add focused verification across response modes and exchange boundaries; it supplies no missing runtime operation required by C2. - -For BAR, HCF will bypass `getPendingFrameFor` and use the BAR duration operation in `SingleProtectionMechanism`. It needs only the selected BAR, SIFS, and that variant's actual response airtime. It will receive no successor DATA and perform no extraction. Other duration paths retain their existing scope. Hypothetical example: peer A needs BAR while peer B has queued DATA. Both BAR selection and its duration calculation leave B's queue ownership and sequence counter unchanged. - -## 5. Separate changes and dependencies - -### Maintainer decisions - -The maintainer accepted all five decisions on 14 October 2026. Their decision conditions are satisfied; source reviews, stage prerequisites, and verification remain required. S1 recipient repair and R1 rate publication retain independent review and publication boundaries. - -| Decision | Status and recorded result | Dependent boundary | -| --- | --- | --- | -| Lifetime compatibility | The maintainer accepted the 0.512-second default on 14 October 2026. It applies to QoS DATA with Block Ack enabled or disabled. The [lifetime record](ieee80211-edca-data-lifetime.md#lifetime-compatibility-decision) states the compatibility effect and required measurements. | The decision condition for S2/L1 is satisfied. | -| Response timeout | The maintainer accepted a positive, finite 100 ms default on 14 October 2026. The [lifecycle contract](ieee80211-blockack-agreement-lifecycle.md#response-timeout-and-data-lifetime) defines its start, recovery, and DATA-lifetime interaction. | The decision condition for A4 is satisfied. | -| Transfer completion | The maintainer accepted the [queue predicate](ieee80211-blockack-agreement-lifecycle.md#transfer-completion-decision) on 14 October 2026. At an exchange boundary, the agreement has no queued DATA, in-progress DATA, or pending BAR exchange. Conditional DELBA remains required. | The decision condition for A5 in S4 is satisfied. | -| Individual-DATA purpose | The maintainer accepted the [intermediate profile](#purpose-of-the-individual-data-profile) on 14 October 2026. Its purpose is bitmap, response, and recovery studies with individual DATA before explicit BAR. Complete HT-immediate transfer remains outside that scope. | The scope decision before C2 is satisfied. | -| Persistent profile conflict | The maintainer accepted a fatal configuration error on 14 October 2026. The [conflict contract](ieee80211-blockack-agreement-lifecycle.md#profile-conflict-detection-and-termination) requires termination before state updates and a new run with corrected profiles. | The decision condition for C2 mismatch implementation is satisfied. | - -### Stage conditions - -The table separates conditions for stage start, continuation, completion, and publication. Each condition blocks only its dependent work. Review of this umbrella plan does not establish either prerequisite plan's correctness or completed verification. - -| Boundary | Responsible owner and required condition | -| --- | --- | -| Before each stage starts. | The stage owner pins the source parent and comparison base under the source-base rules below. | -| Before S2 implementation. | The lifetime reviewer completes the separate [lifetime review](ieee80211-edca-data-lifetime.md). The accepted default is 0.512 seconds; its compatibility decision is satisfied. Before the production change, the implementation owner reproduces absent queue expiration through HCF. | -| Before S2 completes. | The lifetime owner supplies [measured expiry under controlled congestion](ieee80211-edca-data-lifetime.md#5-verification-and-evidence), including a Block Ack-disabled case. A selected regression row without expiry cannot satisfy this condition. | -| S3a preparation. | S3a is merged. Preserve its recorded parent comparison and explicit Basic consumers. Repeat affected checks after shared changes. | -| Before S3b implementation, including A1. | The lifecycle reviewer completes the separate [lifecycle review](ieee80211-blockack-agreement-lifecycle.md). Select a parent that contains merged S3a and R1. Refresh selector, MIB commit, reset, and callback paths against that parent. | -| Before A3b implementation. | Refresh the [consumer assessment](ieee80211-blockack-agreement-lifecycle.md#reassociation-consumers-and-callback-order). Trace Compressed HT removal and replacement. Trace Basic association-reset notifications with the actual peer key. | -| Before A4 implementation. | The lifecycle review checks the [accepted 100 ms timeout](ieee80211-blockack-agreement-lifecycle.md#response-timeout-and-data-lifetime) against the selected source parent. The implementation owner completes S2, A1, A2, and A3a through A3c. | -| Before S4 starts. | The S4 owner confirms that S3b supplies the required teardown behavior and S1 supplies recipient progress. A5 uses the accepted transfer-completion predicate; its decision condition is satisfied. | -| Before S4 completes or its affected Basic path is published. | The S4 owner compares changed BAR timing with S4's pinned parent. Resolve any new unlawful overrun under [Section 6](#airtime-acceptance-and-admission-dependencies) before that publication. This condition requires no future C2 or C3 result. | -| Before S5 starts. | The implementation owners complete the prerequisite contracts from S1 through S4. C2 evidence is produced within S5, so it is not a start condition. | -| R1 publication prerequisite. | R1 is merged. Its [evidence record](../../doc/project/evidence/model/wifi/r1-rate-publication.md) owns the parent comparisons. C2 must repeat notification checks with S3b's subscriber. | -| Before C2 implementation. | C2 uses the accepted individual-DATA purpose and scope. Complete HT-immediate transfer requires a separate A-MPDU design. Other C2 prerequisites retain their stated boundaries. The accepted fatal profile-conflict policy applies. | -| Before C2 individual-MPDU release is complete. | Implement the required clause. Resolve and review its [history and timing design](#interframe-history-and-timing-design) against the actual parent. Verify each condition through production reception without extra unsupported restrictions. | -| Before the C2 individual-MPDU release path is published. | The code reviewer accepts the history and timing design, and direct verification passes. Resolve any observation gap through the [escalation rule](#interframe-history-and-timing-design). A model approximation or reduced scope requires an explicit maintainer-approved plan revision. | -| Before C2 mismatch validation implementation. | Apply the accepted [fatal conflict policy](ieee80211-blockack-agreement-lifecycle.md#profile-conflict-detection-and-termination). Trace production BAR validation before state updates. Require exact diagnostic and compatible-run controls before publication. | -| Before C2's first production exchange or timing assessment. | R1 supplies committed local, BSS, and peer rates. Repeat publication callbacks with S3b's subscriber. HCF supplies actual BAR position. C2 supplies legal modes, timeouts, durations, and protection airtime. | -| Before C4 completes. | The migration fixture proves the default, warning limits, capability-gap fallback, and explicit Basic recovery for external-style configurations. | -| Before C3 or C4 proceeds. | The C2 owner records the first airtime result with its selected response mode and resulting admission decision under [Section 6](#6-verification-and-scope-limits). | -| Before S5 completes or the affected Compressed path is published. | The Compressed owner satisfies Section 6's final airtime conditions, including C3's checks for response modes and any required admission correction. | - -C2 belongs to S5. A new overrun outside Clause 10.23.2.9's permitted cases can require an admission correction before publication of the affected path. A permitted overrun requires its condition-specific evidence, not an admission correction. C3 repeats the assessment across supported response modes and exchange boundaries. The [airtime decision](#6-verification-and-scope-limits) controls continuation and completion; it does not require C2 results before S5 starts. - -### Source base and publication boundaries - -Local master at `633b071e213b825ce6019ff3e344ae49f52791ff` contains S1, R1, S3a, and the VHT/HT prerequisite from PR #1318. S1 merged through PR #1320 on 14 October 2026. Its original feature-series publication base is `ac6344cc5bcac972012759281a11b3f8255b5d46`. Original feature heads and comparison bases remain historical verification boundaries. Each remaining stage must pin its actual source parent and comparison base from the merged integration source. - -The lifetime and lifecycle plans retain their separately pinned `b06e8768` source observations. Before each prerequisite starts, its owner must refresh its source observations and caller assessment against the selected stage parent. This umbrella review does not replace either prerequisite's review. The decision table records accepted policy choices; stage reviews and verification remain required. - -S2 and S3b must refresh their prerequisite source observations against their actual selected parents. Those parents must include merged R1 and S3a; the refresh must not remain fixed to `1cdb362a`. Existing local S2 implementation does not establish merged S2 status or authorize a history change. - -A move to another base requires a fresh caller and test assessment. Shared paths identify overlap; they do not by themselves prove a merge conflict. This plan does not authorize branch mutation or publication. - -Each stage below has its own direct tests and regression evidence. Basic support remains available in every stage and in the final implementation. No prerequisite change claims completed Compressed support. - -The [stage conditions](#stage-conditions) define the remaining design, implementation, and verification obligations. - -### Implementation stages - -| Stage and purpose | Responsible components and change | Result and direct verification | -| --- | --- | --- | -| S1. Merged in PR #1320. | `ReceiveBuffer`, `BlockAckReordering`, and `RecipientQosMacDataService` count sequence positions and release complete groups in cyclic order. Valid Basic BAR creates a record before DATA. | Original-head verification passes eight recipient scenarios, three NAV runs, and 12 selected fingerprints. The [S1 record](#completed-s1-and-recorded-verification) states the supplied-agreement scope and approved baseline changes. | -| S2. Establish DATA lifetime. | Implement the [separate EDCA lifetime plan](ieee80211-edca-data-lifetime.md). Its owner supplies deadlines independently of Block Ack support. | Normal Ack DATA expires under either switch value. Identity transfer and accepted-exchange completion preserve ownership. | -| S3a. Merged. | HCF validates the selector with Basic as the temporary default. Legacy demonstrations and twelve existing fixtures select Basic explicitly. | The [S3a record](../done/ieee80211-compressed-blockack-s3a.md) reports direct Basic exchange and capability comparisons. Compressed selection still stops initialization. | -| S3b. Repair agreement lifecycle. | Implement A1, A2, A3a through A3c, and A4 of the [separate lifecycle plan](ieee80211-blockack-agreement-lifecycle.md#5-reviewable-stages-and-dependencies). A2 distinguishes Basic compatibility from the Compressed HT requirement. Retain Basic fixtures and add focused Compressed admission checks. | Legacy ad hoc and non-HT consumers retain Basic. Compressed admission requires valid HT state; its capability-gap cases use Normal Ack. Shared lifecycle tests cover both profiles. | -| S4. Complete BAR work independently of DATA selection. | The originator policy, ACK handler, agreement window, HCF, and frame sequences isolate peer/TID state. They permit BAR-only contention without DATA extraction. Connect lifecycle stage A5. | One or four outstanding frames cause BAR below the default threshold of five. Another peer cannot suppress this work. Final completion causes DELBA. Compare changed Basic BAR timing with S4's parent before publication. | -| R1. Merged. | Full and simplified management commit local, BSS, and peer rates through the MIB. Combined operations commit related state before notification. | The [R1 record](../../doc/project/evidence/model/wifi/r1-rate-publication.md) reports publication, refresh, cleanup, and malformed-input checks. C2 later consumes these records and repeats subscriber checks. | -| S5. Add Compressed and activate its default. | Frame definitions, serializer, procedures, recipient scoreboard, response matching, rate selection, and protection support both profiles. C4 changes the default only after C2 and C3 pass. | Compressed exchanges pass direct bitmap, rate, and timing checks. Explicit Basic still supports type 0, fragment bitmaps, existing consumers, and its response contract. | - -S1, R1, and S3a are complete in the integration source. The remaining stages are S2, S3b, S4, and S5. A1, A2, and A3a through A3c can proceed without S2; A4 requires S2. Completed stages retain their separate parent comparisons. R1 satisfies the rate-publication prerequisite, but C2 still requires subscriber integration and legal rate consumption. - -S1's direct tests supply an agreement with a known buffer size through the existing Basic path. S3b later verifies that negotiation supplies the correct size to that repaired recipient. Lifecycle stage A4 depends on S2; A1, A2, and A3a through A3c need not wait for S2. S4 depends on S3b teardown and S1 recipient progress. - -The lifecycle plan owns the [A3 review split and publication conditions](ieee80211-blockack-agreement-lifecycle.md#5-reviewable-stages-and-dependencies). A3a covers directional teardown and inactivity; A3b covers association reset; A3c completes Action disposal and absent-agreement recovery. Required Action invalidation and safe completion accompany the first retirement or reset path that uses them. The split does not authorize an unsafe intermediate publication. - -S3a already precedes S3b in the integration source. S3b must use a parent that contains both S3a and R1. Preserve S3a's original parent comparison. Attribute later lifecycle effects to S3b. The final Compressed default takes effect at C4, after the runtime path and timing checks exist. +HCF owns coordination. The originator and recipient agreement handlers own role-specific state by peer and TID. The QoS data service selects DATA in queue service order. `InProgressFrames` holds extracted frames and exposes borrowed preview before extraction. -S5 depends on the completed prerequisite contracts. C1 changes wire definitions without a new rate-publication stage. C2 consumes merged R1 and repeats its interaction with S3b. S1's and R1's recorded parent comparisons remain separate from S4's future comparison. Unresolved C2 or C4 work does not reopen completed stages. +The ACK policy groups outstanding DATA by peer and TID within each accepted transmit window. HCF can request channel access for a due BAR without another DATA candidate. A matched response resolves the selected group. The agreement object owns cyclic sequence distance, bitmap membership, and transmit-window advancement. -### Completed R1 and S3a +Hypothetical example: the accepted window contains one sequence position and the BAR threshold is five. One outstanding DATA frame fills that window. The next candidate lies outside it, so HCF selects BAR despite the threshold. A positive response removes the acknowledged DATA and permits window progress. If no DATA remains at the safe exchange boundary, HCF starts completion DELBA. -R1 spans commits `c1973f443e` through `b385562353`. It adds combined MIB commits, production publication, membership-selector checks, and nonfinite-rate rejection. The [R1 evidence record](../../doc/project/evidence/model/wifi/r1-rate-publication.md) preserves its original source boundaries, commands, failures, and corrected results. Its final broad verification reports 46 runs; a later focused correction adds nonfinite-input checks. These recorded results do not establish a new combined-master pass. - -S3a spans `4e6aa75c99` and `633b071e21`. Its [execution record](../done/ieee80211-compressed-blockack-s3a.md) reports thirteen demonstration comparisons, eight capability probes, and nineteen fingerprint rows. Every calculated fingerprint ingredient equals its parent. Fifteen rows retain graphical `tyf` baseline mismatches, so the fingerprint runner exits 1. Four protocol fixtures retain expected FAIL results with unchanged causes. S3a changes no recorded baseline and proves no Compressed exchange. - -The inventories below remain preservation requirements for later stages. They describe the original S3a consumer set, not every fixture now present. Preserve the new selector, Basic observation, and R1 fixtures as additional controls. The original evidence belongs to its recorded feature source; this plan review runs no simulations. - -S1 changes recipient delivery, not the Compressed bitmap representation. S4 preserves Basic fragment rules; S5 retains those rules beside the Compressed restriction. Neither stage may claim a Compressed exchange solely because a helper handles a Compressed class. - -### S3a: demonstration migration and fallback inventory - -Merged S3a preserves the existing Basic demonstrations through explicit profile selection. The [Block Ack network](../../showcases/wireless/blockack/BlockAckShowcase.ned) and [TXOP network](../../showcases/wireless/txop/TxopShowcase.ned) retain their two ad hoc hosts. Later stages must retain this configuration scope. The plan requires no AP, Ethernet link, channel migration, or new association interval in either showcase. - -The current ad hoc management does not install peer HT records. That limitation prevents the Compressed HT profile, but it will not disable explicit Basic compatibility. The Basic profile preserves INET's existing capability assumptions. Its use with later PHY modes does not establish complete IEEE Std 802.11e-2005 conformance. - -Preserve S3a's explicit Basic assignment in each legacy configuration's existing scope: - -```ini -*.host*.wlan[*].mac.hcf.blockAckVariant = "basic" -``` - -Use the actual node patterns below for networks without `host*` names. HCF already validates the selector. Its temporary default remains Basic until C4 activates the completed Compressed implementation. A2 must revise the temporary rejection of Compressed, including the selector fixture's expected diagnostic. A2 must prevent an admitted setup from reaching the unsupported builder before C2 supplies that path. - -| Configuration and source | Retained behavior | Basic selection to preserve | -| --- | --- | --- | -| Block Ack [General](../../showcases/wireless/blockack/omnetpp.ini), `NoFragmentation`, `MixedTraffic`, and `Fragmentation` | Existing ad hoc topology, modes, radio settings, traffic, and fragment demonstration. | Select Basic on both hosts in General. All named configurations inherit it. | -| TXOP [General](../../showcases/wireless/txop/omnetpp.ini) | Existing ad hoc topology and `n(mixed-2.4Ghz)`; mixed Block Ack, Normal Ack, A-MSDU, and RTS/CTS exchanges. | Select Basic on both hosts. Retain thresholds and application settings. | -| Wireless QoS [MacQosWithBlockAck](../../examples/wireless/qos/omnetpp.ini) | Existing AP, two stations, two wireless hops, and inherited `g(mixed)`. | Select Basic on all participating interfaces in this configuration only. Do not change other configurations. | -| Ad hoc QoS [MacQos](../../examples/adhoc/qos/omnetpp.ini), runs 0 and 1 | Existing topology, `g(mixed)`, and support parameter loop. Run 1 retains Basic; run 0 remains support-disabled. | Select Basic on both hosts without a new parameter loop. | -| Fragmentation [HCFfragblockack](../../showcases/wireless/fragmentation/omnetpp.ini) | Existing Basic fragment exchange and comparison with the other fragmentation cases. | Select Basic for the participating interfaces in this configuration. | -| Fragmentation [parameterstudy.ini](../../showcases/wireless/fragmentation/parameterstudy.ini) | All four Block Ack variants and their existing parameter sweeps. | Select Basic within the shared Block Ack configuration scope or each named variant, according to inheritance. | - -Retain `PacketSizeHCFfragblockack`, `TxPowerHCFfragblockack`, `ThresholdHCFfragblockack`, and `OnlyPacketSizeHCFfragblockack`. Retain their names, result filters, analysis inputs, plot series, fingerprint rows, and speed records. - -S3a's completed migration covers six INI files and the ad hoc `${false, true}` parameter loop. Check effective INI inheritance before a later change to these assignments. Search tracked `tests/**/*.test` sources and shared includes separately. Generated files under `work/` do not replace those sources. - -For each legacy demonstration, require accepted ADDBA, Block Ack-policy DATA, Basic BAR, and a Basic response with positive receipt status. Check fragment status in the fragmentation cases. Record peer addresses and TIDs for every measured wireless hop. No peer HT record is required for Basic eligibility. - -Repeat those assertions after A2 and at final S5. A fingerprint match without a Basic exchange cannot establish preservation. Check the support-disabled ad hoc run separately. Add a focused Compressed ad hoc case with absent peer HT state. That case requires Normal Ack without ADDBA, BAR, or Block Ack. - -Preserve S3a's historical Basic explanation in the [Block Ack page](../../showcases/wireless/blockack/doc/index.rst), [TXOP page](../../showcases/wireless/txop/doc/index.rst), and [fragmentation page](../../showcases/wireless/fragmentation/doc/index.rst). State that Basic originated in IEEE Std 802.11e-2005 and is unsupported by IEEE Std 802.11-2024. Link to Section 2's historical and current-standard sources. Retain this distinction in affected QoS example descriptions and the parameter-study explanation. - -Preserve existing images and plots when the evidence still supports them. Shared recipient, lifetime, and lifecycle repairs can change results despite unchanged topology and traffic. Regenerate only affected evidence after a measured change. Keep prior measurements as historical evidence; do not claim unchanged fingerprints or current performance without verification. - -Existing infrastructure protocol fixtures will supply Compressed coverage through actual AP/STA capability exchange. This plan needs no showcase topology conversion or new IBSS capability implementation. - -### S3a: tracked fixture inventory and VHT scope - -S3a's recorded inventory covers tracked INI files, conditional assignments, included configuration files, and direct Basic consumers. Its original migration set contains twelve fixtures: eight protocol fixtures and four module fixtures. Five further module fixtures explicitly disable support. The separate S1 recipient fixture supplies accepted Basic agreements without an HCF enablement assignment. The response-mode unit fixture and serializer fixture also consume Basic types without that assignment. Later verification must include S3a's new selector and Basic observation fixtures in addition to this original set. - -The existing protocol fixtures include [_n.ini](../../tests/protocol/wifi/ini/_n.ini) or [_ac.ini](../../tests/protocol/wifi/ini/_ac.ini), followed by shared [_base.ini](../../tests/protocol/wifi/ini/_base.ini). Their [infrastructure network](../../tests/protocol/wifi/ned/WifiInfraNetwork.ned) uses full AP/STA management. The HT configuration selects `n(mixed-2.4Ghz)`; the VHT configuration selects `ac`. Association alone therefore does not prove that either endpoint has usable HT state. - -The [mode catalog](../../src/inet/physicallayer/wireless/ieee80211/mode/Ieee80211ModeSet.cc) appends 128 existing HT combinations to `ac` and enables its HT-support flag. These HT modes use 5 GHz timing. [Ieee80211Mib](../../src/inet/linklayer/ieee80211/mib/Ieee80211Mib.cc) derives local capabilities from that catalog and operational limits. The [HT mode-set fixture](../../tests/unit/Ieee80211HtModeSet_1.test) requires `ac` to report HT operation. The [VHT/HT production fixture](../../tests/module/Ieee80211VhtHtSupport_1.test) checks peer HT state after association. Clause 4.3.15 defines a VHT STA as an HT STA with additional VHT features. - -The [S3a record](../done/ieee80211-compressed-blockack-s3a.md) records actual modes, local HT flags, peer HT state, and pre-A2 outcomes. S3b/A2 must retain Basic compatibility and check Compressed admission with real HT state. Before C2, admission fixtures do not claim a production Compressed exchange. C2 and C4 must retain the original `Ac_BlockAck` requirement with matched Compressed exchanges and positive receipt bits. Earlier generic frame-type passes establish neither negotiated-parameter correctness nor final Compressed support. - -This revision removes the proposed `Ac_BlockAck` deferral and its approval gate because their missing-HT premise no longer applies. The implementation must preserve `_ac.ini` and real capability exchange rather than replace VHT fixtures with HT-only configurations. If a later result exposes a different missing prerequisite, record its actual cause before any expectation proposal. The [recorded-expectation rule](../../doc/project/rule/testing.md#tr-baseline-deliberate) still governs such a proposal. - -The proposed `tests/protocol/wifi/11ac/Ac_BlockAckFallback.test` will supply an explicit absent-peer-state condition. Full and simplified management both install peer HT state on this branch. Under full management, a later valid [Beacon](../../src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtSta.cc) can restore the STA's AP record. One-time removal therefore does not maintain the required gap throughout traffic. The fallback fixture will select simplified AP/STA management, which supplies static association without periodic Beacon refresh. Existing `Ac_BlockAck` will retain full management and real capability exchange. - -Use these fixture-local overrides with the existing `_ac.ini` and `_base.ini` includes: - -```ini -*.ap.wlan[*].mgmt.typename = "Ieee80211MgmtApSimplified" -*.sta*.wlan[*].mgmt.typename = "Ieee80211MgmtStaSimplified" -*.sta*.wlan[*].agent.typename = "" -*.sta*.wlan[*].mgmt.accessPointAddress = "ap" -``` - -After all initialization stages, the fixture will remove peer HT records before the first DATA through `removePeerHtCapabilities`. It will remove the records at both ends of each measured wireless hop. Keep association active throughout measured traffic. Keep `opMode = "ac"`, local HT support, and Block Ack support enabled. - -Select the Compressed profile explicitly in the fallback fixture. Schedule no management restart, reassociation, or fixture action that reinstalls capabilities. Repeat this fallback check at A2, C2, and C4. - -The fallback assertions require delivered Normal Ack QoS DATA, absent peer HT state, and no ADDBA, BAR, or Block Ack during the measured interval. Check active association and valid local and peer HT state before the explicit removal. Check absent peer HT state at both ends during traffic and at the end of the measured interval. The fixture must start no agreement before removal. The result establishes fallback under a controlled capability gap with static association. It does not establish an on-air association exchange or a limitation of every `ac` station. - -Hypothetical example: full `ac` management installs valid peer HT state and A2 permits agreement setup. The fallback fixture first establishes static association through simplified management. It removes peer HT state after initialization, before DATA. No Beacon refresh restores that state, so A2 uses Normal Ack throughout the measured traffic. The positive and fallback fixtures must preserve those distinct initial conditions and results. - -The table assigns fixture changes to the stage that changes their contract. S3a recorded the original outcomes; those results do not establish future assertions. S3b's lifecycle owner owns capability and agreement adaptation. C2's production owner owns Compressed exchange assertions. C4's consumer owner owns default activation, profile-specific configuration validation, and coverage of both serializers. - -| Tracked fixture | Current assertion or dependency | Decision and stage | -| --- | --- | --- | -| [WifiQosDelayedBa](../../tests/protocol/wifi/common/WifiQosDelayedBa.test) | Delayed negotiation and response order; an existing deferred failure. | Select Basic explicitly and retain the deferred requirement. Add a separate Compressed initialization-rejection fixture at C4. | -| [Ac_MultiTidBa](../../tests/protocol/wifi/11ac/Ac_MultiTidBa.test) | Two TIDs and Multi-TID response; an existing deferred failure. | Retain its obligation and real `ac` management context. Record the first unmet requirement at each affected stage. | -| [N_Ampdu](../../tests/protocol/wifi/11n/N_Ampdu.test) and [Ac_Ampdu](../../tests/protocol/wifi/11ac/Ac_Ampdu.test) | A-MPDU subframe headers; two existing deferred failures. | Retain the aggregation assertions and HT/VHT capability context. Compressed support does not establish A-MPDU support. | -| [N_BlockAck](../../tests/protocol/wifi/11n/N_BlockAck.test) | Generic Action, BAR, and Block Ack frame types. | Before C2, use explicit Basic. C2 adds accepted ADDBA, matched Compressed frames, and positive bits. C4 checks the default. | -| [N_Amsdu](../../tests/protocol/wifi/11n/N_Amsdu.test) | `aMsduPresent`, without proof of accepted agreement. | Preserve that assertion. Add accepted-agreement permission checks at A2 and repeat with Compressed at C2. | -| [Ac_BlockAck](../../tests/protocol/wifi/11ac/Ac_BlockAck.test) | Generic Block Ack exchange under `ac`, currently passing. | Preserve positive Basic coverage before C2. C2 adds matched Compressed exchanges through real peer HT state; C4 checks the default. | -| [N_CompressedBa](../../tests/protocol/wifi/11n/N_CompressedBa.test) | A Basic class and positive Basic bitmap bit despite its name. | Keep its pre-C2 Basic reproduction. C2 changes this named Compressed fixture to actual Compressed frames and positive receipt assertions. Retain Basic coverage elsewhere. | -| [Ieee80211HcfHeader_1](../../tests/module/Ieee80211HcfHeader_1.test) | Ad hoc mode `a`, custom policy, and synthetic agreement. | Select Basic explicitly. Adapt initialized handlers for shared lifecycle changes without invented HT peer state. Preserve DATA/RTS and policy assertions. | -| [Ieee80211SingleProtectionGroup_1](../../tests/module/Ieee80211SingleProtectionGroup_1.test) | Group duration and no ACK-mode query, with support false and true. | Retain both controls. Explicit Basic preserves the existing support-enabled context; no successful agreement is claimed. | -| [Ieee80211RecipientNav_1](../../tests/module/Ieee80211RecipientNav_1.test) | Injected agreement and Basic BAR/response in ad hoc mode `a`. | Keep Basic types and explicit Basic selection. Add a separate Compressed case with valid HT state. Preserve NAV assertions in both cases. | -| [Ieee80211BlockAckReordering_1](../../tests/module/Ieee80211BlockAckReordering_1.test) | Eight S1 scenarios through the recipient service with supplied Basic agreements. No HCF profile parameter is present. | Retain all eight Basic scenarios through later stages. A2 adds negotiation checks through HCF. C2 and C4 add Compressed integration without removal of Basic assertions. | -| [Ieee80211HcfMultipleProtection_2](../../tests/module/Ieee80211HcfMultipleProtection_2.test) | Synthetic Basic frames and Basic duration calculations. | Keep explicit Basic cases and their duration assertions. Add Compressed duration cases at C2/C3; do not remove Basic coverage. | -| [Ieee80211ResponseModeSelection_1](../../tests/unit/Ieee80211ResponseModeSelection_1.test) | Basic BAR, 152-byte response, and current HT Basic response behavior. | Retain Basic assertions as model compatibility evidence. Add 32-byte non-HT Compressed cases, roles, peer isolation, and asymmetric state at C2/C3. Basic assertions do not establish current-standard conformance. | -| [Ieee80211VhtHtCapabilities_1](../../tests/unit/Ieee80211VhtHtCapabilities_1.test) | Local HT capability assembly from `ac`. | Retain positive capability assertions. Production Compressed fixtures must separately prove peer state and complete exchanges. | -| [serializer_chunk_roundtrip](../../tests/serializer/serializer_chunk_roundtrip.test) and [IEEE 802.11 fillers](../../tests/serializer/lib/fillers/ChunkFillers_ieee80211.cc) | Existing Basic and Compressed BAR and Block Ack producers, with field inventories. | At C1, retain Type 0 Basic round trips and adapt Compressed reserved-field expectations. Verify complete Type decoding and ignored received reserved bits. C4 adds remaining coverage without removal of Basic producers. | - -S3b will adapt synthetic agreements through initialized handlers. Explicit Basic cases retain their existing capability assumptions, frame classes, and rates. Supply matching recipient agreement state when absent-agreement recovery requires it. Do not weaken NAV, policy, duration, or protection assertions to retain a pass. - -Before C2, modern-profile admission tests can exercise agreement policies without a Compressed DATA/BAR exchange. Capability-gap tests must refuse setup before the unsupported builder can run. Positive admission tests must isolate setup; C2 supplies the first complete production Compressed exchange. - -Five module fixtures explicitly disable support: `Ieee80211HcfMultipleProtection_1`, `Ieee80211HcfSingleProtection_1`, `Ieee80211PreparedCancellation_1`, `Ieee80211Txnav_1`, and `Ieee80211VhtHtSupport_1`. Retain these controls. They need no Basic migration or active agreement. Keep HT mode-set and VHT/HT capability unit coverage. +The [S4 verification record](ieee80211-compressed-blockack-s4-execution.md) covers the current final source. It does not establish a test result for every intermediate commit, every protocol fixture, or every configuration. ### R1: publish production rate state -R1 is merged and supplies production publication of local, BSS, and peer rates. The [R1 evidence record](../../doc/project/evidence/model/wifi/r1-rate-publication.md) owns its implementation contract and parent comparisons. C2 owns Compressed rate consumption. The requirements below remain regression obligations when later stages change these paths. - -Use the existing [MIB](../../src/inet/linklayer/ieee80211/mib/Ieee80211Mib.h) stores and validation. The responsible management paths are: - -- `Ieee80211MgmtBase` publishes local legacy operational rates after a mode-set update through `setLocalRateSet`. -- Full AP management publishes BSS rates from its advertised elements through `setBssRateSet`. -- Full AP management installs peer rates from an accepted request when the successful association response exchange commits. -- Full STA management commits BSS and AP rates from accepted advertisements when association commits. -- Full STA management refreshes those records from valid associated-AP Beacons. -- Simplified AP and STA management publish equivalent rates during their existing static association operation. - -Use the merged combined MIB operations when related state commits together. `installBssAndPeerRateSets` commits rate records; `installBssAndPeerState` also commits peer HT state before notification. Preserve unknown state and a known empty basic-rate set as distinct values. Scan candidates and unsuccessful association attempts must not replace active rate state. - -AP departure removes that peer's rates without loss of BSS rates. STA association loss clears its old BSS and peer records. Existing management stop paths clear their corresponding records. R1 adds no stop/start recovery guarantee. - -Retain [Ieee80211MgmtRatePublication_1.test](../../tests/module/Ieee80211MgmtRatePublication_1.test) and [Ieee80211MgmtStateCommit_1.test](../../tests/module/Ieee80211MgmtStateCommit_1.test). These existing fixtures drive real management without direct rate injection. Compare published rates and basic flags with actual Supported Rates and Extended Supported Rates elements after affected changes. - -The fixture must cover these conditions: - -- Full AP/STA association, with observations at both endpoints. -- Simplified management publication, with equivalent static records. -- Valid associated-AP Beacon refresh and unrelated scan advertisements. -- Unsuccessful association without replacement of active records. -- Peer departure, association loss, and existing management stop paths. -- Unknown state and known empty basic-rate state. - -Retain focused Basic DATA, BAR, response-mode, and support-disabled controls. Current rate selectors do not consume these records; later rate consumers must preserve the retained Basic selection contract. Compare each later changed result with the responsible stage's pinned parent. Preserve R1's original comparison separately and record each new result's cause. - -R1 tests the MIB's notification contract without S3b's future subscriber. C2 must repeat that integration after both changes exist. A3b must use the merged combined-commit behavior instead of an assumed AP remove/reinstall notification pair. A rate-only update must preserve unchanged Basic and Compressed agreements. The built-in rate-control path must produce no additional reset or rate statistic solely from these notifications. External listeners retain their documented notification contract. - -C2 cannot replace R1 evidence with helper injection or a successful Compressed exchange. Preserve R1's recorded commands, mode, fixture selectors, seed, parent, and outcomes. Record later subscriber integration against its actual combined source. - -### Compressed replacement steps - -| Step and purpose | Owner and proposed change | Expected result and verification | -| --- | --- | --- | -| C1. Define valid type 2 frames beside Basic. | Add the Compressed builder and fixed 28-byte header chunk. Decode the complete Type field. Retain Basic classes, fields, builders, and producers within the Type 0 contract. Adapt existing Compressed round-trip producers and expected fields in this step. | Golden octets and round trips verify Type 0 and Type 2. Reject Basic values that encode another Type. Compressed reserved bits write zero and received values are ignored. Basic remains 152 bytes with FCS; Compressed remains 32 bytes. | -| C2. Connect complete Compressed exchanges. | Consume R1's committed rates. HCF derives BAR position and the recipient's actual interframe relation. Procedures and ACK handling select the configured profile and match the response variant. The record retains Compressed receipt truth after delivery and supplies the bit at `WinStartR - 1`. Add the individual-MPDU release condition without loss of Basic fragment behavior. Supply fragmentation suppression, Compressed rates, timeouts, durations, and protection airtime. | Real association supplies rate state. Production checks cover receipt retention, zero holes, interframe release, and ordinary gap retention. Empty records yield zero bits. Wrong-profile and malformed input cannot report success. Explicit Basic retains fragments and its response contract. Verify the accepted fatal conflict diagnostic; record the first Compressed timing result before C3 or C4. | -| C3. Verify both profiles and Compressed timing. | Add focused Compressed rate and timing cases. Retain the Basic response-mode fixture and its 152-byte assertions. Add 32-byte Compressed cases with directional queries, peer isolation, and ACK/CTS controls. | Primary and legal alternate Compressed rates produce correct duration. Initial and later BAR use legal rates. Profile-specific lengths remain distinct. Timing checks distinguish permitted overruns from unlawful continuation. | -| C4. Activate the default and complete compatibility guidance. | Set Compressed as the final default. Add the migration diagnostics and external-style fixture. Keep explicit Basic settings and complete both serializer inventories. Add Compressed delayed-policy rejection. | Default eligible HT links use Compressed. Default links without usable HT state use Normal Ack. Explicit Basic remains usable without HT peer records. No Basic class, showcase configuration, parameter-study variant, or result row is removed. | - -S5 consists of C1 through C4. Every commit must build. C4 follows runtime conversion and timing verification. The temporary Basic default in S3a prevents premature activation; the completed implementation defaults to Compressed as requested. - -Retain the existing Basic methods for external consumers. Add Compressed methods or a shared variant-aware operation only where the existing contract cannot serve both formats. Document new interface obligations. Retention avoids Basic class removal; it does not guarantee that every external implementation needs no adaptation. - -C2 adds all runtime operations for a supported Compressed exchange. C3 adds verification after that path exists. Basic fragment cases remain after C2 and C4. Ordinary fragmentation outside any agreement and rejected Compressed fragment input remain separate tests. - -Retain these six speed records from [tests/speed/store.json](../../tests/speed/store.json). Each inspected record has `run_number = 0`. - -| `working_directory` | `ini_file` | `config` | -| --- | --- | --- | -| `showcases/wireless/blockack` | `omnetpp.ini` | `Fragmentation` | -| `showcases/wireless/fragmentation` | `omnetpp.ini` | `HCFfragblockack` | -| `showcases/wireless/fragmentation` | `parameterstudy.ini` | `OnlyPacketSizeHCFfragblockack` | -| `showcases/wireless/fragmentation` | `parameterstudy.ini` | `PacketSizeHCFfragblockack` | -| `showcases/wireless/fragmentation` | `parameterstudy.ini` | `ThresholdHCFfragblockack` | -| `showcases/wireless/fragmentation` | `parameterstudy.ini` | `TxPowerHCFfragblockack` | - -Retain the Block Ack `General`, `MixedTraffic`, and `NoFragmentation` records and TXOP `General`. Match records by directory, INI file, configuration, and run number. Reassess measured effects through the applicable baseline procedure. Do not delete these records because Basic is unsupported by the current standard. - -Retain [Fragmentation.anf](../../showcases/wireless/fragmentation/Fragmentation.anf), its result inputs, filters, configuration order, and plot series. The inspected Block Ack and TXOP directories have no `.anf` files. Repeat the consumer search before implementation. The speed store has no records for either QoS example directory; their direct and fingerprint checks still apply. - -Documentation will label every retained Basic demonstration as historical compatibility. Give the IEEE Std 802.11e-2005 origin and IEEE Std 802.11-2024 exclusion with their references. The label must accompany the relevant user-facing explanation, configuration description, and analysis caption. Do not require a new topology image solely because the standard status note changes. - -Release notes and migration guidance will explain the new default and the explicit Basic compatibility setting. Compressed agreements suppress fragmentation; Basic agreements preserve it. The threshold still applies outside Compressed agreements. An HT PHY mode alone does not select the profile. - -A smaller wire-only prerequisite can add type 2 serialization tests. It cannot establish a complete Compressed exchange without the required agreement, scoreboard, rate, and response behavior. - -Keep `delayedAckPolicySupported` parameters and methods. Both currently default to false. The Compressed profile will reject true at initialization because this plan supplies no delayed Compressed exchange. Retain the existing deferred delayed test with explicit Basic selection. Basic retention does not make that missing behavior pass or authorize a new Basic initialization restriction. - -The choices have explicit owners: - -- The [lifetime plan](ieee80211-edca-data-lifetime.md#3-proposed-ownership-and-behavior) owns `msduLifetime` and its default. -- The [lifecycle plan](ieee80211-blockack-agreement-lifecycle.md#4-standard-requirements-and-inet-choices) owns `addbaFailureTimeout`, its default, and discard-all. -- This plan owns `blockAckVariant`, its final Compressed default, and explicit Basic compatibility. -- This plan owns the fallback when the basic-rate set is unknown. - -The [decision table](#maintainer-decisions) records the accepted lifetime default and transfer-completion predicate. Basic retention does not remove their compatibility effects. Required measurements remain unexecuted. The 100 ms response timeout and fatal profile-conflict policy are also accepted. - -## 6. Verification and scope limits - -The [lifetime plan](ieee80211-edca-data-lifetime.md#5-verification-and-evidence) owns lifetime verification. The [lifecycle plan](ieee80211-blockack-agreement-lifecycle.md#6-direct-verification) owns setup, Action, inactivity, teardown, and association checks. Its performance section owns setup-delay and disposal measurements. - -Retain these direct checks for recipient delivery, BAR channel access, and final Compressed support: - -- Rate publication, R1: Establish real AP/STA association without direct MIB rate injection. Require known local operational rates, BSS basic rates, and peer operational rates at both stations. Compare committed rates and basic flags with the actual Supported Rates and Extended Supported Rates elements. STA management must update rates after a valid associated-AP Beacon; scan candidates and unsuccessful association attempts must preserve active rate state. Check removal after association loss and equivalent publication through simplified management. A rate-only update must preserve an unchanged agreement in either profile. Absent HT state must not retire a Basic compatibility agreement. Repeat these subscriber checks at C2 after R1 and S3b both exist. - -- BAR classification, C2: Use BSS basic rates 6, 12, and 24 Mbps with peer operational rates that also include 54 Mbps. Exercise initial and continuation BAR through HCF. Require 24 Mbps for the initial BAR and 54 Mbps for an eligible later BAR. Repeat after fresh channel access and require initial classification again. Preserve RTS/CTS and ACK control assertions. Direct classification helper tests cannot replace the HCF path. - -- Basic wire contract, C1: Check golden Type 0 octets, lengths, and fragment bitmap format. Retain Basic field round trips that encode Type 0. Reject a Basic reserved value that changes the Type. Type 0 must deserialize as Basic. - -- Compressed wire contract, C1: Check golden Type 2 octets, lengths, and the 64-bit bitmap format. Adapt the current Compressed producers and expected fields with the serializer change. Check zero writes and ignored received values for B0 and B5–B11. Nonzero B3 or B4 changes the Type and cannot use that ignore rule. Check short frames and unsupported types 1, 3, and 4 through 15. - -- Scoreboard validation, C2: Require zero bits for an empty scoreboard under an active agreement. A Basic frame under a Compressed agreement must fail profile validation before receipt-state changes. - -- Compressed response validity: Inject matching Type 2 responses with nonzero Fragment Number, incorrect bitmap size, or incorrect length. Exercise serialized and directly supplied typed input. Require failed exchange recovery without acknowledgment, inactivity refresh, or success feedback. - -- Receipt retention, C2: Drive DATA 100, 102, and 101 through the production recipient path under an accepted Compressed agreement. Require delivery in order 100, 101, and 102. Send BAR at 100 and require all three receipt bits after delivery. Retain Basic fragment checks separately. - -- Scoreboard holes, C2: With agreement start 100 and size eight, receive only DATA 115. Require scoreboard window 108–115, a positive bit only for 115, and zero bits for 108–114. Repeat across sequence wrap. These checks must reject the Basic getter's inferred positives for absent earlier positions. - -- Recipient fragments: Retain S1 scenario 0 to check Basic capacity and complete-unit delivery through the recipient path. At C2, inject fragmented DATA under an active HT-immediate agreement. Use nonzero Fragment Number or More Fragments set. Require no receipt state update, positive bitmap bit, fragment state, or DATA delivery. These checks prohibit fragmented Compressed reception; the originator checks below prohibit fragmented transmission. Repeat S1's Basic fragment case at C2 and C4, with fragment status and complete-unit delivery retained. - -- Originator fragmentation: With an active HT-immediate agreement, extract an MSDU above the configured fragmentation threshold. Check one unfragmented DATA frame, including when the ACK policy selects Normal Ack. Without an agreement, check ordinary fragmentation and Normal Ack. Start setup while numbered fragments remain and check that all resolve before ADDBA transmission. Verify that the first DATA under the new agreement is unfragmented and uses the accepted request number. - -- Basic BAR timing, S4: Compare with S4's pinned parent before publication. Test standalone BAR, final BAR after one or four DATA frames, and late continuation near a positive TXOP limit. Exercise single and multiple protection. Record modes, sizes, IFS, response airtime, completion time, and the Data/Management count. - - Check applicable TXNAV and TXOP bounds with each permitted-overrun condition explicit. Separate inherited violations from violations introduced by S4. Resolve a new unlawful overrun before publication of that affected Basic path. +The MIB owns local, BSS, and peer rate and HT facts. Management publishes coherent state through the combined MIB commit operations. Rate consumers read that committed state. Association reset uses a separate management-to-MAC call because an unchanged capability value does not identify a new association. The [reset contract](ieee80211-blockack-agreement-lifecycle.md#reassociation-consumers-and-callback-order) explains the cleanup order. -- Airtime and TXOP: At C2, repeat affected S4 checks with Compressed exchanges and compare with C2's pinned parent. Test above-threshold DATA near a positive TXOP limit with Block Ack enabled. Record DATA and response modes, sizes, IFS, protection, response airtime, and completion time. Record the Data/Management count and each aggregate format within that TXOP. +## 4. DATA selection and BAR operation - Check containment or the exact permitted-overrun condition under Clause 10.23.2.9. Measure Compressed timing through its infrastructure fixtures. Check retained Basic showcase airtime separately, with both wireless QoS hops and the current ad hoc hops. Separate permitted overruns, inherited violations, and new violations before the C3 or C4 decision. +Preview borrows a candidate without queue removal or sequence assignment. For an unextracted candidate, the data service reports the prospective sequence number. The original frame retains its header and queue ownership. The [preview interface](../../src/inet/linklayer/ieee80211/mac/contract/IOriginatorQosMacDataService.h) exposes these operations. -- Final response timing: At C3, repeat affected airtime checks across primary and legal alternate response modes implemented by C2. Include the lowest supported rates and late continuation near the TXOP limit. Test a permitted initial unaggregated MSDU under Block Ack, an initial A-MSDU, and a later exchange that cannot finish within the required bound. Require containment for the A-MSDU and applicable later exchange. A permitted initial overrun must not create a false admission prerequisite. A C2 result covers only its recorded modes and exchange boundaries; a fingerprint match does not prove timing compliance. +Below `blockAckReqThreshold`, the ACK policy defers a group's BAR only when the next eligible DATA belongs to that group and fits its window. An empty queue, another peer or TID, or an out-of-window candidate can therefore make BAR due. Counts from different groups do not combine to meet the threshold. -- Demonstration coverage: Preserve S3a's explicit Basic selection and recorded direct assertions from Section 5. Repeat the assertions after A2 and at C2/S5. Every legacy Block Ack demonstration must retain actual Basic exchanges, including ad hoc QoS run 1. Retain run 0 as the support-disabled control. Check Compressed capability-gap fallback separately; it must not replace legacy coverage. +The frame sequence selects BAR before DATA extraction. Basic Block Ack response acceptance checks the local receiver, requested peer, and requested TID. Transmitted-BAR processing limits acknowledgment-state changes to the request's peer, TID, and bitmap range. The response starting sequence number alone does not advance the transmit window. -- Fixture coverage: S3a records the [tracked fixture inventory](#s3a-tracked-fixture-inventory-and-vht-scope), including HT/VHT state and actual failure causes. S3b runs the capability, agreement, A-MSDU permission, and fallback checks before final conversion. C2 requires Compressed responses in retained positive Block Ack cases. C4 runs the final inventory, serializer expectations, and delayed-policy rejection fixture. Report deferred protocol obligations separately from successful exchanges and successful fallback checks. +BAR collision and failure update EDCA contention state without a DATA retry entry. Failed Block Ack feedback permits DATA retransmission with Retry set. Resolution and lifetime disposal permit the agreement window to advance, without a jump over unresolved DATA. -- Recipient gap release, completed S1: Retain scenarios 1 and 2 of the recipient fixture. Scenario 1 buffers complete DATA 101 and 102 behind absent DATA 100. Receipt of DATA 100 must release all three units in order in that operation. Scenario 2 repeats this condition across sequence wrap. Retain their assertions for delivery order and the resulting reorder window without a later DATA reception or BAR. +## 5. Configuration and compatibility -- Recipient interframe release, C2: Supply an agreement with start 100 and size four through HCF. Receive Normal Ack DATA 100 and observe its ACK completion. In a zero-propagation control, start DATA 104 reception one SIFS after local ACK transmission ends. Require adjusted scoreboard start 101, receipt evidence for 100, immediate delivery of 104, and reorder start 105. - - Use actual receive times and the transmission callback. A directly supplied relation flag cannot replace this production check. Repeat with applicable SIFS and RIFS relations after a previous MPDU. Repeat the positive case across sequence wrap. - -- Recipient interframe controls, C2: Repeat with a false bit at `WinStartR - 1` and an interval outside the accepted timing relation. Each control must retain 104 behind the gap. Add nonzero propagation delay and intervening unrelated reception or transmission. Test history invalidation after agreement retirement, peer cleanup, and replacement setup. Check that stale history cannot release DATA. Record exact receive and transmit endpoints and the applied timing allowance. Retain Basic controls and explain each changed Compressed fingerprint through observed delivery events. - -- Recipient BAR before DATA, completed S1: Retain scenario 3 with supplied agreement start 100 and buffer size eight. Before DATA, valid Basic BAR at 104 must create the record and set reorder start 104. Subsequent DATA 104 must reach immediate delivery. Invalid BAR and BAR without an agreement must create no reorder record. - -Repeat both recipient cases with Compressed frames at C2 and C4. Each result must preserve the repaired delivery order and window state. - -- Recipient window and BAR: Test DATA beyond `WinEndB` after an older DATA drop. Check its delivery, scoreboard bit, and released older complete units. With DATA 100 absent and DATA 101 buffered, send a valid BAR at 101. Check delivery of 101 and independent scoreboard movement. Release 4095 and 0 in one operation and assert that exact order at the next MAC process. An invalid BAR must leave both windows unchanged. - -- BAR originator: Test BAR-only contention, response matching, timeout, older retries, and window advance after acknowledgment or drop. With single protection enabled, check that BAR selection and duration calculation do not extract or number queued DATA. Test two peers with the same TID and a BAR for only one peer. Under an established agreement, test one and four DATA frames with the default threshold of five. Keep peer B continuously eligible while peer A has four outstanding frames. Check that A receives BAR before another DATA for B. - -- Originator identity, S4: Give one peer outstanding DATA for TIDs 2 and 5. Check separate threshold counts and BAR selection for each TID. Transmit BAR for TID 5. Require no ACK-state change for TID 2. Repeat these checks with Compressed frames at C2 and final S5. - -- Small originator windows, S4: Accept buffer sizes one and four with BAR threshold five. Require BAR before DATA beyond each transmit window. Repeat these checks with Compressed frames at C2 and final S5. - -- Earlier Compressed response start, C2: Use transmit window 100 through 163 and BAR start 104. Let transmitted DATA 102 remain unacknowledged without a wait for that BAR. Receive a matched response with start 100 and a positive bit for DATA 102. Require acknowledgment of 102 through HCF. Positive bits for unsent frames or frames outside the active window must leave those frames unacknowledged. - -- Later or disjoint Compressed response, C2: Send a matched response whose start follows some requested frames. Require unchanged acknowledgment state below that start. Require those frames to leave their BAR wait and become retry eligible. Send a matched response without overlap. Require every requested frame to remain unacknowledged and become retry eligible. - -- DATA lifetime integration: Repeat zero-bit Compressed responses and BAR timeouts until the existing DATA deadline expires. Check sequence preservation, Retry-bit policy, disposal, and window progress. Let the deadline expire during an accepted Compressed exchange. Check safe completion and absence of another DATA attempt through the lifetime owner's contract. - -- Response rates, C3: Test the highest qualifying BSS basic rate and the mandatory-rate fallback when no basic rate qualifies. Test the documented INET fallback when the basic-rate set is unknown. For HT and VHT BAR inputs, assert the non-HT reference rate and the applicable OFDM or ERP-OFDM modulation class. For non-HT BAR, assert the received modulation class and preamble type. Test a legal alternate response rate with equal duration and an invalid override. Observe the transmitted response mode and Duration/ID through HCF. - -- Originated BAR rates, C3: Require a non-HT PPDU for initial and later Compressed BAR. Give the BSS and peer different legacy rate sets. Check the initial basic-rate rule and the later peer-operational-rate rule. Check fallback with unknown peer state, an empty basic-rate set, and unknown BSS rate state. Reject a configured HT/VHT BAR mode or a legacy rate that fails the applicable rule. Preserve unrelated RTS, CTS, ACK, and DATA mode checks. - -- Migration diagnostics, C4: Use the [external-style migration fixture](#migration-diagnostics), outside the explicit legacy override inventory. Check local non-HT warnings, HT ad hoc fallback reasons, and explicit Basic exchanges. Disabled support must produce no irrelevant warning. Keep Compressed as the selected default. - -- Profile conflict, C2: Send a valid addressed BAR of the other variant to an active peer/TID. Require the fatal configuration diagnostic before agreement, scoreboard, reorder, response, or inactivity updates. Check both mismatch directions and no conflict-triggered DELBA. Require termination at the first qualifying BAR. Verify diagnostic fields and cause, not merely an expected failure status. In separate compatible runs, verify Basic and Compressed exchanges plus unaffected Normal Ack traffic. Keep malformed, unknown-variant, unaddressed, and absent-agreement cases separate. - -- Compatibility and activation: Default eligible HT links must use Compressed. Explicit Basic must preserve legacy classes, bitmap fragments, response lengths, and existing NAV and protection assertions. Change `N_CompressedBa.test` to require Compressed and retain positive `Ac_BlockAck` coverage through real HT state. Keep Basic NAV and multiple-protection scenarios; add Compressed scenarios rather than removal of Basic coverage. Extend response-mode tests with 32-byte Compressed cases beside 152-byte Basic cases. Retain directional queries, peer isolation, asymmetric state, and ACK/CTS controls. - -The [standalone lifetime tests](ieee80211-edca-data-lifetime.md#5-verification-and-evidence) own identity, aggregation, fragmentation, and IFS deadline checks. Run each prerequisite's tests against its Basic path before its replacement. Repeat affected integration checks with Compressed frames at S5. - -Use direct production assertions for peer, TID, response timing, bitmap, channel access, agreement state, and queued-frame outcome. A unit bitmap test alone cannot prove HCF uses the result. - -Add a proposed `tests/unit/Ieee80211CompressedBlockAck_1.test` for wire and scoreboard checks. Add a proposed `tests/module/Ieee80211HcfCompressedBlockAck_1.test` for the production exchange. - -Use the HCF module fixture for identity, small-window, shifted-response, response-mode, and profile-mismatch cases. - -- Test the default Compressed setting and explicit Basic at both endpoints. -- Test unknown selector values at initialization. -- Give two HT peers different profiles. -- Require no cross-variant acknowledgment. A valid addressed BAR that conflicts with an active agreement must cause the exact fatal configuration diagnostic before state updates. Require no conflict-triggered DELBA or repeated setup. Verify compatible traffic in separate runs; absent-agreement recovery retains its separate DELBA checks. - -Retain [Ieee80211BlockAckReordering_1.test](../../tests/module/Ieee80211BlockAckReordering_1.test) through the later stages. Its current scenarios 0 through 7 assert delivery and state through `RecipientQosMacDataService`. Scenario 0 covers fragment capacity; scenarios 1 and 2 cover gap release and wrap; scenario 3 covers BAR before DATA. Scenarios 4 through 7 cover BAR order, window movement, peer/TID isolation, and A-MSDU order. The fixture supplies accepted Basic agreements. A2 must add negotiation checks through HCF, while C2 and C4 must verify Compressed integration. - -After the required fresh debug build, use this current selector from the checkout root. The fixture selects all eight recipient scenarios and seed 0 internally. The command also selects the three current NAV runs. This document update does not execute the command. - -```sh -inet_run_module_tests -m debug -f '(Ieee80211BlockAckReordering_1|Ieee80211RecipientNav_1)\.test$' -``` - -Run those exact cases with the unit and module runners in debug mode. Select all eight current protocol fixtures. Add the proposed absent-peer-state `ac` fallback fixture after it exists. Select the four Block Ack-enabled module fixtures and five support-disabled controls. Include the separate S1 recipient fixture with all eight Basic scenarios. - -Include the HT mode-set, VHT/HT capability, and response-mode unit fixtures. Add the proposed delayed-policy rejection fixture at C4. Run the serializer fixture with its suite's runner when C4 changes its expected fields. A fixed seed suffices for these deterministic cases. - -For each stage, record selected paths and runs, expected and observed outcomes, and the first failed assertion or initialization error. Preserve source includes and generated configurations with the evidence. Distinguish an expected protocol failure from generation, compilation, or unrelated runtime failures. Keep the four current deferred protocol requirements separate from positive `Ac_BlockAck` and absent-peer-state fallback coverage. Appendix A separates completed S1 results from the earlier capability results. Checks for the later stages stay proposed. - -Use the common selection from `tests/fingerprint/showcases.csv` and `tests/fingerprint/examples.csv` through final C4. Retain all 19 recorded rows. Preserve each row's configuration, run number, time limit, and fingerprint ingredients. Explicit Basic settings prevent the default change from converting these legacy cases. Shared repairs can still change results; record their causes rather than an assumed unchanged baseline. - -The four wireless QoS rows exercise shared HCF callers, including `MacQosWithBlockAck`. The two ad hoc QoS rows separate the support-disabled control from retained Basic compatibility after A2. The TXOP row preserves its intended mixed frame exchanges through topology and protocol changes. Block Ack-disabled EDCA rows check regression effects within S2's broader lifetime scope. S2 must also satisfy the lifetime plan's [measured-expiry requirement](ieee80211-edca-data-lifetime.md#5-verification-and-evidence). DCF rows serve as controls for shared changes. - -| Simulation path | Retain after C4: 19 rows | +| Setting or contract | Current behavior | | --- | --- | -| `showcases/wireless/blockack` | `NoFragmentation`, `MixedTraffic`, `Fragmentation` | -| `showcases/wireless/aggregation` | `NoAggregation`, `Aggregation`, `VoicePriorityAggregation` | -| `showcases/wireless/fragmentation` | `DCFnofrag`, `DCFfrag`, `HCFfrag`, `HCFfragblockack` | -| `showcases/wireless/qos` | `NonQos`, `Qos` | -| `showcases/wireless/txop` | `General`; run 0 | -| `examples/wireless/qos` | `MacQos`, `MacQosWithoutAggregation`, `MacQosWithRtsCts`, `MacQosWithBlockAck`; run 0 | -| `examples/adhoc/qos` | `MacQos`; runs 0 and 1 | - -The TXOP row records five seconds; each ad hoc QoS row records ten seconds. These limits come from the fingerprint CSV entries, not the INI defaults. Block Ack `General` has no separate fingerprint row; its S3a checks include direct exchanges and its retained speed record. - -Record the exact selected rows before execution. Compare each stage with its pinned parent before later stages change the same paths. Extend the selection when changed callers or a failure justify more cases. Diagnose the first changed exchange in each affected case before any baseline proposal. - -Record a cause for each changed result at the stage that introduces it. A stage need not change every selected fingerprint. Preserve raw results and the selected parent revision. Fingerprints check regression effects; direct production assertions establish the required behavior. S1's four approved changes remain recorded under its [separate authorization](../done/ieee80211-compressed-blockack-s1.md). This plan revision authorizes no additional baseline update. - -Follow [run-the-gates.md](../../doc/project/guide/run-the-gates.md) for builds and checks. Each later implementation will record exact commands, modes, selectors, and outcomes. Appendix A records completed S1 and earlier capability verification. Checks for the later implementation stay unexecuted. - -Basic frame classes and existing builders remain public. The implementation will update user and migration guides, release notes, configuration descriptions, analysis captions, and serializer coverage. State that Compressed is the default and `blockAckVariant = "basic"` selects historical compatibility. Cite IEEE Std 802.11e-2005 as the origin and IEEE Std 802.11-2024 as the standard that reserves type 0. Do not claim current-standard support for Basic or complete historical conformance for existing INET behavior. - -Document added interface obligations without removal of Basic contracts. Explain `addbaFailureTimeout`, per-EDCAF `msduLifetime`, setup deferral, final-transfer DELBA, and discard-all under their separate owners. Preserve individual-DATA and stop/start limitations. No existing showcase topology or configuration name needs migration under this decision. - -The [lifecycle plan](ieee80211-blockack-agreement-lifecycle.md#3-agreement-behavior) owns recovery after rejection, uncertain setup, and failed DELBA for both profiles. Normal Ack fallback due to absent HT state belongs to Compressed. Basic compatibility must not silently become that fallback when the default changes. - -Release notes must retain positive Compressed coverage for eligible `ac` peers and the four existing deferred protocol requirements. Explain originated Compressed BAR's non-HT mode and `controlFrameBitrate` validation. Keep complete VHT transfer support outside the claim. +| `isBlockAckSupported` | Defaults to false. | +| `blockAckVariant` | Defaults to `"basic"`; `"compressed"` fails initialization. | +| `msduLifetime` | Defaults to 0.512 seconds per EDCAF and requires a positive finite value. | +| `addbaFailureTimeout` | Defaults to 100 ms after request acknowledgment; it does not bound contention or DELBA recovery. | +| Completion DELBA | Applies at a safe exchange boundary after first DATA transmission, with no queued or numbered DATA. | +| Originator teardown | Discards transmitted unresolved DATA and preserves sequence continuity for surviving unsent DATA. | +| Recipient teardown | Delivers complete buffered units before resource release. | +| Association reset | Discards old peer DATA and receive state without delivery into the replacement association. | -The table gives normative IEEE Std 802.11-2024 evidence for Compressed and shared repairs. Section 2 gives the historical IEEE Std 802.11e-2005 references. Shared repairs do not establish complete Basic conformance to either edition. [Appendix B](#appendix-b-standards-source-notes) retains canonical locators and extraction limits. +Custom QoS data services must expose borrowed preview and prospective sequence lookup. Custom BAR policies must accept explicit agreement context. Omitted context arguments fail compilation. The [migration section](../../doc/src/migration-guide/development/ieee80211-basic-block-ack-extension-points.rst) defines the extension obligations. -| Decision | Clause or table | Physical PDF pages | -| --- | --- | --- | -| Fragmentation boundary for HT-immediate agreements | 10.2.7 | 1882 | -| VHT stations retain HT operation | 4.3.15 | 356–357 | -| Initial and later BAR transmission rates | 10.6.6.2; 10.6.6.4 | 1943–1945 | -| Non-HT responses to non-HT, HT, and VHT BAR; legal alternate rates | 10.6.6.5.2; 10.6.6.5.4 | 1945–1947; 1950 | -| HT/VHT non-HT reference-rate calculation | 10.6.11 | 1962–1963 | -| Additional exchange bounds and permitted TXOP overruns | 10.23.2.8; 10.23.2.9 | 2010–2014 | -| Compressed retransmission | 10.25.6.7.1 | 2068–2070 | -| Retry for individual DATA; scope of the QoS retry rule | 9.2.4.1.6; 10.23.2.12.1 | 665; 2016–2017 | -| Positive bitmap bits within the transmit window, relative to the received Block Ack start | 10.25.6.8 | 2071–2073 | -| Consecutive delivery when DATA fills a reorder gap | 10.25.6.6.2.1(a)(2) | 2065–2066 | -| Individual-MPDU delivery with SIFS/RIFS and receipt evidence at `WinStartR - 1` | 10.25.6.6.2.1(a)(2)(v) | 2065–2066 | -| Full-state receipt retention and zero status for absent positions | 10.25.6.3 | 2060–2061 | -| Reorder window movement after BAR, including an empty window | 10.25.6.6.3.1 | 2067 | -| HT capability advertisement in IBSS beacons is a valid alternative | Table 9-62, row 33 | 781 | +### Selected-extraction contract -Table 9-62 requires HT Capabilities when `dot11HighThroughputOptionImplemented` is true and the station is not a 6 GHz station. The condition does not exclude IBSS. The choice to defer IBSS capability support remains an INET scope decision. +The data service uses ordinary dequeue for individual extraction of the advertised next frame. Filtered `canPullPacket()` and `pullPacket()` operations permit eligible DATA behind a deferred frame while the queue owner applies normal pull effects. Aggregation validates candidate eligibility and A-MSDU permission before extraction. Invalid aggregate candidates cause individual extraction of the selected eligible frame. -The prerequisite plans own [lifetime evidence](ieee80211-edca-data-lifetime.md#2-current-source-and-standard-support) and [lifecycle evidence](ieee80211-blockack-agreement-lifecycle.md#8-standards-evidence-and-scope-limits). Fatal profile-conflict termination is a model choice under the [lifecycle contract](ieee80211-blockack-agreement-lifecycle.md#profile-conflict-detection-and-termination), not a new requirement inferred from Clause 11.5.4. +This implementation uses the current queue API. It defines no separate optional selected-extraction interface. External queue implementations must preserve service order, ownership, residence metadata, pull events, and compound accounting through their queue operations. -### Airtime acceptance and admission dependencies - -The current branch excludes Block Ack-enabled HCF from complete-cost single-protection TXOP admission. [HCF](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) selects that admission path only when `isBlockAckSupported` is false. [HcfFs](../../src/inet/linklayer/ieee80211/mac/framesequence/HcfFs.cc) rejects continuation when no TXOP time remains. That check does not prove that the complete next exchange fits. This plan does not add complete-cost admission for Block Ack. - -S4 introduces Basic BAR paths before Compressed integration. Its owner must assess those changed exchanges against S4's parent before S4 publication. A standalone BAR can qualify for a Control-frame overrun exception. A final BAR after several DATA frames cannot use the one-Data-or-Management-frame exception. Hypothetical example: four DATA frames leave 20 microseconds, but their final BAR exchange needs 80 microseconds. S4 must not introduce that unlawful continuation without an admission correction or a verified scope restriction. - -S4's record owns violations introduced by S4. The C2 comparison cannot relabel such a violation as acceptable inherited behavior. An inherited violation does not itself require this plan to repair every existing TXOP path. Each stage must still prevent new violations within its supported change. C2 and C3 repeat the assessment for Compressed integration and its supported response modes. - -At a fixed PHY mode, an unfragmented DATA frame takes longer than one constituent fragment. The total airtime can still be lower than the complete fragment sequence because fewer headers and responses are necessary. Hypothetical example: a previous DATA exchange ends with 100 microseconds left, but another DATA exchange needs 200 microseconds. The positive remaining interval does not authorize that continuation. Clause 10.23.2.8's applicable TXNAV bound and Clause 10.23.2.9's TXOP restriction still apply. - -An overrun alone does not establish a violation. Clause 10.23.2.9 permits specified overruns when the TXOP contains at most one Data or Management frame. These cases include initial transmission of an MSDU under a Block Ack agreement, outside an A-MSDU or a multi-MPDU A-MPDU. The clause also permits specified retransmissions and Control frame transmissions under its stated conditions. The timing record must identify the exact exception and every applicable condition. It must also check any independent TXNAV requirement. - -Hypothetical example: the first unaggregated MSDU under an agreement needs 200 microseconds within a 100-microsecond TXOP limit. The TXOP contains no other Data or Management frame. Clause 10.23.2.9 permits that initial-transmission case under its stated aggregate conditions. The same example with an initial A-MSDU does not qualify. A second DATA exchange also defeats the one-Data-or-Management-frame condition. - -No current evidence proves timing compliance for final Compressed operation or the repaired legacy demonstrations. C2 must record its first timing result before C3 or C4 proceeds. Each result must distinguish permitted overrun, inherited violation, and new violation. A permitted overrun creates no admission-correction prerequisite. - -For a new violation in a supported case, the affected stage requires a correction through the separate TXOP design before publication. Apply that condition to S4's changed Basic paths and C2's changed Compressed paths. C3 repeats the Compressed classification across response modes and exchange boundaries. An inherited violation does not justify a new violation. - -If S4 evidence establishes a required correction, its affected Basic path cannot publish until that correction passes its direct checks. S5 likewise cannot complete while a required Compressed correction remains absent or unverified. A new unlawful continuation can block its dependent stage. A permitted initial overrun cannot. Record the blocked path, violated clause, required correction, and comparison parent in the responsible stage's timing result. - -A restriction on supported configurations is an alternative only when direct evidence proves timing compliance throughout its stated scope. Do not select a fixed MSDU size cap as an assumed solution. Hypothetical example: a capped second DATA exchange needs 80 microseconds, but only 50 microseconds remain. The cap does not prevent that unlawful continuation. PHY rates, protection, responses, and the remaining interval all affect the required bound. No size cap or silent Normal Ack fallback is an automatic recovery policy in this plan. - -## Appendix A. Executed evidence - -### Completed S1 and recorded verification - -S1 merged through PR #1320 on 14 October 2026 at `1cdb362a2a4b97f564566487079d9d156a5d213d`. Its original verified feature head is `fcc06450355a52b9c8b0f8f2647e0654711bfaca` on `work/compressed-blockack-s1`. Its original publication base is `ac6344cc5bcac972012759281a11b3f8255b5d46`. The [S1 source record](../done/ieee80211-compressed-blockack-s1.md) supplies scope, reproduction, and approved fingerprints. Its [human summary](../done/ieee80211-compressed-blockack-s1-summary.md) explains recipient behavior and caller requirements. The results below retain their original source boundaries and establish no fresh runtime verification at the merged revision. - -The [published PR description](https://github.com/inet-framework/inet/pull/1320) records verification at each original source boundary. The local final-series audit supplied additional driver commands and raw result locations. That untracked artifact is absent from this worktree. Use the PR description and committed S1 records for available evidence. This plan update ran no new build, module test, simulation, or fingerprint comparison. - -| Recorded check | Result | Scope limit | -| --- | --- | --- | -| Debug and release builds at each commit. | All recorded builds pass. | Release behavior tests remain unrun. | -| Debug recipient fixture at the final head. | All eight scenarios pass through the production recipient service. | Agreements and buffer sizes are supplied; ADDBA negotiation and Compressed exchanges remain outside this evidence. | -| Debug recipient NAV fixture at the final head. | The `hcf`, `dcf`, and `blockAck` runs pass. | The Basic HCF exchange does not establish negotiated capacity or recipient DATA delivery. | -| Debug fingerprint selection at the final head. | All 12 selected configurations pass with the approved S1 values. | This selection differs from the proposed 19-row common inventory; it does not verify that full inventory. | - -The recorded module driver uses `opp_repl` and `run_opp_tests()` for `tests/module` in debug mode after the library build. Its filter is `(Ieee80211BlockAckReordering_1|Ieee80211RecipientNav_1)\.test$`. Both fixtures use seed 0. The recipient fixture selects scenarios 0 through 7 at the original final head. The NAV fixture selects `hcf`, `dcf`, and `blockAck`. These are recorded selectors and results, not fresh execution at the merged revision. - -The fingerprint selection uses the command below from `tests/fingerprint`. The recorded final invocation returns exit status 0. Each selected row uses run 0, its CSV time limit, and the default seed set. The command is recorded evidence, not a new execution by this document update. - -```sh -./fingerprinttest -d -t 4 \ - -m 'showcases/wireless/(blockack|fragmentation|aggregation)/|examples/wireless/qos/.*-c (MacQosWithBlockAck|MacNonQos)' \ - -f tplx -f '~tNl' -f '~tND' showcases.csv examples.csv -``` - -The delivery commit `53130418de` owns four baseline changes under the maintainer's separate approval. Each first changed operation releases additional complete units when DATA fills a gap. The [S1 source record](../done/ieee80211-compressed-blockack-s1.md) gives exact times and fingerprint values for these configurations: - -- `showcases/wireless/blockack:NoFragmentation`, run 0. -- `showcases/wireless/blockack:MixedTraffic`, run 0. -- `showcases/wireless/fragmentation:HCFfragblockack`, run 0. -- `examples/wireless/qos:MacQosWithBlockAck`, run 0. - -The capacity and BAR commits change no baseline. The final series preserves Basic frame formats, fragment bitmaps, and the ordered `ReleasedFrames` contract. The protected compatibility lookup remains deprecated for one release, as the migration guide states. S1 establishes no lifetime, lifecycle, rate publication, Compressed exchange, or performance result. - -### Branch verification record - -The results below are historical evidence from the VHT/HT branch before S1, the proposed selector, and the Compressed default. They retain their original source and scope limits. The separate S1 record above describes the completed recipient repair. This document revision adds no execution result. - -The review executed these checks on 13 October 2026 at source revision `6aefaef1f01a70134fa8283de708353d4a6d4fd8`. The working directory was `/home/user/omnetpp_ws/inet-ieee80211-vht-ht-support`. The build and all three runner commands returned exit status 0. The fixtures use `General` with seed 0. The module fixture runs scenarios 0 through 6. - -| Executed check | Observed result | Scope limit | -| --- | --- | --- | -| `make MODE=debug -j8` | The debug build passed and reported no further source build work. | This build precedes the proposed implementation. | -| Unit filter `Ieee80211(HtModeSet\|VhtHtCapabilities)_1\.test$` | Both fixtures passed. They require HT operation and local HT capabilities under `ac`. | They do not establish a production Block Ack exchange. | -| Protocol filter `/11ac/Ac_BlockAck\.test$` | The fixture passed its Action, BAR, and Block Ack frame-type assertions. The current BAR and Basic response selected 78 Mbps. | The generic assertions do not prove accepted parameters, complete bitmap semantics, or Compressed operation. | -| Module filter `Ieee80211VhtHtSupport_1\.test$` | The fixture passed all seven scenarios. Full and simplified management supply peer HT state. Scenario 1 removes that state at stop. | It disables Block Ack and therefore supplies capability and control evidence only. Stop also removes association; it is not the proposed fallback stimulus. | - -The exact runner commands follow. Each output redirection preserved the raw runner result in the review directory. - -```sh -inet_run_unit_tests -m debug -f 'Ieee80211(HtModeSet|VhtHtCapabilities)_1\.test$' --log-file /tmp/inet-compressed-blockack-review-20261013/unit.log > /tmp/inet-compressed-blockack-review-20261013/unit-output.txt 2>&1 -inet_run_protocol_tests -p inet -m debug -w '^tests/protocol/wifi$' -f '/11ac/Ac_BlockAck\.test$' --log-file /tmp/inet-compressed-blockack-review-20261013/protocol.log > /tmp/inet-compressed-blockack-review-20261013/protocol-output.txt 2>&1 -inet_run_module_tests -m debug -f 'Ieee80211VhtHtSupport_1\.test$' --log-file /tmp/inet-compressed-blockack-review-20261013/module.log > /tmp/inet-compressed-blockack-review-20261013/module-output.txt 2>&1 -``` - -The original record named generated stdout at `tests/protocol/wifi/work/Ac_BlockAck/test.out` and `tests/module/work/Ieee80211VhtHtSupport_1/test.out`. Those paths refer to the earlier checkout; this checkout contains neither output file. Later execution can replace generated output, and temporary-file cleanup can remove the raw review directory. The commands, source revision, selectors, and result limits above preserve the scope of this historical record. These results replace the obsolete absent-HT premise; they do not verify the proposed lifetime, lifecycle, or Compressed repairs. - -### Source comparison for evidence reuse - -The source comparison covers `6aefaef1f01a70134fa8283de708353d4a6d4fd8` and `c15860de93b3764c3e4ead69c6933fc5ae9ce957`. It found only these changed paths: - -- `WHATSNEW`. -- `doc/src/migration-guide/index.rst`. -- `doc/src/users-guide/ch-80211.rst`. - -The `src`, `tests`, and `bin` tree IDs match between those two historical revisions. Their runtime and test inputs therefore match the recorded behavioral source. This equality does not describe the current source after S1, which changes recipient source, tests, and fingerprints. The structural proof permits reuse only within the earlier checks' stated limits. It adds no Compressed, lifetime, lifecycle, or performance result. - -The comparison ran from the checkout root on 14 October 2026. Both commands returned exit status 0: - -```sh -git diff --name-only 6aefaef1f01a70134fa8283de708353d4a6d4fd8 c15860de93b3764c3e4ead69c6933fc5ae9ce957 -git diff --quiet 6aefaef1f01a70134fa8283de708353d4a6d4fd8 c15860de93b3764c3e4ead69c6933fc5ae9ce957 -- src tests bin .oppfeatures .oppfeaturestate Makefile .envrc -``` - -The first command reports the three documentation paths. The second confirms equality for the selected runtime and test inputs. The three directory tree IDs were also compared directly. No behavioral rerun was necessary solely for this documentation difference. - -The final review will check [the IEEE 802.11 domain rules](../../doc/project/domain/ieee80211.md), [minimal design](../../doc/project/rule/quality.md#qr-design-minimal), and [the plan procedure](../../doc/project/guide/write-an-implementation-plan.md). - -## Appendix B. Standards source notes +## 6. Verification and scope limits -Current-standard canonical clause identifiers use `ieee80211-2024:clause:` followed by the clause number. The IBSS table identifier is `ieee80211-2024:table:9-62`. The main evidence table gives physical PDF pages; printed pages differ by one in those ranges. +The [verification record](ieee80211-compressed-blockack-s4-execution.md) identifies the build, module, unit, protocol, and fingerprint results. Its commands and limits define the evidence scope. The fixture inventory is not itself proof that every fixture ran. -The evidence has these limits: +Basic single protection reserves only prepared successors. Prepared fragments can continue within the applicable exchange bounds. An unextracted successor starts another TXOP. Final zero-limit DATA reserves its immediate required response. Multiple protection retains its successor policy. These rules can increase contention and setup cost. -- IEEE Std 802.11e-2005 is present as `../inet-standards/80211e-2005.pdf`, relative to the repository root. The corpus processor does not register this document. No canonical corpus nodes or resolved reference records exist for it. Direct PDF inspection verifies normative Clauses 7.2.1.7, 7.2.1.8, and 9.10. Physical pages 52–54 and 118–122 correspond to printed pages 30–32 and 96–100. Figures 21b and 21e require visual inspection on physical pages 53 and 54. +The implementation does not supply a general complete-cost admission result for Basic DATA or complete NAV correctness. Current checks establish no general throughput, goodput, latency, or agreement-reuse cost result. MAC stop/start recovery also remains outside the lifecycle contract. - The source SHA-256 is `113625f95796112a44aec95378b79362de1c342ee951df5704521f11d1d227a1`. Basic retention makes no complete historical or current-standard conformance claim. +## Capability gaps -- Current control layouts use `ieee80211-2024:figure:9-47` and `ieee80211-2024:figure:9-53`, on physical pages 719 and 722. Their extracted nodes contain captions; PDF inspection supplies the bit layout. Figure 9-47's reference to Table 9-36 resolves. Tables 9-36 and 9-37 resolve at the canonical identifiers in Section 2. -- The individual-MPDU rule uses normative node `ieee80211-2024:clause:10.25.6.6.2.1`, physical pages 2065–2066. Its source locator is `ieee80211-2024@8602874:8608005`. PDF inspection confirms condition (a)(2)(v) and its continuation. This node has no extracted outgoing references. -- Full-state status uses normative node `ieee80211-2024:clause:10.25.6.3`, physical pages 2060–2061. Its source locator is `ieee80211-2024@8581659:8586175`. PDF inspection confirms its DATA and BAR update rules. This node has no extracted outgoing references. -- Clause 9.2.4.1.6 requires Retry for individual non-A-MPDU DATA. The prior PDF check on physical page 665 confirmed the exception's scope. The reference from Clause 10.23.2.12.1 to Clause 10.3.2.11 resolved. -- The extracted Clause 10.25.6.8 node ends at a figure. The PDF text on physical page 2073 supplies the positive-bit rule after that figure. That rule uses Block Ack start, the active transmit window, addresses, and TID. The shortened node is incomplete evidence. -- Relevant clause references resolved except the out-of-scope NGV reference from Clause 10.25.2 to Clause 31.2.3. This gap supplies no conformance claim for excluded features. +The checkout lacks production Compressed setup and exchanges, a Compressed default, and their integrated rate and timing evidence. Compressed-specific fragmentation restrictions, full-state receipt behavior, profile-conflict diagnostics, and end-to-end recovery therefore have no production support claim here. Existing helper coverage cannot replace those missing paths. diff --git a/plan/pending/ieee80211-compressed-blockack-s4-commits.md b/plan/pending/ieee80211-compressed-blockack-s4-commits.md new file mode 100644 index 00000000000..0fa051e151f --- /dev/null +++ b/plan/pending/ieee80211-compressed-blockack-s4-commits.md @@ -0,0 +1,104 @@ +# S4 commit guide: complete Basic Block Ack transfers + +> **Kind:** reference · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [implementation status](ieee80211-compressed-blockack-replacement.md), [series plan](ieee80211-compressed-blockack-s4-corrections.md) + +The series separates preparation, the Retry correction, and transfer completion. Its final production source retains the reviewed Basic behavior. Protocol tests now observe the independent Retry correction and the complete short-transfer sequence. + +Agreement setup, finite DATA lifetime, filtered queue operations, and recipient teardown delivery come from earlier PRs. The [scope table](ieee80211-compressed-blockack-replacement.md#previous-prs-and-s4-scope) identifies them. + +## P0: Record the correction contract + +This documentation commit defines each commit's responsibility and verification. It adds explicit protocol test tasks before the two behavior changes. It changes no production behavior. + +## P1: Expose DATA preview without extraction + +Before this commit, the shared queue can identify a successor through extraction. Extraction changes ownership and can assign its sequence. BAR selection needs candidate information before those changes. + +After this commit, callers can borrow the next eligible frame and query its prospective sequence. Existing calls retain extraction as their default. The DATA-selection fixture checks queue ownership and the unchanged header. + +For example, queued DATA retains sequence 77 while preview reports prospective sequence 0. The frame stays in its queue. + +```text +Before: queue -> extract -> assign sequence -> inspect candidate +After: queue -> borrow candidate -> inspect prospective sequence + queue ownership and stored sequence remain unchanged +``` + +## P2: Mark DATA retries after failed Block Ack feedback + +Before this commit, the ACK handler already permits retransmission after missing or negative feedback. HCF can transmit that DATA with Retry clear. + +After this commit, HCF sets Retry before Tx receives the retransmitted DATA. Sequence and TID remain unchanged. This correction needs no preview, BAR arbitration, or completion change. + +The [protocol reviewer document](../../tests/protocol/wifi/blockack-data-retry.md) explains the lost-response and negative-bitmap cases. Both use production association and ADDBA. + +```mermaid +sequenceDiagram + participant O as Originator + participant R as Recipient + O->>R: Standalone DATA, Retry = 0 + O->>R: BAR + alt Run 0: feedback loss + R--xO: Block Ack lost at the radio tap + else Run 1: negative feedback + R-->>O: Block Ack with cleared bitmap + end + alt Before P2 + O->>R: Same sequence and TID, Retry = 0 + else After P2 + O->>R: Same sequence and TID, Retry = 1 + end +``` + +## P3: Add shared originator window operations + +Before this commit, the agreement stores its window start but lacks shared operations for the planned callers. After this commit, it also owns cyclic distance, bitmap membership, and advancement. + +No production caller uses those new operations until P4. This preparation changes no packet trajectory. The isolated unit fixture checks wraparound, unresolved positions, and the distinct bitmap boundary. + +For example, an accepted window at 4094 with size four includes 4094, 4095, 0, and 1. Its unresolved sequence 4095 prevents advancement to 0. + +```text +Before: agreement stores start; planned callers need window operations +After: caller supplies unresolved identities -> agreement advances window + caller supplies sequence -> agreement tests membership +``` + +## P4: Complete Basic BAR transfer resolution + +Before this commit, a short group can remain without final feedback. Channel access depends on DATA eligibility. Queue exhaustion or a full window can block completion below the BAR threshold. + +After this commit, HCF selects BAR before DATA extraction and permits BAR-only contention. The ACK policy separates peer/TID groups. Matched feedback resolves the group and permits shared window advancement. When no DATA remains, HCF starts completion DELBA. + +The sequence also limits Basic single protection to prepared successors. Unextracted DATA starts another TXOP. This policy can increase contention and repeated setup. Multiple protection retains its successor policy. + +For example, a one-position window and threshold five permit one outstanding DATA. BAR must resolve that position before another sequence can proceed. + +The [protocol reviewer document](../../tests/protocol/wifi/blockack-transfer-completion.md) explains both completion cases. Existing module fixtures retain expiry, collision, feedback, and timing controls. + +```mermaid +sequenceDiagram + participant O as Originator + participant R as Recipient + Note over O,R: Outstanding DATA below threshold five + Note over O: Queue empty or transmit window full + alt Before P4 + Note over O,R: No final feedback, transfer cannot complete + else After P4 + O->>R: BAR for the selected peer and TID + R-->>O: Matched Block Ack + Note over O: After all DATA resolves and none remains + O->>R: Completion DELBA + R-->>O: ACK + end +``` + +## P5: Describe current behavior and evidence + +This documentation commit distinguishes inherited prerequisites from S4 changes. It records each changed fingerprint row's cause and acceptance. It separates fresh execution from source equality and earlier evidence. + +## Evidence and limits + +The [verification record](ieee80211-compressed-blockack-s4-execution.md) supplies commands, source identities, and results. The protocol comparison records use identical test inputs on each behavior change and its parent. + +Basic remains the default compatibility profile. Compressed exchanges, A-MPDU, general Basic DATA admission, and complete NAV conformance remain outside this PR. diff --git a/plan/pending/ieee80211-compressed-blockack-s4-corrections.md b/plan/pending/ieee80211-compressed-blockack-s4-corrections.md new file mode 100644 index 00000000000..cbb38e21837 --- /dev/null +++ b/plan/pending/ieee80211-compressed-blockack-s4-corrections.md @@ -0,0 +1,67 @@ +# S4 correction series + +> **Kind:** reference · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [implementation status](ieee80211-compressed-blockack-replacement.md) + +This series corrects the four findings from the audit of PR #1344. It preserves the final production source at `b716709335f79817542554822279461e61949938`. It adds protocol tests and their explanations. It separates Retry from transfer completion and places shared arithmetic before its callers. + +## Scope and contract + +HCF must set Retry when it retransmits standalone DATA after failed Block Ack feedback. IEEE Std 802.11-2024, 9.2.4.1.6 supplies this requirement. The parent ACK handler already makes that DATA eligible. The correction changes its header before Tx receives it. + +HCF must resolve a final short transfer even without another DATA candidate. IEEE Std 802.11-2024, 10.25.4 requires completion DELBA. Basic remains an INET compatibility profile. This series does not claim complete current-standard Basic support. + +The originator agreement owns cyclic distance, bitmap membership, and window advancement. HCF supplies unresolved identities. The final source already follows this contract. Only its introduction order changes. + +## Proposed commits + +### P0: Record the correction contract + +Add this plan before the implementation commits. The document defines their responsibility, test tasks, and evidence limits. No protocol behavior changes. Protocol tests and a protocol reviewer document do not apply to this documentation commit. Check relative links and series rules. + +### P1: Expose DATA preview without extraction + +Retain the existing preview commit after P0. `IOriginatorQosMacDataService` exposes borrowed preview and prospective sequence lookup. `InProgressFrames` retains extraction as its default. The DATA-selection module fixture checks queue ownership, the unchanged header, and prospective sequence zero. + +This structural commit changes no protocol behavior. New protocol tests and a protocol reviewer document do not apply. Build debug artifacts and run `Ieee80211BlockAckDataSelection_1.test`. + +### P2: Mark DATA retries after failed Block Ack feedback + +The parent can retransmit DATA with Retry clear after a BAR timeout or negative bitmap feedback. HCF already reads ACK status. Move the existing Retry branch into this independent commit. It changes no candidate selection, agreement completion, or reservation policy. + +Add `tests/protocol/wifi/common/WifiBlockAckDataRetry.test`. Start with real association and production ADDBA. Send a continuous UDP stream through the existing infrastructure topology. Disable A-MSDU aggregation. Drop the first Block Ack to sta1 through the radio tap in run 0. Clear its bitmap in run 1. Capture the first Block Ack DATA sequence and TID before BAR. Require retransmission of that same identity with Retry set after BAR. The existing protocol suite has no direct check of this exact path. + +The same fixture must fail before P2 because HCF leaves Retry clear. It must pass after P2 because HCF changes the transmitted header. Add the reviewer document `tests/protocol/wifi/blockack-data-retry.md` with P2. Add a guide and a before/after record under `doc/project/evidence/model/wifi/tests/`. Keep the failure honest; add no expected-failure declaration. + +Build debug artifacts. Run `inet_run_protocol_tests -p inet -m debug -w '^tests/protocol/wifi$' -f 'WifiBlockAckDataRetry\.test$'`. Use seed 0. Check the seven existing changed fingerprint cases to determine P2's exact effects. The user approved five intermediate `~tND` values on 2026-10-22. Adopt those values with P2. Restore the accepted final values with P4. + +### P3: Add shared originator window operations + +Add the final agreement operations before their production callers. Move direct arithmetic assertions into a separate unit fixture. The operations have no production caller until P4. This preparation changes no packet trajectory. New protocol tests and a protocol reviewer document do not apply. Build debug artifacts and run the focused window unit fixture. + +### P4: Complete Basic BAR transfer resolution + +Apply the remaining behavior change through the shared agreement operations. HCF selects BAR before extraction. EDCA permits BAR-only contention. Matched feedback resolves the selected group. Final resolution or expiry starts DELBA. Duration forecasts reserve prepared successors only. + +Add `tests/protocol/wifi/common/WifiBlockAckTransferCompletion.test`. Use real association, production ADDBA, and a finite UDP burst. Run a two-packet burst with an accepted window of 64 and a four-packet burst with a window of one. Keep the BAR threshold at five. Observe ADDBA success, Block Ack DATA, BAR, matched Block Ack, completion DELBA, and its ACK. The empty queue triggers the first case. A full window triggers the second case before further DATA. Existing module fixtures cover these paths, but no protocol fixture checks this complete sequence. + +The fixture must fail before P4 because a short group lacks BAR or completion DELBA. It must pass after P4 through the production owners. Add `tests/protocol/wifi/blockack-transfer-completion.md` with P4. Add its guide and before/after record under `doc/project/evidence/model/wifi/tests/`. Use seed 0. Make no unsupported performance claim. + +Build debug artifacts. Run both new protocol files through explicit filters. Run the seven changed module files and two existing unit files. Compare the seven fingerprint cases with P2 and the pinned final source. Attach each baseline change to its causal behavior commit. Preserve the final approved values. + +The wider protocol selection also checks existing lifecycle fixtures. `WifiBlockAckBarWithoutAgreement.test` must retain its control agreement until the crafted BAR. Hold station contention at 1.002 seconds while queued DATA remains. This prevents completion before the 1.1-second probe without an agreement-state edit. Retain its response assertions. + +The parent passes `WifiBlockAckSameApReassociation.test`, while S4's completion changes its traffic context. Overlap both traffic directions at 6 Mbit/s. Request reassociation at 1.008 seconds, before completion removes the old agreements. Extend fresh traffic until 1.4 seconds. Check fresh roles at 1.38 seconds. Keep the four-role, zero-role, fresh-setup, and UDP-delivery assertions. Disable Block Ack on sta2 and use small downlink packets to isolate the target link's agreements. Permit coincident transmissions as a warning because bidirectional contention can create them. This diagnostic setting changes no reception calculation. + +### P5: Describe the corrected series and evidence + +Update the current implementation documents, commit guide, protocol inventory, and verification record. Give each changed fingerprint row its cause and values. Distinguish fresh execution, source equality, existing evidence, and unavailable approval records. Do not assert an approval whose source is absent. + +This documentation commit changes no protocol behavior. New protocol tests and a protocol reviewer document do not apply. Check links, document structure, series gates, source equality, and the final focused test contract. + +## Verification limits + +The proposed tests observe production MAC exchanges. The radio tap drops feedback only in the Retry test. No fixture supplies an accepted agreement. One fixed seed checks these deterministic paths; it does not establish probabilistic robustness. + +Run each new fixture against its behavior commit and that commit's parent with identical inputs. Keep runtime failure separate from build or setup failure. Render diagrams when a local renderer is available. Report unavailable rendering directly. + +The final source and final existing fingerprint values must equal the pinned source. New tests and documents are the intended final-tree additions. No baseline approval follows from permission to repair source or history. diff --git a/plan/pending/ieee80211-compressed-blockack-s4-execution.md b/plan/pending/ieee80211-compressed-blockack-s4-execution.md new file mode 100644 index 00000000000..581cc6bfa53 --- /dev/null +++ b/plan/pending/ieee80211-compressed-blockack-s4-execution.md @@ -0,0 +1,107 @@ +# Basic Block Ack transfer completion: current verification + +> **Kind:** reference · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [implementation status](ieee80211-compressed-blockack-replacement.md), [correction plan](ieee80211-compressed-blockack-s4-corrections.md) + +The final production source passes debug and release compilation, seven module files, three unit files, seven protocol files, and seven fingerprint cases. The verified `src` tree is `20aade533739a1877a87391909da7dd2a91c79c7`. The correction preserves that production tree and the accepted final fingerprint rows. It adds direct protocol evidence and separates the commit responsibilities. + +## Behavior and ownership + +HCF selects due Basic BAR work before DATA extraction and can contend without queued DATA. The ACK policy separates outstanding DATA by peer and TID within the accepted window. Below the threshold, it defers BAR only for the next eligible DATA in that group and window. + +For example, a window of one and a BAR threshold of five leave one DATA outstanding. The next sequence lies outside the window. HCF sends BAR. Positive feedback resolves that DATA and permits window progress. With no queued or numbered DATA at a safe exchange boundary, HCF queues completion DELBA. + +The originator agreement owns cyclic distance, bitmap membership, and window advancement. HCF supplies unresolved identities. BAR failure updates contention without a DATA retry charge. DATA retransmission sets Retry after failed feedback. Lifetime expiry can resolve outstanding positions and trigger completion teardown. + +Basic single protection reserves only prepared successors. Unextracted DATA starts another TXOP. Duration prediction borrows candidates without extraction. The [migration section](../../doc/src/migration-guide/development/ieee80211-basic-block-ack-extension-points.rst) defines the custom data-service and policy contracts. + +The [scope table](ieee80211-compressed-blockack-replacement.md#previous-prs-and-s4-scope) separates inherited lifecycle and recipient behavior from S4. These results describe the integrated source. They do not establish separate results for prerequisite PR heads. + +## Direct protocol evidence + +The [Retry comparison](../../doc/project/evidence/model/wifi/tests/blockack-data-retry-comparison.md) records lost-feedback and negative-bitmap cases. Both fail at the Retry predicate on the pinned base. Both pass with only HCF's Retry branch. The tests retain the captured sequence and TID across retransmission. + +The [completion comparison](../../doc/project/evidence/model/wifi/tests/blockack-transfer-completion-comparison.md) records queue exhaustion and a one-position window. Both fail before transfer completion. Both pass through BAR, matched feedback, completion DELBA, and ACK on the final source. Neither fixture supplies an accepted agreement. + +The wider protocol selection also checks duplicate ADDBA, dialog tokens, BAR without an agreement, inactivity, and same-AP reassociation. Two inherited fixtures need traffic controls because S4 completes agreements earlier. Their guides describe those controls. All seven files pass in `/tmp/pr1344-correction-final-protocol.log`. + +## Executed final checks + +| Check | Result | Scope | +| --- | --- | --- | +| Debug compilation | PASS | Final production source. | +| Release compilation | PASS | Final production source; no release runtime campaign. | +| Module tests | Seven files PASS | Completion cost, selection, scheduling, deferral, retirement, headers, and protection. | +| Unit tests | Three files PASS | Scheduling, shared window operations, and multiple protection. | +| Protocol tests | Seven files PASS | Thirteen seed-0 simulation runs; four runs exercise the new fixtures. | +| Fingerprints | Seven cases PASS | Existing non-graphical values; 274.663 seconds. | + +The final module log is `/tmp/pr1344-correction-final-modules.log`. The unit log is `/tmp/pr1344-opp-repl-final-contract-v2.log`. The fingerprint log is `/tmp/pr1344-correction-final-fingerprint.log`. Local `/tmp` artifacts can be absent in another checkout. + +These commands run from the checkout root: + +```sh +make MODE=debug -j12 +make MODE=release -j12 +inet_run_module_tests -m debug -f '(Ieee80211BlockAckCompletionCost_1|Ieee80211BlockAckScheduling_1|Ieee80211BlockAckDataSelection_1|Ieee80211BlockAckDeferral_1|Ieee80211BlockAckFragmentRetirement_1|Ieee80211HcfHeader_1|Ieee80211HcfMultipleProtection_2)\.test$' +inet_run_unit_tests -m debug -f '(Ieee80211OriginatorBlockAckWindow_1|Ieee80211BlockAckScheduling_1|Ieee80211MultipleProtection_1)\.test$' +inet_run_protocol_tests -m debug -w '^tests/protocol/wifi$' -f 'WifiBlockAck(DataRetry|TransferCompletion|DuplicateAddba|DialogToken|BarWithoutAgreement|Inactivity|SameApReassociation)\.test$' +``` + +The fingerprint command runs from `tests/fingerprint`: + +```sh +./fingerprinttest -d -F tyf -t 3 -m 'showcases/wireless/blockack/|showcases/wireless/fragmentation/.*-c HCFfragblockack |showcases/wireless/txop/|examples/adhoc/qos/.*-c MacQos -r 1|examples/wireless/qos/.*-c MacQosWithBlockAck ' showcases.csv examples.csv +``` + +The CSV files supply each run, seed, limit, and computed-FCS setting. Graphical `tyf` values remain excluded. + +## Commit verification contract + +The [six-commit plan](ieee80211-compressed-blockack-s4-corrections.md) requires an incremental debug build at each output commit. The retained control worktree reuses compatible objects. The `opp_repl` selection uses the checkout's explicit `inet_project` instance. + +| Commit | Direct selection | +| --- | --- | +| P0: correction contract | Existing multiple-protection unit fixture. | +| P1: preview | DATA-selection module fixture. | +| P2: Retry | Retry protocol fixture; seven fingerprints with five approved intermediate values. | +| P3: shared arithmetic | New window unit fixture and unchanged Retry protocol fixture. | +| P4: completion | Both new protocol fixtures, three unit files, and seven module files. | +| P5: current documents | Both new protocol fixtures and the final related selection. | + +The execution log under `ai-logs/executions/2026-10-22_pr1344-corrections.md` records exact safe points and results. That directory is local workflow state. It does not form portable test evidence by itself. + +## Fingerprint causes and acceptance + +The final source retains the seven accepted non-graphical baseline rows. The original S4 execution record states that the user approved these values on 2026-10-15. Its immutable source is commit `18bba0a41ab8c00aefaeca7de233fd68cbc4ee7f`, before the current documentation replacement. This correction restores that acceptance record. It grants no approval for a new intermediate value. + +| Configuration and run | Final fingerprints | Cause | +| --- | --- | --- | +| Block Ack `NoFragmentation`, run 0 | `9161-625d/tplx;6a02-09aa/~tNl;cbc0-3b0a/~tND` | Final Normal Ack DATA reserves its immediate ACK. Setup and BAR order also change. | +| Block Ack `Fragmentation`, run 0 | `36f4-5c22/tplx;66b0-94cd/~tNl;45f3-af4f/~tND` | Final Block Ack DATA reserves zero. BAR obtains a separate TXOP. | +| Block Ack `MixedTraffic`, run 0 | `351b-d4ba/tplx;5c1f-69a8/~tNl;6182-6da3/~tND` | The current reservation excludes an unextracted large successor. Agreement setup can precede that DATA. | +| Fragmentation `HCFfragblockack`, run 0 | `2597-1e2e/tplx;d269-c6ae/~tNl;2f5c-4cca/~tND` | Retransmitted DATA sets Retry after failed feedback. The final burst boundary also changes. | +| TXOP `General`, run 0 | `ab91-87f3/tplx;f30c-6aa4/~tNl` | HCF excludes an unextracted successor from the reservation. The frame sequence ends at that same boundary. | +| Ad hoc `MacQos`, run 1 | `4fd2-bb56/tplx;ecaf-89f7/~tNl;9398-0fae/~tND` | Final Normal Ack DATA reserves SIFS plus ACK. Further extraction requires another TXOP. | +| Wireless `MacQosWithBlockAck`, run 0 | `6edb-0326/tplx;2a8a-50ee/~tNl;4301-882d/~tND` | ADDBA reserves its immediate ACK without unrelated queued DATA. Later extraction can change aggregation. | + +The causal behavior commit must name these rows and their causes. A matching fingerprint checks the recorded trajectory. Direct protocol and module assertions establish the specific correctness claims. + +## Intermediate fingerprints + +The user approved five intermediate `~tND` values on 2026-10-22. They belong to the isolated Retry commit. All seven event and packet-length fingerprints remain equal to their parent values. TXOP General and ad hoc MacQos run 1 retain every selected value. + +| Configuration | Parent `~tND` | Retry-only `~tND` | +| --- | --- | --- | +| Block Ack NoFragmentation | `2cd4-4795` | `0f38-6042` | +| Block Ack Fragmentation | `feff-7e88` | `ddec-9e3d` | +| Block Ack MixedTraffic | `9724-d1ce` | `2839-8753` | +| Fragmentation HCFfragblockack | `c474-7174` | `bbe5-0771` | +| Wireless MacQosWithBlockAck | `538e-67df` | `1914-cd4d` | + +Each row uses run 0. Retransmitted Block Ack DATA changes its Retry header and computed FCS. The later completion commit replaces these intermediate values with the accepted final rows above. The final CSV files remain byte-identical to the original PR head. + +## Limits + +Basic remains the operational profile and default. HCF rejects Compressed selection during initialization. General Basic DATA admission, complete NAV conformance, A-MPDU, delayed Block Ack, and Multi-TID Block Ack remain outside this claim. + +A fixed seed establishes these deterministic exchange paths. It does not establish probabilistic robustness or performance. Build and mechanical gate passes do not establish protocol correctness. Local verification supplies no CI result for a new commit. The correction self-check does not replace an independent review. diff --git a/plan/pending/ieee80211-edca-data-lifetime.md b/plan/pending/ieee80211-edca-data-lifetime.md index 45f8db4540e..caf97ef4cb8 100644 --- a/plan/pending/ieee80211-edca-data-lifetime.md +++ b/plan/pending/ieee80211-edca-data-lifetime.md @@ -1,111 +1,57 @@ -# Implementation plan: enforce EDCA DATA lifetime +# EDCA DATA lifetime contract -Original source observation revision: `feat/ieee80211-txop-single-protection` at `b06e8768b0e9c78b7a3665b9c69b0e0da9f30e41`. -Current integration source: local `master` at `633b071e213b825ce6019ff3e344ae49f52791ff`, with S1, R1, and S3a merged. -Plan revision: 2026-10-15, revision 11. -Source basis: IEEE Std 802.11-2024 and the revisions above. Source observations do not establish runtime results. +> **Kind:** reference · **Status:** current · **Seal:** none · **Owns:** — · **Stands on:** [lifetime handler](../../src/inet/linklayer/ieee80211/mac/lifetime/EdcaTransmitLifetimeHandler.cc), [HCF](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) -Approval: the maintainer's 14 October 2026 instruction, "proceed", after the revision-24 review authorizes the earlier document corrections. The maintainer's later explicit decision accepts the proposed 0.512-second DATA lifetime default. This decision selects the default and authorizes its record in the plan. These instructions authorize no implementation, recorded expectation change, or publication. +HCF enforces a finite deadline for every QoS DATA frame that it accepts. This contract applies with Block Ack enabled or disabled. DCF lifetime, complete management lifetime, and MAC stop/start recovery remain outside the contract. -The [completed S1 record](ieee80211-compressed-blockack-replacement.md#completed-s1-and-recorded-verification) supplies Basic recipient capacity and ordered delivery. PR #1320 is merged in the integration source. Its original feature-head evidence establishes no fresh runtime result for main or S2 expiration. Lifetime observations retain `b06e8768` until the separate S2 review refreshes them against its selected parent. +## Previous PRs and S4 scope -Revision 11 updates the integration pin for merged R1 and S3a. Their completion does not establish S2 completion. The [umbrella source record](ieee80211-compressed-blockack-replacement.md#source-base-and-publication-boundaries) distinguishes the integration source from this checkout's separate S2 implementation and local edits. This review adds no runtime result or implementation authority. +Merged [PR #1331](https://github.com/inet-framework/inet/pull/1331) supplies the lifetime mechanism described here. It includes identity-based deadlines, the 0.512-second default, expiry, fragment and aggregate rules, and safe completion across expiry. Merged [PR #1343](https://github.com/inet-framework/inet/pull/1343) uses that deadline during agreement setup and teardown recovery. These mechanisms are already present in S4's master base. -## 1. Core intended behavior +This S4 branch, [PR #1344](https://github.com/inet-framework/inet/pull/1344), connects lifetime disposal to transmit-window advancement and final-transfer completion. HCF removes resolved positions without sequence reuse. If the final unresolved DATA expires and no DATA remains, HCF can start completion DELBA at a safe exchange boundary. -HCF, the hybrid coordination function, will enforce a finite lifetime for all QoS DATA. This lifetime applies with either value of `isBlockAckSupported`. EDCA means enhanced distributed channel access. An EDCAF is an EDCA function that serves one access category. +The recipient's complete-unit release on ordinary teardown comes from PR #1343. S4 supplies the final-expiry trigger that reaches that existing path. S4 does not change the lifetime default, restart retry deadlines, or introduce another lifetime store. The [main scope table](ieee80211-compressed-blockack-replacement.md#previous-prs-and-s4-scope) gives the wider implementation boundary. -An MSDU is the data unit that the MAC receives from its service user. An A-MSDU combines several MSDUs inside one MPDU. An MPDU is a MAC frame with its header and frame check sequence. +## 1. Core behavior -This prerequisite supplies the disposal bound for [Block Ack agreement recovery](ieee80211-blockack-agreement-lifecycle.md) and [Compressed Block Ack retransmission](ieee80211-compressed-blockack-replacement.md). It also applies to Normal Ack DATA without an agreement. A Block Ack capability switch will not select whether DATA has a lifetime. +The per-EDCAF parameter `msduLifetime` defaults to 0.512 seconds. Queue residence, setup deferral, retries, and ACK-policy changes consume that deadline. The parameter requires a positive, finite value that simulation time can represent. Zero, negative, and nonfinite values fail initialization. There is no unlimited mode. -Hypothetical example: HCF accepts QoS DATA at 0 s with the default 0.512-second lifetime. Contention prevents transmission before 0.7 s. HCF discards that DATA at its deadline, with Block Ack support either enabled or disabled. DATA that Tx already accepted follows the safe-completion rule below. - -DCF lifetime and complete management-frame lifetime remain outside this change. The current MAC stop and crash handlers do not reset all child state. This plan makes no stop/start recovery claim. +Hypothetical example: HCF accepts DATA at zero seconds and channel access remains blocked until 0.7 seconds. The default deadline expires at 0.512 seconds. A one-second lifetime permits an attempt after channel access resumes, subject to other eligibility and disposal rules. ## 2. Current source and standard support -[EdcaTransmitLifetimeHandler](../../src/inet/linklayer/ieee80211/mac/lifetime/EdcaTransmitLifetimeHandler.cc) stores start times by sequence number. Two peers can therefore share one key. Its current start point excludes queue residence. EDCA does not construct or call this handler in the inspected source. - -[Edcaf.ned](../../src/inet/linklayer/ieee80211/mac/channelaccess/Edcaf.ned) has no `msduLifetime` parameter. HCF and the QoS data service own the entry and replacement paths that must supply lifetime identity. - -IEEE Std 802.11-2024 Clause 10.23.2.12.1 requires the relevant QoS transmit timers. Its scope does not depend on Block Ack support. Clause 10.25.6.7.1 supplies the related Block Ack retransmission conditions. Their normative corpus identifiers are `ieee80211-2024:clause:10.23.2.12.1` and `ieee80211-2024:clause:10.25.6.7.1`. Physical PDF pages are 2016–2017 and 2068–2070. - -Normative Annex C.3 defines `dot11EDCATableMSDULifetime` for non-AP stations and `dot11QAPEDCATableMSDULifetime` for APs. Both attributes use TU and default to 500. One TU is 1024 microseconds, so 500 TU equals 0.512 seconds. Their physical PDF pages are 5418 and 5420. The canonical node is `ieee80211-2024:clause:C.3`; source offsets are 22781782 and 22790375. Corpus text supplied both values without PDF inspection; the retrieved Clause 10.23.2.12.1 reference to Clause 10.3.2.11 resolved. - -The implementation must reproduce missing queue expiration through production HCF before it changes that path. Source inspection establishes the absent integration; it does not establish a measured loss or delay. - -## 3. Proposed ownership and behavior - -The current `EdcaTransmitLifetimeHandler` will own deadlines for QoS DATA regardless of HCF Block Ack support. EDCA will construct this owner from a positive, finite `msduLifetime` parameter on each EDCAF. The accepted default is 0.512 seconds, which matches the standard's 500-TU defaults for AP and non-AP stations. The compatibility record below identifies its acceptance and effect. HCF will register DATA when `processUpperFrame` accepts it, before queue insertion or sequence assignment. The deadline therefore includes queue residence and setup deferral. - -Management exchanges retain their existing retry procedure. This change does not claim complete management-lifetime support. - -The parameter uses seconds and permits other positive, finite values within the supported simulation-time range. Initialization will reject zero, negative, and nonfinite values. Each configured value supplies a DATA deadline; it does not guarantee prompt recovery or expiry within the simulation duration. A large value can postpone lifetime disposal beyond the end of a run. This plan provides no unlimited mode because unresolved DATA must retain a deadline when no earlier disposal or successful exchange resolves it. - -For compatibility studies, users can select a finite lifetime longer than their simulation duration. Hypothetical example: `**.mac.hcf.edca.edcaf[*].msduLifetime = 100s` prevents lifetime expiry for newly accepted DATA during a 10-second run. This proposed setting does not promise unchanged fingerprints or complete legacy behavior. Response acceptance, teardown, queue loss, and terminal failure can still resolve or discard DATA earlier. A recovery path that relies on lifetime expiry inherits the configured delay. - -### Lifetime compatibility decision - -The standards basis establishes the timer's scope and the 500-TU default. It does not measure the effect on current INET simulations. New disposal can occur with Block Ack disabled when retained DATA reaches its deadline. Congestion alone does not prove that a retained frame reaches that age. - -On 14 October 2026, the maintainer explicitly accepted the proposed 0.512-second default. The value matches the 500-TU standards basis and supplies a finite disposal deadline. This acceptance includes the proposed scope with Block Ack disabled. It permits new disposal when retained QoS DATA reaches its deadline. The compatibility decision before L1 is satisfied. Source review, production reproduction, and measured expiry remain required by S2. - -An opt-in or unlimited compatibility mode would require a separate design. That design must state its standards limits and supply another finite disposal bound wherever Block Ack recovery requires progress. This plan retains a finite lifetime and the long-finite compatibility setting above. - -### Deadline ownership and safe completion - -The handler will key retained deadlines by local packet identity, not sequence number. The QoS data service will transfer this identity information when it replaces source frames with an A-MSDU or fragments. Fragments share their source MSDU deadline. Each MSDU addition restarts the aggregate timer under Clause 10.23.2.12.1. Retransmission and ACK-policy selection will not restart a deadline. Queue discard, acknowledgment, teardown, and peer cleanup will remove the corresponding lifetime entries. - -The [current aggregate builder](../../src/inet/linklayer/ieee80211/mac/aggregation/MsduAggregation.cc) adds its inputs synchronously at one simulation time. Its aggregate deadline therefore uses that construction time and the applicable AC lifetime. - -Hypothetical example: an MSDU arrives at 0 seconds and joins an A-MSDU at 0.4 seconds under Normal Ack. This example has no active Block Ack agreement and no pending setup or teardown for that peer and TID. With a 0.512-second lifetime, the aggregate deadline is 0.912 seconds. The original 0.512-second deadline must not discard that aggregate. Queue expiry must remove already expired inputs before aggregation; aggregation cannot revive them. - -This repair will add narrow operations to the concrete EDCA lifetime owner. It needs no change to DCF's lifetime interface. HCF will create one timer for the earliest DATA deadline across its EDCA queues and release it at destruction. Queue owners will remove expired DATA and its ACK state before further selection. HCF will also check the deadline before submission to Tx, including any proposed IFS delay. No DATA transmission may start after that deadline. +[Edca](../../src/inet/linklayer/ieee80211/mac/channelaccess/Edca.cc) owns the lifetime handler. [HCF](../../src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc) registers QoS DATA before queue insertion and uses one timer for the earliest deadline. The queue owner removes expired frames. HCF clears their acknowledgment and recovery state. -An accepted transmission can complete after its deadline; HCF will retain the referenced frame until its current exchange completes. Expiration will prohibit another attempt and trigger disposal at that safe boundary. HCF will not delete a frame that Tx or the frame sequence still references. The lifetime owner will exclude that expired retained entry from its next timer selection. A successful response to the accepted attempt can still acknowledge it. +IEEE Std 802.11-2024 Clause 10.23.2.12.1 covers QoS transmit lifetime. Clause 10.25.6.7.1 supplies related Block Ack retransmission conditions. Annex C.3 supplies 500 TU defaults through `dot11EDCATableMSDULifetime` and `dot11QAPEDCATableMSDULifetime`. The conversion is 500 TU = 0.512 seconds. These references define the requirement basis; this document adds no standards retrieval result. -Hypothetical example: every response reports DATA 100 as absent but acknowledges later DATA. DATA 100 remains eligible until its original deadline, even while successful Block Ack responses refresh agreement inactivity. At expiration, HCF discards DATA 100 and advances the transmit window from resolved status. Later DATA or BAR can advance the recipient past that gap. No inactivity refresh can extend DATA 100's lifetime. +## 3. Implemented ownership and behavior -## 4. Separate implementation stages +The handler keys deadlines by local frame identity. Two peers can use the same sequence number without a shared deadline. The QoS data service clears borrowed source references before source deletion. Fragments retain their source deadline. Retransmission and ACK-policy changes do not restart it. -| Stage and purpose | Responsible component and change | Expected result and direct verification | -| --- | --- | --- | -| L1. Establish lifetime identity. | The lifetime handler stores local packet identities. The QoS data service transfers deadlines across frame replacement. Add the EDCAF parameter with unit seconds and default 0.512 seconds. | Two peers with identical sequence numbers retain separate deadlines. Fragments share the source deadline. A-MSDU construction follows the specified lifetime rule. Invalid lifetime values fail at initialization. | -| L2. Enforce expiration through HCF. | HCF registers DATA before queue insertion. Queue owners remove expired DATA. HCF prevents another attempt after expiration and preserves accepted exchanges until completion. | Production tests expire queued Normal Ack DATA with both Block Ack switch values. Expiration during an accepted exchange causes no premature deletion or later retry. | -| L3. Integrate consumers and document compatibility. | Agreement recovery and Compressed retransmission consume the same deadlines after their respective stages exist. Update user documentation and migration guidance. | Deferred setup and repeated Block Ack failures cannot extend a deadline. Ordinary EDCA users can select a suitable lifetime without enabling Block Ack. | +A new A-MSDU starts a deadline at aggregate construction. The current builder adds all sources at one simulation time. Only tracked sources participate in lifetime replacement, including when `qOsCheck=false` permits non-QoS or mixed sources. A new QoS aggregate receives its own deadline even when no source was tracked. Expired inputs cannot enter an aggregate. -L1 and L2 form the publishable lifetime change in umbrella stage S2. Their commits must build and expose no unused public contract. L3 integration tests accompany the consumers that introduce those paths; they do not block standalone Normal Ack verification. +Hypothetical example: an MSDU accepted at zero seconds joins an A-MSDU at 0.4 seconds without an active or pending agreement. The new aggregate expires at 0.912 seconds. Its source deadline was 0.512 seconds. An expired input cannot receive this extension. Uncertain setup prevents aggregation that could restart the deferred batch's deadlines. -The lifetime compatibility decision for L1 is accepted at 0.512 seconds. Before S2 starts, refresh the older source observations and caller assessment against its pinned parent. The [umbrella decision table](ieee80211-compressed-blockack-replacement.md#maintainer-decisions) records that acceptance and the independent stage boundaries. +### Compatibility setting -Finite lifetime changes Block Ack-disabled EDCA simulations as well as Block Ack-enabled simulations. Affected callers include the single-protection path, the QoS and aggregation showcases, and the `MacQos` examples. Queue residence can now cause disposal before any transmission. User documentation must state the default, parameter location, and the compatibility setting and limits above. It must distinguish aggregation's timer restart from retransmission and ACK-policy changes, which do not restart the deadline. No number of changed fingerprints is assumed before measurement. +For a ten-second study, `**.mac.hcf.edca.edcaf[*].msduLifetime = 100s` prevents lifetime expiry of newly accepted DATA during that interval. Acknowledgment, teardown, queue loss, and terminal failure can still remove DATA. This setting guarantees neither identical fingerprints nor complete compatibility. Recovery that depends on expiry inherits the longer delay. -## 5. Verification and evidence +### Deadline and safe completion -Add a proposed `tests/module/Ieee80211EdcaDataLifetime_1.test` for production expiration and safe completion. Add focused helper assertions for identity transfer only where the production fixture cannot expose the necessary state. +HCF checks the deadline before submission to Tx, with the proposed IFS. No new DATA attempt can start at or after the deadline. An accepted attempt can finish across it and receive successful acknowledgment. -Use these direct cases: +HCF retains referenced frames until exchange cleanup releases the context. It prevents another attempt and excludes expired retained entries from timer selection. This permits safe completion without repeated zero-time expiration events. -- Check the 0.512-second default for AP and non-AP EDCA. Reject zero, negative, and nonfinite values. Confirm that another positive, finite value controls expiration. -- Accept DATA before queue insertion. Hold channel access beyond its deadline. Check disposal without transmission for both Block Ack switch values. -- Give two peers the same TID and sequence number. Expire one frame. Check that the other frame retains its own deadline. -- Aggregate DATA. Fragment separate DATA. Check the resulting deadlines against Clause 10.23.2.12.1. -- A-MSDU extension: Use a peer and TID with no active Block Ack agreement or pending setup or teardown. Accept an MSDU at 0 seconds with a 0.512-second lifetime. Aggregate it under Normal Ack at 0.4 seconds. Hold the aggregate without transmission. Check retention past 0.512 seconds and expiry at 0.912 seconds. -- Expired aggregation input: Expire an input before aggregation. Check that the expired input cannot enter the aggregate. -- Long finite lifetime: Select a 100-second lifetime for a 10-second run. Check that newly accepted DATA does not expire through lifetime during that run. Check earlier acknowledgment and disposal paths separately. Do not treat a matching delivery result as proof of unchanged fingerprints. -- Expire DATA before a proposed IFS ends. Check that HCF rejects submission before transmission can start after expiration. -- Expire DATA during an accepted exchange. Permit its completion. Check that HCF retains references safely and prohibits another attempt. -- Dispose of queued DATA. Acknowledge other DATA. Reset a peer. Check removal of lifetime entries without changes to another peer. +## 4. Agreement integration -The [replacement plan's verification scope](ieee80211-compressed-blockack-replacement.md#6-verification-and-scope-limits) supplies the common regression selection and the current S1 recipient fixture. Retain all eight Basic recipient scenarios as regression checks. Include the Block Ack-disabled EDCA rows because this prerequisite changes their supported behavior. Compare each stage with its pinned parent before any baseline proposal. S1's recorded 12-configuration result does not verify S2's proposed 19-row selection or its measured expiration requirement. +Setup and DELBA recovery consume the existing DATA deadline. HCF advances the transmit window when lifetime disposal resolves an outstanding position. It uses the same identity owner rather than a separate agreement lifetime store. -Measure delivered DATA, lifetime disposal, queue delay, and completion delay under controlled congestion. Keep traffic, seed, rates, and channel conditions identical across the comparison. Record the lifetime value and Block Ack switch for each run. A short run without expiration cannot prove this behavior. +Final expiry can trigger completion DELBA even when the recipient still holds acknowledged complete units behind a gap. Ordinary recipient teardown delivers those complete units before resource release. Association reset discards old buffered units instead. The [lifecycle contract](ieee80211-blockack-agreement-lifecycle.md#recipient-buffer-disposition-at-teardown) defines these separate outcomes. -S2 requires at least one Block Ack-disabled congestion case that demonstrates the default lifetime boundary. Select a common regression row only if measured frame ages establish that condition. Otherwise, add a controlled congestion variant with its parameters and parent comparison recorded separately. Record each affected frame's MAC acceptance time, disposal time, age, and disposal cause. Separate lifetime disposal from queue-capacity loss and retry-limit loss. +Hypothetical example: repeated Block Ack feedback leaves DATA 100 unresolved. Its original deadline expires despite agreement activity. HCF clears its transmit state and permits window progress without sequence reuse. With no further DATA, completion teardown can release complete recipient units behind that gap. -The [QoS showcase](../../showcases/wireless/qos/omnetpp.ini) offers approximately 57.7 Mbps of application payload against a configured 54 Mbps radio rate. Its [pending queues](../../src/inet/linklayer/ieee80211/mac/queue/PendingQueue.ned) default to 100 frames. That offered load does not prove that a retained frame reaches 0.512 seconds of age. The [MacQos example](../../examples/wireless/qos/omnetpp.ini) selects unlimited pending queues, but this setting alone does not prove sufficient delay. Neither configuration supplies measured expiry evidence in this plan. +## 5. Verification and limits -Compare the parent without expiration, the 0.512-second default, and an explicit one-second setting under the same congestion. Hypothetical example: unaggregated DATA waits 0.7 seconds before channel access. The default discards it; the one-second setting still permits an attempt. This comparison measures the compatibility cost without an unlimited production mode. +The source includes lifetime, identity, aggregation, arbitration, and congestion fixtures under `tests/module`. The [current S4 verification record](ieee80211-compressed-blockack-s4-execution.md) defines the executed selection. It includes lifetime interactions through Block Ack fixtures but does not report a new standalone lifetime campaign. -Follow [run-the-gates.md](../../doc/project/guide/run-the-gates.md) for the required build and focused test commands. Record commands, modes, selected cases, and results when implementation exists. This revision adds no execution result. The separate S1 record owns completed recipient verification; lifetime and performance results remain unverified. +The source contract applies independently of Block Ack support. Current S4 results do not establish complete Compressed recovery, general performance, or MAC stop/start behavior. Lifetime disposal, inactivity teardown, queue overflow, and retry-limit disposal remain distinct causes. diff --git a/src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreement.h b/src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreement.h index 8ef73652db3..c760205173a 100644 --- a/src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreement.h +++ b/src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreement.h @@ -8,6 +8,8 @@ #ifndef __INET_ORIGINATORBLOCKACKAGREEMENT_H #define __INET_ORIGINATORBLOCKACKAGREEMENT_H +#include + #include "inet/linklayer/ieee80211/mac/common/SequenceControlField.h" namespace inet { @@ -47,6 +49,29 @@ class INET_API OriginatorBlockAckAgreement : public cObject virtual ~OriginatorBlockAckAgreement() {} virtual int getBufferSize() const { return bufferSize; } + int getWindowSize() const { return std::min(bufferSize, 64); } + static int computeSequenceDistance(SequenceNumberCyclic start, SequenceNumberCyclic sequence) + { + return (sequence.get() - start.get() + 4096) % 4096; + } + bool containsSequence(SequenceNumberCyclic sequence) const + { + return computeSequenceDistance(startingSequenceNumber, sequence) < getWindowSize(); + } + // The Basic and Compressed bitmaps cover 64 sequence positions, independent of the accepted window size. + static bool isInBitmap(SequenceNumberCyclic sequence, SequenceNumberCyclic bitmapStart) + { + return computeSequenceDistance(bitmapStart, sequence) < 64; + } + // Preserve the earliest unresolved position, or advance to the next allocation when none remains. + void advanceWindow(SequenceNumberCyclic nextSequence, const std::vector& unresolvedSequences) + { + auto start = getStartingSequenceNumber(); + int distance = computeSequenceDistance(start, nextSequence); + for (auto sequence : unresolvedSequences) + distance = std::min(distance, computeSequenceDistance(start, sequence)); + setStartingSequenceNumber(start + distance); + } virtual SequenceNumberCyclic getStartingSequenceNumber() { return startingSequenceNumber; } virtual void setStartingSequenceNumber(SequenceNumberCyclic sequenceNumber) { startingSequenceNumber = sequenceNumber; } virtual bool getIsAddbaResponseReceived() const { return isAddbaResponseReceived; } diff --git a/src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.cc b/src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.cc index fdc8c44dd1e..e136518a229 100644 --- a/src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.cc +++ b/src/inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.cc @@ -170,7 +170,6 @@ void OriginatorBlockAckAgreementHandler::processReceivedBlockAck(const Ptr(blockAck)) { auto agreement = getAgreement(basicBlockAck->getTransmitterAddress(), basicBlockAck->getTidInfo()); if (agreement) { - agreement->setStartingSequenceNumber(basicBlockAck->getStartingSequenceNumber()); agreement->calculateExpirationTime(); scheduleInactivityTimer(callback); } diff --git a/src/inet/linklayer/ieee80211/mac/channelaccess/Edca.h b/src/inet/linklayer/ieee80211/mac/channelaccess/Edca.h index b7b9e4d6bc2..4b038c0c914 100644 --- a/src/inet/linklayer/ieee80211/mac/channelaccess/Edca.h +++ b/src/inet/linklayer/ieee80211/mac/channelaccess/Edca.h @@ -30,11 +30,10 @@ class INET_API Edca : public SimpleModule virtual int numInitStages() const override { return NUM_INIT_STAGES; } virtual void initialize(int stage) override; - virtual AccessCategory mapTidToAc(Tid tid); - public: virtual ~Edca(); + virtual AccessCategory mapTidToAc(Tid tid); virtual AccessCategory classifyFrame(const Ptr& header); virtual Edcaf *getEdcaf(AccessCategory ac) const { return edcafs[ac]; } EdcaTransmitLifetimeHandler *getLifetimeHandler() const { return lifetimeHandler; } diff --git a/src/inet/linklayer/ieee80211/mac/contract/IOriginatorQoSAckPolicy.h b/src/inet/linklayer/ieee80211/mac/contract/IOriginatorQoSAckPolicy.h index 94a583a111a..641e21e8ecd 100644 --- a/src/inet/linklayer/ieee80211/mac/contract/IOriginatorQoSAckPolicy.h +++ b/src/inet/linklayer/ieee80211/mac/contract/IOriginatorQoSAckPolicy.h @@ -10,6 +10,7 @@ #include "inet/linklayer/ieee80211/mac/Ieee80211Frame_m.h" #include "inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreement.h" +#include "inet/linklayer/ieee80211/mac/contract/IOriginatorBlockAckAgreementHandler.h" #include "inet/linklayer/ieee80211/mac/originator/TxopProcedure.h" #include "inet/linklayer/ieee80211/mac/queue/InProgressFrames.h" @@ -23,9 +24,9 @@ class INET_API IOriginatorQoSAckPolicy virtual bool isAckNeeded(const Ptr& header) const = 0; virtual AckPolicy computeAckPolicy(Packet *packet, const Ptr& header, OriginatorBlockAckAgreement *agreement) const = 0; - virtual bool isBlockAckReqNeeded(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure) const = 0; + virtual bool isBlockAckReqNeeded(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure, IOriginatorBlockAckAgreementHandler *agreements) const = 0; virtual bool isBlockAckPolicyEligibleFrame(Packet *packet, const Ptr& header) const = 0; - virtual std::tuple computeBlockAckReqParameters(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure) const = 0; + virtual std::tuple computeBlockAckReqParameters(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure, IOriginatorBlockAckAgreementHandler *agreements) const = 0; virtual simtime_t getAckTimeout(Packet *packet, const Ptr& dataOrMgmtHeader) const = 0; virtual simtime_t getBlockAckTimeout(Packet *packet, const Ptr& blockAckReq) const = 0; diff --git a/src/inet/linklayer/ieee80211/mac/contract/IOriginatorQosMacDataService.h b/src/inet/linklayer/ieee80211/mac/contract/IOriginatorQosMacDataService.h new file mode 100644 index 00000000000..e66fa555666 --- /dev/null +++ b/src/inet/linklayer/ieee80211/mac/contract/IOriginatorQosMacDataService.h @@ -0,0 +1,28 @@ +// +// Copyright (C) 2026 OpenSim Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +#ifndef __INET_IORIGINATORQOSMACDATASERVICE_H +#define __INET_IORIGINATORQOSMACDATASERVICE_H + +#include "inet/linklayer/ieee80211/mac/Ieee80211Frame_m.h" +#include "inet/linklayer/ieee80211/mac/contract/IOriginatorMacDataService.h" + +namespace inet { +namespace ieee80211 { + +class INET_API IOriginatorQosMacDataService : public IOriginatorMacDataService +{ + public: + // Preview borrows the frame without extraction or sequence assignment. + virtual Packet *peekEligibleFrame(queueing::IPacketQueue *queue) const = 0; + virtual SequenceNumberCyclic getNextSequenceNumber(MacAddress peer, Tid tid) const = 0; + virtual bool hasAMsduAggregation() const = 0; +}; + +} // namespace ieee80211 +} // namespace inet + +#endif diff --git a/src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc b/src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc index f5b07949b67..1c8dbbdf508 100644 --- a/src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc +++ b/src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.cc @@ -204,6 +204,7 @@ void Hcf::expireDataFrames(bool preserveSequence) frames->clearDroppedFrames(); } scheduleDataLifetimeTimer(); + advanceOriginatorWindows(); } void Hcf::forEachChild(cVisitor *v) @@ -228,6 +229,8 @@ void Hcf::handleMessage(cMessage *msg) } else if (msg == dataLifetimeTimer) { expireDataFrames(); + if (!frameSequenceHandler->isSequenceRunning()) + completeTransfers(); updateAgreementProcedures(); updateContention(); } @@ -433,7 +436,10 @@ bool Hcf::hasQueuedData(MacAddress peer, Tid tid) const return data && data->getType() == ST_DATA_WITH_QOS && data->getReceiverAddress() == peer && data->getTid() == tid && !edca->getLifetimeHandler()->isExpired(packet); }); - for (int ac = 0; ac < AC_NUMCATEGORIES; ac++) { + // Check the TID's category first. Other categories retain support for custom classification. + int first = edca->mapTidToAc(tid); + for (int offset = 0; offset < AC_NUMCATEGORIES; offset++) { + int ac = (first + offset) % AC_NUMCATEGORIES; auto queue = edca->getEdcaf(static_cast(ac))->getPendingQueue(); if (queue->isEmpty()) continue; @@ -513,6 +519,47 @@ void Hcf::updateContention() } } +void Hcf::advanceOriginatorWindows() +{ + if (!originatorBlockAckAgreementHandler) + return; + auto service = check_and_cast(originatorDataService); + for (const auto& entry : originatorBlockAckAgreementHandler->getAgreements()) { + auto agreement = entry.second; + if (!agreement->getIsAddbaResponseReceived()) + continue; + auto next = service->getNextSequenceNumber(entry.first.first, entry.first.second); + std::vector unresolvedSequences; + for (int ac = 0; ac < AC_NUMCATEGORIES; ac++) { + auto frames = edca->getEdcaf(static_cast(ac))->getInProgressFrames(); + for (int i = 0; i < frames->getLength(); i++) { + auto data = dynamicPtrCast(frames->getFrames(i)->peekAtFront()); + if (data && data->getType() == ST_DATA_WITH_QOS && + data->getReceiverAddress() == entry.first.first && data->getTid() == entry.first.second) + unresolvedSequences.push_back(data->getSequenceNumber()); + } + } + // IEEE Std 802.11-2024, 10.25.6.7.1: resolved positions permit transmit-window progress. + agreement->advanceWindow(next, unresolvedSequences); + } +} + +void Hcf::completeTransfers() +{ + if (!originatorBlockAckAgreementHandler) + return; + std::vector> completed; + for (const auto& entry : originatorBlockAckAgreementHandler->getAgreements()) { + auto agreement = entry.second; + if (agreement->getIsAddbaResponseReceived() && agreement->getFirstDataTransmitted() && + !hasNumberedData(entry.first.first, entry.first.second) && !hasQueuedData(entry.first.first, entry.first.second)) + completed.push_back(entry.first); + } + // IEEE Std 802.11-2024, 10.25.4; INET uses the accepted queue predicate at an exchange boundary. + for (const auto& id : completed) + beginTeardown(id.first, id.second, true, 37); +} + void Hcf::discardAgreementData(MacAddress peer, Tid tid, bool all, int64_t highestTransmittedDataIndex) { for (int ac = 0; ac < AC_NUMCATEGORIES; ac++) { @@ -893,6 +940,11 @@ void Hcf::handleInternalCollision(std::vector internallyCollidedEdcafs) for (auto edcaf : internallyCollidedEdcafs) { AccessCategory ac = edcaf->getAccessCategory(); auto dataRecoveryProcedure = edcaf->getRecoveryProcedure(); + if (originatorAckPolicy->isBlockAckReqNeeded(edcaf->getInProgressFrames(), edcaf->getTxopProcedure(), originatorBlockAckAgreementHandler)) { + dataRecoveryProcedure->controlFrameTransmissionFailed(); + edcaf->requestChannel(this); + continue; + } Packet *internallyCollidedFrame = edcaf->getInProgressFrames()->getFrameToTransmit(); if (internallyCollidedFrame == nullptr) continue; @@ -954,6 +1006,8 @@ void Hcf::frameSequenceFinished() if (edcaf) { // The context still owns references. dropFrame defers deletion until context disposal. expireDataFrames(false); + advanceOriginatorWindows(); + completeTransfers(); updateAgreementProcedures(); bool startContention = !handlingAgreementAction && hasFrameToTransmit(); edcaf->releaseChannel(this); @@ -1285,8 +1339,12 @@ void Hcf::originatorProcessTransmittedManagementFrame(const Ptr& controlHeader, AccessCategory ac) { auto edcaf = edca->getEdcaf(ac); - if (auto blockAckReq = dynamicPtrCast(controlHeader)) - edcaf->getAckHandler()->processTransmittedBlockAckReq(blockAckReq); + if (auto blockAckReq = dynamicPtrCast(controlHeader)) { + auto agreement = originatorBlockAckAgreementHandler ? + originatorBlockAckAgreementHandler->getAgreement(blockAckReq->getReceiverAddress(), blockAckReq->getTidInfo()) : nullptr; + if (agreement) + edcaf->getAckHandler()->processTransmittedBlockAckReq(blockAckReq, agreement); + } else if (auto rtsFrame = dynamicPtrCast(controlHeader)) rtsProcedure->processTransmittedRts(rtsFrame); else @@ -1326,6 +1384,7 @@ void Hcf::originatorProcessFailedFrame(Packet *failedPacket) } else if (auto blockAckReq = dynamicPtrCast(failedHeader)) { edcaf->getAckHandler()->processFailedBlockAckReq(blockAckReq); + edcaf->getRecoveryProcedure()->controlFrameTransmissionFailed(); return; } else @@ -1420,6 +1479,7 @@ void Hcf::originatorProcessReceivedControlFrame(Packet *packet, const Ptr(lastTransmittedHeader); edcaf->getAckHandler()->processReceivedAck(ackFrame, lastTransmittedDataOrMgmtHeader); edcaf->getInProgressFrames()->dropFrame(lastTransmittedPacket); + advanceOriginatorWindows(); edcaf->getAckHandler()->dropFrame(lastTransmittedDataOrMgmtHeader); if (dynamicPtrCast(lastTransmittedHeader)) { actionTerminated(lastTransmittedPacket, true); @@ -1427,8 +1487,12 @@ void Hcf::originatorProcessReceivedControlFrame(Packet *packet, const Ptr(header)) { + if (!originatorBlockAckAgreementHandler || + !originatorBlockAckAgreementHandler->getAgreement(blockAck->getTransmitterAddress(), blockAck->getTidInfo())) + return; EV_INFO << "BasicBlockAck has arrived" << std::endl; edcaf->getRecoveryProcedure()->blockAckFrameReceived(); auto ackedSeqAndFragNums = edcaf->getAckHandler()->processReceivedBlockAck(blockAck); @@ -1438,7 +1502,9 @@ void Hcf::originatorProcessReceivedControlFrame(Packet *packet, const Ptr(header)) { + auto status = channelOwner->getAckHandler()->getQoSDataAckStatus(dataHeader); + if (dataHeader->getType() == ST_DATA_WITH_QOS && + (status == QosAckHandler::Status::BLOCK_ACK_NOT_ARRIVED || status == QosAckHandler::Status::BLOCK_ACK_ARRIVED_UNACKED)) { + // IEEE Std 802.11-2024, 9.2.4.1.6: DATA after a failed Block Ack exchange is a retransmission. + auto updated = packet->removeAtFront(); + updated->setRetry(true); + packet->insertAtFront(updated); + header = updated; + } + } auto lifetimeHandler = edca->getLifetimeHandler(); auto step = frameSequenceHandler->getContext()->getLastStep(); auto protectedPacket = dynamic_cast(step); @@ -1646,6 +1725,19 @@ bool Hcf::transmitFrame(Packet *packet, simtime_t ifs) } auto mode = dataAfterCts ? packet->getTag()->getMode() : rateSelection->computeMode(packet, header, txop); setFrameMode(packet, header, mode); + if (auto bar = dynamicPtrCast(header)) { + auto agreement = originatorBlockAckAgreementHandler ? + originatorBlockAckAgreementHandler->getAgreement(bar->getReceiverAddress(), bar->getTidInfo()) : nullptr; + if (!agreement || !agreement->getIsAddbaResponseReceived()) + return false; + auto response = rateSelection->computeResponseBlockAckFrameMode(packet, bar, ResponseQueryRole::PREDICT)->getDuration(LENGTH_BASIC_BLOCKACK); + auto cost = mode->getDuration(packet->getDataLength()) + modeSet->getSifsTime() + response; + // IEEE Std 802.11-2024, 10.23.2.8 and 10.23.2.9: a later BAR must fit both bounds. + if (context->getNumSteps() > 1 && + ((txop->getLimit() > 0 && ifs + cost > txop->getRemaining()) || + (txop->getProtectionMechanism() == TxopProcedure::SINGLE_PROTECTION && cost >= rx->getTxnavRemaining()))) + return false; + } if (scopedSingle) { auto sifs = modeSet->getSifsTime(); auto cost = mode->getDuration(packet->getDataLength()); @@ -1698,7 +1790,16 @@ bool Hcf::transmitFrame(Packet *packet, simtime_t ifs) packet->insertAtFront(updated); } else if (txop->getProtectionMechanism() == TxopProcedure::ProtectionMechanism::SINGLE_PROTECTION) { - auto pendingPacket = channelOwner->getInProgressFrames()->getPendingFrameFor(packet); + auto pendingPacket = dynamicPtrCast(header) ? nullptr : + channelOwner->getInProgressFrames()->getPendingFrameFor(packet, false); + if (dynamicPtrCast(header) && txop->getLimit() == 0) { + // The zero-limit frame sequence ends after this exchange; it has no successor reservation. + pendingPacket = nullptr; + } + else if (pendingPacket && !channelOwner->getInProgressFrames()->containsFrame(pendingPacket)) { + // HcfFs ends this TXOP before extraction can change the successor's size or setup state. + pendingPacket = nullptr; + } const auto& pendingHeader = pendingPacket == nullptr ? nullptr : pendingPacket->peekAtFront(); auto duration = singleProtectionMechanism->computeDurationField(packet, header, pendingPacket, pendingHeader, txop, recipientAckPolicy); auto header = packet->removeAtFront(); diff --git a/src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.h b/src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.h index 1361083c32d..25fa8a0bb90 100644 --- a/src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.h +++ b/src/inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.h @@ -159,6 +159,8 @@ class INET_API Hcf : public ICoordinationFunction, public IFrameSequenceHandler: bool hasNumberedData(MacAddress peer, Tid tid) const; bool hasObsoleteActionInFlight(MacAddress peer, Tid tid, bool originator) const; void updateAgreementProcedures(); + void advanceOriginatorWindows(); + void completeTransfers(); void updateContention(); void scheduleAddbaResponseTimer(); void actionTerminated(Packet *packet, bool acknowledged); diff --git a/src/inet/linklayer/ieee80211/mac/framesequence/HcfFs.cc b/src/inet/linklayer/ieee80211/mac/framesequence/HcfFs.cc index b12ce4d54f4..7a49e0ece7c 100644 --- a/src/inet/linklayer/ieee80211/mac/framesequence/HcfFs.cc +++ b/src/inet/linklayer/ieee80211/mac/framesequence/HcfFs.cc @@ -34,8 +34,12 @@ HcfFs::HcfFs() : int HcfFs::selectHcfSequence(AlternativesFs *frameSequence, FrameSequenceContext *context) { - auto frameToTransmit = context->getInProgressFrames()->getFrameToTransmit(); - return frameToTransmit->peekAtFront()->getReceiverAddress().isMulticast() ? 0 : 1; + auto qos = context->getQoSContext(); + auto frameToTransmit = qos->blockAckAgreementHandler ? context->getInProgressFrames()->peekFrameToTransmit() : + context->getInProgressFrames()->getFrameToTransmit(); + if (qos->ackPolicy->isBlockAckReqNeeded(context->getInProgressFrames(), qos->txopProcedure, qos->blockAckAgreementHandler)) + return 1; + return frameToTransmit && frameToTransmit->peekAtFront()->getReceiverAddress().isMulticast() ? 0 : 1; } int HcfFs::selectDataOrManagementSequence(AlternativesFs *frameSequence, FrameSequenceContext *context) @@ -57,15 +61,21 @@ bool HcfFs::isSelfCtsNeeded(OptionalFs *frameSequence, FrameSequenceContext *con bool HcfFs::hasMoreTxOps(RepeatingFs *frameSequence, FrameSequenceContext *context) { - bool hasFrameToTransmit = context->getInProgressFrames()->hasInProgressFrames(); + auto frames = context->getInProgressFrames(); + auto qos = context->getQoSContext(); + bool bar = qos->ackPolicy->isBlockAckReqNeeded(frames, qos->txopProcedure, qos->blockAckAgreementHandler); + bool hasFrameToTransmit = qos->blockAckAgreementHandler ? + bar || frames->peekFrameToTransmit() != nullptr : frames->hasInProgressFrames(); if (hasFrameToTransmit) { - auto nextFrameToTransmit = context->getInProgressFrames()->getFrameToTransmit(); - const auto& nextHeader = nextFrameToTransmit->peekAtFront(); + auto nextFrameToTransmit = qos->blockAckAgreementHandler ? frames->peekFrameToTransmit() : frames->getFrameToTransmit(); if (frameSequence->getCount() == 0) return true; - auto qos = context->getQoSContext(); auto txop = qos->txopProcedure; - if (nextHeader->getReceiverAddress().isMulticast() || txop->getRemaining() <= 0) + // Basic single protection reserves only prepared MPDUs. Unextracted DATA starts a new TXOP. + if (qos->blockAckAgreementHandler && txop->getProtectionMechanism() == TxopProcedure::SINGLE_PROTECTION && + !bar && !frames->containsFrame(nextFrameToTransmit)) + return false; + if ((!bar && nextFrameToTransmit->peekAtFront()->getReceiverAddress().isMulticast()) || txop->getRemaining() <= 0) return false; if (txop->getProtectionMechanism() == TxopProcedure::MULTIPLE_PROTECTION) { auto deadline = txop->getStart() + txop->getLimit(); @@ -77,8 +87,7 @@ bool HcfFs::hasMoreTxOps(RepeatingFs *frameSequence, FrameSequenceContext *conte if (projectedStart >= deadline) return false; // BAR precedes DATA in TxOpFs and does not use RTS. - if (!qos->ackPolicy->isBlockAckReqNeeded(context->getInProgressFrames(), txop) && - context->getRtsPolicy()->isRtsNeeded(nextFrameToTransmit, nextHeader)) + if (!bar && context->getRtsPolicy()->isRtsNeeded(nextFrameToTransmit, nextFrameToTransmit->peekAtFront())) { // Integer legacy RTS airtime requires its start on the deadline's microsecond grid. if ((projectedStart - deadline).raw() % SimTime(1, SIMTIME_US).raw() != 0) diff --git a/src/inet/linklayer/ieee80211/mac/framesequence/PrimitiveFrameSequences.cc b/src/inet/linklayer/ieee80211/mac/framesequence/PrimitiveFrameSequences.cc index 3fda1fcd52c..f9a3de4a6e5 100644 --- a/src/inet/linklayer/ieee80211/mac/framesequence/PrimitiveFrameSequences.cc +++ b/src/inet/linklayer/ieee80211/mac/framesequence/PrimitiveFrameSequences.cc @@ -412,7 +412,8 @@ IFrameSequenceStep *BlockAckReqBlockAckFs::prepareStep(FrameSequenceContext *con { switch (step) { case 0: { - auto blockAckReqParams = context->getQoSContext()->ackPolicy->computeBlockAckReqParameters(context->getInProgressFrames(), context->getQoSContext()->txopProcedure); + auto qos = context->getQoSContext(); + auto blockAckReqParams = qos->ackPolicy->computeBlockAckReqParameters(context->getInProgressFrames(), qos->txopProcedure, qos->blockAckAgreementHandler); auto receiverAddr = std::get<0>(blockAckReqParams); auto startingSequenceNumber = std::get<1>(blockAckReqParams); auto tid = std::get<2>(blockAckReqParams); @@ -445,7 +446,12 @@ bool BlockAckReqBlockAckFs::completeStep(FrameSequenceContext *context) step++; auto receivedPacket = receiveStep->getReceivedFrame(); const auto& receivedHeader = receivedPacket->peekAtFront(); - return context->isForUs(receivedHeader) && receivedHeader->getType() == ST_BLOCKACK; + auto response = dynamicPtrCast(receivedHeader); + auto requestStep = check_and_cast(context->getStep(firstStep)); + auto request = requestStep->getFrameToTransmit()->peekAtFront(); + return context->isForUs(receivedHeader) && response && + response->getTransmitterAddress() == request->getReceiverAddress() && + response->getTidInfo() == request->getTidInfo(); } default: throw cRuntimeError("Unknown step"); diff --git a/src/inet/linklayer/ieee80211/mac/framesequence/TxOpFs.cc b/src/inet/linklayer/ieee80211/mac/framesequence/TxOpFs.cc index 02420634437..e0daefabaa7 100644 --- a/src/inet/linklayer/ieee80211/mac/framesequence/TxOpFs.cc +++ b/src/inet/linklayer/ieee80211/mac/framesequence/TxOpFs.cc @@ -44,10 +44,11 @@ int TxOpFs::selectMgmtOrDataQap(AlternativesFs *frameSequence, FrameSequenceCont int TxOpFs::selectTxOpSequence(AlternativesFs *frameSequence, FrameSequenceContext *context) { + auto qos = context->getQoSContext(); + if (qos->ackPolicy->isBlockAckReqNeeded(context->getInProgressFrames(), qos->txopProcedure, qos->blockAckAgreementHandler)) + return 2; auto frameToTransmit = context->getInProgressFrames()->getFrameToTransmit(); const auto& macHeader = frameToTransmit->peekAtFront(); - if (context->getQoSContext()->ackPolicy->isBlockAckReqNeeded(context->getInProgressFrames(), context->getQoSContext()->txopProcedure)) - return 2; if (dynamicPtrCast(macHeader)) return 3; else { diff --git a/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.cc b/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.cc index b99e0a3339b..dbdfdf50d0b 100644 --- a/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.cc +++ b/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.cc @@ -31,67 +31,55 @@ bool OriginatorQosAckPolicy::isAckNeeded(const Ptr& h return !header->getReceiverAddress().isMulticast(); } -std::map> OriginatorQosAckPolicy::getOutstandingFramesPerReceiver(InProgressFrames *inProgressFrames) const +bool OriginatorQosAckPolicy::isBlockAckReqNeeded(InProgressFrames *frames, TxopProcedure *txop, IOriginatorBlockAckAgreementHandler *agreements) const { - auto outstandingFrames = inProgressFrames->getOutstandingFrames(); - std::map> outstandingFramesPerReceiver; - for (auto frame : outstandingFrames) - outstandingFramesPerReceiver[frame->peekAtFront()->getReceiverAddress()].push_back(frame); - return outstandingFramesPerReceiver; + return std::get<2>(computeBlockAckReqParameters(frames, txop, agreements)) != -1; } -SequenceNumberCyclic OriginatorQosAckPolicy::computeStartingSequenceNumber(const std::vector& outstandingFrames) const +std::tuple OriginatorQosAckPolicy::computeBlockAckReqParameters(InProgressFrames *frames, TxopProcedure *txop, IOriginatorBlockAckAgreementHandler *agreements) const { - ASSERT(outstandingFrames.size() > 0); - auto startingSequenceNumber = outstandingFrames[0]->peekAtFront()->getSequenceNumber(); - for (size_t i = 1; i < outstandingFrames.size(); i++) { - auto seqNum = outstandingFrames[i]->peekAtFront()->getSequenceNumber(); - if (seqNum < startingSequenceNumber) - startingSequenceNumber = seqNum; + using Id = std::pair; + std::map> groups; + for (auto frame : frames->getOutstandingFrames()) { + auto header = frame->peekAtFront(); + auto agreement = agreements ? agreements->getAgreement(header->getReceiverAddress(), header->getTid()) : nullptr; + if (agreement && agreement->getIsAddbaResponseReceived() && agreement->containsSequence(header->getSequenceNumber())) + groups[{header->getReceiverAddress(), header->getTid()}].push_back(frame); } - return startingSequenceNumber; -} - -bool OriginatorQosAckPolicy::isCompressedBlockAckReq(const std::vector& outstandingFrames, int startingSequenceNumber) const -{ - // The Compressed Bitmap subfield of the BA Control field or BAR Control field shall be set to 1 in all - // BlockAck and BlockAckReq frames sent from one HT STA to another HT STA and shall be set to 0 otherwise. - return false; // non-HT STA -// for (auto frame : outstandingFrames) -// if (frame->getSequenceNumber() >= startingSequenceNumber && frame->getFragmentNumber() > 0) -// return false; -// return true; -} - -// FIXME -bool OriginatorQosAckPolicy::isBlockAckReqNeeded(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure) const -{ - auto outstandingFramesPerReceiver = getOutstandingFramesPerReceiver(inProgressFrames); - for (auto outstandingFrames : outstandingFramesPerReceiver) { - if ((int)outstandingFrames.second.size() >= blockAckReqThreshold) - return true; - } - return false; -} - -// FIXME -std::tuple OriginatorQosAckPolicy::computeBlockAckReqParameters(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure) const -{ - auto outstandingFramesPerReceiver = getOutstandingFramesPerReceiver(inProgressFrames); - for (auto outstandingFrames : outstandingFramesPerReceiver) { - if ((int)outstandingFrames.second.size() >= blockAckReqThreshold) { - auto largestOutstandingFrames = outstandingFramesPerReceiver.begin(); - for (auto it = outstandingFramesPerReceiver.begin(); it != outstandingFramesPerReceiver.end(); it++) { - if (it->second.size() > largestOutstandingFrames->second.size()) - largestOutstandingFrames = it; + if (groups.empty()) + return std::make_tuple(MacAddress::UNSPECIFIED_ADDRESS, SequenceNumberCyclic(0), Tid(-1)); + auto candidate = frames->peekFrameToTransmit(); + auto data = candidate ? dynamicPtrCast(candidate->peekAtFront()) : nullptr; + auto result = std::make_tuple(MacAddress::UNSPECIFIED_ADDRESS, SequenceNumberCyclic(0), Tid(-1)); + simtime_t oldestArrival = SIMTIME_MAX; + for (const auto& entry : groups) { + const auto& id = entry.first; + auto agreement = agreements->getAgreement(id.first, id.second); + // INET BAR policy defers a short group only for DATA within that group's window. + if ((int)entry.second.size() < blockAckReqThreshold && data && + data->getReceiverAddress() == id.first && data->getTid() == id.second && + agreement->containsSequence(frames->getCandidateSequenceNumber(candidate))) + continue; + auto start = agreement->getStartingSequenceNumber(); + int oldestOffset = -1; + simtime_t arrival = SIMTIME_MAX; + for (auto frame : entry.second) { + auto sequence = frame->peekAtFront()->getSequenceNumber(); + int offset = OriginatorBlockAckAgreement::computeSequenceDistance(start, sequence); + if (oldestOffset == -1 || offset < oldestOffset) { + oldestOffset = offset; + arrival = frame->getArrivalTime(); } - MacAddress receiverAddress = largestOutstandingFrames->first; - SequenceNumberCyclic startingSequenceNumber = computeStartingSequenceNumber(largestOutstandingFrames->second); - Tid tid = largestOutstandingFrames->second.at(0)->peekAtFront()->getTid(); - return std::make_tuple(receiverAddress, startingSequenceNumber, tid); + else if (offset == oldestOffset) + arrival = std::min(arrival, frame->getArrivalTime()); + } + // Map order supplies the peer/TID tie break. + if (std::get<2>(result) == -1 || arrival < oldestArrival) { + oldestArrival = arrival; + result = std::make_tuple(id.first, start + oldestOffset, id.second); } } - return std::make_tuple(MacAddress::UNSPECIFIED_ADDRESS, SequenceNumberCyclic(), -1); + return result; } AckPolicy OriginatorQosAckPolicy::computeAckPolicy(Packet *packet, const Ptr& header, OriginatorBlockAckAgreement *agreement) const @@ -117,10 +105,9 @@ bool OriginatorQosAckPolicy::isBlockAckPolicyEligibleFrame(Packet *packet, const bool OriginatorQosAckPolicy::checkAgreementPolicy(const Ptr& header, OriginatorBlockAckAgreement *agreement) const { - bool bufferFull = agreement->getBufferSize() == agreement->getNumSentBaPolicyFrames(); bool aMsduOk = agreement->isAMsduPermitted() || !header->getAMsduPresent(); // TODO bool baPolicy = agreement->getIsDelayedBlockAckPolicySupported() || !frame->getAckPolicy(); - return !bufferFull && aMsduOk && (header->getSequenceNumber() >= agreement->getStartingSequenceNumber()); // TODO && baPolicy + return aMsduOk && agreement->containsSequence(header->getSequenceNumber()); } // diff --git a/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.h b/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.h index bcd9f1b2ae7..cefd7008567 100644 --- a/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.h +++ b/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.h @@ -31,16 +31,13 @@ class INET_API OriginatorQosAckPolicy : public ModeSetListener, public IOriginat virtual void initialize(int stage) override; virtual bool checkAgreementPolicy(const Ptr& header, OriginatorBlockAckAgreement *agreement) const; - virtual std::map> getOutstandingFramesPerReceiver(InProgressFrames *inProgressFrames) const; - virtual SequenceNumberCyclic computeStartingSequenceNumber(const std::vector& outstandingFrames) const; - virtual bool isCompressedBlockAckReq(const std::vector& outstandingFrames, int startingSequenceNumber) const; public: virtual bool isAckNeeded(const Ptr& header) const override; virtual AckPolicy computeAckPolicy(Packet *packet, const Ptr& header, OriginatorBlockAckAgreement *agreement) const override; virtual bool isBlockAckPolicyEligibleFrame(Packet *packet, const Ptr& header) const override; - virtual bool isBlockAckReqNeeded(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure) const override; - virtual std::tuple computeBlockAckReqParameters(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure) const override; + virtual bool isBlockAckReqNeeded(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure, IOriginatorBlockAckAgreementHandler *agreements) const override; + virtual std::tuple computeBlockAckReqParameters(InProgressFrames *inProgressFrames, TxopProcedure *txopProcedure, IOriginatorBlockAckAgreementHandler *agreements) const override; virtual simtime_t getAckTimeout(Packet *packet, const Ptr& dataOrMgmtHeader) const override; virtual simtime_t getBlockAckTimeout(Packet *packet, const Ptr& blockAckReq) const override; diff --git a/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosMacDataService.h b/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosMacDataService.h index 7928e2153bc..997a696d46f 100644 --- a/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosMacDataService.h +++ b/src/inet/linklayer/ieee80211/mac/originator/OriginatorQosMacDataService.h @@ -16,14 +16,14 @@ #include "inet/linklayer/ieee80211/mac/contract/IMpduAggregationPolicy.h" #include "inet/linklayer/ieee80211/mac/contract/IMsduAggregation.h" #include "inet/linklayer/ieee80211/mac/contract/IMsduAggregationPolicy.h" -#include "inet/linklayer/ieee80211/mac/contract/IOriginatorMacDataService.h" +#include "inet/linklayer/ieee80211/mac/contract/IOriginatorQosMacDataService.h" #include "inet/linklayer/ieee80211/mac/contract/ISequenceNumberAssignment.h" #include "inet/linklayer/ieee80211/mac/lifetime/EdcaTransmitLifetimeHandler.h" namespace inet { namespace ieee80211 { -class INET_API OriginatorQosMacDataService : public IOriginatorMacDataService, public SimpleModule +class INET_API OriginatorQosMacDataService : public IOriginatorQosMacDataService, public SimpleModule { protected: // Figure 5-1—MAC data plane architecture @@ -58,9 +58,9 @@ class INET_API OriginatorQosMacDataService : public IOriginatorMacDataService, p extractionEligible = eligible; aMsduPermitted = permission; } - Packet *peekEligibleFrame(queueing::IPacketQueue *queue) const; - SequenceNumberCyclic getNextSequenceNumber(MacAddress peer, Tid tid) const; - bool hasAMsduAggregation() const { return aMsduAggregationPolicy != nullptr; } + virtual Packet *peekEligibleFrame(queueing::IPacketQueue *queue) const override; + virtual SequenceNumberCyclic getNextSequenceNumber(MacAddress peer, Tid tid) const override; + virtual bool hasAMsduAggregation() const override { return aMsduAggregationPolicy != nullptr; } virtual ~OriginatorQosMacDataService(); void setLifetimeHandler(EdcaTransmitLifetimeHandler *handler, std::function expiration) { lifetimeHandler = handler; diff --git a/src/inet/linklayer/ieee80211/mac/originator/QosAckHandler.cc b/src/inet/linklayer/ieee80211/mac/originator/QosAckHandler.cc index 2fa02655743..c79877d4a72 100644 --- a/src/inet/linklayer/ieee80211/mac/originator/QosAckHandler.cc +++ b/src/inet/linklayer/ieee80211/mac/originator/QosAckHandler.cc @@ -147,6 +147,13 @@ std::set>> QosAckHand else { throw cRuntimeError("Multi-TID BlockReq is unimplemented"); } + auto basic = dynamicPtrCast(blockAck); + auto compressed = dynamicPtrCast(blockAck); + auto tid = basic ? basic->getTidInfo() : compressed->getTidInfo(); + for (auto& entry : ackStatuses) { + if (entry.first.first == receiverAddr && entry.first.second.first == tid && entry.second == Status::WAITING_FOR_BLOCK_ACK) + entry.second = Status::BLOCK_ACK_ARRIVED_UNACKED; + } return ackedFrames; } @@ -195,23 +202,28 @@ void QosAckHandler::processTransmittedDataOrMgmtFrame(const PtrgetReceiverAddress(), SequenceControlField(header->getSequenceNumber().get(), header->getFragmentNumber()))] = Status::WAITING_FOR_NORMAL_ACK; } -void QosAckHandler::processTransmittedBlockAckReq(const Ptr& blockAckReq) +void QosAckHandler::processTransmittedBlockAckReq(const Ptr& blockAckReq, const OriginatorBlockAckAgreement *agreement) { for (auto& ackStatus : ackStatuses) { + if (ackStatus.first.first != blockAckReq->getReceiverAddress()) + continue; auto tid = ackStatus.first.second.first; auto seqCtrlField = ackStatus.first.second.second; + auto sequence = SequenceNumberCyclic(seqCtrlField.getSequenceNumber()); + if (agreement && !agreement->containsSequence(sequence)) + continue; auto& status = ackStatus.second; if (auto basicBlockAckReq = dynamicPtrCast(blockAckReq)) { if (basicBlockAckReq->getTidInfo() == tid) { auto startingSeqNum = basicBlockAckReq->getStartingSequenceNumber(); - if (status == Status::BLOCK_ACK_NOT_YET_REQUESTED && SequenceNumberCyclic(seqCtrlField.getSequenceNumber()) >= startingSeqNum) + if (status == Status::BLOCK_ACK_NOT_YET_REQUESTED && OriginatorBlockAckAgreement::isInBitmap(sequence, startingSeqNum)) status = Status::WAITING_FOR_BLOCK_ACK; } } else if (auto compressedBlockAckReq = dynamicPtrCast(blockAckReq)) { if (compressedBlockAckReq->getTidInfo() == tid) { auto startingSeqNum = compressedBlockAckReq->getStartingSequenceNumber(); - if (status == Status::BLOCK_ACK_NOT_YET_REQUESTED && SequenceNumberCyclic(seqCtrlField.getSequenceNumber()) >= startingSeqNum && seqCtrlField.getFragmentNumber() == 0) // TODO ASSERT(seqCtrlField.second == 0)? + if (status == Status::BLOCK_ACK_NOT_YET_REQUESTED && OriginatorBlockAckAgreement::isInBitmap(sequence, startingSeqNum) && seqCtrlField.getFragmentNumber() == 0) status = Status::WAITING_FOR_BLOCK_ACK; } } diff --git a/src/inet/linklayer/ieee80211/mac/originator/QosAckHandler.h b/src/inet/linklayer/ieee80211/mac/originator/QosAckHandler.h index 7c1e0bce61c..96f1026d85f 100644 --- a/src/inet/linklayer/ieee80211/mac/originator/QosAckHandler.h +++ b/src/inet/linklayer/ieee80211/mac/originator/QosAckHandler.h @@ -13,6 +13,7 @@ #include "inet/linklayer/ieee80211/mac/common/SequenceControlField.h" #include "inet/linklayer/ieee80211/mac/contract/IAckHandler.h" +#include "inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreement.h" namespace inet { namespace ieee80211 { @@ -60,7 +61,7 @@ class INET_API QosAckHandler : public SimpleModule, public IAckHandler virtual void frameGotInProgress(const Ptr& dataOrMgmtHeader) override; virtual void processTransmittedDataOrMgmtFrame(const Ptr& header); - virtual void processTransmittedBlockAckReq(const Ptr& blockAckReq); + virtual void processTransmittedBlockAckReq(const Ptr& blockAckReq, const OriginatorBlockAckAgreement *agreement); virtual void processFailedFrame(const Ptr& dataOrMgmtHeader); virtual void dropFrame(const Ptr& dataOrMgmtHeader); virtual void dropFrames(std::set>> seqAndFragNums); diff --git a/src/inet/linklayer/ieee80211/mac/originator/QosRecoveryProcedure.cc b/src/inet/linklayer/ieee80211/mac/originator/QosRecoveryProcedure.cc index e0b177a94b2..e52f6b72652 100644 --- a/src/inet/linklayer/ieee80211/mac/originator/QosRecoveryProcedure.cc +++ b/src/inet/linklayer/ieee80211/mac/originator/QosRecoveryProcedure.cc @@ -110,6 +110,20 @@ void QosRecoveryProcedure::ctsFrameReceived() void QosRecoveryProcedure::blockAckFrameReceived() { resetStationSrc(); + resetContentionWindow(); +} + +void QosRecoveryProcedure::controlFrameTransmissionFailed() +{ + // IEEE Std 802.11-2024, 10.23.2.2: control failures update EDCA backoff without DATA retry feedback. + if (stationShortRetryCounter < shortRetryLimit) { + stationShortRetryCounter++; + incrementContentionWindow(); + } + else { + resetStationSrc(); + resetContentionWindow(); + } } // diff --git a/src/inet/linklayer/ieee80211/mac/originator/QosRecoveryProcedure.h b/src/inet/linklayer/ieee80211/mac/originator/QosRecoveryProcedure.h index 69435073efc..e1804fcc323 100644 --- a/src/inet/linklayer/ieee80211/mac/originator/QosRecoveryProcedure.h +++ b/src/inet/linklayer/ieee80211/mac/originator/QosRecoveryProcedure.h @@ -66,6 +66,7 @@ class INET_API QosRecoveryProcedure : public SimpleModule, public IRecoveryProce virtual void ctsFrameReceived(); virtual void ackFrameReceived(Packet *packet, const Ptr& ackedHeader); virtual void blockAckFrameReceived(); + virtual void controlFrameTransmissionFailed(); virtual void rtsFrameTransmissionFailed(const Ptr& protectedHeader); virtual void dataFrameTransmissionFailed(Packet *packet, const Ptr& failedHeader); diff --git a/src/inet/linklayer/ieee80211/mac/queue/InProgressFrames.cc b/src/inet/linklayer/ieee80211/mac/queue/InProgressFrames.cc index e9918ee20f7..416e9709ad3 100644 --- a/src/inet/linklayer/ieee80211/mac/queue/InProgressFrames.cc +++ b/src/inet/linklayer/ieee80211/mac/queue/InProgressFrames.cc @@ -9,6 +9,8 @@ #include +#include "inet/linklayer/ieee80211/mac/contract/IOriginatorQosMacDataService.h" + namespace inet { namespace ieee80211 { @@ -95,9 +97,26 @@ Packet *InProgressFrames::getFrameToTransmit() return nullptr; } -Packet *InProgressFrames::getPendingFrameFor(Packet *frame) +Packet *InProgressFrames::peekFrameToTransmit() +{ + for (auto frame : inProgressFrames) { + if (isEligibleToTransmit(frame)) + return frame; + } + return check_and_cast(dataService)->peekEligibleFrame(pendingQueue); +} + +SequenceNumberCyclic InProgressFrames::getCandidateSequenceNumber(Packet *packet) const +{ + auto header = packet->peekAtFront(); + if (containsFrame(packet)) + return header->getSequenceNumber(); + return check_and_cast(dataService)->getNextSequenceNumber(header->getReceiverAddress(), header->getTid()); +} + +Packet *InProgressFrames::getPendingFrameFor(Packet *frame, bool extract) { - auto frameToTransmit = getFrameToTransmit(); + auto frameToTransmit = extract ? getFrameToTransmit() : peekFrameToTransmit(); if (dynamicPtrCast(frame->peekAtFront())) return frameToTransmit; else { @@ -105,6 +124,8 @@ Packet *InProgressFrames::getPendingFrameFor(Packet *frame) if (isEligibleToTransmit(frame) && frameToTransmit != frame) return frame; } + if (!extract) + return check_and_cast(dataService)->peekEligibleFrame(pendingQueue); auto frames = dataService->extractFramesToTransmit(pendingQueue); if (frames) { auto firstFrame = (*frames)[0]; @@ -158,7 +179,8 @@ std::vector InProgressFrames::getOutstandingFrames() { std::vector outstandingFrames; for (auto frame : inProgressFrames) { - if (ackHandler->isOutstandingFrame(frame->peekAtFront())) + if ((!lifetimeHandler || !lifetimeHandler->isExpired(frame)) && + ackHandler->isOutstandingFrame(frame->peekAtFront())) outstandingFrames.push_back(frame); } return outstandingFrames; diff --git a/src/inet/linklayer/ieee80211/mac/queue/InProgressFrames.h b/src/inet/linklayer/ieee80211/mac/queue/InProgressFrames.h index 293aebfc3a3..65b13b67aa7 100644 --- a/src/inet/linklayer/ieee80211/mac/queue/InProgressFrames.h +++ b/src/inet/linklayer/ieee80211/mac/queue/InProgressFrames.h @@ -53,7 +53,9 @@ class INET_API InProgressFrames : public SimpleModule virtual Packet *getFrames(int i) const { return inProgressFrames[i]; } bool containsFrame(const Packet *packet) const; virtual Packet *getFrameToTransmit(); - virtual Packet *getPendingFrameFor(Packet *frame); + virtual Packet *peekFrameToTransmit(); + SequenceNumberCyclic getCandidateSequenceNumber(Packet *packet) const; + virtual Packet *getPendingFrameFor(Packet *frame, bool extract = true); virtual void dropFrame(Packet *packet); virtual void dropFrames(std::set>> seqAndFragNums); diff --git a/tests/fingerprint/examples.csv b/tests/fingerprint/examples.csv index 78905809d2c..fed121062af 100644 --- a/tests/fingerprint/examples.csv +++ b/tests/fingerprint/examples.csv @@ -7,7 +7,7 @@ # /examples/adhoc/ieee80211/, -f omnetpp.ini -c Ping2 -r 0, 100s, 0000-0000/tplx;0000-0000/~tNl;0000-0000/~tND, ERROR, wireless adhoc # [Config Ping2] # interactive config, needed a *.numHosts parameter /examples/adhoc/qos/, -f omnetpp.ini -c MacNonQos -r 0, 10s, 5749-0281/tplx;f38a-cb93/~tNl;c2ed-b352/~tND;0eb8-3e3b/tyf, PASS, wireless adhoc Ipv4 /examples/adhoc/qos/, -f omnetpp.ini -c MacQos -r 0, 10s, dd36-1076/tplx;b703-3ef2/~tNl;e07d-2980/~tND;2c1e-66e5/tyf, PASS, wireless adhoc Ipv4 -/examples/adhoc/qos/, -f omnetpp.ini -c MacQos -r 1, 10s, 5fbb-9fd9/tplx;c0a4-97f6/~tNl;2373-df01/~tND;a587-3a4d/tyf, PASS, wireless adhoc Ipv4 +/examples/adhoc/qos/, -f omnetpp.ini -c MacQos -r 1, 10s, 4fd2-bb56/tplx;ecaf-89f7/~tNl;9398-0fae/~tND;a587-3a4d/tyf, PASS, wireless adhoc Ipv4 /examples/adhoc/qos/, -f omnetpp.ini -c Fragmentation, 10s, 2f2d-73b1/tplx;cc9e-d1a6/~tNl;e740-f7d4/~tND;33b7-00f9/tyf, PASS, wireless adhoc Ipv4 /examples/adhoc/qos/, -f omnetpp.ini -c MsduAggregation, 10s, 2c80-6844/tplx;4e9e-cf86/~tNl;ea3d-e802/~tND;df04-18f7/tyf, PASS, wireless adhoc Ipv4 @@ -658,7 +658,7 @@ /examples/wireless/qos/, -f omnetpp.ini -c MacQos -r 0, 10s, d929-5913/tplx;f602-4424/~tNl;f2fb-4d98/~tND;9f3c-4512/tyf, PASS, wireless Ipv4 /examples/wireless/qos/, -f omnetpp.ini -c MacQosWithoutAggregation -r 0, 10s, 0473-f9d2/tplx;e92c-7352/~tNl;317d-aa4f/~tND;a4c3-19bf/tyf, PASS, wireless Ipv4 /examples/wireless/qos/, -f omnetpp.ini -c MacQosWithRtsCts -r 0, 10s, e07a-4c5f/tplx;9f6c-7889/~tNl;29ea-169c/~tND;b2d6-1329/tyf, PASS, wireless Ipv4 -/examples/wireless/qos/, -f omnetpp.ini -c MacQosWithBlockAck -r 0, 10s, f8a4-9474/tplx;1cba-cccc/~tNl;538e-67df/~tND;08b5-d005/tyf, PASS, wireless Ipv4 +/examples/wireless/qos/, -f omnetpp.ini -c MacQosWithBlockAck -r 0, 10s, 6edb-0326/tplx;2a8a-50ee/~tNl;4301-882d/~tND;08b5-d005/tyf, PASS, wireless Ipv4 /examples/wireless/ratecontrol/, -f omnetpp.ini -c Mac -r 0, 100s, bf30-2f13/tplx;7b2f-653d/~tNl;6f09-d8eb/~tND;19fe-8b0e/tyf, PASS, wireless diff --git a/tests/fingerprint/showcases.csv b/tests/fingerprint/showcases.csv index 836d42b5183..9baf2771fb6 100644 --- a/tests/fingerprint/showcases.csv +++ b/tests/fingerprint/showcases.csv @@ -199,9 +199,9 @@ /showcases/wireless/analogmodel/, -f omnetpp.ini -c Distance -r 0, 2.5s, 1e75-270e/tplx;6d7a-d84c/~tNl;7b7c-2bfb/~tND;5575-fd8f/tyf, PASS, wireless Ipv4 /showcases/wireless/analogmodel/, -f omnetpp.ini -c Noise -r 0, 0.1s, dd08-a63c/tplx;e167-9c84/~tNl;d680-b8ad/~tND;0d1f-df73/tyf, PASS, wireless Ipv4 -/showcases/wireless/blockack/, -f omnetpp.ini -c NoFragmentation -r 0, 1s, b828-6bd6/tplx;026f-2c6d/~tNl;2cd4-4795/~tND, PASS, wireless Ipv4 -/showcases/wireless/blockack/, -f omnetpp.ini -c Fragmentation -r 0, 1s, 021a-d29a/tplx;1597-ec6a/~tNl;feff-7e88/~tND, PASS, wireless Ipv4 -/showcases/wireless/blockack/, -f omnetpp.ini -c MixedTraffic -r 0, 1s, 5b9e-801f/tplx;8731-2504/~tNl;9724-d1ce/~tND, PASS, wireless Ipv4 +/showcases/wireless/blockack/, -f omnetpp.ini -c NoFragmentation -r 0, 1s, 9161-625d/tplx;6a02-09aa/~tNl;cbc0-3b0a/~tND, PASS, wireless Ipv4 +/showcases/wireless/blockack/, -f omnetpp.ini -c Fragmentation -r 0, 1s, 36f4-5c22/tplx;66b0-94cd/~tNl;45f3-af4f/~tND, PASS, wireless Ipv4 +/showcases/wireless/blockack/, -f omnetpp.ini -c MixedTraffic -r 0, 1s, 351b-d4ba/tplx;5c1f-69a8/~tNl;6182-6da3/~tND, PASS, wireless Ipv4 /showcases/wireless/crosstalk/, -f omnetpp.ini -c CompletelyOverlappingFrequencyBands -r 0, 1s, d0d7-43e0/tplx;867a-07a4/~tNl;fc60-7eb7/~tND;3ea3-43da/tyf, PASS, wireless Ipv4 /showcases/wireless/crosstalk/, -f omnetpp.ini -c IndependentFrequencyBandsOneRadioMediumModule -r 0, 1s, 70c6-72b6/tplx;cf96-5e4d/~tNl;6f3a-074a/~tND;d1b2-9fd4/tyf, PASS, wireless Ipv4 @@ -267,7 +267,7 @@ /showcases/wireless/fragmentation/, -f omnetpp.ini -c DCFnofrag -r 0, 1s, 52b9-628f/tplx;3fec-74a2/~tNl;dbb5-67b0/~tND;8871-1dd1/tyf, PASS, wireless Ipv4 /showcases/wireless/fragmentation/, -f omnetpp.ini -c DCFfrag -r 0, 1s, 8df2-40a3/tplx;dab9-5e8d/~tNl;2e7b-0729/~tND;f985-34fb/tyf, PASS, wireless Ipv4 /showcases/wireless/fragmentation/, -f omnetpp.ini -c HCFfrag -r 0, 1s, c99f-354d/tplx;8e10-a3f0/~tNl;ac4b-3ba1/~tND;335d-6687/tyf, PASS, wireless Ipv4 -/showcases/wireless/fragmentation/, -f omnetpp.ini -c HCFfragblockack -r 0, 1s, f509-65f1/tplx;6b3a-0d65/~tNl;c474-7174/~tND;6f6e-b101/tyf, PASS, wireless Ipv4 +/showcases/wireless/fragmentation/, -f omnetpp.ini -c HCFfragblockack -r 0, 1s, 2597-1e2e/tplx;d269-c6ae/~tNl;2f5c-4cca/~tND;6f6e-b101/tyf, PASS, wireless Ipv4 /showcases/wireless/handover/, -f omnetpp.ini -c General -r 0, 250s, 6150-7a8b/tplx;bcc9-11d2/~tNl;99fd-923d/~tND;02e9-9ad3/tyf, PASS, wireless @@ -341,5 +341,5 @@ /showcases/wireless/throughput/, -f omnetpp.ini -c General -r 0, 1s, 030e-c416/tplx;66e6-0bca/~tNl;3cb5-d354/~tND;e6a5-bde0/tyf, PASS, wireless Ipv4 -/showcases/wireless/txop/, -f omnetpp.ini -c General -r 0, 5s, f58d-d2fd/tplx;38f7-f642/~tNl;c87d-3f3a/tyf, PASS, wireless Ipv4 +/showcases/wireless/txop/, -f omnetpp.ini -c General -r 0, 5s, ab91-87f3/tplx;f30c-6aa4/~tNl;c87d-3f3a/tyf, PASS, wireless Ipv4 diff --git a/tests/module/Ieee80211BlockAckCompletionCost_1.test b/tests/module/Ieee80211BlockAckCompletionCost_1.test new file mode 100644 index 00000000000..358aee3883e --- /dev/null +++ b/tests/module/Ieee80211BlockAckCompletionCost_1.test @@ -0,0 +1,210 @@ +%description: +Measure production Basic setup and transfer completion with equal UDP payload totals. +One run sends twelve packets continuously. The other run sends three bursts of four packets. +Both runs use seed zero, 6 Mbit/s, zero inactivity timeout, and a fixed 100 ms interval. +The measurements describe these traffic shapes. They do not estimate agreement-reuse performance. + +%extraargs: -r 0..1 + +%file: CompletionCost.cc +#include +#include "inet/common/Simsignals.h" +#include "inet/common/packet/Packet.h" +#include "inet/common/TimeTag_m.h" +#include "inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.h" +#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211Tag_m.h" + +namespace inet::ieee80211 { +class CompletionCostHcf : public Hcf { + simtime_t deferredAt = -1; + simtime_t requestQueuedAt = -1; + simtime_t requestSentAt = -1; + simtime_t delbaQueuedAt = -1; + public: + simtime_t deferral; + simtime_t requestContention; + simtime_t responseAfterRequest; + simtime_t delbaCompletion; + protected: + void originatorProcessTransmittedDataFrame(Packet *packet, const Ptr& header, AccessCategory ac) override { + Hcf::originatorProcessTransmittedDataFrame(packet, header, ac); + const auto& procedures = originatorBlockAckAgreementHandler->getProcedures(); + if (procedures.count({header->getReceiverAddress(), header->getTid()}) && deferredAt < 0) + deferredAt = simTime(); + } + void processMgmtFrame(Packet *packet, const Ptr& header) override { + if (dynamicPtrCast(header)) + requestQueuedAt = simTime(); + if (dynamicPtrCast(header)) + delbaQueuedAt = simTime(); + Hcf::processMgmtFrame(packet, header); + } + bool transmitFrame(Packet *packet, simtime_t ifs) override { + auto request = dynamicPtrCast(packet->peekAtFront()); + bool accepted = Hcf::transmitFrame(packet, ifs); + if (accepted && request) { + requestContention += simTime() + ifs - requestQueuedAt; + requestSentAt = simTime() + ifs; + } + return accepted; + } + void processLowerFrame(Packet *packet, const Ptr& header) override { + bool response = dynamicPtrCast(header) != nullptr; + Hcf::processLowerFrame(packet, header); + if (response && deferredAt >= 0) { + deferral += simTime() - deferredAt; + responseAfterRequest += simTime() - requestSentAt; + deferredAt = -1; + } + } + void originatorProcessReceivedFrame(Packet *packet, Packet *transmitted) override { + bool delba = dynamicPtrCast(transmitted->peekAtFront()) != nullptr; + Hcf::originatorProcessReceivedFrame(packet, transmitted); + if (delba) + delbaCompletion += simTime() - delbaQueuedAt; + } +}; +Define_Module(CompletionCostHcf); +class CompletionCostTest : public cSimpleModule, public cListener { + cModule *sender = nullptr; + cModule *sink = nullptr; + int sent = 0; + int received = 0; + int requests = 0; + int responses = 0; + int delbas = 0; + int drops = 0; + int64_t payloadBytes = 0; + simtime_t managementAirtime; + simtime_t deliveryDelay; + protected: + void initialize() override { + scheduleAt(SimTime(1, SIMTIME_MS), new cMessage("subscribe")); + } + void receiveSignal(cComponent *source, simsignal_t signal, cObject *value, cObject *details) override { + auto packet = check_and_cast(value); + if (source == sender) { + sent++; + return; + } + if (source == sink) { + received++; + payloadBytes += packet->getByteLength(); + auto creation = packet->peekAtFront()->getTag()->getCreationTime(); + deliveryDelay += simTime() - creation; + return; + } + if (signal == packetDroppedSignal) { + drops++; + return; + } + auto header = packet->peekAtFront(); + if (dynamicPtrCast(header)) + requests++; + if (dynamicPtrCast(header)) + responses++; + if (dynamicPtrCast(header)) + delbas++; + if (dynamicPtrCast(header)) + managementAirtime += packet->getTag()->getMode()->getDuration(packet->getDataLength()); + } + void handleMessage(cMessage *message) override { + if (message->isName("subscribe")) { + delete message; + sender = getModuleByPath("^.host1.app[0]"); + sink = getModuleByPath("^.host2.app[0]"); + sender->subscribe(packetSentSignal, this); + sink->subscribe(packetReceivedSignal, this); + for (const char *path : {"^.host1.wlan[0].mac.hcf", "^.host2.wlan[0].mac.hcf"}) { + getModuleByPath(path)->subscribe(packetSentToPeerSignal, this); + getModuleByPath(path)->subscribe(packetDroppedSignal, this); + } + scheduleAt(SimTime(99, SIMTIME_MS), new cMessage("verify")); + return; + } + delete message; + auto hcf = check_and_cast(getModuleByPath("^.host1.wlan[0].mac.hcf")); + std::cout << "Completion cost: gaps=" << par("gaps").boolValue() << " sent=" << sent + << " received=" << received << " bytes=" << payloadBytes << " requests=" << requests + << " responses=" << responses << " delbas=" << delbas << " drops=" << drops + << " managementAirtime=" << managementAirtime << " deferral=" << hcf->deferral + << " requestContention=" << hcf->requestContention << " responseAfterRequest=" << hcf->responseAfterRequest + << " delbaCompletion=" << hcf->delbaCompletion << " deliveryDelaySum=" << deliveryDelay + << " goodputBps=" << payloadBytes * 8 / 0.1 << "\n"; + ASSERT(sent == 12 && received == 12 && payloadBytes == 8400 && drops == 0); + ASSERT(requests == (par("gaps").boolValue() ? 3 : 1)); + ASSERT(responses == requests && delbas == requests); + std::cout << "Block Ack completion cost assertions passed.\n"; + endSimulation(); + } +}; +Define_Module(CompletionCostTest); +} + +%file: test.ned +import inet.linklayer.ieee80211.mac.coordinationfunction.Hcf; +import inet.node.inet.AdhocHost; +import inet.networklayer.configurator.ipv4.Ipv4NetworkConfigurator; +import inet.physicallayer.wireless.ieee80211.packetlevel.Ieee80211ScalarRadioMedium; +module CompletionCostHcf extends Hcf { parameters: @class(::inet::ieee80211::CompletionCostHcf); } +simple CompletionCostTest { parameters: bool gaps; @class(::inet::ieee80211::CompletionCostTest); } +network CompletionCostNetwork { + submodules: + configurator: Ipv4NetworkConfigurator; + radioMedium: Ieee80211ScalarRadioMedium; + host1: AdhocHost; + host2: AdhocHost; + test: CompletionCostTest; +} + +%inifile: omnetpp.ini +[General] +network = CompletionCostNetwork +ned-path = .;../../../../src +sim-time-limit = 100ms +seed-set = 0 +cmdenv-express-mode = true +record-vector-results = false +record-scalar-results = false +*.test.gaps = ${gaps=false,true} +*.host1.numApps = 1 +*.host1.app[0].typename = "UdpBasicBurst" +*.host1.app[0].destAddresses = "host2" +*.host1.app[0].destPort = 1000 +*.host1.app[0].messageLength = 700B +*.host1.app[0].chooseDestAddrMode = "once" +*.host1.app[0].startTime = 10ms +*.host1.app[0].stopTime = ${gaps} ? 52ms : 11.15ms +*.host1.app[0].sendInterval = 100us +*.host1.app[0].burstDuration = ${gaps} ? 350us : 0s +*.host1.app[0].sleepDuration = ${gaps} ? 20ms : 0s +*.host2.numApps = 1 +*.host2.app[0].typename = "UdpSink" +*.host2.app[0].localPort = 1000 +*.host*.ipv4.arp.typename = "GlobalArp" +*.host*.wlan[*].opMode = "a" +*.host*.wlan[*].bitrate = 6Mbps +*.host*.wlan[*].classifier.typename = "QosClassifier" +*.host*.wlan[*].mac.qosStation = true +*.host*.wlan[*].mac.hcf.typename = "CompletionCostHcf" +*.host*.wlan[*].mac.hcf.isBlockAckSupported = true +*.host*.wlan[*].mac.hcf.blockAckVariant = "basic" +**.originatorMacDataService.msduAggregationPolicy.typename = "" +**.originatorMacDataService.fragmentationPolicy.fragmentationThreshold = 2346B +*.host*.wlan[*].radio.receiver.energyDetection = -105dBm +*.host*.wlan[*].radio.receiver.sensitivity = -105dBm +*.host*.wlan[*].radio.receiver.snirThreshold = 0dB +**.mobility.initFromDisplayString = false +**.mobility.constraintAreaMinX = 0m +**.mobility.constraintAreaMinY = 0m +**.mobility.constraintAreaMinZ = 0m +**.mobility.constraintAreaMaxX = 100m +**.mobility.constraintAreaMaxY = 100m +**.mobility.constraintAreaMaxZ = 0m +*.host1.mobility.initialX = 0m +*.host2.mobility.initialX = 10m +**.mobility.initialY = 0m +**.mobility.initialZ = 0m + +%contains: stdout +Block Ack completion cost assertions passed. diff --git a/tests/module/Ieee80211BlockAckDataSelection_1.test b/tests/module/Ieee80211BlockAckDataSelection_1.test index 1282837f8ca..93aea4983b5 100644 --- a/tests/module/Ieee80211BlockAckDataSelection_1.test +++ b/tests/module/Ieee80211BlockAckDataSelection_1.test @@ -185,6 +185,14 @@ class DataSelectionTest : public cSimpleModule, public cListener { ASSERT(queue->getPacket(0) == first); ASSERT(service->peekEligibleFrame(queue) == selected); ASSERT(service->getNextSequenceNumber(MacAddress("02:00:00:00:00:02"), 0) == SequenceNumberCyclic(0)); + auto previewService = check_and_cast(service); + auto frames = edca->getEdcaf(AC_BE)->getInProgressFrames(); + auto owner = selected->getOwner(); + ASSERT(previewService->peekEligibleFrame(queue) == selected); + ASSERT(frames->peekFrameToTransmit() == selected); + ASSERT(frames->getCandidateSequenceNumber(selected) == SequenceNumberCyclic(0)); + ASSERT(frames->getLength() == 0 && selected->getOwner() == owner); + ASSERT(selected->peekAtFront()->getSequenceNumber() == SequenceNumberCyclic(77)); wait(SimTime(100, SIMTIME_MS)); auto extracted = service->extractFramesToTransmit(queue); ASSERT(extracted != nullptr && extracted->size() == 1); diff --git a/tests/module/Ieee80211BlockAckDeferral_1.test b/tests/module/Ieee80211BlockAckDeferral_1.test index 89da8e14084..58f6614bc96 100644 --- a/tests/module/Ieee80211BlockAckDeferral_1.test +++ b/tests/module/Ieee80211BlockAckDeferral_1.test @@ -29,6 +29,8 @@ class DeferralHcf : public Hcf { int dataVoice = 0; int dataVideo = 0; int dataAfterRequest = 0; + int dataWithAgreement = 0; + int dataAfterDelba = 0; int aggregatesAccepted = 0; int requestStart = -1; int firstData = -1; @@ -118,6 +120,12 @@ class DeferralHcf : public Hcf { if (data->getTid() == 6) dataVoice++; if (data->getTid() == 5) dataVideo++; if (requestStart >= 0 && data->getTid() == 6) { + if (hasAgreement(6)) + dataWithAgreement++; + if (delbas > 0 && !hasAgreement(6)) { + ASSERT(data->getAckPolicy() == NORMAL_ACK); + dataAfterDelba++; + } if (firstData < 0) firstData = data->getSequenceNumber().get(); dataAfterRequest++; } @@ -203,7 +211,7 @@ class DeferralTest : public cSimpleModule, public cListener { << ", aggregates=" << sender->aggregatesAccepted << ", request start=" << sender->requestStart << ", first DATA=" << sender->firstData << ".\n"; ASSERT(deferredBeforeExtraction); - ASSERT(sender->requests == 1 && sender->hasAgreement(6)); + ASSERT(sender->requests == 1 && !sender->hasAgreement(6) && sender->delbas == 1); ASSERT(sender->requestStart == 1 && sender->firstData == sender->requestStart); ASSERT(sender->dataAfterRequest == 1); ASSERT(sender->aggregatesAccepted == (scenario == 11 ? 2 : 0)); @@ -249,10 +257,16 @@ class DeferralTest : public cSimpleModule, public cListener { wait(SimTime(560, SIMTIME_MS) - simTime()); ASSERT(sender->rtsFailures >= 1); ASSERT(sender->firstRtsSequence == sender->requestStart); - ASSERT(sender->dataAfterRequest == 0 && sender->firstData == -1); + ASSERT(sender->dataWithAgreement == 0); + if (scenario == 8) { + ASSERT(sender->dataAfterRequest == 1 && sender->dataAfterDelba == 1); + ASSERT(sender->firstData == (sender->requestStart + 1) % 4096); + } + else + ASSERT(sender->dataAfterRequest == 0 && sender->firstData == -1); ASSERT(!sender->hasAgreement(6)); ASSERT(sender->delbas == 1); - ASSERT(lifetimeDrops == (scenario == 9 ? 1 : 0)); + ASSERT(lifetimeDrops == (scenario == 9 ? 2 : 0)); } else if (scenario >= 5) { auto edca = check_and_cast(sender->getSubmodule("edca")); @@ -271,7 +285,8 @@ class DeferralTest : public cSimpleModule, public cListener { accept(sender, 6); } wait(SimTime(513, SIMTIME_MS) - simTime()); - ASSERT(lifetimeDrops == 1 && lifetime->findFrame(deferredId) == nullptr); + // Preview leaves both unsent frames under their original lifetime deadlines. + ASSERT(lifetimeDrops == 2 && lifetime->findFrame(deferredId) == nullptr); if (scenario == 6) ASSERT(sender->delbas == 1 && sender->dataAfterRequest == 0); else { @@ -284,7 +299,7 @@ class DeferralTest : public cSimpleModule, public cListener { << ", response deadline=" << sender->observedDeadline << ", original DATA deadline=0.512.\n"; } else if (scenario == 2) { - ASSERT(sender->dataAfterRequest == 1); + ASSERT(sender->dataAfterRequest == 2); ASSERT(sender->firstData == sender->requestStart); } else { @@ -315,9 +330,12 @@ class DeferralTest : public cSimpleModule, public cListener { ASSERT(!sender->hasAgreement(6)); } else { - ASSERT(sender->delbas == 0); - ASSERT(sender->hasAgreement(6)); - ASSERT(sender->dataAfterRequest == 1); + // The accepted response releases the final DATA before completion causes DELBA. + ASSERT(simTime() < sender->observedDeadline); + ASSERT(sender->delbas == 1); + ASSERT(!sender->hasAgreement(6)); + std::cout << "Completed deferred DATA: " << sender->dataAfterRequest << ".\n"; + ASSERT(sender->dataAfterRequest == 2); ASSERT(sender->firstData == sender->requestStart); } } diff --git a/tests/module/Ieee80211BlockAckFragmentRetirement_1.test b/tests/module/Ieee80211BlockAckFragmentRetirement_1.test index 33429c70e6a..47377708224 100644 --- a/tests/module/Ieee80211BlockAckFragmentRetirement_1.test +++ b/tests/module/Ieee80211BlockAckFragmentRetirement_1.test @@ -2,7 +2,7 @@ Check the sequence boundary after ordinary originator teardown of fragmented DATA. IEEE Std 802.11-2024, 11.5.3.4 requires the next MPDU to use a later sequence when the originator discards the last transmitted MPDU. -The fixture supplies accepted Basic agreements and injects immediate ACKs. +The fixture supplies accepted Basic agreements and injects immediate ACKs and Basic Block Ack responses. Production fragmentation, inactivity expiry, retirement, and transmission remain active. Runs cover sequence 0 and wraparound at 4095, with expiry during transmission or after the first fragment receives its Normal Ack. @@ -10,6 +10,7 @@ Later intact DATA and an unrelated peer must retain their transmissions. Additional runs transmit an earlier DATA unit before a gap in sequence allocation. The fixture extracts and disposes of the skipped DATA through the production allocator. Distances 2047, 2048, 2049, and 4096 cover the half-range boundary and a full wrap. +A deferred successor keeps the transfer open while the fixture advances the allocator. %extraargs: -r 0..19 @@ -45,6 +46,9 @@ class FragmentRetirementHcf : public Hcf { bool retired = false; bool successorSent = false; bool otherSent = false; + bool otherRetired = false; + Ptr pendingBar; + Packet *deferredSuccessor = nullptr; int delbas = 0; void skipData(int count) { @@ -75,7 +79,7 @@ class FragmentRetirementHcf : public Hcf { scheduleAfter(SimTime(acknowledgedFirst ? 650 : 974, SIMTIME_US), new cMessage("queue-data")); } - void queueData(const char *name, MacAddress address, int length) { + Packet *queueData(const char *name, MacAddress address, int length) { auto header = makeShared(); header->setType(ST_DATA_WITH_QOS); header->addChunkLength(QOSCONTROL_PART_LENGTH); @@ -87,6 +91,7 @@ class FragmentRetirementHcf : public Hcf { packet->insertAtBack(makeShared(B(length))); packet->insertAtBack(makeShared()); processUpperFrame(packet, header); + return packet; } public: @@ -106,9 +111,13 @@ class FragmentRetirementHcf : public Hcf { if (distance == 0) startRetirement(); else { + check_and_cast(originatorDataService)->setEligibility( + [this](const Packet *packet) { return !packet->isName("deferred-successor") && isFrameEligible(packet, false); }, + [this](Packet *packet) { return isAMsduPermitted(packet); }); // Force Normal Ack for the earlier DATA, independent of the fragment ACK policy. handler->getAgreement(peer, 5)->setStartingSequenceNumber(SequenceNumberCyclic(start) + 1); queueData("earlier-data", peer, 20); + deferredSuccessor = queueData("deferred-successor", peer, 20); } scheduleAfter(SimTime(10, SIMTIME_MS), new cMessage("verify")); } @@ -119,6 +128,13 @@ class FragmentRetirementHcf : public Hcf { Hcf::receiveSignal(source, signal, object, details); return; } + auto agreement = check_and_cast(object); + if (agreement->getReceiverAddr() == other) { + ASSERT(otherSent); + ASSERT(!hasQueuedData(other, 5) && !hasNumberedData(other, 5)); + otherRetired = true; + return; + } ASSERT(!retired); retired = true; ASSERT(firstCompleted == acknowledgedFirst); @@ -164,6 +180,11 @@ class FragmentRetirementHcf : public Hcf { void transmissionComplete(Packet *packet, const Ptr& header) override { Enter_Method("transmissionComplete"); auto data = dynamicPtrCast(header); + auto bar = dynamicPtrCast(header); + if (bar) { + ASSERT(bar->getReceiverAddress() == other); + pendingBar = bar; + } bool earlier = packet->isName("earlier-data"); bool first = !earlier && data && data->getReceiverAddress() == peer && data->getSequenceNumber() == SequenceNumberCyclic(start); bool ack = dynamicPtrCast(header) || (data && data->getAckPolicy() == NORMAL_ACK); @@ -174,6 +195,8 @@ class FragmentRetirementHcf : public Hcf { Hcf::transmissionComplete(packet, header); if (ack) scheduleAfter(SimTime(20, SIMTIME_US), new cMessage(earlier ? "ack-earlier" : first ? "ack-first" : "ack")); + if (bar) + scheduleAfter(SimTime(20, SIMTIME_US), new cMessage("block-ack")); } void handleMessage(cMessage *message) override { @@ -183,6 +206,24 @@ class FragmentRetirementHcf : public Hcf { queueData("intact-successor", peer, 20); queueData("other-peer", other, 20); } + else if (message->isName("block-ack")) { + delete message; + auto header = makeShared(); + header->setReceiverAddress(mac->getAddress()); + header->setTransmitterAddress(other); + header->setTidInfo(5); + header->setStartingSequenceNumber(pendingBar->getStartingSequenceNumber()); + BitVector bits; + bits.appendBit(true); + for (int i = 1; i < 16; i++) + bits.appendBit(false); + header->setBlockAckBitmap(0, bits); + auto packet = new Packet("block-ack", header); + packet->insertAtBack(makeShared()); + packet->addTag()->setMode(modeSet->getMode(bps(24000000))); + pendingBar = nullptr; + processLowerFrame(packet, header); + } else if (message->isName("ack") || message->isName("ack-first") || message->isName("ack-earlier")) { bool first = message->isName("ack-first"); bool earlier = message->isName("ack-earlier"); @@ -196,6 +237,12 @@ class FragmentRetirementHcf : public Hcf { if (first) firstAcknowledged = true; if (earlier) { + auto queue = edca->getEdcaf(AC_VI)->getPendingQueue(); + queue->removePacket(deferredSuccessor); + take(deferredSuccessor); + edca->getLifetimeHandler()->forgetFrame(deferredSuccessor->getId()); + delete deferredSuccessor; + deferredSuccessor = nullptr; skipData(distance - 1); start = (start + distance) % 4096; startRetirement(); @@ -203,9 +250,11 @@ class FragmentRetirementHcf : public Hcf { } else if (message->isName("verify")) { delete message; + std::cout << "Fragment retirement state: retired=" << retired << " firstCompleted=" << firstCompleted + << " successorSent=" << successorSent << " otherSent=" << otherSent << " delbas=" << delbas << "\n"; ASSERT(retired && firstCompleted && successorSent && otherSent); - ASSERT(delbas == 1); - ASSERT(originatorBlockAckAgreementHandler->getAgreement(other, 5) != nullptr); + ASSERT(delbas == 2 && otherRetired); + ASSERT(originatorBlockAckAgreementHandler->getAgreement(other, 5) == nullptr); unsubscribe(blockAckAgreementDeletedSignal, this); std::cout << "Fragment retirement passed: start=" << start << ", acknowledgedFirst=" << acknowledgedFirst << ", distance=" << distance << std::endl; diff --git a/tests/module/Ieee80211BlockAckScheduling_1.test b/tests/module/Ieee80211BlockAckScheduling_1.test new file mode 100644 index 00000000000..3fe472f6f68 --- /dev/null +++ b/tests/module/Ieee80211BlockAckScheduling_1.test @@ -0,0 +1,455 @@ +%description: +Exercise Basic BAR selection and final DELBA through HCF, frame sequences, EDCA, and Tx. +The fixture supplies accepted agreements and injects responses at the HCF receive boundary. +Response events include SIFS and the selected response airtime. +Cases cover short bursts, windows smaller than the threshold, two peers, BAR timeout, +negative bitmap bits, Normal Ack window progress, and late BAR admission. + +%extraargs: -r 0..29 + +%file: Scheduling.cc +#include +#include "inet/common/Simsignals.h" +#include "inet/common/packet/chunk/ByteCountChunk.h" +#include "inet/linklayer/ieee80211/mac/Ieee80211Mac.h" +#include "inet/linklayer/ieee80211/mac/Ieee80211DataSequenceTag_m.h" +#include "inet/linklayer/ieee80211/mac/coordinationfunction/Hcf.h" +#include "inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.h" +#include "inet/linklayer/ieee80211/mac/blockack/RecipientBlockAckAgreementHandler.h" +#include "inet/linklayer/ieee80211/mac/Rx.h" +#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211Tag_m.h" + +namespace inet::ieee80211 { +class SchedulingRecipientAgreements : public RecipientBlockAckAgreementHandler { + public: + void accept(MacAddress peer) { + auto agreement = new RecipientBlockAckAgreement(peer, 5, SequenceNumberCyclic(0), 64, SIMTIME_ZERO); + agreement->addbaResposneSent(); + agreement->calculateExpirationTime(); + blockAckAgreements[{peer, 5}] = agreement; + } +}; +class SchedulingRecipient : public Hcf { + public: + std::vector delivered; + bool checkedBitmap = false; + void prepare() { + Enter_Method("prepare"); + delete recipientBlockAckAgreementHandler; + auto agreements = new SchedulingRecipientAgreements(); + recipientBlockAckAgreementHandler = agreements; + agreements->accept(MacAddress("02:00:00:00:00:01")); + subscribe(blockAckAgreementDeletedSignal, this); + } + void receive(Packet *packet) { + Enter_Method("receive"); + auto header = packet->peekAtFront(); + if (auto data = dynamicPtrCast(header)) { + if (data->getSequenceNumber() == SequenceNumberCyclic(0) && data->getFragmentNumber() != 0) { + delete packet; + return; + } + } + auto mode = packet->getTag()->getMode(); + packet->addTagIfAbsent()->setMode(mode); + processLowerFrame(packet, header); + } + bool retired() const { return recipientBlockAckAgreementHandler->getAgreements().empty(); } + protected: + void receiveSignal(cComponent *source, simsignal_t signal, cObject *value, cObject *details) override { + if (signal == blockAckAgreementDeletedSignal) + ASSERT((delivered == std::vector{1, 2})); + else + Hcf::receiveSignal(source, signal, value, details); + } + void sendUp(const std::vector& frames) override { + for (auto frame : frames) { + delivered.push_back(frame->peekAtFront()->getSequenceNumber().get()); + take(frame); + delete frame; + } + } + void transmitControlResponseFrame(Packet *packet, const Ptr& header, + Packet *, const Ptr&) override { + if (auto response = dynamicPtrCast(header)) { + ASSERT(response->getStartingSequenceNumber() == SequenceNumberCyclic(0)); + ASSERT(response->getBlockAckBitmap(0).getBit(0)); + ASSERT(!response->getBlockAckBitmap(0).getBit(1)); + if (response->getBlockAckBitmap(1).getBit(0) && response->getBlockAckBitmap(2).getBit(0)) { + checkedBitmap = true; + ASSERT(delivered.empty()); + } + } + delete packet; + } +}; +Define_Module(SchedulingRecipient); +class SchedulingAgreements : public OriginatorBlockAckAgreementHandler { + public: + void accept(MacAddress peer, int size) { + auto request = makeShared(); + request->setReceiverAddress(peer); + request->setTid(5); + request->setStartingSequenceNumber(SequenceNumberCyclic(0)); + request->setBufferSize(size); + request->setBlockAckPolicy(true); + createAgreement(request); + auto agreement = getAgreement(peer, 5); + agreement->setIsAddbaResponseReceived(true); + agreement->setBlockAckTimeoutValue(SIMTIME_ZERO); + agreement->calculateExpirationTime(); + finishProcedure(peer, 5); + } +}; +class SchedulingHcf : public Hcf { + const MacAddress peer{"02:00:00:00:00:02"}; + const MacAddress other{"02:00:00:00:00:03"}; + int dataCount = 0; + int bars = 0; + int delbas = 0; + int refusedBars = 0; + int retries = 0; + int dataInTxop = 0; + bool responsePending = false; + Ptr pendingBar; + const physicallayer::IIeee80211Mode *pendingResponseMode = nullptr; + bool firstBarWasStandalone = false; + int expired = 0; + int collisions = 0; + SchedulingRecipient *recipient = nullptr; + simtime_t responseEnd; + simtime_t txopDeadline; + int scenario() const { return par("scenario"); } + int burst() const { + switch (scenario()) { + case 0: return 1; + case 1: return 4; + case 2: return 6; + case 3: return 9; + case 4: return 4; + case 5: return 1; + case 6: return 1; + case 7: return 2; + case 9: return 3; + case 10: return 1; + case 11: return 8; + case 12: return 1; + case 13: return 1; + case 14: return 1; + default: return 4; + } + } + int window() const { return scenario() == 2 || scenario() == 7 ? 1 : scenario() == 3 ? 4 : 64; } + public: + void begin() { + Enter_Method("begin"); + delete originatorBlockAckAgreementHandler; + auto agreements = new SchedulingAgreements(); + originatorBlockAckAgreementHandler = agreements; + agreements->accept(peer, window()); + if (scenario() == 9) { + recipient = check_and_cast(getModuleByPath("^.^.^.^.recipient.wlan[0].mac.hcf")); + recipient->prepare(); + subscribe(packetDroppedSignal, this); + } + if (scenario() == 4) + agreements->accept(other, 64); + rx->setContentionBlocked(true); + for (int i = 0; i < burst(); i++) + queueData(peer, scenario() == 9 ? (i == 0 ? 200 : 10) : scenario() == 7 && i == 0 ? 1100 : 100); + if (scenario() == 12 || scenario() == 14) { + auto frames = edca->getEdcaf(AC_VI)->getInProgressFrames(); + auto frame = frames->getFrameToTransmit(); + auto header = frame->removeAtFront(); + header->setAckPolicy(BLOCK_ACK); + frame->insertAtFront(header); + edca->getEdcaf(AC_VI)->getAckHandler()->processTransmittedDataOrMgmtFrame(header); + originatorBlockAckAgreementHandler->getAgreement(peer, 5)->recordTransmittedData( + frame->getTag()->getAllocationIndex()); + dataCount = 1; + queueData(other, 1100, 6); + } + if (scenario() == 4) { + for (int i = 0; i < 8; i++) + queueData(other, 100); + } + rx->setContentionBlocked(false); + scheduleAfter(SimTime(40, SIMTIME_MS), new cMessage("verify")); + } + protected: + void receiveSignal(cComponent *source, simsignal_t signal, cObject *value, cObject *details) override { + if (signal == packetDroppedSignal) { + auto drop = dynamic_cast(details); + if (drop && drop->getReason() == LIFETIME_EXPIRED) + expired++; + if (source == this) + return; + } + Hcf::receiveSignal(source, signal, value, details); + } + void queueData(MacAddress receiver, int length, Tid tid = 5) { + auto header = makeShared(); + header->setType(ST_DATA_WITH_QOS); + header->addChunkLength(QOSCONTROL_PART_LENGTH); + header->setTid(tid); + header->setSequenceNumber(SequenceNumberCyclic(77)); + header->setReceiverAddress(receiver); + header->setTransmitterAddress(mac->getAddress()); + header->setAddress3(receiver); + auto packet = new Packet("data", header); + packet->insertAtBack(makeShared(B(length))); + packet->insertAtBack(makeShared()); + processUpperFrame(packet, header); + } + void frameSequenceStarted() override { + dataInTxop = 0; + Hcf::frameSequenceStarted(); + } + void channelGranted(IChannelAccess *access) override { + auto collided = edca->getInternallyCollidedEdcafs(); + if (scenario() == 12 || scenario() == 14) + collisions += collided.size(); + Hcf::channelGranted(access); + if (scenario() == 14 && !collided.empty()) { + auto edcaf = edca->getEdcaf(AC_VI); + ASSERT(edcaf->getCw() == 1); + auto frame = edcaf->getInProgressFrames()->getFrames(0); + bool absent = false; + try { + edcaf->getRecoveryProcedure()->getRetryCount(frame, frame->peekAtFront()); + } + catch (const cRuntimeError& error) { + absent = std::string(error.what()).find("retry counter entry doesn't exist") != std::string::npos; + } + ASSERT(absent); + } + } + bool transmitFrame(Packet *packet, simtime_t ifs) override { + auto header = packet->peekAtFront(); + auto bar = dynamicPtrCast(header); + if (bar) { + auto frames = edca->getChannelOwner()->getInProgressFrames(); + auto candidate = frames->peekFrameToTransmit(); + if (candidate && !frames->containsFrame(candidate)) { + auto sequence = candidate->peekAtFront()->getSequenceNumber(); + auto size = frames->getLength(); + ASSERT(frames->peekFrameToTransmit() == candidate); + ASSERT(frames->getLength() == size); + ASSERT(candidate->peekAtFront()->getSequenceNumber() == sequence); + } + } + bool accepted = Hcf::transmitFrame(packet, ifs); + if (bar && !accepted) { + refusedBars++; + return false; + } + if (!accepted) + return false; + header = packet->peekAtFront(); + if (auto data = dynamicPtrCast(header)) { + auto txop = edca->getChannelOwner()->getTxopProcedure(); + if (!par("multiple").boolValue() && txop->getLimit() == 0 && data->getAckPolicy() == BLOCK_ACK) + ASSERT(data->getDurationField() == SIMTIME_ZERO); + if (!par("multiple").boolValue() && scenario() == 3) { + ASSERT(dataInTxop == 0); + ASSERT(data->getDurationField() == SIMTIME_ZERO); + } + if (scenario() == 4 && data->getReceiverAddress() == other) + ASSERT(bars >= 1); + auto agreement = originatorBlockAckAgreementHandler->getAgreement(data->getReceiverAddress(), data->getTid()); + if ((scenario() == 12 || scenario() == 14) && data->getTid() == 6) + ASSERT(!data->getRetry()); + else + ASSERT(agreement != nullptr && agreement->containsSequence(data->getSequenceNumber())); + if (scenario() != 7 && data->getSequenceNumber().get() >= window() && data->getReceiverAddress() == peer) + ASSERT(bars >= 1); + if (data->getRetry()) + retries++; + dataCount++; + dataInTxop++; + } + if (bar) { + bars++; + if (bars == 1) { + firstBarWasStandalone = dataInTxop == 0; + ASSERT(bar->getReceiverAddress() == peer); + ASSERT(bar->getTidInfo() == 5); + if (scenario() != 9) + ASSERT(dataCount == (scenario() == 2 ? 1 : scenario() == 3 ? 4 : scenario() == 7 || scenario() == 12 || scenario() == 14 ? 2 : scenario() == 11 ? 5 : burst())); + } + auto mode = packet->getTag()->getMode(); + auto responseMode = rateSelection->computeResponseBlockAckFrameMode(packet, bar, ResponseQueryRole::PREDICT); + auto cost = mode->getDuration(packet->getDataLength()) + modeSet->getSifsTime() + responseMode->getDuration(LENGTH_BASIC_BLOCKACK); + auto txop = edca->getChannelOwner()->getTxopProcedure(); + auto end = simTime() + ifs + cost; + if (dataInTxop > 1 && txop->getLimit() > 0) + ASSERT(end <= txop->getStart() + txop->getLimit()); + std::cout << "BAR timing: scenario=" << scenario() << " multiple=" << par("multiple").boolValue() + << " start=" << simTime() << " ifs=" << ifs << " bytes=" << packet->getByteLength() + << " rate=" << mode->getDataMode()->getNetBitrate() << " responseRate=" << responseMode->getDataMode()->getNetBitrate() + << " response=" << responseMode->getDuration(LENGTH_BASIC_BLOCKACK) << " end=" << end + << " deadline=" << txop->getStart() + txop->getLimit() << " data=" << dataInTxop << "\n"; + } + if (auto delba = dynamicPtrCast(header)) { + ASSERT(delba->getInitiator()); + ASSERT(!hasQueuedData(delba->getReceiverAddress(), delba->getTid())); + ASSERT(!hasNumberedData(delba->getReceiverAddress(), delba->getTid())); + delbas++; + } + return true; + } + void transmissionComplete(Packet *packet, const Ptr& header) override { + Enter_Method("transmissionComplete"); + auto bar = dynamicPtrCast(header); + auto data = dynamicPtrCast(header); + if (recipient && (data || bar || dynamicPtrCast(header))) + recipient->receive(packet->dup()); + bool ack = dynamicPtrCast(header) || (data && data->getAckPolicy() == NORMAL_ACK); + if (bar || ack) { + if (!(bar && scenario() == 5 && bars == 1)) { + pendingBar = bar; + responsePending = true; + pendingResponseMode = bar ? + rateSelection->computeResponseBlockAckFrameMode(packet, bar, ResponseQueryRole::PREDICT) : + rateSelection->computeResponseAckFrameMode(packet, dynamicPtrCast(header), ResponseQueryRole::PREDICT); + auto duration = pendingResponseMode->getDuration(bar ? LENGTH_BASIC_BLOCKACK : LENGTH_ACK); + responseEnd = simTime() + modeSet->getSifsTime() + duration; + txopDeadline = edca->getChannelOwner()->getTxopProcedure()->getStart() + edca->getChannelOwner()->getTxopProcedure()->getLimit(); + scheduleAt(responseEnd, new cMessage("response")); + } + } + Hcf::transmissionComplete(packet, header); + } + bool isReceptionInProgress() override { return responsePending || Hcf::isReceptionInProgress(); } + void handleMessage(cMessage *message) override { + if (message->isName("response")) { + delete message; + responsePending = false; + Ptr header; + if (pendingBar) { + auto response = makeShared(); + response->setTransmitterAddress(pendingBar->getReceiverAddress()); + response->setTidInfo(pendingBar->getTidInfo()); + response->setStartingSequenceNumber(pendingBar->getStartingSequenceNumber()); + for (int i = 0; i < 64; i++) { + BitVector bits; + for (int j = 0; j < 16; j++) + bits.appendBit(scenario() == 9 ? (i != 0 || j == 0) : !(scenario() == 6 && bars == 1)); + response->setBlockAckBitmap(i, bits); + } + header = response; + } + else + header = makeShared(); + header->setReceiverAddress(mac->getAddress()); + auto packet = new Packet("response", header); + packet->insertAtBack(makeShared()); + packet->addTag()->setMode(pendingResponseMode); + pendingBar = nullptr; + processLowerFrame(packet, header); + } + else if (message->isName("verify")) { + delete message; + std::cout << "Scheduling totals: data=" << dataCount << " bars=" << bars << " delbas=" << delbas << " refused=" << refusedBars << "\n"; + ASSERT(bars > 0); + ASSERT(delbas == (scenario() == 4 ? 2 : 1)); + if (scenario() != 9) + ASSERT(dataCount == burst() + (scenario() == 4 ? 8 : scenario() == 5 || scenario() == 6 || scenario() == 12 || scenario() == 14 ? 1 : 0)); + else { + ASSERT(recipient->checkedBitmap && recipient->retired()); + ASSERT((recipient->delivered == std::vector{1, 2})); + ASSERT(dataCount > 3); + ASSERT(expired > 0); + } + ASSERT(originatorBlockAckAgreementHandler->getAgreements().empty()); + ASSERT(originatorBlockAckAgreementHandler->getProcedures().empty()); + ASSERT(edca->getLifetimeHandler()->getNumFrames() == 0); + ASSERT(!frameSequenceHandler->isSequenceRunning()); + if (scenario() == 5 || scenario() == 6) + ASSERT(retries == 1 && bars == 2); + if (scenario() == 8 || scenario() == 10 || scenario() == 13) + ASSERT(firstBarWasStandalone); + if (scenario() == 12 || scenario() == 14) + ASSERT(collisions == 1 && retries == 0); + std::cout << "Block Ack scheduling assertions passed.\n"; + endSimulation(); + } + else + Hcf::handleMessage(message); + } +}; +Define_Module(SchedulingHcf); +class SchedulingTest : public cSimpleModule { + protected: + void initialize() override { scheduleAt(SimTime(1, SIMTIME_MS), new cMessage("begin")); } + void handleMessage(cMessage *message) override { + delete message; + check_and_cast(getModuleByPath("^.host.wlan[0].mac.hcf"))->begin(); + } +}; +Define_Module(SchedulingTest); +} + +%file: test.ned +import inet.linklayer.ieee80211.mac.coordinationfunction.Hcf; +import inet.node.inet.WirelessHost; +import inet.physicallayer.wireless.ieee80211.packetlevel.Ieee80211ScalarRadioMedium; +module SchedulingHcf extends Hcf { parameters: int scenario; bool multiple; @class(::inet::ieee80211::SchedulingHcf); } +module SchedulingRecipient extends Hcf { parameters: @class(::inet::ieee80211::SchedulingRecipient); } +simple SchedulingTest { parameters: @class(::inet::ieee80211::SchedulingTest); } +network SchedulingNetwork { + submodules: + radioMedium: Ieee80211ScalarRadioMedium; + host: WirelessHost; + recipient: WirelessHost; + test: SchedulingTest; +} + +%inifile: omnetpp.ini +[General] +network = SchedulingNetwork +ned-path = .;../../../../src +sim-time-limit = 50ms +seed-set = 0 +cmdenv-express-mode = true +record-vector-results = false +record-scalar-results = false +**.wlan[*].agent.typename = "" +**.wlan[*].mgmt.typename = "Ieee80211MgmtAdhoc" +**.wlan[*].opMode = "a" +**.wlan[*].bitrate = 6Mbps +*.host.wlan[*].address = "02:00:00:00:00:01" +*.recipient.wlan[*].address = "02:00:00:00:00:02" +**.wlan[*].mac.qosStation = true +*.recipient.wlan[*].mac.hcf.typename = "SchedulingRecipient" +*.host.wlan[*].mac.hcf.typename = "SchedulingHcf" +**.wlan[*].mac.hcf.scenario = ${scenario=0..14} +**.wlan[*].mac.hcf.multiple = ${multiple=false,true} +**.wlan[*].mac.hcf.isBlockAckSupported = true +**.wlan[*].mac.hcf.blockAckVariant = "basic" +**.wlan[*].mac.hcf.originatorAckPolicy.ackTimeout = 1ms +**.wlan[*].mac.hcf.originatorAckPolicy.blockAckTimeout = 1ms +**.wlan[*].mac.hcf.rtsPolicy.rtsThreshold = 2346B +**.wlan[*].mac.hcf.originatorMacDataService.msduAggregationPolicy.typename = "" +**.wlan[*].mac.hcf.originatorMacDataService.fragmentationPolicy.fragmentationThreshold = ${scenario} == 9 ? 128B : 2346B +**.wlan[*].mac.hcf.edca.edcaf[*].msduLifetime = ${scenario} == 9 ? 10ms : 512ms +**.wlan[*].mac.hcf.edca.edcaf[*].cwMin = ${scenario} == 12 || ${scenario} == 14 ? 0 : -1 +**.wlan[*].mac.hcf.edca.edcaf[2].cwMax = ${scenario} == 14 ? 3 : ${scenario} == 12 ? 0 : -1 +**.wlan[*].mac.hcf.edca.edcaf[2].recoveryProcedure.shortRetryLimit = ${scenario} == 14 ? 1 : 7 +**.wlan[*].mac.hcf.edca.edcaf[*].cwMax = ${scenario} == 12 || ${scenario} == 14 ? 0 : -1 +**.wlan[*].mac.hcf.edca.edcaf[*].txopProcedure.protectionMechanism = ${multiple} ? "multiple" : "single" +**.wlan[*].mac.hcf.edca.edcaf[2].txopProcedure.txopLimit = ${scenario} == 8 ? 900us : ${scenario} == 10 ? 0s : ${scenario} == 11 ? 1160us : ${scenario} == 13 ? 50us : 10ms +**.mobility.initFromDisplayString = false +**.mobility.constraintAreaMinX = 0m +**.mobility.constraintAreaMinY = 0m +**.mobility.constraintAreaMinZ = 0m +**.mobility.constraintAreaMaxX = 2000000m +**.mobility.constraintAreaMaxY = 100m +**.mobility.constraintAreaMaxZ = 0m +*.recipient.mobility.initialX = 1000000m +*.host.mobility.initialX = 0m +**.mobility.initialY = 0m +**.mobility.initialZ = 0m + +%contains: stdout +Block Ack scheduling assertions passed. diff --git a/tests/module/Ieee80211HcfHeader_1.test b/tests/module/Ieee80211HcfHeader_1.test index 81703858adf..595c2b1b6b7 100644 --- a/tests/module/Ieee80211HcfHeader_1.test +++ b/tests/module/Ieee80211HcfHeader_1.test @@ -20,7 +20,7 @@ class HeaderAckPolicy : public OriginatorQosAckPolicy { selections++; return BLOCK_ACK; } - bool isBlockAckReqNeeded(InProgressFrames *, TxopProcedure *) const override { return false; } + bool isBlockAckReqNeeded(InProgressFrames *, TxopProcedure *, IOriginatorBlockAckAgreementHandler *) const override { return false; } }; Define_Module(HeaderAckPolicy); class HeaderAgreementHandler : public OriginatorBlockAckAgreementHandler { diff --git a/tests/module/Ieee80211HcfMultipleProtection_2.test b/tests/module/Ieee80211HcfMultipleProtection_2.test index 748c19d83ef..1d278478756 100644 --- a/tests/module/Ieee80211HcfMultipleProtection_2.test +++ b/tests/module/Ieee80211HcfMultipleProtection_2.test @@ -116,6 +116,7 @@ Define_Module(RateProtectionMac); class RateProtectionHcf : public Hcf { public: int acknowledgments = 0; + int managementAcknowledgments = 0; int blockAcks = 0; int failures = 0; void seedOriginator() { @@ -168,7 +169,12 @@ class RateProtectionHcf : public Hcf { } void originatorProcessReceivedFrame(Packet *packet, Packet *request) override { auto type = packet->peekAtFront()->getType(); - if (type == ST_ACK) acknowledgments++; + if (type == ST_ACK) { + if (dynamicPtrCast(request->peekAtFront())) + acknowledgments++; + else + managementAcknowledgments++; + } if (type == ST_BLOCKACK) blockAcks++; Hcf::originatorProcessReceivedFrame(packet, request); } @@ -208,12 +214,13 @@ class RateProtectionTest : public cSimpleModule { else { sender->inject(66, scenario == 6); if (scenario == 0 || scenario == 1) - sender->inject(); // The existing BAR branch needs a next selected frame. + sender->inject(); } wait(SimTime(5, SIMTIME_MS)); if (scenario == 0 || scenario == 1) { ASSERT(sender->blockAcks >= 1); ASSERT(sender->acknowledgments == 0); + ASSERT(sender->managementAcknowledgments == 1); ASSERT(std::find(senderMac->types.begin(), senderMac->types.end(), ST_BLOCKACK_REQ) != senderMac->types.end()); ASSERT(receiverMac->types[0] == ST_CTS); auto firstRtsEndpoint = senderMac->ends[0] + senderMac->durations[0]; diff --git a/tests/protocol/wifi/README.md b/tests/protocol/wifi/README.md index 04aa9be0fee..4cfb4aa3b6f 100644 --- a/tests/protocol/wifi/README.md +++ b/tests/protocol/wifi/README.md @@ -36,24 +36,26 @@ Each protocol test has two documents. The guide explains its scenario, assertion | `WifiBlockAckBarWithoutAgreement.test` | [Guide](../../../doc/project/evidence/model/wifi/tests/blockack-bar-without-agreement.md) | [Before and after](../../../doc/project/evidence/model/wifi/tests/blockack-bar-without-agreement-comparison.md) | | `WifiBlockAckInactivity.test` | [Guide](../../../doc/project/evidence/model/wifi/tests/blockack-inactivity.md) | [Before and after](../../../doc/project/evidence/model/wifi/tests/blockack-inactivity-comparison.md) | | `WifiBlockAckSameApReassociation.test` | [Guide](../../../doc/project/evidence/model/wifi/tests/blockack-same-ap-reassociation.md) | [Before and after](../../../doc/project/evidence/model/wifi/tests/blockack-same-ap-reassociation-comparison.md) | +| `WifiBlockAckDataRetry.test` | [Guide](../../../doc/project/evidence/model/wifi/tests/blockack-data-retry.md) | [Before and after](../../../doc/project/evidence/model/wifi/tests/blockack-data-retry-comparison.md) | +| `WifiBlockAckTransferCompletion.test` | [Guide](../../../doc/project/evidence/model/wifi/tests/blockack-transfer-completion.md) | [Before and after](../../../doc/project/evidence/model/wifi/tests/blockack-transfer-completion-comparison.md) | The [shared procedure](../../../doc/project/evidence/model/wifi/pr1343-comparison-method.md) explains how to reproduce each comparison with identical fixture inputs. ## Source inventory -The suite contains **80 tests: 50 default PASS expectations and 30 declared FAIL expectations**. +The suite contains **82 tests: 52 default PASS expectations and 30 declared FAIL expectations**. These are source declarations, not a fresh full-suite result. | Directory | Tests | Expected PASS | Expected FAIL | | --- | ---: | ---: | ---: | -| `common/` | 24 | 15 | 9 | +| `common/` | 26 | 17 | 9 | | `legacy/` | 6 | 5 | 1 | | `11b/` | 6 | 4 | 2 | | `11a/` | 4 | 4 | 0 | | `11g/` | 7 | 6 | 1 | | `11n/` | 18 | 11 | 7 | | `11ac/` | 15 | 5 | 10 | -| **Total** | **80** | **50** | **30** | +| **Total** | **82** | **52** | **30** | The [audit report](../../../doc/project/evidence/model/wifi/results.md) owns the observed results, failure classifications, repair dependencies, and verification records. It includes @@ -61,7 +63,7 @@ six repaired behavior checks: HT Capabilities, HT Operation, the modeled dummy f authentication exchange, deauthentication, reassociation, and deterministic retransmission. The authentication check does not establish WEP cryptography. -The five comparison records isolate each test at its related fix and that fix's parent. The BAR and inactivity records use the same lifecycle commit. Each record identifies its inputs, observations, controls, and executed source revisions. These Basic compatibility tests do not establish full standards conformance. +The comparison records isolate each test at its related fix and that fix's parent. The BAR and inactivity records use the same lifecycle commit. Each record identifies its inputs, observations, controls, and executed source revisions. These Basic compatibility tests do not establish full standards conformance. Of the 30 expected failures, 17 are retained unsupported-feature probes or explicit limitations; 13 are deferred repairs declared by maintainer decision. Five of those 13 retain explicit diff --git a/tests/protocol/wifi/blockack-data-retry.md b/tests/protocol/wifi/blockack-data-retry.md new file mode 100644 index 00000000000..6159d28776b --- /dev/null +++ b/tests/protocol/wifi/blockack-data-retry.md @@ -0,0 +1,31 @@ +# DATA Retry after failed Block Ack feedback + +Plan P2, **Mark DATA retries after failed Block Ack feedback**, changes HCF's transmitted header. The test is [WifiBlockAckDataRetry.test](common/WifiBlockAckDataRetry.test). + +Before this commit, HCF can retransmit standalone DATA after failed feedback with Retry clear. The ACK handler already retains the sequence and TID and makes the DATA eligible. The failure therefore concerns the transmitted header, not retransmission eligibility. + +After this commit, HCF sets Retry when the ACK status reports missing feedback or negative feedback. IEEE Std 802.11-2024, 9.2.4.1.6 defines this field for retransmitted standalone DATA. + +The fixture uses real association and production ADDBA. It captures the first Block Ack DATA identity. Run 0 drops the first Block Ack at the originator. Run 1 clears that response's bitmap. Both runs require the same DATA identity after BAR, with Retry set. A radio tap supplies the fault; it does not create an agreement or change originator state. + +```mermaid +sequenceDiagram + participant O as Originator + participant R as Recipient + O->>R: Standalone DATA, Retry = 0 + O->>R: BAR + alt Run 0: feedback loss + R--xO: Block Ack lost at the radio tap + else Run 1: negative feedback + R-->>O: Block Ack with cleared bitmap + end + alt Before P2 + O->>R: Same sequence and TID, Retry = 0 + else After P2 + O->>R: Same sequence and TID, Retry = 1 + end +``` + +The [guide](../../../doc/project/evidence/model/wifi/tests/blockack-data-retry.md) defines setup and assertions. The [comparison](../../../doc/project/evidence/model/wifi/tests/blockack-data-retry-comparison.md) records executed results and limits. + +This test checks the standalone Basic compatibility path. It proves neither A-MPDU retry behavior nor complete IEEE 802.11-2024 Basic conformance. diff --git a/tests/protocol/wifi/blockack-transfer-completion.md b/tests/protocol/wifi/blockack-transfer-completion.md new file mode 100644 index 00000000000..612d3df7751 --- /dev/null +++ b/tests/protocol/wifi/blockack-transfer-completion.md @@ -0,0 +1,32 @@ +# Basic transfer completion below the BAR threshold + +Plan P4, **Complete Basic BAR transfer resolution**, connects outstanding DATA to channel access and final DELBA. The test is [WifiBlockAckTransferCompletion.test](common/WifiBlockAckTransferCompletion.test). + +Before this commit, a short group can lack feedback because the BAR threshold is five. Channel access also requires another DATA candidate. Queue exhaustion or a full transmit window can therefore prevent transfer completion. + +After this commit, the ACK policy can select BAR below the threshold. HCF requests channel access for that BAR before DATA extraction. Matched feedback resolves the group. When no queued or numbered DATA remains, HCF queues DELBA. IEEE Std 802.11-2024, 10.25.4 supplies the completion requirement. + +The fixture uses real association, production ADDBA, and finite UDP bursts. Run 0 sends two packets with an accepted window of 64. Run 1 sends four packets with a one-position window. Both retain threshold five. The next selected DATA-or-BAR transmission after the first Block Ack DATA must be BAR. The test also requires matched feedback, originator-role DELBA, and its ACK. + +The output checks require PASS and reject any FAIL from this program. Both runs must succeed; one passing run cannot hide the other's failure. + +```mermaid +sequenceDiagram + participant O as Originator + participant R as Recipient + Note over O,R: Outstanding DATA below threshold five + Note over O: Queue empty or transmit window full + alt Before P4 + Note over O,R: No final feedback, transfer cannot complete + else After P4 + O->>R: BAR for the selected peer and TID + R-->>O: Matched Block Ack + Note over O: After all DATA resolves and none remains + O->>R: Completion DELBA + R-->>O: ACK + end +``` + +The [guide](../../../doc/project/evidence/model/wifi/tests/blockack-transfer-completion.md) defines setup and assertions. The [comparison](../../../doc/project/evidence/model/wifi/tests/blockack-transfer-completion-comparison.md) records executed results and limits. + +Basic remains an INET compatibility profile. These cases do not establish complete NAV conformance, general Basic DATA admission, or a performance result. diff --git a/tests/protocol/wifi/common/WifiBlockAckBarWithoutAgreement.test b/tests/protocol/wifi/common/WifiBlockAckBarWithoutAgreement.test index 4f9cb137cdd..1b68c527b62 100644 --- a/tests/protocol/wifi/common/WifiBlockAckBarWithoutAgreement.test +++ b/tests/protocol/wifi/common/WifiBlockAckBarWithoutAgreement.test @@ -34,10 +34,21 @@ Define_Module(LifecycleBarMac); class LifecycleBarStimulus : public cSimpleModule, public ITx::ICallback { protected: - void initialize() override { scheduleAt(SimTime(1100, SIMTIME_MS), new cMessage("bar")); } + void initialize() override { + if (par("control").boolValue()) + scheduleAt(SimTime(1002, SIMTIME_MS), new cMessage("hold-contention")); + scheduleAt(SimTime(1100, SIMTIME_MS), new cMessage("bar")); + } void handleMessage(cMessage *message) override { + bool hold = message->isName("hold-contention"); delete message; auto network = getParentModule(); + if (hold) { + // Retained queued DATA prevents completion DELBA before the control BAR. + auto mac = network->getSubmodule("sta1")->getSubmodule("wlan", 0)->getSubmodule("mac"); + check_and_cast(mac->getSubmodule("rx"))->setContentionBlocked(true); + return; + } bool control = par("control"); Tid tid = control ? 6 : 5; auto sender = lifecycleHcf(network, "sta1"); diff --git a/tests/protocol/wifi/common/WifiBlockAckDataRetry.test b/tests/protocol/wifi/common/WifiBlockAckDataRetry.test new file mode 100644 index 00000000000..735436129ca --- /dev/null +++ b/tests/protocol/wifi/common/WifiBlockAckDataRetry.test @@ -0,0 +1,87 @@ +%description: +Production DATA retransmission after one lost Block Ack must retain its sequence and TID with Retry set. +The radio tap drops the first Block Ack or clears its bitmap at sta1. +Real association and ADDBA precede the DATA exchange. +IEEE Std 802.11-2024, 9.2.4.1.6 defines Retry for retransmitted standalone DATA. + +%extraargs: -r 0..1 + +%file: BlockAckDataRetry.cc +#include "BlockAckLifecycleTestSupport.h" + +namespace inet::protocoltest { +static void clearBitmap(Packet *packet) +{ + std::vector> prefix; + while (!dynamicPtrCast(packet->peekAtFront())) + prefix.push_back(packet->removeAtFront(packet->peekAtFront()->getChunkLength())); + auto response = packet->removeAtFront(); + for (int i = 0; i < 64; i++) { + BitVector bits; + for (int fragment = 0; fragment < 16; fragment++) + bits.appendBit(false); + response->setBlockAckBitmap(i, bits); + } + packet->insertAtFront(response); + for (auto it = prefix.rbegin(); it != prefix.rend(); ++it) + packet->insertAtFront(*it); +} + +static ProtocolTest retryProgram(const char *name, bool negative) +{ + auto test = ProtocolTest(name); + if (negative) + test.intercept(tap("radioMedium").to("sta1").filterPacket("ieee80211mac.type == 25").nth(1).mutate(clearBitmap) + .describe("clear the first feedback bitmap at the originator")); + else + test.intercept(tap("radioMedium").to("sta1").filterPacket("ieee80211mac.type == 25").nth(1).drop() + .describe("lose the first Block Ack at the originator")); + return test.once(on("sta1.wlan[0].mac").signal("packetSentToLower") + .filterEvent([](const MatchContext& c) { + auto data = dynamicPtrCast(c.event.packet->peekAtFront()); + return data && data->getAckPolicy() == BLOCK_ACK; + }) + .capture("sequence", [](const PacketEvent& event) { + return cValue(event.packet->peekAtFront()->getSequenceNumber().get()); + }) + .capture("tid", [](const PacketEvent& event) { + return cValue(event.packet->peekAtFront()->getTid()); + }) + .assertEvent([](const MatchContext& c) { + return !c.event.packet->peekAtFront()->getRetry(); + }) + .describe("first standalone DATA under the accepted agreement").within(1.05)) + .once(on("sta1.wlan[0].mac").signal("packetSentToLower") + .filterPacket("ieee80211mac.type == 24") + .describe("BAR requests feedback for the outstanding DATA").within(0.02)) + .once(on("sta1.wlan[0].mac").signal("packetSentToLower") + .filterEvent([](const MatchContext& c) { + auto data = dynamicPtrCast(c.event.packet->peekAtFront()); + return data && data->getType() == ST_DATA_WITH_QOS && + data->getSequenceNumber().get() == c.get("sequence").intValue() && data->getTid() == c.get("tid").intValue(); + }) + .assertEvent([](const MatchContext& c) { + return c.event.packet->peekAtFront()->getRetry(); + }) + .describe("the same DATA identity returns with Retry set").within(0.02)); +} + +Define_ProtocolTest(wifi_block_ack_data_retry) { return retryProgram("wifi_block_ack_data_retry", false); } +Define_ProtocolTest(wifi_block_ack_data_retry_negative) { return retryProgram("wifi_block_ack_data_retry_negative", true); } +} + +%inifile: test.ini +[General] +cmdenv-stop-batch-on-error = false +*.tester.testName = ${negative=false,true} ? "wifi_block_ack_data_retry_negative" : "wifi_block_ack_data_retry" +*.radioMedium.typename = "Ieee80211ScalarTapRadioMedium" +*.sta1.app[0].sendInterval = 0.1ms +*.sta1.app[0].stopTime = 1.02s +**.originatorMacDataService.msduAggregationPolicy.typename = "" +sim-time-limit = 1.1s +include ../../ini/_blockackLifecycle.ini + +%contains: stdout +PROTOCOLTEST wifi_block_ack_data_retry: PASS +%contains: stdout +PROTOCOLTEST wifi_block_ack_data_retry_negative: PASS diff --git a/tests/protocol/wifi/common/WifiBlockAckSameApReassociation.test b/tests/protocol/wifi/common/WifiBlockAckSameApReassociation.test index 7c9d66ed285..6c25407193d 100644 --- a/tests/protocol/wifi/common/WifiBlockAckSameApReassociation.test +++ b/tests/protocol/wifi/common/WifiBlockAckSameApReassociation.test @@ -4,6 +4,7 @@ Same-AP reassociation retains identical peer rates and HT capabilities, with ina Both endpoints must clear both agreement roles before a new traffic batch starts. The new batch must establish fresh agreements and reach both UDP destinations. Read-only queries observe agreement state; the fixture never supplies agreements or calls reset. +The fixture requests reassociation before the old traffic completes. %file: SameApReassociation.cc #include "BlockAckLifecycleTestSupport.h" @@ -29,7 +30,10 @@ class BlockAckReassociationAgent : public Ieee80211AgentSta apHcf->hasOriginator(station, 6) + apHcf->hasRecipient(station, 6); } public: - ~BlockAckReassociationAgent() { cancelAndDelete(replace); cancelAndDelete(verify); } + ~BlockAckReassociationAgent() { + cancelAndDelete(replace); + cancelAndDelete(verify); + } protected: void processAssociateConfirm(Ieee80211Prim_AssociateConfirm *response) override { bool success = response->getResultCode() == PRC_SUCCESS; @@ -37,7 +41,7 @@ class BlockAckReassociationAgent : public Ieee80211AgentSta if (success && !scheduled) { scheduled = true; replace = new cMessage("same-ap-reassociation"); - scheduleAt(SimTime(1100, SIMTIME_MS), replace); + scheduleAt(SimTime(1008, SIMTIME_MS), replace); } } void processReassociateConfirm(Ieee80211Prim_ReassociateConfirm *response) override { @@ -90,7 +94,7 @@ class BlockAckReassociationAgent : public Ieee80211AgentSta emit(registerSignal("equalPeerParameters"), long(equal)); emit(registerSignal("rolesAfterReplacement"), long(agreementRoles())); verify = new cMessage("verify-fresh-setup"); - scheduleAt(SimTime(1400, SIMTIME_MS), verify); + scheduleAt(SimTime(1380, SIMTIME_MS), verify); } else Ieee80211AgentSta::handleMessage(message); @@ -147,6 +151,13 @@ simple BlockAckReassociationAgent extends Ieee80211AgentSta { %inifile: test.ini [General] +**.wlan[*].bitrate = 6Mbps +**.originatorMacDataService.msduAggregationPolicy.typename = "" +# Only the AP-sta1 link needs Block Ack for the reset assertions. +*.sta2.wlan[*].mac.hcf.isBlockAckSupported = false +*.ap.wlan[*].mac.hcf.originatorAckPolicy.maxBlockAckPolicyFrameLength = 500B +# Slotted bidirectional contention can produce simultaneous transmissions. +*.radioMedium.sameTransmissionStartTimeCheck = "warning" *.tester.testName = "wifi_block_ack_same_ap_reassociation" *.sta1.wlan[*].agent.typename = "BlockAckReassociationAgent" *.sta1.numApps = 3 @@ -160,17 +171,17 @@ simple BlockAckReassociationAgent extends Ieee80211AgentSta { *.sta1.app[2].messageLength = 1000B *.sta1.app[2].sendInterval = 0.1ms *.sta1.app[2].startTime = 1.3s -*.sta1.app[2].stopTime = 1.303s +*.sta1.app[2].stopTime = 1.4s *.sta2.numApps = 3 *.sta2.app[1..2].typename = "UdpBasicApp" *.sta2.app[1..2].destAddresses = "sta1" *.sta2.app[1..2].destPort = 5001 -*.sta2.app[1..2].messageLength = 1000B +*.sta2.app[1..2].messageLength = 100B *.sta2.app[1..2].sendInterval = 0.1ms -*.sta2.app[1].startTime = 1.01s -*.sta2.app[1].stopTime = 1.013s +*.sta2.app[1].startTime = 1.000001s +*.sta2.app[1].stopTime = 1.003001s *.sta2.app[2].startTime = 1.31s -*.sta2.app[2].stopTime = 1.313s +*.sta2.app[2].stopTime = 1.4s sim-time-limit = 1.5s include ../../ini/_blockackLifecycle.ini diff --git a/tests/protocol/wifi/common/WifiBlockAckTransferCompletion.test b/tests/protocol/wifi/common/WifiBlockAckTransferCompletion.test new file mode 100644 index 00000000000..f3510b4d32c --- /dev/null +++ b/tests/protocol/wifi/common/WifiBlockAckTransferCompletion.test @@ -0,0 +1,76 @@ +%description: +Production Basic transfers below the BAR threshold must request final feedback and end with DELBA. +The two-packet case exhausts the queue after one Block Ack DATA frame. +The four-packet case uses a one-position window and requires BAR before more DATA. +Both cases use real association, production ADDBA, threshold five, and seed zero. +IEEE Std 802.11-2024, 10.25.4 supplies the final-transfer teardown requirement. +Basic remains an INET compatibility profile. + +%extraargs: -r 0..1 + +%file: BlockAckTransferCompletion.cc +#include "BlockAckLifecycleTestSupport.h" + +namespace inet::protocoltest { +Define_ProtocolTest(wifi_block_ack_transfer_completion) +{ + return ProtocolTest("wifi_block_ack_transfer_completion") + .once(on("sta1.wlan[0].mac").signal("packetSentToLower") + .filterPacket("has(Ieee80211AddbaRequest)") + .capture("tid", "Ieee80211AddbaRequest.tid") + .describe("originator requests the production agreement").within(1.05)) + .once(on("sta1.wlan[0].mac").signal("packetReceivedFromLower") + .filterPacket("has(Ieee80211AddbaResponse)") + .assertPacket("Ieee80211AddbaResponse.statusCode == 0 && Ieee80211AddbaResponse.tid == {tid}") + .describe("recipient accepts the agreement").within(0.01)) + .once(on("sta1.wlan[0].mac").signal("packetSentToLower") + .filterEvent([](const MatchContext& c) { + auto data = dynamicPtrCast(c.event.packet->peekAtFront()); + return data && data->getAckPolicy() == BLOCK_ACK; + }) + .capture("firstSequence", [](const PacketEvent& event) { + return cValue(event.packet->peekAtFront()->getSequenceNumber().get()); + }) + .describe("standalone DATA uses the accepted agreement").within(0.01)) + .once(on("sta1.wlan[0].mac").signal("packetSentToLower") + .filterEvent([](const MatchContext& c) { + auto header = c.event.packet->peekAtFront(); + return dynamicPtrCast(header) != nullptr || header->getType() == ST_DATA_WITH_QOS; + }) + .assertEvent([](const MatchContext& c) { + auto bar = dynamicPtrCast(c.event.packet->peekAtFront()); + return bar && bar->getTidInfo() == c.get("tid").intValue() && + bar->getReceiverAddress() == MacAddress("02:00:00:00:00:01") && + bar->getStartingSequenceNumber().get() == c.get("firstSequence").intValue(); + }) + .describe("BAR proceeds below threshold five").within(0.01)) + .once(on("sta1.wlan[0].mac").signal("packetReceivedFromLower") + .filterPacket("has(Ieee80211BasicBlockAck)") + .assertPacket("Ieee80211BasicBlockAck.tidInfo == {tid}") + .describe("matching Block Ack resolves the group").within(0.01)) + .once(on("sta1.wlan[0].mac").signal("packetSentToLower") + .filterPacket("has(Ieee80211Delba)") + .assertPacket("Ieee80211Delba.initiator == true && Ieee80211Delba.tid == {tid}") + .describe("originator ends the completed transfer").within(0.03)) + .once(on("sta1.wlan[0].mac").signal("packetReceivedFromLower") + .filterPacket("ieee80211mac.type == 29") + .describe("recipient acknowledges completion DELBA").within(0.01)); +} +} + +%inifile: test.ini +[General] +cmdenv-stop-batch-on-error = false +*.tester.testName = "wifi_block_ack_transfer_completion" +*.sta1.app[0].sendInterval = 0.1ms +*.sta1.app[0].stopTime = ${smallWindow=false,true} ? 1.00035s : 1.00015s +**.recipientBlockAckAgreementPolicy.maximumAllowedBufferSize = ${smallWindow} ? 1 : 64 +**.originatorMacDataService.msduAggregationPolicy.typename = "" +sim-time-limit = 1.1s +include ../../ini/_blockackLifecycle.ini + +%contains: stdout +PROTOCOLTEST wifi_block_ack_transfer_completion: PASS + +%not-contains: stdout +PROTOCOLTEST wifi_block_ack_transfer_completion: FAIL diff --git a/tests/unit/Ieee80211BlockAckScheduling_1.test b/tests/unit/Ieee80211BlockAckScheduling_1.test new file mode 100644 index 00000000000..c0fd4049ab9 --- /dev/null +++ b/tests/unit/Ieee80211BlockAckScheduling_1.test @@ -0,0 +1,153 @@ +%description: +Check peer/TID BAR arbitration, window boundaries, cyclic sequence order, and ACK-state isolation. +The production policy reads the production ACK handler through an in-progress queue. +These helper checks supplement the HCF module fixture. + +%includes: +#include +#include +#include "inet/linklayer/ieee80211/mac/originator/OriginatorQosAckPolicy.h" +#include "inet/linklayer/ieee80211/mac/originator/QosAckHandler.h" +#include "inet/linklayer/ieee80211/mac/originator/QosRecoveryProcedure.h" +#include "inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreementHandler.h" +using namespace inet; +using namespace inet::ieee80211; + +namespace Ieee80211BlockAckScheduling_1 { +template struct ImplicitBarQuery : std::false_type {}; +template struct ImplicitBarQuery().isBlockAckReqNeeded(nullptr, nullptr))>> : std::true_type {}; +template struct ImplicitBarParameters : std::false_type {}; +template struct ImplicitBarParameters().computeBlockAckReqParameters(nullptr, nullptr))>> : std::true_type {}; +template struct ImplicitBarWindow : std::false_type {}; +template struct ImplicitBarWindow().processTransmittedBlockAckReq(std::declval>()))>> : std::true_type {}; + +static_assert(!ImplicitBarQuery::value, "The interface requires an explicit agreement handler"); +static_assert(!ImplicitBarQuery::value, "The concrete policy requires an explicit agreement handler"); +static_assert(!ImplicitBarParameters::value, "The interface requires an explicit agreement handler"); +static_assert(!ImplicitBarParameters::value, "The concrete policy requires an explicit agreement handler"); +static_assert(!ImplicitBarWindow::value, "The ACK handler requires an explicit agreement window"); + +class SchedulingCw : public IRecoveryProcedure::ICwCalculator { + public: + int cw = 0; + void incrementCw() override { cw = std::min(7, 2 * cw + 1); } + void resetCw() override { cw = 0; } + int getCw() override { return cw; } +}; +class SchedulingRecovery : public QosRecoveryProcedure { + public: + void configure(ICwCalculator *calculator) { cwCalculator = calculator; shortRetryLimit = 1; } + int getStationSrc() const { return stationShortRetryCounter; } + bool hasDataRetry() const { return !shortRetryCounter.empty() || !longRetryCounter.empty(); } +}; +class SchedulingPolicy : public OriginatorQosAckPolicy { + public: + SchedulingPolicy() { blockAckReqThreshold = 5; } +}; +class SchedulingAgreements : public OriginatorBlockAckAgreementHandler { + public: + OriginatorBlockAckAgreement *accept(MacAddress peer, Tid tid, int start, int size) { + auto agreement = new OriginatorBlockAckAgreement(peer, tid, SequenceNumberCyclic(start), size, false, false); + agreement->setIsAddbaResponseReceived(true); + blockAckAgreements[{peer, tid}] = agreement; + return agreement; + } +}; +class SchedulingFrames : public InProgressFrames { + public: + Packet *candidate = nullptr; + void configure(QosAckHandler *handler) { ackHandler = handler; } + Packet *peekFrameToTransmit() override { return candidate; } + Ptr add(MacAddress peer, Tid tid, int sequence, bool sent = true) { + auto header = makeShared(); + header->setType(ST_DATA_WITH_QOS); + header->setReceiverAddress(peer); + header->setTid(tid); + header->setSequenceNumber(SequenceNumberCyclic(sequence)); + header->setAckPolicy(BLOCK_ACK); + auto packet = new Packet("data", header); + take(packet); + packet->setArrivalTime(simTime()); + inProgressFrames.push_back(packet); + ackHandler->frameGotInProgress(header); + if (sent) + check_and_cast(ackHandler)->processTransmittedDataOrMgmtFrame(header); + return header; + } +}; +} + +%activity: +SchedulingCw cw; +SchedulingRecovery recovery; +recovery.configure(&cw); +recovery.controlFrameTransmissionFailed(); +ASSERT(recovery.getStationSrc() == 1 && cw.getCw() == 1); +recovery.controlFrameTransmissionFailed(); +ASSERT(recovery.getStationSrc() == 0 && cw.getCw() == 0); +recovery.controlFrameTransmissionFailed(); +recovery.blockAckFrameReceived(); +ASSERT(recovery.getStationSrc() == 0 && cw.getCw() == 0 && !recovery.hasDataRetry()); +const MacAddress peer("02:00:00:00:00:02"); +const MacAddress other("02:00:00:00:00:03"); +SchedulingPolicy policy; +SchedulingAgreements agreements; +QosAckHandler ack; +SchedulingFrames frames; +frames.configure(&ack); +agreements.accept(peer, 2, 100, 8); +auto selectedAgreement = agreements.accept(peer, 5, 4094, 4); +auto otherAgreement = agreements.accept(other, 5, 4094, 4); +std::vector> unrelated; +for (int i = 100; i < 104; i++) + unrelated.push_back(frames.add(peer, 2, i)); +auto selected = frames.add(peer, 5, 4095); +auto wrap = frames.add(peer, 5, 0); +auto outside = frames.add(peer, 5, 2); +auto separatePeer = frames.add(other, 5, 4095); +// A candidate inside TID 2 defers only that group. +frames.add(peer, 2, 104, false); +frames.candidate = frames.getFrames(frames.getLength() - 1); +ASSERT(!policy.isBlockAckReqNeeded(&frames, nullptr, nullptr)); +ASSERT(std::get<2>(policy.computeBlockAckReqParameters(&frames, nullptr, nullptr)) == -1); +auto choice = policy.computeBlockAckReqParameters(&frames, nullptr, &agreements); +ASSERT(std::get<0>(choice) == peer && std::get<2>(choice) == 5); +ASSERT(std::get<1>(choice) == SequenceNumberCyclic(4095)); +ASSERT(selectedAgreement->containsSequence(SequenceNumberCyclic(1))); +ASSERT(!selectedAgreement->containsSequence(SequenceNumberCyclic(2))); +auto bar = makeShared(); +bar->setReceiverAddress(peer); +bar->setTidInfo(5); +bar->setStartingSequenceNumber(SequenceNumberCyclic(4095)); +ack.processTransmittedBlockAckReq(bar, selectedAgreement); +ASSERT(ack.getQoSDataAckStatus(selected) == QosAckHandler::Status::WAITING_FOR_BLOCK_ACK); +ASSERT(ack.getQoSDataAckStatus(wrap) == QosAckHandler::Status::WAITING_FOR_BLOCK_ACK); +for (auto header : unrelated) + ASSERT(ack.getQoSDataAckStatus(header) == QosAckHandler::Status::BLOCK_ACK_NOT_YET_REQUESTED); +ASSERT(ack.getQoSDataAckStatus(outside) == QosAckHandler::Status::BLOCK_ACK_NOT_YET_REQUESTED); +ASSERT(ack.getQoSDataAckStatus(separatePeer) == QosAckHandler::Status::BLOCK_ACK_NOT_YET_REQUESTED); +ack.processFailedBlockAckReq(bar); +ASSERT(ack.isEligibleToTransmit(selected)); +ASSERT(ack.isEligibleToTransmit(wrap)); +ASSERT(ack.getQoSDataAckStatus(separatePeer) == QosAckHandler::Status::BLOCK_ACK_NOT_YET_REQUESTED); +frames.candidate = nullptr; +choice = policy.computeBlockAckReqParameters(&frames, nullptr, &agreements); +ASSERT(std::get<0>(choice) == peer && std::get<2>(choice) == 2); +ASSERT(std::get<1>(choice) == SequenceNumberCyclic(100)); +ASSERT(otherAgreement->getStartingSequenceNumber() == SequenceNumberCyclic(4094)); +auto duration = SimTime(1, SIMTIME_US); +EdcaTransmitLifetimeHandler lifetime(duration, duration, duration, duration); +frames.setLifetimeHandler(&lifetime); +for (int i = 0; i < frames.getLength(); i++) + lifetime.registerFrame(frames.getFrames(i), AC_VI); +ASSERT(policy.isBlockAckReqNeeded(&frames, nullptr, &agreements)); +wait(duration); +ASSERT(!policy.isBlockAckReqNeeded(&frames, nullptr, &agreements)); +ASSERT(ack.getQoSDataAckStatus(unrelated.front()) == QosAckHandler::Status::BLOCK_ACK_NOT_YET_REQUESTED); +std::cout << "Block Ack scheduling isolation assertions passed.\n"; + +%contains: stdout +Block Ack scheduling isolation assertions passed. diff --git a/tests/unit/Ieee80211MultipleProtection_1.test b/tests/unit/Ieee80211MultipleProtection_1.test index 1867858da01..d777b2e0e56 100644 --- a/tests/unit/Ieee80211MultipleProtection_1.test +++ b/tests/unit/Ieee80211MultipleProtection_1.test @@ -39,11 +39,12 @@ class PredicateFrames : public InProgressFrames { int reads = 0; bool hasInProgressFrames() override { return true; } Packet *getFrameToTransmit() override { reads++; return selected; } + Packet *peekFrameToTransmit() override { reads++; return selected; } }; class PredicateAckPolicy : public OriginatorQosAckPolicy { public: bool bar = false; - bool isBlockAckReqNeeded(InProgressFrames *, TxopProcedure *) const override { return bar; } + bool isBlockAckReqNeeded(InProgressFrames *, TxopProcedure *, IOriginatorBlockAckAgreementHandler *) const override { return bar; } }; class PredicateRtsPolicy : public IRtsPolicy { public: diff --git a/tests/unit/Ieee80211OriginatorBlockAckWindow_1.test b/tests/unit/Ieee80211OriginatorBlockAckWindow_1.test new file mode 100644 index 00000000000..5526e1cf823 --- /dev/null +++ b/tests/unit/Ieee80211OriginatorBlockAckWindow_1.test @@ -0,0 +1,30 @@ +%description: +Shared originator operations preserve the earliest unresolved sequence across wraparound. +The accepted transmit window and the 64-position response bitmap have distinct boundaries. + +%includes: +#include "inet/linklayer/ieee80211/mac/blockack/OriginatorBlockAckAgreement.h" +using namespace inet; +using namespace inet::ieee80211; + +%activity: +const MacAddress peer("02:00:00:00:00:02"); +OriginatorBlockAckAgreement window(peer, 5, SequenceNumberCyclic(4094), 4, false, false); +ASSERT(window.containsSequence(SequenceNumberCyclic(4094))); +ASSERT(window.containsSequence(SequenceNumberCyclic(1))); +ASSERT(!window.containsSequence(SequenceNumberCyclic(2))); +ASSERT(!window.containsSequence(SequenceNumberCyclic(4093))); +window.advanceWindow(SequenceNumberCyclic(2), {SequenceNumberCyclic(0), SequenceNumberCyclic(4095)}); +ASSERT(window.getStartingSequenceNumber() == SequenceNumberCyclic(4095)); +window.advanceWindow(SequenceNumberCyclic(2), {SequenceNumberCyclic(0)}); +ASSERT(window.getStartingSequenceNumber() == SequenceNumberCyclic(0)); +window.advanceWindow(SequenceNumberCyclic(2), {}); +ASSERT(window.getStartingSequenceNumber() == SequenceNumberCyclic(2)); +ASSERT(OriginatorBlockAckAgreement::isInBitmap(SequenceNumberCyclic(62), SequenceNumberCyclic(4095))); +ASSERT(!OriginatorBlockAckAgreement::isInBitmap(SequenceNumberCyclic(63), SequenceNumberCyclic(4095))); +ASSERT(!OriginatorBlockAckAgreement::isInBitmap(SequenceNumberCyclic(4094), SequenceNumberCyclic(4095))); +ASSERT(!window.containsSequence(SequenceNumberCyclic(62))); +std::cout << "Originator Block Ack window assertions passed.\n"; + +%contains: stdout +Originator Block Ack window assertions passed.