ieee80211_superg.c revision 190451
1/*- 2 * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_superg.c 190451 2009-03-26 19:13:11Z sam $"); 28 29#include "opt_wlan.h" 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/mbuf.h> 34#include <sys/kernel.h> 35#include <sys/endian.h> 36 37#include <sys/socket.h> 38 39#include <net/bpf.h> 40#include <net/ethernet.h> 41#include <net/if.h> 42#include <net/if_llc.h> 43#include <net/if_media.h> 44 45#include <net80211/ieee80211_var.h> 46#include <net80211/ieee80211_input.h> 47#include <net80211/ieee80211_phy.h> 48#include <net80211/ieee80211_superg.h> 49 50#define ETHER_HEADER_COPY(dst, src) \ 51 memcpy(dst, src, sizeof(struct ether_header)) 52 53void 54ieee80211_superg_attach(struct ieee80211com *ic) 55{ 56} 57 58void 59ieee80211_superg_detach(struct ieee80211com *ic) 60{ 61} 62 63void 64ieee80211_superg_vattach(struct ieee80211vap *vap) 65{ 66 if (vap->iv_caps & IEEE80211_C_FF) 67 vap->iv_flags |= IEEE80211_F_FF; 68 /* NB: we only implement sta mode */ 69 if (vap->iv_opmode == IEEE80211_M_STA && 70 (vap->iv_caps & IEEE80211_C_TURBOP)) 71 vap->iv_flags |= IEEE80211_F_TURBOP; 72} 73 74void 75ieee80211_superg_vdetach(struct ieee80211vap *vap) 76{ 77} 78 79#define ATH_OUI_BYTES 0x00, 0x03, 0x7f 80/* 81 * Add a WME information element to a frame. 82 */ 83uint8_t * 84ieee80211_add_ath(uint8_t *frm, uint8_t caps, ieee80211_keyix defkeyix) 85{ 86 static const struct ieee80211_ath_ie info = { 87 .ath_id = IEEE80211_ELEMID_VENDOR, 88 .ath_len = sizeof(struct ieee80211_ath_ie) - 2, 89 .ath_oui = { ATH_OUI_BYTES }, 90 .ath_oui_type = ATH_OUI_TYPE, 91 .ath_oui_subtype= ATH_OUI_SUBTYPE, 92 .ath_version = ATH_OUI_VERSION, 93 }; 94 struct ieee80211_ath_ie *ath = (struct ieee80211_ath_ie *) frm; 95 96 memcpy(frm, &info, sizeof(info)); 97 ath->ath_capability = caps; 98 if (defkeyix != IEEE80211_KEYIX_NONE) { 99 ath->ath_defkeyix[0] = (defkeyix & 0xff); 100 ath->ath_defkeyix[1] = ((defkeyix >> 8) & 0xff); 101 } else { 102 ath->ath_defkeyix[0] = 0xff; 103 ath->ath_defkeyix[1] = 0x7f; 104 } 105 return frm + sizeof(info); 106} 107#undef ATH_OUI_BYTES 108 109uint8_t * 110ieee80211_add_athcaps(uint8_t *frm, const struct ieee80211_node *bss) 111{ 112 const struct ieee80211vap *vap = bss->ni_vap; 113 114 return ieee80211_add_ath(frm, 115 vap->iv_flags & IEEE80211_F_ATHEROS, 116 ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 117 bss->ni_authmode != IEEE80211_AUTH_8021X) ? 118 vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 119} 120 121void 122ieee80211_parse_ath(struct ieee80211_node *ni, uint8_t *ie) 123{ 124 const struct ieee80211_ath_ie *ath = 125 (const struct ieee80211_ath_ie *) ie; 126 127 ni->ni_ath_flags = ath->ath_capability; 128 ni->ni_ath_defkeyix = LE_READ_2(&ath->ath_defkeyix); 129} 130 131int 132ieee80211_parse_athparams(struct ieee80211_node *ni, uint8_t *frm, 133 const struct ieee80211_frame *wh) 134{ 135 struct ieee80211vap *vap = ni->ni_vap; 136 const struct ieee80211_ath_ie *ath; 137 u_int len = frm[1]; 138 int capschanged; 139 uint16_t defkeyix; 140 141 if (len < sizeof(struct ieee80211_ath_ie)-2) { 142 IEEE80211_DISCARD_IE(vap, 143 IEEE80211_MSG_ELEMID | IEEE80211_MSG_SUPERG, 144 wh, "Atheros", "too short, len %u", len); 145 return -1; 146 } 147 ath = (const struct ieee80211_ath_ie *)frm; 148 capschanged = (ni->ni_ath_flags != ath->ath_capability); 149 defkeyix = LE_READ_2(ath->ath_defkeyix); 150 if (capschanged || defkeyix != ni->ni_ath_defkeyix) { 151 ni->ni_ath_flags = ath->ath_capability; 152 ni->ni_ath_defkeyix = defkeyix; 153 IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni, 154 "ath ie change: new caps 0x%x defkeyix 0x%x", 155 ni->ni_ath_flags, ni->ni_ath_defkeyix); 156 } 157 if (IEEE80211_ATH_CAP(vap, ni, ATHEROS_CAP_TURBO_PRIME)) { 158 uint16_t curflags, newflags; 159 160 /* 161 * Check for turbo mode switch. Calculate flags 162 * for the new mode and effect the switch. 163 */ 164 newflags = curflags = vap->iv_ic->ic_bsschan->ic_flags; 165 /* NB: BOOST is not in ic_flags, so get it from the ie */ 166 if (ath->ath_capability & ATHEROS_CAP_BOOST) 167 newflags |= IEEE80211_CHAN_TURBO; 168 else 169 newflags &= ~IEEE80211_CHAN_TURBO; 170 if (newflags != curflags) 171 ieee80211_dturbo_switch(vap, newflags); 172 } 173 return capschanged; 174} 175 176/* 177 * Decap the encapsulated frame pair and dispatch the first 178 * for delivery. The second frame is returned for delivery 179 * via the normal path. 180 */ 181struct mbuf * 182ieee80211_ff_decap(struct ieee80211_node *ni, struct mbuf *m) 183{ 184#define FF_LLC_SIZE (sizeof(struct ether_header) + sizeof(struct llc)) 185#define MS(x,f) (((x) & f) >> f##_S) 186 struct ieee80211vap *vap = ni->ni_vap; 187 struct llc *llc; 188 uint32_t ath; 189 struct mbuf *n; 190 int framelen; 191 192 /* NB: we assume caller does this check for us */ 193 KASSERT(IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF), 194 ("ff not negotiated")); 195 /* 196 * Check for fast-frame tunnel encapsulation. 197 */ 198 if (m->m_pkthdr.len < 3*FF_LLC_SIZE) 199 return m; 200 if (m->m_len < FF_LLC_SIZE && 201 (m = m_pullup(m, FF_LLC_SIZE)) == NULL) { 202 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 203 ni->ni_macaddr, "fast-frame", 204 "%s", "m_pullup(llc) failed"); 205 vap->iv_stats.is_rx_tooshort++; 206 return NULL; 207 } 208 llc = (struct llc *)(mtod(m, uint8_t *) + 209 sizeof(struct ether_header)); 210 if (llc->llc_snap.ether_type != htons(ATH_FF_ETH_TYPE)) 211 return m; 212 m_adj(m, FF_LLC_SIZE); 213 m_copydata(m, 0, sizeof(uint32_t), (caddr_t) &ath); 214 if (MS(ath, ATH_FF_PROTO) != ATH_FF_PROTO_L2TUNNEL) { 215 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 216 ni->ni_macaddr, "fast-frame", 217 "unsupport tunnel protocol, header 0x%x", ath); 218 vap->iv_stats.is_ff_badhdr++; 219 m_freem(m); 220 return NULL; 221 } 222 /* NB: skip header and alignment padding */ 223 m_adj(m, roundup(sizeof(uint32_t) - 2, 4) + 2); 224 225 vap->iv_stats.is_ff_decap++; 226 227 /* 228 * Decap the first frame, bust it apart from the 229 * second and deliver; then decap the second frame 230 * and return it to the caller for normal delivery. 231 */ 232 m = ieee80211_decap1(m, &framelen); 233 if (m == NULL) { 234 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 235 ni->ni_macaddr, "fast-frame", "%s", "first decap failed"); 236 vap->iv_stats.is_ff_tooshort++; 237 return NULL; 238 } 239 n = m_split(m, framelen, M_NOWAIT); 240 if (n == NULL) { 241 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 242 ni->ni_macaddr, "fast-frame", 243 "%s", "unable to split encapsulated frames"); 244 vap->iv_stats.is_ff_split++; 245 m_freem(m); /* NB: must reclaim */ 246 return NULL; 247 } 248 /* XXX not right for WDS */ 249 vap->iv_deliver_data(vap, ni, m); /* 1st of pair */ 250 251 /* 252 * Decap second frame. 253 */ 254 m_adj(n, roundup2(framelen, 4) - framelen); /* padding */ 255 n = ieee80211_decap1(n, &framelen); 256 if (n == NULL) { 257 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 258 ni->ni_macaddr, "fast-frame", "%s", "second decap failed"); 259 vap->iv_stats.is_ff_tooshort++; 260 } 261 /* XXX verify framelen against mbuf contents */ 262 return n; /* 2nd delivered by caller */ 263#undef MS 264#undef FF_LLC_SIZE 265} 266 267/* 268 * Do Ethernet-LLC encapsulation for each payload in a fast frame 269 * tunnel encapsulation. The frame is assumed to have an Ethernet 270 * header at the front that must be stripped before prepending the 271 * LLC followed by the Ethernet header passed in (with an Ethernet 272 * type that specifies the payload size). 273 */ 274static struct mbuf * 275ff_encap1(struct ieee80211vap *vap, struct mbuf *m, 276 const struct ether_header *eh) 277{ 278 struct llc *llc; 279 uint16_t payload; 280 281 /* XXX optimize by combining m_adj+M_PREPEND */ 282 m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 283 llc = mtod(m, struct llc *); 284 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 285 llc->llc_control = LLC_UI; 286 llc->llc_snap.org_code[0] = 0; 287 llc->llc_snap.org_code[1] = 0; 288 llc->llc_snap.org_code[2] = 0; 289 llc->llc_snap.ether_type = eh->ether_type; 290 payload = m->m_pkthdr.len; /* NB: w/o Ethernet header */ 291 292 M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); 293 if (m == NULL) { /* XXX cannot happen */ 294 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 295 "%s: no space for ether_header\n", __func__); 296 vap->iv_stats.is_tx_nobuf++; 297 return NULL; 298 } 299 ETHER_HEADER_COPY(mtod(m, void *), eh); 300 mtod(m, struct ether_header *)->ether_type = htons(payload); 301 return m; 302} 303 304/* 305 * Fast frame encapsulation. There must be two packets 306 * chained with m_nextpkt. We do header adjustment for 307 * each, add the tunnel encapsulation, and then concatenate 308 * the mbuf chains to form a single frame for transmission. 309 */ 310struct mbuf * 311ieee80211_ff_encap(struct ieee80211vap *vap, struct mbuf *m1, int hdrspace, 312 struct ieee80211_key *key) 313{ 314 struct mbuf *m2; 315 struct ether_header eh1, eh2; 316 struct llc *llc; 317 struct mbuf *m; 318 int pad; 319 320 m2 = m1->m_nextpkt; 321 if (m2 == NULL) { 322 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 323 "%s: only one frame\n", __func__); 324 goto bad; 325 } 326 m1->m_nextpkt = NULL; 327 /* 328 * Include fast frame headers in adjusting header 329 * layout; this allocates space according to what 330 * ff_encap will do. 331 */ 332 m1 = ieee80211_mbuf_adjust(vap, 333 hdrspace + sizeof(struct llc) + sizeof(uint32_t) + 2 + 334 sizeof(struct ether_header), 335 key, m1); 336 if (m1 == NULL) { 337 /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 338 m_freem(m2); 339 goto bad; 340 } 341 342 /* 343 * Copy second frame's Ethernet header out of line 344 * and adjust for encapsulation headers. Note that 345 * we make room for padding in case there isn't room 346 * at the end of first frame. 347 */ 348 KASSERT(m2->m_len >= sizeof(eh2), ("no ethernet header!")); 349 ETHER_HEADER_COPY(&eh2, mtod(m2, caddr_t)); 350 m2 = ieee80211_mbuf_adjust(vap, 351 ATH_FF_MAX_HDR_PAD + sizeof(struct ether_header), 352 NULL, m2); 353 if (m2 == NULL) { 354 /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 355 goto bad; 356 } 357 358 /* 359 * Now do tunnel encapsulation. First, each 360 * frame gets a standard encapsulation. 361 */ 362 m1 = ff_encap1(vap, m1, &eh1); 363 if (m1 == NULL) 364 goto bad; 365 m2 = ff_encap1(vap, m2, &eh2); 366 if (m2 == NULL) 367 goto bad; 368 369 /* 370 * Pad leading frame to a 4-byte boundary. If there 371 * is space at the end of the first frame, put it 372 * there; otherwise prepend to the front of the second 373 * frame. We know doing the second will always work 374 * because we reserve space above. We prefer appending 375 * as this typically has better DMA alignment properties. 376 */ 377 for (m = m1; m->m_next != NULL; m = m->m_next) 378 ; 379 pad = roundup2(m1->m_pkthdr.len, 4) - m1->m_pkthdr.len; 380 if (pad) { 381 if (M_TRAILINGSPACE(m) < pad) { /* prepend to second */ 382 m2->m_data -= pad; 383 m2->m_len += pad; 384 m2->m_pkthdr.len += pad; 385 } else { /* append to first */ 386 m->m_len += pad; 387 m1->m_pkthdr.len += pad; 388 } 389 } 390 391 /* 392 * Now, stick 'em together and prepend the tunnel headers; 393 * first the Atheros tunnel header (all zero for now) and 394 * then a special fast frame LLC. 395 * 396 * XXX optimize by prepending together 397 */ 398 m->m_next = m2; /* NB: last mbuf from above */ 399 m1->m_pkthdr.len += m2->m_pkthdr.len; 400 M_PREPEND(m1, sizeof(uint32_t)+2, M_DONTWAIT); 401 if (m1 == NULL) { /* XXX cannot happen */ 402 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 403 "%s: no space for tunnel header\n", __func__); 404 vap->iv_stats.is_tx_nobuf++; 405 return NULL; 406 } 407 memset(mtod(m1, void *), 0, sizeof(uint32_t)+2); 408 409 M_PREPEND(m1, sizeof(struct llc), M_DONTWAIT); 410 if (m1 == NULL) { /* XXX cannot happen */ 411 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 412 "%s: no space for llc header\n", __func__); 413 vap->iv_stats.is_tx_nobuf++; 414 return NULL; 415 } 416 llc = mtod(m1, struct llc *); 417 llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 418 llc->llc_control = LLC_UI; 419 llc->llc_snap.org_code[0] = ATH_FF_SNAP_ORGCODE_0; 420 llc->llc_snap.org_code[1] = ATH_FF_SNAP_ORGCODE_1; 421 llc->llc_snap.org_code[2] = ATH_FF_SNAP_ORGCODE_2; 422 llc->llc_snap.ether_type = htons(ATH_FF_ETH_TYPE); 423 424 vap->iv_stats.is_ff_encap++; 425 426 return m1; 427bad: 428 if (m1 != NULL) 429 m_freem(m1); 430 if (m2 != NULL) 431 m_freem(m2); 432 return NULL; 433} 434 435/* 436 * Switch between turbo and non-turbo operating modes. 437 * Use the specified channel flags to locate the new 438 * channel, update 802.11 state, and then call back into 439 * the driver to effect the change. 440 */ 441void 442ieee80211_dturbo_switch(struct ieee80211vap *vap, int newflags) 443{ 444 struct ieee80211com *ic = vap->iv_ic; 445 struct ieee80211_channel *chan; 446 447 chan = ieee80211_find_channel(ic, ic->ic_bsschan->ic_freq, newflags); 448 if (chan == NULL) { /* XXX should not happen */ 449 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 450 "%s: no channel with freq %u flags 0x%x\n", 451 __func__, ic->ic_bsschan->ic_freq, newflags); 452 return; 453 } 454 455 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 456 "%s: %s -> %s (freq %u flags 0x%x)\n", __func__, 457 ieee80211_phymode_name[ieee80211_chan2mode(ic->ic_bsschan)], 458 ieee80211_phymode_name[ieee80211_chan2mode(chan)], 459 chan->ic_freq, chan->ic_flags); 460 461 ic->ic_bsschan = chan; 462 ic->ic_prevchan = ic->ic_curchan; 463 ic->ic_curchan = chan; 464 ic->ic_set_channel(ic); 465 /* NB: do not need to reset ERP state 'cuz we're in sta mode */ 466} 467 468/* 469 * Return the current ``state'' of an Atheros capbility. 470 * If associated in station mode report the negotiated 471 * setting. Otherwise report the current setting. 472 */ 473static int 474getathcap(struct ieee80211vap *vap, int cap) 475{ 476 if (vap->iv_opmode == IEEE80211_M_STA && 477 vap->iv_state == IEEE80211_S_RUN) 478 return IEEE80211_ATH_CAP(vap, vap->iv_bss, cap) != 0; 479 else 480 return (vap->iv_flags & cap) != 0; 481} 482 483static int 484superg_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 485{ 486 switch (ireq->i_type) { 487 case IEEE80211_IOC_FF: 488 ireq->i_val = getathcap(vap, IEEE80211_F_FF); 489 break; 490 case IEEE80211_IOC_TURBOP: 491 ireq->i_val = getathcap(vap, IEEE80211_F_TURBOP); 492 break; 493 default: 494 return ENOSYS; 495 } 496 return 0; 497} 498IEEE80211_IOCTL_GET(superg, superg_ioctl_get80211); 499 500static int 501superg_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 502{ 503 switch (ireq->i_type) { 504 case IEEE80211_IOC_FF: 505 if (ireq->i_val) { 506 if ((vap->iv_caps & IEEE80211_C_FF) == 0) 507 return EOPNOTSUPP; 508 vap->iv_flags |= IEEE80211_F_FF; 509 } else 510 vap->iv_flags &= ~IEEE80211_F_FF; 511 return ERESTART; 512 case IEEE80211_IOC_TURBOP: 513 if (ireq->i_val) { 514 if ((vap->iv_caps & IEEE80211_C_TURBOP) == 0) 515 return EOPNOTSUPP; 516 vap->iv_flags |= IEEE80211_F_TURBOP; 517 } else 518 vap->iv_flags &= ~IEEE80211_F_TURBOP; 519 return ENETRESET; 520 default: 521 return ENOSYS; 522 } 523 return 0; 524} 525IEEE80211_IOCTL_SET(superg, superg_ioctl_set80211); 526