Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/inet/linklayer/ieee80211/mac/Ieee80211Frame.msg
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const b LENGTH_ADDBAREQ = LENGTH_MGMT + B(9); // mgmt length + action body lengt
const b LENGTH_ADDBARESP = LENGTH_MGMT + B(9); // mgmt length + action body length
const b LENGTH_DELBA = LENGTH_MGMT + B(6); // mgmt length + action body length
const b LENGTH_BASIC_BLOCKACK = B(16 + 2 + (2 + 128) + 4); // header + ba control + ba information + fcs
const b LENGTH_COMPRESSED_BLOCKACK = B(16 + 2 + (2 + 8) + 4); // header + ba control + ba information + fcs
const b DATAFRAME_HEADER_MINLENGTH = B(2 + 2 + 3 * 6 + 2); //bits without QoS, without Address4: 2 + 2 + 3*6(addresses) + 2
const b QOSCONTROL_PART_LENGTH = b(2 * 8); // QoS Control field length (bits)
const short int MAX_NUM_FRAGMENTS = 16;
Expand Down Expand Up @@ -345,7 +346,7 @@ class Ieee80211BlockAckReq extends Ieee80211TwoAddressHeader

class Ieee80211BasicBlockAckReq extends Ieee80211BlockAckReq
{
chunkLength = B(38);
chunkLength = B(20);

int tidInfo; // The TID_INFO subfield of the BAR Control field of the Basic BlockAckReq frame contains the TID for which a Basic BlockAck frame is requested.

Expand All @@ -362,7 +363,7 @@ class Ieee80211BasicBlockAckReq extends Ieee80211BlockAckReq

class Ieee80211CompressedBlockAckReq extends Ieee80211BlockAckReq
{
chunkLength = B(38);
chunkLength = B(20);

int tidInfo; // The TID_INFO subfield of the BAR Control field of the Compressed BlockAckReq frame contains the TID for which a BlockAck frame is requested.
// The BAR Information field of the Compressed BlockAckReq frame contains the Block Ack Starting
Expand Down Expand Up @@ -444,7 +445,7 @@ class Ieee80211BasicBlockAck extends Ieee80211BlockAck
//
class Ieee80211CompressedBlockAck extends Ieee80211BlockAck
{
// chunkLength TODO
chunkLength = LENGTH_COMPRESSED_BLOCKACK - B(4);
multiTid = 0;
compressedBitmap = 1;

Expand Down
115 changes: 72 additions & 43 deletions src/inet/linklayer/ieee80211/mac/Ieee80211MacHeaderSerializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,24 @@ void readSequenceControl(MemoryInputStream& stream, int& fragmentNumber, ieee802
sequenceNumber = ieee80211::SequenceNumberCyclic((sequenceControl >> 4) & 0xFFF);
}

uint16_t packBlockAckControl(bool ackPolicy, bool multiTid, bool compressedBitmap, uint16_t reserved, uint8_t tidInfo)
{
return (ackPolicy ? 0x0001 : 0) |
(multiTid ? 0x0002 : 0) |
(compressedBitmap ? 0x0004 : 0) |
((reserved & 0x1FF) << 3) |
((tidInfo & 0xF) << 12);
}

void unpackBlockAckControl(uint16_t control, bool& ackPolicy, bool& multiTid, bool& compressedBitmap, uint16_t& reserved, uint8_t& tidInfo)
{
ackPolicy = (control & 0x0001) != 0;
multiTid = (control & 0x0002) != 0;
compressedBitmap = (control & 0x0004) != 0;
reserved = (control >> 3) & 0x1FF;
tidInfo = (control >> 12) & 0xF;
}

} // namespace

namespace ieee80211 {
Expand Down Expand Up @@ -266,26 +284,20 @@ void Ieee80211MacHeaderSerializer::serialize(MemoryOutputStream& stream, const P
stream.writeUint16Le(blockAckReq->getDurationField().inUnit(SIMTIME_US));
stream.writeMacAddress(blockAckReq->getReceiverAddress());
stream.writeMacAddress(blockAckReq->getTransmitterAddress());
stream.writeBit(blockAckReq->getBarAckPolicy());
bool multiTid = blockAckReq->getMultiTid();
bool compressedBitmap = blockAckReq->getCompressedBitmap();
stream.writeBit(multiTid);
stream.writeBit(compressedBitmap);
stream.writeNBitsOfUint64Be(blockAckReq->getReserved(), 9);
if (!multiTid && !compressedBitmap) {
auto basicBlockAckReq = dynamicPtrCast<const Ieee80211BasicBlockAckReq>(chunk);
stream.writeUint4(basicBlockAckReq->getTidInfo());
stream.writeUint32Be(basicBlockAckReq->getFragmentNumber());
stream.writeUint64Be(0);
stream.writeUint64Be(basicBlockAckReq->getStartingSequenceNumber().get());
stream.writeUint16Le(packBlockAckControl(blockAckReq->getBarAckPolicy(), multiTid, compressedBitmap, blockAckReq->getReserved(), basicBlockAckReq->getTidInfo()));
writeSequenceControl(stream, basicBlockAckReq->getFragmentNumber(), basicBlockAckReq->getStartingSequenceNumber().get());
ASSERT(stream.getLength() - startPos == basicBlockAckReq->getChunkLength());
}
else if (!multiTid && compressedBitmap) {
auto compressedBlockAckReq = dynamicPtrCast<const Ieee80211CompressedBlockAckReq>(chunk);
stream.writeUint4(compressedBlockAckReq->getTidInfo());
stream.writeUint32Be(compressedBlockAckReq->getFragmentNumber());
stream.writeUint64Be(0);
stream.writeUint64Be(compressedBlockAckReq->getStartingSequenceNumber().get());
// IEEE Std 802.11-2024, 9.3.1.7.2: one-TID compressed BAR Control and
// Starting Sequence Control are little-endian 16-bit on-wire fields.
stream.writeUint16Le(packBlockAckControl(blockAckReq->getBarAckPolicy(), multiTid, compressedBitmap, blockAckReq->getReserved(), compressedBlockAckReq->getTidInfo()));
writeSequenceControl(stream, compressedBlockAckReq->getFragmentNumber(), compressedBlockAckReq->getStartingSequenceNumber().get());
ASSERT(stream.getLength() - startPos == compressedBlockAckReq->getChunkLength());
}
else if (multiTid && compressedBitmap) {
Expand All @@ -300,16 +312,12 @@ void Ieee80211MacHeaderSerializer::serialize(MemoryOutputStream& stream, const P
stream.writeUint16Le(blockAck->getDurationField().inUnit(SIMTIME_US));
stream.writeMacAddress(blockAck->getReceiverAddress());
stream.writeMacAddress(blockAck->getTransmitterAddress());
stream.writeBit(blockAck->getBlockAckPolicy());
bool multiTid = blockAck->getMultiTid();
bool compressedBitmap = blockAck->getCompressedBitmap();
stream.writeBit(multiTid);
stream.writeBit(compressedBitmap);
stream.writeNBitsOfUint64Be(blockAck->getReserved(), 9);
if (!multiTid && !compressedBitmap) {
auto basicBlockAck = dynamicPtrCast<const Ieee80211BasicBlockAck>(chunk);
stream.writeUint4(basicBlockAck->getTidInfo());
stream.writeUint16Be(basicBlockAck->getStartingSequenceNumber().get());
stream.writeUint16Le(packBlockAckControl(blockAck->getBlockAckPolicy(), multiTid, compressedBitmap, blockAck->getReserved(), basicBlockAck->getTidInfo()));
writeSequenceControl(stream, basicBlockAck->getFragmentNumber(), basicBlockAck->getStartingSequenceNumber().get());
for (size_t i = 0; i < 64; ++i) {
stream.writeByte(basicBlockAck->getBlockAckBitmap(i).getBytes()[0]);
stream.writeByte(basicBlockAck->getBlockAckBitmap(i).getBytes()[1]);
Expand All @@ -318,8 +326,10 @@ void Ieee80211MacHeaderSerializer::serialize(MemoryOutputStream& stream, const P
}
else if (!multiTid && compressedBitmap) {
auto compressedBlockAck = dynamicPtrCast<const Ieee80211CompressedBlockAck>(chunk);
stream.writeUint4(compressedBlockAck->getTidInfo());
stream.writeUint16Be(compressedBlockAck->getStartingSequenceNumber().get());
// IEEE Std 802.11-2024, 9.3.1.8.2: the non-HE compressed BA carries
// one Starting Sequence Control field followed by a 64-bit bitmap.
stream.writeUint16Le(packBlockAckControl(blockAck->getBlockAckPolicy(), multiTid, compressedBitmap, blockAck->getReserved(), compressedBlockAck->getTidInfo()));
writeSequenceControl(stream, compressedBlockAck->getFragmentNumber(), compressedBlockAck->getStartingSequenceNumber().get());
for (size_t i = 0; i < 8; ++i) {
stream.writeByte(compressedBlockAck->getBlockAckBitmap().getBytes()[i]);
}
Expand Down Expand Up @@ -507,30 +517,38 @@ const Ptr<Chunk> Ieee80211MacHeaderSerializer::deserialize(MemoryInputStream& st
blockAckReq->setDurationField(SimTime(stream.readUint16Le(), SIMTIME_US));
blockAckReq->setReceiverAddress(stream.readMacAddress());
blockAckReq->setTransmitterAddress(stream.readMacAddress());
blockAckReq->setBarAckPolicy(stream.readBit());
bool multiTid = stream.readBit();
bool compressedBitmap = stream.readBit();
bool barAckPolicy;
bool multiTid;
bool compressedBitmap;
uint16_t reserved;
uint8_t tidInfo;
unpackBlockAckControl(stream.readUint16Le(), barAckPolicy, multiTid, compressedBitmap, reserved, tidInfo);
blockAckReq->setBarAckPolicy(barAckPolicy);
blockAckReq->setMultiTid(multiTid);
blockAckReq->setCompressedBitmap(compressedBitmap);
blockAckReq->setReserved(stream.readNBitsToUint64Be(9));
blockAckReq->setReserved(reserved);
if (!multiTid && !compressedBitmap) {
auto basicBlockAckReq = makeShared<Ieee80211BasicBlockAckReq>();
copyBasicFields(basicBlockAckReq, macHeader);
copyBlockAckReqFrameFields(basicBlockAckReq, blockAckReq);
basicBlockAckReq->setTidInfo(stream.readUint4());
basicBlockAckReq->setFragmentNumber(stream.readUint32Be());
stream.readUint64Be();
basicBlockAckReq->setStartingSequenceNumber(SequenceNumberCyclic(stream.readUint64Be()));
basicBlockAckReq->setTidInfo(tidInfo);
int fragmentNumber;
SequenceNumberCyclic sequenceNumber;
readSequenceControl(stream, fragmentNumber, sequenceNumber);
basicBlockAckReq->setFragmentNumber(fragmentNumber);
basicBlockAckReq->setStartingSequenceNumber(sequenceNumber);
return basicBlockAckReq;
}
else if (!multiTid && compressedBitmap) {
auto compressedBlockAckReq = makeShared<Ieee80211CompressedBlockAckReq>();
copyBasicFields(compressedBlockAckReq, macHeader);
copyBlockAckReqFrameFields(compressedBlockAckReq, blockAckReq);
compressedBlockAckReq->setTidInfo(stream.readUint4());
compressedBlockAckReq->setFragmentNumber(stream.readUint32Be());
stream.readUint64Be();
compressedBlockAckReq->setStartingSequenceNumber(SequenceNumberCyclic(stream.readUint64Be()));
compressedBlockAckReq->setTidInfo(tidInfo);
int fragmentNumber;
SequenceNumberCyclic sequenceNumber;
readSequenceControl(stream, fragmentNumber, sequenceNumber);
compressedBlockAckReq->setFragmentNumber(fragmentNumber);
compressedBlockAckReq->setStartingSequenceNumber(sequenceNumber);
return compressedBlockAckReq;
}
else
Expand All @@ -543,24 +561,31 @@ const Ptr<Chunk> Ieee80211MacHeaderSerializer::deserialize(MemoryInputStream& st
blockAck->setDurationField(SimTime(stream.readUint16Le(), SIMTIME_US));
blockAck->setReceiverAddress(stream.readMacAddress());
blockAck->setTransmitterAddress(stream.readMacAddress());
blockAck->setBlockAckPolicy(stream.readBit());
bool multiTid = stream.readBit();
bool compressedBitmap = stream.readBit();
bool blockAckPolicy;
bool multiTid;
bool compressedBitmap;
uint16_t reserved;
uint8_t tidInfo;
unpackBlockAckControl(stream.readUint16Le(), blockAckPolicy, multiTid, compressedBitmap, reserved, tidInfo);
blockAck->setBlockAckPolicy(blockAckPolicy);
blockAck->setMultiTid(multiTid);
blockAck->setCompressedBitmap(compressedBitmap);
blockAck->setReserved(stream.readNBitsToUint64Be(9));
blockAck->setReserved(reserved);
if (!multiTid && !compressedBitmap) {
auto basicBlockAck = makeShared<Ieee80211BasicBlockAck>();
copyBasicFields(basicBlockAck, macHeader);
copyBlockAckFrameFields(basicBlockAck, blockAck);
basicBlockAck->setTidInfo(stream.readUint4());
basicBlockAck->setStartingSequenceNumber(SequenceNumberCyclic(stream.readUint16Be()));
basicBlockAck->setTidInfo(tidInfo);
int fragmentNumber;
SequenceNumberCyclic sequenceNumber;
readSequenceControl(stream, fragmentNumber, sequenceNumber);
basicBlockAck->setFragmentNumber(fragmentNumber);
basicBlockAck->setStartingSequenceNumber(sequenceNumber);
for (size_t i = 0; i < 64; ++i) {
std::vector<uint8_t> bytes;
bytes.push_back(stream.readByte());
bytes.push_back(stream.readByte());
BitVector *blockAckBitmap = new BitVector(bytes);
basicBlockAck->setBlockAckBitmap(i, *blockAckBitmap);
basicBlockAck->setBlockAckBitmap(i, BitVector(bytes));
}
return basicBlockAck;
}
Expand All @@ -569,13 +594,17 @@ const Ptr<Chunk> Ieee80211MacHeaderSerializer::deserialize(MemoryInputStream& st
copyBasicFields(compressedBlockAck, macHeader);
copyBlockAckFrameFields(compressedBlockAck, blockAck);

compressedBlockAck->setTidInfo(stream.readUint4());
compressedBlockAck->setStartingSequenceNumber(SequenceNumberCyclic(stream.readUint16Be()));
compressedBlockAck->setTidInfo(tidInfo);
int fragmentNumber;
SequenceNumberCyclic sequenceNumber;
readSequenceControl(stream, fragmentNumber, sequenceNumber);
compressedBlockAck->setFragmentNumber(fragmentNumber);
compressedBlockAck->setStartingSequenceNumber(sequenceNumber);
std::vector<uint8_t> bytes;
for (size_t i = 0; i < 8; ++i) {
bytes.push_back(stream.readByte());
}
compressedBlockAck->setBlockAckBitmap(*(new BitVector(bytes)));
compressedBlockAck->setBlockAckBitmap(BitVector(bytes));
return compressedBlockAck;
}
else {
Expand Down
44 changes: 28 additions & 16 deletions src/inet/linklayer/ieee80211/mac/blockack/BlockAckRecord.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,26 @@
namespace inet {
namespace ieee80211 {

BlockAckRecord::BlockAckRecord(MacAddress originatorAddress, Tid tid) :
BlockAckRecord::BlockAckRecord(MacAddress originatorAddress, Tid tid, SequenceNumberCyclic startingSequenceNumber) :
originatorAddress(originatorAddress),
tid(tid)
tid(tid),
startingSequenceNumber(startingSequenceNumber)
{
}

void BlockAckRecord::blockAckPolicyFrameReceived(const Ptr<const Ieee80211DataHeader>& header)
void BlockAckRecord::dataFrameReceived(const Ptr<const Ieee80211DataHeader>& header, int windowSize)
{
SequenceNumberCyclic sequenceNumber = header->getSequenceNumber();
FragmentNumber fragmentNumber = header->getFragmentNumber();
// IEEE Std 802.11-2024, 10.25.6.3(b), case 3: an old related MPDU
// does not change the Block Ack record. The cyclic comparison below already
// restricts the accepted range to [WinStartR, WinStartR + 2047].
if (!(startingSequenceNumber <= sequenceNumber))
return;
// Cases 1 and 2: record an in-window MPDU, or advance WinStartR
// before recording an MPDU beyond WinEndR (also see 10.25.6.4(c)).
if (startingSequenceNumber + windowSize <= sequenceNumber && sequenceNumber < startingSequenceNumber + 2048)
advanceStartingSequenceNumber(sequenceNumber - windowSize + 1);
acknowledgmentState[SequenceControlField(sequenceNumber.get(), fragmentNumber)] = true;
}

Expand All @@ -30,29 +40,31 @@ bool BlockAckRecord::getAckState(SequenceNumberCyclic sequenceNumber, FragmentNu
// The status of MPDUs that are considered “old” and prior to the sequence number
// range for which the receiver maintains status shall be reported as successfully
// received (i.e., the corresponding bit in the bitmap shall be set to 1).
if (containsKey(acknowledgmentState, SequenceControlField(sequenceNumber.get(), fragmentNumber))) {
return true;
}
else if (acknowledgmentState.size() == 0) {
return true; // TODO old?
}
else {
auto earliest = acknowledgmentState.begin();
return SequenceNumberCyclic(earliest->first.getSequenceNumber()) > sequenceNumber; // old = true
}
return containsKey(acknowledgmentState, SequenceControlField(sequenceNumber.get(), fragmentNumber)) || sequenceNumber < startingSequenceNumber;
}

void BlockAckRecord::removeAckStates(SequenceNumberCyclic sequenceNumber)
bool BlockAckRecord::getCompressedAckState(SequenceNumberCyclic sequenceNumber)
{
// IEEE Std 802.11-2024, 10.25.6.1: bits preceding the maintained
// receive-window range are one; missing MPDUs within the range are zero.
return containsKey(acknowledgmentState, SequenceControlField(sequenceNumber.get(), 0)) || sequenceNumber < startingSequenceNumber;
}

void BlockAckRecord::advanceStartingSequenceNumber(SequenceNumberCyclic newStartingSequenceNumber)
{
// IEEE Std 802.11-2024, 10.25.6.3 and 10.25.6.4: advance WinStartR
// for a newer related MPDU or BAR SSN, using the 12-bit sequence space.
if (!(startingSequenceNumber < newStartingSequenceNumber))
return;
auto it = acknowledgmentState.begin();
while (it != acknowledgmentState.end()) {
if (SequenceNumberCyclic(it->first.getSequenceNumber()) < sequenceNumber)
if (SequenceNumberCyclic(it->first.getSequenceNumber()) < newStartingSequenceNumber)
it = acknowledgmentState.erase(it);
else
it++;
}
startingSequenceNumber = newStartingSequenceNumber;
}

} /* namespace ieee80211 */
} /* namespace inet */

10 changes: 6 additions & 4 deletions src/inet/linklayer/ieee80211/mac/blockack/BlockAckRecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,24 @@ class INET_API BlockAckRecord
protected:
MacAddress originatorAddress = MacAddress::UNSPECIFIED_ADDRESS;
Tid tid = -1;
SequenceNumberCyclic startingSequenceNumber;
std::map<SequenceControlField, bool> acknowledgmentState;

public:
BlockAckRecord(MacAddress originatorAddress, Tid tid);
BlockAckRecord(MacAddress originatorAddress, Tid tid, SequenceNumberCyclic startingSequenceNumber);
virtual ~BlockAckRecord() {}

void blockAckPolicyFrameReceived(const Ptr<const Ieee80211DataHeader>& header);
void dataFrameReceived(const Ptr<const Ieee80211DataHeader>& header, int windowSize);
bool getAckState(SequenceNumberCyclic sequenceNumber, FragmentNumber fragmentNumber);
void removeAckStates(SequenceNumberCyclic sequenceNumber);
bool getCompressedAckState(SequenceNumberCyclic sequenceNumber);
void advanceStartingSequenceNumber(SequenceNumberCyclic startingSequenceNumber);

MacAddress getOriginatorAddress() { return originatorAddress; }
Tid getTid() { return tid; }
SequenceNumberCyclic getStartingSequenceNumber() const { return startingSequenceNumber; }
};

} /* namespace ieee80211 */
} /* namespace inet */

#endif

Loading