WEP,WPA-PSK,WPA2-PSK握手深入分析3--wpa_supplicant代码分析-扫描

欢迎转载,转载时请保留作者链接,尊重原作者:http://blog.csdn.net/ivan_

wifi技术交流群QQ92953762



我们使用wext方式与wifi driver交互


当我们在终端中执行wpa_cli scan时,就会触发wpa_supplicant发起扫描流程:

wpa_supplicant_ctrl_iface_receive() ->

  wpa_supplicant_ctrl_iface_process()->

     wpa_supplicant_req_scan()->

        wpa_supplicant_scan()->

            wpa_supplicant_trigger_scan()->

               wpa_drv_scan()->

                  wpa_driver_wext_scan()->

                         ioctl()->pass scan data to wifi driver


以下是核心代码:
/**
 * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
 * @wpa_s: Pointer to wpa_supplicant data
 * @sec: Number of seconds after which to scan
 * @usec: Number of microseconds after which to scan
 *
 * This function is used to schedule a scan for neighboring access points after
 * the specified time.
 */
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
#ifndef ANDROID
	/* If there's at least one network that should be specifically scanned
	 * then don't cancel the scan and reschedule.  Some drivers do
	 * background scanning which generates frequent scan results, and that
	 * causes the specific SSID scan to get continually pushed back and
	 * never happen, which causes hidden APs to never get probe-scanned.
	 */
	if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
	    wpa_s->conf->ap_scan == 1) {
		struct wpa_ssid *ssid = wpa_s->conf->ssid;

		while (ssid) {
			if (!ssid->disabled && ssid->scan_ssid)
				break;
			ssid = ssid->next;
		}
		if (ssid) {
			wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
			        "ensure that specific SSID scans occur");
			return;
		}
	}

#endif /* !ANDROID */
	wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
		sec, usec);
	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
	eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
}

//发起扫描
/*****************************************************************
*
*
*
*
*****************************************************************/
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{

	wpa_printf(MSG_DEBUG,"ivan:%s \n",__FUNCTION__);

	struct wpa_supplicant *wpa_s = eloop_ctx;
	struct wpa_ssid *ssid;
	int scan_req = 0, ret;
	struct wpabuf *wps_ie = NULL;
#ifdef CONFIG_WPS
	int wps = 0;
	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
#endif /* CONFIG_WPS */
	struct wpa_driver_scan_params params;
	size_t max_ssids;
	enum wpa_states prev_state;

    //wlan0 or ra0已经被禁用
	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) {
		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
		return;
	}

	if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
	    !wpa_s->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) {//ap_scan == 0???
		wpa_supplicant_gen_assoc_event(wpa_s);
		return;
	}

	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
#ifdef ANDROID
	    (wpa_s->max_scan_ssids == 1 && wpa_s->conf->ap_scan == 2))
#else
	    wpa_s->conf->ap_scan == 2)
#endif  /* ANDROID for combo scan */
		max_ssids = 1;
	else {
		max_ssids = wpa_s->max_scan_ssids;
		if (max_ssids > WPAS_MAX_SCAN_SSIDS)
			max_ssids = WPAS_MAX_SCAN_SSIDS;
	}

#ifdef CONFIG_WPS
	wps = wpas_wps_in_use(wpa_s->conf, &req_type);
#endif /* CONFIG_WPS */

	scan_req = wpa_s->scan_req;
	wpa_s->scan_req = 0;

	os_memset(¶ms, 0, sizeof(params));

	prev_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 (scan_req != 2 && wpa_s->connect_without_scan) {//无需扫描 直接发起连接
		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
			if (ssid == wpa_s->connect_without_scan)
				break;
		}
		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;
		}
	}

	/* Find the starting point from which to continue scanning */
	ssid = wpa_s->conf->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 (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
		wpa_s->connect_without_scan = NULL;
		wpa_supplicant_assoc_try(wpa_s, ssid);
		return;
#ifdef ANDROID
	} else if ( max_ssids == 1 && wpa_s->conf->ap_scan == 2) {
#else
	} else if (wpa_s->conf->ap_scan == 2) {
#endif /* ANDROID for combo scan */
		/*
		 * User-initiated scan request in ap_scan == 2; scan with
		 * wildcard SSID.
		 */
		ssid = NULL;
	} else {
		struct wpa_ssid *start = ssid, *tssid;
		int freqs_set = 0;
		if (ssid == NULL && max_ssids > 1)
			ssid = wpa_s->conf->ssid;
		while (ssid) {
			if (!ssid->disabled && 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++;
				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;
		}

		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
			if (tssid->disabled)
				continue;
			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
				int_array_concat(¶ms.freqs,
						 tssid->scan_freq);
			} else {
				os_free(params.freqs);
				params.freqs = NULL;
			}
			freqs_set = 1;
		}
		int_array_sort_unique(params.freqs);
	}

	if (ssid) {//扫描指定的SSID
		wpa_s->prev_scan_ssid = ssid;
		if (max_ssids > 1) {
			wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
				"the scan request");
			params.num_ssids++;
		}
		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific "
			"SSID(s)");
	} else {
		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
		params.num_ssids++;
		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
			"SSID");
	}

#ifdef CONFIG_P2P
	if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) {
		wpa_s->wps->dev.p2p = 1;
		if (!wps) {
			wps = 1;
			req_type = WPS_REQ_ENROLLEE_INFO;
		}
	}

	if (params.freqs == NULL && wpa_s->p2p_in_provisioning &&
	    wpa_s->go_params) {
		/* Optimize provisioning state scan based on GO information */
		if (wpa_s->p2p_in_provisioning < 5 &&
		    wpa_s->go_params->freq > 0) {
			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
				"preferred frequency %d MHz",
				wpa_s->go_params->freq);
			params.freqs = os_zalloc(2 * sizeof(int));
			if (params.freqs)
				params.freqs[0] = wpa_s->go_params->freq;
		} else if (wpa_s->p2p_in_provisioning < 8 &&
			   wpa_s->go_params->freq_list[0]) {
			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
				"channels");
			int_array_concat(¶ms.freqs,
					 wpa_s->go_params->freq_list);
			if (params.freqs)
				int_array_sort_unique(params.freqs);
		}
		wpa_s->p2p_in_provisioning++;
	}
#endif /* CONFIG_P2P */

#ifdef CONFIG_WPS
	if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
		/*
		 * Optimize post-provisioning scan based on channel used
		 * during provisioning.
		 */
		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
			"that was used during provisioning", wpa_s->wps_freq);
		params.freqs = os_zalloc(2 * sizeof(int));
		if (params.freqs)
			params.freqs[0] = wpa_s->wps_freq;
		wpa_s->after_wps--;
	}

	if (wps) {
		wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
						wpa_s->wps->uuid, req_type,
						0, NULL);
		if (wps_ie) {
			params.extra_ies = wpabuf_head(wps_ie);
			params.extra_ies_len = wpabuf_len(wps_ie);
		}
	}
#endif /* CONFIG_WPS */

#ifdef CONFIG_P2P
	if (wps_ie) {
		if (wpabuf_resize(&wps_ie, 100) == 0) {
			wpas_p2p_scan_ie(wpa_s, wps_ie);
			params.extra_ies = wpabuf_head(wps_ie);
			params.extra_ies_len = wpabuf_len(wps_ie);
		}
	}
#endif /* CONFIG_P2P */
    //扫描指定的信道
	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;

	params.filter_ssids = wpa_supplicant_build_filter_ssids(
		wpa_s->conf, ¶ms.num_filter_ssids);

	ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms);//发起扫描

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

	if (ret) {
		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
		if (prev_state != wpa_s->wpa_state)
			wpa_supplicant_set_state(wpa_s, prev_state);
		wpa_supplicant_req_scan(wpa_s, 1, 0);
	}
}


/**
 * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
 * @wpa_s: Pointer to wpa_supplicant data
 * @sec: Number of seconds after which to scan
 * @usec: Number of microseconds after which to scan
 *
 * This function is used to schedule a scan for neighboring access points after
 * the specified time.
 */
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
#ifndef ANDROID
	/* If there's at least one network that should be specifically scanned
	 * then don't cancel the scan and reschedule.  Some drivers do
	 * background scanning which generates frequent scan results, and that
	 * causes the specific SSID scan to get continually pushed back and
	 * never happen, which causes hidden APs to never get probe-scanned.
	 */
	if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
	    wpa_s->conf->ap_scan == 1) {
		struct wpa_ssid *ssid = wpa_s->conf->ssid;

		while (ssid) {
			if (!ssid->disabled && ssid->scan_ssid)
				break;
			ssid = ssid->next;
		}
		if (ssid) {
			wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
			        "ensure that specific SSID scans occur");
			return;
		}
	}

#endif /* !ANDROID */
	wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
		sec, usec);
	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
	eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
}


int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
				struct wpa_driver_scan_params *params)
{
	int ret;
	//printf("wpa_supplicant_trigger_scan\n");
	
	wpa_msg(wpa_s, MSG_DEBUG,  "%s",__FUNCTION__);
	wpa_supplicant_notify_scanning(wpa_s, 1);

	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
		ret = ieee80211_sta_req_scan(wpa_s, params);
	else
		ret = wpa_drv_scan(wpa_s, params);//这里

	if (ret) {
		wpa_supplicant_notify_scanning(wpa_s, 0);
		wpas_notify_scan_done(wpa_s, 0);
	} else
		wpa_s->scan_runs++;

	return ret;
}

/**
 * wpa_driver_wext_scan - Request the driver to initiate scan
 * @priv: Pointer to private wext data from wpa_driver_wext_init()
 * @param: Scan parameters (specific SSID to scan for (ProbeReq), etc.)
 * Returns: 0 on success, -1 on failure
 */
 //发起扫描
int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params)
{
	wpa_printf(MSG_DEBUG, "ivan:%s\n",__FUNCTION__);
	struct wpa_driver_wext_data *drv = priv;
	struct iwreq iwr;
	int ret = 0, timeout;
	struct iw_scan_req req;
	const u8 *ssid = params->ssids[0].ssid;
	size_t ssid_len = params->ssids[0].ssid_len;
#ifdef ANDROID
	struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx);
	int scan_probe_flag = 0;
#endif

	if (ssid_len > IW_ESSID_MAX_SIZE) {
		wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
			   __FUNCTION__, (unsigned long) ssid_len);
		return -1;
	}

	os_memset(&iwr, 0, sizeof(iwr));
	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);

#ifdef ANDROID
	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
		scan_probe_flag = wpa_s->prev_scan_ssid->scan_ssid;
	}
	wpa_printf(MSG_DEBUG, "%s: specific scan = %d", __func__,
		(scan_probe_flag && (ssid && ssid_len)) ? 1 : 0);
	if (scan_probe_flag && (ssid && ssid_len)) {
#else
	if (ssid && ssid_len) {//扫描特定热点
#endif
		os_memset(&req, 0, sizeof(req));
		req.essid_len = ssid_len;
		req.bssid.sa_family = ARPHRD_ETHER;
		os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
		os_memcpy(req.essid, ssid, ssid_len);
		iwr.u.data.pointer = (caddr_t) &req;
		iwr.u.data.length = sizeof(req);
		iwr.u.data.flags = IW_SCAN_THIS_ESSID;
	}

	if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
		perror("ioctl[SIOCSIWSCAN]");
		ret = -1;
	}

	/* Not all drivers generate "scan completed" wireless event, so try to
	 * read results after a timeout. */
	timeout = 5;
	if (drv->scan_complete_events) {
		/*
		 * The driver seems to deliver SIOCGIWSCAN events to notify
		 * when scan is complete, so use longer timeout to avoid race
		 * conditions with scanning and following association request.
		 */
		//timeout = 30;//Default
		timeout = 5;//modify by ivanhuang @20131018
	}
	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
		   "seconds", ret, timeout);
	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
	eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
			       drv->ctx);

	return ret;
}

欢迎转载,转载时请保留作者链接,尊重原作者:http://blog.csdn.net/ivan_

wifi技术交流群QQ92953762


 
 

你可能感兴趣的:(WIFI/802.11)