2 * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
30 * IEEE 802.11 PHY-related support.
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 #include <sys/malloc.h>
40 #include <sys/socket.h>
43 #include <net/if_var.h>
44 #include <net/if_media.h>
46 #include <net/ethernet.h>
47 #include <net/route.h>
49 #include <netproto/802_11/ieee80211_var.h>
50 #include <netproto/802_11/ieee80211_phy.h>
53 struct ieee80211_ds_plcp_hdr {
62 /* shorthands to compact tables for readability */
63 #define OFDM IEEE80211_T_OFDM
64 #define CCK IEEE80211_T_CCK
65 #define TURBO IEEE80211_T_TURBO
66 #define HALF IEEE80211_T_OFDM_HALF
67 #define QUART IEEE80211_T_OFDM_QUARTER
68 #define HT IEEE80211_T_HT
69 /* XXX the 11n and the basic rate flag are unfortunately overlapping. Grr. */
70 #define N(r) (IEEE80211_RATE_MCS | r)
71 #define PBCC (IEEE80211_T_OFDM_QUARTER+1) /* XXX */
72 #define B(r) (IEEE80211_RATE_BASIC | r)
73 #define Mb(x) (x*1000)
75 static struct ieee80211_rate_table ieee80211_11b_table = {
76 .rateCount = 4, /* XXX no PBCC */
79 /* Preamble dot11Rate Rate */
80 [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },/* 1 Mb */
81 [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },/* 2 Mb */
82 [2] = { .phy = CCK, 5500, 0x04, B(11), 1 },/* 5.5 Mb */
83 [3] = { .phy = CCK, 11000, 0x04, B(22), 1 },/* 11 Mb */
84 [4] = { .phy = PBCC, 22000, 0x04, 44, 3 } /* 22 Mb */
88 static struct ieee80211_rate_table ieee80211_11g_table = {
92 /* Preamble dot11Rate Rate */
93 [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },
94 [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },
95 [2] = { .phy = CCK, 5500, 0x04, B(11), 2 },
96 [3] = { .phy = CCK, 11000, 0x04, B(22), 3 },
97 [4] = { .phy = OFDM, 6000, 0x00, 12, 4 },
98 [5] = { .phy = OFDM, 9000, 0x00, 18, 4 },
99 [6] = { .phy = OFDM, 12000, 0x00, 24, 6 },
100 [7] = { .phy = OFDM, 18000, 0x00, 36, 6 },
101 [8] = { .phy = OFDM, 24000, 0x00, 48, 8 },
102 [9] = { .phy = OFDM, 36000, 0x00, 72, 8 },
103 [10] = { .phy = OFDM, 48000, 0x00, 96, 8 },
104 [11] = { .phy = OFDM, 54000, 0x00, 108, 8 }
108 static struct ieee80211_rate_table ieee80211_11a_table = {
112 /* Preamble dot11Rate Rate */
113 [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 },
114 [1] = { .phy = OFDM, 9000, 0x00, 18, 0 },
115 [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 },
116 [3] = { .phy = OFDM, 18000, 0x00, 36, 2 },
117 [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 },
118 [5] = { .phy = OFDM, 36000, 0x00, 72, 4 },
119 [6] = { .phy = OFDM, 48000, 0x00, 96, 4 },
120 [7] = { .phy = OFDM, 54000, 0x00, 108, 4 }
124 static struct ieee80211_rate_table ieee80211_half_table = {
128 /* Preamble dot11Rate Rate */
129 [0] = { .phy = HALF, 3000, 0x00, B(6), 0 },
130 [1] = { .phy = HALF, 4500, 0x00, 9, 0 },
131 [2] = { .phy = HALF, 6000, 0x00, B(12), 2 },
132 [3] = { .phy = HALF, 9000, 0x00, 18, 2 },
133 [4] = { .phy = HALF, 12000, 0x00, B(24), 4 },
134 [5] = { .phy = HALF, 18000, 0x00, 36, 4 },
135 [6] = { .phy = HALF, 24000, 0x00, 48, 4 },
136 [7] = { .phy = HALF, 27000, 0x00, 54, 4 }
140 static struct ieee80211_rate_table ieee80211_quarter_table = {
144 /* Preamble dot11Rate Rate */
145 [0] = { .phy = QUART, 1500, 0x00, B(3), 0 },
146 [1] = { .phy = QUART, 2250, 0x00, 4, 0 },
147 [2] = { .phy = QUART, 3000, 0x00, B(9), 2 },
148 [3] = { .phy = QUART, 4500, 0x00, 9, 2 },
149 [4] = { .phy = QUART, 6000, 0x00, B(12), 4 },
150 [5] = { .phy = QUART, 9000, 0x00, 18, 4 },
151 [6] = { .phy = QUART, 12000, 0x00, 24, 4 },
152 [7] = { .phy = QUART, 13500, 0x00, 27, 4 }
156 static struct ieee80211_rate_table ieee80211_turbog_table = {
160 /* Preamble dot11Rate Rate */
161 [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 },
162 [1] = { .phy = TURBO, 24000, 0x00, B(24), 1 },
163 [2] = { .phy = TURBO, 36000, 0x00, 36, 1 },
164 [3] = { .phy = TURBO, 48000, 0x00, B(48), 3 },
165 [4] = { .phy = TURBO, 72000, 0x00, 72, 3 },
166 [5] = { .phy = TURBO, 96000, 0x00, 96, 3 },
167 [6] = { .phy = TURBO, 108000, 0x00, 108, 3 }
171 static struct ieee80211_rate_table ieee80211_turboa_table = {
175 /* Preamble dot11Rate Rate */
176 [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 },
177 [1] = { .phy = TURBO, 18000, 0x00, 18, 0 },
178 [2] = { .phy = TURBO, 24000, 0x00, B(24), 2 },
179 [3] = { .phy = TURBO, 36000, 0x00, 36, 2 },
180 [4] = { .phy = TURBO, 48000, 0x00, B(48), 4 },
181 [5] = { .phy = TURBO, 72000, 0x00, 72, 4 },
182 [6] = { .phy = TURBO, 96000, 0x00, 96, 4 },
183 [7] = { .phy = TURBO, 108000, 0x00, 108, 4 }
187 static struct ieee80211_rate_table ieee80211_11ng_table = {
191 /* Preamble dot11Rate Rate */
192 [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },
193 [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },
194 [2] = { .phy = CCK, 5500, 0x04, B(11), 2 },
195 [3] = { .phy = CCK, 11000, 0x04, B(22), 3 },
196 [4] = { .phy = OFDM, 6000, 0x00, 12, 4 },
197 [5] = { .phy = OFDM, 9000, 0x00, 18, 4 },
198 [6] = { .phy = OFDM, 12000, 0x00, 24, 6 },
199 [7] = { .phy = OFDM, 18000, 0x00, 36, 6 },
200 [8] = { .phy = OFDM, 24000, 0x00, 48, 8 },
201 [9] = { .phy = OFDM, 36000, 0x00, 72, 8 },
202 [10] = { .phy = OFDM, 48000, 0x00, 96, 8 },
203 [11] = { .phy = OFDM, 54000, 0x00, 108, 8 },
205 [12] = { .phy = HT, 6500, 0x00, N(0), 4 },
206 [13] = { .phy = HT, 13000, 0x00, N(1), 6 },
207 [14] = { .phy = HT, 19500, 0x00, N(2), 6 },
208 [15] = { .phy = HT, 26000, 0x00, N(3), 8 },
209 [16] = { .phy = HT, 39000, 0x00, N(4), 8 },
210 [17] = { .phy = HT, 52000, 0x00, N(5), 8 },
211 [18] = { .phy = HT, 58500, 0x00, N(6), 8 },
212 [19] = { .phy = HT, 65000, 0x00, N(7), 8 },
214 [20] = { .phy = HT, 13000, 0x00, N(8), 4 },
215 [21] = { .phy = HT, 26000, 0x00, N(9), 6 },
216 [22] = { .phy = HT, 39000, 0x00, N(10), 6 },
217 [23] = { .phy = HT, 52000, 0x00, N(11), 8 },
218 [24] = { .phy = HT, 78000, 0x00, N(12), 8 },
219 [25] = { .phy = HT, 104000, 0x00, N(13), 8 },
220 [26] = { .phy = HT, 117000, 0x00, N(14), 8 },
221 [27] = { .phy = HT, 130000, 0x00, N(15), 8 },
223 [28] = { .phy = HT, 19500, 0x00, N(16), 4 },
224 [29] = { .phy = HT, 39000, 0x00, N(17), 6 },
225 [30] = { .phy = HT, 58500, 0x00, N(18), 6 },
226 [31] = { .phy = HT, 78000, 0x00, N(19), 8 },
227 [32] = { .phy = HT, 117000, 0x00, N(20), 8 },
228 [33] = { .phy = HT, 156000, 0x00, N(21), 8 },
229 [34] = { .phy = HT, 175500, 0x00, N(22), 8 },
230 [35] = { .phy = HT, 195000, 0x00, N(23), 8 },
235 static struct ieee80211_rate_table ieee80211_11na_table = {
239 /* Preamble dot11Rate Rate */
240 [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 },
241 [1] = { .phy = OFDM, 9000, 0x00, 18, 0 },
242 [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 },
243 [3] = { .phy = OFDM, 18000, 0x00, 36, 2 },
244 [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 },
245 [5] = { .phy = OFDM, 36000, 0x00, 72, 4 },
246 [6] = { .phy = OFDM, 48000, 0x00, 96, 4 },
247 [7] = { .phy = OFDM, 54000, 0x00, 108, 4 },
249 [8] = { .phy = HT, 6500, 0x00, N(0), 0 },
250 [9] = { .phy = HT, 13000, 0x00, N(1), 2 },
251 [10] = { .phy = HT, 19500, 0x00, N(2), 2 },
252 [11] = { .phy = HT, 26000, 0x00, N(3), 4 },
253 [12] = { .phy = HT, 39000, 0x00, N(4), 4 },
254 [13] = { .phy = HT, 52000, 0x00, N(5), 4 },
255 [14] = { .phy = HT, 58500, 0x00, N(6), 4 },
256 [15] = { .phy = HT, 65000, 0x00, N(7), 4 },
258 [16] = { .phy = HT, 13000, 0x00, N(8), 0 },
259 [17] = { .phy = HT, 26000, 0x00, N(9), 2 },
260 [18] = { .phy = HT, 39000, 0x00, N(10), 2 },
261 [19] = { .phy = HT, 52000, 0x00, N(11), 4 },
262 [20] = { .phy = HT, 78000, 0x00, N(12), 4 },
263 [21] = { .phy = HT, 104000, 0x00, N(13), 4 },
264 [22] = { .phy = HT, 117000, 0x00, N(14), 4 },
265 [23] = { .phy = HT, 130000, 0x00, N(15), 4 },
267 [24] = { .phy = HT, 19500, 0x00, N(16), 0 },
268 [25] = { .phy = HT, 39000, 0x00, N(17), 2 },
269 [26] = { .phy = HT, 58500, 0x00, N(18), 2 },
270 [27] = { .phy = HT, 78000, 0x00, N(19), 4 },
271 [28] = { .phy = HT, 117000, 0x00, N(20), 4 },
272 [29] = { .phy = HT, 156000, 0x00, N(21), 4 },
273 [30] = { .phy = HT, 175500, 0x00, N(22), 4 },
274 [31] = { .phy = HT, 195000, 0x00, N(23), 4 },
291 * Setup a rate table's reverse lookup table and fill in
292 * ack durations. The reverse lookup tables are assumed
293 * to be initialized to zero (or at least the first entry).
294 * We use this as a key that indicates whether or not
295 * we've previously setup the reverse lookup table.
297 * XXX not reentrant, but shouldn't matter
300 ieee80211_setup_ratetable(struct ieee80211_rate_table *rt)
302 #define WLAN_CTRL_FRAME_SIZE \
303 (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
307 for (i = 0; i < nitems(rt->rateCodeToIndex); i++)
308 rt->rateCodeToIndex[i] = (uint8_t) -1;
309 for (i = 0; i < rt->rateCount; i++) {
310 uint8_t code = rt->info[i].dot11Rate;
311 uint8_t cix = rt->info[i].ctlRateIndex;
312 uint8_t ctl_rate = rt->info[cix].dot11Rate;
315 * Map without the basic rate bit.
317 * It's up to the caller to ensure that the basic
318 * rate bit is stripped here.
320 * For HT, use the MCS rate bit.
322 code &= IEEE80211_RATE_VAL;
323 if (rt->info[i].phy == IEEE80211_T_HT) {
324 code |= IEEE80211_RATE_MCS;
327 /* XXX assume the control rate is non-MCS? */
328 ctl_rate &= IEEE80211_RATE_VAL;
329 rt->rateCodeToIndex[code] = i;
332 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
333 * depends on whether they are marked as basic rates;
334 * the static tables are setup with an 11b-compatible
335 * 2Mb/s rate which will work but is suboptimal
337 * NB: Control rate is always less than or equal to the
338 * current rate, so control rate's reverse lookup entry
339 * has been installed and following call is safe.
341 rt->info[i].lpAckDuration = ieee80211_compute_duration(rt,
342 WLAN_CTRL_FRAME_SIZE, ctl_rate, 0);
343 rt->info[i].spAckDuration = ieee80211_compute_duration(rt,
344 WLAN_CTRL_FRAME_SIZE, ctl_rate, IEEE80211_F_SHPREAMBLE);
347 #undef WLAN_CTRL_FRAME_SIZE
350 /* Setup all rate tables */
352 ieee80211_phy_init(void)
354 static struct ieee80211_rate_table * const ratetables[] = {
355 &ieee80211_half_table,
356 &ieee80211_quarter_table,
357 &ieee80211_11na_table,
358 &ieee80211_11ng_table,
359 &ieee80211_turbog_table,
360 &ieee80211_turboa_table,
361 &ieee80211_11a_table,
362 &ieee80211_11g_table,
367 for (i = 0; i < nitems(ratetables); ++i)
368 ieee80211_setup_ratetable(ratetables[i]);
371 SYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL);
373 const struct ieee80211_rate_table *
374 ieee80211_get_ratetable(struct ieee80211_channel *c)
376 const struct ieee80211_rate_table *rt;
379 if (IEEE80211_IS_CHAN_HALF(c))
380 rt = &ieee80211_half_table;
381 else if (IEEE80211_IS_CHAN_QUARTER(c))
382 rt = &ieee80211_quarter_table;
383 else if (IEEE80211_IS_CHAN_HTA(c))
384 rt = &ieee80211_11na_table;
385 else if (IEEE80211_IS_CHAN_HTG(c))
386 rt = &ieee80211_11ng_table;
387 else if (IEEE80211_IS_CHAN_108G(c))
388 rt = &ieee80211_turbog_table;
389 else if (IEEE80211_IS_CHAN_ST(c))
390 rt = &ieee80211_turboa_table;
391 else if (IEEE80211_IS_CHAN_TURBO(c))
392 rt = &ieee80211_turboa_table;
393 else if (IEEE80211_IS_CHAN_A(c))
394 rt = &ieee80211_11a_table;
395 else if (IEEE80211_IS_CHAN_ANYG(c))
396 rt = &ieee80211_11g_table;
397 else if (IEEE80211_IS_CHAN_B(c))
398 rt = &ieee80211_11b_table;
400 /* NB: should not get here */
401 panic("%s: no rate table for channel; freq %u flags 0x%x\n",
402 __func__, c->ic_freq, c->ic_flags);
408 * Convert PLCP signal/rate field to 802.11 rate (.5Mbits/s)
410 * Note we do no parameter checking; this routine is mainly
411 * used to derive an 802.11 rate for constructing radiotap
412 * header data for rx frames.
414 * XXX might be a candidate for inline
417 ieee80211_plcp2rate(uint8_t plcp, enum ieee80211_phytype type)
419 if (type == IEEE80211_T_OFDM) {
420 static const uint8_t ofdm_plcp2rate[16] = {
430 return ofdm_plcp2rate[plcp & 0xf];
432 if (type == IEEE80211_T_CCK) {
433 static const uint8_t cck_plcp2rate[16] = {
434 [0xa] = 2, /* 0x0a */
435 [0x4] = 4, /* 0x14 */
436 [0x7] = 11, /* 0x37 */
437 [0xe] = 22, /* 0x6e */
438 [0xc] = 44, /* 0xdc , actually PBCC */
440 return cck_plcp2rate[plcp & 0xf];
446 * Covert 802.11 rate to PLCP signal.
449 ieee80211_rate2plcp(int rate, enum ieee80211_phytype type)
451 /* XXX ignore type for now since rates are unique */
453 /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
461 case 108: return 0xc;
462 /* CCK rates (IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3) */
467 /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */
470 return 0; /* XXX unsupported/unknown rate */
473 #define CCK_SIFS_TIME 10
474 #define CCK_PREAMBLE_BITS 144
475 #define CCK_PLCP_BITS 48
477 #define OFDM_SIFS_TIME 16
478 #define OFDM_PREAMBLE_TIME 20
479 #define OFDM_PLCP_BITS 22
480 #define OFDM_SYMBOL_TIME 4
482 #define OFDM_HALF_SIFS_TIME 32
483 #define OFDM_HALF_PREAMBLE_TIME 40
484 #define OFDM_HALF_PLCP_BITS 22
485 #define OFDM_HALF_SYMBOL_TIME 8
487 #define OFDM_QUARTER_SIFS_TIME 64
488 #define OFDM_QUARTER_PREAMBLE_TIME 80
489 #define OFDM_QUARTER_PLCP_BITS 22
490 #define OFDM_QUARTER_SYMBOL_TIME 16
492 #define TURBO_SIFS_TIME 8
493 #define TURBO_PREAMBLE_TIME 14
494 #define TURBO_PLCP_BITS 22
495 #define TURBO_SYMBOL_TIME 4
498 * Compute the time to transmit a frame of length frameLen bytes
499 * using the specified rate, phy, and short preamble setting.
503 ieee80211_compute_duration(const struct ieee80211_rate_table *rt,
504 uint32_t frameLen, uint16_t rate, int isShortPreamble)
506 uint8_t rix = rt->rateCodeToIndex[rate];
507 uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
510 KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate));
511 kbps = rt->info[rix].rateKbps;
512 if (kbps == 0) /* XXX bandaid for channel changes */
515 switch (rt->info[rix].phy) {
516 case IEEE80211_T_CCK:
517 phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
518 if (isShortPreamble && rt->info[rix].shortPreamble)
520 numBits = frameLen << 3;
521 txTime = CCK_SIFS_TIME + phyTime
522 + ((numBits * 1000)/kbps);
524 case IEEE80211_T_OFDM:
525 bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000;
526 KASSERT(bitsPerSymbol != 0, ("full rate bps"));
528 numBits = OFDM_PLCP_BITS + (frameLen << 3);
529 numSymbols = howmany(numBits, bitsPerSymbol);
530 txTime = OFDM_SIFS_TIME
532 + (numSymbols * OFDM_SYMBOL_TIME);
534 case IEEE80211_T_OFDM_HALF:
535 bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
536 KASSERT(bitsPerSymbol != 0, ("1/4 rate bps"));
538 numBits = OFDM_PLCP_BITS + (frameLen << 3);
539 numSymbols = howmany(numBits, bitsPerSymbol);
540 txTime = OFDM_HALF_SIFS_TIME
541 + OFDM_HALF_PREAMBLE_TIME
542 + (numSymbols * OFDM_HALF_SYMBOL_TIME);
544 case IEEE80211_T_OFDM_QUARTER:
545 bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
546 KASSERT(bitsPerSymbol != 0, ("1/2 rate bps"));
548 numBits = OFDM_PLCP_BITS + (frameLen << 3);
549 numSymbols = howmany(numBits, bitsPerSymbol);
550 txTime = OFDM_QUARTER_SIFS_TIME
551 + OFDM_QUARTER_PREAMBLE_TIME
552 + (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
554 case IEEE80211_T_TURBO:
555 /* we still save OFDM rates in kbps - so double them */
556 bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000;
557 KASSERT(bitsPerSymbol != 0, ("turbo bps"));
559 numBits = TURBO_PLCP_BITS + (frameLen << 3);
560 numSymbols = howmany(numBits, bitsPerSymbol);
561 txTime = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME
562 + (numSymbols * TURBO_SYMBOL_TIME);
565 panic("%s: unknown phy %u (rate %u)\n", __func__,
566 rt->info[rix].phy, rate);
572 static const uint16_t ht20_bps[32] = {
573 26, 52, 78, 104, 156, 208, 234, 260,
574 52, 104, 156, 208, 312, 416, 468, 520,
575 78, 156, 234, 312, 468, 624, 702, 780,
576 104, 208, 312, 416, 624, 832, 936, 1040
578 static const uint16_t ht40_bps[32] = {
579 54, 108, 162, 216, 324, 432, 486, 540,
580 108, 216, 324, 432, 648, 864, 972, 1080,
581 162, 324, 486, 648, 972, 1296, 1458, 1620,
582 216, 432, 648, 864, 1296, 1728, 1944, 2160
586 #define OFDM_PLCP_BITS 22
592 #define HT_LTF(n) ((n) * 4)
594 #define HT_RC_2_MCS(_rc) ((_rc) & 0x1f)
595 #define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
596 #define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS)
599 * Calculate the transmit duration of an 11n frame.
602 ieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate,
603 int streams, int isht40, int isShortGI)
605 uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
607 KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
608 KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
611 bitsPerSymbol = ht40_bps[rate & 0x1f];
613 bitsPerSymbol = ht20_bps[rate & 0x1f];
614 numBits = OFDM_PLCP_BITS + (frameLen << 3);
615 numSymbols = howmany(numBits, bitsPerSymbol);
617 txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */
619 txTime = numSymbols * 4; /* 4us */
620 return txTime + HT_L_STF + HT_L_LTF +
621 HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
625 #undef HT_RC_2_STREAMS
633 #undef OFDM_PLCP_BITS