xref: /dflybsd-src/sys/netproto/802_11/wlan/ieee80211_phy.c (revision bff82488b6f45c2f067e4c552e649b1d3e07cd7c)
132176cfdSRui Paulo /*-
232176cfdSRui Paulo  * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
332176cfdSRui Paulo  * All rights reserved.
432176cfdSRui Paulo  *
532176cfdSRui Paulo  * Redistribution and use in source and binary forms, with or without
632176cfdSRui Paulo  * modification, are permitted provided that the following conditions
732176cfdSRui Paulo  * are met:
832176cfdSRui Paulo  * 1. Redistributions of source code must retain the above copyright
932176cfdSRui Paulo  *    notice, this list of conditions and the following disclaimer.
1032176cfdSRui Paulo  * 2. Redistributions in binary form must reproduce the above copyright
1132176cfdSRui Paulo  *    notice, this list of conditions and the following disclaimer in the
1232176cfdSRui Paulo  *    documentation and/or other materials provided with the distribution.
1332176cfdSRui Paulo  *
1432176cfdSRui Paulo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1532176cfdSRui Paulo  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1632176cfdSRui Paulo  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1732176cfdSRui Paulo  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1832176cfdSRui Paulo  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1932176cfdSRui Paulo  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2032176cfdSRui Paulo  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2132176cfdSRui Paulo  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2232176cfdSRui Paulo  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2332176cfdSRui Paulo  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2432176cfdSRui Paulo  */
2532176cfdSRui Paulo 
26085ff963SMatthew Dillon #include <sys/cdefs.h>
27085ff963SMatthew Dillon __FBSDID("$FreeBSD$");
28085ff963SMatthew Dillon 
2932176cfdSRui Paulo /*
3032176cfdSRui Paulo  * IEEE 802.11 PHY-related support.
3132176cfdSRui Paulo  */
3232176cfdSRui Paulo 
3332176cfdSRui Paulo #include "opt_inet.h"
3432176cfdSRui Paulo 
3532176cfdSRui Paulo #include <sys/param.h>
3632176cfdSRui Paulo #include <sys/kernel.h>
3732176cfdSRui Paulo #include <sys/systm.h>
38085ff963SMatthew Dillon #include <sys/malloc.h>
3932176cfdSRui Paulo 
4032176cfdSRui Paulo #include <sys/socket.h>
4132176cfdSRui Paulo 
4232176cfdSRui Paulo #include <net/if.h>
43*bff82488SAaron LI #include <net/if_var.h>
4432176cfdSRui Paulo #include <net/if_media.h>
45085ff963SMatthew Dillon 
46085ff963SMatthew Dillon #include <net/ethernet.h>
4732176cfdSRui Paulo #include <net/route.h>
4832176cfdSRui Paulo 
4932176cfdSRui Paulo #include <netproto/802_11/ieee80211_var.h>
5032176cfdSRui Paulo #include <netproto/802_11/ieee80211_phy.h>
5132176cfdSRui Paulo 
5232176cfdSRui Paulo #ifdef notyet
5332176cfdSRui Paulo struct ieee80211_ds_plcp_hdr {
5432176cfdSRui Paulo 	uint8_t		i_signal;
5532176cfdSRui Paulo 	uint8_t		i_service;
5632176cfdSRui Paulo 	uint16_t	i_length;
5732176cfdSRui Paulo 	uint16_t	i_crc;
5832176cfdSRui Paulo } __packed;
5932176cfdSRui Paulo 
6032176cfdSRui Paulo #endif	/* notyet */
6132176cfdSRui Paulo 
6232176cfdSRui Paulo /* shorthands to compact tables for readability */
6332176cfdSRui Paulo #define	OFDM	IEEE80211_T_OFDM
6432176cfdSRui Paulo #define	CCK	IEEE80211_T_CCK
6532176cfdSRui Paulo #define	TURBO	IEEE80211_T_TURBO
6632176cfdSRui Paulo #define	HALF	IEEE80211_T_OFDM_HALF
6732176cfdSRui Paulo #define	QUART	IEEE80211_T_OFDM_QUARTER
68085ff963SMatthew Dillon #define	HT	IEEE80211_T_HT
69085ff963SMatthew Dillon /* XXX the 11n and the basic rate flag are unfortunately overlapping. Grr. */
70085ff963SMatthew Dillon #define	N(r)	(IEEE80211_RATE_MCS | r)
7132176cfdSRui Paulo #define	PBCC	(IEEE80211_T_OFDM_QUARTER+1)		/* XXX */
72085ff963SMatthew Dillon #define	B(r)	(IEEE80211_RATE_BASIC | r)
7332176cfdSRui Paulo #define	Mb(x)	(x*1000)
7432176cfdSRui Paulo 
7532176cfdSRui Paulo static struct ieee80211_rate_table ieee80211_11b_table = {
7632176cfdSRui Paulo     .rateCount = 4,		/* XXX no PBCC */
7732176cfdSRui Paulo     .info = {
7832176cfdSRui Paulo /*                                   short            ctrl  */
7932176cfdSRui Paulo /*                                Preamble  dot11Rate Rate */
8032176cfdSRui Paulo      [0] = { .phy = CCK,     1000,    0x00,      B(2),   0 },/*   1 Mb */
8132176cfdSRui Paulo      [1] = { .phy = CCK,     2000,    0x04,      B(4),   1 },/*   2 Mb */
8232176cfdSRui Paulo      [2] = { .phy = CCK,     5500,    0x04,     B(11),   1 },/* 5.5 Mb */
8332176cfdSRui Paulo      [3] = { .phy = CCK,    11000,    0x04,     B(22),   1 },/*  11 Mb */
8432176cfdSRui Paulo      [4] = { .phy = PBCC,   22000,    0x04,        44,   3 } /*  22 Mb */
8532176cfdSRui Paulo     },
8632176cfdSRui Paulo };
8732176cfdSRui Paulo 
8832176cfdSRui Paulo static struct ieee80211_rate_table ieee80211_11g_table = {
8932176cfdSRui Paulo     .rateCount = 12,
9032176cfdSRui Paulo     .info = {
9132176cfdSRui Paulo /*                                   short            ctrl  */
9232176cfdSRui Paulo /*                                Preamble  dot11Rate Rate */
9332176cfdSRui Paulo      [0] = { .phy = CCK,     1000,    0x00,      B(2),   0 },
9432176cfdSRui Paulo      [1] = { .phy = CCK,     2000,    0x04,      B(4),   1 },
9532176cfdSRui Paulo      [2] = { .phy = CCK,     5500,    0x04,     B(11),   2 },
9632176cfdSRui Paulo      [3] = { .phy = CCK,    11000,    0x04,     B(22),   3 },
9732176cfdSRui Paulo      [4] = { .phy = OFDM,    6000,    0x00,        12,   4 },
9832176cfdSRui Paulo      [5] = { .phy = OFDM,    9000,    0x00,        18,   4 },
9932176cfdSRui Paulo      [6] = { .phy = OFDM,   12000,    0x00,        24,   6 },
10032176cfdSRui Paulo      [7] = { .phy = OFDM,   18000,    0x00,        36,   6 },
10132176cfdSRui Paulo      [8] = { .phy = OFDM,   24000,    0x00,        48,   8 },
10232176cfdSRui Paulo      [9] = { .phy = OFDM,   36000,    0x00,        72,   8 },
10332176cfdSRui Paulo     [10] = { .phy = OFDM,   48000,    0x00,        96,   8 },
10432176cfdSRui Paulo     [11] = { .phy = OFDM,   54000,    0x00,       108,   8 }
10532176cfdSRui Paulo     },
10632176cfdSRui Paulo };
10732176cfdSRui Paulo 
10832176cfdSRui Paulo static struct ieee80211_rate_table ieee80211_11a_table = {
10932176cfdSRui Paulo     .rateCount = 8,
11032176cfdSRui Paulo     .info = {
11132176cfdSRui Paulo /*                                   short            ctrl  */
11232176cfdSRui Paulo /*                                Preamble  dot11Rate Rate */
11332176cfdSRui Paulo      [0] = { .phy = OFDM,    6000,    0x00,     B(12),   0 },
11432176cfdSRui Paulo      [1] = { .phy = OFDM,    9000,    0x00,        18,   0 },
11532176cfdSRui Paulo      [2] = { .phy = OFDM,   12000,    0x00,     B(24),   2 },
11632176cfdSRui Paulo      [3] = { .phy = OFDM,   18000,    0x00,        36,   2 },
11732176cfdSRui Paulo      [4] = { .phy = OFDM,   24000,    0x00,     B(48),   4 },
11832176cfdSRui Paulo      [5] = { .phy = OFDM,   36000,    0x00,        72,   4 },
11932176cfdSRui Paulo      [6] = { .phy = OFDM,   48000,    0x00,        96,   4 },
12032176cfdSRui Paulo      [7] = { .phy = OFDM,   54000,    0x00,       108,   4 }
12132176cfdSRui Paulo     },
12232176cfdSRui Paulo };
12332176cfdSRui Paulo 
12432176cfdSRui Paulo static struct ieee80211_rate_table ieee80211_half_table = {
12532176cfdSRui Paulo     .rateCount = 8,
12632176cfdSRui Paulo     .info = {
12732176cfdSRui Paulo /*                                   short            ctrl  */
12832176cfdSRui Paulo /*                                Preamble  dot11Rate Rate */
12932176cfdSRui Paulo      [0] = { .phy = HALF,    3000,    0x00,      B(6),   0 },
13032176cfdSRui Paulo      [1] = { .phy = HALF,    4500,    0x00,         9,   0 },
13132176cfdSRui Paulo      [2] = { .phy = HALF,    6000,    0x00,     B(12),   2 },
13232176cfdSRui Paulo      [3] = { .phy = HALF,    9000,    0x00,        18,   2 },
13332176cfdSRui Paulo      [4] = { .phy = HALF,   12000,    0x00,     B(24),   4 },
13432176cfdSRui Paulo      [5] = { .phy = HALF,   18000,    0x00,        36,   4 },
13532176cfdSRui Paulo      [6] = { .phy = HALF,   24000,    0x00,        48,   4 },
13632176cfdSRui Paulo      [7] = { .phy = HALF,   27000,    0x00,        54,   4 }
13732176cfdSRui Paulo     },
13832176cfdSRui Paulo };
13932176cfdSRui Paulo 
14032176cfdSRui Paulo static struct ieee80211_rate_table ieee80211_quarter_table = {
14132176cfdSRui Paulo     .rateCount = 8,
14232176cfdSRui Paulo     .info = {
14332176cfdSRui Paulo /*                                   short            ctrl  */
14432176cfdSRui Paulo /*                                Preamble  dot11Rate Rate */
14532176cfdSRui Paulo      [0] = { .phy = QUART,   1500,    0x00,      B(3),   0 },
14632176cfdSRui Paulo      [1] = { .phy = QUART,   2250,    0x00,         4,   0 },
14732176cfdSRui Paulo      [2] = { .phy = QUART,   3000,    0x00,      B(9),   2 },
14832176cfdSRui Paulo      [3] = { .phy = QUART,   4500,    0x00,         9,   2 },
14932176cfdSRui Paulo      [4] = { .phy = QUART,   6000,    0x00,     B(12),   4 },
15032176cfdSRui Paulo      [5] = { .phy = QUART,   9000,    0x00,        18,   4 },
15132176cfdSRui Paulo      [6] = { .phy = QUART,  12000,    0x00,        24,   4 },
15232176cfdSRui Paulo      [7] = { .phy = QUART,  13500,    0x00,        27,   4 }
15332176cfdSRui Paulo     },
15432176cfdSRui Paulo };
15532176cfdSRui Paulo 
15632176cfdSRui Paulo static struct ieee80211_rate_table ieee80211_turbog_table = {
15732176cfdSRui Paulo     .rateCount = 7,
15832176cfdSRui Paulo     .info = {
15932176cfdSRui Paulo /*                                   short            ctrl  */
16032176cfdSRui Paulo /*                                Preamble  dot11Rate Rate */
16132176cfdSRui Paulo      [0] = { .phy = TURBO,   12000,   0x00,     B(12),   0 },
16232176cfdSRui Paulo      [1] = { .phy = TURBO,   24000,   0x00,     B(24),   1 },
16332176cfdSRui Paulo      [2] = { .phy = TURBO,   36000,   0x00,        36,   1 },
16432176cfdSRui Paulo      [3] = { .phy = TURBO,   48000,   0x00,     B(48),   3 },
16532176cfdSRui Paulo      [4] = { .phy = TURBO,   72000,   0x00,        72,   3 },
16632176cfdSRui Paulo      [5] = { .phy = TURBO,   96000,   0x00,        96,   3 },
16732176cfdSRui Paulo      [6] = { .phy = TURBO,  108000,   0x00,       108,   3 }
16832176cfdSRui Paulo     },
16932176cfdSRui Paulo };
17032176cfdSRui Paulo 
17132176cfdSRui Paulo static struct ieee80211_rate_table ieee80211_turboa_table = {
17232176cfdSRui Paulo     .rateCount = 8,
17332176cfdSRui Paulo     .info = {
17432176cfdSRui Paulo /*                                   short            ctrl  */
17532176cfdSRui Paulo /*                                Preamble  dot11Rate Rate */
17632176cfdSRui Paulo      [0] = { .phy = TURBO,   12000,   0x00,     B(12),   0 },
17732176cfdSRui Paulo      [1] = { .phy = TURBO,   18000,   0x00,        18,   0 },
17832176cfdSRui Paulo      [2] = { .phy = TURBO,   24000,   0x00,     B(24),   2 },
17932176cfdSRui Paulo      [3] = { .phy = TURBO,   36000,   0x00,        36,   2 },
18032176cfdSRui Paulo      [4] = { .phy = TURBO,   48000,   0x00,     B(48),   4 },
18132176cfdSRui Paulo      [5] = { .phy = TURBO,   72000,   0x00,        72,   4 },
18232176cfdSRui Paulo      [6] = { .phy = TURBO,   96000,   0x00,        96,   4 },
18332176cfdSRui Paulo      [7] = { .phy = TURBO,  108000,   0x00,       108,   4 }
18432176cfdSRui Paulo     },
18532176cfdSRui Paulo };
18632176cfdSRui Paulo 
187085ff963SMatthew Dillon static struct ieee80211_rate_table ieee80211_11ng_table = {
188085ff963SMatthew Dillon     .rateCount = 36,
189085ff963SMatthew Dillon     .info = {
190085ff963SMatthew Dillon /*                                   short            ctrl  */
191085ff963SMatthew Dillon /*                                Preamble  dot11Rate Rate */
192085ff963SMatthew Dillon      [0] = { .phy = CCK,     1000,    0x00,      B(2),   0 },
193085ff963SMatthew Dillon      [1] = { .phy = CCK,     2000,    0x04,      B(4),   1 },
194085ff963SMatthew Dillon      [2] = { .phy = CCK,     5500,    0x04,     B(11),   2 },
195085ff963SMatthew Dillon      [3] = { .phy = CCK,    11000,    0x04,     B(22),   3 },
196085ff963SMatthew Dillon      [4] = { .phy = OFDM,    6000,    0x00,        12,   4 },
197085ff963SMatthew Dillon      [5] = { .phy = OFDM,    9000,    0x00,        18,   4 },
198085ff963SMatthew Dillon      [6] = { .phy = OFDM,   12000,    0x00,        24,   6 },
199085ff963SMatthew Dillon      [7] = { .phy = OFDM,   18000,    0x00,        36,   6 },
200085ff963SMatthew Dillon      [8] = { .phy = OFDM,   24000,    0x00,        48,   8 },
201085ff963SMatthew Dillon      [9] = { .phy = OFDM,   36000,    0x00,        72,   8 },
202085ff963SMatthew Dillon     [10] = { .phy = OFDM,   48000,    0x00,        96,   8 },
203085ff963SMatthew Dillon     [11] = { .phy = OFDM,   54000,    0x00,       108,   8 },
204085ff963SMatthew Dillon 
205085ff963SMatthew Dillon     [12] = { .phy = HT,      6500,    0x00,      N(0),   4 },
206085ff963SMatthew Dillon     [13] = { .phy = HT,     13000,    0x00,      N(1),   6 },
207085ff963SMatthew Dillon     [14] = { .phy = HT,     19500,    0x00,      N(2),   6 },
208085ff963SMatthew Dillon     [15] = { .phy = HT,     26000,    0x00,      N(3),   8 },
209085ff963SMatthew Dillon     [16] = { .phy = HT,     39000,    0x00,      N(4),   8 },
210085ff963SMatthew Dillon     [17] = { .phy = HT,     52000,    0x00,      N(5),   8 },
211085ff963SMatthew Dillon     [18] = { .phy = HT,     58500,    0x00,      N(6),   8 },
212085ff963SMatthew Dillon     [19] = { .phy = HT,     65000,    0x00,      N(7),   8 },
213085ff963SMatthew Dillon 
214085ff963SMatthew Dillon     [20] = { .phy = HT,     13000,    0x00,      N(8),   4 },
215085ff963SMatthew Dillon     [21] = { .phy = HT,     26000,    0x00,      N(9),   6 },
216085ff963SMatthew Dillon     [22] = { .phy = HT,     39000,    0x00,     N(10),   6 },
217085ff963SMatthew Dillon     [23] = { .phy = HT,     52000,    0x00,     N(11),   8 },
218085ff963SMatthew Dillon     [24] = { .phy = HT,     78000,    0x00,     N(12),   8 },
219085ff963SMatthew Dillon     [25] = { .phy = HT,    104000,    0x00,     N(13),   8 },
220085ff963SMatthew Dillon     [26] = { .phy = HT,    117000,    0x00,     N(14),   8 },
221085ff963SMatthew Dillon     [27] = { .phy = HT,    130000,    0x00,     N(15),   8 },
222085ff963SMatthew Dillon 
223085ff963SMatthew Dillon     [28] = { .phy = HT,     19500,    0x00,     N(16),   4 },
224085ff963SMatthew Dillon     [29] = { .phy = HT,     39000,    0x00,     N(17),   6 },
225085ff963SMatthew Dillon     [30] = { .phy = HT,     58500,    0x00,     N(18),   6 },
226085ff963SMatthew Dillon     [31] = { .phy = HT,     78000,    0x00,     N(19),   8 },
227085ff963SMatthew Dillon     [32] = { .phy = HT,    117000,    0x00,     N(20),   8 },
228085ff963SMatthew Dillon     [33] = { .phy = HT,    156000,    0x00,     N(21),   8 },
229085ff963SMatthew Dillon     [34] = { .phy = HT,    175500,    0x00,     N(22),   8 },
230085ff963SMatthew Dillon     [35] = { .phy = HT,    195000,    0x00,     N(23),   8 },
231085ff963SMatthew Dillon 
232085ff963SMatthew Dillon     },
233085ff963SMatthew Dillon };
234085ff963SMatthew Dillon 
235085ff963SMatthew Dillon static struct ieee80211_rate_table ieee80211_11na_table = {
236085ff963SMatthew Dillon     .rateCount = 32,
237085ff963SMatthew Dillon     .info = {
238085ff963SMatthew Dillon /*                                   short            ctrl  */
239085ff963SMatthew Dillon /*                                Preamble  dot11Rate Rate */
240085ff963SMatthew Dillon      [0] = { .phy = OFDM,    6000,    0x00,     B(12),   0 },
241085ff963SMatthew Dillon      [1] = { .phy = OFDM,    9000,    0x00,        18,   0 },
242085ff963SMatthew Dillon      [2] = { .phy = OFDM,   12000,    0x00,     B(24),   2 },
243085ff963SMatthew Dillon      [3] = { .phy = OFDM,   18000,    0x00,        36,   2 },
244085ff963SMatthew Dillon      [4] = { .phy = OFDM,   24000,    0x00,     B(48),   4 },
245085ff963SMatthew Dillon      [5] = { .phy = OFDM,   36000,    0x00,        72,   4 },
246085ff963SMatthew Dillon      [6] = { .phy = OFDM,   48000,    0x00,        96,   4 },
247085ff963SMatthew Dillon      [7] = { .phy = OFDM,   54000,    0x00,       108,   4 },
248085ff963SMatthew Dillon 
249085ff963SMatthew Dillon      [8] = { .phy = HT,      6500,    0x00,      N(0),   0 },
250085ff963SMatthew Dillon      [9] = { .phy = HT,     13000,    0x00,      N(1),   2 },
251085ff963SMatthew Dillon     [10] = { .phy = HT,     19500,    0x00,      N(2),   2 },
252085ff963SMatthew Dillon     [11] = { .phy = HT,     26000,    0x00,      N(3),   4 },
253085ff963SMatthew Dillon     [12] = { .phy = HT,     39000,    0x00,      N(4),   4 },
254085ff963SMatthew Dillon     [13] = { .phy = HT,     52000,    0x00,      N(5),   4 },
255085ff963SMatthew Dillon     [14] = { .phy = HT,     58500,    0x00,      N(6),   4 },
256085ff963SMatthew Dillon     [15] = { .phy = HT,     65000,    0x00,      N(7),   4 },
257085ff963SMatthew Dillon 
258085ff963SMatthew Dillon     [16] = { .phy = HT,     13000,    0x00,      N(8),   0 },
259085ff963SMatthew Dillon     [17] = { .phy = HT,     26000,    0x00,      N(9),   2 },
260085ff963SMatthew Dillon     [18] = { .phy = HT,     39000,    0x00,     N(10),   2 },
261085ff963SMatthew Dillon     [19] = { .phy = HT,     52000,    0x00,     N(11),   4 },
262085ff963SMatthew Dillon     [20] = { .phy = HT,     78000,    0x00,     N(12),   4 },
263085ff963SMatthew Dillon     [21] = { .phy = HT,    104000,    0x00,     N(13),   4 },
264085ff963SMatthew Dillon     [22] = { .phy = HT,    117000,    0x00,     N(14),   4 },
265085ff963SMatthew Dillon     [23] = { .phy = HT,    130000,    0x00,     N(15),   4 },
266085ff963SMatthew Dillon 
267085ff963SMatthew Dillon     [24] = { .phy = HT,     19500,    0x00,     N(16),   0 },
268085ff963SMatthew Dillon     [25] = { .phy = HT,     39000,    0x00,     N(17),   2 },
269085ff963SMatthew Dillon     [26] = { .phy = HT,     58500,    0x00,     N(18),   2 },
270085ff963SMatthew Dillon     [27] = { .phy = HT,     78000,    0x00,     N(19),   4 },
271085ff963SMatthew Dillon     [28] = { .phy = HT,    117000,    0x00,     N(20),   4 },
272085ff963SMatthew Dillon     [29] = { .phy = HT,    156000,    0x00,     N(21),   4 },
273085ff963SMatthew Dillon     [30] = { .phy = HT,    175500,    0x00,     N(22),   4 },
274085ff963SMatthew Dillon     [31] = { .phy = HT,    195000,    0x00,     N(23),   4 },
275085ff963SMatthew Dillon 
276085ff963SMatthew Dillon     },
277085ff963SMatthew Dillon };
278085ff963SMatthew Dillon 
27932176cfdSRui Paulo #undef	Mb
28032176cfdSRui Paulo #undef	B
28132176cfdSRui Paulo #undef	OFDM
28232176cfdSRui Paulo #undef	HALF
28332176cfdSRui Paulo #undef	QUART
28432176cfdSRui Paulo #undef	CCK
28532176cfdSRui Paulo #undef	TURBO
28632176cfdSRui Paulo #undef	XR
287085ff963SMatthew Dillon #undef	HT
288085ff963SMatthew Dillon #undef	N
28932176cfdSRui Paulo 
29032176cfdSRui Paulo /*
29132176cfdSRui Paulo  * Setup a rate table's reverse lookup table and fill in
29232176cfdSRui Paulo  * ack durations.  The reverse lookup tables are assumed
29332176cfdSRui Paulo  * to be initialized to zero (or at least the first entry).
29432176cfdSRui Paulo  * We use this as a key that indicates whether or not
29532176cfdSRui Paulo  * we've previously setup the reverse lookup table.
29632176cfdSRui Paulo  *
29732176cfdSRui Paulo  * XXX not reentrant, but shouldn't matter
29832176cfdSRui Paulo  */
29932176cfdSRui Paulo static void
ieee80211_setup_ratetable(struct ieee80211_rate_table * rt)30032176cfdSRui Paulo ieee80211_setup_ratetable(struct ieee80211_rate_table *rt)
30132176cfdSRui Paulo {
30232176cfdSRui Paulo #define	WLAN_CTRL_FRAME_SIZE \
30332176cfdSRui Paulo 	(sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
30432176cfdSRui Paulo 
30532176cfdSRui Paulo 	int i;
30632176cfdSRui Paulo 
307085ff963SMatthew Dillon 	for (i = 0; i < nitems(rt->rateCodeToIndex); i++)
30832176cfdSRui Paulo 		rt->rateCodeToIndex[i] = (uint8_t) -1;
30932176cfdSRui Paulo 	for (i = 0; i < rt->rateCount; i++) {
31032176cfdSRui Paulo 		uint8_t code = rt->info[i].dot11Rate;
31132176cfdSRui Paulo 		uint8_t cix = rt->info[i].ctlRateIndex;
31232176cfdSRui Paulo 		uint8_t ctl_rate = rt->info[cix].dot11Rate;
31332176cfdSRui Paulo 
31432176cfdSRui Paulo 		/*
315085ff963SMatthew Dillon 		 * Map without the basic rate bit.
316085ff963SMatthew Dillon 		 *
317085ff963SMatthew Dillon 		 * It's up to the caller to ensure that the basic
318085ff963SMatthew Dillon 		 * rate bit is stripped here.
319085ff963SMatthew Dillon 		 *
320085ff963SMatthew Dillon 		 * For HT, use the MCS rate bit.
32132176cfdSRui Paulo 		 */
32232176cfdSRui Paulo 		code &= IEEE80211_RATE_VAL;
323085ff963SMatthew Dillon 		if (rt->info[i].phy == IEEE80211_T_HT) {
324085ff963SMatthew Dillon 			code |= IEEE80211_RATE_MCS;
32532176cfdSRui Paulo 		}
32632176cfdSRui Paulo 
327085ff963SMatthew Dillon 		/* XXX assume the control rate is non-MCS? */
328085ff963SMatthew Dillon 		ctl_rate &= IEEE80211_RATE_VAL;
329085ff963SMatthew Dillon 		rt->rateCodeToIndex[code] = i;
330085ff963SMatthew Dillon 
33132176cfdSRui Paulo 		/*
33232176cfdSRui Paulo 		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
33332176cfdSRui Paulo 		 *     depends on whether they are marked as basic rates;
33432176cfdSRui Paulo 		 *     the static tables are setup with an 11b-compatible
33532176cfdSRui Paulo 		 *     2Mb/s rate which will work but is suboptimal
33632176cfdSRui Paulo 		 *
33732176cfdSRui Paulo 		 * NB: Control rate is always less than or equal to the
33832176cfdSRui Paulo 		 *     current rate, so control rate's reverse lookup entry
33932176cfdSRui Paulo 		 *     has been installed and following call is safe.
34032176cfdSRui Paulo 		 */
34132176cfdSRui Paulo 		rt->info[i].lpAckDuration = ieee80211_compute_duration(rt,
34232176cfdSRui Paulo 			WLAN_CTRL_FRAME_SIZE, ctl_rate, 0);
34332176cfdSRui Paulo 		rt->info[i].spAckDuration = ieee80211_compute_duration(rt,
34432176cfdSRui Paulo 			WLAN_CTRL_FRAME_SIZE, ctl_rate, IEEE80211_F_SHPREAMBLE);
34532176cfdSRui Paulo 	}
34632176cfdSRui Paulo 
34732176cfdSRui Paulo #undef WLAN_CTRL_FRAME_SIZE
34832176cfdSRui Paulo }
34932176cfdSRui Paulo 
35032176cfdSRui Paulo /* Setup all rate tables */
35132176cfdSRui Paulo static void
ieee80211_phy_init(void)35232176cfdSRui Paulo ieee80211_phy_init(void)
35332176cfdSRui Paulo {
35432176cfdSRui Paulo 	static struct ieee80211_rate_table * const ratetables[] = {
35532176cfdSRui Paulo 		&ieee80211_half_table,
35632176cfdSRui Paulo 		&ieee80211_quarter_table,
357085ff963SMatthew Dillon 		&ieee80211_11na_table,
358085ff963SMatthew Dillon 		&ieee80211_11ng_table,
35932176cfdSRui Paulo 		&ieee80211_turbog_table,
36032176cfdSRui Paulo 		&ieee80211_turboa_table,
36132176cfdSRui Paulo 		&ieee80211_11a_table,
36232176cfdSRui Paulo 		&ieee80211_11g_table,
36332176cfdSRui Paulo 		&ieee80211_11b_table
36432176cfdSRui Paulo 	};
36532176cfdSRui Paulo 	int i;
36632176cfdSRui Paulo 
367085ff963SMatthew Dillon 	for (i = 0; i < nitems(ratetables); ++i)
36832176cfdSRui Paulo 		ieee80211_setup_ratetable(ratetables[i]);
36932176cfdSRui Paulo 
37032176cfdSRui Paulo }
37132176cfdSRui Paulo SYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL);
37232176cfdSRui Paulo 
37332176cfdSRui Paulo const struct ieee80211_rate_table *
ieee80211_get_ratetable(struct ieee80211_channel * c)37432176cfdSRui Paulo ieee80211_get_ratetable(struct ieee80211_channel *c)
37532176cfdSRui Paulo {
37632176cfdSRui Paulo 	const struct ieee80211_rate_table *rt;
37732176cfdSRui Paulo 
37832176cfdSRui Paulo 	/* XXX HT */
37932176cfdSRui Paulo 	if (IEEE80211_IS_CHAN_HALF(c))
38032176cfdSRui Paulo 		rt = &ieee80211_half_table;
38132176cfdSRui Paulo 	else if (IEEE80211_IS_CHAN_QUARTER(c))
38232176cfdSRui Paulo 		rt = &ieee80211_quarter_table;
38332176cfdSRui Paulo 	else if (IEEE80211_IS_CHAN_HTA(c))
384085ff963SMatthew Dillon 		rt = &ieee80211_11na_table;
38532176cfdSRui Paulo 	else if (IEEE80211_IS_CHAN_HTG(c))
386085ff963SMatthew Dillon 		rt = &ieee80211_11ng_table;
38732176cfdSRui Paulo 	else if (IEEE80211_IS_CHAN_108G(c))
38832176cfdSRui Paulo 		rt = &ieee80211_turbog_table;
38932176cfdSRui Paulo 	else if (IEEE80211_IS_CHAN_ST(c))
39032176cfdSRui Paulo 		rt = &ieee80211_turboa_table;
39132176cfdSRui Paulo 	else if (IEEE80211_IS_CHAN_TURBO(c))
39232176cfdSRui Paulo 		rt = &ieee80211_turboa_table;
39332176cfdSRui Paulo 	else if (IEEE80211_IS_CHAN_A(c))
39432176cfdSRui Paulo 		rt = &ieee80211_11a_table;
39532176cfdSRui Paulo 	else if (IEEE80211_IS_CHAN_ANYG(c))
39632176cfdSRui Paulo 		rt = &ieee80211_11g_table;
39732176cfdSRui Paulo 	else if (IEEE80211_IS_CHAN_B(c))
39832176cfdSRui Paulo 		rt = &ieee80211_11b_table;
39932176cfdSRui Paulo 	else {
40032176cfdSRui Paulo 		/* NB: should not get here */
401085ff963SMatthew Dillon 		panic("%s: no rate table for channel; freq %u flags 0x%x\n",
40232176cfdSRui Paulo 		      __func__, c->ic_freq, c->ic_flags);
40332176cfdSRui Paulo 	}
40432176cfdSRui Paulo 	return rt;
40532176cfdSRui Paulo }
40632176cfdSRui Paulo 
40732176cfdSRui Paulo /*
40832176cfdSRui Paulo  * Convert PLCP signal/rate field to 802.11 rate (.5Mbits/s)
40932176cfdSRui Paulo  *
41032176cfdSRui Paulo  * Note we do no parameter checking; this routine is mainly
41132176cfdSRui Paulo  * used to derive an 802.11 rate for constructing radiotap
41232176cfdSRui Paulo  * header data for rx frames.
41332176cfdSRui Paulo  *
41432176cfdSRui Paulo  * XXX might be a candidate for inline
41532176cfdSRui Paulo  */
41632176cfdSRui Paulo uint8_t
ieee80211_plcp2rate(uint8_t plcp,enum ieee80211_phytype type)41732176cfdSRui Paulo ieee80211_plcp2rate(uint8_t plcp, enum ieee80211_phytype type)
41832176cfdSRui Paulo {
41932176cfdSRui Paulo 	if (type == IEEE80211_T_OFDM) {
42032176cfdSRui Paulo 		static const uint8_t ofdm_plcp2rate[16] = {
42132176cfdSRui Paulo 			[0xb]	= 12,
42232176cfdSRui Paulo 			[0xf]	= 18,
42332176cfdSRui Paulo 			[0xa]	= 24,
42432176cfdSRui Paulo 			[0xe]	= 36,
42532176cfdSRui Paulo 			[0x9]	= 48,
42632176cfdSRui Paulo 			[0xd]	= 72,
42732176cfdSRui Paulo 			[0x8]	= 96,
42832176cfdSRui Paulo 			[0xc]	= 108
42932176cfdSRui Paulo 		};
43032176cfdSRui Paulo 		return ofdm_plcp2rate[plcp & 0xf];
43132176cfdSRui Paulo 	}
43232176cfdSRui Paulo 	if (type == IEEE80211_T_CCK) {
43332176cfdSRui Paulo 		static const uint8_t cck_plcp2rate[16] = {
43432176cfdSRui Paulo 			[0xa]	= 2,	/* 0x0a */
43532176cfdSRui Paulo 			[0x4]	= 4,	/* 0x14 */
43632176cfdSRui Paulo 			[0x7]	= 11,	/* 0x37 */
43732176cfdSRui Paulo 			[0xe]	= 22,	/* 0x6e */
43832176cfdSRui Paulo 			[0xc]	= 44,	/* 0xdc , actually PBCC */
43932176cfdSRui Paulo 		};
44032176cfdSRui Paulo 		return cck_plcp2rate[plcp & 0xf];
44132176cfdSRui Paulo 	}
44232176cfdSRui Paulo 	return 0;
44332176cfdSRui Paulo }
44432176cfdSRui Paulo 
44532176cfdSRui Paulo /*
44632176cfdSRui Paulo  * Covert 802.11 rate to PLCP signal.
44732176cfdSRui Paulo  */
44832176cfdSRui Paulo uint8_t
ieee80211_rate2plcp(int rate,enum ieee80211_phytype type)44932176cfdSRui Paulo ieee80211_rate2plcp(int rate, enum ieee80211_phytype type)
45032176cfdSRui Paulo {
45132176cfdSRui Paulo 	/* XXX ignore type for now since rates are unique */
45232176cfdSRui Paulo 	switch (rate) {
45332176cfdSRui Paulo 	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
45432176cfdSRui Paulo 	case 12:	return 0xb;
45532176cfdSRui Paulo 	case 18:	return 0xf;
45632176cfdSRui Paulo 	case 24:	return 0xa;
45732176cfdSRui Paulo 	case 36:	return 0xe;
45832176cfdSRui Paulo 	case 48:	return 0x9;
45932176cfdSRui Paulo 	case 72:	return 0xd;
46032176cfdSRui Paulo 	case 96:	return 0x8;
46132176cfdSRui Paulo 	case 108:	return 0xc;
46232176cfdSRui Paulo 	/* CCK rates (IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3) */
46332176cfdSRui Paulo 	case 2:		return 10;
46432176cfdSRui Paulo 	case 4:		return 20;
46532176cfdSRui Paulo 	case 11:	return 55;
46632176cfdSRui Paulo 	case 22:	return 110;
46732176cfdSRui Paulo 	/* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */
46832176cfdSRui Paulo 	case 44:	return 220;
46932176cfdSRui Paulo 	}
47032176cfdSRui Paulo 	return 0;		/* XXX unsupported/unknown rate */
47132176cfdSRui Paulo }
47232176cfdSRui Paulo 
47332176cfdSRui Paulo #define CCK_SIFS_TIME		10
47432176cfdSRui Paulo #define CCK_PREAMBLE_BITS	144
47532176cfdSRui Paulo #define CCK_PLCP_BITS		48
47632176cfdSRui Paulo 
47732176cfdSRui Paulo #define OFDM_SIFS_TIME		16
47832176cfdSRui Paulo #define OFDM_PREAMBLE_TIME	20
47932176cfdSRui Paulo #define OFDM_PLCP_BITS		22
48032176cfdSRui Paulo #define OFDM_SYMBOL_TIME	4
48132176cfdSRui Paulo 
48232176cfdSRui Paulo #define OFDM_HALF_SIFS_TIME	32
48332176cfdSRui Paulo #define OFDM_HALF_PREAMBLE_TIME	40
48432176cfdSRui Paulo #define OFDM_HALF_PLCP_BITS	22
48532176cfdSRui Paulo #define OFDM_HALF_SYMBOL_TIME	8
48632176cfdSRui Paulo 
48732176cfdSRui Paulo #define OFDM_QUARTER_SIFS_TIME 		64
48832176cfdSRui Paulo #define OFDM_QUARTER_PREAMBLE_TIME	80
48932176cfdSRui Paulo #define OFDM_QUARTER_PLCP_BITS		22
49032176cfdSRui Paulo #define OFDM_QUARTER_SYMBOL_TIME	16
49132176cfdSRui Paulo 
49232176cfdSRui Paulo #define TURBO_SIFS_TIME		8
49332176cfdSRui Paulo #define TURBO_PREAMBLE_TIME	14
49432176cfdSRui Paulo #define TURBO_PLCP_BITS		22
49532176cfdSRui Paulo #define TURBO_SYMBOL_TIME	4
49632176cfdSRui Paulo 
49732176cfdSRui Paulo /*
49832176cfdSRui Paulo  * Compute the time to transmit a frame of length frameLen bytes
49932176cfdSRui Paulo  * using the specified rate, phy, and short preamble setting.
50032176cfdSRui Paulo  * SIFS is included.
50132176cfdSRui Paulo  */
50232176cfdSRui Paulo uint16_t
ieee80211_compute_duration(const struct ieee80211_rate_table * rt,uint32_t frameLen,uint16_t rate,int isShortPreamble)50332176cfdSRui Paulo ieee80211_compute_duration(const struct ieee80211_rate_table *rt,
50432176cfdSRui Paulo 	uint32_t frameLen, uint16_t rate, int isShortPreamble)
50532176cfdSRui Paulo {
50632176cfdSRui Paulo 	uint8_t rix = rt->rateCodeToIndex[rate];
50732176cfdSRui Paulo 	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
50832176cfdSRui Paulo 	uint32_t kbps;
50932176cfdSRui Paulo 
51032176cfdSRui Paulo 	KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate));
51132176cfdSRui Paulo 	kbps = rt->info[rix].rateKbps;
51232176cfdSRui Paulo 	if (kbps == 0)			/* XXX bandaid for channel changes */
51332176cfdSRui Paulo 		return 0;
51432176cfdSRui Paulo 
51532176cfdSRui Paulo 	switch (rt->info[rix].phy) {
51632176cfdSRui Paulo 	case IEEE80211_T_CCK:
51732176cfdSRui Paulo 		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
51832176cfdSRui Paulo 		if (isShortPreamble && rt->info[rix].shortPreamble)
51932176cfdSRui Paulo 			phyTime >>= 1;
52032176cfdSRui Paulo 		numBits		= frameLen << 3;
52132176cfdSRui Paulo 		txTime		= CCK_SIFS_TIME + phyTime
52232176cfdSRui Paulo 				+ ((numBits * 1000)/kbps);
52332176cfdSRui Paulo 		break;
52432176cfdSRui Paulo 	case IEEE80211_T_OFDM:
52532176cfdSRui Paulo 		bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
52632176cfdSRui Paulo 		KASSERT(bitsPerSymbol != 0, ("full rate bps"));
52732176cfdSRui Paulo 
52832176cfdSRui Paulo 		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
52932176cfdSRui Paulo 		numSymbols	= howmany(numBits, bitsPerSymbol);
53032176cfdSRui Paulo 		txTime		= OFDM_SIFS_TIME
53132176cfdSRui Paulo 				+ OFDM_PREAMBLE_TIME
53232176cfdSRui Paulo 				+ (numSymbols * OFDM_SYMBOL_TIME);
53332176cfdSRui Paulo 		break;
53432176cfdSRui Paulo 	case IEEE80211_T_OFDM_HALF:
53532176cfdSRui Paulo 		bitsPerSymbol	= (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
53632176cfdSRui Paulo 		KASSERT(bitsPerSymbol != 0, ("1/4 rate bps"));
53732176cfdSRui Paulo 
53832176cfdSRui Paulo 		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
53932176cfdSRui Paulo 		numSymbols	= howmany(numBits, bitsPerSymbol);
54032176cfdSRui Paulo 		txTime		= OFDM_HALF_SIFS_TIME
54132176cfdSRui Paulo 				+ OFDM_HALF_PREAMBLE_TIME
54232176cfdSRui Paulo 				+ (numSymbols * OFDM_HALF_SYMBOL_TIME);
54332176cfdSRui Paulo 		break;
54432176cfdSRui Paulo 	case IEEE80211_T_OFDM_QUARTER:
54532176cfdSRui Paulo 		bitsPerSymbol	= (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
54632176cfdSRui Paulo 		KASSERT(bitsPerSymbol != 0, ("1/2 rate bps"));
54732176cfdSRui Paulo 
54832176cfdSRui Paulo 		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
54932176cfdSRui Paulo 		numSymbols	= howmany(numBits, bitsPerSymbol);
55032176cfdSRui Paulo 		txTime		= OFDM_QUARTER_SIFS_TIME
55132176cfdSRui Paulo 				+ OFDM_QUARTER_PREAMBLE_TIME
55232176cfdSRui Paulo 				+ (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
55332176cfdSRui Paulo 		break;
55432176cfdSRui Paulo 	case IEEE80211_T_TURBO:
55532176cfdSRui Paulo 		/* we still save OFDM rates in kbps - so double them */
55632176cfdSRui Paulo 		bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000;
55732176cfdSRui Paulo 		KASSERT(bitsPerSymbol != 0, ("turbo bps"));
55832176cfdSRui Paulo 
55932176cfdSRui Paulo 		numBits       = TURBO_PLCP_BITS + (frameLen << 3);
56032176cfdSRui Paulo 		numSymbols    = howmany(numBits, bitsPerSymbol);
56132176cfdSRui Paulo 		txTime        = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME
56232176cfdSRui Paulo 			      + (numSymbols * TURBO_SYMBOL_TIME);
56332176cfdSRui Paulo 		break;
56432176cfdSRui Paulo 	default:
565085ff963SMatthew Dillon 		panic("%s: unknown phy %u (rate %u)\n", __func__,
56632176cfdSRui Paulo 		      rt->info[rix].phy, rate);
56732176cfdSRui Paulo 		break;
56832176cfdSRui Paulo 	}
56932176cfdSRui Paulo 	return txTime;
57032176cfdSRui Paulo }
571085ff963SMatthew Dillon 
572085ff963SMatthew Dillon static const uint16_t ht20_bps[32] = {
573085ff963SMatthew Dillon 	26, 52, 78, 104, 156, 208, 234, 260,
574085ff963SMatthew Dillon 	52, 104, 156, 208, 312, 416, 468, 520,
575085ff963SMatthew Dillon 	78, 156, 234, 312, 468, 624, 702, 780,
576085ff963SMatthew Dillon 	104, 208, 312, 416, 624, 832, 936, 1040
577085ff963SMatthew Dillon };
578085ff963SMatthew Dillon static const uint16_t ht40_bps[32] = {
579085ff963SMatthew Dillon 	54, 108, 162, 216, 324, 432, 486, 540,
580085ff963SMatthew Dillon 	108, 216, 324, 432, 648, 864, 972, 1080,
581085ff963SMatthew Dillon 	162, 324, 486, 648, 972, 1296, 1458, 1620,
582085ff963SMatthew Dillon 	216, 432, 648, 864, 1296, 1728, 1944, 2160
583085ff963SMatthew Dillon };
584085ff963SMatthew Dillon 
585085ff963SMatthew Dillon 
586085ff963SMatthew Dillon #define	OFDM_PLCP_BITS	22
587085ff963SMatthew Dillon #define	HT_L_STF	8
588085ff963SMatthew Dillon #define	HT_L_LTF	8
589085ff963SMatthew Dillon #define	HT_L_SIG	4
590085ff963SMatthew Dillon #define	HT_SIG		8
591085ff963SMatthew Dillon #define	HT_STF		4
592085ff963SMatthew Dillon #define	HT_LTF(n)	((n) * 4)
593085ff963SMatthew Dillon 
5944f655ef5SMatthew Dillon #define	HT_RC_2_MCS(_rc)	((_rc) & 0x1f)
595085ff963SMatthew Dillon #define	HT_RC_2_STREAMS(_rc)	((((_rc) & 0x78) >> 3) + 1)
596085ff963SMatthew Dillon #define	IS_HT_RATE(_rc)		( (_rc) & IEEE80211_RATE_MCS)
597085ff963SMatthew Dillon 
598085ff963SMatthew Dillon /*
599085ff963SMatthew Dillon  * Calculate the transmit duration of an 11n frame.
600085ff963SMatthew Dillon  */
601085ff963SMatthew Dillon uint32_t
ieee80211_compute_duration_ht(uint32_t frameLen,uint16_t rate,int streams,int isht40,int isShortGI)602085ff963SMatthew Dillon ieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate,
603085ff963SMatthew Dillon     int streams, int isht40, int isShortGI)
604085ff963SMatthew Dillon {
605085ff963SMatthew Dillon 	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
606085ff963SMatthew Dillon 
607085ff963SMatthew Dillon 	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
608085ff963SMatthew Dillon 	KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
609085ff963SMatthew Dillon 
610085ff963SMatthew Dillon 	if (isht40)
611085ff963SMatthew Dillon 		bitsPerSymbol = ht40_bps[rate & 0x1f];
612085ff963SMatthew Dillon 	else
613085ff963SMatthew Dillon 		bitsPerSymbol = ht20_bps[rate & 0x1f];
614085ff963SMatthew Dillon 	numBits = OFDM_PLCP_BITS + (frameLen << 3);
615085ff963SMatthew Dillon 	numSymbols = howmany(numBits, bitsPerSymbol);
616085ff963SMatthew Dillon 	if (isShortGI)
617085ff963SMatthew Dillon 		txTime = ((numSymbols * 18) + 4) / 5;   /* 3.6us */
618085ff963SMatthew Dillon 	else
619085ff963SMatthew Dillon 		txTime = numSymbols * 4;                /* 4us */
620085ff963SMatthew Dillon 	return txTime + HT_L_STF + HT_L_LTF +
621085ff963SMatthew Dillon 	    HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
622085ff963SMatthew Dillon }
623085ff963SMatthew Dillon 
624085ff963SMatthew Dillon #undef	IS_HT_RATE
625085ff963SMatthew Dillon #undef	HT_RC_2_STREAMS
626085ff963SMatthew Dillon #undef	HT_RC_2_MCS
627085ff963SMatthew Dillon #undef	HT_LTF
628085ff963SMatthew Dillon #undef	HT_STF
629085ff963SMatthew Dillon #undef	HT_SIG
630085ff963SMatthew Dillon #undef	HT_L_SIG
631085ff963SMatthew Dillon #undef	HT_L_LTF
632085ff963SMatthew Dillon #undef	HT_L_STF
633085ff963SMatthew Dillon #undef	OFDM_PLCP_BITS
634