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