wifi, network: Various improvements for radiotap headers

This commit is contained in:
Sébastien Deronne
2024-10-12 09:21:52 +02:00
parent c6351e5471
commit 88cca12375
5 changed files with 825 additions and 542 deletions

View File

@@ -22,40 +22,6 @@ NS_LOG_COMPONENT_DEFINE("RadiotapHeader");
NS_OBJECT_ENSURE_REGISTERED(RadiotapHeader);
RadiotapHeader::RadiotapHeader()
: m_length(8),
m_present(0),
m_tsft(0),
m_flags(FRAME_FLAG_NONE),
m_rate(0),
m_channelFreq(0),
m_channelFlags(CHANNEL_FLAG_NONE),
m_antennaSignal(0),
m_antennaNoise(0),
m_ampduStatusRef(0),
m_ampduStatusFlags(0),
m_ampduStatusCRC(0),
m_vhtPad(0),
m_vhtKnown(0),
m_vhtFlags(0),
m_vhtBandwidth(0),
m_vhtCoding(0),
m_vhtGroupId(0),
m_vhtPartialAid(0),
m_hePad(0),
m_heData1(0),
m_heData2(0),
m_heData3(0),
m_heData4(0),
m_heData5(0),
m_heData6(0),
m_heMuPad(0),
m_heMuFlags1(0),
m_heMuFlags2(0),
m_heMuOtherUserPad(0),
m_heMuPerUser1(0),
m_heMuPerUser2(0),
m_heMuPerUserPosition(0),
m_heMuPerUserKnown(0)
{
NS_LOG_FUNCTION(this);
}
@@ -128,9 +94,7 @@ RadiotapHeader::Serialize(Buffer::Iterator start) const
//
if (m_present & RADIOTAP_CHANNEL) // bit 3
{
start.WriteU8(0, m_channelPad);
start.WriteU16(m_channelFreq);
start.WriteU16(m_channelFlags);
SerializeChannel(start);
}
//
@@ -245,9 +209,7 @@ RadiotapHeader::Serialize(Buffer::Iterator start) const
//
if (m_present & RADIOTAP_MCS) // bit 19
{
start.WriteU8(m_mcsKnown);
start.WriteU8(m_mcsFlags);
start.WriteU8(m_mcsRate);
SerializeMcs(start);
}
//
@@ -256,11 +218,7 @@ RadiotapHeader::Serialize(Buffer::Iterator start) const
//
if (m_present & RADIOTAP_AMPDU_STATUS) // bit 20
{
start.WriteU8(0, m_ampduStatusPad);
start.WriteU32(m_ampduStatusRef);
start.WriteU16(m_ampduStatusFlags);
start.WriteU8(m_ampduStatusCRC);
start.WriteU8(0);
SerializeAmpduStatus(start);
}
//
@@ -269,17 +227,7 @@ RadiotapHeader::Serialize(Buffer::Iterator start) const
//
if (m_present & RADIOTAP_VHT) // bit 21
{
start.WriteU8(0, m_vhtPad);
start.WriteU16(m_vhtKnown);
start.WriteU8(m_vhtFlags);
start.WriteU8(m_vhtBandwidth);
for (uint8_t i = 0; i < 4; i++)
{
start.WriteU8(m_vhtMcsNss[i]);
}
start.WriteU8(m_vhtCoding);
start.WriteU8(m_vhtGroupId);
start.WriteU16(m_vhtPartialAid);
SerializeVht(start);
}
//
@@ -288,13 +236,7 @@ RadiotapHeader::Serialize(Buffer::Iterator start) const
//
if (m_present & RADIOTAP_HE) // bit 23
{
start.WriteU8(0, m_hePad);
start.WriteU16(m_heData1);
start.WriteU16(m_heData2);
start.WriteU16(m_heData3);
start.WriteU16(m_heData4);
start.WriteU16(m_heData5);
start.WriteU16(m_heData6);
SerializeHe(start);
}
//
@@ -303,17 +245,7 @@ RadiotapHeader::Serialize(Buffer::Iterator start) const
//
if (m_present & RADIOTAP_HE_MU) // bit 24
{
start.WriteU8(0, m_heMuPad);
start.WriteU16(m_heMuFlags1);
start.WriteU16(m_heMuFlags2);
start.WriteU8(0);
start.WriteU8(0);
start.WriteU8(0);
start.WriteU8(0);
start.WriteU8(0);
start.WriteU8(0);
start.WriteU8(0);
start.WriteU8(0);
SerializeHeMu(start);
}
//
@@ -322,11 +254,7 @@ RadiotapHeader::Serialize(Buffer::Iterator start) const
//
if (m_present & RADIOTAP_HE_MU_OTHER_USER) // bit 25
{
start.WriteU8(0, m_heMuOtherUserPad);
start.WriteU16(m_heMuPerUser1);
start.WriteU16(m_heMuPerUser2);
start.WriteU8(m_heMuPerUserPosition);
start.WriteU8(m_heMuPerUserKnown);
SerializeHeMuOtherUser(start);
}
}
@@ -380,11 +308,7 @@ RadiotapHeader::Deserialize(Buffer::Iterator start)
//
if (m_present & RADIOTAP_CHANNEL) // bit 3
{
m_channelPad = ((2 - bytesRead % 2) % 2);
start.Next(m_channelPad);
m_channelFreq = start.ReadU16();
m_channelFlags = start.ReadU16();
bytesRead += (4 + m_channelPad);
bytesRead += DeserializeChannel(start, bytesRead);
}
//
@@ -519,25 +443,16 @@ RadiotapHeader::Deserialize(Buffer::Iterator start)
//
if (m_present & RADIOTAP_MCS) // bit 19
{
m_mcsKnown = start.ReadU8();
m_mcsFlags = start.ReadU8();
m_mcsRate = start.ReadU8();
bytesRead += 3;
bytesRead += DeserializeMcs(start, bytesRead);
}
//
// A-MPDU Status, information about the received or transmitted A-MPDU.
// Reference: https://www.radiotap.org/fields/A-MPDU%20status.html
//
if (m_present & RADIOTAP_AMPDU_STATUS) // bit 20
if (m_present & RADIOTAP_AMPDU_STATUS)
{
m_ampduStatusPad = ((4 - bytesRead % 4) % 4);
start.Next(m_ampduStatusPad);
m_ampduStatusRef = start.ReadU32();
m_ampduStatusFlags = start.ReadU16();
m_ampduStatusCRC = start.ReadU8();
start.ReadU8();
bytesRead += (8 + m_ampduStatusPad);
bytesRead += DeserializeAmpduStatus(start, bytesRead);
}
//
@@ -546,19 +461,7 @@ RadiotapHeader::Deserialize(Buffer::Iterator start)
//
if (m_present & RADIOTAP_VHT) // bit 21
{
m_vhtPad = ((2 - bytesRead % 2) % 2);
start.Next(m_vhtPad);
m_vhtKnown = start.ReadU16();
m_vhtFlags = start.ReadU8();
m_vhtBandwidth = start.ReadU8();
for (uint8_t i = 0; i < 4; i++)
{
m_vhtMcsNss[i] = start.ReadU8();
}
m_vhtCoding = start.ReadU8();
m_vhtGroupId = start.ReadU8();
m_vhtPartialAid = start.ReadU16();
bytesRead += (12 + m_vhtPad);
bytesRead += DeserializeVht(start, bytesRead);
}
//
@@ -567,15 +470,7 @@ RadiotapHeader::Deserialize(Buffer::Iterator start)
//
if (m_present & RADIOTAP_HE) // bit 23
{
m_hePad = ((2 - bytesRead % 2) % 2);
start.Next(m_hePad);
m_heData1 = start.ReadU16();
m_heData2 = start.ReadU16();
m_heData3 = start.ReadU16();
m_heData4 = start.ReadU16();
m_heData5 = start.ReadU16();
m_heData6 = start.ReadU16();
bytesRead += (12 + m_hePad);
bytesRead += DeserializeHe(start, bytesRead);
}
//
@@ -584,18 +479,7 @@ RadiotapHeader::Deserialize(Buffer::Iterator start)
//
if (m_present & RADIOTAP_HE_MU) // bit 24
{
m_heMuPad = ((2 - bytesRead % 2) % 2);
m_heMuFlags1 = start.ReadU16();
m_heMuFlags2 = start.ReadU16();
start.ReadU8();
start.ReadU8();
start.ReadU8();
start.ReadU8();
start.ReadU8();
start.ReadU8();
start.ReadU8();
start.ReadU8();
bytesRead += (12 + m_heMuPad);
bytesRead += DeserializeHeMu(start, bytesRead);
}
//
@@ -604,12 +488,7 @@ RadiotapHeader::Deserialize(Buffer::Iterator start)
//
if (m_present & RADIOTAP_HE_MU_OTHER_USER) // bit 25
{
m_heMuOtherUserPad = ((2 - bytesRead % 2) % 2);
m_heMuPerUser1 = start.ReadU16();
m_heMuPerUser2 = start.ReadU16();
m_heMuPerUserPosition = start.ReadU8();
m_heMuPerUserKnown = start.ReadU8();
bytesRead += (6 + m_heMuOtherUserPad);
bytesRead += DeserializeHeMuOtherUser(start, bytesRead);
}
NS_ASSERT_MSG(m_length == bytesRead,
@@ -621,34 +500,47 @@ void
RadiotapHeader::Print(std::ostream& os) const
{
NS_LOG_FUNCTION(this << &os);
os << " tsft=" << m_tsft << " flags=" << std::hex << m_flags << std::dec << " rate=" << +m_rate
<< " freq=" << m_channelFreq << " chflags=" << std::hex << +m_channelFlags << std::dec
<< " signal=" << +m_antennaSignal << " noise=" << +m_antennaNoise
<< " mcsKnown=" << m_mcsKnown << " mcsFlags=" << m_mcsFlags << " mcsRate=" << m_mcsRate
<< " ampduStatusFlags=" << +m_ampduStatusFlags << " vhtKnown=" << m_vhtKnown
<< " vhtFlags=" << m_vhtFlags << " vhtBandwidth=" << m_vhtBandwidth
<< " vhtMcsNss for user 1=" << m_vhtMcsNss[0] << " vhtMcsNss for user 2=" << m_vhtMcsNss[1]
<< " vhtMcsNss for user 3=" << m_vhtMcsNss[2] << " vhtMcsNss for user 4=" << m_vhtMcsNss[3]
<< " vhtCoding=" << m_vhtCoding << " vhtGroupId=" << m_vhtGroupId
<< " vhtPartialAid=" << m_vhtPartialAid << " heData1=" << m_heData1
<< " heData2=" << m_heData2 << " heData3=" << m_heData3 << " heData4=" << m_heData4
<< " heData5=" << m_heData5 << " heData6=" << m_heData6 << " heMuFlags1=" << m_heMuFlags1
<< " heMuFlags2=" << m_heMuFlags2 << " heMuPerUser1=" << m_heMuPerUser1
<< " heMuPerUser2=" << m_heMuPerUser2 << " heMuPerUserPosition=" << +m_heMuPerUserPosition
<< " heMuPerUserKnown=" << +m_heMuPerUserKnown;
os << " tsft=" << m_tsft << " flags=" << std::hex << m_flags << std::dec << " rate=" << +m_rate;
if (m_present & RADIOTAP_CHANNEL)
{
PrintChannel(os);
}
os << std::dec << " signal=" << +m_antennaSignal << " noise=" << +m_antennaNoise;
if (m_present & RADIOTAP_MCS)
{
PrintMcs(os);
}
if (m_present & RADIOTAP_AMPDU_STATUS)
{
PrintAmpduStatus(os);
}
if (m_present & RADIOTAP_VHT)
{
PrintVht(os);
}
if (m_present & RADIOTAP_HE)
{
PrintHe(os);
}
if (m_present & RADIOTAP_HE_MU)
{
PrintHeMu(os);
}
if (m_present & RADIOTAP_HE_MU_OTHER_USER)
{
PrintHeMuOtherUser(os);
}
}
void
RadiotapHeader::SetTsft(uint64_t value)
{
NS_LOG_FUNCTION(this << value);
m_tsft = value;
if (!(m_present & RADIOTAP_TSFT))
{
m_present |= RADIOTAP_TSFT;
m_length += 8;
}
NS_ASSERT_MSG(!(m_present & RADIOTAP_TSFT), "TSFT radiotap field already present");
m_present |= RADIOTAP_TSFT;
m_length += 8;
m_tsft = value;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
@@ -658,13 +550,11 @@ void
RadiotapHeader::SetFrameFlags(uint8_t flags)
{
NS_LOG_FUNCTION(this << +flags);
m_flags = flags;
if (!(m_present & RADIOTAP_FLAGS))
{
m_present |= RADIOTAP_FLAGS;
m_length += 1;
}
NS_ASSERT_MSG(!(m_present & RADIOTAP_FLAGS), "Flags radiotap field already present");
m_present |= RADIOTAP_FLAGS;
m_length += 1;
m_flags = flags;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
@@ -674,46 +564,66 @@ void
RadiotapHeader::SetRate(uint8_t rate)
{
NS_LOG_FUNCTION(this << +rate);
m_rate = rate;
if (!(m_present & RADIOTAP_RATE))
{
m_present |= RADIOTAP_RATE;
m_length += 1;
}
NS_ASSERT_MSG(!(m_present & RADIOTAP_RATE), "Rate radiotap field already present");
m_present |= RADIOTAP_RATE;
m_length += 1;
m_rate = rate;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
}
void
RadiotapHeader::SetChannelFrequencyAndFlags(uint16_t frequency, uint16_t flags)
RadiotapHeader::SetChannelFields(const ChannelFields& channelFields)
{
NS_LOG_FUNCTION(this << frequency << flags);
m_channelFreq = frequency;
m_channelFlags = flags;
NS_LOG_FUNCTION(this << channelFields.frequency << channelFields.flags);
if (!(m_present & RADIOTAP_CHANNEL))
{
m_channelPad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_CHANNEL;
m_length += (4 + m_channelPad);
}
NS_ASSERT_MSG(!(m_present & RADIOTAP_CHANNEL), "Channel radiotap field already present");
m_channelPad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_CHANNEL;
m_length += (sizeof(ChannelFields) + m_channelPad);
m_channelFields = channelFields;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
}
void
RadiotapHeader::SerializeChannel(Buffer::Iterator& start) const
{
start.WriteU8(0, m_channelPad);
start.WriteU16(m_channelFields.frequency);
start.WriteU16(m_channelFields.flags);
}
uint32_t
RadiotapHeader::DeserializeChannel(Buffer::Iterator start, uint32_t bytesRead)
{
m_channelPad = ((2 - bytesRead % 2) % 2);
start.Next(m_channelPad);
m_channelFields.frequency = start.ReadU16();
m_channelFields.flags = start.ReadU16();
return sizeof(ChannelFields) + m_channelPad;
}
void
RadiotapHeader::PrintChannel(std::ostream& os) const
{
os << " channel.frequency=" << m_channelFields.frequency << " channel.flags=0x" << std::hex
<< m_channelFields.flags << std::dec;
}
void
RadiotapHeader::SetAntennaSignalPower(double signal)
{
NS_LOG_FUNCTION(this << signal);
if (!(m_present & RADIOTAP_DBM_ANTSIGNAL))
{
m_present |= RADIOTAP_DBM_ANTSIGNAL;
m_length += 1;
}
NS_ASSERT_MSG(!(m_present & RADIOTAP_DBM_ANTSIGNAL),
"Antenna signal radiotap field already present");
m_present |= RADIOTAP_DBM_ANTSIGNAL;
m_length += 1;
if (signal > 127)
{
m_antennaSignal = 127;
@@ -736,11 +646,11 @@ RadiotapHeader::SetAntennaNoisePower(double noise)
{
NS_LOG_FUNCTION(this << noise);
if (!(m_present & RADIOTAP_DBM_ANTNOISE))
{
m_present |= RADIOTAP_DBM_ANTNOISE;
m_length += 1;
}
NS_ASSERT_MSG(!(m_present & RADIOTAP_DBM_ANTNOISE),
"Antenna noise radiotap field already present");
m_present |= RADIOTAP_DBM_ANTNOISE;
m_length += 1;
if (noise > 127.0)
{
m_antennaNoise = 127;
@@ -759,138 +669,306 @@ RadiotapHeader::SetAntennaNoisePower(double noise)
}
void
RadiotapHeader::SetMcsFields(uint8_t known, uint8_t flags, uint8_t mcs)
RadiotapHeader::SetMcsFields(const McsFields& mcsFields)
{
NS_LOG_FUNCTION(this << known << +flags << +mcs);
m_mcsKnown = known;
m_mcsFlags = flags;
m_mcsRate = mcs;
if (!(m_present & RADIOTAP_MCS))
{
m_present |= RADIOTAP_MCS;
m_length += 3;
}
NS_LOG_FUNCTION(this << +mcsFields.known << +mcsFields.flags << +mcsFields.mcs);
NS_ASSERT_MSG(!(m_present & RADIOTAP_MCS), "MCS radiotap field already present");
m_present |= RADIOTAP_MCS;
m_length += sizeof(McsFields);
m_mcsFields = mcsFields;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
}
void
RadiotapHeader::SetAmpduStatus(uint32_t referenceNumber, uint16_t flags, uint8_t crc)
RadiotapHeader::SerializeMcs(Buffer::Iterator& start) const
{
NS_LOG_FUNCTION(this << referenceNumber << flags);
m_ampduStatusRef = referenceNumber;
m_ampduStatusFlags = flags;
m_ampduStatusCRC = crc;
if (!(m_present & RADIOTAP_AMPDU_STATUS))
{
m_ampduStatusPad = ((4 - m_length % 4) % 4);
m_present |= RADIOTAP_AMPDU_STATUS;
m_length += (8 + m_ampduStatusPad);
}
start.WriteU8(m_mcsFields.known);
start.WriteU8(m_mcsFields.flags);
start.WriteU8(m_mcsFields.mcs);
}
uint32_t
RadiotapHeader::DeserializeMcs(Buffer::Iterator start, uint32_t bytesRead)
{
m_mcsFields.known = start.ReadU8();
m_mcsFields.flags = start.ReadU8();
m_mcsFields.mcs = start.ReadU8();
return sizeof(McsFields);
}
void
RadiotapHeader::PrintMcs(std::ostream& os) const
{
os << " mcs.known=0x" << std::hex << +m_mcsFields.known << " mcs.flags0x=" << +m_mcsFields.flags
<< " mcsRate=" << std::dec << +m_mcsFields.mcs;
}
void
RadiotapHeader::SetAmpduStatus(const AmpduStatusFields& ampduStatusFields)
{
NS_LOG_FUNCTION(this << ampduStatusFields.referenceNumber << ampduStatusFields.flags);
NS_ASSERT_MSG(!(m_present & RADIOTAP_AMPDU_STATUS),
"A-MPDU status radiotap field already present");
m_ampduStatusPad = ((4 - m_length % 4) % 4);
m_present |= RADIOTAP_AMPDU_STATUS;
m_length += (sizeof(ampduStatusFields) + m_ampduStatusPad);
m_ampduStatusFields = ampduStatusFields;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
}
void
RadiotapHeader::SetVhtFields(uint16_t known,
uint8_t flags,
uint8_t bandwidth,
uint8_t mcs_nss[4],
uint8_t coding,
uint8_t group_id,
uint16_t partial_aid)
RadiotapHeader::SerializeAmpduStatus(Buffer::Iterator& start) const
{
NS_LOG_FUNCTION(this << known << flags << +mcs_nss[0] << +mcs_nss[1] << +mcs_nss[2]
<< +mcs_nss[3] << +coding << +group_id << +partial_aid);
m_vhtKnown = known;
m_vhtFlags = flags;
m_vhtBandwidth = bandwidth;
for (uint8_t i = 0; i < 4; i++)
{
m_vhtMcsNss[i] = mcs_nss[i];
}
m_vhtCoding = coding;
m_vhtGroupId = group_id;
m_vhtPartialAid = partial_aid;
if (!(m_present & RADIOTAP_VHT))
{
m_vhtPad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_VHT;
m_length += (12 + m_vhtPad);
}
start.WriteU8(0, m_ampduStatusPad);
start.WriteU32(m_ampduStatusFields.referenceNumber);
start.WriteU16(m_ampduStatusFields.flags);
start.WriteU8(m_ampduStatusFields.crc);
start.WriteU8(m_ampduStatusFields.reserved);
}
uint32_t
RadiotapHeader::DeserializeAmpduStatus(Buffer::Iterator start, uint32_t bytesRead)
{
m_ampduStatusPad = ((4 - bytesRead % 4) % 4);
start.Next(m_ampduStatusPad);
m_ampduStatusFields.referenceNumber = start.ReadU32();
m_ampduStatusFields.flags = start.ReadU16();
m_ampduStatusFields.crc = start.ReadU8();
m_ampduStatusFields.reserved = start.ReadU8();
return sizeof(AmpduStatusFields) + m_ampduStatusPad;
}
void
RadiotapHeader::PrintAmpduStatus(std::ostream& os) const
{
os << " ampduStatus.flags=0x" << std::hex << m_ampduStatusFields.flags << std::dec;
}
void
RadiotapHeader::SetVhtFields(const VhtFields& vhtFields)
{
NS_LOG_FUNCTION(this << vhtFields.known << vhtFields.flags << +vhtFields.mcsNss.at(0)
<< +vhtFields.mcsNss.at(1) << +vhtFields.mcsNss.at(2)
<< +vhtFields.mcsNss.at(3) << +vhtFields.coding << +vhtFields.groupId
<< +vhtFields.partialAid);
NS_ASSERT_MSG(!(m_present & RADIOTAP_VHT), "VHT radiotap field already present");
m_vhtPad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_VHT;
m_length += (sizeof(VhtFields) + m_vhtPad);
m_vhtFields = vhtFields;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
}
void
RadiotapHeader::SetHeFields(uint16_t data1,
uint16_t data2,
uint16_t data3,
uint16_t data4,
uint16_t data5,
uint16_t data6)
RadiotapHeader::SerializeVht(Buffer::Iterator& start) const
{
NS_LOG_FUNCTION(this << data1 << data2 << data3 << data4 << data5 << data6);
m_heData1 = data1;
m_heData2 = data2;
m_heData3 = data3;
m_heData4 = data4;
m_heData5 = data5;
m_heData6 = data6;
if (!(m_present & RADIOTAP_HE))
start.WriteU8(0, m_vhtPad);
start.WriteU16(m_vhtFields.known);
start.WriteU8(m_vhtFields.flags);
start.WriteU8(m_vhtFields.bandwidth);
for (const auto mcsNss : m_vhtFields.mcsNss)
{
m_hePad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_HE;
m_length += (12 + m_hePad);
start.WriteU8(mcsNss);
}
start.WriteU8(m_vhtFields.coding);
start.WriteU8(m_vhtFields.groupId);
start.WriteU16(m_vhtFields.partialAid);
}
uint32_t
RadiotapHeader::DeserializeVht(Buffer::Iterator start, uint32_t bytesRead)
{
m_vhtPad = ((2 - bytesRead % 2) % 2);
start.Next(m_vhtPad);
m_vhtFields.known = start.ReadU16();
m_vhtFields.flags = start.ReadU8();
m_vhtFields.bandwidth = start.ReadU8();
for (auto& mcsNss : m_vhtFields.mcsNss)
{
mcsNss = start.ReadU8();
}
m_vhtFields.coding = start.ReadU8();
m_vhtFields.groupId = start.ReadU8();
m_vhtFields.partialAid = start.ReadU16();
return sizeof(VhtFields) + m_vhtPad;
}
void
RadiotapHeader::PrintVht(std::ostream& os) const
{
os << " vht.known=0x" << m_vhtFields.known << " vht.flags=0x" << m_vhtFields.flags
<< " vht.bandwidth=" << std::dec << m_vhtFields.bandwidth
<< " vht.mcsNss[0]=" << +m_vhtFields.mcsNss.at(0)
<< " vht.mcsNss[1]=" << +m_vhtFields.mcsNss.at(1)
<< " vht.mcsNss[2]=" << +m_vhtFields.mcsNss.at(2)
<< " vht.mcsNss[3]=" << +m_vhtFields.mcsNss.at(3) << " vht.coding=" << m_vhtFields.coding
<< " vht.groupId=" << m_vhtFields.groupId << " vht.partialAid=" << m_vhtFields.partialAid;
}
void
RadiotapHeader::SetHeFields(const HeFields& heFields)
{
NS_LOG_FUNCTION(this << heFields.data1 << heFields.data2 << heFields.data3 << heFields.data4
<< heFields.data5 << heFields.data6);
NS_ASSERT_MSG(!(m_present & RADIOTAP_HE), "HE radiotap field already present");
m_hePad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_HE;
m_length += (sizeof(heFields) + m_hePad);
m_heFields = heFields;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
}
void
RadiotapHeader::SetHeMuFields(uint16_t flags1,
uint16_t flags2,
const std::array<uint8_t, 4>& /*ruChannel1*/,
const std::array<uint8_t, 4>& /*ruChannel2*/)
RadiotapHeader::SerializeHe(Buffer::Iterator& start) const
{
NS_LOG_FUNCTION(this << flags1 << flags2);
m_heMuFlags1 = flags1;
m_heMuFlags2 = flags2;
if (!(m_present & RADIOTAP_HE_MU))
{
m_heMuPad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_HE_MU;
m_length += (12 + m_heMuPad);
}
start.WriteU8(0, m_hePad);
start.WriteU16(m_heFields.data1);
start.WriteU16(m_heFields.data2);
start.WriteU16(m_heFields.data3);
start.WriteU16(m_heFields.data4);
start.WriteU16(m_heFields.data5);
start.WriteU16(m_heFields.data6);
}
uint32_t
RadiotapHeader::DeserializeHe(Buffer::Iterator start, uint32_t bytesRead)
{
m_hePad = ((2 - bytesRead % 2) % 2);
start.Next(m_hePad);
m_heFields.data1 = start.ReadU16();
m_heFields.data2 = start.ReadU16();
m_heFields.data3 = start.ReadU16();
m_heFields.data4 = start.ReadU16();
m_heFields.data5 = start.ReadU16();
m_heFields.data6 = start.ReadU16();
return sizeof(HeFields) + m_hePad;
}
void
RadiotapHeader::PrintHe(std::ostream& os) const
{
os << " he.data1=0x" << std::hex << m_heFields.data1 << " he.data2=0x" << std::hex
<< m_heFields.data2 << " he.data3=0x" << std::hex << m_heFields.data3 << " he.data4=0x"
<< std::hex << m_heFields.data4 << " he.data5=0x" << std::hex << m_heFields.data5
<< " he.data6=0x" << std::hex << m_heFields.data6 << std::dec;
}
void
RadiotapHeader::SetHeMuFields(const HeMuFields& heMuFields)
{
NS_LOG_FUNCTION(this << heMuFields.flags1 << heMuFields.flags2);
NS_ASSERT_MSG(!(m_present & RADIOTAP_HE_MU), "HE-MU radiotap field already present");
m_heMuPad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_HE_MU;
m_length += (sizeof(heMuFields) + m_heMuPad);
m_heMuFields = heMuFields;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
}
void
RadiotapHeader::SetHeMuPerUserFields(uint16_t perUser1,
uint16_t perUser2,
uint8_t perUserPosition,
uint8_t perUserKnown)
RadiotapHeader::SerializeHeMu(Buffer::Iterator& start) const
{
NS_LOG_FUNCTION(this << perUser1 << perUser2 << +perUserPosition << +perUserKnown);
m_heMuPerUser1 = perUser1;
m_heMuPerUser2 = perUser2;
m_heMuPerUserPosition = perUserPosition;
m_heMuPerUserKnown = perUserKnown;
if (!(m_present & RADIOTAP_HE_MU_OTHER_USER))
start.WriteU8(0, m_heMuPad);
start.WriteU16(m_heMuFields.flags1);
start.WriteU16(m_heMuFields.flags2);
for (const auto ruChannel : m_heMuFields.ruChannel1)
{
m_heMuOtherUserPad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_HE_MU_OTHER_USER;
m_length += (6 + m_heMuOtherUserPad);
start.WriteU8(ruChannel);
}
for (const auto ruChannel : m_heMuFields.ruChannel2)
{
start.WriteU8(ruChannel);
}
}
uint32_t
RadiotapHeader::DeserializeHeMu(Buffer::Iterator start, uint32_t bytesRead)
{
m_heMuPad = ((2 - bytesRead % 2) % 2);
start.Next(m_heMuPad);
m_heMuFields.flags1 = start.ReadU16();
m_heMuFields.flags2 = start.ReadU16();
for (auto& ruChannel : m_heMuFields.ruChannel1)
{
ruChannel = start.ReadU8();
}
for (auto& ruChannel : m_heMuFields.ruChannel2)
{
ruChannel = start.ReadU8();
}
return sizeof(HeMuFields) + m_heMuPad;
}
void
RadiotapHeader::PrintHeMu(std::ostream& os) const
{
os << " heMu.flags1=0x" << std::hex << m_heMuFields.flags1 << " heMu.flags2=0x"
<< m_heMuFields.flags2 << std::dec;
}
void
RadiotapHeader::SetHeMuOtherUserFields(const HeMuOtherUserFields& heMuOtherUserFields)
{
NS_LOG_FUNCTION(this << heMuOtherUserFields.perUser1 << heMuOtherUserFields.perUser2
<< +heMuOtherUserFields.perUserPosition
<< +heMuOtherUserFields.perUserKnown);
NS_ASSERT_MSG(!(m_present & RADIOTAP_HE_MU_OTHER_USER),
"HE-MU-other-user radiotap field already present");
m_heMuOtherUserPad = ((2 - m_length % 2) % 2);
m_present |= RADIOTAP_HE_MU_OTHER_USER;
m_length += (sizeof(HeMuOtherUserFields) + m_heMuOtherUserPad);
m_heMuOtherUserFields = heMuOtherUserFields;
NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
<< std::dec);
}
void
RadiotapHeader::SerializeHeMuOtherUser(Buffer::Iterator& start) const
{
start.WriteU8(0, m_heMuOtherUserPad);
start.WriteU16(m_heMuOtherUserFields.perUser1);
start.WriteU16(m_heMuOtherUserFields.perUser2);
start.WriteU8(m_heMuOtherUserFields.perUserPosition);
start.WriteU8(m_heMuOtherUserFields.perUserKnown);
}
uint32_t
RadiotapHeader::DeserializeHeMuOtherUser(Buffer::Iterator start, uint32_t bytesRead)
{
m_heMuOtherUserPad = ((2 - bytesRead % 2) % 2);
start.Next(m_heMuOtherUserPad);
m_heMuOtherUserFields.perUser1 = start.ReadU16();
m_heMuOtherUserFields.perUser2 = start.ReadU16();
m_heMuOtherUserFields.perUserPosition = start.ReadU8();
m_heMuOtherUserFields.perUserKnown = start.ReadU8();
return sizeof(HeMuOtherUserFields) + m_heMuOtherUserPad;
}
void
RadiotapHeader::PrintHeMuOtherUser(std::ostream& os) const
{
os << " heMuOtherUser.perUser1=" << m_heMuOtherUserFields.perUser1
<< " heMuOtherUser.perUser2=" << m_heMuOtherUserFields.perUser2
<< " heMuOtherUser.perUserPosition=" << m_heMuOtherUserFields.perUserPosition
<< " heMuOtherUser.perUserKnown=0x" << std::hex << m_heMuOtherUserFields.perUserKnown
<< std::dec;
}
} // namespace ns3

View File

@@ -12,6 +12,8 @@
#include <ns3/header.h>
#include <array>
namespace ns3
{
@@ -58,8 +60,7 @@ class RadiotapHeader : public Header
* byte buffer of a packet. The data read is expected to match bit-for-bit
* the representation of this header in real networks.
*
* @param start An iterator which points to where the header should
* written.
* @param start An iterator which points to where the header should be read.
* @returns The number of bytes read.
*/
uint32_t Deserialize(Buffer::Iterator start) override;
@@ -92,7 +93,7 @@ class RadiotapHeader : public Header
/**
* @brief Frame flags.
*/
enum FrameFlag
enum FrameFlag : uint8_t
{
FRAME_FLAG_NONE = 0x00, /**< No flags set */
FRAME_FLAG_CFP = 0x01, /**< Frame sent/received during CFP */
@@ -121,7 +122,7 @@ class RadiotapHeader : public Header
/**
* @brief Channel flags.
*/
enum ChannelFlags
enum ChannelFlags : uint16_t
{
CHANNEL_FLAG_NONE = 0x0000, /**< No flags set */
CHANNEL_FLAG_TURBO = 0x0010, /**< Turbo Channel */
@@ -135,12 +136,20 @@ class RadiotapHeader : public Header
};
/**
* @brief Set the transmit/receive channel frequency and flags
* @param frequency The transmit/receive data rate in units of 500 kbps.
* @param flags The flags to set.
* @see ChannelFlags
* structure that contains the subfields of the Channel field.
*/
void SetChannelFrequencyAndFlags(uint16_t frequency, uint16_t flags);
struct ChannelFields
{
uint16_t frequency{0}; //!< Tx/Rx frequency in MHz
uint16_t flags{CHANNEL_FLAG_NONE}; //!< flags field (@see ChannelFlags)
};
/**
* @brief Set the subfields of the Channel field
*
* @param channelFields The subfields of the Channel field.
*/
void SetChannelFields(const ChannelFields& channelFields);
/**
* @brief Set the RF signal power at the antenna as a decibel difference
@@ -163,7 +172,7 @@ class RadiotapHeader : public Header
/**
* @brief MCS known bits.
*/
enum McsKnown
enum McsKnown : uint8_t
{
MCS_KNOWN_NONE = 0x00, /**< No flags set */
MCS_KNOWN_BANDWIDTH = 0x01, /**< Bandwidth */
@@ -180,7 +189,7 @@ class RadiotapHeader : public Header
/**
* @brief MCS flags.
*/
enum McsFlags
enum McsFlags : uint8_t
{
MCS_FLAGS_NONE =
0x00, /**< Default: 20 MHz, long guard interval, mixed HT format and BCC FEC type */
@@ -196,18 +205,26 @@ class RadiotapHeader : public Header
};
/**
* @brief Set the MCS fields
*
* @param known The kwown flags.
* @param flags The flags to set.
* @param mcs The MCS index value.
* structure that contains the subfields of the MCS field.
*/
void SetMcsFields(uint8_t known, uint8_t flags, uint8_t mcs);
struct McsFields
{
uint8_t known{MCS_KNOWN_NONE}; //!< known flags
uint8_t flags{MCS_FLAGS_NONE}; //!< flags field
uint8_t mcs{0}; //!< MCS index value
};
/**
* @brief Set the subfields of the MCS field
*
* @param mcsFields The subfields of the MCS field.
*/
void SetMcsFields(const McsFields& mcsFields);
/**
* @brief A-MPDU status flags.
*/
enum AmpduFlags
enum AmpduFlags : uint8_t
{
A_MPDU_STATUS_NONE = 0x00, /**< No flags set */
A_MPDU_STATUS_REPORT_ZERO_LENGTH = 0x01, /**< Driver reports 0-length subframes */
@@ -222,19 +239,28 @@ class RadiotapHeader : public Header
};
/**
* @brief Set the A-MPDU status fields
*
* @param referenceNumber The A-MPDU reference number to identify all subframes belonging to the
* same A-MPDU.
* @param flags The flags to set.
* @param crc The CRC value value.
* structure that contains the subfields of the A-MPDU status field.
*/
void SetAmpduStatus(uint32_t referenceNumber, uint16_t flags, uint8_t crc);
struct AmpduStatusFields
{
uint32_t referenceNumber{
0}; //!< A-MPDU reference number to identify all subframes belonging to the same A-MPDU
uint16_t flags{A_MPDU_STATUS_NONE}; //!< flags field
uint8_t crc{1}; //!< CRC field
uint8_t reserved{0}; //!< Reserved field
};
/**
* @brief Set the subfields of the A-MPDU status field
*
* @param ampduStatusFields The subfields of the A-MPDU status field.
*/
void SetAmpduStatus(const AmpduStatusFields& ampduStatusFields);
/**
* @brief VHT known bits.
*/
enum VhtKnown
enum VhtKnown : uint16_t
{
VHT_KNOWN_NONE = 0x0000, /**< No flags set */
VHT_KNOWN_STBC = 0x0001, /**< Space-time block coding (1 if all spatial streams of all users
@@ -253,7 +279,7 @@ class RadiotapHeader : public Header
/**
* @brief VHT flags.
*/
enum VhtFlags
enum VhtFlags : uint8_t
{
VHT_FLAGS_NONE = 0x00, /**< No flags set */
VHT_FLAGS_STBC =
@@ -270,29 +296,32 @@ class RadiotapHeader : public Header
};
/**
* @brief Set the VHT fields
*
* @param known The kwown flags.
* @param flags The flags to set.
* @param bandwidth The bandwidth value.
* @param mcs_nss The mcs_nss value.
* @param coding The coding value.
* @param group_id The group_id value.
* @param partial_aid The partial_aid value.
* structure that contains the subfields of the VHT field.
*/
void SetVhtFields(uint16_t known,
uint8_t flags,
uint8_t bandwidth,
uint8_t mcs_nss[4],
uint8_t coding,
uint8_t group_id,
uint16_t partial_aid);
struct VhtFields
{
uint16_t known{VHT_KNOWN_NONE}; //!< known flags field
uint8_t flags{VHT_FLAGS_NONE}; //!< flags field
uint8_t bandwidth{0}; //!< bandwidth field
std::array<uint8_t, 4> mcsNss{}; //!< mcs_nss field
uint8_t coding{0}; //!< coding field
uint8_t groupId{0}; //!< group_id field
uint16_t partialAid{0}; //!< partial_aid field
};
/**
* @brief HE data1.
* @brief Set the subfields of the VHT field
*
* @param vhtFields The subfields of the VHT field.
*/
enum HeData1
void SetVhtFields(const VhtFields& vhtFields);
/**
* @brief bits of the HE data fields.
*/
enum HeData : uint16_t
{
/* Data 1 */
HE_DATA1_FORMAT_EXT_SU = 0x0001, /**< HE EXT SU PPDU format */
HE_DATA1_FORMAT_MU = 0x0002, /**< HE MU PPDU format */
HE_DATA1_FORMAT_TRIG = 0x0003, /**< HE TRIG PPDU format */
@@ -312,13 +341,7 @@ class RadiotapHeader : public Header
HE_DATA1_SPTL_REUSE4_KNOWN = 0x2000, /**< Spatial Reuse 4 known (HE TRIG PPDU format) */
HE_DATA1_BW_RU_ALLOC_KNOWN = 0x4000, /**< data BW/RU allocation known */
HE_DATA1_DOPPLER_KNOWN = 0x8000, /**< Doppler known */
};
/**
* @brief HE data2.
*/
enum HeData2
{
/* Data 2 */
HE_DATA2_PRISEC_80_KNOWN = 0x0001, /**< pri/sec 80 MHz known */
HE_DATA2_GI_KNOWN = 0x0002, /**< GI known */
HE_DATA2_NUM_LTF_SYMS_KNOWN = 0x0004, /**< number of LTF symbols known */
@@ -330,13 +353,23 @@ class RadiotapHeader : public Header
HE_DATA2_RU_OFFSET = 0x3f00, /**< RU allocation offset */
HE_DATA2_RU_OFFSET_KNOWN = 0x4000, /**< RU allocation offset known */
HE_DATA2_PRISEC_80_SEC = 0x8000, /**< pri/sec 80 MHz */
};
/**
* @brief HE data5.
*/
enum HeData5
{
/* Data 3 */
HE_DATA3_BSS_COLOR = 0x003f,
HE_DATA3_BEAM_CHANGE = 0x0040,
HE_DATA3_UL_DL = 0x0080,
HE_DATA3_DATA_MCS = 0x0f00,
HE_DATA3_DATA_DCM = 0x1000,
HE_DATA3_CODING = 0x2000,
HE_DATA3_LDPC_XSYMSEG = 0x4000,
HE_DATA3_STBC = 0x8000,
/* Data 4 */
HE_DATA4_SU_MU_SPTL_REUSE = 0x000f,
HE_DATA4_MU_STA_ID = 0x7ff0,
HE_DATA4_TB_SPTL_REUSE1 = 0x000f,
HE_DATA4_TB_SPTL_REUSE2 = 0x00f0,
HE_DATA4_TB_SPTL_REUSE3 = 0x0f00,
HE_DATA4_TB_SPTL_REUSE4 = 0xf000,
/* Data 5 */
HE_DATA5_DATA_BW_RU_ALLOC_40MHZ = 0x0001, /**< 40 MHz data Bandwidth */
HE_DATA5_DATA_BW_RU_ALLOC_80MHZ = 0x0002, /**< 80 MHz data Bandwidth */
HE_DATA5_DATA_BW_RU_ALLOC_160MHZ = 0x0003, /**< 160 MHz data Bandwidth */
@@ -357,26 +390,29 @@ class RadiotapHeader : public Header
};
/**
* @brief Set the HE fields
*
* @param data1 The data1 field.
* @param data2 The data2 field.
* @param data3 The data3 field.
* @param data4 The data4 field.
* @param data5 The data5 field.
* @param data6 The data6 field.
* structure that contains the subfields of the HE field.
*/
void SetHeFields(uint16_t data1,
uint16_t data2,
uint16_t data3,
uint16_t data4,
uint16_t data5,
uint16_t data6);
struct HeFields
{
uint16_t data1{0}; //!< data1 field
uint16_t data2{0}; //!< data2 field
uint16_t data3{0}; //!< data3 field
uint16_t data4{0}; //!< data4 field
uint16_t data5{0}; //!< data5 field
uint16_t data6{0}; //!< data6 field
};
/**
* @brief Set the subfields of the HE field
*
* @param heFields The subfields of the HE field.
*/
void SetHeFields(const HeFields& heFields);
/**
* @brief HE MU flags1.
*/
enum HeMuFlags1
enum HeMuFlags1 : uint16_t
{
HE_MU_FLAGS1_SIGB_MCS = 0x000f, //!< SIG-B MCS (from SIG-A)
HE_MU_FLAGS1_SIGB_MCS_KNOWN = 0x0010, //!< SIG-B MCS known
@@ -394,7 +430,7 @@ class RadiotapHeader : public Header
/**
* @brief HE MU flags2.
*/
enum HeMuFlags2
enum HeMuFlags2 : uint16_t
{
HE_MU_FLAGS2_BW_FROM_SIGA = 0x0003, /**< Bandwidth from Bandwidth field in HE-SIG-A */
HE_MU_FLAGS2_BW_FROM_SIGA_KNOWN =
@@ -410,22 +446,27 @@ class RadiotapHeader : public Header
};
/**
* @brief Set the HE MU fields
*
* @param flags1 The flags1 field.
* @param flags2 The flags2 field.
* @param ruChannel1 The RU_channel1 field.
* @param ruChannel2 The RU_channel2 field.
* structure that contains the subfields of the HE-MU field.
*/
void SetHeMuFields(uint16_t flags1,
uint16_t flags2,
const std::array<uint8_t, 4>& ruChannel1,
const std::array<uint8_t, 4>& ruChannel2);
struct HeMuFields
{
uint16_t flags1{0}; //!< flags1 field
uint16_t flags2{0}; //!< flags2 field
std::array<uint8_t, 4> ruChannel1{}; //!< RU_channel1 field
std::array<uint8_t, 4> ruChannel2{}; //!< RU_channel2 field
};
/**
* @brief Set the subfields of the HE-MU field
*
* @param heMuFields The subfields of the HE-MU field.
*/
void SetHeMuFields(const HeMuFields& heMuFields);
/**
* @brief HE MU per_user_known.
*/
enum HeMuPerUserKnown
enum HeMuPerUserKnown : uint8_t
{
HE_MU_PER_USER_POSITION_KNOWN = 0x01, //!< User field position known
HE_MU_PER_USER_STA_ID_KNOWN = 0x02, //!< STA-ID known
@@ -438,23 +479,196 @@ class RadiotapHeader : public Header
};
/**
* @brief Set the HE MU per user fields
*
* @param perUser1 The per_user_1 field.
* @param perUser2 The per_user_2 field.
* @param perUserPosition The per_user_position field.
* @param perUserKnown The per_user_known field.
* structure that contains the subfields of the HE-MU-other-user field.
*/
void SetHeMuPerUserFields(uint16_t perUser1,
uint16_t perUser2,
uint8_t perUserPosition,
uint8_t perUserKnown);
struct HeMuOtherUserFields
{
uint16_t perUser1{0}; //!< per_user_1 field
uint16_t perUser2{0}; //!< per_user_2 field
uint8_t perUserPosition{0}; //!< per_user_position field
uint8_t perUserKnown{0}; //!< per_user_known field
};
/**
* @brief Set the subfields of the HE-MU-other-user field
*
* @param heMuOtherUserFields The subfields of the HE-MU-other-user field.
*/
void SetHeMuOtherUserFields(const HeMuOtherUserFields& heMuOtherUserFields);
private:
/**
* Serialize the Channel radiotap header.
*
* @param start An iterator which points to where the header should be written.
*/
void SerializeChannel(Buffer::Iterator& start) const;
/**
* Deserialize the Channel radiotap header.
*
* @param start An iterator which points to where the header should be read.
* @param bytesRead the number of bytes already read.
* @returns The number of bytes read.
*/
uint32_t DeserializeChannel(Buffer::Iterator start, uint32_t bytesRead);
/**
* Add Channel subfield/value pairs to the output stream.
*
* @param os The output stream
*/
void PrintChannel(std::ostream& os) const;
/**
* Serialize the MCS radiotap header.
*
* @param start An iterator which points to where the header should be written.
*/
void SerializeMcs(Buffer::Iterator& start) const;
/**
* Deserialize the MCS radiotap header.
*
* @param start An iterator which points to where the header should be read.
* @param bytesRead the number of bytes already read.
* @returns The number of bytes read.
*/
uint32_t DeserializeMcs(Buffer::Iterator start, uint32_t bytesRead);
/**
* Add MCS subfield/value pairs to the output stream.
*
* @param os The output stream
*/
void PrintMcs(std::ostream& os) const;
/**
* Serialize the A-MPDU Status radiotap header.
*
* @param start An iterator which points to where the header should be written.
*/
void SerializeAmpduStatus(Buffer::Iterator& start) const;
/**
* Deserialize the A-MPDU Status radiotap header.
*
* @param start An iterator which points to where the header should be read.
* @param bytesRead the number of bytes already read.
* @returns The number of bytes read.
*/
uint32_t DeserializeAmpduStatus(Buffer::Iterator start, uint32_t bytesRead);
/**
* Add A-MPDU Status subfield/value pairs to the output stream.
*
* @param os The output stream
*/
void PrintAmpduStatus(std::ostream& os) const;
/**
* Serialize the VHT radiotap header.
*
* @param start An iterator which points to where the header should be written.
*/
void SerializeVht(Buffer::Iterator& start) const;
/**
* Deserialize the VHT radiotap header.
*
* @param start An iterator which points to where the header should be read.
* @param bytesRead the number of bytes already read.
* @returns The number of bytes read.
*/
uint32_t DeserializeVht(Buffer::Iterator start, uint32_t bytesRead);
/**
* Add VHT subfield/value pairs to the output stream.
*
* @param os The output stream
*/
void PrintVht(std::ostream& os) const;
/**
* Serialize the HE radiotap header.
*
* @param start An iterator which points to where the header should be written.
*/
void SerializeHe(Buffer::Iterator& start) const;
/**
* Deserialize the HE radiotap header.
*
* @param start An iterator which points to where the header should be read.
* @param bytesRead the number of bytes already read.
* @returns The number of bytes read.
*/
uint32_t DeserializeHe(Buffer::Iterator start, uint32_t bytesRead);
/**
* Add HE subfield/value pairs to the output stream.
*
* @param os The output stream
*/
void PrintHe(std::ostream& os) const;
/**
* Serialize the HE-MU radiotap header.
*
* @param start An iterator which points to where the header should be written.
*/
void SerializeHeMu(Buffer::Iterator& start) const;
/**
* Deserialize the HE-MU radiotap header.
*
* @param start An iterator which points to where the header should be read.
* @param bytesRead the number of bytes already read.
* @returns The number of bytes read.
*/
uint32_t DeserializeHeMu(Buffer::Iterator start, uint32_t bytesRead);
/**
* Add HE-MU subfield/value pairs to the output stream.
*
* @param os The output stream
*/
void PrintHeMu(std::ostream& os) const;
/**
* Serialize the HE-MU-other-user radiotap header.
*
* @param start An iterator which points to where the header should be written.
*/
void SerializeHeMuOtherUser(Buffer::Iterator& start) const;
/**
* Deserialize the HE-MU-other-user radiotap header.
*
* @param start An iterator which points to where the header should be read.
* @param bytesRead the number of bytes already read.
* @returns The number of bytes read.
*/
uint32_t DeserializeHeMuOtherUser(Buffer::Iterator start, uint32_t bytesRead);
/**
* Add HE-MU-other-user subfield/value pairs to the output stream.
*
* @param os The output stream
*/
void PrintHeMuOtherUser(std::ostream& os) const;
/**
* @brief Radiotap flags.
*/
enum RadiotapFlags
enum RadiotapFlags : uint32_t
{
RADIOTAP_TSFT = 0x00000001,
RADIOTAP_FLAGS = 0x00000002,
@@ -482,56 +696,40 @@ class RadiotapHeader : public Header
RADIOTAP_EXT = 0x80000000
};
uint16_t m_length; //!< entire length of radiotap data + header
uint32_t m_present; //!< bits describing which fields follow header
uint16_t m_length{8}; //!< entire length of radiotap data + header
uint32_t m_present{0}; //!< bits describing which fields follow header
uint64_t m_tsft; //!< Time Synchronization Function Timer (when the first bit of the MPDU
//!< arrived at the MAC)
uint8_t m_flags; //!< Properties of transmitted and received frames.
uint8_t m_rate; //!< TX/RX data rate in units of 500 kbps
uint8_t m_channelPad; //!< Tx/Rx channel padding.
uint16_t m_channelFreq; //!< Tx/Rx frequency in MHz.
uint16_t m_channelFlags; //!< Tx/Rx channel flags.
int8_t m_antennaSignal; //!< RF signal power at the antenna, dB difference from an arbitrary,
//!< fixed reference.
int8_t m_antennaNoise; //!< RF noise power at the antenna, dB difference from an arbitrary,
//!< fixed reference.
uint64_t m_tsft{0}; //!< Time Synchronization Function Timer (when the first bit of the MPDU
//!< arrived at the MAC)
uint8_t m_mcsKnown; //!< MCS Flags, known information field.
uint8_t m_mcsFlags; //!< MCS Flags, flags field.
uint8_t m_mcsRate; //!< MCS Flags, mcs rate index.
uint8_t m_flags{FRAME_FLAG_NONE}; //!< Properties of transmitted and received frames.
uint8_t m_ampduStatusPad; //!< A-MPDU Status Flags, padding before A-MPDU Status Field.
uint32_t m_ampduStatusRef; //!< A-MPDU Status Flags, reference number.
uint16_t m_ampduStatusFlags; //!< A-MPDU Status Flags, information about the received A-MPDU.
uint8_t m_ampduStatusCRC; //!< A-MPDU Status Flags, delimiter CRC value.
uint8_t m_rate{0}; //!< TX/RX data rate in units of 500 kbps
uint8_t m_vhtPad; //!< VHT padding.
uint16_t m_vhtKnown; //!< VHT known field.
uint8_t m_vhtFlags; //!< VHT flags field.
uint8_t m_vhtBandwidth; //!< VHT bandwidth field.
uint8_t m_vhtMcsNss[4]; //!< VHT mcs_nss field.
uint8_t m_vhtCoding; //!< VHT coding field.
uint8_t m_vhtGroupId; //!< VHT group_id field.
uint16_t m_vhtPartialAid; //!< VHT partial_aid field.
uint8_t m_channelPad{0}; //!< Channel padding.
ChannelFields m_channelFields{}; //!< Channel fields.
uint8_t m_hePad; //!< HE padding.
uint16_t m_heData1; //!< HE data1 field.
uint16_t m_heData2; //!< HE data2 field.
uint16_t m_heData3; //!< HE data3 field.
uint16_t m_heData4; //!< HE data4 field.
uint16_t m_heData5; //!< HE data5 field.
uint16_t m_heData6; //!< HE data6 field.
int8_t m_antennaSignal{
0}; //!< RF signal power at the antenna, dB difference from an arbitrary, fixed reference.
int8_t m_antennaNoise{
0}; //!< RF noise power at the antenna, dB difference from an arbitrary, fixed reference.
uint8_t m_heMuPad; //!< HE MU padding.
uint16_t m_heMuFlags1; //!< HE MU flags1 field.
uint16_t m_heMuFlags2; //!< HE MU flags2 field.
McsFields m_mcsFields{}; //!< MCS fields.
uint8_t m_heMuOtherUserPad; //!< HE MU other user padding.
uint16_t m_heMuPerUser1; //!< HE MU per_user_1 field.
uint16_t m_heMuPerUser2; //!< HE MU per_user_2 field.
uint8_t m_heMuPerUserPosition; //!< HE MU per_user_position field.
uint8_t m_heMuPerUserKnown; //!< HE MU per_user_known field.
uint8_t m_ampduStatusPad{0}; //!< A-MPDU Status Flags, padding before A-MPDU Status Field.
AmpduStatusFields m_ampduStatusFields{}; //!< A-MPDU Status fields.
uint8_t m_vhtPad{0}; //!< VHT padding.
VhtFields m_vhtFields{}; //!< VHT fields.
uint8_t m_hePad{0}; //!< HE padding.
HeFields m_heFields{}; //!< HE fields.
uint8_t m_heMuPad{0}; //!< HE MU padding.
HeMuFields m_heMuFields{}; //!< HE MU fields.
uint8_t m_heMuOtherUserPad{0}; //!< HE MU other user padding.
HeMuOtherUserFields m_heMuOtherUserFields{}; //!< HE MU other user fields.
};
} // namespace ns3

View File

@@ -30,8 +30,26 @@
#include "ns3/wifi-mac-queue.h"
#include "ns3/wifi-mac-trailer.h"
#include <bit>
#include <memory>
namespace
{
/**
* Helper function to place the value to set in the correct bit(s) of a radiotap subfield.
*
* \param mask the mask of the corresponding subfield
* \param val the value the subfield should be set to
* \return the value placed at the correct position based on the mask
*/
uint32_t
GetRadiotapField(uint32_t mask, uint32_t val)
{
const auto shift = std::countr_zero(mask);
return (val << shift) & mask;
}
} // namespace
namespace ns3
{
@@ -298,7 +316,7 @@ void
WifiPhyHelper::GetRadiotapHeader(RadiotapHeader& header,
Ptr<Packet> packet,
uint16_t channelFreqMhz,
WifiTxVector txVector,
const WifiTxVector& txVector,
MpduInfo aMpdu,
uint16_t staId,
SignalNoiseDbm signalNoise)
@@ -312,111 +330,108 @@ void
WifiPhyHelper::GetRadiotapHeader(RadiotapHeader& header,
Ptr<Packet> packet,
uint16_t channelFreqMhz,
WifiTxVector txVector,
const WifiTxVector& txVector,
MpduInfo aMpdu,
uint16_t staId)
{
WifiPreamble preamble = txVector.GetPreambleType();
const auto preamble = txVector.GetPreambleType();
const auto modClass = txVector.GetModulationClass();
const auto channelWidth = txVector.GetChannelWidth();
const auto gi = txVector.GetGuardInterval();
uint8_t frameFlags = RadiotapHeader::FRAME_FLAG_NONE;
header.SetTsft(Simulator::Now().GetMicroSeconds());
uint8_t frameFlags = RadiotapHeader::FRAME_FLAG_NONE;
// Our capture includes the FCS, so we set the flag to say so.
frameFlags |= RadiotapHeader::FRAME_FLAG_FCS_INCLUDED;
if (preamble == WIFI_PREAMBLE_SHORT)
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_PREAMBLE;
}
if (txVector.GetGuardInterval().GetNanoSeconds() == 400)
if (gi.GetNanoSeconds() == 400)
{
frameFlags |= RadiotapHeader::FRAME_FLAG_SHORT_GUARD;
}
header.SetFrameFlags(frameFlags);
uint8_t mcs = 0;
uint8_t nss = 1;
uint64_t rate = 0;
if (txVector.GetModulationClass() < WIFI_MOD_CLASS_HT)
if (modClass < WIFI_MOD_CLASS_HT)
{
rate = txVector.GetMode(staId).GetDataRate(txVector.GetChannelWidth(),
txVector.GetGuardInterval(),
1) *
txVector.GetNss(staId) / 500000;
rate = txVector.GetMode(staId).GetDataRate(channelWidth, gi, 1) * nss / 500000;
header.SetRate(static_cast<uint8_t>(rate));
}
else
{
mcs = txVector.GetMode(staId).GetMcsValue();
nss = txVector.GetNss(staId);
}
uint16_t channelFlags = 0;
RadiotapHeader::ChannelFields channelFields{.frequency = channelFreqMhz};
switch (rate)
{
case 2: // 1Mbps
case 4: // 2Mbps
case 10: // 5Mbps
case 22: // 11Mbps
channelFlags |= RadiotapHeader::CHANNEL_FLAG_CCK;
channelFields.flags |= RadiotapHeader::CHANNEL_FLAG_CCK;
break;
default:
channelFlags |= RadiotapHeader::CHANNEL_FLAG_OFDM;
channelFields.flags |= RadiotapHeader::CHANNEL_FLAG_OFDM;
break;
}
if (channelFreqMhz < 2500)
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_2GHZ;
channelFields.flags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_2GHZ;
}
else
{
channelFlags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_5GHZ;
channelFields.flags |= RadiotapHeader::CHANNEL_FLAG_SPECTRUM_5GHZ;
}
header.SetChannelFields(channelFields);
header.SetChannelFrequencyAndFlags(channelFreqMhz, channelFlags);
if (txVector.GetMode(staId).GetModulationClass() == WIFI_MOD_CLASS_HT)
if (modClass == WIFI_MOD_CLASS_HT)
{
uint8_t mcsKnown = RadiotapHeader::MCS_KNOWN_NONE;
uint8_t mcsFlags = RadiotapHeader::MCS_FLAGS_NONE;
RadiotapHeader::McsFields mcsFields{.mcs = mcs};
mcsKnown |= RadiotapHeader::MCS_KNOWN_INDEX;
mcsFields.known |= RadiotapHeader::MCS_KNOWN_INDEX | RadiotapHeader::MCS_KNOWN_BANDWIDTH |
RadiotapHeader::MCS_KNOWN_GUARD_INTERVAL |
RadiotapHeader::MCS_KNOWN_HT_FORMAT | RadiotapHeader::MCS_KNOWN_NESS |
RadiotapHeader::MCS_KNOWN_FEC_TYPE | RadiotapHeader::MCS_KNOWN_STBC;
mcsKnown |= RadiotapHeader::MCS_KNOWN_BANDWIDTH;
if (txVector.GetChannelWidth() == 40)
if (channelWidth == 40)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_BANDWIDTH_40;
mcsFields.flags |= RadiotapHeader::MCS_FLAGS_BANDWIDTH_40;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_GUARD_INTERVAL;
if (txVector.GetGuardInterval().GetNanoSeconds() == 400)
if (gi.GetNanoSeconds() == 400)
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_GUARD_INTERVAL;
mcsFields.flags |= RadiotapHeader::MCS_FLAGS_GUARD_INTERVAL;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_HT_FORMAT;
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS;
if (txVector.GetNess() & 0x01) // bit 1
const auto ness = txVector.GetNess();
if (ness & 0x01) // bit 1
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_NESS_BIT_0;
mcsFields.flags |= RadiotapHeader::MCS_FLAGS_NESS_BIT_0;
}
if (txVector.GetNess() & 0x02) // bit 2
if (ness & 0x02) // bit 2
{
mcsKnown |= RadiotapHeader::MCS_KNOWN_NESS_BIT_1;
mcsFields.flags |= RadiotapHeader::MCS_KNOWN_NESS_BIT_1;
}
mcsKnown |= RadiotapHeader::MCS_KNOWN_FEC_TYPE; // only BCC is currently supported
mcsKnown |= RadiotapHeader::MCS_KNOWN_STBC;
if (txVector.IsStbc())
{
mcsFlags |= RadiotapHeader::MCS_FLAGS_STBC_STREAMS;
mcsFields.flags |= RadiotapHeader::MCS_FLAGS_STBC_STREAMS;
}
header.SetMcsFields(mcsKnown, mcsFlags, txVector.GetMode(staId).GetMcsValue());
header.SetMcsFields(mcsFields);
}
if (txVector.IsAggregation())
{
uint16_t ampduStatusFlags = RadiotapHeader::A_MPDU_STATUS_NONE;
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST_KNOWN;
RadiotapHeader::AmpduStatusFields ampduStatusFields{.referenceNumber = aMpdu.mpduRefNumber};
ampduStatusFields.flags |= RadiotapHeader::A_MPDU_STATUS_LAST_KNOWN;
/* For PCAP file, MPDU Delimiter and Padding should be removed by the MAC Driver */
AmpduSubframeHeader hdr;
uint32_t extractedLength;
@@ -425,163 +440,152 @@ WifiPhyHelper::GetRadiotapHeader(RadiotapHeader& header,
packet = packet->CreateFragment(0, static_cast<uint32_t>(extractedLength));
if (aMpdu.type == LAST_MPDU_IN_AGGREGATE || (hdr.GetEof() && hdr.GetLength() > 0))
{
ampduStatusFlags |= RadiotapHeader::A_MPDU_STATUS_LAST;
ampduStatusFields.flags |= RadiotapHeader::A_MPDU_STATUS_LAST;
}
header.SetAmpduStatus(aMpdu.mpduRefNumber, ampduStatusFlags, 1 /*CRC*/);
header.SetAmpduStatus(ampduStatusFields);
}
if (txVector.GetMode(staId).GetModulationClass() == WIFI_MOD_CLASS_VHT)
if (modClass == WIFI_MOD_CLASS_VHT)
{
uint16_t vhtKnown = RadiotapHeader::VHT_KNOWN_NONE;
uint8_t vhtFlags = RadiotapHeader::VHT_FLAGS_NONE;
uint8_t vhtBandwidth = 0;
uint8_t vhtMcsNss[4] = {0, 0, 0, 0};
uint8_t vhtCoding = 0;
uint8_t vhtGroupId = 0;
uint16_t vhtPartialAid = 0;
RadiotapHeader::VhtFields vhtFields{};
vhtKnown |= RadiotapHeader::VHT_KNOWN_STBC;
vhtFields.known |= RadiotapHeader::VHT_KNOWN_STBC;
if (txVector.IsStbc())
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_STBC;
vhtFields.flags |= RadiotapHeader::VHT_FLAGS_STBC;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_GUARD_INTERVAL;
if (txVector.GetGuardInterval().GetNanoSeconds() == 400)
vhtFields.known |= RadiotapHeader::VHT_KNOWN_GUARD_INTERVAL;
if (gi.GetNanoSeconds() == 400)
{
vhtFlags |= RadiotapHeader::VHT_FLAGS_GUARD_INTERVAL;
vhtFields.flags |= RadiotapHeader::VHT_FLAGS_GUARD_INTERVAL;
}
vhtKnown |= RadiotapHeader::VHT_KNOWN_BEAMFORMED; // Beamforming is currently not supported
vhtKnown |= RadiotapHeader::VHT_KNOWN_BANDWIDTH;
// not all bandwidth values are currently supported
if (txVector.GetChannelWidth() == 40)
vhtFields.known |=
RadiotapHeader::VHT_KNOWN_BEAMFORMED | RadiotapHeader::VHT_KNOWN_BANDWIDTH;
// TODO: bandwidths can be provided with sideband info
if (channelWidth == 40)
{
vhtBandwidth = 1;
vhtFields.bandwidth = 1;
}
else if (txVector.GetChannelWidth() == 80)
else if (channelWidth == 80)
{
vhtBandwidth = 4;
vhtFields.bandwidth = 4;
}
else if (txVector.GetChannelWidth() == 160)
else if (channelWidth == 160)
{
vhtBandwidth = 11;
vhtFields.bandwidth = 11;
}
// only SU PPDUs are currently supported
vhtMcsNss[0] |= (txVector.GetNss(staId) & 0x0f);
vhtMcsNss[0] |= ((txVector.GetMode(staId).GetMcsValue() << 4) & 0xf0);
vhtFields.mcsNss.at(0) |= (nss & 0x0f) | ((mcs << 4) & 0xf0);
header.SetVhtFields(vhtKnown,
vhtFlags,
vhtBandwidth,
vhtMcsNss,
vhtCoding,
vhtGroupId,
vhtPartialAid);
header.SetVhtFields(vhtFields);
}
if (txVector.GetMode(staId).GetModulationClass() == WIFI_MOD_CLASS_HE)
if (modClass == WIFI_MOD_CLASS_HE)
{
uint16_t data1 = RadiotapHeader::HE_DATA1_BSS_COLOR_KNOWN |
RadiotapHeader::HeFields heFields{};
heFields.data1 = RadiotapHeader::HE_DATA1_BSS_COLOR_KNOWN |
RadiotapHeader::HE_DATA1_DATA_MCS_KNOWN |
RadiotapHeader::HE_DATA1_BW_RU_ALLOC_KNOWN;
if (preamble == WIFI_PREAMBLE_HE_ER_SU)
{
data1 |= RadiotapHeader::HE_DATA1_FORMAT_EXT_SU;
heFields.data1 |= RadiotapHeader::HE_DATA1_FORMAT_EXT_SU;
}
else if (preamble == WIFI_PREAMBLE_HE_MU)
{
data1 |= RadiotapHeader::HE_DATA1_FORMAT_MU;
data1 |= RadiotapHeader::HE_DATA1_SPTL_REUSE2_KNOWN;
heFields.data1 |=
RadiotapHeader::HE_DATA1_FORMAT_MU | RadiotapHeader::HE_DATA1_SPTL_REUSE2_KNOWN;
}
else if (preamble == WIFI_PREAMBLE_HE_TB)
{
data1 |= RadiotapHeader::HE_DATA1_FORMAT_TRIG;
heFields.data1 |= RadiotapHeader::HE_DATA1_FORMAT_TRIG;
}
uint16_t data2 = RadiotapHeader::HE_DATA2_GI_KNOWN;
heFields.data2 = RadiotapHeader::HE_DATA2_GI_KNOWN;
if (preamble == WIFI_PREAMBLE_HE_MU || preamble == WIFI_PREAMBLE_HE_TB)
{
data2 |= RadiotapHeader::HE_DATA2_RU_OFFSET_KNOWN;
// HeRu indices start at 1 whereas RadioTap starts at 0
data2 |= (((txVector.GetHeMuUserInfo(staId).ru.GetIndex() - 1) << 8) & 0x3f00);
data2 |= (((!txVector.GetHeMuUserInfo(staId).ru.GetPrimary80MHz()) << 15) & 0x8000);
heFields.data2 |=
RadiotapHeader::HE_DATA2_RU_OFFSET_KNOWN |
// HeRu indices start at 1 whereas RadioTap starts at 0
GetRadiotapField(RadiotapHeader::HE_DATA2_RU_OFFSET,
txVector.GetHeMuUserInfo(staId).ru.GetIndex() - 1) |
GetRadiotapField(RadiotapHeader::HE_DATA2_PRISEC_80_SEC,
!txVector.GetHeMuUserInfo(staId).ru.GetPrimary80MHz());
}
uint16_t data3 = 0;
data3 |= (txVector.GetBssColor() & 0x003f);
data3 |= ((txVector.GetMode(staId).GetMcsValue() << 8) & 0x0f00);
heFields.data3 =
GetRadiotapField(RadiotapHeader::HE_DATA3_BSS_COLOR, txVector.GetBssColor()) |
GetRadiotapField(RadiotapHeader::HE_DATA3_DATA_MCS, mcs);
uint16_t data4 = 0;
if (preamble == WIFI_PREAMBLE_HE_MU)
{
data4 |= ((staId << 4) & 0x7ff0);
}
heFields.data4 = (preamble == WIFI_PREAMBLE_HE_MU)
? GetRadiotapField(RadiotapHeader::HE_DATA4_MU_STA_ID, staId)
: 0;
uint16_t data5 = 0;
heFields.data5 = 0;
if (preamble == WIFI_PREAMBLE_HE_MU || preamble == WIFI_PREAMBLE_HE_TB)
{
HeRu::RuType ruType = txVector.GetHeMuUserInfo(staId).ru.GetRuType();
switch (ruType)
{
case HeRu::RU_26_TONE:
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_26T;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_26T;
break;
case HeRu::RU_52_TONE:
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_52T;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_52T;
break;
case HeRu::RU_106_TONE:
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_106T;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_106T;
break;
case HeRu::RU_242_TONE:
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_242T;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_242T;
break;
case HeRu::RU_484_TONE:
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_484T;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_484T;
break;
case HeRu::RU_996_TONE:
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_996T;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_996T;
break;
case HeRu::RU_2x996_TONE:
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_2x996T;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_2x996T;
break;
default:
NS_ABORT_MSG("Unexpected RU type");
}
}
else if (txVector.GetChannelWidth() == 40)
else if (channelWidth == 40)
{
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_40MHZ;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_40MHZ;
}
else if (txVector.GetChannelWidth() == 80)
else if (channelWidth == 80)
{
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_80MHZ;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_80MHZ;
}
else if (txVector.GetChannelWidth() == 160)
else if (channelWidth == 160)
{
data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_160MHZ;
heFields.data5 |= RadiotapHeader::HE_DATA5_DATA_BW_RU_ALLOC_160MHZ;
}
if (txVector.GetGuardInterval().GetNanoSeconds() == 1600)
if (gi.GetNanoSeconds() == 1600)
{
data5 |= RadiotapHeader::HE_DATA5_GI_1_6;
heFields.data5 |= RadiotapHeader::HE_DATA5_GI_1_6;
}
else if (txVector.GetGuardInterval().GetNanoSeconds() == 3200)
else if (gi.GetNanoSeconds() == 3200)
{
data5 |= RadiotapHeader::HE_DATA5_GI_3_2;
heFields.data5 |= RadiotapHeader::HE_DATA5_GI_3_2;
}
header.SetHeFields(data1, data2, data3, data4, data5, 0);
header.SetHeFields(heFields);
}
if (preamble == WIFI_PREAMBLE_HE_MU)
{
// TODO: fill in fields (everything is set to 0 so far)
std::array<uint8_t, 4> ruChannel1;
std::array<uint8_t, 4> ruChannel2;
header.SetHeMuFields(0, 0, ruChannel1, ruChannel2);
header.SetHeMuPerUserFields(0, 0, 0, 0);
RadiotapHeader::HeMuFields heMuFields{};
// TODO: fill in fields
header.SetHeMuFields(heMuFields);
RadiotapHeader::HeMuOtherUserFields heMuOtherUserFields{};
// TODO: fill in fields
header.SetHeMuOtherUserFields(heMuOtherUserFields);
}
}

View File

@@ -322,7 +322,7 @@ class WifiPhyHelper : public PcapHelperForDevice, public AsciiTraceHelperForDevi
static void GetRadiotapHeader(RadiotapHeader& header,
Ptr<Packet> packet,
uint16_t channelFreqMhz,
WifiTxVector txVector,
const WifiTxVector& txVector,
MpduInfo aMpdu,
uint16_t staId);
@@ -340,7 +340,7 @@ class WifiPhyHelper : public PcapHelperForDevice, public AsciiTraceHelperForDevi
static void GetRadiotapHeader(RadiotapHeader& header,
Ptr<Packet> packet,
uint16_t channelFreqMhz,
WifiTxVector txVector,
const WifiTxVector& txVector,
MpduInfo aMpdu,
uint16_t staId,
SignalNoiseDbm signalNoise);

View File

@@ -1,6 +1,9 @@
#LaTeX
te
#C++
countr
#Core
bu
mone