1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3 * Copyright (c) 2013
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: Ghada Badawy <gbadawy@gmail.com>
19 * Stefano Avallone <stavallo@unina.it>
20 */
21
22 #include "ns3/log.h"
23 #include "ns3/packet.h"
24 #include "mpdu-aggregator.h"
25 #include "ampdu-subframe-header.h"
26 #include "wifi-phy.h"
27 #include "wifi-tx-vector.h"
28 #include "wifi-remote-station-manager.h"
29 #include "wifi-mac-queue-item.h"
30 #include "wifi-mac-queue.h"
31 #include "msdu-aggregator.h"
32 #include "wifi-net-device.h"
33 #include "ns3/ht-capabilities.h"
34 #include "ns3/vht-capabilities.h"
35 #include "ns3/he-capabilities.h"
36 #include "regular-wifi-mac.h"
37 #include "ctrl-headers.h"
38 #include "wifi-mac-trailer.h"
39 #include "wifi-tx-parameters.h"
40
41 NS_LOG_COMPONENT_DEFINE ("MpduAggregator");
42
43 namespace ns3 {
44
45 NS_OBJECT_ENSURE_REGISTERED (MpduAggregator);
46
47 TypeId
GetTypeId(void)48 MpduAggregator::GetTypeId (void)
49 {
50 static TypeId tid = TypeId ("ns3::MpduAggregator")
51 .SetParent<Object> ()
52 .SetGroupName ("Wifi")
53 .AddConstructor<MpduAggregator> ()
54 ;
55 return tid;
56 }
57
MpduAggregator()58 MpduAggregator::MpduAggregator ()
59 {
60 }
61
~MpduAggregator()62 MpduAggregator::~MpduAggregator ()
63 {
64 }
65
66 void
DoDispose()67 MpduAggregator::DoDispose ()
68 {
69 m_mac = 0;
70 Object::DoDispose ();
71 }
72
73 void
SetWifiMac(const Ptr<RegularWifiMac> mac)74 MpduAggregator::SetWifiMac (const Ptr<RegularWifiMac> mac)
75 {
76 NS_LOG_FUNCTION (this << mac);
77 m_mac = mac;
78 }
79
80 void
Aggregate(Ptr<const WifiMacQueueItem> mpdu,Ptr<Packet> ampdu,bool isSingle)81 MpduAggregator::Aggregate (Ptr<const WifiMacQueueItem> mpdu, Ptr<Packet> ampdu, bool isSingle)
82 {
83 NS_LOG_FUNCTION (mpdu << ampdu << isSingle);
84 NS_ASSERT (ampdu);
85 // if isSingle is true, then ampdu must be empty
86 NS_ASSERT (!isSingle || ampdu->GetSize () == 0);
87
88 // pad the previous A-MPDU subframe if the A-MPDU is not empty
89 if (ampdu->GetSize () > 0)
90 {
91 uint8_t padding = CalculatePadding (ampdu->GetSize ());
92
93 if (padding)
94 {
95 Ptr<Packet> pad = Create<Packet> (padding);
96 ampdu->AddAtEnd (pad);
97 }
98 }
99
100 // add MPDU header and trailer
101 Ptr<Packet> tmp = mpdu->GetPacket ()->Copy ();
102 tmp->AddHeader (mpdu->GetHeader ());
103 AddWifiMacTrailer (tmp);
104
105 // add A-MPDU subframe header and MPDU to the A-MPDU
106 AmpduSubframeHeader hdr = GetAmpduSubframeHeader (static_cast<uint16_t> (tmp->GetSize ()), isSingle);
107
108 tmp->AddHeader (hdr);
109 ampdu->AddAtEnd (tmp);
110 }
111
112 uint32_t
GetSizeIfAggregated(uint32_t mpduSize,uint32_t ampduSize)113 MpduAggregator::GetSizeIfAggregated (uint32_t mpduSize, uint32_t ampduSize)
114 {
115 NS_LOG_FUNCTION (mpduSize << ampduSize);
116
117 return ampduSize + CalculatePadding (ampduSize) + 4 + mpduSize;
118 }
119
120 uint32_t
GetMaxAmpduSize(Mac48Address recipient,uint8_t tid,WifiModulationClass modulation) const121 MpduAggregator::GetMaxAmpduSize (Mac48Address recipient, uint8_t tid,
122 WifiModulationClass modulation) const
123 {
124 NS_LOG_FUNCTION (this << recipient << +tid << modulation);
125
126 AcIndex ac = QosUtilsMapTidToAc (tid);
127
128 // Find the A-MPDU max size configured on this device
129 uint32_t maxAmpduSize = m_mac->GetMaxAmpduSize (ac);
130
131 if (maxAmpduSize == 0)
132 {
133 NS_LOG_DEBUG ("A-MPDU Aggregation is disabled on this station for AC " << ac);
134 return 0;
135 }
136
137 Ptr<WifiRemoteStationManager> stationManager = m_mac->GetWifiRemoteStationManager ();
138 NS_ASSERT (stationManager);
139
140 // Retrieve the Capabilities elements advertised by the recipient
141 Ptr<const HeCapabilities> heCapabilities = stationManager->GetStationHeCapabilities (recipient);
142 Ptr<const VhtCapabilities> vhtCapabilities = stationManager->GetStationVhtCapabilities (recipient);
143 Ptr<const HtCapabilities> htCapabilities = stationManager->GetStationHtCapabilities (recipient);
144
145 // Determine the constraint imposed by the recipient based on the PPDU
146 // format used to transmit the A-MPDU
147 if (modulation == WIFI_MOD_CLASS_HE)
148 {
149 NS_ABORT_MSG_IF (!heCapabilities, "HE Capabilities element not received");
150
151 maxAmpduSize = std::min (maxAmpduSize, heCapabilities->GetMaxAmpduLength ());
152 }
153 else if (modulation == WIFI_MOD_CLASS_VHT)
154 {
155 NS_ABORT_MSG_IF (!vhtCapabilities, "VHT Capabilities element not received");
156
157 maxAmpduSize = std::min (maxAmpduSize, vhtCapabilities->GetMaxAmpduLength ());
158 }
159 else if (modulation == WIFI_MOD_CLASS_HT)
160 {
161 NS_ABORT_MSG_IF (!htCapabilities, "HT Capabilities element not received");
162
163 maxAmpduSize = std::min (maxAmpduSize, htCapabilities->GetMaxAmpduLength ());
164 }
165 else // non-HT PPDU
166 {
167 NS_LOG_DEBUG ("A-MPDU aggregation is not available for non-HT PHYs");
168
169 maxAmpduSize = 0;
170 }
171
172 return maxAmpduSize;
173 }
174
175 uint8_t
CalculatePadding(uint32_t ampduSize)176 MpduAggregator::CalculatePadding (uint32_t ampduSize)
177 {
178 return (4 - (ampduSize % 4 )) % 4;
179 }
180
181 AmpduSubframeHeader
GetAmpduSubframeHeader(uint16_t mpduSize,bool isSingle)182 MpduAggregator::GetAmpduSubframeHeader (uint16_t mpduSize, bool isSingle)
183 {
184 AmpduSubframeHeader hdr;
185 hdr.SetLength (mpduSize);
186 if (isSingle)
187 {
188 hdr.SetEof (1);
189 }
190 return hdr;
191 }
192
193 std::vector<Ptr<WifiMacQueueItem>>
GetNextAmpdu(Ptr<WifiMacQueueItem> mpdu,WifiTxParameters & txParams,Time availableTime,WifiMacQueueItem::ConstIterator queueIt) const194 MpduAggregator::GetNextAmpdu (Ptr<WifiMacQueueItem> mpdu, WifiTxParameters& txParams,
195 Time availableTime, WifiMacQueueItem::ConstIterator queueIt) const
196 {
197 NS_LOG_FUNCTION (this << *mpdu << &txParams << availableTime);
198
199 std::vector<Ptr<WifiMacQueueItem>> mpduList;
200
201 Mac48Address recipient = mpdu->GetHeader ().GetAddr1 ();
202 NS_ASSERT (mpdu->GetHeader ().IsQosData () && !recipient.IsBroadcast ());
203 uint8_t tid = mpdu->GetHeader ().GetQosTid ();
204
205 Ptr<QosTxop> qosTxop = m_mac->GetQosTxop (tid);
206 NS_ASSERT (qosTxop != 0);
207
208 //Have to make sure that the block ack agreement is established and A-MPDU is enabled
209 if (qosTxop->GetBaAgreementEstablished (recipient, tid)
210 && GetMaxAmpduSize (recipient, tid, txParams.m_txVector.GetModulationClass ()) > 0)
211 {
212 /* here is performed MPDU aggregation */
213 Ptr<WifiMacQueueItem> nextMpdu = mpdu;
214
215 while (nextMpdu != 0)
216 {
217 // if we are here, nextMpdu can be aggregated to the A-MPDU.
218 NS_LOG_DEBUG ("Adding packet with sequence number " << nextMpdu->GetHeader ().GetSequenceNumber ()
219 << " to A-MPDU, packet size = " << nextMpdu->GetSize ()
220 << ", A-MPDU size = " << txParams.GetSize (recipient));
221
222 mpduList.push_back (nextMpdu);
223
224 // If allowed by the BA agreement, get the next MPDU
225 nextMpdu = 0;
226
227 Ptr<const WifiMacQueueItem> peekedMpdu;
228 peekedMpdu = qosTxop->PeekNextMpdu (queueIt, tid, recipient);
229 if (peekedMpdu != 0)
230 {
231 // PeekNextMpdu() does not return an MPDU that is beyond the transmit window
232 NS_ASSERT (IsInWindow (peekedMpdu->GetHeader ().GetSequenceNumber (),
233 qosTxop->GetBaStartingSequence (recipient, tid),
234 qosTxop->GetBaBufferSize (recipient, tid)));
235
236 // get the next MPDU to aggregate, provided that the constraints on size
237 // and duration limit are met. Note that the returned MPDU differs from
238 // the peeked MPDU if A-MSDU aggregation is enabled.
239 NS_LOG_DEBUG ("Trying to aggregate another MPDU");
240 nextMpdu = qosTxop->GetNextMpdu (peekedMpdu, txParams, availableTime, false, queueIt);
241 }
242 }
243
244 if (mpduList.size () == 1)
245 {
246 // return an empty vector if it was not possible to aggregate at least two MPDUs
247 mpduList.clear ();
248 }
249 }
250
251 return mpduList;
252 }
253
254 } //namespace ns3
255