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