A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
reduced-neighbor-report.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021 Universita' degli Studi di Napoli Federico II
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Stefano Avallone <stavallo@unina.it>
7 */
8
10
12#include "wifi-utils.h"
13
14#include "ns3/abort.h"
15#include "ns3/address-utils.h"
16
17#include <iterator>
18
19namespace ns3
20{
21
25
31
32std::size_t
37
38void
43
44void
46 const WifiPhyOperatingChannel& channel)
47{
48 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
49
50 uint8_t operatingClass = 0;
51 uint8_t channelNumber = channel.GetNumber();
52
53 // Information taken from Table E-4 of 802.11-2020
54 switch (channel.GetPhyBand())
55 {
57 if (channel.GetWidth() == MHz_u{20})
58 {
59 operatingClass = 81;
60 }
61 else if (channel.GetWidth() == MHz_u{40})
62 {
63 operatingClass = 83;
64 }
65 break;
67 if (channel.GetWidth() == MHz_u{20})
68 {
69 if (channelNumber == 36 || channelNumber == 40 || channelNumber == 44 ||
70 channelNumber == 48)
71 {
72 operatingClass = 115;
73 }
74 else if (channelNumber == 52 || channelNumber == 56 || channelNumber == 60 ||
75 channelNumber == 64)
76 {
77 operatingClass = 118;
78 }
79 else if (channelNumber == 100 || channelNumber == 104 || channelNumber == 108 ||
80 channelNumber == 112 || channelNumber == 116 || channelNumber == 120 ||
81 channelNumber == 124 || channelNumber == 128 || channelNumber == 132 ||
82 channelNumber == 136 || channelNumber == 140 || channelNumber == 144)
83 {
84 operatingClass = 121;
85 }
86 else if (channelNumber == 149 || channelNumber == 153 || channelNumber == 157 ||
87 channelNumber == 161 || channelNumber == 165 || channelNumber == 169 ||
88 channelNumber == 173 || channelNumber == 177 || channelNumber == 181)
89 {
90 operatingClass = 125;
91 }
92 }
93 else if (channel.GetWidth() == MHz_u{40})
94 {
95 if (channelNumber == 38 || channelNumber == 46)
96 {
97 operatingClass = 116;
98 }
99 else if (channelNumber == 54 || channelNumber == 62)
100 {
101 operatingClass = 119;
102 }
103 else if (channelNumber == 102 || channelNumber == 110 || channelNumber == 118 ||
104 channelNumber == 126 || channelNumber == 134 || channelNumber == 142)
105 {
106 operatingClass = 122;
107 }
108 else if (channelNumber == 151 || channelNumber == 159 || channelNumber == 167 ||
109 channelNumber == 175)
110 {
111 operatingClass = 126;
112 }
113 }
114 else if (channel.GetWidth() == MHz_u{80})
115 {
116 if (channelNumber == 42 || channelNumber == 58 || channelNumber == 106 ||
117 channelNumber == 122 || channelNumber == 138 || channelNumber == 155 ||
118 channelNumber == 171)
119 {
120 operatingClass = 128;
121 }
122 }
123 else if (channel.GetWidth() == MHz_u{160})
124 {
125 if (channelNumber == 50 || channelNumber == 114 || channelNumber == 163)
126 {
127 operatingClass = 129;
128 }
129 }
130 break;
132 if (channel.GetWidth() == MHz_u{20})
133 {
134 operatingClass = 131;
135 }
136 else if (channel.GetWidth() == MHz_u{40})
137 {
138 operatingClass = 132;
139 }
140 else if (channel.GetWidth() == MHz_u{80})
141 {
142 operatingClass = 133;
143 }
144 else if (channel.GetWidth() == MHz_u{160})
145 {
146 operatingClass = 134;
147 }
148 break;
150 default:
151 NS_ABORT_MSG("The provided channel has an unspecified PHY band");
152 break;
153 }
154
155 NS_ABORT_MSG_IF(operatingClass == 0,
156 "Operating class not found for channel number "
157 << channelNumber << " width " << channel.GetWidth() << " MHz "
158 << "band " << channel.GetPhyBand());
159
160 // find the primary channel number
161 MHz_u startingFreq{0};
162
163 switch (channel.GetPhyBand())
164 {
166 startingFreq = MHz_u{2407};
167 break;
169 startingFreq = MHz_u{5000};
170 break;
172 startingFreq = MHz_u{5950};
173 break;
175 default:
176 NS_ABORT_MSG("The provided channel has an unspecified PHY band");
177 break;
178 }
179
180 uint8_t primaryChannelNumber =
181 (channel.GetPrimaryChannelCenterFrequency(MHz_u{20}) - startingFreq) / MHz_u{5};
182
183 m_nbrApInfoFields.at(nbrApInfoId).operatingClass = operatingClass;
184 m_nbrApInfoFields.at(nbrApInfoId).channelNumber = primaryChannelNumber;
185}
186
188ReducedNeighborReport::GetOperatingChannel(std::size_t nbrApInfoId) const
189{
190 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
191
193 MHz_u width{0};
194
195 switch (m_nbrApInfoFields.at(nbrApInfoId).operatingClass)
196 {
197 case 81:
199 width = MHz_u{20};
200 break;
201 case 83:
203 width = MHz_u{40};
204 break;
205 case 115:
206 case 118:
207 case 121:
208 case 125:
209 band = WIFI_PHY_BAND_5GHZ;
210 width = MHz_u{20};
211 break;
212 case 116:
213 case 119:
214 case 122:
215 case 126:
216 band = WIFI_PHY_BAND_5GHZ;
217 width = MHz_u{40};
218 break;
219 case 128:
220 band = WIFI_PHY_BAND_5GHZ;
221 width = MHz_u{80};
222 break;
223 case 129:
224 band = WIFI_PHY_BAND_5GHZ;
225 width = MHz_u{160};
226 break;
227 case 131:
228 band = WIFI_PHY_BAND_6GHZ;
229 width = MHz_u{20};
230 break;
231 case 132:
232 band = WIFI_PHY_BAND_6GHZ;
233 width = MHz_u{40};
234 break;
235 case 133:
236 band = WIFI_PHY_BAND_6GHZ;
237 width = MHz_u{80};
238 break;
239 case 134:
240 band = WIFI_PHY_BAND_6GHZ;
241 width = MHz_u{160};
242 break;
243 default:
244 break;
245 }
246
247 NS_ABORT_IF(band == WIFI_PHY_BAND_UNSPECIFIED || width == MHz_u{0});
248
249 MHz_u startingFreq{0};
250
251 switch (band)
252 {
254 startingFreq = MHz_u{2407};
255 break;
257 startingFreq = MHz_u{5000};
258 break;
260 startingFreq = MHz_u{5950};
261 break;
263 default:
264 NS_ABORT_MSG("Unspecified band");
265 break;
266 }
267
268 uint8_t primaryChannelNumber = m_nbrApInfoFields.at(nbrApInfoId).channelNumber;
269 auto primaryChannelCenterFrequency = startingFreq + primaryChannelNumber * MHz_u{5};
270
271 uint8_t channelNumber = 0;
272 MHz_u frequency{0};
273
274 for (const auto& channel : WifiPhyOperatingChannel::m_frequencyChannels)
275 {
276 if (channel.width == width && channel.type == FrequencyChannelType::OFDM &&
277 channel.band == band &&
278 primaryChannelCenterFrequency > (channel.frequency - (width / 2)) &&
279 primaryChannelCenterFrequency < (channel.frequency + (width / 2)))
280 {
281 // the center frequency of the primary channel falls into the frequency
282 // range of this channel
283 bool found = false;
284
285 if (band != WIFI_PHY_BAND_2_4GHZ)
286 {
287 found = true;
288 }
289 else
290 {
291 // frequency channels overlap in the 2.4 GHz band, hence we have to check
292 // that the given primary channel center frequency can be the center frequency
293 // of the primary20 channel of the channel under consideration
294 switch (static_cast<uint16_t>(width))
295 {
296 case 20:
297 if (channel.frequency == primaryChannelCenterFrequency)
298 {
299 found = true;
300 }
301 break;
302 case 40:
303 if ((channel.frequency == primaryChannelCenterFrequency + MHz_u{10}) ||
304 (channel.frequency == primaryChannelCenterFrequency - MHz_u{10}))
305 {
306 found = true;
307 }
308 break;
309 default:
310 NS_ABORT_MSG("No channel of width " << width << " MHz in the 2.4 GHz band");
311 }
312 }
313
314 if (found)
315 {
316 channelNumber = channel.number;
317 frequency = channel.frequency;
318 break;
319 }
320 }
321 }
322
323 NS_ABORT_IF(channelNumber == 0 || frequency == MHz_u{0});
324
325 WifiPhyOperatingChannel channel;
326 channel.Set({{channelNumber, frequency, width, band}}, WIFI_STANDARD_UNSPECIFIED);
327
328 const auto channelLowestFreq = frequency - width / 2;
329 const auto primaryChannelLowestFreq = primaryChannelCenterFrequency - MHz_u{10};
330 channel.SetPrimary20Index(Count20MHzSubchannels(channelLowestFreq, primaryChannelLowestFreq));
331
332 return channel;
333}
334
335std::size_t
336ReducedNeighborReport::GetNTbttInformationFields(std::size_t nbrApInfoId) const
337{
338 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
339 return m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size();
340}
341
342void
343ReducedNeighborReport::AddTbttInformationField(std::size_t nbrApInfoId)
344{
345 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
346 m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.emplace_back();
347}
348
349void
350ReducedNeighborReport::WriteTbttInformationLength(std::size_t nbrApInfoId) const
351{
352 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
353
354 uint8_t length = 0; // reserved value
355
356 auto it = std::next(m_nbrApInfoFields.begin(), nbrApInfoId);
357
358 if (it->hasBssid && !it->hasShortSsid && !it->hasBssParams && !it->has20MHzPsd &&
359 !it->hasMldParams)
360 {
361 length = 7;
362 }
363 else if (it->hasBssid && it->hasShortSsid && it->hasBssParams && it->has20MHzPsd &&
364 it->hasMldParams)
365 {
366 length = 16;
367 }
368 else
369 {
370 NS_ABORT_MSG("Unsupported TBTT Information field contents");
371 }
372
373 // set the TBTT Information Length field
374 it->tbttInfoHdr.tbttInfoLength = length;
375}
376
377void
378ReducedNeighborReport::ReadTbttInformationLength(std::size_t nbrApInfoId)
379{
380 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
381
382 auto it = std::next(m_nbrApInfoFields.begin(), nbrApInfoId);
383
384 switch (it->tbttInfoHdr.tbttInfoLength)
385 {
386 case 7:
387 it->hasBssid = true;
388 it->hasShortSsid = false;
389 it->hasBssParams = false;
390 it->has20MHzPsd = false;
391 it->hasMldParams = false;
392 break;
393 case 16:
394 it->hasBssid = true;
395 it->hasShortSsid = true;
396 it->hasBssParams = true;
397 it->has20MHzPsd = true;
398 it->hasMldParams = true;
399 break;
400 default:
402 "Unsupported TBTT Information Length value: " << it->tbttInfoHdr.tbttInfoLength);
403 }
404}
405
406void
407ReducedNeighborReport::SetBssid(std::size_t nbrApInfoId, std::size_t index, Mac48Address bssid)
408{
409 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
410 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
411
412 m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.at(index).bssid = bssid;
413
414 m_nbrApInfoFields.at(nbrApInfoId).hasBssid = true;
415}
416
417bool
418ReducedNeighborReport::HasBssid(std::size_t nbrApInfoId) const
419{
420 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
421
422 return m_nbrApInfoFields.at(nbrApInfoId).hasBssid;
423}
424
426ReducedNeighborReport::GetBssid(std::size_t nbrApInfoId, std::size_t index) const
427{
428 NS_ASSERT(HasBssid(nbrApInfoId));
429 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
430
431 return m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.at(index).bssid;
432}
433
434void
435ReducedNeighborReport::SetShortSsid(std::size_t nbrApInfoId, std::size_t index, uint32_t shortSsid)
436{
437 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
438 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
439
440 m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.at(index).shortSsid = shortSsid;
441
442 m_nbrApInfoFields.at(nbrApInfoId).hasShortSsid = true;
443}
444
445bool
446ReducedNeighborReport::HasShortSsid(std::size_t nbrApInfoId) const
447{
448 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
449
450 return m_nbrApInfoFields.at(nbrApInfoId).hasShortSsid;
451}
452
454ReducedNeighborReport::GetShortSsid(std::size_t nbrApInfoId, std::size_t index) const
455{
456 NS_ASSERT(HasShortSsid(nbrApInfoId));
457 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
458
459 return m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.at(index).shortSsid;
460}
461
462void
463ReducedNeighborReport::SetBssParameters(std::size_t nbrApInfoId,
464 std::size_t index,
465 uint8_t bssParameters)
466{
467 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
468 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
469
470 m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.at(index).bssParameters = bssParameters;
471
472 m_nbrApInfoFields.at(nbrApInfoId).hasBssParams = true;
473}
474
475bool
476ReducedNeighborReport::HasBssParameters(std::size_t nbrApInfoId) const
477{
478 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
479
480 return m_nbrApInfoFields.at(nbrApInfoId).hasBssParams;
481}
482
483uint8_t
484ReducedNeighborReport::GetBssParameters(std::size_t nbrApInfoId, std::size_t index) const
485{
486 NS_ASSERT(HasBssParameters(nbrApInfoId));
487 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
488
489 return m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.at(index).bssParameters;
490}
491
492void
493ReducedNeighborReport::SetPsd20MHz(std::size_t nbrApInfoId, std::size_t index, uint8_t psd20MHz)
494{
495 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
496 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
497
498 m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.at(index).psd20MHz = psd20MHz;
499
500 m_nbrApInfoFields.at(nbrApInfoId).has20MHzPsd = true;
501}
502
503bool
504ReducedNeighborReport::HasPsd20MHz(std::size_t nbrApInfoId) const
505{
506 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
507
508 return m_nbrApInfoFields.at(nbrApInfoId).has20MHzPsd;
509}
510
511uint8_t
512ReducedNeighborReport::GetPsd20MHz(std::size_t nbrApInfoId, std::size_t index) const
513{
514 NS_ASSERT(HasPsd20MHz(nbrApInfoId));
515 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
516
517 return m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.at(index).psd20MHz;
518}
519
520void
521ReducedNeighborReport::SetMldParameters(std::size_t nbrApInfoId,
522 std::size_t index,
523 const MldParameters& mldParams)
524{
525 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
526 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
527
528 auto it = std::next(m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.begin(), index);
529 it->mldParameters = mldParams;
530
531 m_nbrApInfoFields.at(nbrApInfoId).hasMldParams = true;
532}
533
534bool
535ReducedNeighborReport::HasMldParameters(std::size_t nbrApInfoId) const
536{
537 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
538
539 return m_nbrApInfoFields.at(nbrApInfoId).hasMldParams;
540}
541
543ReducedNeighborReport::GetMldParameters(std::size_t nbrApInfoId, std::size_t index) const
544{
545 NS_ASSERT(HasMldParameters(nbrApInfoId));
546 NS_ASSERT(index < m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size());
547
548 return m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.at(index).mldParameters;
549}
550
551void
552ReducedNeighborReport::WriteTbttInformationCount(std::size_t nbrApInfoId) const
553{
554 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
555 NS_ASSERT(!m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.empty());
556
557 // set the TBTT Information Count field
558 m_nbrApInfoFields.at(nbrApInfoId).tbttInfoHdr.tbttInfoCount =
559 m_nbrApInfoFields.at(nbrApInfoId).tbttInformationSet.size() - 1;
560}
561
562uint8_t
563ReducedNeighborReport::ReadTbttInformationCount(std::size_t nbrApInfoId) const
564{
565 NS_ASSERT(nbrApInfoId < m_nbrApInfoFields.size());
566
567 return 1 + m_nbrApInfoFields.at(nbrApInfoId).tbttInfoHdr.tbttInfoCount;
568}
569
570uint16_t
571ReducedNeighborReport::GetInformationFieldSize() const
572{
573 uint16_t size = 0;
574
575 for (const auto& neighborApInfo : m_nbrApInfoFields)
576 {
577 size += 4;
578
579 size += 1 * neighborApInfo.tbttInformationSet.size();
580
581 if (neighborApInfo.hasBssid)
582 {
583 size += 6 * neighborApInfo.tbttInformationSet.size();
584 }
585 if (neighborApInfo.hasShortSsid)
586 {
587 size += 4 * neighborApInfo.tbttInformationSet.size();
588 }
589 if (neighborApInfo.hasBssParams)
590 {
591 size += 1 * neighborApInfo.tbttInformationSet.size();
592 }
593 if (neighborApInfo.has20MHzPsd)
594 {
595 size += 1 * neighborApInfo.tbttInformationSet.size();
596 }
597 if (neighborApInfo.hasMldParams)
598 {
599 size += 3 * neighborApInfo.tbttInformationSet.size();
600 }
601 }
602
603 return size;
604}
605
606void
607ReducedNeighborReport::SerializeInformationField(Buffer::Iterator start) const
608{
609 for (std::size_t id = 0; id < m_nbrApInfoFields.size(); ++id)
610 {
611 WriteTbttInformationCount(id);
612 WriteTbttInformationLength(id);
613 }
614
615 for (auto& neighborApInfo : m_nbrApInfoFields)
616 {
617 // serialize the TBTT Information Header
618 uint16_t tbttInfoHdr = 0;
619 tbttInfoHdr |= neighborApInfo.tbttInfoHdr.type;
620 tbttInfoHdr |= (neighborApInfo.tbttInfoHdr.filtered << 2);
621 tbttInfoHdr |= (neighborApInfo.tbttInfoHdr.tbttInfoCount << 4);
622 tbttInfoHdr |= (neighborApInfo.tbttInfoHdr.tbttInfoLength << 8);
623 start.WriteHtolsbU16(tbttInfoHdr);
624
625 start.WriteU8(neighborApInfo.operatingClass);
626 start.WriteU8(neighborApInfo.channelNumber);
627
628 for (const auto& tbttInformation : neighborApInfo.tbttInformationSet)
629 {
630 start.WriteU8(tbttInformation.neighborApTbttOffset);
631
632 if (neighborApInfo.hasBssid)
633 {
634 WriteTo(start, tbttInformation.bssid);
635 }
636 if (neighborApInfo.hasShortSsid)
637 {
638 start.WriteHtolsbU32(tbttInformation.shortSsid);
639 }
640 if (neighborApInfo.hasBssParams)
641 {
642 start.WriteU8(tbttInformation.bssParameters);
643 }
644 if (neighborApInfo.has20MHzPsd)
645 {
646 start.WriteU8(tbttInformation.psd20MHz);
647 }
648 if (neighborApInfo.hasMldParams)
649 {
650 start.WriteU8(tbttInformation.mldParameters.apMldId);
651 uint16_t other = 0;
652 other |= (tbttInformation.mldParameters.linkId & 0x0f);
653 other |= (tbttInformation.mldParameters.bssParamsChangeCount << 4);
654 other |= (tbttInformation.mldParameters.allUpdates << 12);
655 other |= (tbttInformation.mldParameters.disabledLink << 13);
656 start.WriteHtolsbU16(other);
657 }
658 }
659 }
660}
661
662uint16_t
663ReducedNeighborReport::DeserializeInformationField(Buffer::Iterator start, uint16_t length)
664{
665 Buffer::Iterator i = start;
666 uint16_t count = 0;
667
668 while (count < length)
669 {
670 AddNbrApInfoField();
671
672 auto tbttInfoHdr = i.ReadLsbtohU16();
673 m_nbrApInfoFields.back().tbttInfoHdr.type = tbttInfoHdr & 0x0003;
674 m_nbrApInfoFields.back().tbttInfoHdr.filtered = (tbttInfoHdr >> 2) & 0x0001;
675 m_nbrApInfoFields.back().tbttInfoHdr.tbttInfoCount = (tbttInfoHdr >> 4) & 0x000f;
676 m_nbrApInfoFields.back().tbttInfoHdr.tbttInfoLength = (tbttInfoHdr >> 8) & 0x00ff;
677
678 m_nbrApInfoFields.back().operatingClass = i.ReadU8();
679 m_nbrApInfoFields.back().channelNumber = i.ReadU8();
680 count += 4;
681
682 std::size_t neighborId = m_nbrApInfoFields.size() - 1;
683 ReadTbttInformationLength(neighborId);
684
685 for (uint8_t j = 0; j < ReadTbttInformationCount(neighborId); j++)
686 {
687 AddTbttInformationField(neighborId);
688
689 m_nbrApInfoFields.back().tbttInformationSet.back().neighborApTbttOffset = i.ReadU8();
690 count++;
691
692 if (m_nbrApInfoFields.back().hasBssid)
693 {
694 ReadFrom(i, m_nbrApInfoFields.back().tbttInformationSet.back().bssid);
695 count += 6;
696 }
697 if (m_nbrApInfoFields.back().hasShortSsid)
698 {
699 m_nbrApInfoFields.back().tbttInformationSet.back().shortSsid = i.ReadLsbtohU32();
700 count += 4;
701 }
702 if (m_nbrApInfoFields.back().hasBssParams)
703 {
704 m_nbrApInfoFields.back().tbttInformationSet.back().bssParameters = i.ReadU8();
705 count += 1;
706 }
707 if (m_nbrApInfoFields.back().has20MHzPsd)
708 {
709 m_nbrApInfoFields.back().tbttInformationSet.back().psd20MHz = i.ReadU8();
710 count += 1;
711 }
712 if (m_nbrApInfoFields.back().hasMldParams)
713 {
714 auto& mldParams = m_nbrApInfoFields.back().tbttInformationSet.back().mldParameters;
715 mldParams.apMldId = i.ReadU8();
716 uint16_t other = i.ReadLsbtohU16();
717 count += 3;
718 mldParams.linkId = other & 0x000f;
719 mldParams.bssParamsChangeCount = (other >> 4) & 0x00ff;
720 mldParams.allUpdates = (other >> 12) & 0x01;
721 mldParams.disabledLink = (other >> 13) & 0x01;
722 }
723 }
724 }
725
726 return count;
727}
728
729} // namespace ns3
iterator in a Buffer instance
Definition buffer.h:89
uint16_t ReadLsbtohU16()
Definition buffer.cc:1053
uint32_t ReadLsbtohU32()
Definition buffer.cc:1065
an EUI-48 address
std::vector< NeighborApInformation > m_nbrApInfoFields
one or more Neighbor AP Information fields
std::size_t GetNNbrApInfoFields() const
Get the number of Neighbor AP Information fields.
WifiInformationElementId ElementId() const override
Get the wifi information element ID.
void AddNbrApInfoField()
Add a Neighbor AP Information field.
WifiPhyOperatingChannel GetOperatingChannel(std::size_t nbrApInfoId) const
Get the operating channel coded into the Operating Class and the Channel Number fields of the given N...
void SetOperatingChannel(std::size_t nbrApInfoId, const WifiPhyOperatingChannel &channel)
Set the Operating Class and the Channel Number fields of the given Neighbor AP Information field base...
Class that keeps track of all information about the current PHY operating channel.
static const std::set< FrequencyChannelInfo > m_frequencyChannels
Available frequency channels.
#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_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition abort.h:38
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97
#define NS_ABORT_IF(cond)
Abnormal program termination if a condition is true.
Definition abort.h:65
WifiPhyBand
Identifies the PHY band.
@ WIFI_STANDARD_UNSPECIFIED
@ WIFI_PHY_BAND_6GHZ
The 6 GHz band.
@ WIFI_PHY_BAND_UNSPECIFIED
Unspecified.
@ WIFI_PHY_BAND_2_4GHZ
The 2.4 GHz band.
@ WIFI_PHY_BAND_5GHZ
The 5 GHz band.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
double MHz_u
MHz weak type.
Definition wifi-units.h:31
std::size_t Count20MHzSubchannels(MHz_u channelWidth)
Return the number of 20 MHz subchannels covering the channel width.
Definition wifi-utils.h:135
void WriteTo(Buffer::Iterator &i, Ipv4Address ad)
Write an Ipv4Address to a Buffer.
uint8_t WifiInformationElementId
This type is used to represent an Information Element ID.
void ReadFrom(Buffer::Iterator &i, Ipv4Address &ad)
Read an Ipv4Address from a Buffer.
channel
Definition third.py:77
#define IE_REDUCED_NEIGHBOR_REPORT