1 wpa_supplicant_connect
events.c
int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
struct wpa_bss *selected,
struct wpa_ssid *ssid) {
wpa_msg(wpa_s, MSG_DEBUG,
"Considering connect request: reassociate: %d selected: "
MACSTR " bssid: " MACSTR " pending: " MACSTR
" wpa_state: %s ssid=%p current_ssid=%p",
wpa_s->reassociate, MAC2STR(selected->bssid),
MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
wpa_supplicant_state_txt(wpa_s->wpa_state),
ssid, wpa_s->current_ssid);
//wpa_s->pending_bssid用于存储目标网络的BSSID
if (wpa_s->reassociate ||
(os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
((wpa_s->wpa_state != WPA_ASSOCIATING &&
wpa_s->wpa_state != WPA_AUTHENTICATING) ||
(!is_zero_ether_addr(wpa_s->pending_bssid) &&
os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
0) ||
(is_zero_ether_addr(wpa_s->pending_bssid) &&
ssid != wpa_s->current_ssid)))) {
if (wpa_supplicant_scard_init(wpa_s, ssid)) {
wpa_supplicant_req_new_scan(wpa_s, 10, 0);
return 0;
}
wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR,
MAC2STR(selected->bssid));
//发起关联操作
wpa_supplicant_associate(wpa_s, selected, ssid);
} else {
wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to "
"connect with the selected AP");
}
return 0;
}
wpa_supplicant_connect 最重要的工作就是触发STA发起关联操作
2 wpa_supplicant_associate
wpa_supplicant.c
和发起无线扫描请求一样,wpa_supplicant_associate函数主要目的就是
填充一个用于向wlan driver发起关联请求的 struct wpa_driver_associate_params 类型的对象
然后调用driver interface对应的接口函数
下面这份代码不匹配教材上的
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss, struct wpa_ssid *ssid)
{
struct wpa_connect_work *cwork;
int rand_style;
wpa_s->own_disconnect_req = 0;
wpa_s->own_reconnect_req = 0;
/*
* If we are starting a new connection, any previously pending EAPOL
* RX cannot be valid anymore.
*/
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = NULL;
if (ssid->mac_addr == -1)
rand_style = wpa_s->conf->mac_addr;
else
rand_style = ssid->mac_addr;
wpa_s->multi_ap_ie = 0;
wmm_ac_clear_saved_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 0;
wpa_s->reassoc_same_ess = 0;
#ifdef CONFIG_TESTING_OPTIONS
wpa_s->testing_resend_assoc = 0;
#endif /* CONFIG_TESTING_OPTIONS */
if (wpa_s->last_ssid == ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
wpa_s->reassoc_same_ess = 1;
if (wpa_s->current_bss && wpa_s->current_bss == bss) {
wmm_ac_save_tspecs(wpa_s);
wpa_s->reassoc_same_bss = 1;
} else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
os_get_reltime(&wpa_s->roam_start);
}
} else {
#ifdef CONFIG_SAE
wpa_s_clear_sae_rejected(wpa_s);
wpa_s_setup_sae_pt(wpa_s->conf, ssid);
#endif /* CONFIG_SAE */
}
if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
if (wpas_update_random_addr(wpa_s, rand_style) < 0)
return;
wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
} else if (rand_style == 0 && wpa_s->mac_addr_changed) {
if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Could not restore permanent MAC address");
return;
}
wpa_s->mac_addr_changed = 0;
if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Could not update MAC address information");
return;
}
wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
}
wpa_s->last_ssid = ssid;
if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
return;
}
if (ssid->mode == WPAS_MODE_MESH) {
return;
}
/*
* Set WPA state machine configuration to match the selected network now
* so that the information is available before wpas_start_assoc_cb()
* gets called. This is needed at least for RSN pre-authentication where
* candidate APs are added to a list based on scan result processing
* before completion of the first association.
*/
wpa_supplicant_rsn_supp_set_config(wpa_s, ssid);
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
ssid->mode == WPAS_MODE_INFRA) {
sme_authenticate(wpa_s, bss, ssid);
return;
}
if (wpa_s->connect_work) {
wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
return;
}
if (radio_work_pending(wpa_s, "connect")) {
wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since pending work exist");
return;
}
#ifdef CONFIG_SME
if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
/* Clear possibly set auth_alg, if any, from last attempt. */
wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
}
#endif /* CONFIG_SME */
wpas_abort_ongoing_scan(wpa_s);
cwork = os_zalloc(sizeof(*cwork));
if (cwork == NULL)
return;
cwork->bss = bss;
cwork->ssid = ssid;
if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
wpas_start_assoc_cb, cwork) < 0) {
os_free(cwork);
}
}
3 wpa_driver_nl80211_associate
driver_nl80211.c
static int wpa_driver_nl80211_associate(
void *priv, struct wpa_driver_associate_params *params)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ret = -1;
struct nl_msg *msg;
nl80211_unmask_11b_rates(bss);
//处理AP和IBSS的情况
if (params->mode == IEEE80211_MODE_AP)
return wpa_driver_nl80211_ap(drv, params);
if (params->mode == IEEE80211_MODE_IBSS)
return wpa_driver_nl80211_ibss(drv, params);
//目前大部分手机不支持WPA_DRIVER_FLAGS_SME
//前面的描述是,STA首先发送authentication请求,然后再发送association请求
//wpa_supplicant_associate中有一个sme_authenticate函数,用于发起authentication请求
//对于不支持SME(Station Management Entity)的wlan driver来说,WPAS只需要向wlan driver发送connect命令
//即可完成association和authentication两步
//实现方式与wlan driver和cfg80211有关
if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
enum nl80211_iftype nlmode = params->p2p ?
NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
if (params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE)
bss->use_nl_connect = 1;
else
bss->use_nl_connect = 0;
return wpa_driver_nl80211_connect(drv, params,
get_connect_handle(bss));
}
fail:
nlmsg_free(msg);
return ret;
}
4 wpa_driver_nl80211_connect
static int wpa_driver_nl80211_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
struct nl_sock *nl_connect)
{
int ret;
/* Store the connection attempted bssid for future use */
if (params->bssid)
os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
else
os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
if (ret == -EALREADY) {
/*
* cfg80211 does not currently accept new connections if
* we are already connected. As a workaround, force
* disconnection and try again.
*/
wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
"disconnecting before reassociation "
"attempt");
if (wpa_driver_nl80211_disconnect(
drv, WLAN_REASON_PREV_AUTH_NOT_VALID, nl_connect))
return -1;
ret = wpa_driver_nl80211_try_connect(drv, params, nl_connect);
}
return ret;
}
static int wpa_driver_nl80211_try_connect(
struct wpa_driver_nl80211_data *drv,
struct wpa_driver_associate_params *params,
struct nl_sock *nl_connect)
{
struct nl_msg *msg;
enum nl80211_auth_type type;
int ret;
int algs;
wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
if (!msg)
return -1;
ret = nl80211_connect_common(drv, params, msg);
}
至此,WPAS就把CONNECT请求发给了驱动,驱动将完成 Authenticaiton帧和Association Request帧的处理