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(hdr);
167 const auto source = hdr.GetAddr2();
168 if (hdr.IsQosData() && !source.IsGroup())
169 {
170 /* only for QoS data non-broadcast frames */
171 const auto key = std::make_pair(source, hdr.GetQosTid());
172 auto [it, inserted] = m_qosOriginatorStatus.try_emplace(key);
173 return it->second;
174 }
175 /* - management frames
176 * - QoS data broadcast frames
177 * - non-QoS data frames
178 * see section 7.1.3.4.1
179 */
180 auto [it, inserted] = m_originatorStatus.try_emplace(source);
181 return it->second;
182}
183
184bool
186{
187 NS_LOG_FUNCTION(hdr << &originator);
188 return hdr.IsRetry() && originator.GetLastSequenceControl() == hdr.GetSequenceControl();
189}
190
193 const WifiMacHeader& hdr,
194 OriginatorRxStatus& originator)
195{
196 NS_LOG_FUNCTION(packet << hdr << &originator);
197 if (originator.IsDeFragmenting())
198 {
199 if (hdr.IsMoreFragments())
200 {
201 if (originator.IsNextFragment(hdr.GetSequenceControl()))
202 {
203 NS_LOG_DEBUG("accumulate fragment seq=" << hdr.GetSequenceNumber()
204 << ", frag=" << +hdr.GetFragmentNumber()
205 << ", size=" << packet->GetSize());
206 originator.AccumulateFragment(packet);
207 originator.SetSequenceControl(hdr.GetSequenceControl());
208 }
209 else
210 {
211 NS_LOG_DEBUG("non-ordered fragment");
212 }
213 return nullptr;
214 }
215 else
216 {
217 if (originator.IsNextFragment(hdr.GetSequenceControl()))
218 {
219 NS_LOG_DEBUG("accumulate last fragment seq=" << hdr.GetSequenceNumber() << ", frag="
220 << +hdr.GetFragmentNumber()
221 << ", size=" << hdr.GetSize());
222 Ptr<Packet> p = originator.AccumulateLastFragment(packet);
223 originator.SetSequenceControl(hdr.GetSequenceControl());
224 return p;
225 }
226 else
227 {
228 NS_LOG_DEBUG("non-ordered fragment");
229 return nullptr;
230 }
231 }
232 }
233 else
234 {
235 if (hdr.IsMoreFragments())
236 {
237 NS_LOG_DEBUG("accumulate first fragment seq=" << hdr.GetSequenceNumber()
238 << ", frag=" << +hdr.GetFragmentNumber()
239 << ", size=" << packet->GetSize());
240 originator.AccumulateFirstFragment(packet);
241 originator.SetSequenceControl(hdr.GetSequenceControl());
242 return nullptr;
243 }
244 else
245 {
246 return packet;
247 }
248 }
249}
250
251void
253{
254 NS_LOG_FUNCTION(*mpdu << +linkId);
255 // consider the MAC header of the original MPDU (makes a difference for data frames only)
256 const auto& hdr = mpdu->GetOriginal()->GetHeader();
257 NS_ASSERT(hdr.IsData() || hdr.IsMgt());
258
259 auto& originator = Lookup(hdr);
260 /**
261 * The check below is really unneeded because it can fail in a lot of
262 * normal cases. Specifically, it is possible for sequence numbers to
263 * loop back to zero once they reach 0xfff0 and to go up to 0xf7f0 in
264 * which case the check below will report the two sequence numbers to
265 * not have the correct order relationship.
266 * So, this check cannot be used to discard old duplicate frames. It is
267 * thus here only for documentation purposes.
268 */
269 if (!(SequenceNumber16(originator.GetLastSequenceControl()) <
270 SequenceNumber16(hdr.GetSequenceControl())))
271 {
272 NS_LOG_DEBUG("Sequence numbers have looped back. last recorded="
273 << originator.GetLastSequenceControl()
274 << " currently seen=" << hdr.GetSequenceControl());
275 }
276 // filter duplicates.
277 if (IsDuplicate(hdr, originator))
278 {
279 NS_LOG_DEBUG("duplicate from=" << hdr.GetAddr2() << ", seq=" << hdr.GetSequenceNumber()
280 << ", frag=" << +hdr.GetFragmentNumber());
281 return;
282 }
283 Ptr<const Packet> aggregate = HandleFragments(mpdu->GetPacket(), hdr, originator);
284 if (!aggregate)
285 {
286 return;
287 }
288 NS_LOG_DEBUG("forwarding data from=" << hdr.GetAddr2() << ", seq=" << hdr.GetSequenceNumber()
289 << ", frag=" << +hdr.GetFragmentNumber());
290 if (!hdr.GetAddr1().IsGroup())
291 {
292 originator.SetSequenceControl(hdr.GetSequenceControl());
293 }
294 if (aggregate == mpdu->GetPacket())
295 {
296 m_callback(mpdu, linkId);
297 }
298 else
299 {
300 // We could do this in all cases, but passing the received mpdu in case of
301 // A-MSDUs saves us the time to deaggregate the A-MSDU in MSDUs (which are
302 // kept separate in the received mpdu) and allows us to pass the originally
303 // transmitted packets (i.e., with the same UID) to the receiver.
304 m_callback(Create<WifiMpdu>(aggregate, hdr), linkId);
305 }
306}
307
308} // 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
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
OriginatorRxStatus & Lookup(const WifiMacHeader &hdr)
Look up for OriginatorRxStatus associated with the sender address (by looking at ADDR2 field in the h...
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.
uint8_t GetQosTid() const
Return the Traffic ID of a QoS 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.
Mac48Address GetAddr2() const
Return the address in the Address 2 field.
uint8_t GetFragmentNumber() const
Return the fragment number of the header.
bool IsQosData() const
Return true if the Type is DATA and Subtype is one of the possible values for QoS Data.
#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.