xref: /freebsd/sys/net80211/ieee80211_phy.c (revision 5dae51da3da0cc94d17bd67b308fad304ebec7e0)
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 #include <sys/malloc.h>
39 
40 #include <sys/socket.h>
41 
42 #include <net/if.h>
43 #include <net/if_media.h>
44 
45 #include <net/ethernet.h>
46 #include <net/route.h>
47 
48 #include <net80211/ieee80211_var.h>
49 #include <net80211/ieee80211_phy.h>
50 
51 #ifdef notyet
52 struct 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
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)
70 #define	PBCC	(IEEE80211_T_OFDM_QUARTER+1)		/* XXX */
71 #define	B(r)	(IEEE80211_RATE_BASIC | r)
72 #define	Mb(x)	(x*1000)
73 
74 static 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 
87 static 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 
107 static 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 
123 static 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 
139 static 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 
155 static 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 
170 static 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 
186 static 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 
234 static 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 
278 #undef	Mb
279 #undef	B
280 #undef	OFDM
281 #undef	HALF
282 #undef	QUART
283 #undef	CCK
284 #undef	TURBO
285 #undef	XR
286 #undef	HT
287 #undef	N
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  */
298 static void
299 ieee80211_setup_ratetable(struct ieee80211_rate_table *rt)
300 {
301 #define	WLAN_CTRL_FRAME_SIZE \
302 	(sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
303 
304 	int i;
305 
306 	for (i = 0; i < nitems(rt->rateCodeToIndex); i++)
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 
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;
324 		}
325 
326 		/* XXX assume the control rate is non-MCS? */
327 		ctl_rate &= IEEE80211_RATE_VAL;
328 		rt->rateCodeToIndex[code] = i;
329 
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
347 }
348 
349 /* Setup all rate tables */
350 static void
351 ieee80211_phy_init(void)
352 {
353 	static struct ieee80211_rate_table * const ratetables[] = {
354 		&ieee80211_half_table,
355 		&ieee80211_quarter_table,
356 		&ieee80211_11na_table,
357 		&ieee80211_11ng_table,
358 		&ieee80211_turbog_table,
359 		&ieee80211_turboa_table,
360 		&ieee80211_11a_table,
361 		&ieee80211_11g_table,
362 		&ieee80211_11b_table
363 	};
364 	int i;
365 
366 	for (i = 0; i < nitems(ratetables); ++i)
367 		ieee80211_setup_ratetable(ratetables[i]);
368 
369 }
370 SYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL);
371 
372 const struct ieee80211_rate_table *
373 ieee80211_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))
383 		rt = &ieee80211_11na_table;
384 	else if (IEEE80211_IS_CHAN_HTG(c))
385 		rt = &ieee80211_11ng_table;
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 */
400 		panic("%s: no rate table for channel; freq %u flags 0x%x\n",
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  */
415 uint8_t
416 ieee80211_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  */
447 uint8_t
448 ieee80211_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  */
501 uint16_t
502 ieee80211_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:
564 		panic("%s: unknown phy %u (rate %u)\n", __func__,
565 		      rt->info[rix].phy, rate);
566 	}
567 	return txTime;
568 }
569 
570 static const uint16_t ht20_bps[32] = {
571 	26, 52, 78, 104, 156, 208, 234, 260,
572 	52, 104, 156, 208, 312, 416, 468, 520,
573 	78, 156, 234, 312, 468, 624, 702, 780,
574 	104, 208, 312, 416, 624, 832, 936, 1040
575 };
576 static const uint16_t ht40_bps[32] = {
577 	54, 108, 162, 216, 324, 432, 486, 540,
578 	108, 216, 324, 432, 648, 864, 972, 1080,
579 	162, 324, 486, 648, 972, 1296, 1458, 1620,
580 	216, 432, 648, 864, 1296, 1728, 1944, 2160
581 };
582 
583 
584 #define	OFDM_PLCP_BITS	22
585 #define	HT_L_STF	8
586 #define	HT_L_LTF	8
587 #define	HT_L_SIG	4
588 #define	HT_SIG		8
589 #define	HT_STF		4
590 #define	HT_LTF(n)	((n) * 4)
591 
592 /*
593  * Calculate the transmit duration of an 11n frame.
594  */
595 uint32_t
596 ieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate,
597     int streams, int isht40, int isShortGI)
598 {
599 	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
600 
601 	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
602 	KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
603 
604 	if (isht40)
605 		bitsPerSymbol = ht40_bps[rate & 0x1f];
606 	else
607 		bitsPerSymbol = ht20_bps[rate & 0x1f];
608 	numBits = OFDM_PLCP_BITS + (frameLen << 3);
609 	numSymbols = howmany(numBits, bitsPerSymbol);
610 	if (isShortGI)
611 		txTime = ((numSymbols * 18) + 4) / 5;   /* 3.6us */
612 	else
613 		txTime = numSymbols * 4;                /* 4us */
614 	return txTime + HT_L_STF + HT_L_LTF +
615 	    HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
616 }
617 
618 #undef	HT_LTF
619 #undef	HT_STF
620 #undef	HT_SIG
621 #undef	HT_L_SIG
622 #undef	HT_L_LTF
623 #undef	HT_L_STF
624 #undef	OFDM_PLCP_BITS
625