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
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
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
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
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
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 */
298static void
299ieee80211_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 */
350static void
351ieee80211_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}
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))
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 */
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:
564		panic("%s: unknown phy %u (rate %u)\n", __func__,
565		      rt->info[rix].phy, rate);
566	}
567	return txTime;
568}
569
570static 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};
576static 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 */
595uint32_t
596ieee80211_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