A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
radiotap-header.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2009 CTTC
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Nicola Baldo <nbaldo@cttc.es>
7 * Sébastien Deronne <sebastien.deronne@gmail.com>
8 */
9
10#include "radiotap-header.h"
11
12#include "ns3/log.h"
13
14#include <bit>
15#include <cmath>
16#include <iomanip>
17
18namespace ns3
19{
20
21NS_LOG_COMPONENT_DEFINE("RadiotapHeader");
22
23NS_OBJECT_ENSURE_REGISTERED(RadiotapHeader);
24
29
32{
33 static TypeId tid = TypeId("ns3::RadiotapHeader")
35 .SetGroupName("Network")
36
37 .AddConstructor<RadiotapHeader>();
38 return tid;
39}
40
43{
44 return GetTypeId();
45}
46
49{
50 NS_LOG_FUNCTION(this);
51 return m_length;
52}
53
54void
56{
57 NS_LOG_FUNCTION(this << &start);
58
59 start.WriteU8(0); // major version of radiotap header
60 start.WriteU8(0); // pad field
61 start.WriteU16(m_length); // entire length of radiotap data + header
62 start.WriteU32(m_present); // bits describing which fields follow header
63 if (m_presentExt)
64 {
65 start.WriteU32(*m_presentExt); // extended bitmasks
66 }
67
68 //
69 // Time Synchronization Function Timer (when the first bit of the MPDU
70 // arrived at the MAC)
71 // Reference: https://www.radiotap.org/fields/TSFT.html
72 //
73 if (m_present & RADIOTAP_TSFT) // bit 0
74 {
75 start.WriteU64(m_tsft);
76 }
77
78 //
79 // Properties of transmitted and received frames.
80 // Reference: https://www.radiotap.org/fields/Flags.html
81 //
82 if (m_present & RADIOTAP_FLAGS) // bit 1
83 {
84 start.WriteU8(m_flags);
85 }
86
87 //
88 // TX/RX data rate in units of 500 kbps
89 // Reference: https://www.radiotap.org/fields/Rate.html
90 //
91 if (m_present & RADIOTAP_RATE) // bit 2
92 {
93 start.WriteU8(m_rate);
94 }
95
96 //
97 // Tx/Rx frequency in MHz, followed by flags.
98 // Reference: https://www.radiotap.org/fields/Channel.html
99 //
100 if (m_present & RADIOTAP_CHANNEL) // bit 3
101 {
102 SerializeChannel(start);
103 }
104
105 //
106 // The hop set and pattern for frequency-hopping radios. We don't need it but
107 // still need to account for it.
108 // Reference: https://www.radiotap.org/fields/FHSS.html
109 //
110 if (m_present & RADIOTAP_FHSS) // bit 4
111 {
112 start.WriteU8(0); // not yet implemented
113 }
114
115 //
116 // RF signal power at the antenna, decibel difference from an arbitrary, fixed
117 // reference.
118 // Reference: https://www.radiotap.org/fields/Antenna%20signal.html
119 //
120 if (m_present & RADIOTAP_DBM_ANTSIGNAL) // bit 5
121 {
122 start.WriteU8(m_antennaSignal);
123 }
124
125 //
126 // RF noise power at the antenna, decibel difference from an arbitrary, fixed
127 // reference.
128 // Reference: https://www.radiotap.org/fields/Antenna%20noise.html
129 //
130 if (m_present & RADIOTAP_DBM_ANTNOISE) // bit 6
131 {
132 start.WriteU8(m_antennaNoise);
133 }
134
135 //
136 // Quality of Barker code lock.
137 // Reference: https://www.radiotap.org/fields/Lock%20quality.html
138 //
139 if (m_present & RADIOTAP_LOCK_QUALITY) // bit 7
140 {
141 start.WriteU16(0); // not yet implemented
142 }
143
144 //
145 // Transmit power expressed as unitless distance from max power
146 // set at factory calibration (0 is max power).
147 // Reference: https://www.radiotap.org/fields/TX%20attenuation.html
148 //
149 if (m_present & RADIOTAP_TX_ATTENUATION) // bit 8
150 {
151 start.WriteU16(0); // not yet implemented
152 }
153
154 //
155 // Transmit power expressed as decibel distance from max power
156 // set at factory calibration (0 is max power).
157 // Reference: https://www.radiotap.org/fields/dB%20TX%20attenuation.html
158 //
160 {
161 start.WriteU16(0); // not yet implemented
162 }
163
164 //
165 // Transmit power expressed as dBm (decibels from a 1 milliwatt reference).
166 // This is the absolute power level measured at the antenna port.
167 // Reference: https://www.radiotap.org/fields/dBm%20TX%20power.html
168 //
169 if (m_present & RADIOTAP_DBM_TX_POWER) // bit 10
170 {
171 start.WriteU8(0); // not yet implemented
172 }
173
174 //
175 // Unitless indication of the Rx/Tx antenna for this packet.
176 // The first antenna is antenna 0.
177 // Reference: https://www.radiotap.org/fields/Antenna.html
178 //
179 if (m_present & RADIOTAP_ANTENNA) // bit 11
180 {
181 start.WriteU8(0); // not yet implemented
182 }
183
184 //
185 // RF signal power at the antenna (decibel difference from an arbitrary fixed reference).
186 // Reference: https://www.radiotap.org/fields/dB%20antenna%20signal.html
187 //
188 if (m_present & RADIOTAP_DB_ANTSIGNAL) // bit 12
189 {
190 start.WriteU8(0); // not yet implemented
191 }
192
193 //
194 // RF noise power at the antenna (decibel difference from an arbitrary fixed reference).
195 // Reference: https://www.radiotap.org/fields/dB%20antenna%20noise.html
196 //
197 if (m_present & RADIOTAP_DB_ANTNOISE) // bit 13
198 {
199 start.WriteU8(0); // not yet implemented
200 }
201
202 //
203 // Properties of received frames.
204 // Reference: https://www.radiotap.org/fields/RX%20flags.html
205 //
206 if (m_present & RADIOTAP_RX_FLAGS) // bit 14
207 {
208 start.WriteU16(0); // not yet implemented
209 }
210
211 //
212 // MCS field.
213 // Reference: https://www.radiotap.org/fields/MCS.html
214 //
215 if (m_present & RADIOTAP_MCS) // bit 19
216 {
217 SerializeMcs(start);
218 }
219
220 //
221 // A-MPDU Status, information about the received or transmitted A-MPDU.
222 // Reference: https://www.radiotap.org/fields/A-MPDU%20status.html
223 //
224 if (m_present & RADIOTAP_AMPDU_STATUS) // bit 20
225 {
227 }
228
229 //
230 // Information about the received or transmitted VHT frame.
231 // Reference: https://www.radiotap.org/fields/VHT.html
232 //
233 if (m_present & RADIOTAP_VHT) // bit 21
234 {
235 SerializeVht(start);
236 }
237
238 //
239 // HE field.
240 // Reference: https://www.radiotap.org/fields/HE.html
241 //
242 if (m_present & RADIOTAP_HE) // bit 23
243 {
244 SerializeHe(start);
245 }
246
247 //
248 // HE MU field.
249 // Reference: https://www.radiotap.org/fields/HE-MU.html
250 //
251 if (m_present & RADIOTAP_HE_MU) // bit 24
252 {
253 SerializeHeMu(start);
254 }
255
256 //
257 // HE MU other user field.
258 // Reference: https://www.radiotap.org/fields/HE-MU-other-user.html
259 //
260 if (m_present & RADIOTAP_HE_MU_OTHER_USER) // bit 25
261 {
263 }
264
265 //
266 // U-SIG field.
267 // Reference: https://www.radiotap.org/fields/U-SIG.html
268 //
269 if (m_presentExt && (*m_presentExt & RADIOTAP_USIG)) // bit 33
270 {
271 SerializeUsig(start);
272 }
273
274 //
275 // EHT field.
276 // Reference: https://www.radiotap.org/fields/EHT.html
277 //
278 if (m_presentExt && (*m_presentExt & RADIOTAP_EHT_SIG)) // bit 34
279 {
280 SerializeEht(start);
281 }
282}
283
286{
287 NS_LOG_FUNCTION(this << &start);
288
289 uint8_t tmp = start.ReadU8(); // major version of radiotap header
290 NS_ASSERT_MSG(tmp == 0x00, "RadiotapHeader::Deserialize(): Unexpected major version");
291 start.ReadU8(); // pad field
292
293 m_length = start.ReadU16(); // entire length of radiotap data + header
294 m_present = start.ReadU32(); // bits describing which fields follow header
295 uint32_t bytesRead = 8;
296
298 {
299 // If bit 31 of the it_present field is set, an extended it_present bitmask is present.
300 m_presentExt = start.ReadU32();
301 bytesRead += 4;
302 }
303
304 //
305 // Time Synchronization Function Timer (when the first bit of the MPDU arrived at the MAC)
306 // Reference: https://www.radiotap.org/fields/TSFT.html
307 //
308 if (m_present & RADIOTAP_TSFT) // bit 0
309 {
310 m_tsft = start.ReadU64();
311 bytesRead += 8;
312 }
313
314 //
315 // Properties of transmitted and received frames.
316 // Reference: https://www.radiotap.org/fields/Flags.html
317 //
318 if (m_present & RADIOTAP_FLAGS) // bit 1
319 {
320 m_flags = start.ReadU8();
321 ++bytesRead;
322 }
323
324 //
325 // TX/RX data rate in units of 500 kbps
326 // Reference: https://www.radiotap.org/fields/Rate.html
327 //
328 if (m_present & RADIOTAP_RATE) // bit 2
329 {
330 m_rate = start.ReadU8();
331 ++bytesRead;
332 }
333
334 //
335 // Tx/Rx frequency in MHz, followed by flags.
336 // Reference: https://www.radiotap.org/fields/Channel.html
337 //
338 if (m_present & RADIOTAP_CHANNEL) // bit 3
339 {
340 bytesRead += DeserializeChannel(start, bytesRead);
341 }
342
343 //
344 // The hop set and pattern for frequency-hopping radios. We don't need it but
345 // still need to account for it.
346 // Reference: https://www.radiotap.org/fields/FHSS.html
347 //
348 if (m_present & RADIOTAP_FHSS) // bit 4
349 {
350 // not yet implemented
351 start.ReadU8();
352 ++bytesRead;
353 }
354
355 //
356 // RF signal power at the antenna, decibel difference from an arbitrary, fixed
357 // reference.
358 // Reference: https://www.radiotap.org/fields/Antenna%20signal.html
359 //
360 if (m_present & RADIOTAP_DBM_ANTSIGNAL) // bit 5
361 {
362 m_antennaSignal = start.ReadU8();
363 ++bytesRead;
364 }
365
366 //
367 // RF noise power at the antenna, decibel difference from an arbitrary, fixed
368 // reference.
369 // Reference: https://www.radiotap.org/fields/Antenna%20noise.html
370 //
371 if (m_present & RADIOTAP_DBM_ANTNOISE) // bit 6
372 {
373 m_antennaNoise = start.ReadU8();
374 ++bytesRead;
375 }
376
377 //
378 // Quality of Barker code lock.
379 // Reference: https://www.radiotap.org/fields/Lock%20quality.html
380 //
381 if (m_present & RADIOTAP_LOCK_QUALITY) // bit 7
382 {
383 // not yet implemented
384 start.ReadU16();
385 bytesRead += 2;
386 }
387
388 //
389 // Transmit power expressed as unitless distance from max power
390 // set at factory calibration (0 is max power).
391 // Reference: https://www.radiotap.org/fields/TX%20attenuation.html
392 //
393 if (m_present & RADIOTAP_TX_ATTENUATION) // bit 8
394 {
395 // not yet implemented
396 start.ReadU16();
397 bytesRead += 2;
398 }
399
400 //
401 // Transmit power expressed as decibel distance from max power
402 // set at factory calibration (0 is max power).
403 // Reference: https://www.radiotap.org/fields/dB%20TX%20attenuation.html
404 //
406 {
407 // not yet implemented
408 start.ReadU16();
409 bytesRead += 2;
410 }
411
412 //
413 // Transmit power expressed as dBm (decibels from a 1 milliwatt reference).
414 // This is the absolute power level measured at the antenna port.
415 // Reference: https://www.radiotap.org/fields/dBm%20TX%20power.html
416 //
417 if (m_present & RADIOTAP_DBM_TX_POWER) // bit 10
418 {
419 // not yet implemented
420 start.ReadU8();
421 ++bytesRead;
422 }
423
424 //
425 // Unitless indication of the Rx/Tx antenna for this packet.
426 // The first antenna is antenna 0.
427 // Reference: https://www.radiotap.org/fields/Antenna.html
428 //
429 if (m_present & RADIOTAP_ANTENNA) // bit 11
430 {
431 // not yet implemented
432 start.ReadU8();
433 ++bytesRead;
434 }
435
436 //
437 // RF signal power at the antenna (decibel difference from an arbitrary fixed reference).
438 // Reference: https://www.radiotap.org/fields/dB%20antenna%20signal.html
439 //
440 if (m_present & RADIOTAP_DB_ANTSIGNAL) // bit 12
441 {
442 // not yet implemented
443 start.ReadU8();
444 ++bytesRead;
445 }
446
447 //
448 // RF noise power at the antenna (decibel difference from an arbitrary fixed reference).
449 // Reference: https://www.radiotap.org/fields/dB%20antenna%20noise.html
450 //
451 if (m_present & RADIOTAP_DB_ANTNOISE) // bit 13
452 {
453 // not yet implemented
454 start.ReadU8();
455 ++bytesRead;
456 }
457
458 //
459 // Properties of received frames.
460 // Reference: https://www.radiotap.org/fields/RX%20flags.html
461 //
462 if (m_present & RADIOTAP_RX_FLAGS) // bit 14
463 {
464 // not yet implemented
465 start.ReadU16();
466 bytesRead += 2;
467 }
468
469 //
470 // MCS field.
471 // Reference: https://www.radiotap.org/fields/MCS.html
472 //
473 if (m_present & RADIOTAP_MCS) // bit 19
474 {
475 bytesRead += DeserializeMcs(start, bytesRead);
476 }
477
478 //
479 // A-MPDU Status, information about the received or transmitted A-MPDU.
480 // Reference: https://www.radiotap.org/fields/A-MPDU%20status.html
481 //
483 {
484 bytesRead += DeserializeAmpduStatus(start, bytesRead);
485 }
486
487 //
488 // Information about the received or transmitted VHT frame.
489 // Reference: https://www.radiotap.org/fields/VHT.html
490 //
491 if (m_present & RADIOTAP_VHT) // bit 21
492 {
493 bytesRead += DeserializeVht(start, bytesRead);
494 }
495
496 //
497 // HE field.
498 // Reference: https://www.radiotap.org/fields/HE.html
499 //
500 if (m_present & RADIOTAP_HE) // bit 23
501 {
502 bytesRead += DeserializeHe(start, bytesRead);
503 }
504
505 //
506 // HE MU field.
507 // Reference: https://www.radiotap.org/fields/HE-MU.html
508 //
509 if (m_present & RADIOTAP_HE_MU) // bit 24
510 {
511 bytesRead += DeserializeHeMu(start, bytesRead);
512 }
513
514 //
515 // HE MU other user field.
516 // Reference: https://www.radiotap.org/fields/HE-MU-other-user.html
517 //
518 if (m_present & RADIOTAP_HE_MU_OTHER_USER) // bit 25
519 {
520 bytesRead += DeserializeHeMuOtherUser(start, bytesRead);
521 }
522
523 //
524 // U-SIG field.
525 // Reference: https://www.radiotap.org/fields/U-SIG.html
526 //
527 if (m_presentExt && (*m_presentExt & RADIOTAP_USIG)) // bit 33
528 {
529 bytesRead += DeserializeUsig(start, bytesRead);
530 }
531
532 //
533 // EHT field.
534 // Reference: https://www.radiotap.org/fields/EHT.html
535 //
536 if (m_presentExt && (*m_presentExt & RADIOTAP_EHT_SIG)) // bit 34
537 {
538 bytesRead += DeserializeEht(start, bytesRead);
539 }
540
541 NS_ASSERT_MSG(m_length == bytesRead,
542 "RadiotapHeader::Deserialize(): expected and actual lengths inconsistent");
543 return bytesRead;
544}
545
546void
547RadiotapHeader::Print(std::ostream& os) const
548{
549 NS_LOG_FUNCTION(this << &os);
550 os << " tsft=" << m_tsft << " flags=" << std::hex << m_flags << std::dec << " rate=" << +m_rate;
552 {
553 PrintChannel(os);
554 }
555 os << std::dec << " signal=" << +m_antennaSignal << " noise=" << +m_antennaNoise;
557 {
558 PrintMcs(os);
559 }
561 {
563 }
565 {
566 PrintVht(os);
567 }
569 {
570 PrintHe(os);
571 }
573 {
574 PrintHeMu(os);
575 }
577 {
579 }
581 {
582 PrintUsig(os);
583 }
585 {
586 PrintEht(os);
587 }
588}
589
590void
592{
593 NS_LOG_FUNCTION(this << value);
594
595 NS_ASSERT_MSG(!(m_present & RADIOTAP_TSFT), "TSFT radiotap field already present");
597 m_length += 8;
598 m_tsft = value;
599
600 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
601 << std::dec);
602}
603
604void
606{
607 NS_LOG_FUNCTION(this << +flags);
608
609 NS_ASSERT_MSG(!(m_present & RADIOTAP_FLAGS), "Flags radiotap field already present");
611 m_length += 1;
612 m_flags = flags;
613
614 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
615 << std::dec);
616}
617
618void
620{
621 NS_LOG_FUNCTION(this << +rate);
622
623 NS_ASSERT_MSG(!(m_present & RADIOTAP_RATE), "Rate radiotap field already present");
625 m_length += 1;
626 m_rate = rate;
627
628 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
629 << std::dec);
630}
631
632void
634{
635 NS_LOG_FUNCTION(this << channelFields.frequency << channelFields.flags);
636
637 NS_ASSERT_MSG(!(m_present & RADIOTAP_CHANNEL), "Channel radiotap field already present");
638 m_channelPad = ((2 - m_length % 2) % 2);
640 m_length += (sizeof(ChannelFields) + m_channelPad);
641 m_channelFields = channelFields;
642
643 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
644 << std::dec);
645}
646
647void
649{
650 start.WriteU8(0, m_channelPad);
651 start.WriteU16(m_channelFields.frequency);
652 start.WriteU16(m_channelFields.flags);
653}
654
657{
658 m_channelPad = ((2 - bytesRead % 2) % 2);
659 start.Next(m_channelPad);
660 m_channelFields.frequency = start.ReadU16();
661 m_channelFields.flags = start.ReadU16();
662 return sizeof(ChannelFields) + m_channelPad;
663}
664
665void
666RadiotapHeader::PrintChannel(std::ostream& os) const
667{
668 os << " channel.frequency=" << m_channelFields.frequency << " channel.flags=0x" << std::hex
669 << m_channelFields.flags << std::dec;
670}
671
672void
674{
675 NS_LOG_FUNCTION(this << signal);
676
678 "Antenna signal radiotap field already present");
680 m_length += 1;
681
682 if (signal > 127)
683 {
684 m_antennaSignal = 127;
685 }
686 else if (signal < -128)
687 {
688 m_antennaSignal = -128;
689 }
690 else
691 {
692 m_antennaSignal = static_cast<int8_t>(floor(signal + 0.5));
693 }
694
695 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
696 << std::dec);
697}
698
699void
701{
702 NS_LOG_FUNCTION(this << noise);
703
705 "Antenna noise radiotap field already present");
707 m_length += 1;
708
709 if (noise > 127.0)
710 {
711 m_antennaNoise = 127;
712 }
713 else if (noise < -128.0)
714 {
715 m_antennaNoise = -128;
716 }
717 else
718 {
719 m_antennaNoise = static_cast<int8_t>(floor(noise + 0.5));
720 }
721
722 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
723 << std::dec);
724}
725
726void
728{
729 NS_LOG_FUNCTION(this << +mcsFields.known << +mcsFields.flags << +mcsFields.mcs);
730
731 NS_ASSERT_MSG(!(m_present & RADIOTAP_MCS), "MCS radiotap field already present");
733 m_length += sizeof(McsFields);
734 m_mcsFields = mcsFields;
735
736 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
737 << std::dec);
738}
739
740void
742{
743 start.WriteU8(m_mcsFields.known);
744 start.WriteU8(m_mcsFields.flags);
745 start.WriteU8(m_mcsFields.mcs);
746}
747
750{
751 m_mcsFields.known = start.ReadU8();
752 m_mcsFields.flags = start.ReadU8();
753 m_mcsFields.mcs = start.ReadU8();
754 return sizeof(McsFields);
755}
756
757void
758RadiotapHeader::PrintMcs(std::ostream& os) const
759{
760 os << " mcs.known=0x" << std::hex << +m_mcsFields.known << " mcs.flags0x=" << +m_mcsFields.flags
761 << " mcsRate=" << std::dec << +m_mcsFields.mcs;
762}
763
764void
766{
767 NS_LOG_FUNCTION(this << ampduStatusFields.referenceNumber << ampduStatusFields.flags);
768
770 "A-MPDU status radiotap field already present");
771 m_ampduStatusPad = ((4 - m_length % 4) % 4);
773 m_length += (sizeof(ampduStatusFields) + m_ampduStatusPad);
774 m_ampduStatusFields = ampduStatusFields;
775
776 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
777 << std::dec);
778}
779
780void
782{
783 start.WriteU8(0, m_ampduStatusPad);
784 start.WriteU32(m_ampduStatusFields.referenceNumber);
785 start.WriteU16(m_ampduStatusFields.flags);
786 start.WriteU8(m_ampduStatusFields.crc);
787 start.WriteU8(m_ampduStatusFields.reserved);
788}
789
792{
793 m_ampduStatusPad = ((4 - bytesRead % 4) % 4);
794 start.Next(m_ampduStatusPad);
795 m_ampduStatusFields.referenceNumber = start.ReadU32();
796 m_ampduStatusFields.flags = start.ReadU16();
797 m_ampduStatusFields.crc = start.ReadU8();
798 m_ampduStatusFields.reserved = start.ReadU8();
799 return sizeof(AmpduStatusFields) + m_ampduStatusPad;
800}
801
802void
803RadiotapHeader::PrintAmpduStatus(std::ostream& os) const
804{
805 os << " ampduStatus.flags=0x" << std::hex << m_ampduStatusFields.flags << std::dec;
806}
807
808void
810{
811 NS_LOG_FUNCTION(this << vhtFields.known << vhtFields.flags << +vhtFields.mcsNss.at(0)
812 << +vhtFields.mcsNss.at(1) << +vhtFields.mcsNss.at(2)
813 << +vhtFields.mcsNss.at(3) << +vhtFields.coding << +vhtFields.groupId
814 << +vhtFields.partialAid);
815
816 NS_ASSERT_MSG(!(m_present & RADIOTAP_VHT), "VHT radiotap field already present");
817 m_vhtPad = ((2 - m_length % 2) % 2);
819 m_length += (sizeof(VhtFields) + m_vhtPad);
820 m_vhtFields = vhtFields;
821
822 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
823 << std::dec);
824}
825
826void
828{
829 start.WriteU8(0, m_vhtPad);
830 start.WriteU16(m_vhtFields.known);
831 start.WriteU8(m_vhtFields.flags);
832 start.WriteU8(m_vhtFields.bandwidth);
833 for (const auto mcsNss : m_vhtFields.mcsNss)
834 {
835 start.WriteU8(mcsNss);
836 }
837 start.WriteU8(m_vhtFields.coding);
838 start.WriteU8(m_vhtFields.groupId);
839 start.WriteU16(m_vhtFields.partialAid);
840}
841
844{
845 m_vhtPad = ((2 - bytesRead % 2) % 2);
846 start.Next(m_vhtPad);
847 m_vhtFields.known = start.ReadU16();
848 m_vhtFields.flags = start.ReadU8();
849 m_vhtFields.bandwidth = start.ReadU8();
850 for (auto& mcsNss : m_vhtFields.mcsNss)
851 {
852 mcsNss = start.ReadU8();
853 }
854 m_vhtFields.coding = start.ReadU8();
855 m_vhtFields.groupId = start.ReadU8();
856 m_vhtFields.partialAid = start.ReadU16();
857 return sizeof(VhtFields) + m_vhtPad;
858}
859
860void
861RadiotapHeader::PrintVht(std::ostream& os) const
862{
863 os << " vht.known=0x" << m_vhtFields.known << " vht.flags=0x" << m_vhtFields.flags
864 << " vht.bandwidth=" << std::dec << m_vhtFields.bandwidth
865 << " vht.mcsNss[0]=" << +m_vhtFields.mcsNss.at(0)
866 << " vht.mcsNss[1]=" << +m_vhtFields.mcsNss.at(1)
867 << " vht.mcsNss[2]=" << +m_vhtFields.mcsNss.at(2)
868 << " vht.mcsNss[3]=" << +m_vhtFields.mcsNss.at(3) << " vht.coding=" << m_vhtFields.coding
869 << " vht.groupId=" << m_vhtFields.groupId << " vht.partialAid=" << m_vhtFields.partialAid;
870}
871
872void
874{
875 NS_LOG_FUNCTION(this << heFields.data1 << heFields.data2 << heFields.data3 << heFields.data4
876 << heFields.data5 << heFields.data6);
877
878 NS_ASSERT_MSG(!(m_present & RADIOTAP_HE), "HE radiotap field already present");
879 m_hePad = ((2 - m_length % 2) % 2);
881 m_length += (sizeof(heFields) + m_hePad);
882 m_heFields = heFields;
883
884 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
885 << std::dec);
886}
887
888void
890{
891 start.WriteU8(0, m_hePad);
892 start.WriteU16(m_heFields.data1);
893 start.WriteU16(m_heFields.data2);
894 start.WriteU16(m_heFields.data3);
895 start.WriteU16(m_heFields.data4);
896 start.WriteU16(m_heFields.data5);
897 start.WriteU16(m_heFields.data6);
898}
899
902{
903 m_hePad = ((2 - bytesRead % 2) % 2);
904 start.Next(m_hePad);
905 m_heFields.data1 = start.ReadU16();
906 m_heFields.data2 = start.ReadU16();
907 m_heFields.data3 = start.ReadU16();
908 m_heFields.data4 = start.ReadU16();
909 m_heFields.data5 = start.ReadU16();
910 m_heFields.data6 = start.ReadU16();
911 return sizeof(HeFields) + m_hePad;
912}
913
914void
915RadiotapHeader::PrintHe(std::ostream& os) const
916{
917 os << " he.data1=0x" << std::hex << m_heFields.data1 << " he.data2=0x" << std::hex
918 << m_heFields.data2 << " he.data3=0x" << std::hex << m_heFields.data3 << " he.data4=0x"
919 << std::hex << m_heFields.data4 << " he.data5=0x" << std::hex << m_heFields.data5
920 << " he.data6=0x" << std::hex << m_heFields.data6 << std::dec;
921}
922
923void
925{
926 NS_LOG_FUNCTION(this << heMuFields.flags1 << heMuFields.flags2);
927
928 NS_ASSERT_MSG(!(m_present & RADIOTAP_HE_MU), "HE-MU radiotap field already present");
929 m_heMuPad = ((2 - m_length % 2) % 2);
931 m_length += (sizeof(heMuFields) + m_heMuPad);
932 m_heMuFields = heMuFields;
933
934 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
935 << std::dec);
936}
937
938void
940{
941 start.WriteU8(0, m_heMuPad);
942 start.WriteU16(m_heMuFields.flags1);
943 start.WriteU16(m_heMuFields.flags2);
944 for (const auto ruChannel : m_heMuFields.ruChannel1)
945 {
946 start.WriteU8(ruChannel);
947 }
948 for (const auto ruChannel : m_heMuFields.ruChannel2)
949 {
950 start.WriteU8(ruChannel);
951 }
952}
953
956{
957 m_heMuPad = ((2 - bytesRead % 2) % 2);
958 start.Next(m_heMuPad);
959 m_heMuFields.flags1 = start.ReadU16();
960 m_heMuFields.flags2 = start.ReadU16();
961 for (auto& ruChannel : m_heMuFields.ruChannel1)
962 {
963 ruChannel = start.ReadU8();
964 }
965 for (auto& ruChannel : m_heMuFields.ruChannel2)
966 {
967 ruChannel = start.ReadU8();
968 }
969 return sizeof(HeMuFields) + m_heMuPad;
970}
971
972void
973RadiotapHeader::PrintHeMu(std::ostream& os) const
974{
975 os << " heMu.flags1=0x" << std::hex << m_heMuFields.flags1 << " heMu.flags2=0x"
976 << m_heMuFields.flags2 << std::dec;
977}
978
979void
981{
982 NS_LOG_FUNCTION(this << heMuOtherUserFields.perUser1 << heMuOtherUserFields.perUser2
983 << +heMuOtherUserFields.perUserPosition
984 << +heMuOtherUserFields.perUserKnown);
985
987 "HE-MU-other-user radiotap field already present");
988 m_heMuOtherUserPad = ((2 - m_length % 2) % 2);
991 m_heMuOtherUserFields = heMuOtherUserFields;
992
993 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
994 << std::dec);
995}
996
997void
999{
1000 start.WriteU8(0, m_heMuOtherUserPad);
1001 start.WriteU16(m_heMuOtherUserFields.perUser1);
1002 start.WriteU16(m_heMuOtherUserFields.perUser2);
1004 start.WriteU8(m_heMuOtherUserFields.perUserKnown);
1005}
1006
1009{
1010 m_heMuOtherUserPad = ((2 - bytesRead % 2) % 2);
1011 start.Next(m_heMuOtherUserPad);
1012 m_heMuOtherUserFields.perUser1 = start.ReadU16();
1013 m_heMuOtherUserFields.perUser2 = start.ReadU16();
1014 m_heMuOtherUserFields.perUserPosition = start.ReadU8();
1015 m_heMuOtherUserFields.perUserKnown = start.ReadU8();
1016 return sizeof(HeMuOtherUserFields) + m_heMuOtherUserPad;
1017}
1018
1019void
1021{
1022 os << " heMuOtherUser.perUser1=" << m_heMuOtherUserFields.perUser1
1023 << " heMuOtherUser.perUser2=" << m_heMuOtherUserFields.perUser2
1024 << " heMuOtherUser.perUserPosition=" << m_heMuOtherUserFields.perUserPosition
1025 << " heMuOtherUser.perUserKnown=0x" << std::hex << m_heMuOtherUserFields.perUserKnown
1026 << std::dec;
1027}
1028
1029void
1031{
1032 NS_LOG_FUNCTION(this << usigFields.common << usigFields.mask << usigFields.value);
1033 if (!m_presentExt)
1034 {
1036 m_presentExt = 0;
1037 m_length += sizeof(RadiotapExtFlags);
1038 }
1039
1040 NS_ASSERT_MSG(!(*m_presentExt & RADIOTAP_USIG), "U-SIG radiotap field already present");
1042
1043 m_usigTlvPad = ((8 - m_length % 8) % 8);
1044 m_usigTlv.type = 32 + std::countr_zero<uint16_t>(RADIOTAP_USIG);
1045 m_usigTlv.length = sizeof(UsigFields);
1046 m_length += sizeof(TlvFields) + m_usigTlvPad;
1047
1048 m_usigPad = ((4 - m_length % 4) % 4);
1049 m_usigFields = usigFields;
1051
1052 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
1053 << " m_presentExt=0x" << *m_presentExt << std::dec);
1054}
1055
1056void
1058{
1059 start.WriteU8(0, m_usigTlvPad);
1060 start.WriteU16(m_usigTlv.type);
1061 start.WriteU16(m_usigTlv.length);
1062 start.WriteU8(0, m_usigPad);
1063 start.WriteU32(m_usigFields.common);
1064 start.WriteU32(m_usigFields.value);
1065 start.WriteU32(m_usigFields.mask);
1066}
1067
1070{
1071 const auto startBytesRead = bytesRead;
1072 m_usigTlvPad = ((8 - bytesRead % 8) % 8);
1073 start.Next(m_usigTlvPad);
1074 bytesRead += m_usigTlvPad;
1075 m_usigTlv.type = start.ReadU16();
1076 m_usigTlv.length = start.ReadU16();
1077 bytesRead += sizeof(TlvFields);
1078 m_usigPad = ((4 - bytesRead % 4) % 4);
1079 start.Next(m_usigPad);
1080 bytesRead += m_usigPad;
1081 m_usigFields.common = start.ReadU32();
1082 m_usigFields.value = start.ReadU32();
1083 m_usigFields.mask = start.ReadU32();
1084 bytesRead += sizeof(UsigFields);
1085 return bytesRead - startBytesRead;
1086}
1087
1088void
1089RadiotapHeader::PrintUsig(std::ostream& os) const
1090{
1091 os << " usig.common=0x" << std::hex << m_usigFields.common << " usig.value=0x"
1092 << m_usigFields.value << " usig.mask=0x" << m_usigFields.mask << std::dec;
1093}
1094
1095void
1097{
1098 NS_LOG_FUNCTION(this << ehtFields.known);
1099 if (!m_presentExt)
1100 {
1102 m_presentExt = 0;
1103 m_length += sizeof(RadiotapExtFlags);
1104 }
1105
1106 NS_ASSERT_MSG(!(*m_presentExt & RADIOTAP_EHT_SIG), "EHT radiotap field already present");
1108
1109 m_ehtTlvPad = ((8 - m_length % 8) % 8);
1110 m_ehtTlv.type = 32 + std::countr_zero<uint16_t>(RADIOTAP_EHT_SIG);
1111 m_ehtTlv.length = (40 + ehtFields.userInfo.size() * 4);
1112 m_length += sizeof(TlvFields) + m_ehtTlvPad;
1113
1114 m_ehtPad = ((4 - m_length % 4) % 4);
1115 m_ehtFields = ehtFields;
1117
1118 NS_LOG_LOGIC(this << " m_length=" << m_length << " m_present=0x" << std::hex << m_present
1119 << " m_presentExt=0x" << *m_presentExt << std::dec);
1120}
1121
1122void
1124{
1125 start.WriteU8(0, m_ehtTlvPad);
1126 start.WriteU16(m_ehtTlv.type);
1127 start.WriteU16(m_ehtTlv.length);
1128 start.WriteU8(0, m_ehtPad);
1129 start.WriteU32(m_ehtFields.known);
1130 for (const auto dataField : m_ehtFields.data)
1131 {
1132 start.WriteU32(dataField);
1133 }
1134 for (const auto userInfoField : m_ehtFields.userInfo)
1135 {
1136 start.WriteU32(userInfoField);
1137 }
1138}
1139
1142{
1143 const auto startBytesRead = bytesRead;
1144
1145 m_ehtTlvPad = ((8 - bytesRead % 8) % 8);
1146 start.Next(m_ehtTlvPad);
1147 bytesRead += m_ehtTlvPad;
1148 m_ehtTlv.type = start.ReadU16();
1149 m_ehtTlv.length = start.ReadU16();
1150 bytesRead += sizeof(TlvFields);
1151
1152 m_ehtPad = ((4 - bytesRead % 4) % 4);
1153 start.Next(m_ehtPad);
1154 bytesRead += m_ehtPad;
1155 m_ehtFields.known = start.ReadU32();
1156 bytesRead += 4;
1157 for (auto& dataField : m_ehtFields.data)
1158 {
1159 dataField = start.ReadU32();
1160 bytesRead += 4;
1161 }
1162 const auto userInfosBytes = m_ehtTlv.length - bytesRead - m_ehtTlvPad;
1163 NS_ASSERT(userInfosBytes % 4 == 0);
1164 const std::size_t numUsers = userInfosBytes / 4;
1165 for (std::size_t i = 0; i < numUsers; ++i)
1166 {
1167 m_ehtFields.userInfo.push_back(start.ReadU32());
1168 bytesRead += 4;
1169 }
1170
1171 return bytesRead - startBytesRead;
1172}
1173
1174void
1175RadiotapHeader::PrintEht(std::ostream& os) const
1176{
1177 os << " eht.known=0x" << std::hex << m_ehtFields.known;
1178 std::size_t index = 0;
1179 for (const auto dataField : m_ehtFields.data)
1180 {
1181 os << " eht.data" << index++ << "=0x" << dataField;
1182 }
1183 index = 0;
1184 for (const auto userInfoField : m_ehtFields.userInfo)
1185 {
1186 os << " eht.userInfo" << index++ << "=0x" << userInfoField;
1187 }
1188 os << std::dec;
1189}
1190
1191} // namespace ns3
iterator in a Buffer instance
Definition buffer.h:89
Protocol header serialization and deserialization.
Definition header.h:33
Radiotap header implementation.
void SerializeMcs(Buffer::Iterator &start) const
Serialize the MCS radiotap header.
std::optional< uint32_t > m_presentExt
optional extended present bitmask
HeMuFields m_heMuFields
HE MU fields.
uint32_t DeserializeHe(Buffer::Iterator start, uint32_t bytesRead)
Deserialize the HE radiotap header.
void PrintHeMu(std::ostream &os) const
Add HE-MU subfield/value pairs to the output stream.
void SerializeHe(Buffer::Iterator &start) const
Serialize the HE radiotap header.
uint8_t m_rate
TX/RX data rate in units of 500 kbps.
void PrintMcs(std::ostream &os) const
Add MCS subfield/value pairs to the output stream.
void SetAmpduStatus(const AmpduStatusFields &ampduStatusFields)
Set the subfields of the A-MPDU status field.
uint32_t DeserializeUsig(Buffer::Iterator start, uint32_t bytesRead)
Deserialize the U-SIG radiotap header.
void PrintEht(std::ostream &os) const
Add EHT subfield/value pairs to the output stream.
static TypeId GetTypeId()
Get the type ID.
uint8_t m_ampduStatusPad
A-MPDU Status Flags, padding before A-MPDU Status Field.
void PrintHeMuOtherUser(std::ostream &os) const
Add HE-MU-other-user subfield/value pairs to the output stream.
void SetHeMuOtherUserFields(const HeMuOtherUserFields &heMuOtherUserFields)
Set the subfields of the HE-MU-other-user field.
uint8_t m_ehtPad
EHT padding.
HeFields m_heFields
HE fields.
uint8_t m_heMuPad
HE MU padding.
void Print(std::ostream &os) const override
This method is used by Packet::Print to print the content of the header as ascii data to a C++ output...
uint8_t m_usigPad
U-SIG padding.
uint8_t m_heMuOtherUserPad
HE MU other user padding.
void SetHeFields(const HeFields &heFields)
Set the subfields of the HE field.
uint8_t m_hePad
HE padding.
void SerializeHeMuOtherUser(Buffer::Iterator &start) const
Serialize the HE-MU-other-user radiotap header.
EhtFields m_ehtFields
EHT fields.
void SetMcsFields(const McsFields &mcsFields)
Set the subfields of the MCS field.
void SetRate(uint8_t rate)
Set the transmit/receive channel frequency in units of megahertz.
uint8_t m_ehtTlvPad
EHT TLV padding.
int8_t m_antennaSignal
RF signal power at the antenna, dB difference from an arbitrary, fixed reference.
void SetAntennaSignalPower(double signal)
Set the RF signal power at the antenna as a decibel difference from an arbitrary, fixed reference.
uint32_t DeserializeAmpduStatus(Buffer::Iterator start, uint32_t bytesRead)
Deserialize the A-MPDU Status radiotap header.
uint32_t DeserializeVht(Buffer::Iterator start, uint32_t bytesRead)
Deserialize the VHT radiotap header.
uint32_t DeserializeHeMuOtherUser(Buffer::Iterator start, uint32_t bytesRead)
Deserialize the HE-MU-other-user radiotap header.
void SetTsft(uint64_t tsft)
Set the Time Synchronization Function Timer (TSFT) value.
void PrintHe(std::ostream &os) const
Add HE subfield/value pairs to the output stream.
TlvFields m_usigTlv
U-SIG TLV fields.
uint16_t m_length
entire length of radiotap data + header
void Serialize(Buffer::Iterator start) const override
This method is used by Packet::AddHeader to store the header into the byte buffer of a packet.
uint32_t m_present
bits describing which fields follow header
void SetUsigFields(const UsigFields &usigFields)
Set the subfields of the U-SIG field.
void SerializeUsig(Buffer::Iterator &start) const
Serialize the U-SIG radiotap header.
uint32_t Deserialize(Buffer::Iterator start) override
This method is used by Packet::RemoveHeader to re-create a header from the byte buffer of a packet.
void PrintUsig(std::ostream &os) const
Add U-SIG subfield/value pairs to the output stream.
void PrintChannel(std::ostream &os) const
Add Channel subfield/value pairs to the output stream.
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
uint32_t DeserializeMcs(Buffer::Iterator start, uint32_t bytesRead)
Deserialize the MCS radiotap header.
void SerializeHeMu(Buffer::Iterator &start) const
Serialize the HE-MU radiotap header.
McsFields m_mcsFields
MCS fields.
void SerializeAmpduStatus(Buffer::Iterator &start) const
Serialize the A-MPDU Status radiotap header.
void SetVhtFields(const VhtFields &vhtFields)
Set the subfields of the VHT field.
void SerializeEht(Buffer::Iterator &start) const
Serialize the EHT radiotap header.
uint32_t DeserializeChannel(Buffer::Iterator start, uint32_t bytesRead)
Deserialize the Channel radiotap header.
UsigFields m_usigFields
U-SIG fields.
RadiotapExtFlags
Radiotap extended flags.
void SerializeChannel(Buffer::Iterator &start) const
Serialize the Channel radiotap header.
void SetAntennaNoisePower(double noise)
Set the RF noise power at the antenna as a decibel difference from an arbitrary, fixed reference.
void PrintVht(std::ostream &os) const
Add VHT subfield/value pairs to the output stream.
uint32_t GetSerializedSize() const override
This method is used by Packet::AddHeader to store the header into the byte buffer of a packet.
TlvFields m_ehtTlv
EHT TLV fields.
void SetEhtFields(const EhtFields &ehtFields)
Set the subfields of the EHT-SIG field.
ChannelFields m_channelFields
Channel fields.
uint8_t m_usigTlvPad
U-SIG TLV padding.
uint8_t m_channelPad
Channel padding.
uint32_t DeserializeHeMu(Buffer::Iterator start, uint32_t bytesRead)
Deserialize the HE-MU radiotap header.
uint8_t m_vhtPad
VHT padding.
AmpduStatusFields m_ampduStatusFields
A-MPDU Status fields.
void SerializeVht(Buffer::Iterator &start) const
Serialize the VHT radiotap header.
void PrintAmpduStatus(std::ostream &os) const
Add A-MPDU Status subfield/value pairs to the output stream.
uint8_t m_flags
Properties of transmitted and received frames.
void SetHeMuFields(const HeMuFields &heMuFields)
Set the subfields of the HE-MU field.
void SetChannelFields(const ChannelFields &channelFields)
Set the subfields of the Channel field.
HeMuOtherUserFields m_heMuOtherUserFields
HE MU other user fields.
void SetFrameFlags(uint8_t flags)
Set the frame flags of the transmitted or received frame.
VhtFields m_vhtFields
VHT fields.
uint64_t m_tsft
Time Synchronization Function Timer (when the first bit of the MPDU arrived at the MAC)
uint32_t DeserializeEht(Buffer::Iterator start, uint32_t bytesRead)
Deserialize the EHT radiotap header.
int8_t m_antennaNoise
RF noise power at the antenna, dB difference from an arbitrary, fixed reference.
a unique identifier for an interface.
Definition type-id.h:49
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition assert.h:75
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Every class exported by the ns3 library is enclosed in the ns3 namespace.
structure that contains the subfields of the A-MPDU status field.
uint32_t referenceNumber
A-MPDU reference number to identify all subframes belonging to the same A-MPDU.
structure that contains the subfields of the Channel field.
uint16_t frequency
Tx/Rx frequency in MHz.
structure that contains the subfields of the EHT field.
std::vector< uint32_t > userInfo
user info fields.
std::array< uint32_t, 9 > data
data fields.
structure that contains the subfields of the HE field.
structure that contains the subfields of the HE-MU field.
std::array< uint8_t, 4 > ruChannel2
RU_channel2 field.
std::array< uint8_t, 4 > ruChannel1
RU_channel1 field.
structure that contains the subfields of the HE-MU-other-user field.
uint8_t perUserKnown
per_user_known field
uint8_t perUserPosition
per_user_position field
structure that contains the subfields of the MCS field.
uint8_t mcs
MCS index value.
structure that contains the subfields of the TLV fields.
structure that contains the subfields of the U-SIG field.
structure that contains the subfields of the VHT field.
uint8_t groupId
group_id field
uint8_t bandwidth
bandwidth field
std::array< uint8_t, 4 > mcsNss
mcs_nss field
uint16_t partialAid
partial_aid field
uint16_t known
known flags field