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$"); 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> 38178354Ssam 39178354Ssam#include <sys/socket.h> 40178354Ssam 41178354Ssam#include <net/if.h> 42178354Ssam#include <net/if_media.h> 43178354Ssam 44178354Ssam#include <net80211/ieee80211_var.h> 45178354Ssam#include <net80211/ieee80211_phy.h> 46178354Ssam 47178354Ssam#ifdef notyet 48178354Ssamstruct ieee80211_ds_plcp_hdr { 49178354Ssam uint8_t i_signal; 50178354Ssam uint8_t i_service; 51178354Ssam uint16_t i_length; 52178354Ssam uint16_t i_crc; 53178354Ssam} __packed; 54178354Ssam 55178354Ssam#endif /* notyet */ 56178354Ssam 57178354Ssam/* shorthands to compact tables for readability */ 58178354Ssam#define OFDM IEEE80211_T_OFDM 59178354Ssam#define CCK IEEE80211_T_CCK 60178354Ssam#define TURBO IEEE80211_T_TURBO 61188821Ssam#define HALF IEEE80211_T_OFDM_HALF 62188821Ssam#define QUART IEEE80211_T_OFDM_QUARTER 63252727Sadrian#define HT IEEE80211_T_HT 64252727Sadrian/* XXX the 11n and the basic rate flag are unfortunately overlapping. Grr. */ 65252727Sadrian#define N(r) (IEEE80211_RATE_MCS | r) 66188821Ssam#define PBCC (IEEE80211_T_OFDM_QUARTER+1) /* XXX */ 67252727Sadrian#define B(r) (IEEE80211_RATE_BASIC | r) 68182833Ssam#define Mb(x) (x*1000) 69178354Ssam 70178354Ssamstatic struct ieee80211_rate_table ieee80211_11b_table = { 71182833Ssam .rateCount = 4, /* XXX no PBCC */ 72182833Ssam .info = { 73182833Ssam/* short ctrl */ 74182833Ssam/* Preamble dot11Rate Rate */ 75182833Ssam [0] = { .phy = CCK, 1000, 0x00, B(2), 0 },/* 1 Mb */ 76182833Ssam [1] = { .phy = CCK, 2000, 0x04, B(4), 1 },/* 2 Mb */ 77182833Ssam [2] = { .phy = CCK, 5500, 0x04, B(11), 1 },/* 5.5 Mb */ 78182833Ssam [3] = { .phy = CCK, 11000, 0x04, B(22), 1 },/* 11 Mb */ 79182833Ssam [4] = { .phy = PBCC, 22000, 0x04, 44, 3 } /* 22 Mb */ 80182833Ssam }, 81178354Ssam}; 82178354Ssam 83178354Ssamstatic struct ieee80211_rate_table ieee80211_11g_table = { 84182833Ssam .rateCount = 12, 85182833Ssam .info = { 86182833Ssam/* short ctrl */ 87182833Ssam/* Preamble dot11Rate Rate */ 88182833Ssam [0] = { .phy = CCK, 1000, 0x00, B(2), 0 }, 89182833Ssam [1] = { .phy = CCK, 2000, 0x04, B(4), 1 }, 90182833Ssam [2] = { .phy = CCK, 5500, 0x04, B(11), 2 }, 91182833Ssam [3] = { .phy = CCK, 11000, 0x04, B(22), 3 }, 92182833Ssam [4] = { .phy = OFDM, 6000, 0x00, 12, 4 }, 93182833Ssam [5] = { .phy = OFDM, 9000, 0x00, 18, 4 }, 94182833Ssam [6] = { .phy = OFDM, 12000, 0x00, 24, 6 }, 95182833Ssam [7] = { .phy = OFDM, 18000, 0x00, 36, 6 }, 96182833Ssam [8] = { .phy = OFDM, 24000, 0x00, 48, 8 }, 97182833Ssam [9] = { .phy = OFDM, 36000, 0x00, 72, 8 }, 98182833Ssam [10] = { .phy = OFDM, 48000, 0x00, 96, 8 }, 99182833Ssam [11] = { .phy = OFDM, 54000, 0x00, 108, 8 } 100182833Ssam }, 101178354Ssam}; 102178354Ssam 103178354Ssamstatic struct ieee80211_rate_table ieee80211_11a_table = { 104182833Ssam .rateCount = 8, 105182833Ssam .info = { 106182833Ssam/* short ctrl */ 107182833Ssam/* Preamble dot11Rate Rate */ 108182833Ssam [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 }, 109182833Ssam [1] = { .phy = OFDM, 9000, 0x00, 18, 0 }, 110182833Ssam [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 }, 111182833Ssam [3] = { .phy = OFDM, 18000, 0x00, 36, 2 }, 112182833Ssam [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 }, 113182833Ssam [5] = { .phy = OFDM, 36000, 0x00, 72, 4 }, 114182833Ssam [6] = { .phy = OFDM, 48000, 0x00, 96, 4 }, 115182833Ssam [7] = { .phy = OFDM, 54000, 0x00, 108, 4 } 116182833Ssam }, 117178354Ssam}; 118178354Ssam 119178354Ssamstatic struct ieee80211_rate_table ieee80211_half_table = { 120182833Ssam .rateCount = 8, 121182833Ssam .info = { 122182833Ssam/* short ctrl */ 123182833Ssam/* Preamble dot11Rate Rate */ 124188821Ssam [0] = { .phy = HALF, 3000, 0x00, B(6), 0 }, 125188821Ssam [1] = { .phy = HALF, 4500, 0x00, 9, 0 }, 126188821Ssam [2] = { .phy = HALF, 6000, 0x00, B(12), 2 }, 127188821Ssam [3] = { .phy = HALF, 9000, 0x00, 18, 2 }, 128188821Ssam [4] = { .phy = HALF, 12000, 0x00, B(24), 4 }, 129188821Ssam [5] = { .phy = HALF, 18000, 0x00, 36, 4 }, 130188821Ssam [6] = { .phy = HALF, 24000, 0x00, 48, 4 }, 131188821Ssam [7] = { .phy = HALF, 27000, 0x00, 54, 4 } 132182833Ssam }, 133178354Ssam}; 134178354Ssam 135178354Ssamstatic struct ieee80211_rate_table ieee80211_quarter_table = { 136182833Ssam .rateCount = 8, 137182833Ssam .info = { 138182833Ssam/* short ctrl */ 139182833Ssam/* Preamble dot11Rate Rate */ 140188821Ssam [0] = { .phy = QUART, 1500, 0x00, B(3), 0 }, 141188821Ssam [1] = { .phy = QUART, 2250, 0x00, 4, 0 }, 142188821Ssam [2] = { .phy = QUART, 3000, 0x00, B(9), 2 }, 143188821Ssam [3] = { .phy = QUART, 4500, 0x00, 9, 2 }, 144188821Ssam [4] = { .phy = QUART, 6000, 0x00, B(12), 4 }, 145188821Ssam [5] = { .phy = QUART, 9000, 0x00, 18, 4 }, 146188821Ssam [6] = { .phy = QUART, 12000, 0x00, 24, 4 }, 147188821Ssam [7] = { .phy = QUART, 13500, 0x00, 27, 4 } 148182833Ssam }, 149178354Ssam}; 150178354Ssam 151178354Ssamstatic struct ieee80211_rate_table ieee80211_turbog_table = { 152182833Ssam .rateCount = 7, 153182833Ssam .info = { 154182833Ssam/* short ctrl */ 155182833Ssam/* Preamble dot11Rate Rate */ 156182833Ssam [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 }, 157182833Ssam [1] = { .phy = TURBO, 24000, 0x00, B(24), 1 }, 158182833Ssam [2] = { .phy = TURBO, 36000, 0x00, 36, 1 }, 159182833Ssam [3] = { .phy = TURBO, 48000, 0x00, B(48), 3 }, 160182833Ssam [4] = { .phy = TURBO, 72000, 0x00, 72, 3 }, 161182833Ssam [5] = { .phy = TURBO, 96000, 0x00, 96, 3 }, 162182833Ssam [6] = { .phy = TURBO, 108000, 0x00, 108, 3 } 163182833Ssam }, 164178354Ssam}; 165178354Ssam 166178354Ssamstatic struct ieee80211_rate_table ieee80211_turboa_table = { 167182833Ssam .rateCount = 8, 168182833Ssam .info = { 169182833Ssam/* short ctrl */ 170182833Ssam/* Preamble dot11Rate Rate */ 171182833Ssam [0] = { .phy = TURBO, 12000, 0x00, B(12), 0 }, 172182833Ssam [1] = { .phy = TURBO, 18000, 0x00, 18, 0 }, 173182833Ssam [2] = { .phy = TURBO, 24000, 0x00, B(24), 2 }, 174182833Ssam [3] = { .phy = TURBO, 36000, 0x00, 36, 2 }, 175182833Ssam [4] = { .phy = TURBO, 48000, 0x00, B(48), 4 }, 176182833Ssam [5] = { .phy = TURBO, 72000, 0x00, 72, 4 }, 177182833Ssam [6] = { .phy = TURBO, 96000, 0x00, 96, 4 }, 178182833Ssam [7] = { .phy = TURBO, 108000, 0x00, 108, 4 } 179182833Ssam }, 180178354Ssam}; 181178354Ssam 182252727Sadrianstatic struct ieee80211_rate_table ieee80211_11ng_table = { 183252727Sadrian .rateCount = 36, 184252727Sadrian .info = { 185252727Sadrian/* short ctrl */ 186252727Sadrian/* Preamble dot11Rate Rate */ 187252727Sadrian [0] = { .phy = CCK, 1000, 0x00, B(2), 0 }, 188252727Sadrian [1] = { .phy = CCK, 2000, 0x04, B(4), 1 }, 189252727Sadrian [2] = { .phy = CCK, 5500, 0x04, B(11), 2 }, 190252727Sadrian [3] = { .phy = CCK, 11000, 0x04, B(22), 3 }, 191252727Sadrian [4] = { .phy = OFDM, 6000, 0x00, 12, 4 }, 192252727Sadrian [5] = { .phy = OFDM, 9000, 0x00, 18, 4 }, 193252727Sadrian [6] = { .phy = OFDM, 12000, 0x00, 24, 6 }, 194252727Sadrian [7] = { .phy = OFDM, 18000, 0x00, 36, 6 }, 195252727Sadrian [8] = { .phy = OFDM, 24000, 0x00, 48, 8 }, 196252727Sadrian [9] = { .phy = OFDM, 36000, 0x00, 72, 8 }, 197252727Sadrian [10] = { .phy = OFDM, 48000, 0x00, 96, 8 }, 198252727Sadrian [11] = { .phy = OFDM, 54000, 0x00, 108, 8 }, 199252727Sadrian 200252727Sadrian [12] = { .phy = HT, 6500, 0x00, N(0), 4 }, 201252727Sadrian [13] = { .phy = HT, 13000, 0x00, N(1), 6 }, 202252727Sadrian [14] = { .phy = HT, 19500, 0x00, N(2), 6 }, 203252727Sadrian [15] = { .phy = HT, 26000, 0x00, N(3), 8 }, 204252727Sadrian [16] = { .phy = HT, 39000, 0x00, N(4), 8 }, 205252727Sadrian [17] = { .phy = HT, 52000, 0x00, N(5), 8 }, 206252727Sadrian [18] = { .phy = HT, 58500, 0x00, N(6), 8 }, 207252727Sadrian [19] = { .phy = HT, 65000, 0x00, N(7), 8 }, 208252727Sadrian 209252727Sadrian [20] = { .phy = HT, 13000, 0x00, N(8), 4 }, 210252727Sadrian [21] = { .phy = HT, 26000, 0x00, N(9), 6 }, 211252727Sadrian [22] = { .phy = HT, 39000, 0x00, N(10), 6 }, 212252727Sadrian [23] = { .phy = HT, 52000, 0x00, N(11), 8 }, 213252727Sadrian [24] = { .phy = HT, 78000, 0x00, N(12), 8 }, 214252727Sadrian [25] = { .phy = HT, 104000, 0x00, N(13), 8 }, 215252727Sadrian [26] = { .phy = HT, 117000, 0x00, N(14), 8 }, 216252727Sadrian [27] = { .phy = HT, 130000, 0x00, N(15), 8 }, 217252727Sadrian 218252727Sadrian [28] = { .phy = HT, 19500, 0x00, N(16), 4 }, 219252727Sadrian [29] = { .phy = HT, 39000, 0x00, N(17), 6 }, 220252727Sadrian [30] = { .phy = HT, 58500, 0x00, N(18), 6 }, 221252727Sadrian [31] = { .phy = HT, 78000, 0x00, N(19), 8 }, 222252727Sadrian [32] = { .phy = HT, 117000, 0x00, N(20), 8 }, 223252727Sadrian [33] = { .phy = HT, 156000, 0x00, N(21), 8 }, 224252727Sadrian [34] = { .phy = HT, 175500, 0x00, N(22), 8 }, 225252727Sadrian [35] = { .phy = HT, 195000, 0x00, N(23), 8 }, 226252727Sadrian 227252727Sadrian }, 228252727Sadrian}; 229252727Sadrian 230252727Sadrianstatic struct ieee80211_rate_table ieee80211_11na_table = { 231252727Sadrian .rateCount = 32, 232252727Sadrian .info = { 233252727Sadrian/* short ctrl */ 234252727Sadrian/* Preamble dot11Rate Rate */ 235252727Sadrian [0] = { .phy = OFDM, 6000, 0x00, B(12), 0 }, 236252727Sadrian [1] = { .phy = OFDM, 9000, 0x00, 18, 0 }, 237252727Sadrian [2] = { .phy = OFDM, 12000, 0x00, B(24), 2 }, 238252727Sadrian [3] = { .phy = OFDM, 18000, 0x00, 36, 2 }, 239252727Sadrian [4] = { .phy = OFDM, 24000, 0x00, B(48), 4 }, 240252727Sadrian [5] = { .phy = OFDM, 36000, 0x00, 72, 4 }, 241252727Sadrian [6] = { .phy = OFDM, 48000, 0x00, 96, 4 }, 242252727Sadrian [7] = { .phy = OFDM, 54000, 0x00, 108, 4 }, 243252727Sadrian 244252727Sadrian [8] = { .phy = HT, 6500, 0x00, N(0), 0 }, 245252727Sadrian [9] = { .phy = HT, 13000, 0x00, N(1), 2 }, 246252727Sadrian [10] = { .phy = HT, 19500, 0x00, N(2), 2 }, 247252727Sadrian [11] = { .phy = HT, 26000, 0x00, N(3), 4 }, 248252727Sadrian [12] = { .phy = HT, 39000, 0x00, N(4), 4 }, 249252727Sadrian [13] = { .phy = HT, 52000, 0x00, N(5), 4 }, 250252727Sadrian [14] = { .phy = HT, 58500, 0x00, N(6), 4 }, 251252727Sadrian [15] = { .phy = HT, 65000, 0x00, N(7), 4 }, 252252727Sadrian 253252727Sadrian [16] = { .phy = HT, 13000, 0x00, N(8), 0 }, 254252727Sadrian [17] = { .phy = HT, 26000, 0x00, N(9), 2 }, 255252727Sadrian [18] = { .phy = HT, 39000, 0x00, N(10), 2 }, 256252727Sadrian [19] = { .phy = HT, 52000, 0x00, N(11), 4 }, 257252727Sadrian [20] = { .phy = HT, 78000, 0x00, N(12), 4 }, 258252727Sadrian [21] = { .phy = HT, 104000, 0x00, N(13), 4 }, 259252727Sadrian [22] = { .phy = HT, 117000, 0x00, N(14), 4 }, 260252727Sadrian [23] = { .phy = HT, 130000, 0x00, N(15), 4 }, 261252727Sadrian 262252727Sadrian [24] = { .phy = HT, 19500, 0x00, N(16), 0 }, 263252727Sadrian [25] = { .phy = HT, 39000, 0x00, N(17), 2 }, 264252727Sadrian [26] = { .phy = HT, 58500, 0x00, N(18), 2 }, 265252727Sadrian [27] = { .phy = HT, 78000, 0x00, N(19), 4 }, 266252727Sadrian [28] = { .phy = HT, 117000, 0x00, N(20), 4 }, 267252727Sadrian [29] = { .phy = HT, 156000, 0x00, N(21), 4 }, 268252727Sadrian [30] = { .phy = HT, 175500, 0x00, N(22), 4 }, 269252727Sadrian [31] = { .phy = HT, 195000, 0x00, N(23), 4 }, 270252727Sadrian 271252727Sadrian }, 272252727Sadrian}; 273252727Sadrian 274182833Ssam#undef Mb 275182833Ssam#undef B 276178354Ssam#undef OFDM 277188821Ssam#undef HALF 278188821Ssam#undef QUART 279178354Ssam#undef CCK 280178354Ssam#undef TURBO 281178354Ssam#undef XR 282252727Sadrian#undef HT 283252727Sadrian#undef N 284178354Ssam 285178354Ssam/* 286178354Ssam * Setup a rate table's reverse lookup table and fill in 287178354Ssam * ack durations. The reverse lookup tables are assumed 288178354Ssam * to be initialized to zero (or at least the first entry). 289178354Ssam * We use this as a key that indicates whether or not 290178354Ssam * we've previously setup the reverse lookup table. 291178354Ssam * 292178354Ssam * XXX not reentrant, but shouldn't matter 293178354Ssam */ 294178354Ssamstatic void 295178354Ssamieee80211_setup_ratetable(struct ieee80211_rate_table *rt) 296178354Ssam{ 297178354Ssam#define WLAN_CTRL_FRAME_SIZE \ 298178354Ssam (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN) 299178354Ssam 300178354Ssam int i; 301178354Ssam 302254315Srpaulo for (i = 0; i < nitems(rt->rateCodeToIndex); i++) 303178354Ssam rt->rateCodeToIndex[i] = (uint8_t) -1; 304178354Ssam for (i = 0; i < rt->rateCount; i++) { 305178354Ssam uint8_t code = rt->info[i].dot11Rate; 306178354Ssam uint8_t cix = rt->info[i].ctlRateIndex; 307178354Ssam uint8_t ctl_rate = rt->info[cix].dot11Rate; 308178354Ssam 309252727Sadrian /* 310252727Sadrian * Map without the basic rate bit. 311252727Sadrian * 312252727Sadrian * It's up to the caller to ensure that the basic 313252727Sadrian * rate bit is stripped here. 314252727Sadrian * 315252727Sadrian * For HT, use the MCS rate bit. 316252727Sadrian */ 317252727Sadrian code &= IEEE80211_RATE_VAL; 318252727Sadrian if (rt->info[i].phy == IEEE80211_T_HT) { 319252727Sadrian code |= IEEE80211_RATE_MCS; 320178354Ssam } 321178354Ssam 322252727Sadrian /* XXX assume the control rate is non-MCS? */ 323252727Sadrian ctl_rate &= IEEE80211_RATE_VAL; 324252727Sadrian rt->rateCodeToIndex[code] = i; 325252727Sadrian 326178354Ssam /* 327178354Ssam * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 328178354Ssam * depends on whether they are marked as basic rates; 329178354Ssam * the static tables are setup with an 11b-compatible 330178354Ssam * 2Mb/s rate which will work but is suboptimal 331178354Ssam * 332178354Ssam * NB: Control rate is always less than or equal to the 333178354Ssam * current rate, so control rate's reverse lookup entry 334178354Ssam * has been installed and following call is safe. 335178354Ssam */ 336178354Ssam rt->info[i].lpAckDuration = ieee80211_compute_duration(rt, 337178354Ssam WLAN_CTRL_FRAME_SIZE, ctl_rate, 0); 338178354Ssam rt->info[i].spAckDuration = ieee80211_compute_duration(rt, 339178354Ssam WLAN_CTRL_FRAME_SIZE, ctl_rate, IEEE80211_F_SHPREAMBLE); 340178354Ssam } 341178354Ssam 342178354Ssam#undef WLAN_CTRL_FRAME_SIZE 343178354Ssam} 344178354Ssam 345178354Ssam/* Setup all rate tables */ 346178354Ssamstatic void 347178354Ssamieee80211_phy_init(void) 348178354Ssam{ 349178354Ssam static struct ieee80211_rate_table * const ratetables[] = { 350178354Ssam &ieee80211_half_table, 351178354Ssam &ieee80211_quarter_table, 352252727Sadrian &ieee80211_11na_table, 353252727Sadrian &ieee80211_11ng_table, 354178354Ssam &ieee80211_turbog_table, 355178354Ssam &ieee80211_turboa_table, 356178354Ssam &ieee80211_11a_table, 357178354Ssam &ieee80211_11g_table, 358178354Ssam &ieee80211_11b_table 359178354Ssam }; 360178354Ssam int i; 361178354Ssam 362254315Srpaulo for (i = 0; i < nitems(ratetables); ++i) 363178354Ssam ieee80211_setup_ratetable(ratetables[i]); 364178354Ssam 365178354Ssam} 366178354SsamSYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL); 367178354Ssam 368178354Ssamconst struct ieee80211_rate_table * 369178354Ssamieee80211_get_ratetable(struct ieee80211_channel *c) 370178354Ssam{ 371178354Ssam const struct ieee80211_rate_table *rt; 372178354Ssam 373178354Ssam /* XXX HT */ 374178354Ssam if (IEEE80211_IS_CHAN_HALF(c)) 375178354Ssam rt = &ieee80211_half_table; 376178354Ssam else if (IEEE80211_IS_CHAN_QUARTER(c)) 377178354Ssam rt = &ieee80211_quarter_table; 378178354Ssam else if (IEEE80211_IS_CHAN_HTA(c)) 379252727Sadrian rt = &ieee80211_11na_table; 380178354Ssam else if (IEEE80211_IS_CHAN_HTG(c)) 381252727Sadrian rt = &ieee80211_11ng_table; 382178354Ssam else if (IEEE80211_IS_CHAN_108G(c)) 383178354Ssam rt = &ieee80211_turbog_table; 384178354Ssam else if (IEEE80211_IS_CHAN_ST(c)) 385178354Ssam rt = &ieee80211_turboa_table; 386178354Ssam else if (IEEE80211_IS_CHAN_TURBO(c)) 387178354Ssam rt = &ieee80211_turboa_table; 388178354Ssam else if (IEEE80211_IS_CHAN_A(c)) 389178354Ssam rt = &ieee80211_11a_table; 390178354Ssam else if (IEEE80211_IS_CHAN_ANYG(c)) 391178354Ssam rt = &ieee80211_11g_table; 392178354Ssam else if (IEEE80211_IS_CHAN_B(c)) 393178354Ssam rt = &ieee80211_11b_table; 394178354Ssam else { 395178354Ssam /* NB: should not get here */ 396178354Ssam panic("%s: no rate table for channel; freq %u flags 0x%x\n", 397178354Ssam __func__, c->ic_freq, c->ic_flags); 398178354Ssam } 399178354Ssam return rt; 400178354Ssam} 401178354Ssam 402178354Ssam/* 403178354Ssam * Convert PLCP signal/rate field to 802.11 rate (.5Mbits/s) 404178354Ssam * 405178354Ssam * Note we do no parameter checking; this routine is mainly 406178354Ssam * used to derive an 802.11 rate for constructing radiotap 407178354Ssam * header data for rx frames. 408178354Ssam * 409178354Ssam * XXX might be a candidate for inline 410178354Ssam */ 411178354Ssamuint8_t 412178958Ssamieee80211_plcp2rate(uint8_t plcp, enum ieee80211_phytype type) 413178354Ssam{ 414178958Ssam if (type == IEEE80211_T_OFDM) { 415178354Ssam static const uint8_t ofdm_plcp2rate[16] = { 416178354Ssam [0xb] = 12, 417178354Ssam [0xf] = 18, 418178354Ssam [0xa] = 24, 419178354Ssam [0xe] = 36, 420178354Ssam [0x9] = 48, 421178354Ssam [0xd] = 72, 422178354Ssam [0x8] = 96, 423178354Ssam [0xc] = 108 424178354Ssam }; 425178354Ssam return ofdm_plcp2rate[plcp & 0xf]; 426178958Ssam } 427178958Ssam if (type == IEEE80211_T_CCK) { 428178354Ssam static const uint8_t cck_plcp2rate[16] = { 429178354Ssam [0xa] = 2, /* 0x0a */ 430178354Ssam [0x4] = 4, /* 0x14 */ 431178354Ssam [0x7] = 11, /* 0x37 */ 432178354Ssam [0xe] = 22, /* 0x6e */ 433178354Ssam [0xc] = 44, /* 0xdc , actually PBCC */ 434178354Ssam }; 435178354Ssam return cck_plcp2rate[plcp & 0xf]; 436178354Ssam } 437178958Ssam return 0; 438178354Ssam} 439178354Ssam 440178354Ssam/* 441178354Ssam * Covert 802.11 rate to PLCP signal. 442178354Ssam */ 443178354Ssamuint8_t 444178958Ssamieee80211_rate2plcp(int rate, enum ieee80211_phytype type) 445178354Ssam{ 446178958Ssam /* XXX ignore type for now since rates are unique */ 447178354Ssam switch (rate) { 448178354Ssam /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 449178354Ssam case 12: return 0xb; 450178354Ssam case 18: return 0xf; 451178354Ssam case 24: return 0xa; 452178354Ssam case 36: return 0xe; 453178354Ssam case 48: return 0x9; 454178354Ssam case 72: return 0xd; 455178354Ssam case 96: return 0x8; 456178354Ssam case 108: return 0xc; 457178958Ssam /* CCK rates (IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3) */ 458178958Ssam case 2: return 10; 459178958Ssam case 4: return 20; 460178958Ssam case 11: return 55; 461178958Ssam case 22: return 110; 462178958Ssam /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ 463178958Ssam case 44: return 220; 464178354Ssam } 465178958Ssam return 0; /* XXX unsupported/unknown rate */ 466178354Ssam} 467178958Ssam 468188821Ssam#define CCK_SIFS_TIME 10 469188821Ssam#define CCK_PREAMBLE_BITS 144 470188821Ssam#define CCK_PLCP_BITS 48 471188821Ssam 472188821Ssam#define OFDM_SIFS_TIME 16 473188821Ssam#define OFDM_PREAMBLE_TIME 20 474188821Ssam#define OFDM_PLCP_BITS 22 475188821Ssam#define OFDM_SYMBOL_TIME 4 476188821Ssam 477188821Ssam#define OFDM_HALF_SIFS_TIME 32 478188821Ssam#define OFDM_HALF_PREAMBLE_TIME 40 479188821Ssam#define OFDM_HALF_PLCP_BITS 22 480188821Ssam#define OFDM_HALF_SYMBOL_TIME 8 481188821Ssam 482188821Ssam#define OFDM_QUARTER_SIFS_TIME 64 483188821Ssam#define OFDM_QUARTER_PREAMBLE_TIME 80 484188821Ssam#define OFDM_QUARTER_PLCP_BITS 22 485188821Ssam#define OFDM_QUARTER_SYMBOL_TIME 16 486188821Ssam 487188821Ssam#define TURBO_SIFS_TIME 8 488188821Ssam#define TURBO_PREAMBLE_TIME 14 489188821Ssam#define TURBO_PLCP_BITS 22 490188821Ssam#define TURBO_SYMBOL_TIME 4 491188821Ssam 492178354Ssam/* 493178354Ssam * Compute the time to transmit a frame of length frameLen bytes 494178354Ssam * using the specified rate, phy, and short preamble setting. 495178354Ssam * SIFS is included. 496178354Ssam */ 497178354Ssamuint16_t 498178354Ssamieee80211_compute_duration(const struct ieee80211_rate_table *rt, 499178354Ssam uint32_t frameLen, uint16_t rate, int isShortPreamble) 500178354Ssam{ 501178354Ssam uint8_t rix = rt->rateCodeToIndex[rate]; 502178354Ssam uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 503178354Ssam uint32_t kbps; 504178354Ssam 505178354Ssam KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate)); 506178354Ssam kbps = rt->info[rix].rateKbps; 507178354Ssam if (kbps == 0) /* XXX bandaid for channel changes */ 508178354Ssam return 0; 509178354Ssam 510178354Ssam switch (rt->info[rix].phy) { 511178354Ssam case IEEE80211_T_CCK: 512178354Ssam phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 513178354Ssam if (isShortPreamble && rt->info[rix].shortPreamble) 514178354Ssam phyTime >>= 1; 515178354Ssam numBits = frameLen << 3; 516178354Ssam txTime = CCK_SIFS_TIME + phyTime 517178354Ssam + ((numBits * 1000)/kbps); 518178354Ssam break; 519178354Ssam case IEEE80211_T_OFDM: 520188821Ssam bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 521188821Ssam KASSERT(bitsPerSymbol != 0, ("full rate bps")); 522178354Ssam 523188821Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 524188821Ssam numSymbols = howmany(numBits, bitsPerSymbol); 525188821Ssam txTime = OFDM_SIFS_TIME 526188821Ssam + OFDM_PREAMBLE_TIME 527188821Ssam + (numSymbols * OFDM_SYMBOL_TIME); 528188821Ssam break; 529188821Ssam case IEEE80211_T_OFDM_HALF: 530188821Ssam bitsPerSymbol = (kbps * OFDM_HALF_SYMBOL_TIME) / 1000; 531188821Ssam KASSERT(bitsPerSymbol != 0, ("1/4 rate bps")); 532178354Ssam 533188821Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 534188821Ssam numSymbols = howmany(numBits, bitsPerSymbol); 535188821Ssam txTime = OFDM_HALF_SIFS_TIME 536188821Ssam + OFDM_HALF_PREAMBLE_TIME 537188821Ssam + (numSymbols * OFDM_HALF_SYMBOL_TIME); 538188821Ssam break; 539188821Ssam case IEEE80211_T_OFDM_QUARTER: 540188821Ssam bitsPerSymbol = (kbps * OFDM_QUARTER_SYMBOL_TIME) / 1000; 541188821Ssam KASSERT(bitsPerSymbol != 0, ("1/2 rate bps")); 542178354Ssam 543188821Ssam numBits = OFDM_PLCP_BITS + (frameLen << 3); 544188821Ssam numSymbols = howmany(numBits, bitsPerSymbol); 545188821Ssam txTime = OFDM_QUARTER_SIFS_TIME 546188821Ssam + OFDM_QUARTER_PREAMBLE_TIME 547188821Ssam + (numSymbols * OFDM_QUARTER_SYMBOL_TIME); 548178354Ssam break; 549178354Ssam case IEEE80211_T_TURBO: 550178354Ssam /* we still save OFDM rates in kbps - so double them */ 551178354Ssam bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000; 552178354Ssam KASSERT(bitsPerSymbol != 0, ("turbo bps")); 553178354Ssam 554178354Ssam numBits = TURBO_PLCP_BITS + (frameLen << 3); 555178354Ssam numSymbols = howmany(numBits, bitsPerSymbol); 556178354Ssam txTime = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME 557178354Ssam + (numSymbols * TURBO_SYMBOL_TIME); 558178354Ssam break; 559178354Ssam default: 560178354Ssam panic("%s: unknown phy %u (rate %u)\n", __func__, 561178354Ssam rt->info[rix].phy, rate); 562178354Ssam break; 563178354Ssam } 564178354Ssam return txTime; 565178354Ssam} 566252727Sadrian 567252727Sadrianstatic const uint16_t ht20_bps[32] = { 568252727Sadrian 26, 52, 78, 104, 156, 208, 234, 260, 569252727Sadrian 52, 104, 156, 208, 312, 416, 468, 520, 570252727Sadrian 78, 156, 234, 312, 468, 624, 702, 780, 571252727Sadrian 104, 208, 312, 416, 624, 832, 936, 1040 572252727Sadrian}; 573252727Sadrianstatic const uint16_t ht40_bps[32] = { 574252727Sadrian 54, 108, 162, 216, 324, 432, 486, 540, 575252727Sadrian 108, 216, 324, 432, 648, 864, 972, 1080, 576252727Sadrian 162, 324, 486, 648, 972, 1296, 1458, 1620, 577252727Sadrian 216, 432, 648, 864, 1296, 1728, 1944, 2160 578252727Sadrian}; 579252727Sadrian 580252727Sadrian 581252727Sadrian#define OFDM_PLCP_BITS 22 582252727Sadrian#define HT_L_STF 8 583252727Sadrian#define HT_L_LTF 8 584252727Sadrian#define HT_L_SIG 4 585252727Sadrian#define HT_SIG 8 586252727Sadrian#define HT_STF 4 587252727Sadrian#define HT_LTF(n) ((n) * 4) 588252727Sadrian 589252727Sadrian#define HT_RC_2_MCS(_rc) ((_rc) & 0xf) 590252727Sadrian#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) 591252727Sadrian#define IS_HT_RATE(_rc) ( (_rc) & IEEE80211_RATE_MCS) 592252727Sadrian 593252727Sadrian/* 594252727Sadrian * Calculate the transmit duration of an 11n frame. 595252727Sadrian */ 596252727Sadrianuint32_t 597252727Sadrianieee80211_compute_duration_ht(uint32_t frameLen, uint16_t rate, 598252727Sadrian int streams, int isht40, int isShortGI) 599252727Sadrian{ 600252727Sadrian uint32_t bitsPerSymbol, numBits, numSymbols, txTime; 601252727Sadrian 602252727Sadrian KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate)); 603252727Sadrian KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate)); 604252727Sadrian 605252727Sadrian if (isht40) 606252727Sadrian bitsPerSymbol = ht40_bps[rate & 0x1f]; 607252727Sadrian else 608252727Sadrian bitsPerSymbol = ht20_bps[rate & 0x1f]; 609252727Sadrian numBits = OFDM_PLCP_BITS + (frameLen << 3); 610252727Sadrian numSymbols = howmany(numBits, bitsPerSymbol); 611252727Sadrian if (isShortGI) 612252727Sadrian txTime = ((numSymbols * 18) + 4) / 5; /* 3.6us */ 613252727Sadrian else 614252727Sadrian txTime = numSymbols * 4; /* 4us */ 615252727Sadrian return txTime + HT_L_STF + HT_L_LTF + 616252727Sadrian HT_L_SIG + HT_SIG + HT_STF + HT_LTF(streams); 617252727Sadrian} 618252727Sadrian 619252727Sadrian#undef IS_HT_RATE 620252727Sadrian#undef HT_RC_2_STREAMS 621252727Sadrian#undef HT_RC_2_MCS 622252727Sadrian#undef HT_LTF 623252727Sadrian#undef HT_STF 624252727Sadrian#undef HT_SIG 625252727Sadrian#undef HT_L_SIG 626252727Sadrian#undef HT_L_LTF 627252727Sadrian#undef HT_L_STF 628252727Sadrian#undef OFDM_PLCP_BITS 629