| 1 | /*- |
| 2 | * Copyright (c) 2007-2008 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 | * $FreeBSD: head/sys/net80211/ieee80211_sta.c 203422 2010-02-03 10:07:43Z rpaulo $ |
| 26 | */ |
| 27 | |
| 28 | /* |
| 29 | * IEEE 802.11 Station mode support. |
| 30 | */ |
| 31 | #include "opt_inet.h" |
| 32 | #include "opt_wlan.h" |
| 33 | |
| 34 | #include <sys/param.h> |
| 35 | #include <sys/systm.h> |
| 36 | #include <sys/mbuf.h> |
| 37 | #include <sys/malloc.h> |
| 38 | #include <sys/kernel.h> |
| 39 | |
| 40 | #include <sys/socket.h> |
| 41 | #include <sys/sockio.h> |
| 42 | #include <sys/endian.h> |
| 43 | #include <sys/errno.h> |
| 44 | #include <sys/proc.h> |
| 45 | #include <sys/sysctl.h> |
| 46 | |
| 47 | #include <net/if.h> |
| 48 | #include <net/if_media.h> |
| 49 | #include <net/if_llc.h> |
| 50 | #include <net/ethernet.h> |
| 51 | #include <net/route.h> |
| 52 | |
| 53 | #include <net/bpf.h> |
| 54 | |
| 55 | #include <netproto/802_11/ieee80211_var.h> |
| 56 | #include <netproto/802_11/ieee80211_sta.h> |
| 57 | #include <netproto/802_11/ieee80211_input.h> |
| 58 | #ifdef IEEE80211_SUPPORT_SUPERG |
| 59 | #include <netproto/802_11/ieee80211_superg.h> |
| 60 | #endif |
| 61 | |
| 62 | #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) |
| 63 | |
| 64 | static void sta_vattach(struct ieee80211vap *); |
| 65 | static void sta_beacon_miss(struct ieee80211vap *); |
| 66 | static int sta_newstate(struct ieee80211vap *, enum ieee80211_state, int); |
| 67 | static int sta_input(struct ieee80211_node *, struct mbuf *, int, int); |
| 68 | static void sta_recv_mgmt(struct ieee80211_node *, struct mbuf *, |
| 69 | int subtype, int rssi, int nf); |
| 70 | static void sta_recv_ctl(struct ieee80211_node *, struct mbuf *, int subtype); |
| 71 | |
| 72 | void |
| 73 | ieee80211_sta_attach(struct ieee80211com *ic) |
| 74 | { |
| 75 | ic->ic_vattach[IEEE80211_M_STA] = sta_vattach; |
| 76 | } |
| 77 | |
| 78 | void |
| 79 | ieee80211_sta_detach(struct ieee80211com *ic) |
| 80 | { |
| 81 | } |
| 82 | |
| 83 | static void |
| 84 | sta_vdetach(struct ieee80211vap *vap) |
| 85 | { |
| 86 | } |
| 87 | |
| 88 | static void |
| 89 | sta_vattach(struct ieee80211vap *vap) |
| 90 | { |
| 91 | vap->iv_newstate = sta_newstate; |
| 92 | vap->iv_input = sta_input; |
| 93 | vap->iv_recv_mgmt = sta_recv_mgmt; |
| 94 | vap->iv_recv_ctl = sta_recv_ctl; |
| 95 | vap->iv_opdetach = sta_vdetach; |
| 96 | vap->iv_bmiss = sta_beacon_miss; |
| 97 | } |
| 98 | |
| 99 | /* |
| 100 | * Handle a beacon miss event. The common code filters out |
| 101 | * spurious events that can happen when scanning and/or before |
| 102 | * reaching RUN state. |
| 103 | */ |
| 104 | static void |
| 105 | sta_beacon_miss(struct ieee80211vap *vap) |
| 106 | { |
| 107 | struct ieee80211com *ic = vap->iv_ic; |
| 108 | |
| 109 | KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning")); |
| 110 | KASSERT(vap->iv_state >= IEEE80211_S_RUN, |
| 111 | ("wrong state %s", ieee80211_state_name[vap->iv_state])); |
| 112 | |
| 113 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, |
| 114 | "beacon miss, mode %s state %s\n", |
| 115 | ieee80211_opmode_name[vap->iv_opmode], |
| 116 | ieee80211_state_name[vap->iv_state]); |
| 117 | |
| 118 | if (vap->iv_state == IEEE80211_S_CSA) { |
| 119 | /* |
| 120 | * A Channel Switch is pending; assume we missed the |
| 121 | * beacon that would've completed the process and just |
| 122 | * force the switch. If we made a mistake we'll not |
| 123 | * find the AP on the new channel and fall back to a |
| 124 | * normal scan. |
| 125 | */ |
| 126 | ieee80211_csa_completeswitch(ic); |
| 127 | return; |
| 128 | } |
| 129 | if (++vap->iv_bmiss_count < vap->iv_bmiss_max) { |
| 130 | /* |
| 131 | * Send a directed probe req before falling back to a |
| 132 | * scan; if we receive a response ic_bmiss_count will |
| 133 | * be reset. Some cards mistakenly report beacon miss |
| 134 | * so this avoids the expensive scan if the ap is |
| 135 | * still there. |
| 136 | */ |
| 137 | ieee80211_send_probereq(vap->iv_bss, vap->iv_myaddr, |
| 138 | vap->iv_bss->ni_bssid, vap->iv_bss->ni_bssid, |
| 139 | vap->iv_bss->ni_essid, vap->iv_bss->ni_esslen); |
| 140 | return; |
| 141 | } |
| 142 | vap->iv_bmiss_count = 0; |
| 143 | vap->iv_stats.is_beacon_miss++; |
| 144 | if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) { |
| 145 | #ifdef IEEE80211_SUPPORT_SUPERG |
| 146 | struct ieee80211com *ic = vap->iv_ic; |
| 147 | |
| 148 | /* |
| 149 | * If we receive a beacon miss interrupt when using |
| 150 | * dynamic turbo, attempt to switch modes before |
| 151 | * reassociating. |
| 152 | */ |
| 153 | if (IEEE80211_ATH_CAP(vap, vap->iv_bss, IEEE80211_NODE_TURBOP)) |
| 154 | ieee80211_dturbo_switch(vap, |
| 155 | ic->ic_bsschan->ic_flags ^ IEEE80211_CHAN_TURBO); |
| 156 | #endif |
| 157 | /* |
| 158 | * Try to reassociate before scanning for a new ap. |
| 159 | */ |
| 160 | ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1); |
| 161 | } else { |
| 162 | /* |
| 163 | * Somebody else is controlling state changes (e.g. |
| 164 | * a user-mode app) don't do anything that would |
| 165 | * confuse them; just drop into scan mode so they'll |
| 166 | * notified of the state change and given control. |
| 167 | */ |
| 168 | ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | /* |
| 173 | * Handle deauth with reason. We retry only for |
| 174 | * the cases where we might succeed. Otherwise |
| 175 | * we downgrade the ap and scan. |
| 176 | */ |
| 177 | static void |
| 178 | sta_authretry(struct ieee80211vap *vap, struct ieee80211_node *ni, int reason) |
| 179 | { |
| 180 | switch (reason) { |
| 181 | case IEEE80211_STATUS_SUCCESS: /* NB: MLME assoc */ |
| 182 | case IEEE80211_STATUS_TIMEOUT: |
| 183 | case IEEE80211_REASON_ASSOC_EXPIRE: |
| 184 | case IEEE80211_REASON_NOT_AUTHED: |
| 185 | case IEEE80211_REASON_NOT_ASSOCED: |
| 186 | case IEEE80211_REASON_ASSOC_LEAVE: |
| 187 | case IEEE80211_REASON_ASSOC_NOT_AUTHED: |
| 188 | IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_AUTH, 1); |
| 189 | break; |
| 190 | default: |
| 191 | ieee80211_scan_assoc_fail(vap, vap->iv_bss->ni_macaddr, reason); |
| 192 | if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) |
| 193 | ieee80211_check_scan_current(vap); |
| 194 | break; |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | /* |
| 199 | * IEEE80211_M_STA vap state machine handler. |
| 200 | * This routine handles the main states in the 802.11 protocol. |
| 201 | */ |
| 202 | static int |
| 203 | sta_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) |
| 204 | { |
| 205 | struct ieee80211com *ic = vap->iv_ic; |
| 206 | struct ieee80211_node *ni; |
| 207 | enum ieee80211_state ostate; |
| 208 | |
| 209 | ostate = vap->iv_state; |
| 210 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n", |
| 211 | __func__, ieee80211_state_name[ostate], |
| 212 | ieee80211_state_name[nstate], arg); |
| 213 | vap->iv_state = nstate; /* state transition */ |
| 214 | callout_stop(&vap->iv_mgtsend); /* XXX callout_drain */ |
| 215 | if (ostate != IEEE80211_S_SCAN) |
| 216 | ieee80211_cancel_scan(vap); /* background scan */ |
| 217 | ni = vap->iv_bss; /* NB: no reference held */ |
| 218 | if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) |
| 219 | callout_stop(&vap->iv_swbmiss); |
| 220 | switch (nstate) { |
| 221 | case IEEE80211_S_INIT: |
| 222 | switch (ostate) { |
| 223 | case IEEE80211_S_SLEEP: |
| 224 | /* XXX wakeup */ |
| 225 | case IEEE80211_S_RUN: |
| 226 | IEEE80211_SEND_MGMT(ni, |
| 227 | IEEE80211_FC0_SUBTYPE_DISASSOC, |
| 228 | IEEE80211_REASON_ASSOC_LEAVE); |
| 229 | ieee80211_sta_leave(ni); |
| 230 | break; |
| 231 | case IEEE80211_S_ASSOC: |
| 232 | IEEE80211_SEND_MGMT(ni, |
| 233 | IEEE80211_FC0_SUBTYPE_DEAUTH, |
| 234 | IEEE80211_REASON_AUTH_LEAVE); |
| 235 | break; |
| 236 | case IEEE80211_S_SCAN: |
| 237 | ieee80211_cancel_scan(vap); |
| 238 | break; |
| 239 | default: |
| 240 | goto invalid; |
| 241 | } |
| 242 | if (ostate != IEEE80211_S_INIT) { |
| 243 | /* NB: optimize INIT -> INIT case */ |
| 244 | ieee80211_reset_bss(vap); |
| 245 | } |
| 246 | if (vap->iv_auth->ia_detach != NULL) |
| 247 | vap->iv_auth->ia_detach(vap); |
| 248 | break; |
| 249 | case IEEE80211_S_SCAN: |
| 250 | switch (ostate) { |
| 251 | case IEEE80211_S_INIT: |
| 252 | /* |
| 253 | * Initiate a scan. We can come here as a result |
| 254 | * of an IEEE80211_IOC_SCAN_REQ too in which case |
| 255 | * the vap will be marked with IEEE80211_FEXT_SCANREQ |
| 256 | * and the scan request parameters will be present |
| 257 | * in iv_scanreq. Otherwise we do the default. |
| 258 | */ |
| 259 | if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) { |
| 260 | ieee80211_check_scan(vap, |
| 261 | vap->iv_scanreq_flags, |
| 262 | vap->iv_scanreq_duration, |
| 263 | vap->iv_scanreq_mindwell, |
| 264 | vap->iv_scanreq_maxdwell, |
| 265 | vap->iv_scanreq_nssid, vap->iv_scanreq_ssid); |
| 266 | vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ; |
| 267 | } else |
| 268 | ieee80211_check_scan_current(vap); |
| 269 | break; |
| 270 | case IEEE80211_S_SCAN: |
| 271 | case IEEE80211_S_AUTH: |
| 272 | case IEEE80211_S_ASSOC: |
| 273 | /* |
| 274 | * These can happen either because of a timeout |
| 275 | * on an assoc/auth response or because of a |
| 276 | * change in state that requires a reset. For |
| 277 | * the former we're called with a non-zero arg |
| 278 | * that is the cause for the failure; pass this |
| 279 | * to the scan code so it can update state. |
| 280 | * Otherwise trigger a new scan unless we're in |
| 281 | * manual roaming mode in which case an application |
| 282 | * must issue an explicit scan request. |
| 283 | */ |
| 284 | if (arg != 0) |
| 285 | ieee80211_scan_assoc_fail(vap, |
| 286 | vap->iv_bss->ni_macaddr, arg); |
| 287 | if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) |
| 288 | ieee80211_check_scan_current(vap); |
| 289 | break; |
| 290 | case IEEE80211_S_RUN: /* beacon miss */ |
| 291 | /* |
| 292 | * Beacon miss. Notify user space and if not |
| 293 | * under control of a user application (roaming |
| 294 | * manual) kick off a scan to re-connect. |
| 295 | */ |
| 296 | ieee80211_sta_leave(ni); |
| 297 | if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) |
| 298 | ieee80211_check_scan_current(vap); |
| 299 | break; |
| 300 | default: |
| 301 | goto invalid; |
| 302 | } |
| 303 | break; |
| 304 | case IEEE80211_S_AUTH: |
| 305 | switch (ostate) { |
| 306 | case IEEE80211_S_INIT: |
| 307 | case IEEE80211_S_SCAN: |
| 308 | IEEE80211_SEND_MGMT(ni, |
| 309 | IEEE80211_FC0_SUBTYPE_AUTH, 1); |
| 310 | break; |
| 311 | case IEEE80211_S_AUTH: |
| 312 | case IEEE80211_S_ASSOC: |
| 313 | switch (arg & 0xff) { |
| 314 | case IEEE80211_FC0_SUBTYPE_AUTH: |
| 315 | /* ??? */ |
| 316 | IEEE80211_SEND_MGMT(ni, |
| 317 | IEEE80211_FC0_SUBTYPE_AUTH, 2); |
| 318 | break; |
| 319 | case IEEE80211_FC0_SUBTYPE_DEAUTH: |
| 320 | sta_authretry(vap, ni, arg>>8); |
| 321 | break; |
| 322 | } |
| 323 | break; |
| 324 | case IEEE80211_S_RUN: |
| 325 | switch (arg & 0xff) { |
| 326 | case IEEE80211_FC0_SUBTYPE_AUTH: |
| 327 | IEEE80211_SEND_MGMT(ni, |
| 328 | IEEE80211_FC0_SUBTYPE_AUTH, 2); |
| 329 | vap->iv_state = ostate; /* stay RUN */ |
| 330 | break; |
| 331 | case IEEE80211_FC0_SUBTYPE_DEAUTH: |
| 332 | ieee80211_sta_leave(ni); |
| 333 | if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) { |
| 334 | /* try to reauth */ |
| 335 | IEEE80211_SEND_MGMT(ni, |
| 336 | IEEE80211_FC0_SUBTYPE_AUTH, 1); |
| 337 | } |
| 338 | break; |
| 339 | } |
| 340 | break; |
| 341 | default: |
| 342 | goto invalid; |
| 343 | } |
| 344 | break; |
| 345 | case IEEE80211_S_ASSOC: |
| 346 | switch (ostate) { |
| 347 | case IEEE80211_S_AUTH: |
| 348 | case IEEE80211_S_ASSOC: |
| 349 | IEEE80211_SEND_MGMT(ni, |
| 350 | IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); |
| 351 | break; |
| 352 | case IEEE80211_S_SLEEP: /* cannot happen */ |
| 353 | case IEEE80211_S_RUN: |
| 354 | ieee80211_sta_leave(ni); |
| 355 | if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) { |
| 356 | IEEE80211_SEND_MGMT(ni, arg ? |
| 357 | IEEE80211_FC0_SUBTYPE_REASSOC_REQ : |
| 358 | IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); |
| 359 | } |
| 360 | break; |
| 361 | default: |
| 362 | goto invalid; |
| 363 | } |
| 364 | break; |
| 365 | case IEEE80211_S_RUN: |
| 366 | if (vap->iv_flags & IEEE80211_F_WPA) { |
| 367 | /* XXX validate prerequisites */ |
| 368 | } |
| 369 | switch (ostate) { |
| 370 | case IEEE80211_S_RUN: |
| 371 | case IEEE80211_S_CSA: |
| 372 | break; |
| 373 | case IEEE80211_S_AUTH: /* when join is done in fw */ |
| 374 | case IEEE80211_S_ASSOC: |
| 375 | #ifdef IEEE80211_DEBUG |
| 376 | if (ieee80211_msg_debug(vap)) { |
| 377 | ieee80211_note(vap, "%s with %6D ssid ", |
| 378 | (vap->iv_opmode == IEEE80211_M_STA ? |
| 379 | "associated" : "synchronized"), |
| 380 | ni->ni_bssid, ":"); |
| 381 | ieee80211_print_essid(vap->iv_bss->ni_essid, |
| 382 | ni->ni_esslen); |
| 383 | /* XXX MCS/HT */ |
| 384 | kprintf(" channel %d start %uMb\n", |
| 385 | ieee80211_chan2ieee(ic, ic->ic_curchan), |
| 386 | IEEE80211_RATE2MBS(ni->ni_txrate)); |
| 387 | } |
| 388 | #endif |
| 389 | ieee80211_scan_assoc_success(vap, ni->ni_macaddr); |
| 390 | ieee80211_notify_node_join(ni, |
| 391 | arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); |
| 392 | break; |
| 393 | case IEEE80211_S_SLEEP: |
| 394 | ieee80211_sta_pwrsave(vap, 0); |
| 395 | break; |
| 396 | default: |
| 397 | goto invalid; |
| 398 | } |
| 399 | ieee80211_sync_curchan(ic); |
| 400 | if (ostate != IEEE80211_S_RUN && |
| 401 | (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS)) { |
| 402 | /* |
| 403 | * Start s/w beacon miss timer for devices w/o |
| 404 | * hardware support. We fudge a bit here since |
| 405 | * we're doing this in software. |
| 406 | */ |
| 407 | vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS( |
| 408 | 2 * vap->iv_bmissthreshold * ni->ni_intval); |
| 409 | vap->iv_swbmiss_count = 0; |
| 410 | callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period, |
| 411 | ieee80211_swbmiss_callout, vap); |
| 412 | } |
| 413 | /* |
| 414 | * When 802.1x is not in use mark the port authorized |
| 415 | * at this point so traffic can flow. |
| 416 | */ |
| 417 | if (ni->ni_authmode != IEEE80211_AUTH_8021X) |
| 418 | ieee80211_node_authorize(ni); |
| 419 | /* |
| 420 | * Fake association when joining an existing bss. |
| 421 | */ |
| 422 | if (ic->ic_newassoc != NULL) |
| 423 | ic->ic_newassoc(vap->iv_bss, ostate != IEEE80211_S_RUN); |
| 424 | break; |
| 425 | case IEEE80211_S_CSA: |
| 426 | if (ostate != IEEE80211_S_RUN) |
| 427 | goto invalid; |
| 428 | break; |
| 429 | case IEEE80211_S_SLEEP: |
| 430 | ieee80211_sta_pwrsave(vap, 1); |
| 431 | break; |
| 432 | default: |
| 433 | invalid: |
| 434 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, |
| 435 | "%s: unexpected state transition %s -> %s\n", __func__, |
| 436 | ieee80211_state_name[ostate], ieee80211_state_name[nstate]); |
| 437 | break; |
| 438 | } |
| 439 | return 0; |
| 440 | } |
| 441 | |
| 442 | /* |
| 443 | * Return non-zero if the frame is an echo of a multicast |
| 444 | * frame sent by ourself. The dir is known to be DSTODS. |
| 445 | */ |
| 446 | static __inline int |
| 447 | isdstods_mcastecho(struct ieee80211vap *vap, const struct ieee80211_frame *wh) |
| 448 | { |
| 449 | #define QWH4(wh) ((const struct ieee80211_qosframe_addr4 *)wh) |
| 450 | #define WH4(wh) ((const struct ieee80211_frame_addr4 *)wh) |
| 451 | const uint8_t *sa; |
| 452 | |
| 453 | KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode")); |
| 454 | |
| 455 | if (!IEEE80211_IS_MULTICAST(wh->i_addr3)) |
| 456 | return 0; |
| 457 | sa = IEEE80211_QOS_HAS_SEQ(wh) ? QWH4(wh)->i_addr4 : WH4(wh)->i_addr4; |
| 458 | return IEEE80211_ADDR_EQ(sa, vap->iv_myaddr); |
| 459 | #undef WH4 |
| 460 | #undef QWH4 |
| 461 | } |
| 462 | |
| 463 | /* |
| 464 | * Return non-zero if the frame is an echo of a multicast |
| 465 | * frame sent by ourself. The dir is known to be FROMDS. |
| 466 | */ |
| 467 | static __inline int |
| 468 | isfromds_mcastecho(struct ieee80211vap *vap, const struct ieee80211_frame *wh) |
| 469 | { |
| 470 | KASSERT(vap->iv_opmode == IEEE80211_M_STA, ("wrong mode")); |
| 471 | |
| 472 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) |
| 473 | return 0; |
| 474 | return IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_myaddr); |
| 475 | } |
| 476 | |
| 477 | /* |
| 478 | * Decide if a received management frame should be |
| 479 | * printed when debugging is enabled. This filters some |
| 480 | * of the less interesting frames that come frequently |
| 481 | * (e.g. beacons). |
| 482 | */ |
| 483 | static __inline int |
| 484 | doprint(struct ieee80211vap *vap, int subtype) |
| 485 | { |
| 486 | switch (subtype) { |
| 487 | case IEEE80211_FC0_SUBTYPE_BEACON: |
| 488 | return (vap->iv_ic->ic_flags & IEEE80211_F_SCAN); |
| 489 | case IEEE80211_FC0_SUBTYPE_PROBE_REQ: |
| 490 | return 0; |
| 491 | } |
| 492 | return 1; |
| 493 | } |
| 494 | |
| 495 | /* |
| 496 | * Process a received frame. The node associated with the sender |
| 497 | * should be supplied. If nothing was found in the node table then |
| 498 | * the caller is assumed to supply a reference to iv_bss instead. |
| 499 | * The RSSI and a timestamp are also supplied. The RSSI data is used |
| 500 | * during AP scanning to select a AP to associate with; it can have |
| 501 | * any units so long as values have consistent units and higher values |
| 502 | * mean ``better signal''. The receive timestamp is currently not used |
| 503 | * by the 802.11 layer. |
| 504 | */ |
| 505 | static int |
| 506 | sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf) |
| 507 | { |
| 508 | #define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) |
| 509 | #define HAS_SEQ(type) ((type & 0x4) == 0) |
| 510 | struct ieee80211vap *vap = ni->ni_vap; |
| 511 | struct ieee80211com *ic = ni->ni_ic; |
| 512 | struct ifnet *ifp = vap->iv_ifp; |
| 513 | struct ieee80211_frame *wh; |
| 514 | struct ieee80211_key *key; |
| 515 | struct ether_header *eh; |
| 516 | int hdrspace, need_tap = 1; /* mbuf need to be tapped. */ |
| 517 | uint8_t dir, type, subtype, qos; |
| 518 | uint8_t *bssid; |
| 519 | uint16_t rxseq; |
| 520 | |
| 521 | if (m->m_flags & M_AMPDU_MPDU) { |
| 522 | /* |
| 523 | * Fastpath for A-MPDU reorder q resubmission. Frames |
| 524 | * w/ M_AMPDU_MPDU marked have already passed through |
| 525 | * here but were received out of order and been held on |
| 526 | * the reorder queue. When resubmitted they are marked |
| 527 | * with the M_AMPDU_MPDU flag and we can bypass most of |
| 528 | * the normal processing. |
| 529 | */ |
| 530 | wh = mtod(m, struct ieee80211_frame *); |
| 531 | type = IEEE80211_FC0_TYPE_DATA; |
| 532 | dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; |
| 533 | subtype = IEEE80211_FC0_SUBTYPE_QOS; |
| 534 | hdrspace = ieee80211_hdrspace(ic, wh); /* XXX optimize? */ |
| 535 | goto resubmit_ampdu; |
| 536 | } |
| 537 | |
| 538 | KASSERT(ni != NULL, ("null node")); |
| 539 | ni->ni_inact = ni->ni_inact_reload; |
| 540 | |
| 541 | type = -1; /* undefined */ |
| 542 | |
| 543 | if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) { |
| 544 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, |
| 545 | ni->ni_macaddr, NULL, |
| 546 | "too short (1): len %u", m->m_pkthdr.len); |
| 547 | vap->iv_stats.is_rx_tooshort++; |
| 548 | goto out; |
| 549 | } |
| 550 | /* |
| 551 | * Bit of a cheat here, we use a pointer for a 3-address |
| 552 | * frame format but don't reference fields past outside |
| 553 | * ieee80211_frame_min w/o first validating the data is |
| 554 | * present. |
| 555 | */ |
| 556 | wh = mtod(m, struct ieee80211_frame *); |
| 557 | |
| 558 | if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != |
| 559 | IEEE80211_FC0_VERSION_0) { |
| 560 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, |
| 561 | ni->ni_macaddr, NULL, "wrong version, fc %02x:%02x", |
| 562 | wh->i_fc[0], wh->i_fc[1]); |
| 563 | vap->iv_stats.is_rx_badversion++; |
| 564 | goto err; |
| 565 | } |
| 566 | |
| 567 | dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; |
| 568 | type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; |
| 569 | subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; |
| 570 | if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { |
| 571 | bssid = wh->i_addr2; |
| 572 | if (!IEEE80211_ADDR_EQ(bssid, ni->ni_bssid)) { |
| 573 | /* not interested in */ |
| 574 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, |
| 575 | bssid, NULL, "%s", "not to bss"); |
| 576 | vap->iv_stats.is_rx_wrongbss++; |
| 577 | goto out; |
| 578 | } |
| 579 | IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi); |
| 580 | ni->ni_noise = nf; |
| 581 | if (HAS_SEQ(type) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) { |
| 582 | uint8_t tid = ieee80211_gettid(wh); |
| 583 | if (IEEE80211_QOS_HAS_SEQ(wh) && |
| 584 | TID_TO_WME_AC(tid) >= WME_AC_VI) |
| 585 | ic->ic_wme.wme_hipri_traffic++; |
| 586 | rxseq = le16toh(*(uint16_t *)wh->i_seq); |
| 587 | if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && |
| 588 | (wh->i_fc[1] & IEEE80211_FC1_RETRY) && |
| 589 | SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { |
| 590 | /* duplicate, discard */ |
| 591 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, |
| 592 | bssid, "duplicate", |
| 593 | "seqno <%u,%u> fragno <%u,%u> tid %u", |
| 594 | rxseq >> IEEE80211_SEQ_SEQ_SHIFT, |
| 595 | ni->ni_rxseqs[tid] >> |
| 596 | IEEE80211_SEQ_SEQ_SHIFT, |
| 597 | rxseq & IEEE80211_SEQ_FRAG_MASK, |
| 598 | ni->ni_rxseqs[tid] & |
| 599 | IEEE80211_SEQ_FRAG_MASK, |
| 600 | tid); |
| 601 | vap->iv_stats.is_rx_dup++; |
| 602 | IEEE80211_NODE_STAT(ni, rx_dup); |
| 603 | goto out; |
| 604 | } |
| 605 | ni->ni_rxseqs[tid] = rxseq; |
| 606 | } |
| 607 | } |
| 608 | |
| 609 | switch (type) { |
| 610 | case IEEE80211_FC0_TYPE_DATA: |
| 611 | hdrspace = ieee80211_hdrspace(ic, wh); |
| 612 | if (m->m_len < hdrspace && |
| 613 | (m = m_pullup(m, hdrspace)) == NULL) { |
| 614 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, |
| 615 | ni->ni_macaddr, NULL, |
| 616 | "data too short: expecting %u", hdrspace); |
| 617 | vap->iv_stats.is_rx_tooshort++; |
| 618 | goto out; /* XXX */ |
| 619 | } |
| 620 | /* |
| 621 | * Handle A-MPDU re-ordering. If the frame is to be |
| 622 | * processed directly then ieee80211_ampdu_reorder |
| 623 | * will return 0; otherwise it has consumed the mbuf |
| 624 | * and we should do nothing more with it. |
| 625 | */ |
| 626 | if ((m->m_flags & M_AMPDU) && |
| 627 | (dir == IEEE80211_FC1_DIR_FROMDS || |
| 628 | dir == IEEE80211_FC1_DIR_DSTODS) && |
| 629 | ieee80211_ampdu_reorder(ni, m) != 0) { |
| 630 | m = NULL; |
| 631 | goto out; |
| 632 | } |
| 633 | resubmit_ampdu: |
| 634 | if (dir == IEEE80211_FC1_DIR_FROMDS) { |
| 635 | if ((ifp->if_flags & IFF_SIMPLEX) && |
| 636 | isfromds_mcastecho(vap, wh)) { |
| 637 | /* |
| 638 | * In IEEE802.11 network, multicast |
| 639 | * packets sent from "me" are broadcast |
| 640 | * from the AP; silently discard for |
| 641 | * SIMPLEX interface. |
| 642 | */ |
| 643 | IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, |
| 644 | wh, "data", "%s", "multicast echo"); |
| 645 | vap->iv_stats.is_rx_mcastecho++; |
| 646 | goto out; |
| 647 | } |
| 648 | if ((vap->iv_flags & IEEE80211_F_DWDS) && |
| 649 | IEEE80211_IS_MULTICAST(wh->i_addr1)) { |
| 650 | /* |
| 651 | * DWDS sta's must drop 3-address mcast frames |
| 652 | * as they will be sent separately as a 4-addr |
| 653 | * frame. Accepting the 3-addr frame will |
| 654 | * confuse the bridge into thinking the sending |
| 655 | * sta is located at the end of WDS link. |
| 656 | */ |
| 657 | IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, |
| 658 | "3-address data", "%s", "DWDS enabled"); |
| 659 | vap->iv_stats.is_rx_mcastecho++; |
| 660 | goto out; |
| 661 | } |
| 662 | } else if (dir == IEEE80211_FC1_DIR_DSTODS) { |
| 663 | if ((vap->iv_flags & IEEE80211_F_DWDS) == 0) { |
| 664 | IEEE80211_DISCARD(vap, |
| 665 | IEEE80211_MSG_INPUT, wh, "4-address data", |
| 666 | "%s", "DWDS not enabled"); |
| 667 | vap->iv_stats.is_rx_wrongdir++; |
| 668 | goto out; |
| 669 | } |
| 670 | if ((ifp->if_flags & IFF_SIMPLEX) && |
| 671 | isdstods_mcastecho(vap, wh)) { |
| 672 | /* |
| 673 | * In IEEE802.11 network, multicast |
| 674 | * packets sent from "me" are broadcast |
| 675 | * from the AP; silently discard for |
| 676 | * SIMPLEX interface. |
| 677 | */ |
| 678 | IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, |
| 679 | "4-address data", "%s", "multicast echo"); |
| 680 | vap->iv_stats.is_rx_mcastecho++; |
| 681 | goto out; |
| 682 | } |
| 683 | } else { |
| 684 | IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, wh, |
| 685 | "data", "incorrect dir 0x%x", dir); |
| 686 | vap->iv_stats.is_rx_wrongdir++; |
| 687 | goto out; |
| 688 | } |
| 689 | |
| 690 | /* |
| 691 | * Handle privacy requirements. Note that we |
| 692 | * must not be preempted from here until after |
| 693 | * we (potentially) call ieee80211_crypto_demic; |
| 694 | * otherwise we may violate assumptions in the |
| 695 | * crypto cipher modules used to do delayed update |
| 696 | * of replay sequence numbers. |
| 697 | */ |
| 698 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { |
| 699 | if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { |
| 700 | /* |
| 701 | * Discard encrypted frames when privacy is off. |
| 702 | */ |
| 703 | IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, |
| 704 | wh, "WEP", "%s", "PRIVACY off"); |
| 705 | vap->iv_stats.is_rx_noprivacy++; |
| 706 | IEEE80211_NODE_STAT(ni, rx_noprivacy); |
| 707 | goto out; |
| 708 | } |
| 709 | key = ieee80211_crypto_decap(ni, m, hdrspace); |
| 710 | if (key == NULL) { |
| 711 | /* NB: stats+msgs handled in crypto_decap */ |
| 712 | IEEE80211_NODE_STAT(ni, rx_wepfail); |
| 713 | goto out; |
| 714 | } |
| 715 | wh = mtod(m, struct ieee80211_frame *); |
| 716 | wh->i_fc[1] &= ~IEEE80211_FC1_WEP; |
| 717 | } else { |
| 718 | /* XXX M_WEP and IEEE80211_F_PRIVACY */ |
| 719 | key = NULL; |
| 720 | } |
| 721 | |
| 722 | /* |
| 723 | * Save QoS bits for use below--before we strip the header. |
| 724 | */ |
| 725 | if (subtype == IEEE80211_FC0_SUBTYPE_QOS) { |
| 726 | qos = (dir == IEEE80211_FC1_DIR_DSTODS) ? |
| 727 | ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] : |
| 728 | ((struct ieee80211_qosframe *)wh)->i_qos[0]; |
| 729 | } else |
| 730 | qos = 0; |
| 731 | |
| 732 | /* |
| 733 | * Next up, any fragmentation. |
| 734 | */ |
| 735 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { |
| 736 | m = ieee80211_defrag(ni, m, hdrspace); |
| 737 | if (m == NULL) { |
| 738 | /* Fragment dropped or frame not complete yet */ |
| 739 | goto out; |
| 740 | } |
| 741 | } |
| 742 | wh = NULL; /* no longer valid, catch any uses */ |
| 743 | |
| 744 | /* |
| 745 | * Next strip any MSDU crypto bits. |
| 746 | */ |
| 747 | if (key != NULL && !ieee80211_crypto_demic(vap, key, m, 0)) { |
| 748 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, |
| 749 | ni->ni_macaddr, "data", "%s", "demic error"); |
| 750 | vap->iv_stats.is_rx_demicfail++; |
| 751 | IEEE80211_NODE_STAT(ni, rx_demicfail); |
| 752 | goto out; |
| 753 | } |
| 754 | |
| 755 | /* copy to listener after decrypt */ |
| 756 | if (ieee80211_radiotap_active_vap(vap)) |
| 757 | ieee80211_radiotap_rx(vap, m); |
| 758 | need_tap = 0; |
| 759 | |
| 760 | /* |
| 761 | * Finally, strip the 802.11 header. |
| 762 | */ |
| 763 | m = ieee80211_decap(vap, m, hdrspace); |
| 764 | if (m == NULL) { |
| 765 | /* XXX mask bit to check for both */ |
| 766 | /* don't count Null data frames as errors */ |
| 767 | if (subtype == IEEE80211_FC0_SUBTYPE_NODATA || |
| 768 | subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL) |
| 769 | goto out; |
| 770 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, |
| 771 | ni->ni_macaddr, "data", "%s", "decap error"); |
| 772 | vap->iv_stats.is_rx_decap++; |
| 773 | IEEE80211_NODE_STAT(ni, rx_decap); |
| 774 | goto err; |
| 775 | } |
| 776 | eh = mtod(m, struct ether_header *); |
| 777 | if (!ieee80211_node_is_authorized(ni)) { |
| 778 | /* |
| 779 | * Deny any non-PAE frames received prior to |
| 780 | * authorization. For open/shared-key |
| 781 | * authentication the port is mark authorized |
| 782 | * after authentication completes. For 802.1x |
| 783 | * the port is not marked authorized by the |
| 784 | * authenticator until the handshake has completed. |
| 785 | */ |
| 786 | if (eh->ether_type != htons(ETHERTYPE_PAE)) { |
| 787 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, |
| 788 | eh->ether_shost, "data", |
| 789 | "unauthorized port: ether type 0x%x len %u", |
| 790 | eh->ether_type, m->m_pkthdr.len); |
| 791 | vap->iv_stats.is_rx_unauth++; |
| 792 | IEEE80211_NODE_STAT(ni, rx_unauth); |
| 793 | goto err; |
| 794 | } |
| 795 | } else { |
| 796 | /* |
| 797 | * When denying unencrypted frames, discard |
| 798 | * any non-PAE frames received without encryption. |
| 799 | */ |
| 800 | if ((vap->iv_flags & IEEE80211_F_DROPUNENC) && |
| 801 | (key == NULL && (m->m_flags & M_WEP) == 0) && |
| 802 | eh->ether_type != htons(ETHERTYPE_PAE)) { |
| 803 | /* |
| 804 | * Drop unencrypted frames. |
| 805 | */ |
| 806 | vap->iv_stats.is_rx_unencrypted++; |
| 807 | IEEE80211_NODE_STAT(ni, rx_unencrypted); |
| 808 | goto out; |
| 809 | } |
| 810 | } |
| 811 | /* XXX require HT? */ |
| 812 | if (qos & IEEE80211_QOS_AMSDU) { |
| 813 | m = ieee80211_decap_amsdu(ni, m); |
| 814 | if (m == NULL) |
| 815 | return IEEE80211_FC0_TYPE_DATA; |
| 816 | } else { |
| 817 | #ifdef IEEE80211_SUPPORT_SUPERG |
| 818 | m = ieee80211_decap_fastframe(vap, ni, m); |
| 819 | if (m == NULL) |
| 820 | return IEEE80211_FC0_TYPE_DATA; |
| 821 | #endif |
| 822 | } |
| 823 | ieee80211_deliver_data(vap, ni, m); |
| 824 | return IEEE80211_FC0_TYPE_DATA; |
| 825 | |
| 826 | case IEEE80211_FC0_TYPE_MGT: |
| 827 | vap->iv_stats.is_rx_mgmt++; |
| 828 | IEEE80211_NODE_STAT(ni, rx_mgmt); |
| 829 | if (dir != IEEE80211_FC1_DIR_NODS) { |
| 830 | IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, |
| 831 | wh, "data", "incorrect dir 0x%x", dir); |
| 832 | vap->iv_stats.is_rx_wrongdir++; |
| 833 | goto err; |
| 834 | } |
| 835 | if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) { |
| 836 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, |
| 837 | ni->ni_macaddr, "mgt", "too short: len %u", |
| 838 | m->m_pkthdr.len); |
| 839 | vap->iv_stats.is_rx_tooshort++; |
| 840 | goto out; |
| 841 | } |
| 842 | #ifdef IEEE80211_DEBUG |
| 843 | if ((ieee80211_msg_debug(vap) && doprint(vap, subtype)) || |
| 844 | ieee80211_msg_dumppkts(vap)) { |
| 845 | if_printf(ifp, "received %s from %6D rssi %d\n", |
| 846 | ieee80211_mgt_subtype_name[subtype >> |
| 847 | IEEE80211_FC0_SUBTYPE_SHIFT], |
| 848 | wh->i_addr2, ":", rssi); |
| 849 | } |
| 850 | #endif |
| 851 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { |
| 852 | if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) { |
| 853 | /* |
| 854 | * Only shared key auth frames with a challenge |
| 855 | * should be encrypted, discard all others. |
| 856 | */ |
| 857 | IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, |
| 858 | wh, ieee80211_mgt_subtype_name[subtype >> |
| 859 | IEEE80211_FC0_SUBTYPE_SHIFT], |
| 860 | "%s", "WEP set but not permitted"); |
| 861 | vap->iv_stats.is_rx_mgtdiscard++; /* XXX */ |
| 862 | goto out; |
| 863 | } |
| 864 | if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { |
| 865 | /* |
| 866 | * Discard encrypted frames when privacy is off. |
| 867 | */ |
| 868 | IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, |
| 869 | wh, "mgt", "%s", "WEP set but PRIVACY off"); |
| 870 | vap->iv_stats.is_rx_noprivacy++; |
| 871 | goto out; |
| 872 | } |
| 873 | hdrspace = ieee80211_hdrspace(ic, wh); |
| 874 | key = ieee80211_crypto_decap(ni, m, hdrspace); |
| 875 | if (key == NULL) { |
| 876 | /* NB: stats+msgs handled in crypto_decap */ |
| 877 | goto out; |
| 878 | } |
| 879 | wh = mtod(m, struct ieee80211_frame *); |
| 880 | wh->i_fc[1] &= ~IEEE80211_FC1_WEP; |
| 881 | } |
| 882 | vap->iv_recv_mgmt(ni, m, subtype, rssi, nf); |
| 883 | goto out; |
| 884 | |
| 885 | case IEEE80211_FC0_TYPE_CTL: |
| 886 | vap->iv_stats.is_rx_ctl++; |
| 887 | IEEE80211_NODE_STAT(ni, rx_ctrl); |
| 888 | vap->iv_recv_ctl(ni, m, subtype); |
| 889 | goto out; |
| 890 | |
| 891 | default: |
| 892 | IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, |
| 893 | wh, NULL, "bad frame type 0x%x", type); |
| 894 | /* should not come here */ |
| 895 | break; |
| 896 | } |
| 897 | err: |
| 898 | ifp->if_ierrors++; |
| 899 | out: |
| 900 | if (m != NULL) { |
| 901 | if (need_tap && ieee80211_radiotap_active_vap(vap)) |
| 902 | ieee80211_radiotap_rx(vap, m); |
| 903 | m_freem(m); |
| 904 | } |
| 905 | return type; |
| 906 | #undef SEQ_LEQ |
| 907 | } |
| 908 | |
| 909 | static void |
| 910 | sta_auth_open(struct ieee80211_node *ni, struct ieee80211_frame *wh, |
| 911 | int rssi, int nf, uint16_t seq, uint16_t status) |
| 912 | { |
| 913 | struct ieee80211vap *vap = ni->ni_vap; |
| 914 | |
| 915 | if (ni->ni_authmode == IEEE80211_AUTH_SHARED) { |
| 916 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, |
| 917 | ni->ni_macaddr, "open auth", |
| 918 | "bad sta auth mode %u", ni->ni_authmode); |
| 919 | vap->iv_stats.is_rx_bad_auth++; /* XXX */ |
| 920 | return; |
| 921 | } |
| 922 | if (vap->iv_state != IEEE80211_S_AUTH || |
| 923 | seq != IEEE80211_AUTH_OPEN_RESPONSE) { |
| 924 | vap->iv_stats.is_rx_bad_auth++; |
| 925 | return; |
| 926 | } |
| 927 | if (status != 0) { |
| 928 | IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, |
| 929 | ni, "open auth failed (reason %d)", status); |
| 930 | vap->iv_stats.is_rx_auth_fail++; |
| 931 | vap->iv_stats.is_rx_authfail_code = status; |
| 932 | ieee80211_new_state(vap, IEEE80211_S_SCAN, |
| 933 | IEEE80211_SCAN_FAIL_STATUS); |
| 934 | } else |
| 935 | ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0); |
| 936 | } |
| 937 | |
| 938 | static void |
| 939 | sta_auth_shared(struct ieee80211_node *ni, struct ieee80211_frame *wh, |
| 940 | uint8_t *frm, uint8_t *efrm, int rssi, int nf, |
| 941 | uint16_t seq, uint16_t status) |
| 942 | { |
| 943 | struct ieee80211vap *vap = ni->ni_vap; |
| 944 | uint8_t *challenge; |
| 945 | |
| 946 | /* |
| 947 | * NB: this can happen as we allow pre-shared key |
| 948 | * authentication to be enabled w/o wep being turned |
| 949 | * on so that configuration of these can be done |
| 950 | * in any order. It may be better to enforce the |
| 951 | * ordering in which case this check would just be |
| 952 | * for sanity/consistency. |
| 953 | */ |
| 954 | if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { |
| 955 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, |
| 956 | ni->ni_macaddr, "shared key auth", |
| 957 | "%s", " PRIVACY is disabled"); |
| 958 | goto bad; |
| 959 | } |
| 960 | /* |
| 961 | * Pre-shared key authentication is evil; accept |
| 962 | * it only if explicitly configured (it is supported |
| 963 | * mainly for compatibility with clients like OS X). |
| 964 | */ |
| 965 | if (ni->ni_authmode != IEEE80211_AUTH_AUTO && |
| 966 | ni->ni_authmode != IEEE80211_AUTH_SHARED) { |
| 967 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, |
| 968 | ni->ni_macaddr, "shared key auth", |
| 969 | "bad sta auth mode %u", ni->ni_authmode); |
| 970 | vap->iv_stats.is_rx_bad_auth++; /* XXX maybe a unique error? */ |
| 971 | goto bad; |
| 972 | } |
| 973 | |
| 974 | challenge = NULL; |
| 975 | if (frm + 1 < efrm) { |
| 976 | if ((frm[1] + 2) > (efrm - frm)) { |
| 977 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, |
| 978 | ni->ni_macaddr, "shared key auth", |
| 979 | "ie %d/%d too long", |
| 980 | frm[0], (int)((frm[1] + 2) - (efrm - frm))); |
| 981 | vap->iv_stats.is_rx_bad_auth++; |
| 982 | goto bad; |
| 983 | } |
| 984 | if (*frm == IEEE80211_ELEMID_CHALLENGE) |
| 985 | challenge = frm; |
| 986 | frm += frm[1] + 2; |
| 987 | } |
| 988 | switch (seq) { |
| 989 | case IEEE80211_AUTH_SHARED_CHALLENGE: |
| 990 | case IEEE80211_AUTH_SHARED_RESPONSE: |
| 991 | if (challenge == NULL) { |
| 992 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, |
| 993 | ni->ni_macaddr, "shared key auth", |
| 994 | "%s", "no challenge"); |
| 995 | vap->iv_stats.is_rx_bad_auth++; |
| 996 | goto bad; |
| 997 | } |
| 998 | if (challenge[1] != IEEE80211_CHALLENGE_LEN) { |
| 999 | IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH, |
| 1000 | ni->ni_macaddr, "shared key auth", |
| 1001 | "bad challenge len %d", challenge[1]); |
| 1002 | vap->iv_stats.is_rx_bad_auth++; |
| 1003 | goto bad; |
| 1004 | } |
| 1005 | default: |
| 1006 | break; |
| 1007 | } |
| 1008 | if (vap->iv_state != IEEE80211_S_AUTH) |
| 1009 | return; |
| 1010 | switch (seq) { |
| 1011 | case IEEE80211_AUTH_SHARED_PASS: |
| 1012 | if (ni->ni_challenge != NULL) { |
| 1013 | kfree(ni->ni_challenge, M_80211_NODE); |
| 1014 | ni->ni_challenge = NULL; |
| 1015 | } |
| 1016 | if (status != 0) { |
| 1017 | IEEE80211_NOTE_FRAME(vap, |
| 1018 | IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH, wh, |
| 1019 | "shared key auth failed (reason %d)", status); |
| 1020 | vap->iv_stats.is_rx_auth_fail++; |
| 1021 | vap->iv_stats.is_rx_authfail_code = status; |
| 1022 | return; |
| 1023 | } |
| 1024 | ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0); |
| 1025 | break; |
| 1026 | case IEEE80211_AUTH_SHARED_CHALLENGE: |
| 1027 | if (!ieee80211_alloc_challenge(ni)) |
| 1028 | return; |
| 1029 | /* XXX could optimize by passing recvd challenge */ |
| 1030 | memcpy(ni->ni_challenge, &challenge[2], challenge[1]); |
| 1031 | IEEE80211_SEND_MGMT(ni, |
| 1032 | IEEE80211_FC0_SUBTYPE_AUTH, seq + 1); |
| 1033 | break; |
| 1034 | default: |
| 1035 | IEEE80211_DISCARD(vap, IEEE80211_MSG_AUTH, |
| 1036 | wh, "shared key auth", "bad seq %d", seq); |
| 1037 | vap->iv_stats.is_rx_bad_auth++; |
| 1038 | return; |
| 1039 | } |
| 1040 | return; |
| 1041 | bad: |
| 1042 | /* |
| 1043 | * Kick the state machine. This short-circuits |
| 1044 | * using the mgt frame timeout to trigger the |
| 1045 | * state transition. |
| 1046 | */ |
| 1047 | if (vap->iv_state == IEEE80211_S_AUTH) |
| 1048 | ieee80211_new_state(vap, IEEE80211_S_SCAN, |
| 1049 | IEEE80211_SCAN_FAIL_STATUS); |
| 1050 | } |
| 1051 | |
| 1052 | static int |
| 1053 | ieee80211_parse_wmeparams(struct ieee80211vap *vap, uint8_t *frm, |
| 1054 | const struct ieee80211_frame *wh) |
| 1055 | { |
| 1056 | #define MS(_v, _f) (((_v) & _f) >> _f##_S) |
| 1057 | struct ieee80211_wme_state *wme = &vap->iv_ic->ic_wme; |
| 1058 | u_int len = frm[1], qosinfo; |
| 1059 | int i; |
| 1060 | |
| 1061 | if (len < sizeof(struct ieee80211_wme_param)-2) { |
| 1062 | IEEE80211_DISCARD_IE(vap, |
| 1063 | IEEE80211_MSG_ELEMID | IEEE80211_MSG_WME, |
| 1064 | wh, "WME", "too short, len %u", len); |
| 1065 | return -1; |
| 1066 | } |
| 1067 | qosinfo = frm[__offsetof(struct ieee80211_wme_param, param_qosInfo)]; |
| 1068 | qosinfo &= WME_QOSINFO_COUNT; |
| 1069 | /* XXX do proper check for wraparound */ |
| 1070 | if (qosinfo == wme->wme_wmeChanParams.cap_info) |
| 1071 | return 0; |
| 1072 | frm += __offsetof(struct ieee80211_wme_param, params_acParams); |
| 1073 | for (i = 0; i < WME_NUM_AC; i++) { |
| 1074 | struct wmeParams *wmep = |
| 1075 | &wme->wme_wmeChanParams.cap_wmeParams[i]; |
| 1076 | /* NB: ACI not used */ |
| 1077 | wmep->wmep_acm = MS(frm[0], WME_PARAM_ACM); |
| 1078 | wmep->wmep_aifsn = MS(frm[0], WME_PARAM_AIFSN); |
| 1079 | wmep->wmep_logcwmin = MS(frm[1], WME_PARAM_LOGCWMIN); |
| 1080 | wmep->wmep_logcwmax = MS(frm[1], WME_PARAM_LOGCWMAX); |
| 1081 | wmep->wmep_txopLimit = LE_READ_2(frm+2); |
| 1082 | frm += 4; |
| 1083 | } |
| 1084 | wme->wme_wmeChanParams.cap_info = qosinfo; |
| 1085 | return 1; |
| 1086 | #undef MS |
| 1087 | } |
| 1088 | |
| 1089 | /* |
| 1090 | * Process 11h Channel Switch Announcement (CSA) ie. If this |
| 1091 | * is the first CSA then initiate the switch. Otherwise we |
| 1092 | * track state and trigger completion and/or cancel of the switch. |
| 1093 | * XXX should be public for IBSS use |
| 1094 | */ |
| 1095 | static void |
| 1096 | ieee80211_parse_csaparams(struct ieee80211vap *vap, uint8_t *frm, |
| 1097 | const struct ieee80211_frame *wh) |
| 1098 | { |
| 1099 | struct ieee80211com *ic = vap->iv_ic; |
| 1100 | const struct ieee80211_csa_ie *csa = |
| 1101 | (const struct ieee80211_csa_ie *) frm; |
| 1102 | |
| 1103 | KASSERT(vap->iv_state >= IEEE80211_S_RUN, |
| 1104 | ("state %s", ieee80211_state_name[vap->iv_state])); |
| 1105 | |
| 1106 | if (csa->csa_mode > 1) { |
| 1107 | IEEE80211_DISCARD_IE(vap, |
| 1108 | IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH, |
| 1109 | wh, "CSA", "invalid mode %u", csa->csa_mode); |
| 1110 | return; |
| 1111 | } |
| 1112 | if ((ic->ic_flags & IEEE80211_F_CSAPENDING) == 0) { |
| 1113 | /* |
| 1114 | * Convert the channel number to a channel reference. We |
| 1115 | * try first to preserve turbo attribute of the current |
| 1116 | * channel then fallback. Note this will not work if the |
| 1117 | * CSA specifies a channel that requires a band switch (e.g. |
| 1118 | * 11a => 11g). This is intentional as 11h is defined only |
| 1119 | * for 5GHz/11a and because the switch does not involve a |
| 1120 | * reassociation, protocol state (capabilities, negotated |
| 1121 | * rates, etc) may/will be wrong. |
| 1122 | */ |
| 1123 | struct ieee80211_channel *c = |
| 1124 | ieee80211_find_channel_byieee(ic, csa->csa_newchan, |
| 1125 | (ic->ic_bsschan->ic_flags & IEEE80211_CHAN_ALLTURBO)); |
| 1126 | if (c == NULL) { |
| 1127 | c = ieee80211_find_channel_byieee(ic, |
| 1128 | csa->csa_newchan, |
| 1129 | (ic->ic_bsschan->ic_flags & IEEE80211_CHAN_ALL)); |
| 1130 | if (c == NULL) { |
| 1131 | IEEE80211_DISCARD_IE(vap, |
| 1132 | IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH, |
| 1133 | wh, "CSA", "invalid channel %u", |
| 1134 | csa->csa_newchan); |
| 1135 | goto done; |
| 1136 | } |
| 1137 | } |
| 1138 | #if IEEE80211_CSA_COUNT_MIN > 0 |
| 1139 | if (csa->csa_count < IEEE80211_CSA_COUNT_MIN) { |
| 1140 | /* |
| 1141 | * Require at least IEEE80211_CSA_COUNT_MIN count to |
| 1142 | * reduce the risk of being redirected by a fabricated |
| 1143 | * CSA. If a valid CSA is dropped we'll still get a |
| 1144 | * beacon miss when the AP leaves the channel so we'll |
| 1145 | * eventually follow to the new channel. |
| 1146 | * |
| 1147 | * NOTE: this violates the 11h spec that states that |
| 1148 | * count may be any value and if 0 then a switch |
| 1149 | * should happen asap. |
| 1150 | */ |
| 1151 | IEEE80211_DISCARD_IE(vap, |
| 1152 | IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH, |
| 1153 | wh, "CSA", "count %u too small, must be >= %u", |
| 1154 | csa->csa_count, IEEE80211_CSA_COUNT_MIN); |
| 1155 | goto done; |
| 1156 | } |
| 1157 | #endif |
| 1158 | ieee80211_csa_startswitch(ic, c, csa->csa_mode, csa->csa_count); |
| 1159 | } else { |
| 1160 | /* |
| 1161 | * Validate this ie against the initial CSA. We require |
| 1162 | * mode and channel not change and the count must be |
| 1163 | * monotonically decreasing. This may be pointless and |
| 1164 | * canceling the switch as a result may be too paranoid but |
| 1165 | * in the worst case if we drop out of CSA because of this |
| 1166 | * and the AP does move then we'll just end up taking a |
| 1167 | * beacon miss and scan to find the AP. |
| 1168 | * |
| 1169 | * XXX may want <= on count as we also process ProbeResp |
| 1170 | * frames and those may come in w/ the same count as the |
| 1171 | * previous beacon; but doing so leaves us open to a stuck |
| 1172 | * count until we add a dead-man timer |
| 1173 | */ |
| 1174 | if (!(csa->csa_count < ic->ic_csa_count && |
| 1175 | csa->csa_mode == ic->ic_csa_mode && |
| 1176 | csa->csa_newchan == ieee80211_chan2ieee(ic, ic->ic_csa_newchan))) { |
| 1177 | IEEE80211_NOTE_FRAME(vap, IEEE80211_MSG_DOTH, wh, |
| 1178 | "CSA ie mismatch, initial ie <%d,%d,%d>, " |
| 1179 | "this ie <%d,%d,%d>", ic->ic_csa_mode, |
| 1180 | ic->ic_csa_newchan->ic_ieee, ic->ic_csa_count, |
| 1181 | csa->csa_mode, csa->csa_newchan, csa->csa_count); |
| 1182 | ieee80211_csa_cancelswitch(ic); |
| 1183 | } else { |
| 1184 | if (csa->csa_count <= 1) |
| 1185 | ieee80211_csa_completeswitch(ic); |
| 1186 | else |
| 1187 | ic->ic_csa_count = csa->csa_count; |
| 1188 | } |
| 1189 | } |
| 1190 | done: |
| 1191 | ; |
| 1192 | } |
| 1193 | |
| 1194 | /* |
| 1195 | * Return non-zero if a background scan may be continued: |
| 1196 | * o bg scan is active |
| 1197 | * o no channel switch is pending |
| 1198 | * o there has not been any traffic recently |
| 1199 | * |
| 1200 | * Note we do not check if there is an administrative enable; |
| 1201 | * this is only done to start the scan. We assume that any |
| 1202 | * change in state will be accompanied by a request to cancel |
| 1203 | * active scans which will otherwise cause this test to fail. |
| 1204 | */ |
| 1205 | static __inline int |
| 1206 | contbgscan(struct ieee80211vap *vap) |
| 1207 | { |
| 1208 | struct ieee80211com *ic = vap->iv_ic; |
| 1209 | |
| 1210 | return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) && |
| 1211 | (ic->ic_flags & IEEE80211_F_CSAPENDING) == 0 && |
| 1212 | vap->iv_state == IEEE80211_S_RUN && /* XXX? */ |
| 1213 | time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle)); |
| 1214 | } |
| 1215 | |
| 1216 | /* |
| 1217 | * Return non-zero if a backgrond scan may be started: |
| 1218 | * o bg scanning is administratively enabled |
| 1219 | * o no channel switch is pending |
| 1220 | * o we are not boosted on a dynamic turbo channel |
| 1221 | * o there has not been a scan recently |
| 1222 | * o there has not been any traffic recently |
| 1223 | */ |
| 1224 | static __inline int |
| 1225 | startbgscan(struct ieee80211vap *vap) |
| 1226 | { |
| 1227 | struct ieee80211com *ic = vap->iv_ic; |
| 1228 | |
| 1229 | return ((vap->iv_flags & IEEE80211_F_BGSCAN) && |
| 1230 | (ic->ic_flags & IEEE80211_F_CSAPENDING) == 0 && |
| 1231 | #ifdef IEEE80211_SUPPORT_SUPERG |
| 1232 | !IEEE80211_IS_CHAN_DTURBO(ic->ic_curchan) && |
| 1233 | #endif |
| 1234 | time_after(ticks, ic->ic_lastscan + vap->iv_bgscanintvl) && |
| 1235 | time_after(ticks, ic->ic_lastdata + vap->iv_bgscanidle)); |
| 1236 | } |
| 1237 | |
| 1238 | static void |
| 1239 | sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, |
| 1240 | int subtype, int rssi, int nf) |
| 1241 | { |
| 1242 | #define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP) |
| 1243 | #define ISREASSOC(_st) ((_st) == IEEE80211_FC0_SUBTYPE_REASSOC_RESP) |
| 1244 | struct ieee80211vap *vap = ni->ni_vap; |
| 1245 | struct ieee80211com *ic = ni->ni_ic; |
| 1246 | struct ieee80211_frame *wh; |
| 1247 | uint8_t *frm, *efrm; |
| 1248 | uint8_t *rates, *xrates, *wme, *htcap, *htinfo; |
| 1249 | uint8_t rate; |
| 1250 | |
| 1251 | wh = mtod(m0, struct ieee80211_frame *); |
| 1252 | frm = (uint8_t *)&wh[1]; |
| 1253 | efrm = mtod(m0, uint8_t *) + m0->m_len; |
| 1254 | switch (subtype) { |
| 1255 | case IEEE80211_FC0_SUBTYPE_PROBE_RESP: |
| 1256 | case IEEE80211_FC0_SUBTYPE_BEACON: { |
| 1257 | struct ieee80211_scanparams scan; |
| 1258 | /* |
| 1259 | * We process beacon/probe response frames: |
| 1260 | * o when scanning, or |
| 1261 | * o station mode when associated (to collect state |
| 1262 | * updates such as 802.11g slot time) |
| 1263 | * Frames otherwise received are discarded. |
| 1264 | */ |
| 1265 | if (!((ic->ic_flags & IEEE80211_F_SCAN) || ni->ni_associd)) { |
| 1266 | vap->iv_stats.is_rx_mgtdiscard++; |
| 1267 | return; |
| 1268 | } |
| 1269 | /* XXX probe response in sta mode when !scanning? */ |
| 1270 | if (ieee80211_parse_beacon(ni, m0, &scan) != 0) |
| 1271 | return; |
| 1272 | /* |
| 1273 | * Count frame now that we know it's to be processed. |
| 1274 | */ |
| 1275 | if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) { |
| 1276 | vap->iv_stats.is_rx_beacon++; /* XXX remove */ |
| 1277 | IEEE80211_NODE_STAT(ni, rx_beacons); |
| 1278 | } else |
| 1279 | IEEE80211_NODE_STAT(ni, rx_proberesp); |
| 1280 | /* |
| 1281 | * When operating in station mode, check for state updates. |
| 1282 | * Be careful to ignore beacons received while doing a |
| 1283 | * background scan. We consider only 11g/WMM stuff right now. |
| 1284 | */ |
| 1285 | if (ni->ni_associd != 0 && |
| 1286 | ((ic->ic_flags & IEEE80211_F_SCAN) == 0 || |
| 1287 | IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid))) { |
| 1288 | /* record tsf of last beacon */ |
| 1289 | memcpy(ni->ni_tstamp.data, scan.tstamp, |
| 1290 | sizeof(ni->ni_tstamp)); |
| 1291 | /* count beacon frame for s/w bmiss handling */ |
| 1292 | vap->iv_swbmiss_count++; |
| 1293 | vap->iv_bmiss_count = 0; |
| 1294 | if (ni->ni_erp != scan.erp) { |
| 1295 | IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC, |
| 1296 | wh->i_addr2, |
| 1297 | "erp change: was 0x%x, now 0x%x", |
| 1298 | ni->ni_erp, scan.erp); |
| 1299 | if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && |
| 1300 | (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION)) |
| 1301 | ic->ic_flags |= IEEE80211_F_USEPROT; |
| 1302 | else |
| 1303 | ic->ic_flags &= ~IEEE80211_F_USEPROT; |
| 1304 | ni->ni_erp = scan.erp; |
| 1305 | /* XXX statistic */ |
| 1306 | /* XXX driver notification */ |
| 1307 | } |
| 1308 | if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) { |
| 1309 | IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC, |
| 1310 | wh->i_addr2, |
| 1311 | "capabilities change: was 0x%x, now 0x%x", |
| 1312 | ni->ni_capinfo, scan.capinfo); |
| 1313 | /* |
| 1314 | * NB: we assume short preamble doesn't |
| 1315 | * change dynamically |
| 1316 | */ |
| 1317 | ieee80211_set_shortslottime(ic, |
| 1318 | IEEE80211_IS_CHAN_A(ic->ic_bsschan) || |
| 1319 | (scan.capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)); |
| 1320 | ni->ni_capinfo = (ni->ni_capinfo &~ IEEE80211_CAPINFO_SHORT_SLOTTIME) |
| 1321 | | (scan.capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME); |
| 1322 | /* XXX statistic */ |
| 1323 | } |
| 1324 | if (scan.wme != NULL && |
| 1325 | (ni->ni_flags & IEEE80211_NODE_QOS) && |
| 1326 | ieee80211_parse_wmeparams(vap, scan.wme, wh) > 0) |
| 1327 | ieee80211_wme_updateparams(vap); |
| 1328 | #ifdef IEEE80211_SUPPORT_SUPERG |
| 1329 | if (scan.ath != NULL) |
| 1330 | ieee80211_parse_athparams(ni, scan.ath, wh); |
| 1331 | #endif |
| 1332 | if (scan.htcap != NULL && scan.htinfo != NULL && |
| 1333 | (vap->iv_flags_ht & IEEE80211_FHT_HT)) { |
| 1334 | ieee80211_ht_updateparams(ni, |
| 1335 | scan.htcap, scan.htinfo); |
| 1336 | /* XXX state changes? */ |
| 1337 | } |
| 1338 | if (scan.tim != NULL) { |
| 1339 | struct ieee80211_tim_ie *tim = |
| 1340 | (struct ieee80211_tim_ie *) scan.tim; |
| 1341 | #if 0 |
| 1342 | int aid = IEEE80211_AID(ni->ni_associd); |
| 1343 | int ix = aid / NBBY; |
| 1344 | int min = tim->tim_bitctl &~ 1; |
| 1345 | int max = tim->tim_len + min - 4; |
| 1346 | if ((tim->tim_bitctl&1) || |
| 1347 | (min <= ix && ix <= max && |
| 1348 | isset(tim->tim_bitmap - min, aid))) { |
| 1349 | /* |
| 1350 | * XXX Do not let bg scan kick off |
| 1351 | * we are expecting data. |
| 1352 | */ |
| 1353 | ic->ic_lastdata = ticks; |
| 1354 | ieee80211_sta_pwrsave(vap, 0); |
| 1355 | } |
| 1356 | #endif |
| 1357 | ni->ni_dtim_count = tim->tim_count; |
| 1358 | ni->ni_dtim_period = tim->tim_period; |
| 1359 | } |
| 1360 | if (scan.csa != NULL && |
| 1361 | (vap->iv_flags & IEEE80211_F_DOTH)) |
| 1362 | ieee80211_parse_csaparams(vap, scan.csa, wh); |
| 1363 | else if (ic->ic_flags & IEEE80211_F_CSAPENDING) { |
| 1364 | /* |
| 1365 | * No CSA ie or 11h disabled, but a channel |
| 1366 | * switch is pending; drop out so we aren't |
| 1367 | * stuck in CSA state. If the AP really is |
| 1368 | * moving we'll get a beacon miss and scan. |
| 1369 | */ |
| 1370 | ieee80211_csa_cancelswitch(ic); |
| 1371 | } |
| 1372 | /* |
| 1373 | * If scanning, pass the info to the scan module. |
| 1374 | * Otherwise, check if it's the right time to do |
| 1375 | * a background scan. Background scanning must |
| 1376 | * be enabled and we must not be operating in the |
| 1377 | * turbo phase of dynamic turbo mode. Then, |
| 1378 | * it's been a while since the last background |
| 1379 | * scan and if no data frames have come through |
| 1380 | * recently, kick off a scan. Note that this |
| 1381 | * is the mechanism by which a background scan |
| 1382 | * is started _and_ continued each time we |
| 1383 | * return on-channel to receive a beacon from |
| 1384 | * our ap. |
| 1385 | */ |
| 1386 | if (ic->ic_flags & IEEE80211_F_SCAN) { |
| 1387 | ieee80211_add_scan(vap, &scan, wh, |
| 1388 | subtype, rssi, nf); |
| 1389 | } else if (contbgscan(vap)) { |
| 1390 | ieee80211_bg_scan(vap, 0); |
| 1391 | } else if (startbgscan(vap)) { |
| 1392 | vap->iv_stats.is_scan_bg++; |
| 1393 | #if 0 |
| 1394 | /* wakeup if we are sleeing */ |
| 1395 | ieee80211_set_pwrsave(vap, 0); |
| 1396 | #endif |
| 1397 | ieee80211_bg_scan(vap, 0); |
| 1398 | } |
| 1399 | return; |
| 1400 | } |
| 1401 | /* |
| 1402 | * If scanning, just pass information to the scan module. |
| 1403 | */ |
| 1404 | if (ic->ic_flags & IEEE80211_F_SCAN) { |
| 1405 | if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) { |
| 1406 | /* |
| 1407 | * Actively scanning a channel marked passive; |
| 1408 | * send a probe request now that we know there |
| 1409 | * is 802.11 traffic present. |
| 1410 | * |
| 1411 | * XXX check if the beacon we recv'd gives |
| 1412 | * us what we need and suppress the probe req |
| 1413 | */ |
| 1414 | ieee80211_probe_curchan(vap, 1); |
| 1415 | ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; |
| 1416 | } |
| 1417 | ieee80211_add_scan(vap, &scan, wh, subtype, rssi, nf); |
| 1418 | return; |
| 1419 | } |
| 1420 | break; |
| 1421 | } |
| 1422 | |
| 1423 | case IEEE80211_FC0_SUBTYPE_AUTH: { |
| 1424 | uint16_t algo, seq, status; |
| 1425 | /* |
| 1426 | * auth frame format |
| 1427 | * [2] algorithm |
| 1428 | * [2] sequence |
| 1429 | * [2] status |
| 1430 | * [tlv*] challenge |
| 1431 | */ |
| 1432 | IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return); |
| 1433 | algo = le16toh(*(uint16_t *)frm); |
| 1434 | seq = le16toh(*(uint16_t *)(frm + 2)); |
| 1435 | status = le16toh(*(uint16_t *)(frm + 4)); |
| 1436 | IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr2, |
| 1437 | "recv auth frame with algorithm %d seq %d", algo, seq); |
| 1438 | |
| 1439 | if (vap->iv_flags & IEEE80211_F_COUNTERM) { |
| 1440 | IEEE80211_DISCARD(vap, |
| 1441 | IEEE80211_MSG_AUTH | IEEE80211_MSG_CRYPTO, |
| 1442 | wh, "auth", "%s", "TKIP countermeasures enabled"); |
| 1443 | vap->iv_stats.is_rx_auth_countermeasures++; |
| 1444 | if (vap->iv_opmode == IEEE80211_M_HOSTAP) { |
| 1445 | ieee80211_send_error(ni, wh->i_addr2, |
| 1446 | IEEE80211_FC0_SUBTYPE_AUTH, |
| 1447 | IEEE80211_REASON_MIC_FAILURE); |
| 1448 | } |
| 1449 | return; |
| 1450 | } |
| 1451 | if (algo == IEEE80211_AUTH_ALG_SHARED) |
| 1452 | sta_auth_shared(ni, wh, frm + 6, efrm, rssi, nf, |
| 1453 | seq, status); |
| 1454 | else if (algo == IEEE80211_AUTH_ALG_OPEN) |
| 1455 | sta_auth_open(ni, wh, rssi, nf, seq, status); |
| 1456 | else { |
| 1457 | IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, |
| 1458 | wh, "auth", "unsupported alg %d", algo); |
| 1459 | vap->iv_stats.is_rx_auth_unsupported++; |
| 1460 | return; |
| 1461 | } |
| 1462 | break; |
| 1463 | } |
| 1464 | |
| 1465 | case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: |
| 1466 | case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: { |
| 1467 | uint16_t capinfo, associd; |
| 1468 | uint16_t status; |
| 1469 | |
| 1470 | if (vap->iv_state != IEEE80211_S_ASSOC) { |
| 1471 | vap->iv_stats.is_rx_mgtdiscard++; |
| 1472 | return; |
| 1473 | } |
| 1474 | |
| 1475 | /* |
| 1476 | * asresp frame format |
| 1477 | * [2] capability information |
| 1478 | * [2] status |
| 1479 | * [2] association ID |
| 1480 | * [tlv] supported rates |
| 1481 | * [tlv] extended supported rates |
| 1482 | * [tlv] WME |
| 1483 | * [tlv] HT capabilities |
| 1484 | * [tlv] HT info |
| 1485 | */ |
| 1486 | IEEE80211_VERIFY_LENGTH(efrm - frm, 6, return); |
| 1487 | ni = vap->iv_bss; |
| 1488 | capinfo = le16toh(*(uint16_t *)frm); |
| 1489 | frm += 2; |
| 1490 | status = le16toh(*(uint16_t *)frm); |
| 1491 | frm += 2; |
| 1492 | if (status != 0) { |
| 1493 | IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC, |
| 1494 | wh->i_addr2, "%sassoc failed (reason %d)", |
| 1495 | ISREASSOC(subtype) ? "re" : "", status); |
| 1496 | vap->iv_stats.is_rx_auth_fail++; /* XXX */ |
| 1497 | return; |
| 1498 | } |
| 1499 | associd = le16toh(*(uint16_t *)frm); |
| 1500 | frm += 2; |
| 1501 | |
| 1502 | rates = xrates = wme = htcap = htinfo = NULL; |
| 1503 | while (efrm - frm > 1) { |
| 1504 | IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return); |
| 1505 | switch (*frm) { |
| 1506 | case IEEE80211_ELEMID_RATES: |
| 1507 | rates = frm; |
| 1508 | break; |
| 1509 | case IEEE80211_ELEMID_XRATES: |
| 1510 | xrates = frm; |
| 1511 | break; |
| 1512 | case IEEE80211_ELEMID_HTCAP: |
| 1513 | htcap = frm; |
| 1514 | break; |
| 1515 | case IEEE80211_ELEMID_HTINFO: |
| 1516 | htinfo = frm; |
| 1517 | break; |
| 1518 | case IEEE80211_ELEMID_VENDOR: |
| 1519 | if (iswmeoui(frm)) |
| 1520 | wme = frm; |
| 1521 | else if (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) { |
| 1522 | /* |
| 1523 | * Accept pre-draft HT ie's if the |
| 1524 | * standard ones have not been seen. |
| 1525 | */ |
| 1526 | if (ishtcapoui(frm)) { |
| 1527 | if (htcap == NULL) |
| 1528 | htcap = frm; |
| 1529 | } else if (ishtinfooui(frm)) { |
| 1530 | if (htinfo == NULL) |
| 1531 | htcap = frm; |
| 1532 | } |
| 1533 | } |
| 1534 | /* XXX Atheros OUI support */ |
| 1535 | break; |
| 1536 | } |
| 1537 | frm += frm[1] + 2; |
| 1538 | } |
| 1539 | |
| 1540 | IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return); |
| 1541 | if (xrates != NULL) |
| 1542 | IEEE80211_VERIFY_ELEMENT(xrates, |
| 1543 | IEEE80211_RATE_MAXSIZE - rates[1], return); |
| 1544 | rate = ieee80211_setup_rates(ni, rates, xrates, |
| 1545 | IEEE80211_F_JOIN | |
| 1546 | IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | |
| 1547 | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); |
| 1548 | if (rate & IEEE80211_RATE_BASIC) { |
| 1549 | IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC, |
| 1550 | wh->i_addr2, |
| 1551 | "%sassoc failed (rate set mismatch)", |
| 1552 | ISREASSOC(subtype) ? "re" : ""); |
| 1553 | vap->iv_stats.is_rx_assoc_norate++; |
| 1554 | ieee80211_new_state(vap, IEEE80211_S_SCAN, |
| 1555 | IEEE80211_SCAN_FAIL_STATUS); |
| 1556 | return; |
| 1557 | } |
| 1558 | |
| 1559 | ni->ni_capinfo = capinfo; |
| 1560 | ni->ni_associd = associd; |
| 1561 | if (ni->ni_jointime == 0) |
| 1562 | ni->ni_jointime = time_second; |
| 1563 | if (wme != NULL && |
| 1564 | ieee80211_parse_wmeparams(vap, wme, wh) >= 0) { |
| 1565 | ni->ni_flags |= IEEE80211_NODE_QOS; |
| 1566 | ieee80211_wme_updateparams(vap); |
| 1567 | } else |
| 1568 | ni->ni_flags &= ~IEEE80211_NODE_QOS; |
| 1569 | /* |
| 1570 | * Setup HT state according to the negotiation. |
| 1571 | * |
| 1572 | * NB: shouldn't need to check if HT use is enabled but some |
| 1573 | * ap's send back HT ie's even when we don't indicate we |
| 1574 | * are HT capable in our AssocReq. |
| 1575 | */ |
| 1576 | if (htcap != NULL && htinfo != NULL && |
| 1577 | (vap->iv_flags_ht & IEEE80211_FHT_HT)) { |
| 1578 | ieee80211_ht_node_init(ni); |
| 1579 | ieee80211_ht_updateparams(ni, htcap, htinfo); |
| 1580 | ieee80211_setup_htrates(ni, htcap, |
| 1581 | IEEE80211_F_JOIN | IEEE80211_F_DOBRS); |
| 1582 | ieee80211_setup_basic_htrates(ni, htinfo); |
| 1583 | ieee80211_node_setuptxparms(ni); |
| 1584 | } else { |
| 1585 | #ifdef IEEE80211_SUPPORT_SUPERG |
| 1586 | if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_ATH)) |
| 1587 | ieee80211_ff_node_init(ni); |
| 1588 | #endif |
| 1589 | } |
| 1590 | /* |
| 1591 | * Configure state now that we are associated. |
| 1592 | * |
| 1593 | * XXX may need different/additional driver callbacks? |
| 1594 | */ |
| 1595 | if (IEEE80211_IS_CHAN_A(ic->ic_curchan) || |
| 1596 | (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) { |
| 1597 | ic->ic_flags |= IEEE80211_F_SHPREAMBLE; |
| 1598 | ic->ic_flags &= ~IEEE80211_F_USEBARKER; |
| 1599 | } else { |
| 1600 | ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; |
| 1601 | ic->ic_flags |= IEEE80211_F_USEBARKER; |
| 1602 | } |
| 1603 | ieee80211_set_shortslottime(ic, |
| 1604 | IEEE80211_IS_CHAN_A(ic->ic_curchan) || |
| 1605 | (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)); |
| 1606 | /* |
| 1607 | * Honor ERP protection. |
| 1608 | * |
| 1609 | * NB: ni_erp should zero for non-11g operation. |
| 1610 | */ |
| 1611 | if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && |
| 1612 | (ni->ni_erp & IEEE80211_ERP_USE_PROTECTION)) |
| 1613 | ic->ic_flags |= IEEE80211_F_USEPROT; |
| 1614 | else |
| 1615 | ic->ic_flags &= ~IEEE80211_F_USEPROT; |
| 1616 | IEEE80211_NOTE_MAC(vap, |
| 1617 | IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, wh->i_addr2, |
| 1618 | "%sassoc success at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s", |
| 1619 | ISREASSOC(subtype) ? "re" : "", |
| 1620 | IEEE80211_NODE_AID(ni), |
| 1621 | ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long", |
| 1622 | ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long", |
| 1623 | ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "", |
| 1624 | ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "", |
| 1625 | ni->ni_flags & IEEE80211_NODE_HT ? |
| 1626 | (ni->ni_chw == 40 ? ", HT40" : ", HT20") : "", |
| 1627 | ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "", |
| 1628 | ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" : |
| 1629 | ni->ni_flags & IEEE80211_NODE_MIMO_PS ? " (+SMPS)" : "", |
| 1630 | ni->ni_flags & IEEE80211_NODE_RIFS ? " (+RIFS)" : "", |
| 1631 | IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF) ? |
| 1632 | ", fast-frames" : "", |
| 1633 | IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_TURBOP) ? |
| 1634 | ", turbo" : "" |
| 1635 | ); |
| 1636 | ieee80211_new_state(vap, IEEE80211_S_RUN, subtype); |
| 1637 | break; |
| 1638 | } |
| 1639 | |
| 1640 | case IEEE80211_FC0_SUBTYPE_DEAUTH: { |
| 1641 | uint16_t reason; |
| 1642 | |
| 1643 | if (vap->iv_state == IEEE80211_S_SCAN) { |
| 1644 | vap->iv_stats.is_rx_mgtdiscard++; |
| 1645 | return; |
| 1646 | } |
| 1647 | if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr)) { |
| 1648 | /* NB: can happen when in promiscuous mode */ |
| 1649 | vap->iv_stats.is_rx_mgtdiscard++; |
| 1650 | break; |
| 1651 | } |
| 1652 | |
| 1653 | /* |
| 1654 | * deauth frame format |
| 1655 | * [2] reason |
| 1656 | */ |
| 1657 | IEEE80211_VERIFY_LENGTH(efrm - frm, 2, return); |
| 1658 | reason = le16toh(*(uint16_t *)frm); |
| 1659 | |
| 1660 | vap->iv_stats.is_rx_deauth++; |
| 1661 | vap->iv_stats.is_rx_deauth_code = reason; |
| 1662 | IEEE80211_NODE_STAT(ni, rx_deauth); |
| 1663 | |
| 1664 | IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, |
| 1665 | "recv deauthenticate (reason %d)", reason); |
| 1666 | ieee80211_new_state(vap, IEEE80211_S_AUTH, |
| 1667 | (reason << 8) | IEEE80211_FC0_SUBTYPE_DEAUTH); |
| 1668 | break; |
| 1669 | } |
| 1670 | |
| 1671 | case IEEE80211_FC0_SUBTYPE_DISASSOC: { |
| 1672 | uint16_t reason; |
| 1673 | |
| 1674 | if (vap->iv_state != IEEE80211_S_RUN && |
| 1675 | vap->iv_state != IEEE80211_S_ASSOC && |
| 1676 | vap->iv_state != IEEE80211_S_AUTH) { |
| 1677 | vap->iv_stats.is_rx_mgtdiscard++; |
| 1678 | return; |
| 1679 | } |
| 1680 | if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr)) { |
| 1681 | /* NB: can happen when in promiscuous mode */ |
| 1682 | vap->iv_stats.is_rx_mgtdiscard++; |
| 1683 | break; |
| 1684 | } |
| 1685 | |
| 1686 | /* |
| 1687 | * disassoc frame format |
| 1688 | * [2] reason |
| 1689 | */ |
| 1690 | IEEE80211_VERIFY_LENGTH(efrm - frm, 2, return); |
| 1691 | reason = le16toh(*(uint16_t *)frm); |
| 1692 | |
| 1693 | vap->iv_stats.is_rx_disassoc++; |
| 1694 | vap->iv_stats.is_rx_disassoc_code = reason; |
| 1695 | IEEE80211_NODE_STAT(ni, rx_disassoc); |
| 1696 | |
| 1697 | IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, |
| 1698 | "recv disassociate (reason %d)", reason); |
| 1699 | ieee80211_new_state(vap, IEEE80211_S_ASSOC, 0); |
| 1700 | break; |
| 1701 | } |
| 1702 | |
| 1703 | case IEEE80211_FC0_SUBTYPE_ACTION: |
| 1704 | if (vap->iv_state == IEEE80211_S_RUN) { |
| 1705 | if (ieee80211_parse_action(ni, m0) == 0) |
| 1706 | ic->ic_recv_action(ni, wh, frm, efrm); |
| 1707 | } else |
| 1708 | vap->iv_stats.is_rx_mgtdiscard++; |
| 1709 | break; |
| 1710 | |
| 1711 | case IEEE80211_FC0_SUBTYPE_PROBE_REQ: |
| 1712 | case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: |
| 1713 | case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: |
| 1714 | vap->iv_stats.is_rx_mgtdiscard++; |
| 1715 | return; |
| 1716 | default: |
| 1717 | IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, |
| 1718 | wh, "mgt", "subtype 0x%x not handled", subtype); |
| 1719 | vap->iv_stats.is_rx_badsubtype++; |
| 1720 | break; |
| 1721 | } |
| 1722 | #undef ISREASSOC |
| 1723 | #undef ISPROBE |
| 1724 | } |
| 1725 | |
| 1726 | static void |
| 1727 | sta_recv_ctl(struct ieee80211_node *ni, struct mbuf *m0, int subtype) |
| 1728 | { |
| 1729 | } |