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
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
30namespace ns3
31{
32
33NS_LOG_COMPONENT_DEFINE("WifiPsdu");
34
36 : m_isSingle(false)
37{
38 m_mpduList.push_back(Create<WifiMpdu>(p, header));
40}
41
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
54WifiPsdu::WifiPsdu(Ptr<const WifiMpdu> mpdu, bool isSingle)
55 : WifiPsdu(Create<WifiMpdu>(*mpdu), isSingle)
56{
57}
58
59WifiPsdu::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
76bool
78{
79 return m_isSingle;
80}
81
82bool
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
142Time
144{
145 Time duration = m_mpduList.at(0)->GetHeader().GetDuration();
146 // check that the other MPDUs have the same Duration/ID
147 for (std::size_t i = 1; i < m_mpduList.size(); i++)
148 {
149 if (m_mpduList.at(i)->GetHeader().GetDuration() != duration)
150 {
151 NS_ABORT_MSG("MPDUs in an A-AMPDU must have the same Duration/ID");
152 }
153 }
154 return duration;
155}
156
157void
159{
160 NS_LOG_FUNCTION(this << duration);
161 for (auto& mpdu : m_mpduList)
162 {
163 mpdu->GetHeader().SetDuration(duration);
164 }
165}
166
167std::set<uint8_t>
169{
170 std::set<uint8_t> s;
171 for (auto& mpdu : m_mpduList)
172 {
173 if (mpdu->GetHeader().IsQosData())
174 {
175 s.insert(mpdu->GetHeader().GetQosTid());
176 }
177 }
178 return s;
179}
180
183{
184 NS_LOG_FUNCTION(this << +tid);
186 auto it = m_mpduList.begin();
187 bool found = false;
188
189 // find the first QoS Data frame with the given TID
190 do
191 {
192 if ((*it)->GetHeader().IsQosData() && (*it)->GetHeader().GetQosTid() == tid)
193 {
194 policy = (*it)->GetHeader().GetQosAckPolicy();
195 found = true;
196 }
197 it++;
198 } while (!found && it != m_mpduList.end());
199
200 NS_ABORT_MSG_IF(!found, "No QoS Data frame in the PSDU");
201
202 // check that the other QoS Data frames with the given TID have the same ack policy
203 while (it != m_mpduList.end())
204 {
205 if ((*it)->GetHeader().IsQosData() && (*it)->GetHeader().GetQosTid() == tid &&
206 (*it)->GetHeader().GetQosAckPolicy() != policy)
207 {
208 NS_ABORT_MSG("QoS Data frames with the same TID must have the same QoS Ack Policy");
209 }
210 it++;
211 }
212 return policy;
213}
214
215void
217{
218 NS_LOG_FUNCTION(this << +tid << policy);
219 for (auto& mpdu : m_mpduList)
220 {
221 if (mpdu->GetHeader().IsQosData() && mpdu->GetHeader().GetQosTid() == tid)
222 {
223 mpdu->GetHeader().SetQosAckPolicy(policy);
224 }
225 }
226}
227
228uint16_t
229WifiPsdu::GetMaxDistFromStartingSeq(uint16_t startingSeq) const
230{
231 NS_LOG_FUNCTION(this << startingSeq);
232
233 uint16_t maxDistFromStartingSeq = 0;
234 bool foundFirst = false;
235
236 for (auto& mpdu : m_mpduList)
237 {
238 uint16_t currSeqNum = mpdu->GetHeader().GetSequenceNumber();
239
240 if (mpdu->GetHeader().IsQosData() && !QosUtilsIsOldPacket(startingSeq, currSeqNum))
241 {
242 uint16_t currDistToStartingSeq =
243 (currSeqNum - startingSeq + SEQNO_SPACE_SIZE) % SEQNO_SPACE_SIZE;
244
245 if (!foundFirst || currDistToStartingSeq > maxDistFromStartingSeq)
246 {
247 foundFirst = true;
248 maxDistFromStartingSeq = currDistToStartingSeq;
249 }
250 }
251 }
252
253 if (!foundFirst)
254 {
255 NS_LOG_DEBUG("All QoS Data frames in this PSDU are old frames");
256 return SEQNO_SPACE_SIZE;
257 }
258 NS_LOG_DEBUG("Returning " << maxDistFromStartingSeq);
259 return maxDistFromStartingSeq;
260}
261
264{
265 return m_size;
266}
267
268const WifiMacHeader&
269WifiPsdu::GetHeader(std::size_t i) const
270{
271 return m_mpduList.at(i)->GetHeader();
272}
273
276{
277 return m_mpduList.at(i)->GetHeader();
278}
279
281WifiPsdu::GetPayload(std::size_t i) const
282{
283 return m_mpduList.at(i)->GetPacket();
284}
285
287WifiPsdu::GetAmpduSubframe(std::size_t i) const
288{
289 NS_ASSERT(i < m_mpduList.size());
290 Ptr<Packet> subframe = m_mpduList.at(i)->GetProtocolDataUnit();
291 subframe->AddHeader(
292 MpduAggregator::GetAmpduSubframeHeader(static_cast<uint16_t>(subframe->GetSize()),
293 m_isSingle));
294 size_t padding = GetAmpduSubframeSize(i) - subframe->GetSize();
295 if (padding > 0)
296 {
297 Ptr<Packet> pad = Create<Packet>(padding);
298 subframe->AddAtEnd(pad);
299 }
300 return subframe;
301}
302
303std::size_t
305{
306 NS_ASSERT(i < m_mpduList.size());
307 size_t subframeSize = 4; // A-MPDU Subframe header size
308 subframeSize += m_mpduList.at(i)->GetSize();
309 if (i != m_mpduList.size() - 1) // add padding if not last
310 {
311 subframeSize += MpduAggregator::CalculatePadding(subframeSize);
312 }
313 return subframeSize;
314}
315
316std::size_t
318{
319 return m_mpduList.size();
320}
321
322std::vector<Ptr<WifiMpdu>>::const_iterator
324{
325 return m_mpduList.begin();
326}
327
328std::vector<Ptr<WifiMpdu>>::iterator
330{
331 return m_mpduList.begin();
332}
333
334std::vector<Ptr<WifiMpdu>>::const_iterator
336{
337 return m_mpduList.end();
338}
339
340std::vector<Ptr<WifiMpdu>>::iterator
342{
343 return m_mpduList.end();
344}
345
346void
347WifiPsdu::Print(std::ostream& os) const
348{
349 os << "size=" << m_size;
350 if (IsAggregate())
351 {
352 os << ", A-MPDU of " << GetNMpdus() << " MPDUs";
353 for (const auto& mpdu : m_mpduList)
354 {
355 os << " (" << *mpdu << ")";
356 }
357 }
358 else
359 {
360 os << ", " << ((m_isSingle) ? "S-MPDU" : "normal MPDU") << " (" << *(m_mpduList.at(0))
361 << ")";
362 }
363}
364
365std::ostream&
366operator<<(std::ostream& os, const WifiPsdu& psdu)
367{
368 psdu.Print(os);
369 return os;
370}
371
372} // 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:863
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 (const) packets along with their Wifi MAC headers and the time when they were enqueue...
Definition: wifi-mpdu.h:57
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:168
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:216
const WifiMacHeader & GetHeader(std::size_t i) const
Get the header of the i-th MPDU.
Definition: wifi-psdu.cc:269
void Print(std::ostream &os) const
Print the PSDU contents.
Definition: wifi-psdu.cc:347
Time GetDuration() const
Get the duration from the Duration/ID field, which is common to all the MPDUs.
Definition: wifi-psdu.cc:143
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:287
std::vector< Ptr< WifiMpdu > >::const_iterator end() const
Return a const iterator to past-the-last MPDU.
Definition: wifi-psdu.cc:335
std::vector< Ptr< WifiMpdu > >::const_iterator begin() const
Return a const iterator to the first MPDU.
Definition: wifi-psdu.cc:323
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
uint32_t m_size
the size of the PSDU in bytes
Definition: wifi-psdu.h:251
virtual ~WifiPsdu()
Definition: wifi-psdu.cc:72
uint32_t GetSize() const
Return the size of the PSDU in bytes.
Definition: wifi-psdu.cc:263
Ptr< const Packet > GetPayload(std::size_t i) const
Get the payload of the i-th MPDU.
Definition: wifi-psdu.cc:281
std::size_t GetAmpduSubframeSize(std::size_t i) const
Return the size of the i-th A-MPDU subframe.
Definition: wifi-psdu.cc:304
bool m_isSingle
true for an S-MPDU
Definition: wifi-psdu.h:249
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:158
std::vector< Ptr< WifiMpdu > > m_mpduList
list of constituent MPDUs
Definition: wifi-psdu.h:250
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:229
std::size_t GetNMpdus() const
Return the number of MPDUs constituting the PSDU.
Definition: wifi-psdu.cc:317
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:182
#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:481
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:184
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static const uint16_t WIFI_MAC_FCS_LENGTH
The length in octects of the IEEE 802.11 MAC FCS field.
std::ostream & operator<<(std::ostream &os, const Angles &a)
Definition: angles.cc:129
static constexpr uint16_t SEQNO_SPACE_SIZE
Size of the space of sequence numbers.
Definition: wifi-utils.h:133
void AddWifiMacTrailer(Ptr< Packet > packet)
Add FCS trailer to a packet.
Definition: wifi-utils.cc:125