A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
mac-rx-middle.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2005 INRIA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 */
8
9#include "mac-rx-middle.h"
10
11#include "wifi-mpdu.h"
12
13#include "ns3/log.h"
14#include "ns3/packet.h"
15#include "ns3/sequence-number.h"
16
17namespace ns3
18{
19
20NS_LOG_COMPONENT_DEFINE("MacRxMiddle");
21
22/**
23 * A class to keep track of the packet originator status.
24 * It recomposes the packet from multiple fragments.
25 */
27{
28 private:
29 /**
30 * typedef for a list of fragments (i.e. incomplete Packet).
31 */
32 typedef std::list<Ptr<const Packet>> Fragments;
33 /**
34 * typedef for a const iterator for Fragments
35 */
36 typedef std::list<Ptr<const Packet>>::const_iterator FragmentsCI;
37
38 bool m_defragmenting; ///< flag to indicate whether we are defragmenting
39 uint16_t m_lastSequenceControl; ///< last sequence control
40 Fragments m_fragments; ///< fragments
41
42 public:
44 {
45 /* this is a magic value necessary. */
46 m_lastSequenceControl = 0xffff;
47 m_defragmenting = false;
48 }
49
50 /**
51 * Check if we are de-fragmenting packets.
52 *
53 * @return true if we are de-fragmenting packets,
54 * false otherwise
55 */
56 bool IsDeFragmenting() const
57 {
58 return m_defragmenting;
59 }
60
61 /**
62 * We have received a first fragmented packet.
63 * We start the deframentation by saving the first fragment.
64 *
65 * @param packet the first fragmented packet
66 */
68 {
70 m_defragmenting = true;
71 m_fragments.push_back(packet);
72 }
73
74 /**
75 * We have received a last fragment of the fragmented packets
76 * (indicated by the no more fragment field).
77 * We re-construct the packet from the fragments we saved
78 * and return the full packet.
79 *
80 * @param packet the last fragment
81 *
82 * @return the fully reconstructed packet
83 */
85 {
87 m_fragments.push_back(packet);
88 m_defragmenting = false;
90 for (auto i = m_fragments.begin(); i != m_fragments.end(); i++)
91 {
92 full->AddAtEnd(*i);
93 }
94 m_fragments.erase(m_fragments.begin(), m_fragments.end());
95 return full;
96 }
97
98 /**
99 * We received a fragmented packet (not first and not last).
100 * We simply save it into our internal list.
101 *
102 * @param packet the received fragment
103 */
105 {
107 m_fragments.push_back(packet);
108 }
109
110 /**
111 * Check if the sequence control (i.e. fragment number) is
112 * in order.
113 *
114 * @param sequenceControl the raw sequence control
115 *
116 * @return true if the sequence control is in order,
117 * false otherwise
118 */
119 bool IsNextFragment(uint16_t sequenceControl) const
120 {
121 return (sequenceControl >> 4) == (m_lastSequenceControl >> 4) &&
122 (sequenceControl & 0x0f) == ((m_lastSequenceControl & 0x0f) + 1);
123 }
124
125 /**
126 * Return the last sequence control we received.
127 *
128 * @return the last sequence control
129 */
130 uint16_t GetLastSequenceControl() const
131 {
133 }
134
135 /**
136 * Set the last sequence control we received.
137 *
138 * @param sequenceControl the last sequence control we received
139 */
140 void SetSequenceControl(uint16_t sequenceControl)
141 {
142 m_lastSequenceControl = sequenceControl;
143 }
144};
145
150
155
156void
162
165{
166 NS_LOG_FUNCTION(*mpdu);
167 const auto& hdr = mpdu->GetOriginal()->GetHeader();
168 const auto source = hdr.GetAddr2();
169 const auto dest = hdr.GetAddr1();
170 if (hdr.IsQosData() && !dest.IsGroup())
171 {
172 /* only for QoS data unicast frames */
173 const auto key = std::make_pair(source, hdr.GetQosTid());
174 auto [it, inserted] = m_qosOriginatorStatus.try_emplace(key);
175 return it->second;
176 }
177 else if (hdr.IsQosData() && dest.IsGroup())
178 {
179 /* for QoS data groupcast frames: use the (nonconcealed) group address as key */
180 const auto groupAddress =
181 hdr.IsQosAmsdu() ? mpdu->begin()->second.GetDestinationAddr() : hdr.GetAddr1();
182 const auto key = std::make_pair(groupAddress, hdr.GetQosTid());
183 auto [it, inserted] = m_qosOriginatorStatus.insert({key, {}});
184 return it->second;
185 }
186 /* - management frames
187 * - QoS data broadcast frames
188 * - non-QoS data frames
189 * see section 7.1.3.4.1
190 */
191 auto [it, inserted] = m_originatorStatus.try_emplace(source);
192 return it->second;
193}
194
195bool
197{
198 NS_LOG_FUNCTION(hdr << &originator);
199 return hdr.IsRetry() && originator.GetLastSequenceControl() == hdr.GetSequenceControl();
200}
201
204 const WifiMacHeader& hdr,
205 OriginatorRxStatus& originator)
206{
207 NS_LOG_FUNCTION(packet << hdr << &originator);
208 if (originator.IsDeFragmenting())
209 {
210 if (hdr.IsMoreFragments())
211 {
212 if (originator.IsNextFragment(hdr.GetSequenceControl()))
213 {
214 NS_LOG_DEBUG("accumulate fragment seq=" << hdr.GetSequenceNumber()
215 << ", frag=" << +hdr.GetFragmentNumber()
216 << ", size=" << packet->GetSize());
217 originator.AccumulateFragment(packet);
218 originator.SetSequenceControl(hdr.GetSequenceControl());
219 }
220 else
221 {
222 NS_LOG_DEBUG("non-ordered fragment");
223 }
224 return nullptr;
225 }
226 else
227 {
228 if (originator.IsNextFragment(hdr.GetSequenceControl()))
229 {
230 NS_LOG_DEBUG("accumulate last fragment seq=" << hdr.GetSequenceNumber() << ", frag="
231 << +hdr.GetFragmentNumber()
232 << ", size=" << hdr.GetSize());
233 Ptr<Packet> p = originator.AccumulateLastFragment(packet);
234 originator.SetSequenceControl(hdr.GetSequenceControl());
235 return p;
236 }
237 else
238 {
239 NS_LOG_DEBUG("non-ordered fragment");
240 return nullptr;
241 }
242 }
243 }
244 else
245 {
246 if (hdr.IsMoreFragments())
247 {
248 NS_LOG_DEBUG("accumulate first fragment seq=" << hdr.GetSequenceNumber()
249 << ", frag=" << +hdr.GetFragmentNumber()
250 << ", size=" << packet->GetSize());
251 originator.AccumulateFirstFragment(packet);
252 originator.SetSequenceControl(hdr.GetSequenceControl());
253 return nullptr;
254 }
255 else
256 {
257 return packet;
258 }
259 }
260}
261
262void
264{
265 NS_LOG_FUNCTION(*mpdu << +linkId);
266 // consider the MAC header of the original MPDU (makes a difference for data frames only)
267 const auto& hdr = mpdu->GetOriginal()->GetHeader();
268 NS_ASSERT(hdr.IsData() || hdr.IsMgt());
269
270 auto& originator = Lookup(mpdu);
271 /**
272 * The check below is really unneeded because it can fail in a lot of
273 * normal cases. Specifically, it is possible for sequence numbers to
274 * loop back to zero once they reach 0xfff0 and to go up to 0xf7f0 in
275 * which case the check below will report the two sequence numbers to
276 * not have the correct order relationship.
277 * So, this check cannot be used to discard old duplicate frames. It is
278 * thus here only for documentation purposes.
279 */
280 if (!(SequenceNumber16(originator.GetLastSequenceControl()) <
281 SequenceNumber16(hdr.GetSequenceControl())))
282 {
283 NS_LOG_DEBUG("Sequence numbers have looped back. last recorded="
284 << originator.GetLastSequenceControl()
285 << " currently seen=" << hdr.GetSequenceControl());
286 }
287 // filter duplicates.
288 if (IsDuplicate(hdr, originator))
289 {
290 NS_LOG_DEBUG("duplicate from=" << hdr.GetAddr2() << ", seq=" << hdr.GetSequenceNumber()
291 << ", frag=" << +hdr.GetFragmentNumber());
292 return;
293 }
294 Ptr<const Packet> aggregate = HandleFragments(mpdu->GetPacket(), hdr, originator);
295 if (!aggregate)
296 {
297 return;
298 }
299 NS_LOG_DEBUG("forwarding data from=" << hdr.GetAddr2() << ", seq=" << hdr.GetSequenceNumber()
300 << ", frag=" << +hdr.GetFragmentNumber());
301 originator.SetSequenceControl(hdr.GetSequenceControl());
302 if (aggregate == mpdu->GetPacket())
303 {
304 m_callback(mpdu, linkId);
305 }
306 else
307 {
308 // We could do this in all cases, but passing the received mpdu in case of
309 // A-MSDUs saves us the time to deaggregate the A-MSDU in MSDUs (which are
310 // kept separate in the received mpdu) and allows us to pass the originally
311 // transmitted packets (i.e., with the same UID) to the receiver.
312 m_callback(Create<WifiMpdu>(aggregate, hdr), linkId);
313 }
314}
315
316} // namespace ns3
void SetForwardCallback(ForwardUpCallback callback)
Set a callback to forward the packet up.
bool IsDuplicate(const WifiMacHeader &hdr, const OriginatorRxStatus &originator) const
Check if we have already received the packet from the sender before (by looking at the sequence contr...
Originators m_originatorStatus
originator status
OriginatorRxStatus & Lookup(Ptr< const WifiMpdu > mpdu)
Look up for OriginatorRxStatus associated with the sender address (by looking at ADDR2 field in the h...
Ptr< const Packet > HandleFragments(Ptr< const Packet > packet, const WifiMacHeader &hdr, OriginatorRxStatus &originator)
Check if the received packet is a fragment and handle it appropriately.
void Receive(Ptr< const WifiMpdu > mpdu, uint8_t linkId)
Receive an MPDU on the given link.
QosOriginators m_qosOriginatorStatus
QOS originator status.
ForwardUpCallback m_callback
forward up callback
A class to keep track of the packet originator status.
void AccumulateFragment(Ptr< const Packet > packet)
We received a fragmented packet (not first and not last).
Ptr< Packet > AccumulateLastFragment(Ptr< const Packet > packet)
We have received a last fragment of the fragmented packets (indicated by the no more fragment field).
Fragments m_fragments
fragments
uint16_t m_lastSequenceControl
last sequence control
void SetSequenceControl(uint16_t sequenceControl)
Set the last sequence control we received.
bool IsDeFragmenting() const
Check if we are de-fragmenting packets.
std::list< Ptr< constPacket > >::const_iterator FragmentsCI
typedef for a const iterator for Fragments
std::list< Ptr< const Packet > > Fragments
typedef for a list of fragments (i.e.
void AccumulateFirstFragment(Ptr< const Packet > packet)
We have received a first fragmented packet.
bool m_defragmenting
flag to indicate whether we are defragmenting
bool IsNextFragment(uint16_t sequenceControl) const
Check if the sequence control (i.e.
uint16_t GetLastSequenceControl() const
Return the last sequence control we received.
Smart pointer class similar to boost::intrusive_ptr.
Generic "sequence number" class.
Implements the IEEE 802.11 MAC header.
uint16_t GetSequenceNumber() const
Return the sequence number of the header.
bool IsMoreFragments() const
Return if the More Fragment bit is set.
uint16_t GetSequenceControl() const
Return the raw Sequence Control field.
bool IsRetry() const
Return if the Retry bit is set.
virtual uint32_t GetSize() const
Return the size of the WifiMacHeader in octets.
uint8_t GetFragmentNumber() const
Return the fragment number of the header.
#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_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition log.h:257
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#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:436
SequenceNumber< uint16_t, int16_t > SequenceNumber16
16 bit Sequence number.
Every class exported by the ns3 library is enclosed in the ns3 namespace.