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