1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3 * Copyright (c) 2020 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 "wifi-tx-parameters.h"
22 #include "wifi-mac-queue-item.h"
23 #include "wifi-mac-trailer.h"
24 #include "msdu-aggregator.h"
25 #include "mpdu-aggregator.h"
26 #include "wifi-protection.h"
27 #include "wifi-acknowledgment.h"
28 #include "ns3/packet.h"
29 #include "ns3/log.h"
30
31 namespace ns3 {
32
33 NS_LOG_COMPONENT_DEFINE ("WifiTxParameters");
34
WifiTxParameters()35 WifiTxParameters::WifiTxParameters ()
36 {
37 }
38
WifiTxParameters(const WifiTxParameters & txParams)39 WifiTxParameters::WifiTxParameters (const WifiTxParameters& txParams)
40 {
41 m_txVector = txParams.m_txVector;
42 m_protection = (txParams.m_protection ? txParams.m_protection->Copy () : nullptr);
43 m_acknowledgment = (txParams.m_acknowledgment ? txParams.m_acknowledgment->Copy () : nullptr);
44 m_txDuration = txParams.m_txDuration;
45 m_info = txParams.m_info;
46 }
47
48 WifiTxParameters&
operator =(const WifiTxParameters & txParams)49 WifiTxParameters::operator= (const WifiTxParameters& txParams)
50 {
51 // check for self-assignment
52 if (&txParams == this)
53 {
54 return *this;
55 }
56
57 m_txVector = txParams.m_txVector;
58 m_protection = (txParams.m_protection ? txParams.m_protection->Copy () : nullptr);
59 m_acknowledgment = (txParams.m_acknowledgment ? txParams.m_acknowledgment->Copy () : nullptr);
60 m_txDuration = txParams.m_txDuration;
61 m_info = txParams.m_info;
62
63 return *this;
64 }
65
66 void
Clear(void)67 WifiTxParameters::Clear (void)
68 {
69 NS_LOG_FUNCTION (this);
70
71 // Reset the current info
72 m_info.clear ();
73 m_txVector = WifiTxVector ();
74 m_protection.reset (nullptr);
75 m_acknowledgment.reset (nullptr);
76 m_txDuration = Time::Min ();
77 }
78
79 const WifiTxParameters::PsduInfo*
GetPsduInfo(Mac48Address receiver) const80 WifiTxParameters::GetPsduInfo (Mac48Address receiver) const
81 {
82 auto infoIt = m_info.find (receiver);
83
84 if (infoIt == m_info.end ())
85 {
86 return nullptr;
87 }
88 return &infoIt->second;
89 }
90
91 const WifiTxParameters::PsduInfoMap&
GetPsduInfoMap(void) const92 WifiTxParameters::GetPsduInfoMap (void) const
93 {
94 return m_info;
95 }
96
97 void
AddMpdu(Ptr<const WifiMacQueueItem> mpdu)98 WifiTxParameters::AddMpdu (Ptr<const WifiMacQueueItem> mpdu)
99 {
100 NS_LOG_FUNCTION (this << *mpdu);
101
102 const WifiMacHeader& hdr = mpdu->GetHeader ();
103
104 auto infoIt = m_info.find (hdr.GetAddr1 ());
105
106 if (infoIt == m_info.end ())
107 {
108 // this is an MPDU starting a new PSDU
109 std::map<uint8_t, std::set<uint16_t>> seqNumbers;
110 if (hdr.IsQosData ())
111 {
112 seqNumbers[hdr.GetQosTid ()] = {hdr.GetSequenceNumber ()};
113 }
114
115 // Insert the info about the given frame
116 m_info.emplace (hdr.GetAddr1 (),
117 PsduInfo {hdr, mpdu->GetPacketSize (), 0, seqNumbers});
118 return;
119 }
120
121 // a PSDU for the receiver of the given MPDU is already being built
122 NS_ASSERT_MSG ((hdr.IsQosData () && !hdr.HasData ()) || infoIt->second.amsduSize > 0,
123 "An MPDU can only be aggregated to an existing (A-)MPDU");
124
125 // The (A-)MSDU being built is included in an A-MPDU subframe
126 infoIt->second.ampduSize = MpduAggregator::GetSizeIfAggregated (infoIt->second.header.GetSize ()
127 + infoIt->second.amsduSize
128 + WIFI_MAC_FCS_LENGTH,
129 infoIt->second.ampduSize);
130 infoIt->second.header = hdr;
131 infoIt->second.amsduSize = mpdu->GetPacketSize ();
132
133 if (hdr.IsQosData ())
134 {
135 auto ret = infoIt->second.seqNumbers.emplace (hdr.GetQosTid (),
136 std::set<uint16_t> {hdr.GetSequenceNumber ()});
137
138 if (!ret.second)
139 {
140 // insertion did not happen because an entry with the same TID already exists
141 ret.first->second.insert (hdr.GetSequenceNumber ());
142 }
143 }
144 }
145
146 uint32_t
GetSizeIfAddMpdu(Ptr<const WifiMacQueueItem> mpdu) const147 WifiTxParameters::GetSizeIfAddMpdu (Ptr<const WifiMacQueueItem> mpdu) const
148 {
149 NS_LOG_FUNCTION (this << *mpdu);
150
151 auto infoIt = m_info.find (mpdu->GetHeader ().GetAddr1 ());
152
153 if (infoIt == m_info.end ())
154 {
155 // this is an MPDU starting a new PSDU
156 if (m_txVector.GetModulationClass () >= WIFI_MOD_CLASS_VHT)
157 {
158 // All MPDUs are sent with the A-MPDU structure
159 return MpduAggregator::GetSizeIfAggregated (mpdu->GetSize (), 0);
160 }
161 return mpdu->GetSize ();
162 }
163
164 // aggregate the (A-)MSDU being built to the existing A-MPDU (if any)
165 uint32_t ampduSize = MpduAggregator::GetSizeIfAggregated (infoIt->second.header.GetSize ()
166 + infoIt->second.amsduSize
167 + WIFI_MAC_FCS_LENGTH,
168 infoIt->second.ampduSize);
169 // aggregate the new MPDU to the A-MPDU
170 return MpduAggregator::GetSizeIfAggregated (mpdu->GetSize (), ampduSize);
171 }
172
173 void
AggregateMsdu(Ptr<const WifiMacQueueItem> msdu)174 WifiTxParameters::AggregateMsdu (Ptr<const WifiMacQueueItem> msdu)
175 {
176 NS_LOG_FUNCTION (this << *msdu);
177
178 auto infoIt = m_info.find (msdu->GetHeader ().GetAddr1 ());
179 NS_ASSERT_MSG (infoIt != m_info.end (),
180 "There must be already an MPDU addressed to the same receiver");
181
182 infoIt->second.amsduSize = GetSizeIfAggregateMsdu (msdu).first;
183 infoIt->second.header.SetQosAmsdu ();
184 }
185
186 std::pair<uint32_t, uint32_t>
GetSizeIfAggregateMsdu(Ptr<const WifiMacQueueItem> msdu) const187 WifiTxParameters::GetSizeIfAggregateMsdu (Ptr<const WifiMacQueueItem> msdu) const
188 {
189 NS_LOG_FUNCTION (this << *msdu);
190
191 NS_ASSERT_MSG (msdu->GetHeader ().IsQosData (), "Can only aggregate a QoS data frame to an A-MSDU");
192
193 auto infoIt = m_info.find (msdu->GetHeader ().GetAddr1 ());
194 NS_ASSERT_MSG (infoIt != m_info.end (),
195 "There must be already an MPDU addressed to the same receiver");
196
197 NS_ASSERT_MSG (infoIt->second.amsduSize > 0,
198 "The amsduSize should be set to the size of the previous MSDU(s)");
199 NS_ASSERT_MSG (infoIt->second.header.IsQosData (),
200 "The MPDU being built for this receiver must be a QoS data frame");
201 NS_ASSERT_MSG (infoIt->second.header.GetQosTid () == msdu->GetHeader ().GetQosTid (),
202 "The MPDU being built must belong to the same TID as the MSDU to aggregate");
203 NS_ASSERT_MSG (infoIt->second.seqNumbers.find (msdu->GetHeader ().GetQosTid ()) != infoIt->second.seqNumbers.end (),
204 "At least one MPDU with the same TID must have been added previously");
205
206 // all checks passed
207 uint32_t currAmsduSize = infoIt->second.amsduSize;
208
209 if (!infoIt->second.header.IsQosAmsdu ())
210 {
211 // consider the A-MSDU subframe for the first MSDU
212 currAmsduSize = MsduAggregator::GetSizeIfAggregated (currAmsduSize, 0);
213 }
214
215 uint32_t newAmsduSize = MsduAggregator::GetSizeIfAggregated (msdu->GetPacket ()->GetSize (), currAmsduSize);
216 uint32_t newMpduSize = infoIt->second.header.GetSize () + newAmsduSize + WIFI_MAC_FCS_LENGTH;
217
218 if (infoIt->second.ampduSize > 0 || m_txVector.GetModulationClass () >= WIFI_MOD_CLASS_VHT)
219 {
220 return {newAmsduSize, MpduAggregator::GetSizeIfAggregated (newMpduSize, infoIt->second.ampduSize)};
221 }
222
223 return {newAmsduSize, newMpduSize};
224 }
225
226 uint32_t
GetSize(Mac48Address receiver) const227 WifiTxParameters::GetSize (Mac48Address receiver) const
228 {
229 NS_LOG_FUNCTION (this << receiver);
230
231 auto infoIt = m_info.find (receiver);
232
233 if (infoIt == m_info.end ())
234 {
235 return 0;
236 }
237
238 uint32_t newMpduSize = infoIt->second.header.GetSize () + infoIt->second.amsduSize + WIFI_MAC_FCS_LENGTH;
239
240 if (infoIt->second.ampduSize > 0 || m_txVector.GetModulationClass () >= WIFI_MOD_CLASS_VHT)
241 {
242 return MpduAggregator::GetSizeIfAggregated (newMpduSize, infoIt->second.ampduSize);
243 }
244
245 return newMpduSize;
246 }
247
248 void
Print(std::ostream & os) const249 WifiTxParameters::Print (std::ostream& os) const
250 {
251 os << "TXVECTOR=" << m_txVector;
252 if (m_protection)
253 {
254 os << ", Protection=" << m_protection.get ();
255 }
256 if (m_acknowledgment)
257 {
258 os << ", Acknowledgment=" << m_acknowledgment.get ();
259 }
260 os << ", PSDUs:";
261 for (const auto& info : m_info)
262 {
263 os << " [To=" << info.second.header.GetAddr1 () << ", A-MSDU size="
264 << info.second.amsduSize << ", A-MPDU size=" << info.second.ampduSize << "]";
265 }
266 }
267
operator <<(std::ostream & os,const WifiTxParameters * txParams)268 std::ostream & operator << (std::ostream &os, const WifiTxParameters* txParams)
269 {
270 txParams->Print (os);
271 return os;
272 }
273
274 } //namespace ns3
275