wlan - Update wlan from Adrian / FreeBSD
[dragonfly.git] / sys / netproto / 802_11 / wlan / ieee80211_phy.c
CommitLineData
32176cfd
RP
1/*-
2 * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32176cfd
RP
24 */
25
085ff963
MD
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD$");
28
32176cfd
RP
29/*
30 * IEEE 802.11 PHY-related support.
31 */
32
33#include "opt_inet.h"
34
35#include <sys/param.h>
36#include <sys/kernel.h>
37#include <sys/systm.h>
085ff963 38#include <sys/malloc.h>
32176cfd
RP
39
40#include <sys/socket.h>
41
42#include <net/if.h>
43#include <net/if_media.h>
085ff963
MD
44
45#include <net/ethernet.h>
32176cfd
RP
46#include <net/route.h>
47
48#include <netproto/802_11/ieee80211_var.h>
49#include <netproto/802_11/ieee80211_phy.h>
50
51#ifdef notyet
52struct ieee80211_ds_plcp_hdr {
53 uint8_t i_signal;
54 uint8_t i_service;
55 uint16_t i_length;
56 uint16_t i_crc;
57} __packed;
58
59#endif /* notyet */
60
61/* shorthands to compact tables for readability */
62#define OFDM IEEE80211_T_OFDM
63#define CCK IEEE80211_T_CCK
64#define TURBO IEEE80211_T_TURBO
65#define HALF IEEE80211_T_OFDM_HALF
66#define QUART IEEE80211_T_OFDM_QUARTER
085ff963
MD
67#define HT IEEE80211_T_HT
68/* XXX the 11n and the basic rate flag are unfortunately overlapping. Grr. */
69#define N(r) (IEEE80211_RATE_MCS | r)
32176cfd 70#define PBCC (IEEE80211_T_OFDM_QUARTER+1) /* XXX */
085ff963 71#define B(r) (IEEE80211_RATE_BASIC | r)
32176cfd
RP
72#define Mb(x) (x*1000)
73
74static struct ieee80211_rate_table ieee80211_11b_table = {
75 .rateCount = 4, /* XXX no PBCC */
76 .info = {
77/* short ctrl */
78/* Preamble dot11Rate Rate */
79 [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },/* 1 Mb */
80 [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },/* 2 Mb */
81 [2] = { .phy = CCK, 5500, 0x04, B(11), 1 },/* 5.5 Mb */
82 [3] = { .phy = CCK, 11000, 0x04, B(22), 1 },/* 11 Mb */
83 [4] = { .phy = PBCC, 22000, 0x04, 44, 3 } /* 22 Mb */
84 },
85};
86
87static struct ieee80211_rate_table ieee80211_11g_table = {
88 .rateCount = 12,
89 .info = {
90/* short ctrl */
91/* Preamble dot11Rate Rate */
92 [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },
93 [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },
94 [2] = { .phy = CCK, 5500, 0x04, B(11), 2 },
95 [3] = { .phy = CCK, 11000, 0x04, B(22), 3 },
96 [4] = { .phy = OFDM, 6000, 0x00, 12, 4 },
97 [5] = { .phy = OFDM, 9000, 0x00, 18, 4 },
98 [6] = { .phy = OFDM, 12000, 0x00, 24, 6 },
99 [7] = { .phy = OFDM, 18000, 0x00, 36, 6 },
100 [8] = { .phy = OFDM, 24000, 0x00, 48, 8 },
101 [9] = { .phy = OFDM, 36000, 0x00, 72, 8 },
102 [10] = { .phy = OFDM, 48000, 0x00, 96, 8 },
103 [11] = { .phy = OFDM, 54000, 0x00, 108, 8 }
104 },
105};
106
107static struct ieee80211_rate_table ieee80211_11a_table = {
108 .rateCount = 8,
109 .info = {
110/* short ctrl */
111/* Preamble dot11Rate Rate */
112 [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 },
113 [1] = { .phy = OFDM, 9000, 0x00, 18, 0 },
114 [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 },
115 [3] = { .phy = OFDM, 18000, 0x00, 36, 2 },
116 [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 },
117 [5] = { .phy = OFDM, 36000, 0x00, 72, 4 },
118 [6] = { .phy = OFDM, 48000, 0x00, 96, 4 },
119 [7] = { .phy = OFDM, 54000, 0x00, 108, 4 }
120 },
121};
122
123static struct ieee80211_rate_table ieee80211_half_table = {
124 .rateCount = 8,
125 .info = {
126/* short ctrl */
127/* Preamble dot11Rate Rate */
128 [0] = { .phy = HALF, 3000, 0x00, B(6), 0 },
129 [1] = { .phy = HALF, 4500, 0x00, 9, 0 },
130 [2] = { .phy = HALF, 6000, 0x00, B(12), 2 },
131 [3] = { .phy = HALF, 9000, 0x00, 18, 2 },
132 [4] = { .phy = HALF, 12000, 0x00, B(24), 4 },
133 [5] = { .phy = HALF, 18000, 0x00, 36, 4 },
134 [6] = { .phy = HALF, 24000, 0x00, 48, 4 },
135 [7] = { .phy = HALF, 27000, 0x00, 54, 4 }
136 },
137};
138
139static struct ieee80211_rate_table ieee80211_quarter_table = {
140 .rateCount = 8,
141 .info = {
142/* short ctrl */
143/* Preamble dot11Rate Rate */
144 [0] = { .phy = QUART, 1500, 0x00, B(3), 0 },
145 [1] = { .phy = QUART, 2250, 0x00, 4, 0 },
146 [2] = { .phy = QUART, 3000, 0x00, B(9), 2 },
147 [3] = { .phy = QUART, 4500, 0x00, 9, 2 },
148 [4] = { .phy = QUART, 6000, 0x00, B(12), 4 },
149 [5] = { .phy = QUART, 9000, 0x00, 18, 4 },
150 [6] = { .phy = QUART, 12000, 0x00, 24, 4 },
151 [7] = { .phy = QUART, 13500, 0x00, 27, 4 }
152 },
153};
154
155static struct ieee80211_rate_table ieee80211_turbog_table = {
156 .rateCount = 7,
157 .info = {
158/* short ctrl */
159/* Preamble dot11Rate Rate */
160 [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 },
161 [1] = { .phy = TURBO, 24000, 0x00, B(24), 1 },
162 [2] = { .phy = TURBO, 36000, 0x00, 36, 1 },
163 [3] = { .phy = TURBO, 48000, 0x00, B(48), 3 },
164 [4] = { .phy = TURBO, 72000, 0x00, 72, 3 },
165 [5] = { .phy = TURBO, 96000, 0x00, 96, 3 },
166 [6] = { .phy = TURBO, 108000, 0x00, 108, 3 }
167 },
168};
169
170static struct ieee80211_rate_table ieee80211_turboa_table = {
171 .rateCount = 8,
172 .info = {
173/* short ctrl */
174/* Preamble dot11Rate Rate */
175 [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 },
176 [1] = { .phy = TURBO, 18000, 0x00, 18, 0 },
177 [2] = { .phy = TURBO, 24000, 0x00, B(24), 2 },
178 [3] = { .phy = TURBO, 36000, 0x00, 36, 2 },
179 [4] = { .phy = TURBO, 48000, 0x00, B(48), 4 },
180 [5] = { .phy = TURBO, 72000, 0x00, 72, 4 },
181 [6] = { .phy = TURBO, 96000, 0x00, 96, 4 },
182 [7] = { .phy = TURBO, 108000, 0x00, 108, 4 }
183 },
184};
185
085ff963
MD
186static struct ieee80211_rate_table ieee80211_11ng_table = {
187 .rateCount = 36,
188 .info = {
189/* short ctrl */
190/* Preamble dot11Rate Rate */
191 [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },
192 [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },
193 [2] = { .phy = CCK, 5500, 0x04, B(11), 2 },
194 [3] = { .phy = CCK, 11000, 0x04, B(22), 3 },
195 [4] = { .phy = OFDM, 6000, 0x00, 12, 4 },
196 [5] = { .phy = OFDM, 9000, 0x00, 18, 4 },
197 [6] = { .phy = OFDM, 12000, 0x00, 24, 6 },
198 [7] = { .phy = OFDM, 18000, 0x00, 36, 6 },
199 [8] = { .phy = OFDM, 24000, 0x00, 48, 8 },
200 [9] = { .phy = OFDM, 36000, 0x00, 72, 8 },
201 [10] = { .phy = OFDM, 48000, 0x00, 96, 8 },
202 [11] = { .phy = OFDM, 54000, 0x00, 108, 8 },
203
204 [12] = { .phy = HT, 6500, 0x00, N(0), 4 },
205 [13] = { .phy = HT, 13000, 0x00, N(1), 6 },
206 [14] = { .phy = HT, 19500, 0x00, N(2), 6 },
207 [15] = { .phy = HT, 26000, 0x00, N(3), 8 },
208 [16] = { .phy = HT, 39000, 0x00, N(4), 8 },
209 [17] = { .phy = HT, 52000, 0x00, N(5), 8 },
210 [18] = { .phy = HT, 58500, 0x00, N(6), 8 },
211 [19] = { .phy = HT, 65000, 0x00, N(7), 8 },
212
213 [20] = { .phy = HT, 13000, 0x00, N(8), 4 },
214 [21] = { .phy = HT, 26000, 0x00, N(9), 6 },
215 [22] = { .phy = HT, 39000, 0x00, N(10), 6 },
216 [23] = { .phy = HT, 52000, 0x00, N(11), 8 },
217 [24] = { .phy = HT, 78000, 0x00, N(12), 8 },
218 [25] = { .phy = HT, 104000, 0x00, N(13), 8 },
219 [26] = { .phy = HT, 117000, 0x00, N(14), 8 },
220 [27] = { .phy = HT, 130000, 0x00, N(15), 8 },
221
222 [28] = { .phy = HT, 19500, 0x00, N(16), 4 },
223 [29] = { .phy = HT, 39000, 0x00, N(17), 6 },
224 [30] = { .phy = HT, 58500, 0x00, N(18), 6 },
225 [31] = { .phy = HT, 78000, 0x00, N(19), 8 },
226 [32] = { .phy = HT, 117000, 0x00, N(20), 8 },
227 [33] = { .phy = HT, 156000, 0x00, N(21), 8 },
228 [34] = { .phy = HT, 175500, 0x00, N(22), 8 },
229 [35] = { .phy = HT, 195000, 0x00, N(23), 8 },
230
231 },
232};
233
234static struct ieee80211_rate_table ieee80211_11na_table = {
235 .rateCount = 32,
236 .info = {
237/* short ctrl */
238/* Preamble dot11Rate Rate */
239 [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 },
240 [1] = { .phy = OFDM, 9000, 0x00, 18, 0 },
241 [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 },
242 [3] = { .phy = OFDM, 18000, 0x00, 36, 2 },
243 [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 },
244 [5] = { .phy = OFDM, 36000, 0x00, 72, 4 },
245 [6] = { .phy = OFDM, 48000, 0x00, 96, 4 },
246 [7] = { .phy = OFDM, 54000, 0x00, 108, 4 },
247
248 [8] = { .phy = HT, 6500, 0x00, N(0), 0 },
249 [9] = { .phy = HT, 13000, 0x00, N(1), 2 },
250 [10] = { .phy = HT, 19500, 0x00, N(2), 2 },
251 [11] = { .phy = HT, 26000, 0x00, N(3), 4 },
252 [12] = { .phy = HT, 39000, 0x00, N(4), 4 },
253 [13] = { .phy = HT, 52000, 0x00, N(5), 4 },
254 [14] = { .phy = HT, 58500, 0x00, N(6), 4 },
255 [15] = { .phy = HT, 65000, 0x00, N(7), 4 },
256
257 [16] = { .phy = HT, 13000, 0x00, N(8), 0 },
258 [17] = { .phy = HT, 26000, 0x00, N(9), 2 },
259 [18] = { .phy = HT, 39000, 0x00, N(10), 2 },
260 [19] = { .phy = HT, 52000, 0x00, N(11), 4 },
261 [20] = { .phy = HT, 78000, 0x00, N(12), 4 },
262 [21] = { .phy = HT, 104000, 0x00, N(13), 4 },
263 [22] = { .phy = HT, 117000, 0x00, N(14), 4 },
264 [23] = { .phy = HT, 130000, 0x00, N(15), 4 },
265
266 [24] = { .phy = HT, 19500, 0x00, N(16), 0 },
267 [25] = { .phy = HT, 39000, 0x00, N(17), 2 },
268 [26] = { .phy = HT, 58500, 0x00, N(18), 2 },
269 [27] = { .phy = HT, 78000, 0x00, N(19), 4 },
270 [28] = { .phy = HT, 117000, 0x00, N(20), 4 },
271 [29] = { .phy = HT, 156000, 0x00, N(21), 4 },
272 [30] = { .phy = HT, 175500, 0x00, N(22), 4 },
273 [31] = { .phy = HT, 195000, 0x00, N(23), 4 },
274
275 },
276};
277
32176cfd
RP
278#undef Mb
279#undef B
280#undef OFDM
281#undef HALF
282#undef QUART
283#undef CCK
284#undef TURBO
285#undef XR
085ff963
MD
286#undef HT
287#undef N
32176cfd
RP
288
289/*
290 * Setup a rate table's reverse lookup table and fill in
291 * ack durations. The reverse lookup tables are assumed
292 * to be initialized to zero (or at least the first entry).
293 * We use this as a key that indicates whether or not
294 * we've previously setup the reverse lookup table.
295 *
296 * XXX not reentrant, but shouldn't matter
297 */
298static void
299ieee80211_setup_ratetable(struct ieee80211_rate_table *rt)
300{
32176cfd
RP
301#define WLAN_CTRL_FRAME_SIZE \
302 (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
303
304 int i;
305
085ff963 306 for (i = 0; i < nitems(rt->rateCodeToIndex); i++)
32176cfd
RP
307 rt->rateCodeToIndex[i] = (uint8_t) -1;
308 for (i = 0; i < rt->rateCount; i++) {
309 uint8_t code = rt->info[i].dot11Rate;
310 uint8_t cix = rt->info[i].ctlRateIndex;
311 uint8_t ctl_rate = rt->info[cix].dot11Rate;
312
085ff963
MD
313 /*
314 * Map without the basic rate bit.
315 *
316 * It's up to the caller to ensure that the basic
317 * rate bit is stripped here.
318 *
319 * For HT, use the MCS rate bit.
320 */
321 code &= IEEE80211_RATE_VAL;
322 if (rt->info[i].phy == IEEE80211_T_HT) {
323 code |= IEEE80211_RATE_MCS;
32176cfd
RP
324 }
325
085ff963
MD
326 /* XXX assume the control rate is non-MCS? */
327 ctl_rate &= IEEE80211_RATE_VAL;
328 rt->rateCodeToIndex[code] = i;
329
32176cfd
RP
330 /*
331 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
332 * depends on whether they are marked as basic rates;
333 * the static tables are setup with an 11b-compatible
334 * 2Mb/s rate which will work but is suboptimal
335 *
336 * NB: Control rate is always less than or equal to the
337 * current rate, so control rate's reverse lookup entry
338 * has been installed and following call is safe.
339 */
340 rt->info[i].lpAckDuration = ieee80211_compute_duration(rt,
341 WLAN_CTRL_FRAME_SIZE, ctl_rate, 0);
342 rt->info[i].spAckDuration = ieee80211_compute_duration(rt,
343 WLAN_CTRL_FRAME_SIZE, ctl_rate, IEEE80211_F_SHPREAMBLE);
344 }
345
346#undef WLAN_CTRL_FRAME_SIZE
32176cfd
RP
347}
348
349/* Setup all rate tables */
350static void
351ieee80211_phy_init(void)
352{
32176cfd
RP
353 static struct ieee80211_rate_table * const ratetables[] = {
354 &ieee80211_half_table,
355 &ieee80211_quarter_table,
085ff963
MD
356 &ieee80211_11na_table,
357 &ieee80211_11ng_table,
32176cfd
RP
358 &ieee80211_turbog_table,
359 &ieee80211_turboa_table,
32176cfd
RP
360 &ieee80211_11a_table,
361 &ieee80211_11g_table,
362 &ieee80211_11b_table
363 };
364 int i;
365
085ff963 366 for (i = 0; i < nitems(ratetables); ++i)
32176cfd
RP
367 ieee80211_setup_ratetable(ratetables[i]);
368
32176cfd
RP
369}
370SYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL);
371
372const struct ieee80211_rate_table *
373ieee80211_get_ratetable(struct ieee80211_channel *c)
374{
375 const struct ieee80211_rate_table *rt;
376
377 /* XXX HT */
378 if (IEEE80211_IS_CHAN_HALF(c))
379 rt = &ieee80211_half_table;
380 else if (IEEE80211_IS_CHAN_QUARTER(c))
381 rt = &ieee80211_quarter_table;
382 else if (IEEE80211_IS_CHAN_HTA(c))
085ff963 383 rt = &ieee80211_11na_table;
32176cfd 384 else if (IEEE80211_IS_CHAN_HTG(c))
085ff963 385 rt = &ieee80211_11ng_table;
32176cfd
RP
386 else if (IEEE80211_IS_CHAN_108G(c))
387 rt = &ieee80211_turbog_table;
388 else if (IEEE80211_IS_CHAN_ST(c))
389 rt = &ieee80211_turboa_table;
390 else if (IEEE80211_IS_CHAN_TURBO(c))
391 rt = &ieee80211_turboa_table;
392 else if (IEEE80211_IS_CHAN_A(c))
393 rt = &ieee80211_11a_table;
394 else if (IEEE80211_IS_CHAN_ANYG(c))
395 rt = &ieee80211_11g_table;
396 else if (IEEE80211_IS_CHAN_B(c))
397 rt = &ieee80211_11b_table;
398 else {
399 /* NB: should not get here */
085ff963 400 panic("%s: no rate table for channel; freq %u flags 0x%x\n",
32176cfd
RP
401 __func__, c->ic_freq, c->ic_flags);
402 }
403 return rt;
404}
405
406/*
407 * Convert PLCP signal/rate field to 802.11 rate (.5Mbits/s)
408 *
409 * Note we do no parameter checking; this routine is mainly
410 * used to derive an 802.11 rate for constructing radiotap
411 * header data for rx frames.
412 *
413 * XXX might be a candidate for inline
414 */
415uint8_t
416ieee80211_plcp2rate(uint8_t plcp, enum ieee80211_phytype type)
417{
418 if (type == IEEE80211_T_OFDM) {
419 static const uint8_t ofdm_plcp2rate[16] = {
420 [0xb] = 12,
421 [0xf] = 18,
422 [0xa] = 24,
423 [0xe] = 36,
424 [0x9] = 48,
425 [0xd] = 72,
426 [0x8] = 96,
427 [0xc] = 108
428 };
429 return ofdm_plcp2rate[plcp & 0xf];
430 }
431 if (type == IEEE80211_T_CCK) {
432 static const uint8_t cck_plcp2rate[16] = {
433 [0xa] = 2, /* 0x0a */
434 [0x4] = 4, /* 0x14 */
435 [0x7] = 11, /* 0x37 */
436 [0xe] = 22, /* 0x6e */
437 [0xc] = 44, /* 0xdc , actually PBCC */
438 };
439 return cck_plcp2rate[plcp & 0xf];
440 }
441 return 0;
442}
443
444/*
445 * Covert 802.11 rate to PLCP signal.
446 */
447uint8_t
448ieee80211_rate2plcp(int rate, enum ieee80211_phytype type)
449{
450 /* XXX ignore type for now since rates are unique */
451 switch (rate) {
452 /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
453 case 12: return 0xb;
454 case 18: return 0xf;
455 case 24: return 0xa;
456 case 36: return 0xe;
457 case 48: return 0x9;
458 case 72: return 0xd;
459 case 96: return 0x8;
460 case 108: return 0xc;
461 /* CCK rates (IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3) */
462 case 2: return 10;
463 case 4: return 20;
464 case 11: return 55;
465 case 22: return 110;
466 /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */
467 case 44: return 220;
468 }
469 return 0; /* XXX unsupported/unknown rate */
470}
471
472#define CCK_SIFS_TIME 10
473#define CCK_PREAMBLE_BITS 144
474#define CCK_PLCP_BITS 48
475
476#define OFDM_SIFS_TIME 16
477#define OFDM_PREAMBLE_TIME 20
478#define OFDM_PLCP_BITS 22
479#define OFDM_SYMBOL_TIME 4
480
481#define OFDM_HALF_SIFS_TIME 32
482#define OFDM_HALF_PREAMBLE_TIME 40
483#define OFDM_HALF_PLCP_BITS 22
484#define OFDM_HALF_SYMBOL_TIME 8
485
486#define OFDM_QUARTER_SIFS_TIME 64
487#define OFDM_QUARTER_PREAMBLE_TIME 80
488#define OFDM_QUARTER_PLCP_BITS 22
489#define OFDM_QUARTER_SYMBOL_TIME 16
490
491#define TURBO_SIFS_TIME 8
492#define TURBO_PREAMBLE_TIME 14
493#define TURBO_PLCP_BITS 22
494#define TURBO_SYMBOL_TIME 4
495
496/*
497 * Compute the time to transmit a frame of length frameLen bytes
498 * using the specified rate, phy, and short preamble setting.
499 * SIFS is included.
500 */
501uint16_t
502ieee80211_compute_duration(const struct ieee80211_rate_table *rt,
503 uint32_t frameLen, uint16_t rate, int isShortPreamble)
504{
505 uint8_t rix = rt->rateCodeToIndex[rate];
506 uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
507 uint32_t kbps;
508
509 KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate));
510 kbps = rt->info[rix].rateKbps;
511 if (kbps == 0) /* XXX bandaid for channel changes */
512 return 0;
513
514 switch (rt->info[rix].phy) {
515 case IEEE80211_T_CCK:
516 phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
517 if (isShortPreamble && rt->info[rix].shortPreamble)
518 phyTime >>= 1;
519 numBits = frameLen << 3;
520 txTime = CCK_SIFS_TIME + phyTime
521 + ((numBits * 1000)/kbps);
522 break;
523 case IEEE80211_T_OFDM:
524 bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
525 KASSERT(bitsPerSymbol != 0, ("full rate bps"));
526
527 numBits = OFDM_PLCP_BITS + (frameLen << 3);
528 numSymbols = howmany(numBits, bitsPerSymbol);
529 txTime = OFDM_SIFS_TIME
530 + OFDM_PREAMBLE_TIME
531 + (numSymbols * OFDM_SYMBOL_TIME);
532 break;
533 case IEEE80211_T_OFDM_HALF:
534 bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
535 KASSERT(bitsPerSymbol != 0, ("1/4 rate bps"));
536
537 numBits = OFDM_PLCP_BITS + (frameLen << 3);
538 numSymbols = howmany(numBits, bitsPerSymbol);
539 txTime = OFDM_HALF_SIFS_TIME
540 + OFDM_HALF_PREAMBLE_TIME
541 + (numSymbols * OFDM_HALF_SYMBOL_TIME);
542 break;
543 case IEEE80211_T_OFDM_QUARTER:
544 bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
545 KASSERT(bitsPerSymbol != 0, ("1/2 rate bps"));
546
547 numBits = OFDM_PLCP_BITS + (frameLen << 3);
548 numSymbols = howmany(numBits, bitsPerSymbol);
549 txTime = OFDM_QUARTER_SIFS_TIME
550 + OFDM_QUARTER_PREAMBLE_TIME
551 + (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
552 break;
553 case IEEE80211_T_TURBO:
554 /* we still save OFDM rates in kbps - so double them */
555 bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000;
556 KASSERT(bitsPerSymbol != 0, ("turbo bps"));
557
558 numBits = TURBO_PLCP_BITS + (frameLen << 3);
559 numSymbols = howmany(numBits, bitsPerSymbol);
560 txTime = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME
561 + (numSymbols * TURBO_SYMBOL_TIME);
562 break;
563 default:
085ff963 564 panic("%s: unknown phy %u (rate %u)\n", __func__,
32176cfd
RP
565 rt->info[rix].phy, rate);
566 break;
567 }
568 return txTime;
569}
085ff963
MD
570
571static const uint16_t ht20_bps[32] = {
572 26, 52, 78, 104, 156, 208, 234, 260,
573 52, 104, 156, 208, 312, 416, 468, 520,
574 78, 156, 234, 312, 468, 624, 702, 780,
575 104, 208, 312, 416, 624, 832, 936, 1040
576};
577static const uint16_t ht40_bps[32] = {
578 54, 108, 162, 216, 324, 432, 486, 540,
579 108, 216, 324, 432, 648, 864, 972, 1080,
580 162, 324, 486, 648, 972, 1296, 1458, 1620,
581 216, 432, 648, 864, 1296, 1728, 1944, 2160
582};
583
584
585#define OFDM_PLCP_BITS 22
586#define HT_L_STF 8
587#define HT_L_LTF 8
588#define HT_L_SIG 4
589#define HT_SIG 8
590#define HT_STF 4
591#define HT_LTF(n) ((n) * 4)
592
593#define HT_RC_2_MCS(_rc) ((_rc) & 0xf)
594#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
595#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS)
596
597/*
598 * Calculate the transmit duration of an 11n frame.
599 */
600uint32_t
601ieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate,
602 int streams, int isht40, int isShortGI)
603{
604 uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
605
606 KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
607 KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
608
609 if (isht40)
610 bitsPerSymbol = ht40_bps[rate & 0x1f];
611 else
612 bitsPerSymbol = ht20_bps[rate & 0x1f];
613 numBits = OFDM_PLCP_BITS + (frameLen << 3);
614 numSymbols = howmany(numBits, bitsPerSymbol);
615 if (isShortGI)
616 txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */
617 else
618 txTime = numSymbols * 4; /* 4us */
619 return txTime + HT_L_STF + HT_L_LTF +
620 HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
621}
622
623#undef IS_HT_RATE
624#undef HT_RC_2_STREAMS
625#undef HT_RC_2_MCS
626#undef HT_LTF
627#undef HT_STF
628#undef HT_SIG
629#undef HT_L_SIG
630#undef HT_L_LTF
631#undef HT_L_STF
632#undef OFDM_PLCP_BITS