ieee80211_phy.c revision 254315
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: head/sys/net80211/ieee80211_phy.c 254315 2013-08-14 04:24:25Z rpaulo $");
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
48struct 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
70static 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
83static 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
103static 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
119static 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
135static 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
151static 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
166static 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
182static 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
230static 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 */
294static void
295ieee80211_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 */
346static void
347ieee80211_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}
366SYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL);
367
368const struct ieee80211_rate_table *
369ieee80211_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 */
411uint8_t
412ieee80211_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 */
443uint8_t
444ieee80211_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 */
497uint16_t
498ieee80211_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
567static 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};
573static 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 */
596uint32_t
597ieee80211_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