九阳神功爱喝茶 发表于 2015-11-25 17:10

被动扫描问题求解

本帖最后由 九阳神功爱喝茶 于 2015-11-25 19:06 编辑

小弟最近在看主动扫描和被动扫描的ath9k源代码,遇到一个问题想和大家一起讨论下。
被动扫描是Client接收AP的beacon帧,然后对这个信道进行扫描,扫描之后获取该AP的BSS信息,保存下来,即完成了扫描过程;然后进入ieee80211_rx_mgmt_beacon函数,我分析了下其中的与创建连接有关的代码,如下:
static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgmt *mgmt, size_t len,
                                     struct ieee80211_rx_status *rx_status)
{
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        size_t baselen;
        struct ieee802_11_elems elems;
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_channel *chan;
        struct sta_info *sta;
        u32 changed = 0;
        bool erp_valid;
        u8 erp_value = 0;
        u32 ncrc;
        u8 *bssid;
        u8 deauth_buf;

        sdata_assert_lock(sdata);

        /* Process beacon from the current BSS */
        baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
        if (baselen > len)
                return;

        rcu_read_lock();
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (!chanctx_conf) {
                rcu_read_unlock();
                return;
        }

        if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
                rcu_read_unlock();
                return;
        }
        chan = chanctx_conf->def.chan;
        rcu_read_unlock();

       //也就是说第一次等到该AP的beacon帧
        if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
          ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
                ieee802_11_parse_elems(mgmt->u.beacon.variable,
                                     len - baselen, false, &elems);

                ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);
                if (elems.tim && !elems.parse_error) {
                        const struct ieee80211_tim_ie *tim_ie = elems.tim;
                        ifmgd->dtim_period = tim_ie->dtim_period;
                }
                ifmgd->have_beacon = true;
                ifmgd->assoc_data->need_beacon = false;
                if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
                        sdata->vif.bss_conf.sync_tsf =
                                le64_to_cpu(mgmt->u.beacon.timestamp);
                        sdata->vif.bss_conf.sync_device_ts =
                                rx_status->device_timestamp;
                        if (elems.tim)
                                sdata->vif.bss_conf.sync_dtim_count =
                                        elems.tim->dtim_count;
                        else
                                sdata->vif.bss_conf.sync_dtim_count = 0;
                }
                /* continue assoc process */
                ifmgd->assoc_data->timeout = jiffies;
                ifmgd->assoc_data->timeout_started = true;
                run_again(sdata, ifmgd->assoc_data->timeout);
                return;
        }
//如果当前未连接或者说收到的BSSID与当前连接的BSSID不匹配,直接return。。。
        if (!ifmgd->associated ||
          !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
                return;
        bssid = ifmgd->associated->bssid;

        /* Track average RSSI from the Beacon frames of the current AP */
        ifmgd->last_beacon_signal = rx_status->signal;
        if (ifmgd->flags & IEEE80211_STA_RESET_SIGNAL_AVE) {
                ifmgd->flags &= ~IEEE80211_STA_RESET_SIGNAL_AVE;
                ifmgd->ave_beacon_signal = rx_status->signal * 16;
                ifmgd->last_cqm_event_signal = 0;
                ifmgd->count_beacon_signal = 1;
                ifmgd->last_ave_beacon_signal = 0;
        } else {
                ifmgd->ave_beacon_signal =
                        (IEEE80211_SIGNAL_AVE_WEIGHT * rx_status->signal * 16 +
                       (16 - IEEE80211_SIGNAL_AVE_WEIGHT) *
                       ifmgd->ave_beacon_signal) / 16;
                ifmgd->count_beacon_signal++;
        }

        if (ifmgd->rssi_min_thold != ifmgd->rssi_max_thold &&
          ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
                int sig = ifmgd->ave_beacon_signal;
                int last_sig = ifmgd->last_ave_beacon_signal;

                /*
               * if signal crosses either of the boundaries, invoke callback
               * with appropriate parameters
               */
                if (sig > ifmgd->rssi_max_thold &&
                  (last_sig <= ifmgd->rssi_min_thold || last_sig == 0)) {
                        ifmgd->last_ave_beacon_signal = sig;
                        drv_rssi_callback(local, sdata, RSSI_EVENT_HIGH);
                } else if (sig < ifmgd->rssi_min_thold &&
                           (last_sig >= ifmgd->rssi_max_thold ||
                           last_sig == 0)) {
                        ifmgd->last_ave_beacon_signal = sig;
                        drv_rssi_callback(local, sdata, RSSI_EVENT_LOW);
                }
        }

        if (bss_conf->cqm_rssi_thold &&
          ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT &&
          !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) {
                int sig = ifmgd->ave_beacon_signal / 16;
                int last_event = ifmgd->last_cqm_event_signal;
                int thold = bss_conf->cqm_rssi_thold;
                int hyst = bss_conf->cqm_rssi_hyst;
                if (sig < thold &&
                  (last_event == 0 || sig < last_event - hyst)) {
                        ifmgd->last_cqm_event_signal = sig;
                        ieee80211_cqm_rssi_notify(
                                &sdata->vif,
                                NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
                                GFP_KERNEL);
                } else if (sig > thold &&
                           (last_event == 0 || sig > last_event + hyst)) {
                        ifmgd->last_cqm_event_signal = sig;
                        ieee80211_cqm_rssi_notify(
                                &sdata->vif,
                                NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
                                GFP_KERNEL);
                }
        }

        if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
                mlme_dbg_ratelimited(sdata,
                                     "cancelling AP probe due to a received beacon\n");
                ieee80211_reset_ap_probe(sdata);
        }

        /*
       * Push the beacon loss detection into the future since
       * we are processing a beacon from the AP just now.
       */
        ieee80211_sta_reset_beacon_monitor(sdata);

        ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
        ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
                                          len - baselen, false, &elems,
                                          care_about_ies, ncrc);

        if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
                bool directed_tim = ieee80211_check_tim(elems.tim,
                                                        elems.tim_len,
                                                        ifmgd->aid);
                if (directed_tim) {
                        if (local->hw.conf.dynamic_ps_timeout > 0) {
                                if (local->hw.conf.flags & IEEE80211_CONF_PS) {
                                        local->hw.conf.flags &= ~IEEE80211_CONF_PS;
                                        ieee80211_hw_config(local,
                                                          IEEE80211_CONF_CHANGE_PS);
                                }
                                ieee80211_send_nullfunc(local, sdata, 0);
                        } else if (!local->pspolling && sdata->u.mgd.powersave) {
                                local->pspolling = true;

                                /*
                               * Here is assumed that the driver will be
                               * able to send ps-poll frame and receive a
                               * response even though power save mode is
                               * enabled, but some drivers might require
                               * to disable power save here. This needs
                               * to be investigated.
                               */
                                ieee80211_send_pspoll(local, sdata);
                        }
                }
        }

        if (sdata->vif.p2p) {
                struct ieee80211_p2p_noa_attr noa = {};
                int ret;

                ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable,
                                          len - baselen,
                                          IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
                                          (u8 *) &noa, sizeof(noa));
                if (ret >= 2) {
                        if (sdata->u.mgd.p2p_noa_index != noa.index) {
                                /* valid noa_attr and index changed */
                                sdata->u.mgd.p2p_noa_index = noa.index;
                                memcpy(&bss_conf->p2p_noa_attr, &noa, sizeof(noa));
                                changed |= BSS_CHANGED_P2P_PS;
                                /*
                               * make sure we update all information, the CRC
                               * mechanism doesn't look at P2P attributes.
                               */
                                ifmgd->beacon_crc_valid = false;
                        }
                } else if (sdata->u.mgd.p2p_noa_index != -1) {
                        /* noa_attr not found and we had valid noa_attr before */
                        sdata->u.mgd.p2p_noa_index = -1;
                        memset(&bss_conf->p2p_noa_attr, 0, sizeof(bss_conf->p2p_noa_attr));
                        changed |= BSS_CHANGED_P2P_PS;
                        ifmgd->beacon_crc_valid = false;
                }
        }

        if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
                return;
        ifmgd->beacon_crc = ncrc;
        ifmgd->beacon_crc_valid = true;

        ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems);

        ieee80211_sta_process_chanswitch(sdata, rx_status->mactime,
                                       &elems, true);

        if (!(ifmgd->flags & IEEE80211_STA_DISABLE_WMM) &&
          ieee80211_sta_wmm_params(local, sdata, elems.wmm_param,
                                     elems.wmm_param_len))
                changed |= BSS_CHANGED_QOS;

        /*
       * If we haven't had a beacon before, tell the driver about the
       * DTIM period (and beacon timing if desired) now.
       */
        if (!ifmgd->have_beacon) {
                /* a few bogus AP send dtim_period = 0 or no TIM IE */
                if (elems.tim)
                        bss_conf->dtim_period = elems.tim->dtim_period ?: 1;
                else
                        bss_conf->dtim_period = 1;

                if (local->hw.flags & IEEE80211_HW_TIMING_BEACON_ONLY) {
                        sdata->vif.bss_conf.sync_tsf =
                                le64_to_cpu(mgmt->u.beacon.timestamp);
                        sdata->vif.bss_conf.sync_device_ts =
                                rx_status->device_timestamp;
                        if (elems.tim)
                                sdata->vif.bss_conf.sync_dtim_count =
                                        elems.tim->dtim_count;
                        else
                                sdata->vif.bss_conf.sync_dtim_count = 0;
                }

                changed |= BSS_CHANGED_BEACON_INFO;
                ifmgd->have_beacon = true;

                mutex_lock(&local->iflist_mtx);
                ieee80211_recalc_ps(local, -1);
                mutex_unlock(&local->iflist_mtx);

                ieee80211_recalc_ps_vif(sdata);
        }

        if (elems.erp_info) {
                erp_valid = true;
                erp_value = elems.erp_info;
        } else {
                erp_valid = false;
        }
        changed |= ieee80211_handle_bss_capability(sdata,
                        le16_to_cpu(mgmt->u.beacon.capab_info),
                        erp_valid, erp_value);

        mutex_lock(&local->sta_mtx);
        sta = sta_info_get(sdata, bssid);

        if (ieee80211_config_bw(sdata, sta, elems.ht_operation,
                                elems.vht_operation, bssid, &changed)) {
                mutex_unlock(&local->sta_mtx);
                ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
                                     WLAN_REASON_DEAUTH_LEAVING,
                                     true, deauth_buf);
                cfg80211_tx_mlme_mgmt(sdata->dev, deauth_buf,
                                      sizeof(deauth_buf));
                return;
        }

        if (sta && elems.opmode_notif)
                ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
                                          rx_status->band, true);
        mutex_unlock(&local->sta_mtx);

        if (elems.country_elem && elems.pwr_constr_elem &&
          mgmt->u.probe_resp.capab_info &
                                cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
                changed |= ieee80211_handle_pwr_constr(sdata, chan,
                                                     elems.country_elem,
                                                     elems.country_elem_len,
                                                     elems.pwr_constr_elem);

        ieee80211_bss_info_change_notify(sdata, changed);
}
还请各位大神指导下,小弟分析对吗?
页: [1]
查看完整版本: 被动扫描问题求解