| | 2240 | static void |
|---|
| | 2241 | ieee80211_doth_cancel_cs(struct ieee80211vap *vap) |
|---|
| | 2242 | { |
|---|
| | 2243 | del_timer(&vap->iv_csa_timer); |
|---|
| | 2244 | if (vap->iv_csa_jiffies) |
|---|
| | 2245 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2246 | "channel switch cancelled (was: to %u in %u " |
|---|
| | 2247 | "tbtt, mode %u)\n", vap->iv_csa_chan->ic_ieee, |
|---|
| | 2248 | vap->iv_csa_count, vap->iv_csa_mode); |
|---|
| | 2249 | vap->iv_csa_jiffies = 0; |
|---|
| | 2250 | } |
|---|
| | 2251 | |
|---|
| | 2252 | static void |
|---|
| | 2253 | ieee80211_doth_switch_channel(struct ieee80211vap *vap) |
|---|
| | 2254 | { |
|---|
| | 2255 | struct ieee80211com *ic = vap->iv_ic; |
|---|
| | 2256 | |
|---|
| | 2257 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2258 | "%s: Channel switch to %d NOW!\n", |
|---|
| | 2259 | __func__, vap->iv_csa_chan->ic_ieee); |
|---|
| | 2260 | #if 0 |
|---|
| | 2261 | /* XXX does not belong here? */ |
|---|
| | 2262 | /* XXX doesn't stop management frames */ |
|---|
| | 2263 | /* XXX who restarts the queue? */ |
|---|
| | 2264 | /* NB: for now, error here is non-catastrophic. |
|---|
| | 2265 | * in the future we may need to ensure we |
|---|
| | 2266 | * stop xmit on this channel. |
|---|
| | 2267 | */ |
|---|
| | 2268 | netif_stop_queue(ic->ic_dev); |
|---|
| | 2269 | #endif |
|---|
| | 2270 | |
|---|
| | 2271 | vap->iv_csa_jiffies = 0; /* supress "cancel" msg */ |
|---|
| | 2272 | ieee80211_doth_cancel_cs(vap); |
|---|
| | 2273 | |
|---|
| | 2274 | ic->ic_prevchan = ic->ic_curchan; |
|---|
| | 2275 | ic->ic_curchan = ic->ic_bsschan = vap->iv_csa_chan; |
|---|
| | 2276 | ic->ic_set_channel(ic); |
|---|
| | 2277 | } |
|---|
| | 2278 | |
|---|
| | 2279 | static void |
|---|
| | 2280 | ieee80211_doth_switch_channel_tmr(unsigned long arg) |
|---|
| | 2281 | { |
|---|
| | 2282 | struct ieee80211vap *vap = (struct ieee80211vap *)arg; |
|---|
| | 2283 | ieee80211_doth_switch_channel(vap); |
|---|
| | 2284 | } |
|---|
| | 2285 | |
|---|
| 2267 | | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| 2268 | | "%s: Channel switch to %d NOW!\n", __func__, chan); |
|---|
| 2269 | | #if 0 |
|---|
| 2270 | | /* XXX does not belong here? */ |
|---|
| 2271 | | /* XXX doesn't stop management frames */ |
|---|
| 2272 | | /* XXX who restarts the queue? */ |
|---|
| 2273 | | /* NB: for now, error here is non-catastrophic. |
|---|
| 2274 | | * in the future we may need to ensure we |
|---|
| 2275 | | * stop xmit on this channel. |
|---|
| 2276 | | */ |
|---|
| 2277 | | netif_stop_queue(ic->ic_dev); |
|---|
| 2278 | | #endif |
|---|
| 2279 | | if ((c = ieee80211_doth_findchan(vap, chan)) == NULL) { |
|---|
| 2280 | | /* XXX something wrong */ |
|---|
| 2281 | | IEEE80211_DISCARD_IE(vap, |
|---|
| | 2323 | if ((c = ieee80211_doth_findchan(vap, csa_ie->csa_chan)) == NULL) { |
|---|
| | 2324 | /* XXX something wrong */ |
|---|
| | 2325 | IEEE80211_DISCARD_IE(vap, |
|---|
| 2284 | | "channel %u lookup failed", chan); |
|---|
| | 2328 | "channel %u lookup failed", csa_ie->csa_chan); |
|---|
| | 2329 | return -1; |
|---|
| | 2330 | } |
|---|
| | 2331 | |
|---|
| | 2332 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2333 | "%s: channel switch to %u in %u tbtt (mode %u) announced\n", |
|---|
| | 2334 | __func__, csa_ie->csa_chan, csa_ie->csa_count, |
|---|
| | 2335 | csa_ie->csa_mode); |
|---|
| | 2336 | |
|---|
| | 2337 | if (vap->iv_csa_jiffies) { |
|---|
| | 2338 | /* CSA was received recently */ |
|---|
| | 2339 | if (c != vap->iv_csa_chan) { |
|---|
| | 2340 | /* XXX abuse? */ |
|---|
| | 2341 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2342 | "%s: channel switch channel " |
|---|
| | 2343 | "changed from %u to %u!\n", __func__, |
|---|
| | 2344 | vap->iv_csa_chan->ic_ieee, |
|---|
| | 2345 | csa_ie->csa_chan); |
|---|
| | 2346 | |
|---|
| | 2347 | if (vap->iv_csa_count > IEEE80211_CSA_PROTECTION_PERIOD) |
|---|
| | 2348 | ieee80211_doth_cancel_cs(vap); |
|---|
| 2287 | | ic->ic_prevchan = ic->ic_curchan; |
|---|
| 2288 | | ic->ic_curchan = ic->ic_bsschan = c; |
|---|
| 2289 | | ic->ic_set_channel(ic); |
|---|
| 2290 | | return 1; |
|---|
| | 2351 | |
|---|
| | 2352 | if (csa_ie->csa_mode != vap->iv_csa_mode) { |
|---|
| | 2353 | /* Can be abused, but with no (to little) impact. */ |
|---|
| | 2354 | |
|---|
| | 2355 | /* CS mode change has no influence on our actions since |
|---|
| | 2356 | * we don't respect cs modes at all (yet). Complain and |
|---|
| | 2357 | * forget. */ |
|---|
| | 2358 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2359 | "%s: channel switch mode changed from " |
|---|
| | 2360 | "%u to %u!\n", __func__, |
|---|
| | 2361 | vap->iv_csa_mode, csa_ie->csa_mode); |
|---|
| | 2362 | } |
|---|
| | 2363 | |
|---|
| | 2364 | if (csa_ie->csa_count >= vap->iv_csa_count) { |
|---|
| | 2365 | /* XXX abuse? what for? */ |
|---|
| | 2366 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2367 | "%s: channel switch count didn't " |
|---|
| | 2368 | "decrease (%u -> %u)!\n", __func__, |
|---|
| | 2369 | vap->iv_csa_count, csa_ie->csa_count); |
|---|
| | 2370 | return 0; |
|---|
| | 2371 | } |
|---|
| | 2372 | |
|---|
| | 2373 | { |
|---|
| | 2374 | u_int32_t elapsed = IEEE80211_JIFFIES_TO_TU( |
|---|
| | 2375 | jiffies - vap->iv_csa_jiffies); |
|---|
| | 2376 | u_int32_t cnt_diff = vap->iv_csa_count - |
|---|
| | 2377 | csa_ie->csa_count; |
|---|
| | 2378 | u_int32_t expected = ni->ni_intval * cnt_diff; |
|---|
| | 2379 | int32_t delta = elapsed - expected; |
|---|
| | 2380 | if (delta < 0) |
|---|
| | 2381 | delta = -delta; |
|---|
| | 2382 | if (delta > IEEE80211_CSA_SANITY_THRESHOLD) { |
|---|
| | 2383 | /* XXX abuse? for now, it's safer to cancel CS |
|---|
| | 2384 | * than to follow it blindly */ |
|---|
| | 2385 | IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, |
|---|
| | 2386 | "%s: %u.%02u bintvals elapsed, " |
|---|
| | 2387 | "but count dropped by %u (delta" |
|---|
| | 2388 | " = %u TUs)\n", __func__, |
|---|
| | 2389 | elapsed / ni->ni_intval, |
|---|
| | 2390 | elapsed * 100 / ni->ni_intval |
|---|
| | 2391 | % 100, cnt_diff, delta); |
|---|
| | 2392 | |
|---|
| | 2393 | ieee80211_doth_cancel_cs(vap); |
|---|
| | 2394 | return 0; |
|---|
| | 2395 | } |
|---|
| | 2396 | } |
|---|
| | 2397 | |
|---|
| | 2398 | vap->iv_csa_count = csa_ie->csa_count; |
|---|
| | 2399 | mod_timer(&vap->iv_csa_timer, jiffies + |
|---|
| | 2400 | IEEE80211_TU_TO_JIFFIES(vap->iv_csa_count |
|---|
| | 2401 | * ni->ni_intval + 10)); |
|---|
| | 2402 | } else { |
|---|
| | 2403 | /* CSA wasn't received recently, so this is the first one in |
|---|
| | 2404 | * the sequence. */ |
|---|
| | 2405 | |
|---|
| | 2406 | if (csa_ie->csa_count < IEEE80211_CSA_PROTECTION_PERIOD) { |
|---|
| | 2407 | /* XXX abuse? */ |
|---|
| | 2408 | IEEE80211_DISCARD_IE(vap, |
|---|
| | 2409 | IEEE80211_MSG_ELEMID | |
|---|
| | 2410 | IEEE80211_MSG_DOTH, |
|---|
| | 2411 | wh, "channel switch", |
|---|
| | 2412 | "initial announcement: channel switch" |
|---|
| | 2413 | " would occur too soon (in %u tbtt)", |
|---|
| | 2414 | csa_ie->csa_count); |
|---|
| | 2415 | return 0; |
|---|
| | 2416 | } |
|---|
| | 2417 | |
|---|
| | 2418 | vap->iv_csa_mode = csa_ie->csa_mode; |
|---|
| | 2419 | vap->iv_csa_count = csa_ie->csa_count; |
|---|
| | 2420 | vap->iv_csa_chan = c; |
|---|
| | 2421 | |
|---|
| | 2422 | vap->iv_csa_timer.function = ieee80211_doth_switch_channel_tmr; |
|---|
| | 2423 | vap->iv_csa_timer.data = (unsigned long)vap; |
|---|
| | 2424 | vap->iv_csa_timer.expires = jiffies + IEEE80211_TU_TO_JIFFIES( |
|---|
| | 2425 | vap->iv_csa_count * ni->ni_intval + 10); |
|---|
| | 2426 | add_timer(&vap->iv_csa_timer); |
|---|