ieee80211_phy.c revision 257179
1178354Ssam/*- 2178354Ssam * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting 3178354Ssam * All rights reserved. 4178354Ssam * 5178354Ssam * Redistribution and use in source and binary forms, with or without 6178354Ssam * modification, are permitted provided that the following conditions 7178354Ssam * are met: 8178354Ssam * 1. Redistributions of source code must retain the above copyright 9178354Ssam * notice, this list of conditions and the following disclaimer. 10178354Ssam * 2. Redistributions in binary form must reproduce the above copyright 11178354Ssam * notice, this list of conditions and the following disclaimer in the 12178354Ssam * documentation and/or other materials provided with the distribution. 13178354Ssam * 14178354Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15178354Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16178354Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17178354Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18178354Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19178354Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20178354Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21178354Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22178354Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23178354Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24178354Ssam */ 25178354Ssam 26178354Ssam#include <sys/cdefs.h> 27178354Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_phy.c 257179 2013-10-26 18:18:50Z glebius $"); 28178354Ssam 29178354Ssam/* 30178354Ssam * IEEE 802.11 PHY-related support. 31178354Ssam */ 32178354Ssam 33178354Ssam#include "opt_inet.h" 34178354Ssam 35178354Ssam#include <sys/param.h> 36178354Ssam#include <sys/kernel.h> 37178354Ssam#include <sys/systm.h> 38257179Sglebius#include <sys/malloc.h> 39178354Ssam 40178354Ssam#include <sys/socket.h> 41178354Ssam 42178354Ssam#include <net/if.h> 43178354Ssam#include <net/if_media.h> 44178354Ssam 45257179Sglebius#include <net/ethernet.h> 46257179Sglebius#include <net/route.h> 47257179Sglebius 48178354Ssam#include <net80211/ieee80211_var.h> 49178354Ssam#include <net80211/ieee80211_phy.h> 50178354Ssam 51178354Ssam#ifdef notyet 52178354Ssamstruct ieee80211_ds_plcp_hdr { 53178354Ssam uint8_t i_signal; 54178354Ssam uint8_t i_service; 55178354Ssam uint16_t i_length; 56178354Ssam uint16_t i_crc; 57178354Ssam} __packed; 58178354Ssam 59178354Ssam#endif /* notyet */ 60178354Ssam 61178354Ssam/* shorthands to compact tables for readability */ 62178354Ssam#define OFDM IEEE80211_T_OFDM 63178354Ssam#define CCK IEEE80211_T_CCK 64178354Ssam#define TURBO IEEE80211_T_TURBO 65188821Ssam#define HALF IEEE80211_T_OFDM_HALF 66188821Ssam#define QUART IEEE80211_T_OFDM_QUARTER 67252727Sadrian#define HT IEEE80211_T_HT 68252727Sadrian/* XXX the 11n and the basic rate flag are unfortunately overlapping. Grr. */ 69252727Sadrian#define N(r) (IEEE80211_RATE_MCS | r) 70188821Ssam#define PBCC (IEEE80211_T_OFDM_QUARTER+1) /* XXX */ 71252727Sadrian#define B(r) (IEEE80211_RATE_BASIC | r) 72182833Ssam#define Mb(x) (x*1000) 73178354Ssam 74178354Ssamstatic struct ieee80211_rate_table ieee80211_11b_table = { 75182833Ssam .rateCount = 4, /* XXX no PBCC */ 76182833Ssam .info = { 77182833Ssam/* short ctrl */ 78182833Ssam/* Preamble dot11Rate Rate */ 79182833Ssam [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },/* 1 Mb */ 80182833Ssam [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },/* 2 Mb */ 81182833Ssam [2] = { .phy = CCK, 5500, 0x04, B(11), 1 },/* 5.5 Mb */ 82182833Ssam [3] = { .phy = CCK, 11000, 0x04, B(22), 1 },/* 11 Mb */ 83182833Ssam [4] = { .phy = PBCC, 22000, 0x04, 44, 3 } /* 22 Mb */ 84182833Ssam }, 85178354Ssam}; 86178354Ssam 87178354Ssamstatic struct ieee80211_rate_table ieee80211_11g_table = { 88182833Ssam .rateCount = 12, 89182833Ssam .info = { 90182833Ssam/* short ctrl */ 91182833Ssam/* Preamble dot11Rate Rate */ 92182833Ssam [0] = { .phy = CCK, 1000, 0x00, B(2), 0 }, 93182833Ssam [1] = { .phy = CCK, 2000, 0x04, B(4), 1 }, 94182833Ssam [2] = { .phy = CCK, 5500, 0x04, B(11), 2 }, 95182833Ssam [3] = { .phy = CCK, 11000, 0x04, B(22), 3 }, 96182833Ssam [4] = { .phy = OFDM, 6000, 0x00, 12, 4 }, 97182833Ssam [5] = { .phy = OFDM, 9000, 0x00, 18, 4 }, 98182833Ssam [6] = { .phy = OFDM, 12000, 0x00, 24, 6 }, 99182833Ssam [7] = { .phy = OFDM, 18000, 0x00, 36, 6 }, 100182833Ssam [8] = { .phy = OFDM, 24000, 0x00, 48, 8 }, 101182833Ssam [9] = { .phy = OFDM, 36000, 0x00, 72, 8 }, 102182833Ssam [10] = { .phy = OFDM, 48000, 0x00, 96, 8 }, 103182833Ssam [11] = { .phy = OFDM, 54000, 0x00, 108, 8 } 104182833Ssam }, 105178354Ssam}; 106178354Ssam 107178354Ssamstatic struct ieee80211_rate_table ieee80211_11a_table = { 108182833Ssam .rateCount = 8, 109182833Ssam .info = { 110182833Ssam/* short ctrl */ 111182833Ssam/* Preamble dot11Rate Rate */ 112182833Ssam [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 }, 113182833Ssam [1] = { .phy = OFDM, 9000, 0x00, 18, 0 }, 114182833Ssam [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 }, 115182833Ssam [3] = { .phy = OFDM, 18000, 0x00, 36, 2 }, 116182833Ssam [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 }, 117182833Ssam [5] = { .phy = OFDM, 36000, 0x00, 72, 4 }, 118182833Ssam [6] = { .phy = OFDM, 48000, 0x00, 96, 4 }, 119182833Ssam [7] = { .phy = OFDM, 54000, 0x00, 108, 4 } 120182833Ssam }, 121178354Ssam}; 122178354Ssam 123178354Ssamstatic struct ieee80211_rate_table ieee80211_half_table = { 124182833Ssam .rateCount = 8, 125182833Ssam .info = { 126182833Ssam/* short ctrl */ 127182833Ssam/* Preamble dot11Rate Rate */ 128188821Ssam [0] = { .phy = HALF, 3000, 0x00, B(6), 0 }, 129188821Ssam [1] = { .phy = HALF, 4500, 0x00, 9, 0 }, 130188821Ssam [2] = { .phy = HALF, 6000, 0x00, B(12), 2 }, 131188821Ssam [3] = { .phy = HALF, 9000, 0x00, 18, 2 }, 132188821Ssam [4] = { .phy = HALF, 12000, 0x00, B(24), 4 }, 133188821Ssam [5] = { .phy = HALF, 18000, 0x00, 36, 4 }, 134188821Ssam [6] = { .phy = HALF, 24000, 0x00, 48, 4 }, 135188821Ssam [7] = { .phy = HALF, 27000, 0x00, 54, 4 } 136182833Ssam }, 137178354Ssam}; 138178354Ssam 139178354Ssamstatic struct ieee80211_rate_table ieee80211_quarter_table = { 140182833Ssam .rateCount = 8, 141182833Ssam .info = { 142182833Ssam/* short ctrl */ 143182833Ssam/* Preamble dot11Rate Rate */ 144188821Ssam [0] = { .phy = QUART, 1500, 0x00, B(3), 0 }, 145188821Ssam [1] = { .phy = QUART, 2250, 0x00, 4, 0 }, 146188821Ssam [2] = { .phy = QUART, 3000, 0x00, B(9), 2 }, 147188821Ssam [3] = { .phy = QUART, 4500, 0x00, 9, 2 }, 148188821Ssam [4] = { .phy = QUART, 6000, 0x00, B(12), 4 }, 149188821Ssam [5] = { .phy = QUART, 9000, 0x00, 18, 4 }, 150188821Ssam [6] = { .phy = QUART, 12000, 0x00, 24, 4 }, 151188821Ssam [7] = { .phy = QUART, 13500, 0x00, 27, 4 } 152182833Ssam }, 153178354Ssam}; 154178354Ssam 155178354Ssamstatic struct ieee80211_rate_table ieee80211_turbog_table = { 156182833Ssam .rateCount = 7, 157182833Ssam .info = { 158182833Ssam/* short ctrl */ 159182833Ssam/* Preamble dot11Rate Rate */ 160182833Ssam [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 }, 161182833Ssam [1] = { .phy = TURBO, 24000, 0x00, B(24), 1 }, 162182833Ssam [2] = { .phy = TURBO, 36000, 0x00, 36, 1 }, 163182833Ssam [3] = { .phy = TURBO, 48000, 0x00, B(48), 3 }, 164182833Ssam [4] = { .phy = TURBO, 72000, 0x00, 72, 3 }, 165182833Ssam [5] = { .phy = TURBO, 96000, 0x00, 96, 3 }, 166182833Ssam [6] = { .phy = TURBO, 108000, 0x00, 108, 3 } 167182833Ssam }, 168178354Ssam}; 169178354Ssam 170178354Ssamstatic struct ieee80211_rate_table ieee80211_turboa_table = { 171182833Ssam .rateCount = 8, 172182833Ssam .info = { 173182833Ssam/* short ctrl */ 174182833Ssam/* Preamble dot11Rate Rate */ 175182833Ssam [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 }, 176182833Ssam [1] = { .phy = TURBO, 18000, 0x00, 18, 0 }, 177182833Ssam [2] = { .phy = TURBO, 24000, 0x00, B(24), 2 }, 178182833Ssam [3] = { .phy = TURBO, 36000, 0x00, 36, 2 }, 179182833Ssam [4] = { .phy = TURBO, 48000, 0x00, B(48), 4 }, 180182833Ssam [5] = { .phy = TURBO, 72000, 0x00, 72, 4 }, 181182833Ssam [6] = { .phy = TURBO, 96000, 0x00, 96, 4 }, 182182833Ssam [7] = { .phy = TURBO, 108000, 0x00, 108, 4 } 183182833Ssam }, 184178354Ssam}; 185178354Ssam 186252727Sadrianstatic struct ieee80211_rate_table ieee80211_11ng_table = { 187252727Sadrian .rateCount = 36, 188252727Sadrian .info = { 189252727Sadrian/* short ctrl */ 190252727Sadrian/* Preamble dot11Rate Rate */ 191252727Sadrian [0] = { .phy = CCK, 1000, 0x00, B(2), 0 }, 192252727Sadrian [1] = { .phy = CCK, 2000, 0x04, B(4), 1 }, 193252727Sadrian [2] = { .phy = CCK, 5500, 0x04, B(11), 2 }, 194252727Sadrian [3] = { .phy = CCK, 11000, 0x04, B(22), 3 }, 195252727Sadrian [4] = { .phy = OFDM, 6000, 0x00, 12, 4 }, 196252727Sadrian [5] = { .phy = OFDM, 9000, 0x00, 18, 4 }, 197252727Sadrian [6] = { .phy = OFDM, 12000, 0x00, 24, 6 }, 198252727Sadrian [7] = { .phy = OFDM, 18000, 0x00, 36, 6 }, 199252727Sadrian [8] = { .phy = OFDM, 24000, 0x00, 48, 8 }, 200252727Sadrian [9] = { .phy = OFDM, 36000, 0x00, 72, 8 }, 201252727Sadrian [10] = { .phy = OFDM, 48000, 0x00, 96, 8 }, 202252727Sadrian [11] = { .phy = OFDM, 54000, 0x00, 108, 8 }, 203252727Sadrian 204252727Sadrian [12] = { .phy = HT, 6500, 0x00, N(0), 4 }, 205252727Sadrian [13] = { .phy = HT, 13000, 0x00, N(1), 6 }, 206252727Sadrian [14] = { .phy = HT, 19500, 0x00, N(2), 6 }, 207252727Sadrian [15] = { .phy = HT, 26000, 0x00, N(3), 8 }, 208252727Sadrian [16] = { .phy = HT, 39000, 0x00, N(4), 8 }, 209252727Sadrian [17] = { .phy = HT, 52000, 0x00, N(5), 8 }, 210252727Sadrian [18] = { .phy = HT, 58500, 0x00, N(6), 8 }, 211252727Sadrian [19] = { .phy = HT, 65000, 0x00, N(7), 8 }, 212252727Sadrian 213252727Sadrian [20] = { .phy = HT, 13000, 0x00, N(8), 4 }, 214252727Sadrian [21] = { .phy = HT, 26000, 0x00, N(9), 6 }, 215252727Sadrian [22] = { .phy = HT, 39000, 0x00, N(10), 6 }, 216252727Sadrian [23] = { .phy = HT, 52000, 0x00, N(11), 8 }, 217252727Sadrian [24] = { .phy = HT, 78000, 0x00, N(12), 8 }, 218252727Sadrian [25] = { .phy = HT, 104000, 0x00, N(13), 8 }, 219252727Sadrian [26] = { .phy = HT, 117000, 0x00, N(14), 8 }, 220252727Sadrian [27] = { .phy = HT, 130000, 0x00, N(15), 8 }, 221252727Sadrian 222252727Sadrian [28] = { .phy = HT, 19500, 0x00, N(16), 4 }, 223252727Sadrian [29] = { .phy = HT, 39000, 0x00, N(17), 6 }, 224252727Sadrian [30] = { .phy = HT, 58500, 0x00, N(18), 6 }, 225252727Sadrian [31] = { .phy = HT, 78000, 0x00, N(19), 8 }, 226252727Sadrian [32] = { .phy = HT, 117000, 0x00, N(20), 8 }, 227252727Sadrian [33] = { .phy = HT, 156000, 0x00, N(21), 8 }, 228252727Sadrian [34] = { .phy = HT, 175500, 0x00, N(22), 8 }, 229252727Sadrian [35] = { .phy = HT, 195000, 0x00, N(23), 8 }, 230252727Sadrian 231252727Sadrian }, 232252727Sadrian}; 233252727Sadrian 234252727Sadrianstatic struct ieee80211_rate_table ieee80211_11na_table = { 235252727Sadrian .rateCount = 32, 236252727Sadrian .info = { 237252727Sadrian/* short ctrl */ 238252727Sadrian/* Preamble dot11Rate Rate */ 239252727Sadrian [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 }, 240252727Sadrian [1] = { .phy = OFDM, 9000, 0x00, 18, 0 }, 241252727Sadrian [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 }, 242252727Sadrian [3] = { .phy = OFDM, 18000, 0x00, 36, 2 }, 243252727Sadrian [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 }, 244252727Sadrian [5] = { .phy = OFDM, 36000, 0x00, 72, 4 }, 245252727Sadrian [6] = { .phy = OFDM, 48000, 0x00, 96, 4 }, 246252727Sadrian [7] = { .phy = OFDM, 54000, 0x00, 108, 4 }, 247252727Sadrian 248252727Sadrian [8] = { .phy = HT, 6500, 0x00, N(0), 0 }, 249252727Sadrian [9] = { .phy = HT, 13000, 0x00, N(1), 2 }, 250252727Sadrian [10] = { .phy = HT, 19500, 0x00, N(2), 2 }, 251252727Sadrian [11] = { .phy = HT, 26000, 0x00, N(3), 4 }, 252252727Sadrian [12] = { .phy = HT, 39000, 0x00, N(4), 4 }, 253252727Sadrian [13] = { .phy = HT, 52000, 0x00, N(5), 4 }, 254252727Sadrian [14] = { .phy = HT, 58500, 0x00, N(6), 4 }, 255252727Sadrian [15] = { .phy = HT, 65000, 0x00, N(7), 4 }, 256252727Sadrian 257252727Sadrian [16] = { .phy = HT, 13000, 0x00, N(8), 0 }, 258252727Sadrian [17] = { .phy = HT, 26000, 0x00, N(9), 2 }, 259252727Sadrian [18] = { .phy = HT, 39000, 0x00, N(10), 2 }, 260252727Sadrian [19] = { .phy = HT, 52000, 0x00, N(11), 4 }, 261252727Sadrian [20] = { .phy = HT, 78000, 0x00, N(12), 4 }, 262252727Sadrian [21] = { .phy = HT, 104000, 0x00, N(13), 4 }, 263252727Sadrian [22] = { .phy = HT, 117000, 0x00, N(14), 4 }, 264252727Sadrian [23] = { .phy = HT, 130000, 0x00, N(15), 4 }, 265252727Sadrian 266252727Sadrian [24] = { .phy = HT, 19500, 0x00, N(16), 0 }, 267252727Sadrian [25] = { .phy = HT, 39000, 0x00, N(17), 2 }, 268252727Sadrian [26] = { .phy = HT, 58500, 0x00, N(18), 2 }, 269252727Sadrian [27] = { .phy = HT, 78000, 0x00, N(19), 4 }, 270252727Sadrian [28] = { .phy = HT, 117000, 0x00, N(20), 4 }, 271252727Sadrian [29] = { .phy = HT, 156000, 0x00, N(21), 4 }, 272252727Sadrian [30] = { .phy = HT, 175500, 0x00, N(22), 4 }, 273252727Sadrian [31] = { .phy = HT, 195000, 0x00, N(23), 4 }, 274252727Sadrian 275252727Sadrian }, 276252727Sadrian}; 277252727Sadrian 278182833Ssam#undef Mb 279182833Ssam#undef B 280178354Ssam#undef OFDM 281188821Ssam#undef HALF 282188821Ssam#undef QUART 283178354Ssam#undef CCK 284178354Ssam#undef TURBO 285178354Ssam#undef XR 286252727Sadrian#undef HT 287252727Sadrian#undef N 288178354Ssam 289178354Ssam/* 290178354Ssam * Setup a rate table's reverse lookup table and fill in 291178354Ssam * ack durations. The reverse lookup tables are assumed 292178354Ssam * to be initialized to zero (or at least the first entry). 293178354Ssam * We use this as a key that indicates whether or not 294178354Ssam * we've previously setup the reverse lookup table. 295178354Ssam * 296178354Ssam * XXX not reentrant, but shouldn't matter 297178354Ssam */ 298178354Ssamstatic void 299178354Ssamieee80211_setup_ratetable(struct ieee80211_rate_table *rt) 300178354Ssam{ 301178354Ssam#define WLAN_CTRL_FRAME_SIZE \ 302178354Ssam (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN) 303178354Ssam 304178354Ssam int i; 305178354Ssam 306254315Srpaulo for (i = 0; i < nitems(rt->rateCodeToIndex); i++) 307178354Ssam rt->rateCodeToIndex[i] = (uint8_t) -1; 308178354Ssam for (i = 0; i < rt->rateCount; i++) { 309178354Ssam uint8_t code = rt->info[i].dot11Rate; 310178354Ssam uint8_t cix = rt->info[i].ctlRateIndex; 311178354Ssam uint8_t ctl_rate = rt->info[cix].dot11Rate; 312178354Ssam 313252727Sadrian /* 314252727Sadrian * Map without the basic rate bit. 315252727Sadrian * 316252727Sadrian * It's up to the caller to ensure that the basic 317252727Sadrian * rate bit is stripped here. 318252727Sadrian * 319252727Sadrian * For HT, use the MCS rate bit. 320252727Sadrian */ 321252727Sadrian code &= IEEE80211_RATE_VAL; 322252727Sadrian if (rt->info[i].phy == IEEE80211_T_HT) { 323252727Sadrian code |= IEEE80211_RATE_MCS; 324178354Ssam } 325178354Ssam 326252727Sadrian /* XXX assume the control rate is non-MCS? */ 327252727Sadrian ctl_rate &= IEEE80211_RATE_VAL; 328252727Sadrian rt->rateCodeToIndex[code] = i; 329252727Sadrian 330178354Ssam /* 331178354Ssam * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 332178354Ssam * depends on whether they are marked as basic rates; 333178354Ssam * the static tables are setup with an 11b-compatible 334178354Ssam * 2Mb/s rate which will work but is suboptimal 335178354Ssam * 336178354Ssam * NB: Control rate is always less than or equal to the 337178354Ssam * current rate, so control rate's reverse lookup entry 338178354Ssam * has been installed and following call is safe. 339178354Ssam */ 340178354Ssam rt->info[i].lpAckDuration = ieee80211_compute_duration(rt, 341178354Ssam WLAN_CTRL_FRAME_SIZE, ctl_rate, 0); 342178354Ssam rt->info[i].spAckDuration = ieee80211_compute_duration(rt, 343178354Ssam WLAN_CTRL_FRAME_SIZE, ctl_rate, IEEE80211_F_SHPREAMBLE); 344178354Ssam } 345178354Ssam 346178354Ssam#undef WLAN_CTRL_FRAME_SIZE 347178354Ssam} 348178354Ssam 349178354Ssam/* Setup all rate tables */ 350178354Ssamstatic void 351178354Ssamieee80211_phy_init(void) 352178354Ssam{ 353178354Ssam static struct ieee80211_rate_table * const ratetables[] = { 354178354Ssam &ieee80211_half_table, 355178354Ssam &ieee80211_quarter_table, 356252727Sadrian &ieee80211_11na_table, 357252727Sadrian &ieee80211_11ng_table, 358178354Ssam &ieee80211_turbog_table, 359178354Ssam &ieee80211_turboa_table, 360178354Ssam &ieee80211_11a_table, 361178354Ssam &ieee80211_11g_table, 362178354Ssam &ieee80211_11b_table 363178354Ssam }; 364178354Ssam int i; 365178354Ssam 366254315Srpaulo for (i = 0; i < nitems(ratetables); ++i) 367178354Ssam ieee80211_setup_ratetable(ratetables[i]); 368178354Ssam 369178354Ssam} 370178354SsamSYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL); 371178354Ssam 372178354Ssamconst struct ieee80211_rate_table * 373178354Ssamieee80211_get_ratetable(struct ieee80211_channel *c) 374178354Ssam{ 375178354Ssam const struct ieee80211_rate_table *rt; 376178354Ssam 377178354Ssam /* XXX HT */ 378178354Ssam if (IEEE80211_IS_CHAN_HALF(c)) 379178354Ssam rt = &ieee80211_half_table; 380178354Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 381178354Ssam rt = &ieee80211_quarter_table; 382178354Ssam else if (IEEE80211_IS_CHAN_HTA(c)) 383252727Sadrian rt = &ieee80211_11na_table; 384178354Ssam else if (IEEE80211_IS_CHAN_HTG(c)) 385252727Sadrian rt = &ieee80211_11ng_table; 386178354Ssam else if (IEEE80211_IS_CHAN_108G(c)) 387178354Ssam rt = &ieee80211_turbog_table; 388178354Ssam else if (IEEE80211_IS_CHAN_ST(c)) 389178354Ssam rt = &ieee80211_turboa_table; 390178354Ssam else if (IEEE80211_IS_CHAN_TURBO(c)) 391178354Ssam rt = &ieee80211_turboa_table; 392178354Ssam else if (IEEE80211_IS_CHAN_A(c)) 393178354Ssam rt = &ieee80211_11a_table; 394178354Ssam else if (IEEE80211_IS_CHAN_ANYG(c)) 395178354Ssam rt = &ieee80211_11g_table; 396178354Ssam else if (IEEE80211_IS_CHAN_B(c)) 397178354Ssam rt = &ieee80211_11b_table; 398178354Ssam else { 399178354Ssam /* NB: should not get here */ 400178354Ssam panic("%s: no rate table for channel; freq %u flags 0x%x\n", 401178354Ssam __func__, c->ic_freq, c->ic_flags); 402178354Ssam } 403178354Ssam return rt; 404178354Ssam} 405178354Ssam 406178354Ssam/* 407178354Ssam * Convert PLCP signal/rate field to 802.11 rate (.5Mbits/s) 408178354Ssam * 409178354Ssam * Note we do no parameter checking; this routine is mainly 410178354Ssam * used to derive an 802.11 rate for constructing radiotap 411178354Ssam * header data for rx frames. 412178354Ssam * 413178354Ssam * XXX might be a candidate for inline 414178354Ssam */ 415178354Ssamuint8_t 416178958Ssamieee80211_plcp2rate(uint8_t plcp, enum ieee80211_phytype type) 417178354Ssam{ 418178958Ssam if (type == IEEE80211_T_OFDM) { 419178354Ssam static const uint8_t ofdm_plcp2rate[16] = { 420178354Ssam [0xb] = 12, 421178354Ssam [0xf] = 18, 422178354Ssam [0xa] = 24, 423178354Ssam [0xe] = 36, 424178354Ssam [0x9] = 48, 425178354Ssam [0xd] = 72, 426178354Ssam [0x8] = 96, 427178354Ssam [0xc] = 108 428178354Ssam }; 429178354Ssam return ofdm_plcp2rate[plcp & 0xf]; 430178958Ssam } 431178958Ssam if (type == IEEE80211_T_CCK) { 432178354Ssam static const uint8_t cck_plcp2rate[16] = { 433178354Ssam [0xa] = 2, /* 0x0a */ 434178354Ssam [0x4] = 4, /* 0x14 */ 435178354Ssam [0x7] = 11, /* 0x37 */ 436178354Ssam [0xe] = 22, /* 0x6e */ 437178354Ssam [0xc] = 44, /* 0xdc , actually PBCC */ 438178354Ssam }; 439178354Ssam return cck_plcp2rate[plcp & 0xf]; 440178354Ssam } 441178958Ssam return 0; 442178354Ssam} 443178354Ssam 444178354Ssam/* 445178354Ssam * Covert 802.11 rate to PLCP signal. 446178354Ssam */ 447178354Ssamuint8_t 448178958Ssamieee80211_rate2plcp(int rate, enum ieee80211_phytype type) 449178354Ssam{ 450178958Ssam /* XXX ignore type for now since rates are unique */ 451178354Ssam switch (rate) { 452178354Ssam /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 453178354Ssam case 12: return 0xb; 454178354Ssam case 18: return 0xf; 455178354Ssam case 24: return 0xa; 456178354Ssam case 36: return 0xe; 457178354Ssam case 48: return 0x9; 458178354Ssam case 72: return 0xd; 459178354Ssam case 96: return 0x8; 460178354Ssam case 108: return 0xc; 461178958Ssam /* CCK rates (IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3) */ 462178958Ssam case 2: return 10; 463178958Ssam case 4: return 20; 464178958Ssam case 11: return 55; 465178958Ssam case 22: return 110; 466178958Ssam /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ 467178958Ssam case 44: return 220; 468178354Ssam } 469178958Ssam return 0; /* XXX unsupported/unknown rate */ 470178354Ssam} 471178958Ssam 472188821Ssam#define CCK_SIFS_TIME 10 473188821Ssam#define CCK_PREAMBLE_BITS 144 474188821Ssam#define CCK_PLCP_BITS 48 475188821Ssam 476188821Ssam#define OFDM_SIFS_TIME 16 477188821Ssam#define OFDM_PREAMBLE_TIME 20 478188821Ssam#define OFDM_PLCP_BITS 22 479188821Ssam#define OFDM_SYMBOL_TIME 4 480188821Ssam 481188821Ssam#define OFDM_HALF_SIFS_TIME 32 482188821Ssam#define OFDM_HALF_PREAMBLE_TIME 40 483188821Ssam#define OFDM_HALF_PLCP_BITS 22 484188821Ssam#define OFDM_HALF_SYMBOL_TIME 8 485188821Ssam 486188821Ssam#define OFDM_QUARTER_SIFS_TIME 64 487188821Ssam#define OFDM_QUARTER_PREAMBLE_TIME 80 488188821Ssam#define OFDM_QUARTER_PLCP_BITS 22 489188821Ssam#define OFDM_QUARTER_SYMBOL_TIME 16 490188821Ssam 491188821Ssam#define TURBO_SIFS_TIME 8 492188821Ssam#define TURBO_PREAMBLE_TIME 14 493188821Ssam#define TURBO_PLCP_BITS 22 494188821Ssam#define TURBO_SYMBOL_TIME 4 495188821Ssam 496178354Ssam/* 497178354Ssam * Compute the time to transmit a frame of length frameLen bytes 498178354Ssam * using the specified rate, phy, and short preamble setting. 499178354Ssam * SIFS is included. 500178354Ssam */ 501178354Ssamuint16_t 502178354Ssamieee80211_compute_duration(const struct ieee80211_rate_table *rt, 503178354Ssam uint32_t frameLen, uint16_t rate, int isShortPreamble) 504178354Ssam{ 505178354Ssam uint8_t rix = rt->rateCodeToIndex[rate]; 506178354Ssam uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 507178354Ssam uint32_t kbps; 508178354Ssam 509178354Ssam KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate)); 510178354Ssam kbps = rt->info[rix].rateKbps; 511178354Ssam if (kbps == 0) /* XXX bandaid for channel changes */ 512178354Ssam return 0; 513178354Ssam 514178354Ssam switch (rt->info[rix].phy) { 515178354Ssam case IEEE80211_T_CCK: 516178354Ssam phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 517178354Ssam if (isShortPreamble && rt->info[rix].shortPreamble) 518178354Ssam phyTime >>= 1; 519178354Ssam numBits = frameLen << 3; 520178354Ssam txTime = CCK_SIFS_TIME + phyTime 521178354Ssam + ((numBits * 1000)/kbps); 522178354Ssam break; 523178354Ssam case IEEE80211_T_OFDM: 524188821Ssam bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 525188821Ssam KASSERT(bitsPerSymbol != 0, ("full rate bps")); 526178354Ssam 527188821Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 528188821Ssam numSymbols = howmany(numBits, bitsPerSymbol); 529188821Ssam txTime = OFDM_SIFS_TIME 530188821Ssam + OFDM_PREAMBLE_TIME 531188821Ssam + (numSymbols * OFDM_SYMBOL_TIME); 532188821Ssam break; 533188821Ssam case IEEE80211_T_OFDM_HALF: 534188821Ssam bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; 535188821Ssam KASSERT(bitsPerSymbol != 0, ("1/4 rate bps")); 536178354Ssam 537188821Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 538188821Ssam numSymbols = howmany(numBits, bitsPerSymbol); 539188821Ssam txTime = OFDM_HALF_SIFS_TIME 540188821Ssam + OFDM_HALF_PREAMBLE_TIME 541188821Ssam + (numSymbols * OFDM_HALF_SYMBOL_TIME); 542188821Ssam break; 543188821Ssam case IEEE80211_T_OFDM_QUARTER: 544188821Ssam bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; 545188821Ssam KASSERT(bitsPerSymbol != 0, ("1/2 rate bps")); 546178354Ssam 547188821Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 548188821Ssam numSymbols = howmany(numBits, bitsPerSymbol); 549188821Ssam txTime = OFDM_QUARTER_SIFS_TIME 550188821Ssam + OFDM_QUARTER_PREAMBLE_TIME 551188821Ssam + (numSymbols * OFDM_QUARTER_SYMBOL_TIME); 552178354Ssam break; 553178354Ssam case IEEE80211_T_TURBO: 554178354Ssam /* we still save OFDM rates in kbps - so double them */ 555178354Ssam bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000; 556178354Ssam KASSERT(bitsPerSymbol != 0, ("turbo bps")); 557178354Ssam 558178354Ssam numBits = TURBO_PLCP_BITS + (frameLen << 3); 559178354Ssam numSymbols = howmany(numBits, bitsPerSymbol); 560178354Ssam txTime = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME 561178354Ssam + (numSymbols * TURBO_SYMBOL_TIME); 562178354Ssam break; 563178354Ssam default: 564178354Ssam panic("%s: unknown phy %u (rate %u)\n", __func__, 565178354Ssam rt->info[rix].phy, rate); 566178354Ssam break; 567178354Ssam } 568178354Ssam return txTime; 569178354Ssam} 570252727Sadrian 571252727Sadrianstatic const uint16_t ht20_bps[32] = { 572252727Sadrian 26, 52, 78, 104, 156, 208, 234, 260, 573252727Sadrian 52, 104, 156, 208, 312, 416, 468, 520, 574252727Sadrian 78, 156, 234, 312, 468, 624, 702, 780, 575252727Sadrian 104, 208, 312, 416, 624, 832, 936, 1040 576252727Sadrian}; 577252727Sadrianstatic const uint16_t ht40_bps[32] = { 578252727Sadrian 54, 108, 162, 216, 324, 432, 486, 540, 579252727Sadrian 108, 216, 324, 432, 648, 864, 972, 1080, 580252727Sadrian 162, 324, 486, 648, 972, 1296, 1458, 1620, 581252727Sadrian 216, 432, 648, 864, 1296, 1728, 1944, 2160 582252727Sadrian}; 583252727Sadrian 584252727Sadrian 585252727Sadrian#define OFDM_PLCP_BITS 22 586252727Sadrian#define HT_L_STF 8 587252727Sadrian#define HT_L_LTF 8 588252727Sadrian#define HT_L_SIG 4 589252727Sadrian#define HT_SIG 8 590252727Sadrian#define HT_STF 4 591252727Sadrian#define HT_LTF(n) ((n) * 4) 592252727Sadrian 593252727Sadrian#define HT_RC_2_MCS(_rc) ((_rc) & 0xf) 594252727Sadrian#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) 595252727Sadrian#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS) 596252727Sadrian 597252727Sadrian/* 598252727Sadrian * Calculate the transmit duration of an 11n frame. 599252727Sadrian */ 600252727Sadrianuint32_t 601252727Sadrianieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate, 602252727Sadrian int streams, int isht40, int isShortGI) 603252727Sadrian{ 604252727Sadrian uint32_t bitsPerSymbol, numBits, numSymbols, txTime; 605252727Sadrian 606252727Sadrian KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate)); 607252727Sadrian KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate)); 608252727Sadrian 609252727Sadrian if (isht40) 610252727Sadrian bitsPerSymbol = ht40_bps[rate & 0x1f]; 611252727Sadrian else 612252727Sadrian bitsPerSymbol = ht20_bps[rate & 0x1f]; 613252727Sadrian numBits = OFDM_PLCP_BITS + (frameLen << 3); 614252727Sadrian numSymbols = howmany(numBits, bitsPerSymbol); 615252727Sadrian if (isShortGI) 616252727Sadrian txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */ 617252727Sadrian else 618252727Sadrian txTime = numSymbols * 4; /* 4us */ 619252727Sadrian return txTime + HT_L_STF + HT_L_LTF + 620252727Sadrian HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 621252727Sadrian} 622252727Sadrian 623252727Sadrian#undef IS_HT_RATE 624252727Sadrian#undef HT_RC_2_STREAMS 625252727Sadrian#undef HT_RC_2_MCS 626252727Sadrian#undef HT_LTF 627252727Sadrian#undef HT_STF 628252727Sadrian#undef HT_SIG 629252727Sadrian#undef HT_L_SIG 630252727Sadrian#undef HT_L_LTF 631252727Sadrian#undef HT_L_STF 632252727Sadrian#undef OFDM_PLCP_BITS 633