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