A Discrete-Event Network Simulator
API
wifi-psdu.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Universita' degli Studi di Napoli Federico II
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Stefano Avallone <stavallo@unina.it>
18  */
19 
20 #include "wifi-psdu.h"
21 
22 #include "ampdu-subframe-header.h"
23 #include "mpdu-aggregator.h"
24 #include "wifi-mac-trailer.h"
25 #include "wifi-utils.h"
26 
27 #include "ns3/log.h"
28 #include "ns3/packet.h"
29 
30 namespace ns3
31 {
32 
33 NS_LOG_COMPONENT_DEFINE("WifiPsdu");
34 
36  : m_isSingle(false)
37 {
38  m_mpduList.push_back(Create<WifiMpdu>(p, header));
40 }
41 
42 WifiPsdu::WifiPsdu(Ptr<WifiMpdu> mpdu, bool isSingle)
43  : m_isSingle(isSingle)
44 {
45  m_mpduList.push_back(mpdu);
46  m_size = mpdu->GetSize();
47 
48  if (isSingle)
49  {
50  m_size += 4; // A-MPDU Subframe header size
51  }
52 }
53 
54 WifiPsdu::WifiPsdu(Ptr<const WifiMpdu> mpdu, bool isSingle)
55  : WifiPsdu(Create<WifiMpdu>(*mpdu), isSingle)
56 {
57 }
58 
59 WifiPsdu::WifiPsdu(std::vector<Ptr<WifiMpdu>> mpduList)
60  : m_isSingle(mpduList.size() == 1),
61  m_mpduList(mpduList)
62 {
63  NS_ABORT_MSG_IF(mpduList.empty(), "Cannot initialize a WifiPsdu with an empty MPDU list");
64 
65  m_size = 0;
66  for (auto& mpdu : m_mpduList)
67  {
69  }
70 }
71 
73 {
74 }
75 
76 bool
78 {
79  return m_isSingle;
80 }
81 
82 bool
84 {
85  return (m_mpduList.size() > 1 || m_isSingle);
86 }
87 
90 {
91  Ptr<Packet> packet = Create<Packet>();
92  if (m_mpduList.size() == 1 && !m_isSingle)
93  {
94  packet = m_mpduList.at(0)->GetPacket()->Copy();
95  packet->AddHeader(m_mpduList.at(0)->GetHeader());
96  AddWifiMacTrailer(packet);
97  }
98  else if (m_isSingle)
99  {
100  MpduAggregator::Aggregate(m_mpduList.at(0), packet, true);
101  }
102  else
103  {
104  for (auto& mpdu : m_mpduList)
105  {
106  MpduAggregator::Aggregate(mpdu, packet, false);
107  }
108  }
109  return packet;
110 }
111 
114 {
115  Mac48Address ra = m_mpduList.at(0)->GetHeader().GetAddr1();
116  // check that the other MPDUs have the same RA
117  for (std::size_t i = 1; i < m_mpduList.size(); i++)
118  {
119  if (m_mpduList.at(i)->GetHeader().GetAddr1() != ra)
120  {
121  NS_ABORT_MSG("MPDUs in an A-AMPDU must have the same receiver address");
122  }
123  }
124  return ra;
125 }
126 
129 {
130  Mac48Address ta = m_mpduList.at(0)->GetHeader().GetAddr2();
131  // check that the other MPDUs have the same TA
132  for (std::size_t i = 1; i < m_mpduList.size(); i++)
133  {
134  if (m_mpduList.at(i)->GetHeader().GetAddr2() != ta)
135  {
136  NS_ABORT_MSG("MPDUs in an A-AMPDU must have the same transmitter address");
137  }
138  }
139  return ta;
140 }
141 
142 bool
144 {
145  // When the contents of a received Duration/ID field, treated as an unsigned integer,
146  // are greater than 32 768, the contents are interpreted as appropriate for the frame
147  // type and subtype or ignored if the receiving MAC entity does not have a defined
148  // interpretation for that type and subtype (IEEE 802.11-2016 sec. 10.27.3)
149  return (m_mpduList.at(0)->GetHeader().GetRawDuration() & 0x8000) == 0;
150 }
151 
152 Time
154 {
155  Time duration = m_mpduList.at(0)->GetHeader().GetDuration();
156  // check that the other MPDUs have the same Duration/ID
157  for (std::size_t i = 1; i < m_mpduList.size(); i++)
158  {
159  if (m_mpduList.at(i)->GetHeader().GetDuration() != duration)
160  {
161  NS_ABORT_MSG("MPDUs in an A-AMPDU must have the same Duration/ID");
162  }
163  }
164  return duration;
165 }
166 
167 void
169 {
170  NS_LOG_FUNCTION(this << duration);
171  for (auto& mpdu : m_mpduList)
172  {
173  mpdu->GetHeader().SetDuration(duration);
174  }
175 }
176 
177 std::set<uint8_t>
179 {
180  std::set<uint8_t> s;
181  for (auto& mpdu : m_mpduList)
182  {
183  if (mpdu->GetHeader().IsQosData())
184  {
185  s.insert(mpdu->GetHeader().GetQosTid());
186  }
187  }
188  return s;
189 }
190 
193 {
194  NS_LOG_FUNCTION(this << +tid);
196  auto it = m_mpduList.begin();
197  bool found = false;
198 
199  // find the first QoS Data frame with the given TID
200  do
201  {
202  if ((*it)->GetHeader().IsQosData() && (*it)->GetHeader().GetQosTid() == tid)
203  {
204  policy = (*it)->GetHeader().GetQosAckPolicy();
205  found = true;
206  }
207  it++;
208  } while (!found && it != m_mpduList.end());
209 
210  NS_ABORT_MSG_IF(!found, "No QoS Data frame in the PSDU");
211 
212  // check that the other QoS Data frames with the given TID have the same ack policy
213  while (it != m_mpduList.end())
214  {
215  if ((*it)->GetHeader().IsQosData() && (*it)->GetHeader().GetQosTid() == tid &&
216  (*it)->GetHeader().GetQosAckPolicy() != policy)
217  {
218  NS_ABORT_MSG("QoS Data frames with the same TID must have the same QoS Ack Policy");
219  }
220  it++;
221  }
222  return policy;
223 }
224 
225 void
227 {
228  NS_LOG_FUNCTION(this << +tid << policy);
229  for (auto& mpdu : m_mpduList)
230  {
231  if (mpdu->GetHeader().IsQosData() && mpdu->GetHeader().GetQosTid() == tid)
232  {
233  mpdu->GetHeader().SetQosAckPolicy(policy);
234  }
235  }
236 }
237 
238 uint16_t
239 WifiPsdu::GetMaxDistFromStartingSeq(uint16_t startingSeq) const
240 {
241  NS_LOG_FUNCTION(this << startingSeq);
242 
243  uint16_t maxDistFromStartingSeq = 0;
244  bool foundFirst = false;
245 
246  for (auto& mpdu : m_mpduList)
247  {
248  uint16_t currSeqNum = mpdu->GetHeader().GetSequenceNumber();
249 
250  if (mpdu->GetHeader().IsQosData() && !QosUtilsIsOldPacket(startingSeq, currSeqNum))
251  {
252  uint16_t currDistToStartingSeq =
253  (currSeqNum - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
254 
255  if (!foundFirst || currDistToStartingSeq > maxDistFromStartingSeq)
256  {
257  foundFirst = true;
258  maxDistFromStartingSeq = currDistToStartingSeq;
259  }
260  }
261  }
262 
263  if (!foundFirst)
264  {
265  NS_LOG_DEBUG("All QoS Data frames in this PSDU are old frames");
266  return SEQNO_SPACE_SIZE;
267  }
268  NS_LOG_DEBUG("Returning " << maxDistFromStartingSeq);
269  return maxDistFromStartingSeq;
270 }
271 
272 uint32_t
274 {
275  return m_size;
276 }
277 
278 const WifiMacHeader&
279 WifiPsdu::GetHeader(std::size_t i) const
280 {
281  return m_mpduList.at(i)->GetHeader();
282 }
283 
285 WifiPsdu::GetHeader(std::size_t i)
286 {
287  return m_mpduList.at(i)->GetHeader();
288 }
289 
291 WifiPsdu::GetPayload(std::size_t i) const
292 {
293  return m_mpduList.at(i)->GetPacket();
294 }
295 
297 WifiPsdu::GetAmpduSubframe(std::size_t i) const
298 {
299  NS_ASSERT(i < m_mpduList.size());
300  Ptr<Packet> subframe = m_mpduList.at(i)->GetProtocolDataUnit();
301  subframe->AddHeader(
302  MpduAggregator::GetAmpduSubframeHeader(static_cast<uint16_t>(subframe->GetSize()),
303  m_isSingle));
304  size_t padding = GetAmpduSubframeSize(i) - subframe->GetSize();
305  if (padding > 0)
306  {
307  Ptr<Packet> pad = Create<Packet>(padding);
308  subframe->AddAtEnd(pad);
309  }
310  return subframe;
311 }
312 
313 std::size_t
314 WifiPsdu::GetAmpduSubframeSize(std::size_t i) const
315 {
316  NS_ASSERT(i < m_mpduList.size());
317  size_t subframeSize = 4; // A-MPDU Subframe header size
318  subframeSize += m_mpduList.at(i)->GetSize();
319  if (i != m_mpduList.size() - 1) // add padding if not last
320  {
321  subframeSize += MpduAggregator::CalculatePadding(subframeSize);
322  }
323  return subframeSize;
324 }
325 
326 std::size_t
328 {
329  return m_mpduList.size();
330 }
331 
332 std::vector<Ptr<WifiMpdu>>::const_iterator
334 {
335  return m_mpduList.begin();
336 }
337 
338 std::vector<Ptr<WifiMpdu>>::iterator
340 {
341  return m_mpduList.begin();
342 }
343 
344 std::vector<Ptr<WifiMpdu>>::const_iterator
346 {
347  return m_mpduList.end();
348 }
349 
350 std::vector<Ptr<WifiMpdu>>::iterator
352 {
353  return m_mpduList.end();
354 }
355 
356 void
357 WifiPsdu::Print(std::ostream& os) const
358 {
359  os << "size=" << m_size;
360  if (IsAggregate())
361  {
362  os << ", A-MPDU of " << GetNMpdus() << " MPDUs";
363  for (const auto& mpdu : m_mpduList)
364  {
365  os << " (" << *mpdu << ")";
366  }
367  }
368  else
369  {
370  os << ", " << ((m_isSingle) ? "S-MPDU" : "normal MPDU") << " (" << *(m_mpduList.at(0))
371  << ")";
372  }
373 }
374 
375 std::ostream&
376 operator<<(std::ostream& os, const WifiPsdu& psdu)
377 {
378  psdu.Print(os);
379  return os;
380 }
381 
382 } // namespace ns3
an EUI-48 address
Definition: mac48-address.h:46
static uint8_t CalculatePadding(uint32_t ampduSize)
static void Aggregate(Ptr< const WifiMpdu > mpdu, Ptr< Packet > ampdu, bool isSingle)
Aggregate an MPDU to an A-MPDU.
static AmpduSubframeHeader GetAmpduSubframeHeader(uint16_t mpduSize, bool isSingle)
Get the A-MPDU subframe header corresponding to the MPDU size and whether the MPDU is a single MPDU.
static uint32_t GetSizeIfAggregated(uint32_t mpduSize, uint32_t ampduSize)
Compute the size of the A-MPDU resulting from the aggregation of an MPDU of size mpduSize and an A-MP...
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition: packet.cc:354
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:268
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
Implements the IEEE 802.11 MAC header.
uint32_t GetSerializedSize() const override
QosAckPolicy
Ack policy for QoS frames.
WifiMpdu stores a (const) packet along with a MAC header.
Definition: wifi-mpdu.h:62
WifiPsdu stores an MPDU, S-MPDU or A-MPDU, by keeping header(s) and payload(s) separate for each cons...
Definition: wifi-psdu.h:43
std::set< uint8_t > GetTids() const
Get the set of TIDs of the QoS Data frames included in the PSDU.
Definition: wifi-psdu.cc:178
void SetAckPolicyForTid(uint8_t tid, WifiMacHeader::QosAckPolicy policy)
Set the QoS Ack Policy of the QoS Data frames included in the PSDU that have the given TID to the giv...
Definition: wifi-psdu.cc:226
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Definition: wifi-psdu.cc:279
void Print(std::ostream &os) const
Print the PSDU contents.
Definition: wifi-psdu.cc:357
Time GetDuration() const
Get the duration from the Duration/ID field, which is common to all the MPDUs.
Definition: wifi-psdu.cc:153
Ptr< const Packet > GetPacket() const
Get the PSDU as a single packet.
Definition: wifi-psdu.cc:89
Ptr< Packet > GetAmpduSubframe(std::size_t i) const
Get a copy of the i-th A-MPDU subframe (includes subframe header, MPDU, and possibly padding)
Definition: wifi-psdu.cc:297
std::vector< Ptr< WifiMpdu > >::const_iterator end() const
Return a const iterator to past-the-last MPDU.
Definition: wifi-psdu.cc:345
std::vector< Ptr< WifiMpdu > >::const_iterator begin() const
Return a const iterator to the first MPDU.
Definition: wifi-psdu.cc:333
WifiPsdu(Ptr< const Packet > p, const WifiMacHeader &header)
Create a PSDU storing an MPDU.
Definition: wifi-psdu.cc:35
Mac48Address GetAddr2() const
Get the Transmitter Address (TA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:128
bool HasNav() const
Definition: wifi-psdu.cc:143
uint32_t m_size
the size of the PSDU in bytes
Definition: wifi-psdu.h:256
virtual ~WifiPsdu()
Definition: wifi-psdu.cc:72
uint32_t GetSize() const
Return the size of the PSDU in bytes.
Definition: wifi-psdu.cc:273
Ptr< const Packet > GetPayload(std::size_t i) const
Get the payload of the i-th MPDU.
Definition: wifi-psdu.cc:291
std::size_t GetAmpduSubframeSize(std::size_t i) const
Return the size of the i-th A-MPDU subframe.
Definition: wifi-psdu.cc:314
bool m_isSingle
true for an S-MPDU
Definition: wifi-psdu.h:254
Mac48Address GetAddr1() const
Get the Receiver Address (RA), which is common to all the MPDUs.
Definition: wifi-psdu.cc:113
bool IsAggregate() const
Return true if the PSDU is an S-MPDU or A-MPDU.
Definition: wifi-psdu.cc:83
bool IsSingle() const
Return true if the PSDU is an S-MPDU.
Definition: wifi-psdu.cc:77
void SetDuration(Time duration)
Set the Duration/ID field on all the MPDUs.
Definition: wifi-psdu.cc:168
std::vector< Ptr< WifiMpdu > > m_mpduList
list of constituent MPDUs
Definition: wifi-psdu.h:255
uint16_t GetMaxDistFromStartingSeq(uint16_t startingSeq) const
Get the maximum distance between the sequence number of any QoS Data frame included in this PSDU that...
Definition: wifi-psdu.cc:239
std::size_t GetNMpdus() const
Return the number of MPDUs constituting the PSDU.
Definition: wifi-psdu.cc:327
WifiMacHeader::QosAckPolicy GetAckPolicyForTid(uint8_t tid) const
Get the QoS Ack Policy of the QoS Data frames included in the PSDU that have the given TID.
Definition: wifi-psdu.cc:192
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_ABORT_MSG(msg)
Unconditional abnormal program termination with a message.
Definition: abort.h:49
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition: abort.h:108
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition: ptr.h:442
bool QosUtilsIsOldPacket(uint16_t startingSeq, uint16_t seqNumber)
This function checks if packet with sequence number seqNumber is an "old" packet.
Definition: qos-utils.cc:182
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static const uint16_t WIFI_MAC_FCS_LENGTH
The length in octets of the IEEE 802.11 MAC FCS field.
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:185
void AddWifiMacTrailer(Ptr< Packet > packet)
Add FCS trailer to a packet.
Definition: wifi-utils.cc:125
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:159