1. 程式人生 > >Android wifi 掃描流程 分析

Android wifi 掃描流程 分析

void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
    int res;

    if (wpa_s->p2p_mgmt) {
        wpa_dbg(wpa_s, MSG_DEBUG,
            "Ignore scan request (%d.%06d sec) on p2p_mgmt interface",
            sec, usec);
        return;
    }

    res = eloop_deplete_timeout(sec, usec, wpa_supplicant_scan, wpa_s,
                    NULL);
    if (res == 1) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Rescheduling scan request: %d.%06d sec",
            sec, usec);
    } else if (res == 0) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Ignore new scan request for %d.%06d sec since an earlier request is scheduled to trigger sooner",
            sec, usec);
    } else {
        wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d.%06d sec",
            sec, usec);
        eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
    }
}


static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
    struct wpa_supplicant *wpa_s = eloop_ctx;
    struct wpa_ssid *ssid;
    int ret, p2p_in_prog;
    struct wpabuf *extra_ie = NULL;
    struct wpa_driver_scan_params params;
    struct wpa_driver_scan_params *scan_params;
    size_t max_ssids;
    int connect_without_scan = 0;

    wpa_s->ignore_post_flush_scan_res = 0;
    // 介面未使能
    if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
        return;
    }

    if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
        wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
        return;
    }
    // 如果正在掃描, 推遲本次掃描
    if (wpa_s->scanning) {
        /*
         * If we are already in scanning state, we shall reschedule the
         * the incoming scan request.
         */
        wpa_dbg(wpa_s, MSG_DEBUG, "Already scanning - Reschedule the incoming scan req");
        wpa_supplicant_req_scan(wpa_s, 1, 0);
        return;
    }
    // 檢視是否有使能的ssid
    if (!wpa_supplicant_enabled_networks(wpa_s) &&
        wpa_s->scan_req == NORMAL_SCAN_REQ) {
        wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
        wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
        return;
    }

    if (wpa_s->conf->ap_scan != 0 &&
        (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
            "overriding ap_scan configuration");
        wpa_s->conf->ap_scan = 0;
        wpas_notify_ap_scan_changed(wpa_s);
    }

    if (wpa_s->conf->ap_scan == 0) {
        wpa_supplicant_gen_assoc_event(wpa_s);
        return;
    }

    ssid = NULL;
    if (wpa_s->scan_req != MANUAL_SCAN_REQ &&
        wpa_s->connect_without_scan) {
        connect_without_scan = 1;
        for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
            if (ssid == wpa_s->connect_without_scan)
                break;
        }
    }

    p2p_in_prog = wpas_p2p_in_progress(wpa_s);
    if (p2p_in_prog && p2p_in_prog != 2 &&
        (!ssid ||
         (ssid->mode != WPAS_MODE_AP && ssid->mode != WPAS_MODE_P2P_GO))) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
        wpa_supplicant_req_scan(wpa_s, 5, 0);
        return;
    }

    /*
     * Don't cancel the scan based on ongoing PNO; defer it. Some scans are
     * used for changing modes inside wpa_supplicant (roaming,
     * auto-reconnect, etc). Discarding the scan might hurt these processes.
     * The normal use case for PNO is to suspend the host immediately after
     * starting PNO, so the periodic 100 ms attempts to run the scan do not
     * normally happen in practice multiple times, i.e., this is simply
     * restarting scanning once the host is woken up and PNO stopped.
     */
    if (wpa_s->pno || wpa_s->pno_sched_pending) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Defer scan - PNO is in progress");
        wpa_supplicant_req_scan(wpa_s, 0, 100000);
        return;
    }

    if (wpa_s->conf->ap_scan == 2)
        max_ssids = 1;
    else {
        max_ssids = wpa_s->max_scan_ssids;
        if (max_ssids > WPAS_MAX_SCAN_SSIDS)
            max_ssids = WPAS_MAX_SCAN_SSIDS;
    }

    wpa_s->last_scan_req = wpa_s->scan_req;
    wpa_s->scan_req = NORMAL_SCAN_REQ;
    // 如果設定了connect_without_scan, 連線之前選擇的網路,不進行掃描,直接關聯
    if (connect_without_scan) {
        wpa_s->connect_without_scan = NULL;
        if (ssid) {
            wpa_printf(MSG_DEBUG, "Start a pre-selected network "
                   "without scan step");
            wpa_supplicant_associate(wpa_s, NULL, ssid);
            return;
        }
    }

    os_memset(&params, 0, sizeof(params));
    // 設定狀態為掃描
    wpa_s->scan_prev_wpa_state = wpa_s->wpa_state;
    if (wpa_s->wpa_state == WPA_DISCONNECTED ||
        wpa_s->wpa_state == WPA_INACTIVE)
        wpa_supplicant_set_state(wpa_s, WPA_SCANNING);

    /*
     * If autoscan has set its own scanning parameters
     */
    if (wpa_s->autoscan_params != NULL) {
        scan_params = wpa_s->autoscan_params;
        goto scan;
    }

    if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
        wpa_set_ssids_from_scan_req(wpa_s, &params, max_ssids)) {
        wpa_printf(MSG_DEBUG, "Use specific SSIDs from SCAN command");
        goto ssid_list_set;
    }

......

    /* Find the starting point from which to continue scanning */
    // 查詢開始掃描的ssid
    ssid = wpa_s->conf->ssid;
    // 從這裡看,應該是連結串列裡面下一個ssid
    if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
        while (ssid) {
            if (ssid == wpa_s->prev_scan_ssid) {
                ssid = ssid->next;
                break;
            }
            ssid = ssid->next;
        }
    }

    if (wpa_s->last_scan_req != MANUAL_SCAN_REQ &&
#ifdef CONFIG_AP
        !wpa_s->ap_iface &&
#endif /* CONFIG_AP */
        wpa_s->conf->ap_scan == 2) {
        wpa_s->connect_without_scan = NULL;
        wpa_s->prev_scan_wildcard = 0;
        wpa_supplicant_assoc_try(wpa_s, ssid);
        return;
    } else if (wpa_s->conf->ap_scan == 2) {
        /*
         * User-initiated scan request in ap_scan == 2; scan with
         * wildcard SSID.
         */
        ssid = NULL;
    } else if (wpa_s->reattach && wpa_s->current_ssid != NULL) {
    // 實行單通道,單個ssid掃描。難道是漫遊的操作?
    // reassoicate重關聯
        /*
         * Perform single-channel single-SSID scan for
         * reassociate-to-same-BSS operation.
         */
        /* Setup SSID */
        ssid = wpa_s->current_ssid;
        wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
                  ssid->ssid, ssid->ssid_len);
        params.ssids[0].ssid = ssid->ssid;
        params.ssids[0].ssid_len = ssid->ssid_len;
        params.num_ssids = 1;

        /*
         * Allocate memory for frequency array, allocate one extra
         * slot for the zero-terminator.
         */
        params.freqs = os_malloc(sizeof(int) * 2);
        if (params.freqs) {
            params.freqs[0] = wpa_s->assoc_freq;
            params.freqs[1] = 0;
        }

        /*
         * Reset the reattach flag so that we fall back to full scan if
         * this scan fails.
         */
        wpa_s->reattach = 0;
    } else {
        struct wpa_ssid *start = ssid, *tssid;
        int freqs_set = 0;
        if (ssid == NULL && max_ssids > 1)
            ssid = wpa_s->conf->ssid;
        // 獲取配置檔案中的ssid
        while (ssid) {
            if (!wpas_network_disabled(wpa_s, ssid) &&
                ssid->scan_ssid) {
                wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
                          ssid->ssid, ssid->ssid_len);
                params.ssids[params.num_ssids].ssid =
                    ssid->ssid;
                params.ssids[params.num_ssids].ssid_len =
                    ssid->ssid_len;
                params.num_ssids++;
                // 達到所能支援的最大ssid個數,退出迴圈
                if (params.num_ssids + 1 >= max_ssids)
                    break;
            }
            ssid = ssid->next;
            if (ssid == start)
                break;
            if (ssid == NULL && max_ssids > 1 &&
                start != wpa_s->conf->ssid)
                ssid = wpa_s->conf->ssid;
        }

        if (wpa_s->scan_id_count &&
            wpa_s->last_scan_req == MANUAL_SCAN_REQ)
            wpa_set_scan_ssids(wpa_s, &params, max_ssids);

        for (tssid = wpa_s->conf->ssid;
             wpa_s->last_scan_req != MANUAL_SCAN_REQ && tssid;
             tssid = tssid->next) {
             // 網路關閉,不進行掃描
            if (wpas_network_disabled(wpa_s, tssid))
                continue;
            if ((params.freqs || !freqs_set) && tssid->scan_freq) {
                int_array_concat(&params.freqs,
                         tssid->scan_freq);
            } else {
                os_free(params.freqs);
                params.freqs = NULL;
            }
            freqs_set = 1;
        }
        // 對頻率進行排序
        int_array_sort_unique(params.freqs);
    }

    if (ssid && max_ssids == 1) {
        /*
         * If the driver is limited to 1 SSID at a time interleave
         * wildcard SSID scans with specific SSID scans to avoid
         * waiting a long time for a wildcard scan.
         */
        if (!wpa_s->prev_scan_wildcard) {
            params.ssids[0].ssid = NULL;
            params.ssids[0].ssid_len = 0;
            wpa_s->prev_scan_wildcard = 1;
            wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for "
                "wildcard SSID (Interleave with specific)");
        } else {
            wpa_s->prev_scan_ssid = ssid;
            wpa_s->prev_scan_wildcard = 0;
            wpa_dbg(wpa_s, MSG_DEBUG,
                "Starting AP scan for specific SSID: %s",
                wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
        }
    } else if (ssid) {
        /* max_ssids > 1 */

        wpa_s->prev_scan_ssid = ssid;
        wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
            "the scan request");
        params.num_ssids++;
    } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
           wpa_s->manual_scan_passive && params.num_ssids == 0) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request");
    } else if (wpa_s->conf->passive_scan) {
        wpa_dbg(wpa_s, MSG_DEBUG,
            "Use passive scan based on configuration");
    } else {
        wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
        params.num_ssids++;
        wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
            "SSID");
    }

ssid_list_set:
    wpa_supplicant_optimize_freqs(wpa_s, &params);
    extra_ie = wpa_supplicant_extra_ies(wpa_s);
    // 手動發起的掃描
    if (wpa_s->last_scan_req == MANUAL_SCAN_REQ &&
        wpa_s->manual_scan_only_new) {
        wpa_printf(MSG_DEBUG,
               "Request driver to clear scan cache due to manual only_new=1 scan");
        params.only_new_results = 1;
    }

    if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs == NULL &&
        wpa_s->manual_scan_freqs) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Limit manual scan to specified channels");
        params.freqs = wpa_s->manual_scan_freqs;
        wpa_s->manual_scan_freqs = NULL;
    }

    if (params.freqs == NULL && wpa_s->select_network_scan_freqs) {
        wpa_dbg(wpa_s, MSG_DEBUG,
            "Limit select_network scan to specified channels");
        params.freqs = wpa_s->select_network_scan_freqs;
        wpa_s->select_network_scan_freqs = NULL;
    }
    // 引數裡面的頻率為空
    // 優化掃描,基於的頻率列表
    if (params.freqs == NULL && wpa_s->next_scan_freqs) {
        wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
            "generated frequency list");
        params.freqs = wpa_s->next_scan_freqs;
    } else
        os_free(wpa_s->next_scan_freqs);
    wpa_s->next_scan_freqs = NULL;
    wpa_setband_scan_freqs(wpa_s, &params);

    /* See if user specified frequencies. If so, scan only those. */
    if (wpa_s->conf->freq_list && !params.freqs) {
        wpa_dbg(wpa_s, MSG_DEBUG,
            "Optimize scan based on conf->freq_list");
        int_array_concat(&params.freqs, wpa_s->conf->freq_list);
    }

    /* Use current associated channel? */
    // 是否只掃描當前通道
    if (wpa_s->conf->scan_cur_freq && !params.freqs) {
        unsigned int num = wpa_s->num_multichan_concurrent;

        params.freqs = os_calloc(num + 1, sizeof(int));
        if (params.freqs) {
            num = get_shared_radio_freqs(wpa_s, params.freqs, num);
            if (num > 0) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Scan only the "
                    "current operating channels since "
                    "scan_cur_freq is enabled");
            } else {
                os_free(params.freqs);
                params.freqs = NULL;
            }
        }
    }

    params.filter_ssids = wpa_supplicant_build_filter_ssids(
        wpa_s->conf, &params.num_filter_ssids);
    if (extra_ie) {
        params.extra_ies = wpabuf_head(extra_ie);
        params.extra_ies_len = wpabuf_len(extra_ie);
    }

...

    if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
        wpa_s->wpa_state <= WPA_SCANNING) {
        params.mac_addr_rand = 1;
        if (wpa_s->mac_addr_scan) {
            params.mac_addr = wpa_s->mac_addr_scan;
            params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
        }
    }

    if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
        struct wpa_bss *bss;

        params.bssid = wpa_s->next_scan_bssid;
        bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid);
        if (bss && bss->ssid_len && params.num_ssids == 1 &&
            params.ssids[0].ssid_len == 0) {
            params.ssids[0].ssid = bss->ssid;
            params.ssids[0].ssid_len = bss->ssid_len;
            wpa_dbg(wpa_s, MSG_DEBUG,
                "Scan a previously specified BSSID " MACSTR
                " and SSID %s",
                MAC2STR(params.bssid),
                wpa_ssid_txt(bss->ssid, bss->ssid_len));
        } else {
            wpa_dbg(wpa_s, MSG_DEBUG,
                "Scan a previously specified BSSID " MACSTR,
                MAC2STR(params.bssid));
        }
    }

    scan_params = &params;

scan:
...
    ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);

    if (ret && wpa_s->last_scan_req == MANUAL_SCAN_REQ && params.freqs &&
        !wpa_s->manual_scan_freqs) {
        /* Restore manual_scan_freqs for the next attempt */
        wpa_s->manual_scan_freqs = params.freqs;
        params.freqs = NULL;
    }

    wpabuf_free(extra_ie);
    os_free(params.freqs);
    os_free(params.filter_ssids);

    if (ret) {
        wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
        if (wpa_s->scan_prev_wpa_state != wpa_s->wpa_state)
            wpa_supplicant_set_state(wpa_s,
                         wpa_s->scan_prev_wpa_state);
        /* Restore scan_req since we will try to scan again */
        wpa_s->scan_req = wpa_s->last_scan_req;
        wpa_supplicant_req_scan(wpa_s, 1, 0);
    } else {
        wpa_s->scan_for_connection = 0;
#ifdef CONFIG_INTERWORKING
        wpa_s->interworking_fast_assoc_tried = 0;
#endif /* CONFIG_INTERWORKING */
        if (params.bssid)
            os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN);
    }
}

wpa_supplicant_trigger_scan
        --> wpas_trigger_scan_cb
            --> wpa_drv_scan(wpa_s, params);
                --> wpa_s->driver->scan2(wpa_s->drv_priv, params);

external\wpa_supplicant_8\src\drivers\driver_nl80211.c              
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
    .name = "nl80211",
    .desc = "Linux nl80211/cfg80211",
    .get_bssid = wpa_driver_nl80211_get_bssid,
    .get_ssid = wpa_driver_nl80211_get_ssid,
    .set_key = driver_nl80211_set_key,
    .scan2 = driver_nl80211_scan2,
    ...
}

static int driver_nl80211_scan2(void *priv,
                struct wpa_driver_scan_params *params)
{
    struct i802_bss *bss = priv;
#ifdef CONFIG_DRIVER_NL80211_QCA
    struct wpa_driver_nl80211_data *drv = bss->drv;

    /*
     * Do a vendor specific scan if possible. If only_new_results is
     * set, do a normal scan since a kernel (cfg80211) BSS cache flush
     * cannot be achieved through a vendor scan. The below condition may
     * need to be modified if new scan flags are added in the future whose
     * functionality can only be achieved through a normal scan.
     */
    if (drv->scan_vendor_cmd_avail && !params->only_new_results)
        return wpa_driver_nl80211_vendor_scan(bss, params);
#endif /* CONFIG_DRIVER_NL80211_QCA */
    return wpa_driver_nl80211_scan(bss, params);
}

external\wpa_supplicant_8\hostapd\src\drivers\driver_nl80211_scan.c
int wpa_driver_nl80211_scan(struct i802_bss *bss,
                struct wpa_driver_scan_params *params)
{
    struct wpa_driver_nl80211_data *drv = bss->drv;
    int ret = -1, timeout;
    struct nl_msg *msg = NULL;

    wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
    drv->scan_for_auth = 0;

    if (TEST_FAIL())
        return -1;

    msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
    if (!msg)
        return -1;

    if (params->p2p_probe) {
        struct nlattr *rates;

        wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");

        rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
        if (rates == NULL)
            goto fail;

        /*
         * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
         * by masking out everything else apart from the OFDM rates 6,
         * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
         * rates are left enabled.
         */
        if (nla_put(msg, NL80211_BAND_2GHZ, 8,
                "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
            goto fail;
        nla_nest_end(msg, rates);

        if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE))
            goto fail;
    }

    if (params->bssid) {
        wpa_printf(MSG_DEBUG, "nl80211: Scan for a specific BSSID: "
               MACSTR, MAC2STR(params->bssid));
        if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
            goto fail;
    }

    ret = send_and_recv_msgs(drv, msg, NULL, NULL);
    msg = NULL;
    if (ret) {
        wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
               "(%s)", ret, strerror(-ret));
        if (drv->hostapd && is_ap_interface(drv->nlmode)) {
            enum nl80211_iftype old_mode = drv->nlmode;

            /*
             * mac80211 does not allow scan requests in AP mode, so
             * try to do this in station mode.
             */
            if (wpa_driver_nl80211_set_mode(
                    bss, NL80211_IFTYPE_STATION))
                goto fail;

            if (wpa_driver_nl80211_scan(bss, params)) {
                wpa_driver_nl80211_set_mode(bss, old_mode);
                goto fail;
            }

            /* Restore AP mode when processing scan results */
            drv->ap_scan_as_station = old_mode;
            ret = 0;
        } else
            goto fail;
    }

    drv->scan_state = SCAN_REQUESTED;
    /* Not all drivers generate "scan completed" wireless event, so try to
     * read results after a timeout. */
    // 掃描超時時間,超時之後讀取結果。
    timeout = 10;
    if (drv->scan_complete_events) {
        /*
         * The driver seems to deliver events to notify when scan is
         * complete, so use longer timeout to avoid race conditions
         * with scanning and following association request.
         */
        timeout = 30;
    }
    wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
           "seconds", ret, timeout);
    eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
    eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
                   drv, drv->ctx);
    drv->last_scan_cmd = NL80211_CMD_TRIGGER_SCAN;

fail:
    nlmsg_free(msg);
    return ret;
}


static struct nl_msg *
nl80211_scan_common(struct i802_bss *bss, u8 cmd,
            struct wpa_driver_scan_params *params)
{
    struct wpa_driver_nl80211_data *drv = bss->drv;
    struct nl_msg *msg;
    size_t i;
    u32 scan_flags = 0;

    msg = nl80211_cmd_msg(bss, 0, cmd);
    if (!msg)
        return NULL;

    if (params->num_ssids) {
        struct nlattr *ssids;

        ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
        if (ssids == NULL)
            goto fail;
        for (i = 0; i < params->num_ssids; i++) {
            wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
                      params->ssids[i].ssid,
                      params->ssids[i].ssid_len);
            if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
                    params->ssids[i].ssid))
                goto fail;
        }
        nla_nest_end(msg, ssids);
    } else {
        wpa_printf(MSG_DEBUG, "nl80211: Passive scan requested");
    }

    if (params->extra_ies) {
        wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
                params->extra_ies, params->extra_ies_len);
        if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
                params->extra_ies))
            goto fail;
    }
    // 掃描頻率
    if (params->freqs) {
        struct nlattr *freqs;
        freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
        if (freqs == NULL)
            goto fail;
        for (i = 0; params->freqs[i]; i++) {
            wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
                   "MHz", params->freqs[i]);
            if (nla_put_u32(msg, i + 1, params->freqs[i]))
                goto fail;
        }
        nla_nest_end(msg, freqs);
    }

    os_free(drv->filter_ssids);
    drv->filter_ssids = params->filter_ssids;
    params->filter_ssids = NULL;
    drv->num_filter_ssids = params->num_filter_ssids;

    if (params->only_new_results) {
        wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
        scan_flags |= NL80211_SCAN_FLAG_FLUSH;
    }

    if (params->low_priority && drv->have_low_prio_scan) {
        wpa_printf(MSG_DEBUG,
               "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
        scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
    }

    if (params->mac_addr_rand) {
        wpa_printf(MSG_DEBUG,
               "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
        scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;

        if (params->mac_addr) {
            wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
                   MAC2STR(params->mac_addr));
            if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
                    params->mac_addr))
                goto fail;
        }

        if (params->mac_addr_mask) {
            wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
                   MACSTR, MAC2STR(params->mac_addr_mask));
            if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
                    params->mac_addr_mask))
                goto fail;
        }
    }

    if (params->duration) {
        if (!(drv->capa.rrm_flags &
              WPA_DRIVER_FLAGS_SUPPORT_SET_SCAN_DWELL) ||
            nla_put_u16(msg, NL80211_ATTR_MEASUREMENT_DURATION,
                params->duration))
            goto fail;

        if (params->duration_mandatory &&
            nla_put_flag(msg,
                 NL80211_ATTR_MEASUREMENT_DURATION_MANDATORY))
            goto fail;
    }

    if (scan_flags &&
        nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
        goto fail;

    return msg;

fail:
    nlmsg_free(msg);
    return NULL;
}

2018-11-14