• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "frame.h"
18 
19 #include "hwsim.h"
20 #include "ieee80211.h"
21 
22 #include <asm/byteorder.h>
23 
24 #include <sstream>
25 
26 static constexpr uint64_t kSlotTime = 9;
27 
28 static const AccessCategory kPriorityToAc[8] = {
29     AccessCategory::BestEffort,
30     AccessCategory::Background,
31     AccessCategory::Background,
32     AccessCategory::BestEffort,
33     AccessCategory::Video,
34     AccessCategory::Video,
35     AccessCategory::Voice,
36     AccessCategory::Voice,
37 };
38 
calcContentionWindowMin(AccessCategory ac)39 static uint32_t calcContentionWindowMin(AccessCategory ac) {
40     switch (ac) {
41         case AccessCategory::Voice:
42             return 3;
43         case AccessCategory::Video:
44             return 7;
45         case AccessCategory::BestEffort:
46             return 15;
47         case AccessCategory::Background:
48             return 15;
49     }
50 }
51 
calcContentionWindowMax(AccessCategory ac)52 static uint32_t calcContentionWindowMax(AccessCategory ac) {
53     switch (ac) {
54         case AccessCategory::Voice:
55             return 7;
56         case AccessCategory::Video:
57             return 15;
58         case AccessCategory::BestEffort:
59             return 1023;
60         case AccessCategory::Background:
61             return 1023;
62     }
63 }
64 
frameTypeFromByte(uint8_t byte)65 FrameType frameTypeFromByte(uint8_t byte) {
66     if (byte == static_cast<uint8_t>(FrameType::Ack)) {
67         return FrameType::Ack;
68     } else if (byte == static_cast<uint8_t>(FrameType::Data)) {
69         return FrameType::Data;
70     }
71     return FrameType::Unknown;
72 }
73 
FrameInfo(const MacAddress & transmitter,uint64_t cookie,uint32_t flags,uint32_t channel,const hwsim_tx_rate * rates,size_t numRates)74 FrameInfo::FrameInfo(const MacAddress& transmitter,
75                      uint64_t cookie,
76                      uint32_t flags,
77                      uint32_t channel,
78                      const hwsim_tx_rate* rates,
79                      size_t numRates)
80     : mTransmitter(transmitter)
81     , mCookie(cookie)
82     , mFlags(flags)
83     , mChannel(channel) {
84     size_t i = 0;
85     for (; i < numRates; ++i) {
86         mTxRates[i].count = 0;
87         mTxRates[i].idx = rates[i].idx;
88     }
89     for (; i < mTxRates.size(); ++i) {
90         mTxRates[i].count = 0;
91         mTxRates[i].idx = -1;
92     }
93 }
94 
shouldAck() const95 bool FrameInfo::shouldAck() const {
96     return !!(mFlags & HWSIM_TX_CTL_REQ_TX_STATUS);
97 }
98 
Frame(const uint8_t * data,size_t size)99 Frame::Frame(const uint8_t* data, size_t size) : mData(data, data + size) {
100 }
101 
Frame(const uint8_t * data,size_t size,const MacAddress & transmitter,uint64_t cookie,uint32_t flags,uint32_t channel,const hwsim_tx_rate * rates,size_t numRates)102 Frame::Frame(const uint8_t* data, size_t size, const MacAddress& transmitter,
103              uint64_t cookie, uint32_t flags, uint32_t channel,
104              const hwsim_tx_rate* rates, size_t numRates)
105     : mData(data, data + size)
106     , mInfo(transmitter, cookie, flags, channel, rates, numRates)
107     , mContentionWindow(calcContentionWindowMin(getAc()))
108     , mContentionWindowMax(calcContentionWindowMax(getAc())) {
109     memcpy(mInitialTxRates.data(), rates, numRates * sizeof(*rates));
110 }
111 
incrementAttempts()112 bool Frame::incrementAttempts() {
113     Rates& rates = mInfo.rates();
114     for (size_t i = 0; i < rates.size(); ++i) {
115         if (mInitialTxRates[i].idx == -1) {
116             // We've run out of attempts
117             break;
118         }
119         if (rates[i].count < mInitialTxRates[i].count) {
120             ++rates[i].count;
121             return true;
122         }
123     }
124     return false;
125 }
126 
hasRemainingAttempts()127 bool Frame::hasRemainingAttempts() {
128     Rates& rates = mInfo.rates();
129     for (size_t i = 0; i < rates.size(); ++i) {
130         if (mInitialTxRates[i].idx == -1) {
131             break;
132         }
133         if (rates[i].count < mInitialTxRates[i].count) {
134             return true;
135         }
136     }
137     return false;
138 }
139 
source() const140 const MacAddress& Frame::source() const {
141     auto hdr = reinterpret_cast<const struct ieee80211_hdr*>(mData.data());
142     return *reinterpret_cast<const MacAddress*>(hdr->addr2);
143 }
144 
destination() const145 const MacAddress& Frame::destination() const {
146     auto hdr = reinterpret_cast<const struct ieee80211_hdr*>(mData.data());
147     return *reinterpret_cast<const MacAddress*>(hdr->addr1);
148 }
149 
str() const150 std::string Frame::str() const {
151     uint8_t type = (mData[0] >> 2) & 0x3;
152     uint8_t subType = (mData[0] >> 4) & 0x0F;
153 
154     std::stringstream ss;
155     ss << "[ Ck: " << cookie() << " Ch: " << channel() << " ] ";
156     switch (type) {
157         case 0:
158             // Management
159             ss << "Management (";
160             switch (subType) {
161                 case 0:
162                     ss << "Association Request";
163                     break;
164                 case 1:
165                     ss << "Association Response";
166                     break;
167                 case 2:
168                     ss << "Reassociation Request";
169                     break;
170                 case 3:
171                     ss << "Reassociation Response";
172                     break;
173                 case 4:
174                     ss << "Probe Request";
175                     break;
176                 case 5:
177                     ss << "Probe Response";
178                     break;
179                 case 6:
180                     ss << "Timing Advertisement";
181                     break;
182                 case 8:
183                     ss << "Beacon";
184                     break;
185                 case 9:
186                     ss << "ATIM";
187                     break;
188                 case 10:
189                     ss << "Disassociation";
190                     break;
191                 case 11:
192                     ss << "Authentication";
193                     break;
194                 case 12:
195                     ss << "Deauthentication";
196                     break;
197                 case 13:
198                     ss << "Action";
199                     break;
200                 case 14:
201                     ss << "Action No Ack";
202                     break;
203                 default:
204                     ss << subType;
205                     break;
206             }
207             ss << ')';
208             break;
209         case 1:
210             // Control
211             ss << "Control (";
212             switch (subType) {
213                 case 4:
214                     ss << "Beamforming Report Poll";
215                     break;
216                 case 5:
217                     ss << "VHT NDP Announcement";
218                     break;
219                 case 6:
220                     ss << "Control Frame Extension";
221                     break;
222                 case 7:
223                     ss << "Control Wrapper";
224                     break;
225                 case 8:
226                     ss << "Block Ack Request";
227                     break;
228                 case 9:
229                     ss << "Block Ack";
230                     break;
231                 case 10:
232                     ss << "PS-Poll";
233                     break;
234                 case 11:
235                     ss << "RTS";
236                     break;
237                 case 12:
238                     ss << "CTS";
239                     break;
240                 case 13:
241                     ss << "Ack";
242                     break;
243                 case 14:
244                     ss << "CF-End";
245                     break;
246                 case 15:
247                     ss << "CF-End+CF-Ack";
248                     break;
249                 default:
250                     ss << subType;
251                     break;
252             }
253             ss << ')';
254             break;
255         case 2:
256             // Data
257             ss << "Data (";
258             switch (subType) {
259                 case 0:
260                     ss << "Data";
261                     break;
262                 case 1:
263                     ss << "Data+CF-Ack";
264                     break;
265                 case 2:
266                     ss << "Data+CF-Poll";
267                     break;
268                 case 3:
269                     ss << "Data+CF-Ack+CF-Poll";
270                     break;
271                 case 4:
272                     ss << "Null";
273                     break;
274                 case 5:
275                     ss << "CF-Ack";
276                     break;
277                 case 6:
278                     ss << "CF-Poll";
279                     break;
280                 case 7:
281                     ss << "CF-Ack+CF-Poll";
282                     break;
283                 case 8:
284                     ss << "QoS Data";
285                     break;
286                 case 9:
287                     ss << "QoS Data+CF-Ack";
288                     break;
289                 case 10:
290                     ss << "QoS Data+CF-Poll";
291                     break;
292                 case 11:
293                     ss << "QoS Data+CF-Ack+CF-Poll";
294                     break;
295                 case 12:
296                     ss << "QoS Null";
297                     break;
298                 case 14:
299                     ss << "QoS CF-Poll";
300                     break;
301                 case 15:
302                     ss << "QoS CF-Poll+CF-Ack";
303                     break;
304                 default:
305                     ss << subType;
306                     break;
307             }
308             ss << ')';
309             break;
310         case 3:
311             // Extension
312             ss << "Extension (";
313             switch (subType) {
314                 case 0:
315                     ss << "DMG Beacon";
316                     break;
317                 default:
318                     ss << subType;
319                     break;
320             }
321             ss << ')';
322             break;
323         default:
324             ss << type << " (" << subType << ')';
325             break;
326     }
327     return ss.str();
328 }
329 
isBeacon() const330 bool Frame::isBeacon() const {
331     uint8_t totalType = mData[0] & 0xFC;
332     return totalType == 0x80;
333 }
334 
isData() const335 bool Frame::isData() const {
336     uint8_t totalType = mData[0] & 0x0C;
337     return totalType == 0x08;
338 }
339 
isDataQoS() const340 bool Frame::isDataQoS() const {
341     uint8_t totalType = mData[0] & 0xFC;
342     return totalType == 0x88;
343 }
344 
getQoSControl() const345 uint16_t Frame::getQoSControl() const {
346     // Some frames have 4 address fields instead of 3 which pushes QoS control
347     // forward 6 bytes.
348     bool uses4Addresses = !!(mData[1] & 0x03);
349     const uint8_t* addr = &mData[uses4Addresses ? 30 : 24];
350 
351     return __le16_to_cpu(*reinterpret_cast<const uint16_t*>(addr));
352 }
353 
calcNextTimeout()354 uint64_t Frame::calcNextTimeout() {
355     mNextTimeout = (mContentionWindow * kSlotTime) / 2;
356     mContentionWindow = std::min((mContentionWindow * 2) + 1,
357                                  mContentionWindowMax);
358     return mNextTimeout;
359 }
360 
getAc() const361 AccessCategory Frame::getAc() const {
362     if (!isData()) {
363         return AccessCategory::Voice;
364     }
365     if (!isDataQoS()) {
366         return AccessCategory::BestEffort;
367     }
368     uint16_t priority = getQoSControl() & 0x07;
369     return kPriorityToAc[priority];
370 }
371