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