Ticket #963: 009-csa_ie_handling_fix.diff

File 009-csa_ie_handling_fix.diff, 11.0 kB (added by xmxwx@asn.pl, 2 years ago)
  • madwifi/net80211/ieee80211.h

    old new  
    363363        u_int8_t country_triplet[IEEE80211_COUNTRY_MAX_TRIPLETS * 3]; 
    364364} __packed; 
    365365 
     366/* 
     367 * Channel Switch Announcement information element. 
     368 */ 
     369struct ieee80211_ie_csa { 
     370        u_int8_t csa_id;        /* IEEE80211_ELEMID_CHANSWITCHANN */ 
     371        u_int8_t csa_len;       /* == 3 */ 
     372        u_int8_t csa_mode;      /* Channel Switch Mode: 1 == stop transmission until CS */ 
     373        u_int8_t csa_chan;      /* New Channel Number */ 
     374        u_int8_t csa_count;     /* TBTTs until Channel Switch happens */ 
     375} __packed; 
     376 
     377/* minimal Channel Switch Count in the initial announcement */ 
     378#define IEEE80211_CSA_PROTECTION_PERIOD 3 
     379 
     380/* maximum allowed deviance of measurement of intervals between CSA in Beacons */ 
     381#define IEEE80211_CSA_SANITY_THRESHOLD 100     
     382 
     383 
    366384/* does frame have QoS sequence control data */ 
    367385#define IEEE80211_QOS_HAS_SEQ(wh) \ 
    368386        (((wh)->i_fc[0] & \ 
  • madwifi/net80211/ieee80211_scan.h

    old new  
    138138        u_int8_t *ssid; 
    139139        u_int8_t *rates; 
    140140        u_int8_t *xrates; 
    141         u_int8_t *doth
     141        u_int8_t *csa
    142142        u_int8_t *wpa; 
    143143        u_int8_t *rsn; 
    144144        u_int8_t *wme; 
  • madwifi/net80211/ieee80211_input.c

    old new  
    22372237        return c; 
    22382238} 
    22392239 
     2240static void 
     2241ieee80211_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 
     2252static void 
     2253ieee80211_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 
     2279static void 
     2280ieee80211_doth_switch_channel_tmr(unsigned long arg) 
     2281{ 
     2282        struct ieee80211vap *vap = (struct ieee80211vap *)arg; 
     2283        ieee80211_doth_switch_channel(vap); 
     2284} 
     2285 
    22402286static int 
    2241 ieee80211_parse_dothparams(struct ieee80211vap *vap, u_int8_t *frm, 
     2287ieee80211_parse_csaie(struct ieee80211_node *ni, u_int8_t *frm, 
    22422288        const struct ieee80211_frame *wh) 
    22432289{ 
     2290        struct ieee80211vap *vap = ni->ni_vap; 
    22442291        struct ieee80211com *ic = vap->iv_ic; 
    2245         u_int len = frm[1]
    2246         u_int8_t chan, tbtt
     2292        struct ieee80211_channel *c
     2293        struct ieee80211_ie_csa *csa_ie = (struct ieee80211_ie_csa *)frm
    22472294 
    2248         if (len < 4 - 2) {              /* XXX ie struct definition */ 
     2295        if (!frm) { 
     2296                /* we had CS underway but now we got Beacon without CSA IE */ 
     2297                /* XXX abuse? */ 
     2298 
     2299                IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, 
     2300                                "%s: channel switch is scheduled, but we got " 
     2301                                "Beacon without CSA IE!\n", __func__); 
     2302 
     2303                ieee80211_doth_cancel_cs(vap); 
     2304                return 0; 
     2305        } 
     2306 
     2307        if (csa_ie->csa_len != 3) { 
    22492308                IEEE80211_DISCARD_IE(vap, 
    22502309                        IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH, 
    2251                         wh, "channel switch", "too short, len %u", len); 
     2310                        wh, "channel switch", "invalid length %u", 
     2311                        csa_ie->csa_len); 
    22522312                return -1; 
    22532313        } 
    2254         chan = frm[3]; 
    2255         if (isclr(ic->ic_chan_avail, chan)) { 
     2314 
     2315        if (isclr(ic->ic_chan_avail, csa_ie->csa_chan)) { 
    22562316                IEEE80211_DISCARD_IE(vap, 
    22572317                        IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH, 
    2258                         wh, "channel switch", "invalid channel %u", chan); 
     2318                        wh, "channel switch", "invalid channel %u",  
     2319                        csa_ie->csa_chan); 
    22592320                return -1; 
    22602321        } 
    2261         tbtt = frm[4]; 
    2262         IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH, 
    2263                 "%s: channel switch to %d in %d tbtt\n", __func__, chan, tbtt); 
    2264         if (tbtt <= 1) { 
    2265                 struct ieee80211_channel *c; 
    22662322 
    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, 
    22822326                                IEEE80211_MSG_ELEMID | IEEE80211_MSG_DOTH, 
    22832327                                wh, "channel switch", 
    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); 
    22852349                        return 0; 
    22862350                } 
    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); 
    22912427        } 
     2428 
     2429        vap->iv_csa_jiffies = jiffies; 
     2430 
     2431        if (vap->iv_csa_count <= 1) 
     2432                ieee80211_doth_switch_channel(vap); 
     2433 
    22922434        return 0; 
    22932435} 
    22942436 
     
    24852627                                break; 
    24862628                        case IEEE80211_ELEMID_CHANSWITCHANN: 
    24872629                                if (ic->ic_flags & IEEE80211_F_DOTH) 
    2488                                         scan.doth = frm; 
     2630                                        scan.csa = frm; 
    24892631                                break; 
    24902632                        default: 
    24912633                                IEEE80211_DISCARD_IE(vap, IEEE80211_MSG_ELEMID, 
     
    26282770                                ni->ni_flags &= ~IEEE80211_NODE_UAPSD; 
    26292771                        if (scan.ath != NULL) 
    26302772                                ieee80211_parse_athParams(ni, scan.ath); 
    2631                         if (scan.doth != NULL
    2632                                 ieee80211_parse_dothparams(vap, scan.doth, wh); 
     2773                        if (scan.csa != NULL || vap->iv_csa_jiffies
     2774                                ieee80211_parse_csaie(ni, scan.csa, wh); 
    26332775                        if (scan.tim != NULL) { 
    26342776                                /* 
    26352777                                 * Check the TIM. For now we drop out of 
  • madwifi/net80211/ieee80211_var.h

    old new  
    8787#define IEEE80211_MS_TO_TU(x)   (((x) * 1000) / 1024) 
    8888#define IEEE80211_TU_TO_MS(x)   (((x) * 1024) / 1000) 
    8989#define IEEE80211_TU_TO_JIFFIES(x) ((IEEE80211_TU_TO_MS(x) * HZ) / 1000) 
     90#define IEEE80211_JIFFIES_TO_TU(x) IEEE80211_MS_TO_TU((x) * 1000 / HZ) 
    9091 
    9192#define IEEE80211_PWRCONSTRAINT_VAL(ic) \ 
    9293        (((ic)->ic_bsschan->ic_maxregpower > (ic)->ic_curchanmaxpwr) ? \ 
     
    341342        u_int iv_scanvalid;                     /* scan cache valid threshold */ 
    342343        struct ieee80211_roam iv_roam;          /* sta-mode roaming state */ 
    343344 
     345        u_int32_t iv_csa_jiffies;               /* last csa recv jiffies */ 
     346        u_int8_t iv_csa_count;                  /* last csa count */ 
     347        struct ieee80211_channel *iv_csa_chan;  /* last csa channel */ 
     348        u_int8_t iv_csa_mode;                   /* last csa mode */ 
     349        struct timer_list iv_csa_timer;         /* csa timer */ 
    344350        u_int32_t *iv_aid_bitmap;               /* association id map */ 
    345351        u_int16_t iv_max_aid; 
    346352        u_int16_t iv_sta_assoc;                 /* stations associated */ 
  • madwifi/net80211/ieee80211_proto.c

    old new  
    125125        init_timer(&vap->iv_mgtsend); 
    126126        init_timer(&vap->iv_xrvapstart); 
    127127        init_timer(&vap->iv_swbmiss); 
     128        init_timer(&vap->iv_csa_timer); 
    128129        vap->iv_mgtsend.function = ieee80211_tx_timeout; 
    129130        vap->iv_mgtsend.data = (unsigned long) vap; 
    130131