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