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