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
19 changes: 19 additions & 0 deletions WHATSNEW
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@ Notable backward incompatible changes are the following:
adaptive rate control, either where a station transmits to several peers or
where it sends group-addressed traffic.

2. IEEE 802.11 wire and reception corrections

QoS Control fields now use the standard bit positions. Non-QoS Data no
longer aliases the QoS TID-0 duplicate cache. OFDM radios generate and check
SIGNAL parity and reject undefined RATE codes; HR/DSSS and ERP transmissions
carry their specific PHY protocol identities.

AP beacon intervals are rounded down to whole 1024-us TUs for both target
scheduling and advertisement (100ms becomes 99.328ms). Configured intervals
must be between 1 and 65535 TUs. Beacon and Probe Response frames now encode
the DSSS Current Channel for 2.4 GHz operation. Their channelNumber field is
a standard channel number, with -1 for an absent element, rather than an
internal channel index. Radio channel parameters and scan results remain
internal indices. Custom frame producers should follow the migration guide.

The mesh no-forwarding-information reason code is corrected from 60 to 62.
These corrections change affected packet bytes and may change Wi-Fi
simulation trajectories and fingerprints.

Notable backward compatible changes are the following:

1. IEEE 802.11 per-station rate statistics
Expand Down
36 changes: 35 additions & 1 deletion doc/src/migration-guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,40 @@ Migrating Code from INET 3.x
============================
Release: |release|

IEEE 802.11 Beacon and Probe Response Fields
------------------------------------------

``Ieee80211BeaconFrame::channelNumber`` (also inherited by Probe Response) now
represents the DSSS Parameter Set's standard Current Channel value. Its default,
``-1``, means that the element is absent. Custom frame producers that previously
stored a radio's internal index must use
``band->getStandardChannelNumber(channelIndex)`` and account for the element's
three bytes in the body chunk length. Consumers convert a present value back
with ``receivedBand->getChannelIndex(currentChannel)``. These mapping functions
throw for unmappable values. Radio configuration and scan-result channel fields
continue to use internal indices.

The built-in AP emits this element for its modeled 2.4 GHz operation and omits
it for other bands or radios without IEEE channel information. Without the
element, discovery uses the receive channel when available. HT discovery still
uses HT Operation as its primary-channel authority.

AP ``beaconInterval`` values are rounded down to whole 1024-us TUs once, during
initialization, and must be between 1 and 65535 TUs. The effective value drives
both target scheduling and advertised content. Use ``102400us`` for exactly
100 TUs; the default ``100ms`` now schedules targets 97 TUs apart. Actual beacon
transmissions can be delayed by channel access. Custom producers should put
the same effective interval in Beacon and Probe Response bodies as they use
for target scheduling.
The serializers require an interval between 1 and 65535 TUs for both frame
types and throw for out-of-range values, including the default zero interval.
Custom producers must set a valid interval before serialization.

``RC_MESH_PATH_ERROR_NO_FORWARDING_INFORMATION`` now has its standard value,
62. Code using the symbolic name needs only recompilation. Update external
numeric mappings that used 60 for this reason. Old stored value 60 cannot be
reinterpreted automatically: it also denoted invalid mesh security capability.

Migrating ``FieldsChunkSerializer`` Subclasses
---------------------------------------------

Expand Down Expand Up @@ -381,4 +415,4 @@ Computing and verifying checksums is up to the protocol implementations, and it
is independent of the actual representation of the header. In general, protocols
should have parameters to declare the checksum correct/incorrect or to actually
compute and verify it. Of course, for emulation, one should enable computing and
verifying checksums.
verifying checksums.
18 changes: 10 additions & 8 deletions src/inet/linklayer/ieee80211/mac/Ieee80211MacHeaderSerializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -345,10 +345,12 @@ void Ieee80211MacHeaderSerializer::serializeFields(MemoryOutputStream& stream, c
if (dataHeader->getFromDS() && dataHeader->getToDS())
stream.writeMacAddress(dataHeader->getAddress4());
if (type == ST_DATA_WITH_QOS) {
stream.writeUint4(dataHeader->getTid());
stream.writeBit(true);
stream.writeUint2(dataHeader->getAckPolicy());
stream.writeBit(dataHeader->getAMsduPresent());
// IEEE Std 802.11-2024, Table 9-10. Modeling simplification:
// leave bit 4 clear (no EOSP or Queue Size report); the second
// octet remains zero (no TXOP duration request or AP PS buffer state).
stream.writeByte((dataHeader->getTid() & 0x0F) |
((dataHeader->getAckPolicy() & 3) << 5) |
(dataHeader->getAMsduPresent() ? 0x80 : 0));
stream.writeByte(0);
}
ASSERT(stream.getLength() - startPos == dataHeader->getChunkLength());
Expand Down Expand Up @@ -601,10 +603,10 @@ const Ptr<Chunk> Ieee80211MacHeaderSerializer::deserializeFields(MemoryInputStre
if (dataHeader->getFromDS() && dataHeader->getToDS())
dataHeader->setAddress4(stream.readMacAddress());
if (type == ST_DATA_WITH_QOS) {
dataHeader->setTid(stream.readUint4());
stream.readBit();
dataHeader->setAckPolicy(static_cast<AckPolicy>(stream.readUint2()));
dataHeader->setAMsduPresent(stream.readBit());
auto qosControl = stream.readByte();
dataHeader->setTid(qosControl & 0x0F);
dataHeader->setAckPolicy(static_cast<AckPolicy>((qosControl >> 5) & 3));
dataHeader->setAMsduPresent((qosControl & 0x80) != 0);
stream.readByte();
}
return dataHeader;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ bool QoSDuplicateRemoval::isDuplicate(const Ptr<const Ieee80211DataOrMgmtHeader>
SequenceControlField seqVal(header->getSequenceNumber().get(), header->getFragmentNumber());
bool isManagementFrame = dynamicPtrCast<const Ieee80211MgmtHeader>(header) != nullptr;
bool isTimePriorityManagementFrame = isManagementFrame && false; // TODO hack
if (isTimePriorityManagementFrame || isManagementFrame) {
// IEEE Std 802.11-2024, 10.3.2.14.3, Table 10-6: non-QoS Data
// belongs to RC1, not the per-TID QoS Data cache (RC2).
if (isTimePriorityManagementFrame || isManagementFrame || header->getType() == ST_DATA) {
MacAddress transmitterAddr = header->getTransmitterAddress();
Mac2SeqValMap& cache = isTimePriorityManagementFrame ? lastSeenTimePriorityManagementSeqNumCache : lastSeenSharedSeqNumCache;
auto it = cache.find(transmitterAddr);
Expand Down Expand Up @@ -51,4 +53,3 @@ bool QoSDuplicateRemoval::isDuplicate(const Ptr<const Ieee80211DataOrMgmtHeader>

} // namespace ieee80211
} // namespace inet

26 changes: 26 additions & 0 deletions src/inet/linklayer/ieee80211/mgmt/Ieee80211BeaconInterval.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//

#ifndef __INET_IEEE80211BEACONINTERVAL_H
#define __INET_IEEE80211BEACONINTERVAL_H

#include "inet/common/INETDefs.h"

namespace inet {
namespace ieee80211 {

inline simtime_t normalizeIeee80211BeaconInterval(simtime_t interval)
{
// IEEE Std 802.11-2024, 9.4.1.3: a 16-bit count of 1024 us TUs.
// INET policy: round down once, matching the historical wire encoding,
// and use the resulting duration for both TBTTs and advertisements.
if (interval < SimTime(1024, SIMTIME_US) || interval > SimTime(65535LL * 1024, SIMTIME_US))
throw cRuntimeError("Beacon interval must be between 1 and 65535 TUs (1024 us each)");
return SimTime(interval.inUnit(SIMTIME_US) / 1024 * 1024, SIMTIME_US);
}

} // namespace ieee80211
} // namespace inet

#endif
15 changes: 6 additions & 9 deletions src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "inet/linklayer/ieee80211/mac/Ieee80211Mac.h"
#include "inet/linklayer/ieee80211/mac/Ieee80211SubtypeTag_m.h"
#include "inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.h"
#include "inet/linklayer/ieee80211/mgmt/Ieee80211BeaconInterval.h"
#include "inet/linklayer/ieee80211/mgmt/Ieee80211HtMgmtElements.h"
#include "inet/linklayer/ieee80211/mgmt/Ieee80211MgmtTransactionTag_m.h"
#include "inet/networklayer/common/NetworkInterface.h"
Expand Down Expand Up @@ -47,7 +48,7 @@ void Ieee80211MgmtAp::initialize(int stage)
if (stage == INITSTAGE_LOCAL) {
// read params and init vars
ssid = par("ssid").stdstringValue();
beaconInterval = par("beaconInterval");
beaconInterval = normalizeIeee80211BeaconInterval(par("beaconInterval"));
numAuthSteps = par("numAuthSteps");
if (numAuthSteps != 2 && numAuthSteps != 4)
throw cRuntimeError("parameter 'numAuthSteps' (number of frames exchanged during authentication) must be 2 or 4, not %d", numAuthSteps);
Expand Down Expand Up @@ -209,17 +210,15 @@ void Ieee80211MgmtAp::clearPendingAssociation(StaInfo *sta)
void Ieee80211MgmtAp::sendBeacon()
{
EV << "Sending beacon\n";
// Generic radios may not publish an IEEE channel; retain the legacy unknown value.
int primaryChannel = mib->hasPrimaryChannel() ? mib->requirePrimaryChannel() : -1;
const auto& body = makeShared<Ieee80211BeaconFrame>();
body->setSSID(ssid.c_str());
setSupportedRateElements(body);
body->setBeaconInterval(beaconInterval);
body->setChannelNumber(primaryChannel);
body->setChannelNumber(getDsssParameterSetChannel());
addHtCapabilities(body);
if (mib->isHtOperationSupported())
setHtOperation(body, getHtOperationBand(), mib->getHtOperation());
body->setChunkLength(B(8 + 2 + 2 + (2 + ssid.length())) + getSupportedRateElementsLength(body) + getHtMgmtElementsLength(body));
body->setChunkLength(B(8 + 2 + 2 + (2 + ssid.length()) + (body->getChannelNumber() != -1 ? 3 : 0)) + getSupportedRateElementsLength(body) + getHtMgmtElementsLength(body));
sendManagementFrame("Beacon", body, ST_BEACON, MacAddress::BROADCAST_ADDRESS);
}

Expand Down Expand Up @@ -525,17 +524,15 @@ void Ieee80211MgmtAp::handleProbeRequestFrame(Packet *packet, const Ptr<const Ie
delete packet;

EV << "Sending ProbeResponse frame\n";
// Generic radios may not publish an IEEE channel; retain the legacy unknown value.
int primaryChannel = mib->hasPrimaryChannel() ? mib->requirePrimaryChannel() : -1;
const auto& body = makeShared<Ieee80211ProbeResponseFrame>();
body->setSSID(ssid.c_str());
setSupportedRateElements(body);
body->setBeaconInterval(beaconInterval);
body->setChannelNumber(primaryChannel);
body->setChannelNumber(getDsssParameterSetChannel());
addHtCapabilities(body);
if (mib->isHtOperationSupported())
setHtOperation(body, getHtOperationBand(), mib->getHtOperation());
body->setChunkLength(B(8 + 2 + 2 + (2 + ssid.length())) + getSupportedRateElementsLength(body) + getHtMgmtElementsLength(body));
body->setChunkLength(B(8 + 2 + 2 + (2 + ssid.length()) + (body->getChannelNumber() != -1 ? 3 : 0)) + getSupportedRateElementsLength(body) + getHtMgmtElementsLength(body));
sendManagementFrame("ProbeResp", body, ST_PROBERESPONSE, staAddress);
}

Expand Down
2 changes: 1 addition & 1 deletion src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtAp.ned
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ simple Ieee80211MgmtAp extends SimpleModule like IIeee80211Mgmt
parameters:
@class(Ieee80211MgmtAp);
string ssid = default("SSID");
double beaconInterval @unit(s) = default(100ms);
double beaconInterval @unit(s) = default(100ms); // 1..65535 TUs; rounded down to whole 1024 us TUs for scheduling and advertisement
int numAuthSteps = default(4); // Use 2 for Open System auth, 4 for WEP
string interfaceTableModule;
string radioModule = default("^.radio"); // The path to the Radio module //FIXME remove default value
Expand Down
44 changes: 27 additions & 17 deletions src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtApBase.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@
#endif // ifdef INET_WITH_ETHERNET

#include "inet/linklayer/ieee80211/mgmt/Ieee80211MgmtApBase.h"
#include "inet/physicallayer/wireless/common/contract/packetlevel/IRadio.h"
#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211Transmitter.h"
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211Channel.h"
#include "inet/physicallayer/wireless/ieee80211/mode/Ieee80211Band.h"
#include "inet/physicallayer/wireless/ieee80211/packetlevel/Ieee80211RadioChannelChangedDetails.h"

namespace inet {

Expand Down Expand Up @@ -58,27 +57,38 @@ void Ieee80211MgmtApBase::receiveSignal(cComponent *source, simsignal_t signalID

if (source == radio && signalID == ieee80211RadioChannelChangedSignal) {
EV << "Updating AP primary channel to " << value << ".\n";
if (mib->isHtOperationSupported())
mib->setPrimaryChannel(value, getHtOperationBand());
const auto *channelDetails = dynamic_cast<const physicallayer::Ieee80211RadioChannelChangedDetails *>(details);
const auto *band = channelDetails == nullptr ? nullptr : channelDetails->getBand();
if (mib->isHtOperationSupported()) {
if (band == nullptr)
throw cRuntimeError("HT Operation channel conversion requires radioChannelChanged with IEEE 802.11 band details");
mib->setPrimaryChannel(value, band);
}
else
mib->setPrimaryChannel(value);
radioBand = band;
}
}

const physicallayer::IIeee80211Band *Ieee80211MgmtApBase::getHtOperationBand() const
{
if (radio == nullptr)
throw cRuntimeError("HT Operation channel conversion requires a configured radioModule");
const auto *radioContract = dynamic_cast<const physicallayer::IRadio *>(radio);
if (radioContract == nullptr)
throw cRuntimeError("HT Operation channel conversion requires radioModule to reference a radio, got %s", radio->getClassName());
const auto *transmitter = dynamic_cast<const physicallayer::Ieee80211Transmitter *>(radioContract->getTransmitter());
if (transmitter == nullptr)
throw cRuntimeError("HT Operation channel conversion requires radioModule's transmitter to provide an IEEE 802.11 channel");
const auto *channel = transmitter->getChannel();
if (channel == nullptr || channel->getBand() == nullptr)
throw cRuntimeError("HT Operation channel conversion requires radioModule's IEEE 802.11 transmitter to have a configured channel and band");
return channel->getBand();
if (radioBand == nullptr)
throw cRuntimeError("HT Operation channel conversion requires radioChannelChanged with IEEE 802.11 band details");
return radioBand;
}

int Ieee80211MgmtApBase::getDsssParameterSetChannel() const
{
// IEEE Std 802.11-2024, Tables 9-62 and 9-69, 9.4.2.4:
// advertise DSSS Current Channel for the modeled 2.4 GHz operation.
// Omit it for other bands and generic radios without an IEEE channel.
if (radioBand == nullptr || !mib->hasPrimaryChannel())
return -1;
int channelIndex = mib->requirePrimaryChannel();
auto frequency = radioBand->getCenterFrequency(channelIndex);
if (frequency < GHz(2.4) || frequency >= GHz(2.5))
return -1;
return radioBand->getStandardChannelNumber(channelIndex);
}

} // namespace ieee80211
Expand Down
3 changes: 2 additions & 1 deletion src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtApBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ class INET_API Ieee80211MgmtApBase : public Ieee80211MgmtBase
{
protected:
cModule *radio = nullptr;
const physicallayer::IIeee80211Band *radioBand = nullptr; // Immutable band observed via radioChannelChanged

const physicallayer::IIeee80211Band *getHtOperationBand() const;
int getDsssParameterSetChannel() const;

virtual int numInitStages() const override { return NUM_INIT_STAGES; }
virtual void initialize(int) override;
Expand All @@ -45,4 +47,3 @@ class INET_API Ieee80211MgmtApBase : public Ieee80211MgmtBase
} // namespace inet

#endif

4 changes: 2 additions & 2 deletions src/inet/linklayer/ieee80211/mgmt/Ieee80211MgmtFrame.msg
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ enum Ieee80211ReasonCode
RC_MESH_INCONSISTENT_PARAMETERS = 59;
RC_MESH_INVALID_SECURITY_CAPABILITY = 60;
RC_MESH_PATH_ERROR_NO_PROXY_INFORMATION = 61;
RC_MESH_PATH_ERROR_NO_FORWARDING_INFORMATION = 60;
RC_MESH_PATH_ERROR_NO_FORWARDING_INFORMATION = 62; // IEEE Std 802.11-2024, Table 9-79
RC_MESH_PATH_ERROR_DESTINATION_UNREACHABLE = 63;
RC_MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS = 64;
RC_MESH_CHANNEL_SWITCH_REGULATORY_REQUIREMENTS = 65;
Expand Down Expand Up @@ -253,7 +253,7 @@ class Ieee80211BeaconFrame extends Ieee80211MgmtFrame
string SSID;
Ieee80211SupportedRatesElement supportedRates;
simtime_t beaconInterval;
int channelNumber;
int channelNumber = -1; // DSSS Parameter Set Current Channel (standard channel number, not an internal index); -1 means absent
Ieee80211HandoverParameters handoverParameters; //TODO is it a vendor-specific parameter in serializer?
}

Expand Down
Loading