1b032f27cSSam Leffler /*- 2b032f27cSSam Leffler * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting 3b032f27cSSam Leffler * All rights reserved. 4b032f27cSSam Leffler * 5b032f27cSSam Leffler * Redistribution and use in source and binary forms, with or without 6b032f27cSSam Leffler * modification, are permitted provided that the following conditions 7b032f27cSSam Leffler * are met: 8b032f27cSSam Leffler * 1. Redistributions of source code must retain the above copyright 9b032f27cSSam Leffler * notice, this list of conditions and the following disclaimer. 10b032f27cSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 11b032f27cSSam Leffler * notice, this list of conditions and the following disclaimer in the 12b032f27cSSam Leffler * documentation and/or other materials provided with the distribution. 13b032f27cSSam Leffler * 14b032f27cSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15b032f27cSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16b032f27cSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17b032f27cSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18b032f27cSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19b032f27cSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20b032f27cSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21b032f27cSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22b032f27cSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23b032f27cSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24b032f27cSSam Leffler */ 25b032f27cSSam Leffler 26b032f27cSSam Leffler #include <sys/cdefs.h> 27b032f27cSSam Leffler __FBSDID("$FreeBSD$"); 28b032f27cSSam Leffler 29b032f27cSSam Leffler /* 30b032f27cSSam Leffler * IEEE 802.11 PHY-related support. 31b032f27cSSam Leffler */ 32b032f27cSSam Leffler 33b032f27cSSam Leffler #include "opt_inet.h" 34b032f27cSSam Leffler 35b032f27cSSam Leffler #include <sys/param.h> 36b032f27cSSam Leffler #include <sys/kernel.h> 37b032f27cSSam Leffler #include <sys/systm.h> 38b032f27cSSam Leffler 39b032f27cSSam Leffler #include <sys/socket.h> 40b032f27cSSam Leffler 41b032f27cSSam Leffler #include <net/if.h> 42b032f27cSSam Leffler #include <net/if_media.h> 43b032f27cSSam Leffler 44b032f27cSSam Leffler #include <net80211/ieee80211_var.h> 45b032f27cSSam Leffler #include <net80211/ieee80211_phy.h> 46b032f27cSSam Leffler 47b032f27cSSam Leffler #ifdef notyet 48b032f27cSSam Leffler struct ieee80211_ds_plcp_hdr { 49b032f27cSSam Leffler uint8_t i_signal; 50b032f27cSSam Leffler uint8_t i_service; 51b032f27cSSam Leffler uint16_t i_length; 52b032f27cSSam Leffler uint16_t i_crc; 53b032f27cSSam Leffler } __packed; 54b032f27cSSam Leffler 55b032f27cSSam Leffler #endif /* notyet */ 56b032f27cSSam Leffler 57b032f27cSSam Leffler /* shorthands to compact tables for readability */ 58b032f27cSSam Leffler #define OFDM IEEE80211_T_OFDM 59b032f27cSSam Leffler #define CCK IEEE80211_T_CCK 60b032f27cSSam Leffler #define TURBO IEEE80211_T_TURBO 61b032f27cSSam Leffler #define PBCC (IEEE80211_T_HT+1) /* XXX */ 62b032f27cSSam Leffler 63b032f27cSSam Leffler static struct ieee80211_rate_table ieee80211_11b_table = { 64b032f27cSSam Leffler 4, /* number of rates, XXX no PBCC */ 65b032f27cSSam Leffler { 0 }, 66b032f27cSSam Leffler { 67b032f27cSSam Leffler /* short ctrl */ 68b032f27cSSam Leffler /* Preamble dot11Rate Rate */ 69b032f27cSSam Leffler /* 1 Mb */ { CCK, 1000, 0x00, (0x80| 2), 0 }, 70b032f27cSSam Leffler /* 2 Mb */ { CCK, 2000, 0x04, (0x80| 4), 1 }, 71b032f27cSSam Leffler /* 5.5 Mb */ { CCK, 5500, 0x04, (0x80|11), 1 }, 72b032f27cSSam Leffler /* 11 Mb */ { CCK, 11000, 0x04, (0x80|22), 1 }, 73b032f27cSSam Leffler /* 22 Mb */ { PBCC, 22000, 0x04, 44, 3 } 74b032f27cSSam Leffler }, 75b032f27cSSam Leffler }; 76b032f27cSSam Leffler 77b032f27cSSam Leffler 78b032f27cSSam Leffler static struct ieee80211_rate_table ieee80211_11g_table = { 79b032f27cSSam Leffler 12, /* number of rates */ 80b032f27cSSam Leffler { 0 }, 81b032f27cSSam Leffler { 82b032f27cSSam Leffler /* short ctrl */ 83b032f27cSSam Leffler /* Preamble dot11Rate Rate */ 84b032f27cSSam Leffler /* 1 Mb */ { CCK, 1000, 0x00, (0x80| 2), 0 }, 85b032f27cSSam Leffler /* 2 Mb */ { CCK, 2000, 0x04, (0x80| 4), 1 }, 86b032f27cSSam Leffler /* 5.5 Mb */ { CCK, 5500, 0x04, (0x80|11), 2 }, 87b032f27cSSam Leffler /* 11 Mb */ { CCK, 11000, 0x04, (0x80|22), 3 }, 88b032f27cSSam Leffler /* 6 Mb */ { OFDM, 6000, 0x00, 12, 4 }, 89b032f27cSSam Leffler /* 9 Mb */ { OFDM, 9000, 0x00, 18, 4 }, 90b032f27cSSam Leffler /* 12 Mb */ { OFDM, 12000, 0x00, 24, 6 }, 91b032f27cSSam Leffler /* 18 Mb */ { OFDM, 18000, 0x00, 36, 6 }, 92b032f27cSSam Leffler /* 24 Mb */ { OFDM, 24000, 0x00, 48, 8 }, 93b032f27cSSam Leffler /* 36 Mb */ { OFDM, 36000, 0x00, 72, 8 }, 94b032f27cSSam Leffler /* 48 Mb */ { OFDM, 48000, 0x00, 96, 8 }, 95b032f27cSSam Leffler /* 54 Mb */ { OFDM, 54000, 0x00, 108, 8 } 96b032f27cSSam Leffler }, 97b032f27cSSam Leffler }; 98b032f27cSSam Leffler 99b032f27cSSam Leffler static struct ieee80211_rate_table ieee80211_11a_table = { 100b032f27cSSam Leffler 8, /* number of rates */ 101b032f27cSSam Leffler { 0 }, 102b032f27cSSam Leffler { 103b032f27cSSam Leffler /* short ctrl */ 104b032f27cSSam Leffler /* Preamble dot11Rate Rate */ 105b032f27cSSam Leffler /* 6 Mb */ { OFDM, 6000, 0x00, (0x80|12), 0 }, 106b032f27cSSam Leffler /* 9 Mb */ { OFDM, 9000, 0x00, 18, 0 }, 107b032f27cSSam Leffler /* 12 Mb */ { OFDM, 12000, 0x00, (0x80|24), 2 }, 108b032f27cSSam Leffler /* 18 Mb */ { OFDM, 18000, 0x00, 36, 2 }, 109b032f27cSSam Leffler /* 24 Mb */ { OFDM, 24000, 0x00, (0x80|48), 4 }, 110b032f27cSSam Leffler /* 36 Mb */ { OFDM, 36000, 0x00, 72, 4 }, 111b032f27cSSam Leffler /* 48 Mb */ { OFDM, 48000, 0x00, 96, 4 }, 112b032f27cSSam Leffler /* 54 Mb */ { OFDM, 54000, 0x00, 108, 4 } 113b032f27cSSam Leffler }, 114b032f27cSSam Leffler }; 115b032f27cSSam Leffler 116b032f27cSSam Leffler static struct ieee80211_rate_table ieee80211_half_table = { 117b032f27cSSam Leffler 8, /* number of rates */ 118b032f27cSSam Leffler { 0 }, 119b032f27cSSam Leffler { 120b032f27cSSam Leffler /* short ctrl */ 121b032f27cSSam Leffler /* Preamble dot11Rate Rate */ 122b032f27cSSam Leffler /* 6 Mb */ { OFDM, 3000, 0x00, (0x80| 6), 0 }, 123b032f27cSSam Leffler /* 9 Mb */ { OFDM, 4500, 0x00, 9, 0 }, 124b032f27cSSam Leffler /* 12 Mb */ { OFDM, 6000, 0x00, (0x80|12), 2 }, 125b032f27cSSam Leffler /* 18 Mb */ { OFDM, 9000, 0x00, 18, 2 }, 126b032f27cSSam Leffler /* 24 Mb */ { OFDM, 12000, 0x00, (0x80|24), 4 }, 127b032f27cSSam Leffler /* 36 Mb */ { OFDM, 18000, 0x00, 36, 4 }, 128b032f27cSSam Leffler /* 48 Mb */ { OFDM, 24000, 0x00, 48, 4 }, 129b032f27cSSam Leffler /* 54 Mb */ { OFDM, 27000, 0x00, 54, 4 } 130b032f27cSSam Leffler }, 131b032f27cSSam Leffler }; 132b032f27cSSam Leffler 133b032f27cSSam Leffler static struct ieee80211_rate_table ieee80211_quarter_table = { 134b032f27cSSam Leffler 8, /* number of rates */ 135b032f27cSSam Leffler { 0 }, 136b032f27cSSam Leffler { 137b032f27cSSam Leffler /* short ctrl */ 138b032f27cSSam Leffler /* Preamble dot11Rate Rate */ 139b032f27cSSam Leffler /* 6 Mb */ { OFDM, 1500, 0x00, (0x80| 3), 0 }, 140b032f27cSSam Leffler /* 9 Mb */ { OFDM, 2250, 0x00, 4, 0 }, 141b032f27cSSam Leffler /* 12 Mb */ { OFDM, 3000, 0x00, (0x80| 6), 2 }, 142b032f27cSSam Leffler /* 18 Mb */ { OFDM, 4500, 0x00, 9, 2 }, 143b032f27cSSam Leffler /* 24 Mb */ { OFDM, 6000, 0x00, (0x80|12), 4 }, 144b032f27cSSam Leffler /* 36 Mb */ { OFDM, 9000, 0x00, 18, 4 }, 145b032f27cSSam Leffler /* 48 Mb */ { OFDM, 12000, 0x00, 24, 4 }, 146b032f27cSSam Leffler /* 54 Mb */ { OFDM, 13500, 0x00, 27, 4 } 147b032f27cSSam Leffler }, 148b032f27cSSam Leffler }; 149b032f27cSSam Leffler 150b032f27cSSam Leffler static struct ieee80211_rate_table ieee80211_turbog_table = { 151b032f27cSSam Leffler 7, /* number of rates */ 152b032f27cSSam Leffler { 0 }, 153b032f27cSSam Leffler { 154b032f27cSSam Leffler /* short ctrl */ 155b032f27cSSam Leffler /* Preamble dot11Rate Rate */ 156b032f27cSSam Leffler /* 6 Mb */ { TURBO, 6000, 0x00, (0x80|12), 0 }, 157b032f27cSSam Leffler /* 12 Mb */ { TURBO, 12000, 0x00, (0x80|24), 1 }, 158b032f27cSSam Leffler /* 18 Mb */ { TURBO, 18000, 0x00, 36, 1 }, 159b032f27cSSam Leffler /* 24 Mb */ { TURBO, 24000, 0x00, (0x80|48), 3 }, 160b032f27cSSam Leffler /* 36 Mb */ { TURBO, 36000, 0x00, 72, 3 }, 161b032f27cSSam Leffler /* 48 Mb */ { TURBO, 48000, 0x00, 96, 3 }, 162b032f27cSSam Leffler /* 54 Mb */ { TURBO, 54000, 0x00, 108, 3 } 163b032f27cSSam Leffler }, 164b032f27cSSam Leffler }; 165b032f27cSSam Leffler 166b032f27cSSam Leffler static struct ieee80211_rate_table ieee80211_turboa_table = { 167b032f27cSSam Leffler 8, /* number of rates */ 168b032f27cSSam Leffler { 0 }, 169b032f27cSSam Leffler { 170b032f27cSSam Leffler /* short ctrl */ 171b032f27cSSam Leffler /* Preamble dot11Rate Rate */ 172b032f27cSSam Leffler /* 6 Mb */ { TURBO, 6000, 0x00, (0x80|12), 0 }, 173b032f27cSSam Leffler /* 9 Mb */ { TURBO, 9000, 0x00, 18, 0 }, 174b032f27cSSam Leffler /* 12 Mb */ { TURBO, 12000, 0x00, (0x80|24), 2 }, 175b032f27cSSam Leffler /* 18 Mb */ { TURBO, 18000, 0x00, 36, 2 }, 176b032f27cSSam Leffler /* 24 Mb */ { TURBO, 24000, 0x00, (0x80|48), 4 }, 177b032f27cSSam Leffler /* 36 Mb */ { TURBO, 36000, 0x00, 72, 4 }, 178b032f27cSSam Leffler /* 48 Mb */ { TURBO, 48000, 0x00, 96, 4 }, 179b032f27cSSam Leffler /* 54 Mb */ { TURBO, 54000, 0x00, 108, 4 } 180b032f27cSSam Leffler }, 181b032f27cSSam Leffler }; 182b032f27cSSam Leffler 183b032f27cSSam Leffler #undef OFDM 184b032f27cSSam Leffler #undef CCK 185b032f27cSSam Leffler #undef TURBO 186b032f27cSSam Leffler #undef XR 187b032f27cSSam Leffler 188b032f27cSSam Leffler /* 189b032f27cSSam Leffler * Setup a rate table's reverse lookup table and fill in 190b032f27cSSam Leffler * ack durations. The reverse lookup tables are assumed 191b032f27cSSam Leffler * to be initialized to zero (or at least the first entry). 192b032f27cSSam Leffler * We use this as a key that indicates whether or not 193b032f27cSSam Leffler * we've previously setup the reverse lookup table. 194b032f27cSSam Leffler * 195b032f27cSSam Leffler * XXX not reentrant, but shouldn't matter 196b032f27cSSam Leffler */ 197b032f27cSSam Leffler static void 198b032f27cSSam Leffler ieee80211_setup_ratetable(struct ieee80211_rate_table *rt) 199b032f27cSSam Leffler { 200b032f27cSSam Leffler #define N(a) (sizeof(a)/sizeof(a[0])) 201b032f27cSSam Leffler #define WLAN_CTRL_FRAME_SIZE \ 202b032f27cSSam Leffler (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN) 203b032f27cSSam Leffler 204b032f27cSSam Leffler int i; 205b032f27cSSam Leffler 206b032f27cSSam Leffler for (i = 0; i < N(rt->rateCodeToIndex); i++) 207b032f27cSSam Leffler rt->rateCodeToIndex[i] = (uint8_t) -1; 208b032f27cSSam Leffler for (i = 0; i < rt->rateCount; i++) { 209b032f27cSSam Leffler uint8_t code = rt->info[i].dot11Rate; 210b032f27cSSam Leffler uint8_t cix = rt->info[i].ctlRateIndex; 211b032f27cSSam Leffler uint8_t ctl_rate = rt->info[cix].dot11Rate; 212b032f27cSSam Leffler 213b032f27cSSam Leffler rt->rateCodeToIndex[code] = i; 214b032f27cSSam Leffler if (code & IEEE80211_RATE_BASIC) { 215b032f27cSSam Leffler /* 216b032f27cSSam Leffler * Map w/o basic rate bit too. 217b032f27cSSam Leffler */ 218b032f27cSSam Leffler code &= IEEE80211_RATE_VAL; 219b032f27cSSam Leffler rt->rateCodeToIndex[code] = i; 220b032f27cSSam Leffler } 221b032f27cSSam Leffler 222b032f27cSSam Leffler /* 223b032f27cSSam Leffler * XXX for 11g the control rate to use for 5.5 and 11 Mb/s 224b032f27cSSam Leffler * depends on whether they are marked as basic rates; 225b032f27cSSam Leffler * the static tables are setup with an 11b-compatible 226b032f27cSSam Leffler * 2Mb/s rate which will work but is suboptimal 227b032f27cSSam Leffler * 228b032f27cSSam Leffler * NB: Control rate is always less than or equal to the 229b032f27cSSam Leffler * current rate, so control rate's reverse lookup entry 230b032f27cSSam Leffler * has been installed and following call is safe. 231b032f27cSSam Leffler */ 232b032f27cSSam Leffler rt->info[i].lpAckDuration = ieee80211_compute_duration(rt, 233b032f27cSSam Leffler WLAN_CTRL_FRAME_SIZE, ctl_rate, 0); 234b032f27cSSam Leffler rt->info[i].spAckDuration = ieee80211_compute_duration(rt, 235b032f27cSSam Leffler WLAN_CTRL_FRAME_SIZE, ctl_rate, IEEE80211_F_SHPREAMBLE); 236b032f27cSSam Leffler } 237b032f27cSSam Leffler 238b032f27cSSam Leffler #undef WLAN_CTRL_FRAME_SIZE 239b032f27cSSam Leffler #undef N 240b032f27cSSam Leffler } 241b032f27cSSam Leffler 242b032f27cSSam Leffler /* Setup all rate tables */ 243b032f27cSSam Leffler static void 244b032f27cSSam Leffler ieee80211_phy_init(void) 245b032f27cSSam Leffler { 246b032f27cSSam Leffler #define N(arr) (int)(sizeof(arr) / sizeof(arr[0])) 247b032f27cSSam Leffler static struct ieee80211_rate_table * const ratetables[] = { 248b032f27cSSam Leffler &ieee80211_half_table, 249b032f27cSSam Leffler &ieee80211_quarter_table, 250b032f27cSSam Leffler &ieee80211_11a_table, 251b032f27cSSam Leffler &ieee80211_11g_table, 252b032f27cSSam Leffler &ieee80211_turbog_table, 253b032f27cSSam Leffler &ieee80211_turboa_table, 254b032f27cSSam Leffler &ieee80211_turboa_table, 255b032f27cSSam Leffler &ieee80211_11a_table, 256b032f27cSSam Leffler &ieee80211_11g_table, 257b032f27cSSam Leffler &ieee80211_11b_table 258b032f27cSSam Leffler }; 259b032f27cSSam Leffler int i; 260b032f27cSSam Leffler 261b032f27cSSam Leffler for (i = 0; i < N(ratetables); ++i) 262b032f27cSSam Leffler ieee80211_setup_ratetable(ratetables[i]); 263b032f27cSSam Leffler 264b032f27cSSam Leffler #undef N 265b032f27cSSam Leffler } 266b032f27cSSam Leffler SYSINIT(wlan_phy, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_phy_init, NULL); 267b032f27cSSam Leffler 268b032f27cSSam Leffler const struct ieee80211_rate_table * 269b032f27cSSam Leffler ieee80211_get_ratetable(struct ieee80211_channel *c) 270b032f27cSSam Leffler { 271b032f27cSSam Leffler const struct ieee80211_rate_table *rt; 272b032f27cSSam Leffler 273b032f27cSSam Leffler /* XXX HT */ 274b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HALF(c)) 275b032f27cSSam Leffler rt = &ieee80211_half_table; 276b032f27cSSam Leffler else if (IEEE80211_IS_CHAN_QUARTER(c)) 277b032f27cSSam Leffler rt = &ieee80211_quarter_table; 278b032f27cSSam Leffler else if (IEEE80211_IS_CHAN_HTA(c)) 279b032f27cSSam Leffler rt = &ieee80211_11a_table; /* XXX */ 280b032f27cSSam Leffler else if (IEEE80211_IS_CHAN_HTG(c)) 281b032f27cSSam Leffler rt = &ieee80211_11g_table; /* XXX */ 282b032f27cSSam Leffler else if (IEEE80211_IS_CHAN_108G(c)) 283b032f27cSSam Leffler rt = &ieee80211_turbog_table; 284b032f27cSSam Leffler else if (IEEE80211_IS_CHAN_ST(c)) 285b032f27cSSam Leffler rt = &ieee80211_turboa_table; 286b032f27cSSam Leffler else if (IEEE80211_IS_CHAN_TURBO(c)) 287b032f27cSSam Leffler rt = &ieee80211_turboa_table; 288b032f27cSSam Leffler else if (IEEE80211_IS_CHAN_A(c)) 289b032f27cSSam Leffler rt = &ieee80211_11a_table; 290b032f27cSSam Leffler else if (IEEE80211_IS_CHAN_ANYG(c)) 291b032f27cSSam Leffler rt = &ieee80211_11g_table; 292b032f27cSSam Leffler else if (IEEE80211_IS_CHAN_B(c)) 293b032f27cSSam Leffler rt = &ieee80211_11b_table; 294b032f27cSSam Leffler else { 295b032f27cSSam Leffler /* NB: should not get here */ 296b032f27cSSam Leffler panic("%s: no rate table for channel; freq %u flags 0x%x\n", 297b032f27cSSam Leffler __func__, c->ic_freq, c->ic_flags); 298b032f27cSSam Leffler } 299b032f27cSSam Leffler return rt; 300b032f27cSSam Leffler } 301b032f27cSSam Leffler 302b032f27cSSam Leffler /* 303b032f27cSSam Leffler * Convert PLCP signal/rate field to 802.11 rate (.5Mbits/s) 304b032f27cSSam Leffler * 305b032f27cSSam Leffler * Note we do no parameter checking; this routine is mainly 306b032f27cSSam Leffler * used to derive an 802.11 rate for constructing radiotap 307b032f27cSSam Leffler * header data for rx frames. 308b032f27cSSam Leffler * 309b032f27cSSam Leffler * XXX might be a candidate for inline 310b032f27cSSam Leffler */ 311b032f27cSSam Leffler uint8_t 3128215d906SSam Leffler ieee80211_plcp2rate(uint8_t plcp, enum ieee80211_phytype type) 313b032f27cSSam Leffler { 3148215d906SSam Leffler if (type == IEEE80211_T_OFDM) { 315b032f27cSSam Leffler static const uint8_t ofdm_plcp2rate[16] = { 316b032f27cSSam Leffler [0xb] = 12, 317b032f27cSSam Leffler [0xf] = 18, 318b032f27cSSam Leffler [0xa] = 24, 319b032f27cSSam Leffler [0xe] = 36, 320b032f27cSSam Leffler [0x9] = 48, 321b032f27cSSam Leffler [0xd] = 72, 322b032f27cSSam Leffler [0x8] = 96, 323b032f27cSSam Leffler [0xc] = 108 324b032f27cSSam Leffler }; 325b032f27cSSam Leffler return ofdm_plcp2rate[plcp & 0xf]; 3268215d906SSam Leffler } 3278215d906SSam Leffler if (type == IEEE80211_T_CCK) { 328b032f27cSSam Leffler static const uint8_t cck_plcp2rate[16] = { 329b032f27cSSam Leffler [0xa] = 2, /* 0x0a */ 330b032f27cSSam Leffler [0x4] = 4, /* 0x14 */ 331b032f27cSSam Leffler [0x7] = 11, /* 0x37 */ 332b032f27cSSam Leffler [0xe] = 22, /* 0x6e */ 333b032f27cSSam Leffler [0xc] = 44, /* 0xdc , actually PBCC */ 334b032f27cSSam Leffler }; 335b032f27cSSam Leffler return cck_plcp2rate[plcp & 0xf]; 336b032f27cSSam Leffler } 3378215d906SSam Leffler return 0; 338b032f27cSSam Leffler } 339b032f27cSSam Leffler 340b032f27cSSam Leffler /* 341b032f27cSSam Leffler * Covert 802.11 rate to PLCP signal. 342b032f27cSSam Leffler */ 343b032f27cSSam Leffler uint8_t 3448215d906SSam Leffler ieee80211_rate2plcp(int rate, enum ieee80211_phytype type) 345b032f27cSSam Leffler { 3468215d906SSam Leffler /* XXX ignore type for now since rates are unique */ 347b032f27cSSam Leffler switch (rate) { 348b032f27cSSam Leffler /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */ 349b032f27cSSam Leffler case 12: return 0xb; 350b032f27cSSam Leffler case 18: return 0xf; 351b032f27cSSam Leffler case 24: return 0xa; 352b032f27cSSam Leffler case 36: return 0xe; 353b032f27cSSam Leffler case 48: return 0x9; 354b032f27cSSam Leffler case 72: return 0xd; 355b032f27cSSam Leffler case 96: return 0x8; 356b032f27cSSam Leffler case 108: return 0xc; 3578215d906SSam Leffler /* CCK rates (IEEE Std 802.11b-1999 page 15, subclause 18.2.3.3) */ 3588215d906SSam Leffler case 2: return 10; 3598215d906SSam Leffler case 4: return 20; 3608215d906SSam Leffler case 11: return 55; 3618215d906SSam Leffler case 22: return 110; 3628215d906SSam Leffler /* IEEE Std 802.11g-2003 page 19, subclause 19.3.2.1 */ 3638215d906SSam Leffler case 44: return 220; 364b032f27cSSam Leffler } 3658215d906SSam Leffler return 0; /* XXX unsupported/unknown rate */ 366b032f27cSSam Leffler } 3678215d906SSam Leffler 368b032f27cSSam Leffler /* 369b032f27cSSam Leffler * Compute the time to transmit a frame of length frameLen bytes 370b032f27cSSam Leffler * using the specified rate, phy, and short preamble setting. 371b032f27cSSam Leffler * SIFS is included. 372b032f27cSSam Leffler */ 373b032f27cSSam Leffler uint16_t 374b032f27cSSam Leffler ieee80211_compute_duration(const struct ieee80211_rate_table *rt, 375b032f27cSSam Leffler uint32_t frameLen, uint16_t rate, int isShortPreamble) 376b032f27cSSam Leffler { 377b032f27cSSam Leffler uint8_t rix = rt->rateCodeToIndex[rate]; 378b032f27cSSam Leffler uint32_t bitsPerSymbol, numBits, numSymbols, phyTime, txTime; 379b032f27cSSam Leffler uint32_t kbps; 380b032f27cSSam Leffler 381b032f27cSSam Leffler KASSERT(rix != (uint8_t)-1, ("rate %d has no info", rate)); 382b032f27cSSam Leffler kbps = rt->info[rix].rateKbps; 383b032f27cSSam Leffler if (kbps == 0) /* XXX bandaid for channel changes */ 384b032f27cSSam Leffler return 0; 385b032f27cSSam Leffler 386b032f27cSSam Leffler switch (rt->info[rix].phy) { 387b032f27cSSam Leffler case IEEE80211_T_CCK: 388b032f27cSSam Leffler #define CCK_SIFS_TIME 10 389b032f27cSSam Leffler #define CCK_PREAMBLE_BITS 144 390b032f27cSSam Leffler #define CCK_PLCP_BITS 48 391b032f27cSSam Leffler phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; 392b032f27cSSam Leffler if (isShortPreamble && rt->info[rix].shortPreamble) 393b032f27cSSam Leffler phyTime >>= 1; 394b032f27cSSam Leffler numBits = frameLen << 3; 395b032f27cSSam Leffler txTime = CCK_SIFS_TIME + phyTime 396b032f27cSSam Leffler + ((numBits * 1000)/kbps); 397b032f27cSSam Leffler break; 398b032f27cSSam Leffler #undef CCK_SIFS_TIME 399b032f27cSSam Leffler #undef CCK_PREAMBLE_BITS 400b032f27cSSam Leffler #undef CCK_PLCP_BITS 401b032f27cSSam Leffler 402b032f27cSSam Leffler case IEEE80211_T_OFDM: 403b032f27cSSam Leffler #define OFDM_SIFS_TIME 16 404b032f27cSSam Leffler #define OFDM_PREAMBLE_TIME 20 405b032f27cSSam Leffler #define OFDM_PLCP_BITS 22 406b032f27cSSam Leffler #define OFDM_SYMBOL_TIME 4 407b032f27cSSam Leffler 408b032f27cSSam Leffler #define OFDM_SIFS_TIME_HALF 32 409b032f27cSSam Leffler #define OFDM_PREAMBLE_TIME_HALF 40 410b032f27cSSam Leffler #define OFDM_PLCP_BITS_HALF 22 411b032f27cSSam Leffler #define OFDM_SYMBOL_TIME_HALF 8 412b032f27cSSam Leffler 413b032f27cSSam Leffler #define OFDM_SIFS_TIME_QUARTER 64 414b032f27cSSam Leffler #define OFDM_PREAMBLE_TIME_QUARTER 80 415b032f27cSSam Leffler #define OFDM_PLCP_BITS_QUARTER 22 416b032f27cSSam Leffler #define OFDM_SYMBOL_TIME_QUARTER 16 417b032f27cSSam Leffler if (rt == &ieee80211_half_table) { 418b032f27cSSam Leffler bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; 419b032f27cSSam Leffler KASSERT(bitsPerSymbol != 0, ("1/2 rate bps")); 420b032f27cSSam Leffler 421b032f27cSSam Leffler numBits = OFDM_PLCP_BITS + (frameLen << 3); 422b032f27cSSam Leffler numSymbols = howmany(numBits, bitsPerSymbol); 423b032f27cSSam Leffler txTime = OFDM_SIFS_TIME_QUARTER 424b032f27cSSam Leffler + OFDM_PREAMBLE_TIME_QUARTER 425b032f27cSSam Leffler + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); 426b032f27cSSam Leffler } else if (rt == &ieee80211_quarter_table) { 427b032f27cSSam Leffler bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; 428b032f27cSSam Leffler KASSERT(bitsPerSymbol != 0, ("1/4 rate bps")); 429b032f27cSSam Leffler 430b032f27cSSam Leffler numBits = OFDM_PLCP_BITS + (frameLen << 3); 431b032f27cSSam Leffler numSymbols = howmany(numBits, bitsPerSymbol); 432b032f27cSSam Leffler txTime = OFDM_SIFS_TIME_HALF 433b032f27cSSam Leffler + OFDM_PREAMBLE_TIME_HALF 434b032f27cSSam Leffler + (numSymbols * OFDM_SYMBOL_TIME_HALF); 435b032f27cSSam Leffler } else { /* full rate channel */ 436b032f27cSSam Leffler bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; 437b032f27cSSam Leffler KASSERT(bitsPerSymbol != 0, ("full rate bps")); 438b032f27cSSam Leffler 439b032f27cSSam Leffler numBits = OFDM_PLCP_BITS + (frameLen << 3); 440b032f27cSSam Leffler numSymbols = howmany(numBits, bitsPerSymbol); 441b032f27cSSam Leffler txTime = OFDM_SIFS_TIME 442b032f27cSSam Leffler + OFDM_PREAMBLE_TIME 443b032f27cSSam Leffler + (numSymbols * OFDM_SYMBOL_TIME); 444b032f27cSSam Leffler } 445b032f27cSSam Leffler break; 446b032f27cSSam Leffler 447b032f27cSSam Leffler #undef OFDM_SIFS_TIME 448b032f27cSSam Leffler #undef OFDM_PREAMBLE_TIME 449b032f27cSSam Leffler #undef OFDM_PLCP_BITS 450b032f27cSSam Leffler #undef OFDM_SYMBOL_TIME 451b032f27cSSam Leffler 452b032f27cSSam Leffler case IEEE80211_T_TURBO: 453b032f27cSSam Leffler #define TURBO_SIFS_TIME 8 454b032f27cSSam Leffler #define TURBO_PREAMBLE_TIME 14 455b032f27cSSam Leffler #define TURBO_PLCP_BITS 22 456b032f27cSSam Leffler #define TURBO_SYMBOL_TIME 4 457b032f27cSSam Leffler /* we still save OFDM rates in kbps - so double them */ 458b032f27cSSam Leffler bitsPerSymbol = ((kbps << 1) * TURBO_SYMBOL_TIME) / 1000; 459b032f27cSSam Leffler KASSERT(bitsPerSymbol != 0, ("turbo bps")); 460b032f27cSSam Leffler 461b032f27cSSam Leffler numBits = TURBO_PLCP_BITS + (frameLen << 3); 462b032f27cSSam Leffler numSymbols = howmany(numBits, bitsPerSymbol); 463b032f27cSSam Leffler txTime = TURBO_SIFS_TIME + TURBO_PREAMBLE_TIME 464b032f27cSSam Leffler + (numSymbols * TURBO_SYMBOL_TIME); 465b032f27cSSam Leffler break; 466b032f27cSSam Leffler #undef TURBO_SIFS_TIME 467b032f27cSSam Leffler #undef TURBO_PREAMBLE_TIME 468b032f27cSSam Leffler #undef TURBO_PLCP_BITS 469b032f27cSSam Leffler #undef TURBO_SYMBOL_TIME 470b032f27cSSam Leffler 471b032f27cSSam Leffler default: 472b032f27cSSam Leffler panic("%s: unknown phy %u (rate %u)\n", __func__, 473b032f27cSSam Leffler rt->info[rix].phy, rate); 474b032f27cSSam Leffler break; 475b032f27cSSam Leffler } 476b032f27cSSam Leffler return txTime; 477b032f27cSSam Leffler } 478