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