wifi, network: Various improvements for radiotap headers
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#LaTeX
|
||||
te
|
||||
|
||||
#C++
|
||||
countr
|
||||
|
||||
#Core
|
||||
bu
|
||||
mone
|
||||
|
||||
Reference in New Issue
Block a user