| | 2293 | static void |
|---|
| | 2294 | ieee80211_doth_cancel_cs(struct ieee80211vap *vap) |
|---|
| | 2295 | { |
|---|
| | 2296 | del_timer(&vap->iv_csa_timer); |
|---|
| | 2297 | if (vap->iv_csa_jiffies) |
|---|
| | 2298 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2299 | "channel switch cancelled (was: to %u in %u " |
|---|
| | 2300 | "tbtt, mode %u)\n", vap->iv_csa_chan->ic_ieee, |
|---|
| | 2301 | vap->iv_csa_count, vap->iv_csa_mode); |
|---|
| | 2302 | vap->iv_csa_jiffies = 0; |
|---|
| | 2303 | } |
|---|
| | 2304 | |
|---|
| | 2305 | static void |
|---|
| | 2306 | ieee80211_doth_switch_channel(struct ieee80211vap *vap) |
|---|
| | 2307 | { |
|---|
| | 2308 | struct ieee80211com *ic = vap->iv_ic; |
|---|
| | 2309 | |
|---|
| | 2310 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2311 | "%s: Channel switch to %d NOW!\n", |
|---|
| | 2312 | __func__, vap->iv_csa_chan->ic_ieee); |
|---|
| | 2313 | #if 0 |
|---|
| | 2314 | /* XXX does not belong here? */ |
|---|
| | 2315 | /* XXX doesn't stop management frames */ |
|---|
| | 2316 | /* XXX who restarts the queue? */ |
|---|
| | 2317 | /* NB: for now, error here is non-catastrophic. |
|---|
| | 2318 | * in the future we may need to ensure we |
|---|
| | 2319 | * stop xmit on this channel. |
|---|
| | 2320 | */ |
|---|
| | 2321 | netif_stop_queue(ic->ic_dev); |
|---|
| | 2322 | #endif |
|---|
| | 2323 | |
|---|
| | 2324 | vap->iv_csa_jiffies = 0; /* supress "cancel" msg */ |
|---|
| | 2325 | ieee80211_doth_cancel_cs(vap); |
|---|
| | 2326 | |
|---|
| | 2327 | ic->ic_prevchan = ic->ic_curchan; |
|---|
| | 2328 | ic->ic_curchan = ic->ic_bsschan = vap->iv_csa_chan; |
|---|
| | 2329 | ic->ic_set_channel(ic); |
|---|
| | 2330 | } |
|---|
| | 2331 | |
|---|
| | 2332 | static void |
|---|
| | 2333 | ieee80211_doth_switch_channel_tmr(unsigned long arg) |
|---|
| | 2334 | { |
|---|
| | 2335 | struct ieee80211vap *vap = (struct ieee80211vap *)arg; |
|---|
| | 2336 | ieee80211_doth_switch_channel(vap); |
|---|
| | 2337 | } |
|---|
| | 2338 | |
|---|
| 2314 | | tbtt = frm[4]; |
|---|
| 2315 | | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| 2316 | | "%s: channel switch to %d in %d tbtt\n", __func__, chan, tbtt); |
|---|
| 2317 | | if (tbtt <= 1) { |
|---|
| 2318 | | struct ieee80211_channel *c; |
|---|
| 2319 | | |
|---|
| 2320 | | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| 2321 | | "%s: Channel switch to %d NOW!\n", __func__, chan); |
|---|
| 2322 | | #if 0 |
|---|
| 2323 | | /* XXX does not belong here? */ |
|---|
| 2324 | | /* XXX doesn't stop management frames */ |
|---|
| 2325 | | /* XXX who restarts the queue? */ |
|---|
| 2326 | | /* NB: for now, error here is non-catastrophic. |
|---|
| 2327 | | * in the future we may need to ensure we |
|---|
| 2328 | | * stop xmit on this channel. |
|---|
| 2329 | | */ |
|---|
| 2330 | | netif_stop_queue(ic->ic_dev); |
|---|
| 2331 | | #endif |
|---|
| 2332 | | if ((c = ieee80211_doth_findchan(vap, chan)) == NULL) { |
|---|
| 2333 | | /* XXX something wrong */ |
|---|
| 2334 | | IEEE80211_DISCARD_IE(vap, |
|---|
| | 2375 | |
|---|
| | 2376 | if ((c = ieee80211_doth_findchan(vap, csa_ie->csa_chan)) == NULL) { |
|---|
| | 2377 | /* XXX something wrong */ |
|---|
| | 2378 | IEEE80211_DISCARD_IE(vap, |
|---|
| 2337 | | "channel %u lookup failed", chan); |
|---|
| | 2381 | "channel %u lookup failed", csa_ie->csa_chan); |
|---|
| | 2382 | return -1; |
|---|
| | 2383 | } |
|---|
| | 2384 | |
|---|
| | 2385 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2386 | "%s: channel switch to %u in %u tbtt (mode %u) announced\n", |
|---|
| | 2387 | __func__, csa_ie->csa_chan, csa_ie->csa_count, |
|---|
| | 2388 | csa_ie->csa_mode); |
|---|
| | 2389 | |
|---|
| | 2390 | if (vap->iv_csa_jiffies) { |
|---|
| | 2391 | /* CSA was received recently */ |
|---|
| | 2392 | if (c != vap->iv_csa_chan) { |
|---|
| | 2393 | /* XXX abuse? */ |
|---|
| | 2394 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2395 | "%s: channel switch channel " |
|---|
| | 2396 | "changed from %u to %u!\n", __func__, |
|---|
| | 2397 | vap->iv_csa_chan->ic_ieee, |
|---|
| | 2398 | csa_ie->csa_chan); |
|---|
| | 2399 | |
|---|
| | 2400 | if (vap->iv_csa_count > IEEE80211_CSA_PROTECTION_PERIOD) |
|---|
| | 2401 | ieee80211_doth_cancel_cs(vap); |
|---|
| 2340 | | ic->ic_prevchan = ic->ic_curchan; |
|---|
| 2341 | | ic->ic_curchan = ic->ic_bsschan = c; |
|---|
| 2342 | | ic->ic_set_channel(ic); |
|---|
| 2343 | | return 1; |
|---|
| 2344 | | } |
|---|
| | 2404 | |
|---|
| | 2405 | if (csa_ie->csa_mode != vap->iv_csa_mode) { |
|---|
| | 2406 | /* Can be abused, but with no (to little) impact. */ |
|---|
| | 2407 | |
|---|
| | 2408 | /* CS mode change has no influence on our actions since |
|---|
| | 2409 | * we don't respect cs modes at all (yet). Complain and |
|---|
| | 2410 | * forget. */ |
|---|
| | 2411 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2412 | "%s: channel switch mode changed from " |
|---|
| | 2413 | "%u to %u!\n", __func__, |
|---|
| | 2414 | vap->iv_csa_mode, csa_ie->csa_mode); |
|---|
| | 2415 | } |
|---|
| | 2416 | |
|---|
| | 2417 | if (csa_ie->csa_count >= vap->iv_csa_count) { |
|---|
| | 2418 | /* XXX abuse? what for? */ |
|---|
| | 2419 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2420 | "%s: channel switch count didn't " |
|---|
| | 2421 | "decrease (%u -> %u)!\n", __func__, |
|---|
| | 2422 | vap->iv_csa_count, csa_ie->csa_count); |
|---|
| | 2423 | return 0; |
|---|
| | 2424 | } |
|---|
| | 2425 | |
|---|
| | 2426 | { |
|---|
| | 2427 | u_int32_t elapsed = IEEE80211_JIFFIES_TO_TU( |
|---|
| | 2428 | jiffies - vap->iv_csa_jiffies); |
|---|
| | 2429 | u_int32_t cnt_diff = vap->iv_csa_count - |
|---|
| | 2430 | csa_ie->csa_count; |
|---|
| | 2431 | u_int32_t expected = ni->ni_intval * cnt_diff; |
|---|
| | 2432 | int32_t delta = elapsed - expected; |
|---|
| | 2433 | if (delta < 0) |
|---|
| | 2434 | delta = -delta; |
|---|
| | 2435 | if (delta > IEEE80211_CSA_SANITY_THRESHOLD) { |
|---|
| | 2436 | /* XXX abuse? for now, it's safer to cancel CS |
|---|
| | 2437 | * than to follow it blindly */ |
|---|
| | 2438 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2439 | "%s: %u.%02u bintvals elapsed, " |
|---|
| | 2440 | "but count dropped by %u (delta" |
|---|
| | 2441 | " = %u TUs)\n", __func__, |
|---|
| | 2442 | elapsed / ni->ni_intval, |
|---|
| | 2443 | elapsed * 100 / ni->ni_intval |
|---|
| | 2444 | % 100, cnt_diff, delta); |
|---|
| | 2445 | |
|---|
| | 2446 | ieee80211_doth_cancel_cs(vap); |
|---|
| | 2447 | return 0; |
|---|
| | 2448 | } |
|---|
| | 2449 | } |
|---|
| | 2450 | |
|---|
| | 2451 | vap->iv_csa_count = csa_ie->csa_count; |
|---|
| | 2452 | mod_timer(&vap->iv_csa_timer, jiffies + |
|---|
| | 2453 | IEEE80211_TU_TO_JIFFIES(vap->iv_csa_count |
|---|
| | 2454 | * ni->ni_intval + 10)); |
|---|
| | 2455 | } else { |
|---|
| | 2456 | /* CSA wasn't received recently, so this is the first one in |
|---|
| | 2457 | * the sequence. */ |
|---|
| | 2458 | |
|---|
| | 2459 | if (csa_ie->csa_count < IEEE80211_CSA_PROTECTION_PERIOD) { |
|---|
| | 2460 | /* XXX abuse? */ |
|---|
| | 2461 | IEEE80211_DISCARD_IE(vap, |
|---|
| | 2462 | IEEE80211_MSG_ELEMID | |
|---|
| | 2463 | IEEE80211_MSG_DOTH, |
|---|
| | 2464 | wh, "channel switch", |
|---|
| | 2465 | "initial announcement: channel switch" |
|---|
| | 2466 | " would occur too soon (in %u tbtt)", |
|---|
| | 2467 | csa_ie->csa_count); |
|---|
| | 2468 | return 0; |
|---|
| | 2469 | } |
|---|
| | 2470 | |
|---|
| | 2471 | vap->iv_csa_mode = csa_ie->csa_mode; |
|---|
| | 2472 | vap->iv_csa_count = csa_ie->csa_count; |
|---|
| | 2473 | vap->iv_csa_chan = c; |
|---|
| | 2474 | |
|---|
| | 2475 | vap->iv_csa_timer.function = ieee80211_doth_switch_channel_tmr; |
|---|
| | 2476 | vap->iv_csa_timer.data = (unsigned long)vap; |
|---|
| | 2477 | vap->iv_csa_timer.expires = jiffies + IEEE80211_TU_TO_JIFFIES( |
|---|
| | 2478 | vap->iv_csa_count * ni->ni_intval + 10); |
|---|
| | 2479 | add_timer(&vap->iv_csa_timer); |
|---|
| | 2480 | } |
|---|
| | 2481 | |
|---|
| | 2482 | vap->iv_csa_jiffies = jiffies; |
|---|
| | 2483 | |
|---|
| | 2484 | if (vap->iv_csa_count <= 1) |
|---|
| | 2485 | ieee80211_doth_switch_channel(vap); |
|---|
| | 2486 | |
|---|