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