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