xref: /haiku/src/libs/compat/freebsd_wlan/net80211/ieee80211_phy.c (revision 8244a9baad63102214028afbb3b1e2326f4c4cca)
1753c7e08SAugustin Cavalier /*-
2*8244a9baSAugustin Cavalier  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*8244a9baSAugustin Cavalier  *
4753c7e08SAugustin Cavalier  * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
5753c7e08SAugustin Cavalier  * All rights reserved.
6753c7e08SAugustin Cavalier  *
7753c7e08SAugustin Cavalier  * Redistribution and use in source and binary forms, with or without
8753c7e08SAugustin Cavalier  * modification, are permitted provided that the following conditions
9753c7e08SAugustin Cavalier  * are met:
10753c7e08SAugustin Cavalier  * 1. Redistributions of source code must retain the above copyright
11753c7e08SAugustin Cavalier  *    notice, this list of conditions and the following disclaimer.
12753c7e08SAugustin Cavalier  * 2. Redistributions in binary form must reproduce the above copyright
13753c7e08SAugustin Cavalier  *    notice, this list of conditions and the following disclaimer in the
14753c7e08SAugustin Cavalier  *    documentation and/or other materials provided with the distribution.
15753c7e08SAugustin Cavalier  *
16753c7e08SAugustin Cavalier  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17753c7e08SAugustin Cavalier  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18753c7e08SAugustin Cavalier  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19753c7e08SAugustin Cavalier  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20753c7e08SAugustin Cavalier  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21753c7e08SAugustin Cavalier  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22753c7e08SAugustin Cavalier  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23753c7e08SAugustin Cavalier  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24753c7e08SAugustin Cavalier  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25753c7e08SAugustin Cavalier  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26753c7e08SAugustin Cavalier  */
27753c7e08SAugustin Cavalier 
28753c7e08SAugustin Cavalier #include <sys/cdefs.h>
29*8244a9baSAugustin Cavalier __FBSDID("$FreeBSD: releng/12.0/sys/net80211/ieee80211_phy.c 326272 2017-11-27 15:23:17Z pfg $");
30753c7e08SAugustin Cavalier 
31753c7e08SAugustin Cavalier /*
32753c7e08SAugustin Cavalier  * IEEE 802.11 PHY-related support.
33753c7e08SAugustin Cavalier  */
34753c7e08SAugustin Cavalier 
35753c7e08SAugustin Cavalier #include "opt_inet.h"
36753c7e08SAugustin Cavalier 
37753c7e08SAugustin Cavalier #include <sys/param.h>
38753c7e08SAugustin Cavalier #include <sys/kernel.h>
39753c7e08SAugustin Cavalier #include <sys/systm.h>
40753c7e08SAugustin Cavalier #include <sys/malloc.h>
41753c7e08SAugustin Cavalier 
42753c7e08SAugustin Cavalier #include <sys/socket.h>
43753c7e08SAugustin Cavalier 
44753c7e08SAugustin Cavalier #include <net/if.h>
45753c7e08SAugustin Cavalier #include <net/if_media.h>
46753c7e08SAugustin Cavalier 
47753c7e08SAugustin Cavalier #include <net/ethernet.h>
48753c7e08SAugustin Cavalier #include <net/route.h>
49753c7e08SAugustin Cavalier 
50753c7e08SAugustin Cavalier #include <net80211/ieee80211_var.h>
51753c7e08SAugustin Cavalier #include <net80211/ieee80211_phy.h>
52753c7e08SAugustin Cavalier 
53753c7e08SAugustin Cavalier #ifdef notyet
54753c7e08SAugustin Cavalier struct ieee80211_ds_plcp_hdr {
55753c7e08SAugustin Cavalier 	uint8_t		i_signal;
56753c7e08SAugustin Cavalier 	uint8_t		i_service;
57753c7e08SAugustin Cavalier 	uint16_t	i_length;
58753c7e08SAugustin Cavalier 	uint16_t	i_crc;
59753c7e08SAugustin Cavalier } __packed;
60753c7e08SAugustin Cavalier 
61753c7e08SAugustin Cavalier #endif	/* notyet */
62753c7e08SAugustin Cavalier 
63753c7e08SAugustin Cavalier /* shorthands to compact tables for readability */
64753c7e08SAugustin Cavalier #define	OFDM	IEEE80211_T_OFDM
65753c7e08SAugustin Cavalier #define	CCK	IEEE80211_T_CCK
66753c7e08SAugustin Cavalier #define	TURBO	IEEE80211_T_TURBO
67753c7e08SAugustin Cavalier #define	HALF	IEEE80211_T_OFDM_HALF
68753c7e08SAugustin Cavalier #define	QUART	IEEE80211_T_OFDM_QUARTER
69753c7e08SAugustin Cavalier #define	HT	IEEE80211_T_HT
70753c7e08SAugustin Cavalier /* XXX the 11n and the basic rate flag are unfortunately overlapping. Grr. */
71753c7e08SAugustin Cavalier #define	N(r)	(IEEE80211_RATE_MCS | r)
72753c7e08SAugustin Cavalier #define	PBCC	(IEEE80211_T_OFDM_QUARTER+1)		/* XXX */
73753c7e08SAugustin Cavalier #define	B(r)	(IEEE80211_RATE_BASIC | r)
74753c7e08SAugustin Cavalier #define	Mb(x)	(x*1000)
75753c7e08SAugustin Cavalier 
76753c7e08SAugustin Cavalier static struct ieee80211_rate_table ieee80211_11b_table = {
77753c7e08SAugustin Cavalier     .rateCount = 4,		/* XXX no PBCC */
78753c7e08SAugustin Cavalier     .info = {
79753c7e08SAugustin Cavalier /*                                   short            ctrl  */
80753c7e08SAugustin Cavalier /*                                Preamble  dot11Rate Rate */
81753c7e08SAugustin Cavalier      [0] = { .phy = CCK,     1000,    0x00,      B(2),   0 },/*   1 Mb */
82753c7e08SAugustin Cavalier      [1] = { .phy = CCK,     2000,    0x04,      B(4),   1 },/*   2 Mb */
83753c7e08SAugustin Cavalier      [2] = { .phy = CCK,     5500,    0x04,     B(11),   1 },/* 5.5 Mb */
84753c7e08SAugustin Cavalier      [3] = { .phy = CCK,    11000,    0x04,     B(22),   1 },/*  11 Mb */
85753c7e08SAugustin Cavalier      [4] = { .phy = PBCC,   22000,    0x04,        44,   3 } /*  22 Mb */
86753c7e08SAugustin Cavalier     },
87753c7e08SAugustin Cavalier };
88753c7e08SAugustin Cavalier 
89753c7e08SAugustin Cavalier static struct ieee80211_rate_table ieee80211_11g_table = {
90753c7e08SAugustin Cavalier     .rateCount = 12,
91753c7e08SAugustin Cavalier     .info = {
92753c7e08SAugustin Cavalier /*                                   short            ctrl  */
93753c7e08SAugustin Cavalier /*                                Preamble  dot11Rate Rate */
94753c7e08SAugustin Cavalier      [0] = { .phy = CCK,     1000,    0x00,      B(2),   0 },
95753c7e08SAugustin Cavalier      [1] = { .phy = CCK,     2000,    0x04,      B(4),   1 },
96753c7e08SAugustin Cavalier      [2] = { .phy = CCK,     5500,    0x04,     B(11),   2 },
97753c7e08SAugustin Cavalier      [3] = { .phy = CCK,    11000,    0x04,     B(22),   3 },
98753c7e08SAugustin Cavalier      [4] = { .phy = OFDM,    6000,    0x00,        12,   4 },
99753c7e08SAugustin Cavalier      [5] = { .phy = OFDM,    9000,    0x00,        18,   4 },
100753c7e08SAugustin Cavalier      [6] = { .phy = OFDM,   12000,    0x00,        24,   6 },
101753c7e08SAugustin Cavalier      [7] = { .phy = OFDM,   18000,    0x00,        36,   6 },
102753c7e08SAugustin Cavalier      [8] = { .phy = OFDM,   24000,    0x00,        48,   8 },
103753c7e08SAugustin Cavalier      [9] = { .phy = OFDM,   36000,    0x00,        72,   8 },
104753c7e08SAugustin Cavalier     [10] = { .phy = OFDM,   48000,    0x00,        96,   8 },
105753c7e08SAugustin Cavalier     [11] = { .phy = OFDM,   54000,    0x00,       108,   8 }
106753c7e08SAugustin Cavalier     },
107753c7e08SAugustin Cavalier };
108753c7e08SAugustin Cavalier 
109753c7e08SAugustin Cavalier static struct ieee80211_rate_table ieee80211_11a_table = {
110753c7e08SAugustin Cavalier     .rateCount = 8,
111753c7e08SAugustin Cavalier     .info = {
112753c7e08SAugustin Cavalier /*                                   short            ctrl  */
113753c7e08SAugustin Cavalier /*                                Preamble  dot11Rate Rate */
114753c7e08SAugustin Cavalier      [0] = { .phy = OFDM,    6000,    0x00,     B(12),   0 },
115753c7e08SAugustin Cavalier      [1] = { .phy = OFDM,    9000,    0x00,        18,   0 },
116753c7e08SAugustin Cavalier      [2] = { .phy = OFDM,   12000,    0x00,     B(24),   2 },
117753c7e08SAugustin Cavalier      [3] = { .phy = OFDM,   18000,    0x00,        36,   2 },
118753c7e08SAugustin Cavalier      [4] = { .phy = OFDM,   24000,    0x00,     B(48),   4 },
119753c7e08SAugustin Cavalier      [5] = { .phy = OFDM,   36000,    0x00,        72,   4 },
120753c7e08SAugustin Cavalier      [6] = { .phy = OFDM,   48000,    0x00,        96,   4 },
121753c7e08SAugustin Cavalier      [7] = { .phy = OFDM,   54000,    0x00,       108,   4 }
122753c7e08SAugustin Cavalier     },
123753c7e08SAugustin Cavalier };
124753c7e08SAugustin Cavalier 
125753c7e08SAugustin Cavalier static struct ieee80211_rate_table ieee80211_half_table = {
126753c7e08SAugustin Cavalier     .rateCount = 8,
127753c7e08SAugustin Cavalier     .info = {
128753c7e08SAugustin Cavalier /*                                   short            ctrl  */
129753c7e08SAugustin Cavalier /*                                Preamble  dot11Rate Rate */
130753c7e08SAugustin Cavalier      [0] = { .phy = HALF,    3000,    0x00,      B(6),   0 },
131753c7e08SAugustin Cavalier      [1] = { .phy = HALF,    4500,    0x00,         9,   0 },
132753c7e08SAugustin Cavalier      [2] = { .phy = HALF,    6000,    0x00,     B(12),   2 },
133753c7e08SAugustin Cavalier      [3] = { .phy = HALF,    9000,    0x00,        18,   2 },
134753c7e08SAugustin Cavalier      [4] = { .phy = HALF,   12000,    0x00,     B(24),   4 },
135753c7e08SAugustin Cavalier      [5] = { .phy = HALF,   18000,    0x00,        36,   4 },
136753c7e08SAugustin Cavalier      [6] = { .phy = HALF,   24000,    0x00,        48,   4 },
137753c7e08SAugustin Cavalier      [7] = { .phy = HALF,   27000,    0x00,        54,   4 }
138753c7e08SAugustin Cavalier     },
139753c7e08SAugustin Cavalier };
140753c7e08SAugustin Cavalier 
141753c7e08SAugustin Cavalier static struct ieee80211_rate_table ieee80211_quarter_table = {
142753c7e08SAugustin Cavalier     .rateCount = 8,
143753c7e08SAugustin Cavalier     .info = {
144753c7e08SAugustin Cavalier /*                                   short            ctrl  */
145753c7e08SAugustin Cavalier /*                                Preamble  dot11Rate Rate */
146753c7e08SAugustin Cavalier      [0] = { .phy = QUART,   1500,    0x00,      B(3),   0 },
147753c7e08SAugustin Cavalier      [1] = { .phy = QUART,   2250,    0x00,         4,   0 },
148753c7e08SAugustin Cavalier      [2] = { .phy = QUART,   3000,    0x00,      B(9),   2 },
149753c7e08SAugustin Cavalier      [3] = { .phy = QUART,   4500,    0x00,         9,   2 },
150753c7e08SAugustin Cavalier      [4] = { .phy = QUART,   6000,    0x00,     B(12),   4 },
151753c7e08SAugustin Cavalier      [5] = { .phy = QUART,   9000,    0x00,        18,   4 },
152753c7e08SAugustin Cavalier      [6] = { .phy = QUART,  12000,    0x00,        24,   4 },
153753c7e08SAugustin Cavalier      [7] = { .phy = QUART,  13500,    0x00,        27,   4 }
154753c7e08SAugustin Cavalier     },
155753c7e08SAugustin Cavalier };
156753c7e08SAugustin Cavalier 
157753c7e08SAugustin Cavalier static struct ieee80211_rate_table ieee80211_turbog_table = {
158753c7e08SAugustin Cavalier     .rateCount = 7,
159753c7e08SAugustin Cavalier     .info = {
160753c7e08SAugustin Cavalier /*                                   short            ctrl  */
161753c7e08SAugustin Cavalier /*                                Preamble  dot11Rate Rate */
162753c7e08SAugustin Cavalier      [0] = { .phy = TURBO,   12000,   0x00,     B(12),   0 },
163753c7e08SAugustin Cavalier      [1] = { .phy = TURBO,   24000,   0x00,     B(24),   1 },
164753c7e08SAugustin Cavalier      [2] = { .phy = TURBO,   36000,   0x00,        36,   1 },
165753c7e08SAugustin Cavalier      [3] = { .phy = TURBO,   48000,   0x00,     B(48),   3 },
166753c7e08SAugustin Cavalier      [4] = { .phy = TURBO,   72000,   0x00,        72,   3 },
167753c7e08SAugustin Cavalier      [5] = { .phy = TURBO,   96000,   0x00,        96,   3 },
168753c7e08SAugustin Cavalier      [6] = { .phy = TURBO,  108000,   0x00,       108,   3 }
169753c7e08SAugustin Cavalier     },
170753c7e08SAugustin Cavalier };
171753c7e08SAugustin Cavalier 
172753c7e08SAugustin Cavalier static struct ieee80211_rate_table ieee80211_turboa_table = {
173753c7e08SAugustin Cavalier     .rateCount = 8,
174753c7e08SAugustin Cavalier     .info = {
175753c7e08SAugustin Cavalier /*                                   short            ctrl  */
176753c7e08SAugustin Cavalier /*                                Preamble  dot11Rate Rate */
177753c7e08SAugustin Cavalier      [0] = { .phy = TURBO,   12000,   0x00,     B(12),   0 },
178753c7e08SAugustin Cavalier      [1] = { .phy = TURBO,   18000,   0x00,        18,   0 },
179753c7e08SAugustin Cavalier      [2] = { .phy = TURBO,   24000,   0x00,     B(24),   2 },
180753c7e08SAugustin Cavalier      [3] = { .phy = TURBO,   36000,   0x00,        36,   2 },
181753c7e08SAugustin Cavalier      [4] = { .phy = TURBO,   48000,   0x00,     B(48),   4 },
182753c7e08SAugustin Cavalier      [5] = { .phy = TURBO,   72000,   0x00,        72,   4 },
183753c7e08SAugustin Cavalier      [6] = { .phy = TURBO,   96000,   0x00,        96,   4 },
184753c7e08SAugustin Cavalier      [7] = { .phy = TURBO,  108000,   0x00,       108,   4 }
185753c7e08SAugustin Cavalier     },
186753c7e08SAugustin Cavalier };
187753c7e08SAugustin Cavalier 
188753c7e08SAugustin Cavalier static struct ieee80211_rate_table ieee80211_11ng_table = {
189753c7e08SAugustin Cavalier     .rateCount = 36,
190753c7e08SAugustin Cavalier     .info = {
191753c7e08SAugustin Cavalier /*                                   short            ctrl  */
192753c7e08SAugustin Cavalier /*                                Preamble  dot11Rate Rate */
193753c7e08SAugustin Cavalier      [0] = { .phy = CCK,     1000,    0x00,      B(2),   0 },
194753c7e08SAugustin Cavalier      [1] = { .phy = CCK,     2000,    0x04,      B(4),   1 },
195753c7e08SAugustin Cavalier      [2] = { .phy = CCK,     5500,    0x04,     B(11),   2 },
196753c7e08SAugustin Cavalier      [3] = { .phy = CCK,    11000,    0x04,     B(22),   3 },
197753c7e08SAugustin Cavalier      [4] = { .phy = OFDM,    6000,    0x00,        12,   4 },
198753c7e08SAugustin Cavalier      [5] = { .phy = OFDM,    9000,    0x00,        18,   4 },
199753c7e08SAugustin Cavalier      [6] = { .phy = OFDM,   12000,    0x00,        24,   6 },
200753c7e08SAugustin Cavalier      [7] = { .phy = OFDM,   18000,    0x00,        36,   6 },
201753c7e08SAugustin Cavalier      [8] = { .phy = OFDM,   24000,    0x00,        48,   8 },
202753c7e08SAugustin Cavalier      [9] = { .phy = OFDM,   36000,    0x00,        72,   8 },
203753c7e08SAugustin Cavalier     [10] = { .phy = OFDM,   48000,    0x00,        96,   8 },
204753c7e08SAugustin Cavalier     [11] = { .phy = OFDM,   54000,    0x00,       108,   8 },
205753c7e08SAugustin Cavalier 
206753c7e08SAugustin Cavalier     [12] = { .phy = HT,      6500,    0x00,      N(0),   4 },
207753c7e08SAugustin Cavalier     [13] = { .phy = HT,     13000,    0x00,      N(1),   6 },
208753c7e08SAugustin Cavalier     [14] = { .phy = HT,     19500,    0x00,      N(2),   6 },
209753c7e08SAugustin Cavalier     [15] = { .phy = HT,     26000,    0x00,      N(3),   8 },
210753c7e08SAugustin Cavalier     [16] = { .phy = HT,     39000,    0x00,      N(4),   8 },
211753c7e08SAugustin Cavalier     [17] = { .phy = HT,     52000,    0x00,      N(5),   8 },
212753c7e08SAugustin Cavalier     [18] = { .phy = HT,     58500,    0x00,      N(6),   8 },
213753c7e08SAugustin Cavalier     [19] = { .phy = HT,     65000,    0x00,      N(7),   8 },
214753c7e08SAugustin Cavalier 
215753c7e08SAugustin Cavalier     [20] = { .phy = HT,     13000,    0x00,      N(8),   4 },
216753c7e08SAugustin Cavalier     [21] = { .phy = HT,     26000,    0x00,      N(9),   6 },
217753c7e08SAugustin Cavalier     [22] = { .phy = HT,     39000,    0x00,     N(10),   6 },
218753c7e08SAugustin Cavalier     [23] = { .phy = HT,     52000,    0x00,     N(11),   8 },
219753c7e08SAugustin Cavalier     [24] = { .phy = HT,     78000,    0x00,     N(12),   8 },
220753c7e08SAugustin Cavalier     [25] = { .phy = HT,    104000,    0x00,     N(13),   8 },
221753c7e08SAugustin Cavalier     [26] = { .phy = HT,    117000,    0x00,     N(14),   8 },
222753c7e08SAugustin Cavalier     [27] = { .phy = HT,    130000,    0x00,     N(15),   8 },
223753c7e08SAugustin Cavalier 
224753c7e08SAugustin Cavalier     [28] = { .phy = HT,     19500,    0x00,     N(16),   4 },
225753c7e08SAugustin Cavalier     [29] = { .phy = HT,     39000,    0x00,     N(17),   6 },
226753c7e08SAugustin Cavalier     [30] = { .phy = HT,     58500,    0x00,     N(18),   6 },
227753c7e08SAugustin Cavalier     [31] = { .phy = HT,     78000,    0x00,     N(19),   8 },
228753c7e08SAugustin Cavalier     [32] = { .phy = HT,    117000,    0x00,     N(20),   8 },
229753c7e08SAugustin Cavalier     [33] = { .phy = HT,    156000,    0x00,     N(21),   8 },
230753c7e08SAugustin Cavalier     [34] = { .phy = HT,    175500,    0x00,     N(22),   8 },
231753c7e08SAugustin Cavalier     [35] = { .phy = HT,    195000,    0x00,     N(23),   8 },
232753c7e08SAugustin Cavalier 
233753c7e08SAugustin Cavalier     },
234753c7e08SAugustin Cavalier };
235753c7e08SAugustin Cavalier 
236753c7e08SAugustin Cavalier static struct ieee80211_rate_table ieee80211_11na_table = {
237753c7e08SAugustin Cavalier     .rateCount = 32,
238753c7e08SAugustin Cavalier     .info = {
239753c7e08SAugustin Cavalier /*                                   short            ctrl  */
240753c7e08SAugustin Cavalier /*                                Preamble  dot11Rate Rate */
241753c7e08SAugustin Cavalier      [0] = { .phy = OFDM,    6000,    0x00,     B(12),   0 },
242753c7e08SAugustin Cavalier      [1] = { .phy = OFDM,    9000,    0x00,        18,   0 },
243753c7e08SAugustin Cavalier      [2] = { .phy = OFDM,   12000,    0x00,     B(24),   2 },
244753c7e08SAugustin Cavalier      [3] = { .phy = OFDM,   18000,    0x00,        36,   2 },
245753c7e08SAugustin Cavalier      [4] = { .phy = OFDM,   24000,    0x00,     B(48),   4 },
246753c7e08SAugustin Cavalier      [5] = { .phy = OFDM,   36000,    0x00,        72,   4 },
247753c7e08SAugustin Cavalier      [6] = { .phy = OFDM,   48000,    0x00,        96,   4 },
248753c7e08SAugustin Cavalier      [7] = { .phy = OFDM,   54000,    0x00,       108,   4 },
249753c7e08SAugustin Cavalier 
250753c7e08SAugustin Cavalier      [8] = { .phy = HT,      6500,    0x00,      N(0),   0 },
251753c7e08SAugustin Cavalier      [9] = { .phy = HT,     13000,    0x00,      N(1),   2 },
252753c7e08SAugustin Cavalier     [10] = { .phy = HT,     19500,    0x00,      N(2),   2 },
253753c7e08SAugustin Cavalier     [11] = { .phy = HT,     26000,    0x00,      N(3),   4 },
254753c7e08SAugustin Cavalier     [12] = { .phy = HT,     39000,    0x00,      N(4),   4 },
255753c7e08SAugustin Cavalier     [13] = { .phy = HT,     52000,    0x00,      N(5),   4 },
256753c7e08SAugustin Cavalier     [14] = { .phy = HT,     58500,    0x00,      N(6),   4 },
257753c7e08SAugustin Cavalier     [15] = { .phy = HT,     65000,    0x00,      N(7),   4 },
258753c7e08SAugustin Cavalier 
259753c7e08SAugustin Cavalier     [16] = { .phy = HT,     13000,    0x00,      N(8),   0 },
260753c7e08SAugustin Cavalier     [17] = { .phy = HT,     26000,    0x00,      N(9),   2 },
261753c7e08SAugustin Cavalier     [18] = { .phy = HT,     39000,    0x00,     N(10),   2 },
262753c7e08SAugustin Cavalier     [19] = { .phy = HT,     52000,    0x00,     N(11),   4 },
263753c7e08SAugustin Cavalier     [20] = { .phy = HT,     78000,    0x00,     N(12),   4 },
264753c7e08SAugustin Cavalier     [21] = { .phy = HT,    104000,    0x00,     N(13),   4 },
265753c7e08SAugustin Cavalier     [22] = { .phy = HT,    117000,    0x00,     N(14),   4 },
266753c7e08SAugustin Cavalier     [23] = { .phy = HT,    130000,    0x00,     N(15),   4 },
267753c7e08SAugustin Cavalier 
268753c7e08SAugustin Cavalier     [24] = { .phy = HT,     19500,    0x00,     N(16),   0 },
269753c7e08SAugustin Cavalier     [25] = { .phy = HT,     39000,    0x00,     N(17),   2 },
270753c7e08SAugustin Cavalier     [26] = { .phy = HT,     58500,    0x00,     N(18),   2 },
271753c7e08SAugustin Cavalier     [27] = { .phy = HT,     78000,    0x00,     N(19),   4 },
272753c7e08SAugustin Cavalier     [28] = { .phy = HT,    117000,    0x00,     N(20),   4 },
273753c7e08SAugustin Cavalier     [29] = { .phy = HT,    156000,    0x00,     N(21),   4 },
274753c7e08SAugustin Cavalier     [30] = { .phy = HT,    175500,    0x00,     N(22),   4 },
275753c7e08SAugustin Cavalier     [31] = { .phy = HT,    195000,    0x00,     N(23),   4 },
276753c7e08SAugustin Cavalier 
277753c7e08SAugustin Cavalier     },
278753c7e08SAugustin Cavalier };
279753c7e08SAugustin Cavalier 
280753c7e08SAugustin Cavalier #undef	Mb
281753c7e08SAugustin Cavalier #undef	B
282753c7e08SAugustin Cavalier #undef	OFDM
283753c7e08SAugustin Cavalier #undef	HALF
284753c7e08SAugustin Cavalier #undef	QUART
285753c7e08SAugustin Cavalier #undef	CCK
286753c7e08SAugustin Cavalier #undef	TURBO
287753c7e08SAugustin Cavalier #undef	XR
288753c7e08SAugustin Cavalier #undef	HT
289753c7e08SAugustin Cavalier #undef	N
290753c7e08SAugustin Cavalier 
291753c7e08SAugustin Cavalier /*
292753c7e08SAugustin Cavalier  * Setup a rate table's reverse lookup table and fill in
293753c7e08SAugustin Cavalier  * ack durations.  The reverse lookup tables are assumed
294753c7e08SAugustin Cavalier  * to be initialized to zero (or at least the first entry).
295753c7e08SAugustin Cavalier  * We use this as a key that indicates whether or not
296753c7e08SAugustin Cavalier  * we've previously setup the reverse lookup table.
297753c7e08SAugustin Cavalier  *
298753c7e08SAugustin Cavalier  * XXX not reentrant, but shouldn't matter
299753c7e08SAugustin Cavalier  */
300753c7e08SAugustin Cavalier static void
301753c7e08SAugustin Cavalier ieee80211_setup_ratetable(struct ieee80211_rate_table *rt)
302753c7e08SAugustin Cavalier {
303753c7e08SAugustin Cavalier #define	WLAN_CTRL_FRAME_SIZE \
304753c7e08SAugustin Cavalier 	(sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN)
305753c7e08SAugustin Cavalier 
306753c7e08SAugustin Cavalier 	int i;
307753c7e08SAugustin Cavalier 
308753c7e08SAugustin Cavalier 	for (i = 0; i < nitems(rt->rateCodeToIndex); i++)
309753c7e08SAugustin Cavalier 		rt->rateCodeToIndex[i] = (uint8_t) -1;
310753c7e08SAugustin Cavalier 	for (i = 0; i < rt->rateCount; i++) {
311753c7e08SAugustin Cavalier 		uint8_t code = rt->info[i].dot11Rate;
312753c7e08SAugustin Cavalier 		uint8_t cix = rt->info[i].ctlRateIndex;
313753c7e08SAugustin Cavalier 		uint8_t ctl_rate = rt->info[cix].dot11Rate;
314753c7e08SAugustin Cavalier 
315753c7e08SAugustin Cavalier 		/*
316753c7e08SAugustin Cavalier 		 * Map without the basic rate bit.
317753c7e08SAugustin Cavalier 		 *
318753c7e08SAugustin Cavalier 		 * It's up to the caller to ensure that the basic
319753c7e08SAugustin Cavalier 		 * rate bit is stripped here.
320753c7e08SAugustin Cavalier 		 *
321753c7e08SAugustin Cavalier 		 * For HT, use the MCS rate bit.
322753c7e08SAugustin Cavalier 		 */
323753c7e08SAugustin Cavalier 		code &= IEEE80211_RATE_VAL;
324753c7e08SAugustin Cavalier 		if (rt->info[i].phy == IEEE80211_T_HT) {
325753c7e08SAugustin Cavalier 			code |= IEEE80211_RATE_MCS;
326753c7e08SAugustin Cavalier 		}
327753c7e08SAugustin Cavalier 
328753c7e08SAugustin Cavalier 		/* XXX assume the control rate is non-MCS? */
329753c7e08SAugustin Cavalier 		ctl_rate &= IEEE80211_RATE_VAL;
330753c7e08SAugustin Cavalier 		rt->rateCodeToIndex[code] = i;
331753c7e08SAugustin Cavalier 
332753c7e08SAugustin Cavalier 		/*
333753c7e08SAugustin Cavalier 		 * XXX for 11g the control rate to use for 5.5 and 11 Mb/s
334753c7e08SAugustin Cavalier 		 *     depends on whether they are marked as basic rates;
335753c7e08SAugustin Cavalier 		 *     the static tables are setup with an 11b-compatible
336753c7e08SAugustin Cavalier 		 *     2Mb/s rate which will work but is suboptimal
337753c7e08SAugustin Cavalier 		 *
338753c7e08SAugustin Cavalier 		 * NB: Control rate is always less than or equal to the
339753c7e08SAugustin Cavalier 		 *     current rate, so control rate's reverse lookup entry
340753c7e08SAugustin Cavalier 		 *     has been installed and following call is safe.
341753c7e08SAugustin Cavalier 		 */
342753c7e08SAugustin Cavalier 		rt->info[i].lpAckDuration = ieee80211_compute_duration(rt,
343753c7e08SAugustin Cavalier 			WLAN_CTRL_FRAME_SIZE, ctl_rate, 0);
344753c7e08SAugustin Cavalier 		rt->info[i].spAckDuration = ieee80211_compute_duration(rt,
345753c7e08SAugustin Cavalier 			WLAN_CTRL_FRAME_SIZE, ctl_rate, IEEE80211_F_SHPREAMBLE);
346753c7e08SAugustin Cavalier 	}
347753c7e08SAugustin Cavalier 
348753c7e08SAugustin Cavalier #undef WLAN_CTRL_FRAME_SIZE
349753c7e08SAugustin Cavalier }
350753c7e08SAugustin Cavalier 
351753c7e08SAugustin Cavalier /* Setup all rate tables */
352*8244a9baSAugustin Cavalier static void
353753c7e08SAugustin Cavalier ieee80211_phy_init(void)
354753c7e08SAugustin Cavalier {
355753c7e08SAugustin Cavalier 	static struct ieee80211_rate_table * const ratetables[] = {
356753c7e08SAugustin Cavalier 		&ieee80211_half_table,
357753c7e08SAugustin Cavalier 		&ieee80211_quarter_table,
358753c7e08SAugustin Cavalier 		&ieee80211_11na_table,
359753c7e08SAugustin Cavalier 		&ieee80211_11ng_table,
360753c7e08SAugustin Cavalier 		&ieee80211_turbog_table,
361753c7e08SAugustin Cavalier 		&ieee80211_turboa_table,
362753c7e08SAugustin Cavalier 		&ieee80211_11a_table,
363753c7e08SAugustin Cavalier 		&ieee80211_11g_table,
364753c7e08SAugustin Cavalier 		&ieee80211_11b_table
365753c7e08SAugustin Cavalier 	};
366753c7e08SAugustin Cavalier 	int i;
367753c7e08SAugustin Cavalier 
368753c7e08SAugustin Cavalier 	for (i = 0; i < nitems(ratetables); ++i)
369753c7e08SAugustin Cavalier 		ieee80211_setup_ratetable(ratetables[i]);
370753c7e08SAugustin Cavalier 
371753c7e08SAugustin Cavalier }
372753c7e08SAugustin Cavalier SYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL);
373753c7e08SAugustin Cavalier 
374753c7e08SAugustin Cavalier const struct ieee80211_rate_table *
375753c7e08SAugustin Cavalier ieee80211_get_ratetable(struct ieee80211_channel *c)
376753c7e08SAugustin Cavalier {
377753c7e08SAugustin Cavalier 	const struct ieee80211_rate_table *rt;
378753c7e08SAugustin Cavalier 
379753c7e08SAugustin Cavalier 	/* XXX HT */
380753c7e08SAugustin Cavalier 	if (IEEE80211_IS_CHAN_HALF(c))
381753c7e08SAugustin Cavalier 		rt = &ieee80211_half_table;
382753c7e08SAugustin Cavalier 	else if (IEEE80211_IS_CHAN_QUARTER(c))
383753c7e08SAugustin Cavalier 		rt = &ieee80211_quarter_table;
384753c7e08SAugustin Cavalier 	else if (IEEE80211_IS_CHAN_HTA(c))
385753c7e08SAugustin Cavalier 		rt = &ieee80211_11na_table;
386753c7e08SAugustin Cavalier 	else if (IEEE80211_IS_CHAN_HTG(c))
387753c7e08SAugustin Cavalier 		rt = &ieee80211_11ng_table;
388753c7e08SAugustin Cavalier 	else if (IEEE80211_IS_CHAN_108G(c))
389753c7e08SAugustin Cavalier 		rt = &ieee80211_turbog_table;
390753c7e08SAugustin Cavalier 	else if (IEEE80211_IS_CHAN_ST(c))
391753c7e08SAugustin Cavalier 		rt = &ieee80211_turboa_table;
392753c7e08SAugustin Cavalier 	else if (IEEE80211_IS_CHAN_TURBO(c))
393753c7e08SAugustin Cavalier 		rt = &ieee80211_turboa_table;
394753c7e08SAugustin Cavalier 	else if (IEEE80211_IS_CHAN_A(c))
395753c7e08SAugustin Cavalier 		rt = &ieee80211_11a_table;
396753c7e08SAugustin Cavalier 	else if (IEEE80211_IS_CHAN_ANYG(c))
397753c7e08SAugustin Cavalier 		rt = &ieee80211_11g_table;
398753c7e08SAugustin Cavalier 	else if (IEEE80211_IS_CHAN_B(c))
399753c7e08SAugustin Cavalier 		rt = &ieee80211_11b_table;
400753c7e08SAugustin Cavalier 	else {
401753c7e08SAugustin Cavalier 		/* NB: should not get here */
402753c7e08SAugustin Cavalier 		panic("%s: no rate table for channel; freq %u flags 0x%x\n",
403753c7e08SAugustin Cavalier 		      __func__, c->ic_freq, c->ic_flags);
404753c7e08SAugustin Cavalier 	}
405753c7e08SAugustin Cavalier 	return rt;
406753c7e08SAugustin Cavalier }
407753c7e08SAugustin Cavalier 
408753c7e08SAugustin Cavalier /*
409753c7e08SAugustin Cavalier  * Convert PLCP signal/rate field to 802.11 rate (.5Mbits/s)
410753c7e08SAugustin Cavalier  *
411753c7e08SAugustin Cavalier  * Note we do no parameter checking; this routine is mainly
412753c7e08SAugustin Cavalier  * used to derive an 802.11 rate for constructing radiotap
413753c7e08SAugustin Cavalier  * header data for rx frames.
414753c7e08SAugustin Cavalier  *
415753c7e08SAugustin Cavalier  * XXX might be a candidate for inline
416753c7e08SAugustin Cavalier  */
417753c7e08SAugustin Cavalier uint8_t
418753c7e08SAugustin Cavalier ieee80211_plcp2rate(uint8_t plcp, enum ieee80211_phytype type)
419753c7e08SAugustin Cavalier {
420753c7e08SAugustin Cavalier 	if (type == IEEE80211_T_OFDM) {
421753c7e08SAugustin Cavalier 		static const uint8_t ofdm_plcp2rate[16] = {
422753c7e08SAugustin Cavalier 			[0xb]	= 12,
423753c7e08SAugustin Cavalier 			[0xf]	= 18,
424753c7e08SAugustin Cavalier 			[0xa]	= 24,
425753c7e08SAugustin Cavalier 			[0xe]	= 36,
426753c7e08SAugustin Cavalier 			[0x9]	= 48,
427753c7e08SAugustin Cavalier 			[0xd]	= 72,
428753c7e08SAugustin Cavalier 			[0x8]	= 96,
429753c7e08SAugustin Cavalier 			[0xc]	= 108
430753c7e08SAugustin Cavalier 		};
431753c7e08SAugustin Cavalier 		return ofdm_plcp2rate[plcp & 0xf];
432753c7e08SAugustin Cavalier 	}
433753c7e08SAugustin Cavalier 	if (type == IEEE80211_T_CCK) {
434753c7e08SAugustin Cavalier 		static const uint8_t cck_plcp2rate[16] = {
435753c7e08SAugustin Cavalier 			[0xa]	= 2,	/* 0x0a */
436753c7e08SAugustin Cavalier 			[0x4]	= 4,	/* 0x14 */
437753c7e08SAugustin Cavalier 			[0x7]	= 11,	/* 0x37 */
438753c7e08SAugustin Cavalier 			[0xe]	= 22,	/* 0x6e */
439753c7e08SAugustin Cavalier 			[0xc]	= 44,	/* 0xdc , actually PBCC */
440753c7e08SAugustin Cavalier 		};
441753c7e08SAugustin Cavalier 		return cck_plcp2rate[plcp & 0xf];
442753c7e08SAugustin Cavalier 	}
443753c7e08SAugustin Cavalier 	return 0;
444753c7e08SAugustin Cavalier }
445753c7e08SAugustin Cavalier 
446753c7e08SAugustin Cavalier /*
447753c7e08SAugustin Cavalier  * Covert 802.11 rate to PLCP signal.
448753c7e08SAugustin Cavalier  */
449753c7e08SAugustin Cavalier uint8_t
450753c7e08SAugustin Cavalier ieee80211_rate2plcp(int rate, enum ieee80211_phytype type)
451753c7e08SAugustin Cavalier {
452753c7e08SAugustin Cavalier 	/* XXX ignore type for now since rates are unique */
453753c7e08SAugustin Cavalier 	switch (rate) {
454753c7e08SAugustin Cavalier 	/* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
455753c7e08SAugustin Cavalier 	case 12:	return 0xb;
456753c7e08SAugustin Cavalier 	case 18:	return 0xf;
457753c7e08SAugustin Cavalier 	case 24:	return 0xa;
458753c7e08SAugustin Cavalier 	case 36:	return 0xe;
459753c7e08SAugustin Cavalier 	case 48:	return 0x9;
460753c7e08SAugustin Cavalier 	case 72:	return 0xd;
461753c7e08SAugustin Cavalier 	case 96:	return 0x8;
462753c7e08SAugustin Cavalier 	case 108:	return 0xc;
463753c7e08SAugustin Cavalier 	/* CCK rates (IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3) */
464753c7e08SAugustin Cavalier 	case 2:		return 10;
465753c7e08SAugustin Cavalier 	case 4:		return 20;
466753c7e08SAugustin Cavalier 	case 11:	return 55;
467753c7e08SAugustin Cavalier 	case 22:	return 110;
468753c7e08SAugustin Cavalier 	/* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */
469753c7e08SAugustin Cavalier 	case 44:	return 220;
470753c7e08SAugustin Cavalier 	}
471753c7e08SAugustin Cavalier 	return 0;		/* XXX unsupported/unknown rate */
472753c7e08SAugustin Cavalier }
473753c7e08SAugustin Cavalier 
474753c7e08SAugustin Cavalier #define CCK_SIFS_TIME		10
475753c7e08SAugustin Cavalier #define CCK_PREAMBLE_BITS	144
476753c7e08SAugustin Cavalier #define CCK_PLCP_BITS		48
477753c7e08SAugustin Cavalier 
478753c7e08SAugustin Cavalier #define OFDM_SIFS_TIME		16
479753c7e08SAugustin Cavalier #define OFDM_PREAMBLE_TIME	20
480753c7e08SAugustin Cavalier #define OFDM_PLCP_BITS		22
481753c7e08SAugustin Cavalier #define OFDM_SYMBOL_TIME	4
482753c7e08SAugustin Cavalier 
483753c7e08SAugustin Cavalier #define OFDM_HALF_SIFS_TIME	32
484753c7e08SAugustin Cavalier #define OFDM_HALF_PREAMBLE_TIME	40
485753c7e08SAugustin Cavalier #define OFDM_HALF_PLCP_BITS	22
486753c7e08SAugustin Cavalier #define OFDM_HALF_SYMBOL_TIME	8
487753c7e08SAugustin Cavalier 
488753c7e08SAugustin Cavalier #define OFDM_QUARTER_SIFS_TIME 		64
489753c7e08SAugustin Cavalier #define OFDM_QUARTER_PREAMBLE_TIME	80
490753c7e08SAugustin Cavalier #define OFDM_QUARTER_PLCP_BITS		22
491753c7e08SAugustin Cavalier #define OFDM_QUARTER_SYMBOL_TIME	16
492753c7e08SAugustin Cavalier 
493753c7e08SAugustin Cavalier #define TURBO_SIFS_TIME		8
494753c7e08SAugustin Cavalier #define TURBO_PREAMBLE_TIME	14
495753c7e08SAugustin Cavalier #define TURBO_PLCP_BITS		22
496753c7e08SAugustin Cavalier #define TURBO_SYMBOL_TIME	4
497753c7e08SAugustin Cavalier 
498753c7e08SAugustin Cavalier /*
499753c7e08SAugustin Cavalier  * Compute the time to transmit a frame of length frameLen bytes
500753c7e08SAugustin Cavalier  * using the specified rate, phy, and short preamble setting.
501753c7e08SAugustin Cavalier  * SIFS is included.
502753c7e08SAugustin Cavalier  */
503753c7e08SAugustin Cavalier uint16_t
504753c7e08SAugustin Cavalier ieee80211_compute_duration(const struct ieee80211_rate_table *rt,
505753c7e08SAugustin Cavalier 	uint32_t frameLen, uint16_t rate, int isShortPreamble)
506753c7e08SAugustin Cavalier {
507753c7e08SAugustin Cavalier 	uint8_t rix = rt->rateCodeToIndex[rate];
508753c7e08SAugustin Cavalier 	uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime;
509753c7e08SAugustin Cavalier 	uint32_t kbps;
510753c7e08SAugustin Cavalier 
511753c7e08SAugustin Cavalier 	KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate));
512753c7e08SAugustin Cavalier 	kbps = rt->info[rix].rateKbps;
513753c7e08SAugustin Cavalier 	if (kbps == 0)			/* XXX bandaid for channel changes */
514753c7e08SAugustin Cavalier 		return 0;
515753c7e08SAugustin Cavalier 
516753c7e08SAugustin Cavalier 	switch (rt->info[rix].phy) {
517753c7e08SAugustin Cavalier 	case IEEE80211_T_CCK:
518753c7e08SAugustin Cavalier 		phyTime		= CCK_PREAMBLE_BITS + CCK_PLCP_BITS;
519753c7e08SAugustin Cavalier 		if (isShortPreamble && rt->info[rix].shortPreamble)
520753c7e08SAugustin Cavalier 			phyTime >>= 1;
521753c7e08SAugustin Cavalier 		numBits		= frameLen << 3;
522753c7e08SAugustin Cavalier 		txTime		= CCK_SIFS_TIME + phyTime
523753c7e08SAugustin Cavalier 				+ ((numBits * 1000)/kbps);
524753c7e08SAugustin Cavalier 		break;
525753c7e08SAugustin Cavalier 	case IEEE80211_T_OFDM:
526753c7e08SAugustin Cavalier 		bitsPerSymbol	= (kbps * OFDM_SYMBOL_TIME) / 1000;
527753c7e08SAugustin Cavalier 		KASSERT(bitsPerSymbol != 0, ("full rate bps"));
528753c7e08SAugustin Cavalier 
529753c7e08SAugustin Cavalier 		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
530753c7e08SAugustin Cavalier 		numSymbols	= howmany(numBits, bitsPerSymbol);
531753c7e08SAugustin Cavalier 		txTime		= OFDM_SIFS_TIME
532753c7e08SAugustin Cavalier 				+ OFDM_PREAMBLE_TIME
533753c7e08SAugustin Cavalier 				+ (numSymbols * OFDM_SYMBOL_TIME);
534753c7e08SAugustin Cavalier 		break;
535753c7e08SAugustin Cavalier 	case IEEE80211_T_OFDM_HALF:
536753c7e08SAugustin Cavalier 		bitsPerSymbol	= (kbps * OFDM_HALF_SYMBOL_TIME) / 1000;
537753c7e08SAugustin Cavalier 		KASSERT(bitsPerSymbol != 0, ("1/4 rate bps"));
538753c7e08SAugustin Cavalier 
539753c7e08SAugustin Cavalier 		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
540753c7e08SAugustin Cavalier 		numSymbols	= howmany(numBits, bitsPerSymbol);
541753c7e08SAugustin Cavalier 		txTime		= OFDM_HALF_SIFS_TIME
542753c7e08SAugustin Cavalier 				+ OFDM_HALF_PREAMBLE_TIME
543753c7e08SAugustin Cavalier 				+ (numSymbols * OFDM_HALF_SYMBOL_TIME);
544753c7e08SAugustin Cavalier 		break;
545753c7e08SAugustin Cavalier 	case IEEE80211_T_OFDM_QUARTER:
546753c7e08SAugustin Cavalier 		bitsPerSymbol	= (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000;
547753c7e08SAugustin Cavalier 		KASSERT(bitsPerSymbol != 0, ("1/2 rate bps"));
548753c7e08SAugustin Cavalier 
549753c7e08SAugustin Cavalier 		numBits		= OFDM_PLCP_BITS + (frameLen << 3);
550753c7e08SAugustin Cavalier 		numSymbols	= howmany(numBits, bitsPerSymbol);
551753c7e08SAugustin Cavalier 		txTime		= OFDM_QUARTER_SIFS_TIME
552753c7e08SAugustin Cavalier 				+ OFDM_QUARTER_PREAMBLE_TIME
553753c7e08SAugustin Cavalier 				+ (numSymbols * OFDM_QUARTER_SYMBOL_TIME);
554753c7e08SAugustin Cavalier 		break;
555753c7e08SAugustin Cavalier 	case IEEE80211_T_TURBO:
556753c7e08SAugustin Cavalier 		/* we still save OFDM rates in kbps - so double them */
557753c7e08SAugustin Cavalier 		bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000;
558753c7e08SAugustin Cavalier 		KASSERT(bitsPerSymbol != 0, ("turbo bps"));
559753c7e08SAugustin Cavalier 
560753c7e08SAugustin Cavalier 		numBits       = TURBO_PLCP_BITS + (frameLen << 3);
561753c7e08SAugustin Cavalier 		numSymbols    = howmany(numBits, bitsPerSymbol);
562753c7e08SAugustin Cavalier 		txTime        = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME
563753c7e08SAugustin Cavalier 			      + (numSymbols * TURBO_SYMBOL_TIME);
564753c7e08SAugustin Cavalier 		break;
565753c7e08SAugustin Cavalier 	default:
566753c7e08SAugustin Cavalier 		panic("%s: unknown phy %u (rate %u)\n", __func__,
567753c7e08SAugustin Cavalier 		      rt->info[rix].phy, rate);
568753c7e08SAugustin Cavalier 	}
569753c7e08SAugustin Cavalier 	return txTime;
570753c7e08SAugustin Cavalier }
571753c7e08SAugustin Cavalier 
572753c7e08SAugustin Cavalier static const uint16_t ht20_bps[32] = {
573753c7e08SAugustin Cavalier 	26, 52, 78, 104, 156, 208, 234, 260,
574753c7e08SAugustin Cavalier 	52, 104, 156, 208, 312, 416, 468, 520,
575753c7e08SAugustin Cavalier 	78, 156, 234, 312, 468, 624, 702, 780,
576753c7e08SAugustin Cavalier 	104, 208, 312, 416, 624, 832, 936, 1040
577753c7e08SAugustin Cavalier };
578753c7e08SAugustin Cavalier static const uint16_t ht40_bps[32] = {
579753c7e08SAugustin Cavalier 	54, 108, 162, 216, 324, 432, 486, 540,
580753c7e08SAugustin Cavalier 	108, 216, 324, 432, 648, 864, 972, 1080,
581753c7e08SAugustin Cavalier 	162, 324, 486, 648, 972, 1296, 1458, 1620,
582753c7e08SAugustin Cavalier 	216, 432, 648, 864, 1296, 1728, 1944, 2160
583753c7e08SAugustin Cavalier };
584753c7e08SAugustin Cavalier 
585753c7e08SAugustin Cavalier 
586753c7e08SAugustin Cavalier #define	OFDM_PLCP_BITS	22
587753c7e08SAugustin Cavalier #define	HT_L_STF	8
588753c7e08SAugustin Cavalier #define	HT_L_LTF	8
589753c7e08SAugustin Cavalier #define	HT_L_SIG	4
590753c7e08SAugustin Cavalier #define	HT_SIG		8
591753c7e08SAugustin Cavalier #define	HT_STF		4
592753c7e08SAugustin Cavalier #define	HT_LTF(n)	((n) * 4)
593753c7e08SAugustin Cavalier 
594753c7e08SAugustin Cavalier /*
595753c7e08SAugustin Cavalier  * Calculate the transmit duration of an 11n frame.
596753c7e08SAugustin Cavalier  */
597753c7e08SAugustin Cavalier uint32_t
598753c7e08SAugustin Cavalier ieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate,
599753c7e08SAugustin Cavalier     int streams, int isht40, int isShortGI)
600753c7e08SAugustin Cavalier {
601753c7e08SAugustin Cavalier 	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
602753c7e08SAugustin Cavalier 
603753c7e08SAugustin Cavalier 	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
604753c7e08SAugustin Cavalier 	KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
605753c7e08SAugustin Cavalier 
606753c7e08SAugustin Cavalier 	if (isht40)
607753c7e08SAugustin Cavalier 		bitsPerSymbol = ht40_bps[rate & 0x1f];
608753c7e08SAugustin Cavalier 	else
609753c7e08SAugustin Cavalier 		bitsPerSymbol = ht20_bps[rate & 0x1f];
610753c7e08SAugustin Cavalier 	numBits = OFDM_PLCP_BITS + (frameLen << 3);
611753c7e08SAugustin Cavalier 	numSymbols = howmany(numBits, bitsPerSymbol);
612753c7e08SAugustin Cavalier 	if (isShortGI)
613753c7e08SAugustin Cavalier 		txTime = ((numSymbols * 18) + 4) / 5;   /* 3.6us */
614753c7e08SAugustin Cavalier 	else
615753c7e08SAugustin Cavalier 		txTime = numSymbols * 4;                /* 4us */
616753c7e08SAugustin Cavalier 	return txTime + HT_L_STF + HT_L_LTF +
617753c7e08SAugustin Cavalier 	    HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
618753c7e08SAugustin Cavalier }
619753c7e08SAugustin Cavalier 
620753c7e08SAugustin Cavalier #undef	HT_LTF
621753c7e08SAugustin Cavalier #undef	HT_STF
622753c7e08SAugustin Cavalier #undef	HT_SIG
623753c7e08SAugustin Cavalier #undef	HT_L_SIG
624753c7e08SAugustin Cavalier #undef	HT_L_LTF
625753c7e08SAugustin Cavalier #undef	HT_L_STF
626753c7e08SAugustin Cavalier #undef	OFDM_PLCP_BITS
627