前言:之前在(九十四) Android O 连接WiFi AP流程梳理续——连接网络 和(一百一十四) Android O 连接WiFi AP流程梳理续打了写基础,梳理到了eapol,现在继续看下。
1.eapol
百度百科是这么介绍的:
EAP是Extensible Authentication Protocol的缩写,EAPOL就是(EAP OVER LAN )基于局域网的扩展认证协议。 EAPOL是基于802.1X网络访问认证技术发展而来的。
2.流程梳理
之前看代码看到了
if (ssid) {
wpa_s->current_ssid = ssid;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->connect_without_scan =
(ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
/*
* Don\'t optimize next scan freqs since a new ESS has been
* selected.
*/
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
} else {
wpa_s->connect_without_scan = NULL;
}
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
wpa_s->scan_req = NORMAL_SCAN_REQ;
wpas_scan_reset_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
}
if (ssid)
先看下wpa_s->eapol是如何初始化的
2.1 eapol初始化
在wpa_supplicant.c中的 wpa_supplicant_init_iface 有这么一句
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
...
if (wpa_supplicant_init_eapol(wpa_s) < 0)
return -1;
wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
看下具体实现
int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
{
#ifdef IEEE8021X_EAPOL
struct eapol_ctx *ctx;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL) {
wpa_printf(MSG_ERROR, \"Failed to allocate EAPOL context.\");
return -1;
}
ctx->ctx = wpa_s;
ctx->msg_ctx = wpa_s;
ctx->eapol_send_ctx = wpa_s;
ctx->preauth = 0;
ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
ctx->eapol_send = wpa_supplicant_eapol_send;
ctx->set_wep_key = wpa_eapol_set_wep_key;
#ifndef CONFIG_NO_CONFIG_BLOBS
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
#endif /* CONFIG_NO_CONFIG_BLOBS */
ctx->aborted_cached = wpa_supplicant_aborted_cached;
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
ctx->wps = wpa_s->wps;
ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
#ifdef CONFIG_EAP_PROXY
ctx->eap_proxy_cb = wpa_supplicant_eap_proxy_cb;
ctx->eap_proxy_notify_sim_status =
wpa_supplicant_eap_proxy_notify_sim_status;
#endif /* CONFIG_EAP_PROXY */
ctx->port_cb = wpa_supplicant_port_cb;
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cert_cb = wpa_supplicant_cert_cb;
ctx->cert_in_cb = wpa_s->conf->cert_in_cb;
ctx->status_cb = wpa_supplicant_status_cb;
ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
os_free(ctx);
wpa_printf(MSG_ERROR, \"Failed to initialize EAPOL state \"
\"machines.\");
return -1;
}
#endif /* IEEE8021X_EAPOL */
return 0;
}
接着看eapol_sm_init
/**
* eapol_sm_init - Initialize EAPOL state machine
* @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
* and EAPOL state machine will free it in eapol_sm_deinit()
* Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
*
* Allocate and initialize an EAPOL state machine.
*/
struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
struct eapol_sm *sm;
struct eap_config conf;
sm = os_zalloc(sizeof(*sm));
if (sm == NULL)
return NULL;
sm->ctx = ctx;
sm->portControl = Auto;
/* Supplicant PAE state machine */
sm->heldPeriod = 60;
sm->startPeriod = 30;
sm->maxStart = 3;
/* Supplicant Backend state machine */
sm->authPeriod = 30;
os_memset(&conf, 0, sizeof(conf));
conf.opensc_engine_path = ctx->opensc_engine_path;
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
conf.pkcs11_module_path = ctx->pkcs11_module_path;
conf.openssl_ciphers = ctx->openssl_ciphers;
conf.wps = ctx->wps;
conf.cert_in_cb = ctx->cert_in_cb;
sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
if (sm->eap == NULL) {
os_free(sm);
return NULL;
}
#ifdef CONFIG_EAP_PROXY
sm->use_eap_proxy = FALSE;
sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
if (sm->eap_proxy == NULL) {
wpa_printf(MSG_ERROR, \"Unable to initialize EAP Proxy\");
}
#endif /* CONFIG_EAP_PROXY */
/* Initialize EAPOL state machines */
sm->force_authorized_update = TRUE;
sm->initialize = TRUE;
eapol_sm_step(sm);
sm->initialize = FALSE;
eapol_sm_step(sm);
sm->timer_tick_enabled = 1;
eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
return sm;
}
再看下eapol_sm_step
/**
* eapol_sm_step - EAPOL state machine step function
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
*
* This function is called to notify the state machine about changed external
* variables. It will step through the EAPOL state machines in loop to process
* all triggered state changes.
*/
void eapol_sm_step(struct eapol_sm *sm)
{
int i;
/* In theory, it should be ok to run this in loop until !changed.
* However, it is better to use a limit on number of iterations to
* allow events (e.g., SIGTERM) to stop the program cleanly if the
* state machine were to generate a busy loop. */
for (i = 0; i < 100; i++) {
sm->changed = FALSE;
SM_STEP_RUN(SUPP_PAE);
SM_STEP_RUN(KEY_RX);
SM_STEP_RUN(SUPP_BE);
#ifdef CONFIG_EAP_PROXY
if (sm->use_eap_proxy) {
/* Drive the EAP proxy state machine */
if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
sm->changed = TRUE;
} else
#endif /* CONFIG_EAP_PROXY */
if (eap_peer_sm_step(sm->eap))
sm->changed = TRUE;
if (!sm->changed)
break;
}
if (sm->changed) {
/* restart EAPOL state machine step from timeout call in order
* to allow other events to be processed. */
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
}
if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
enum eapol_supp_result result;
if (sm->cb_status == EAPOL_CB_SUCCESS)
result = EAPOL_SUPP_RESULT_SUCCESS;
else if (eap_peer_was_failure_expected(sm->eap))
result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
else
result = EAPOL_SUPP_RESULT_FAILURE;
sm->cb_status = EAPOL_CB_IN_PROGRESS;
sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
}
}
2.2 连接
if (ssid) {
wpa_s->current_ssid = ssid;
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_s->connect_without_scan =
(ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
/*
* Don\'t optimize next scan freqs since a new ESS has been
* selected.
*/
os_free(wpa_s->next_scan_freqs);
wpa_s->next_scan_freqs = NULL;
} else {
wpa_s->connect_without_scan = NULL;
}
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
wpa_s->scan_req = NORMAL_SCAN_REQ;
wpas_scan_reset_sched_scan(wpa_s);
wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
}
if (ssid)
wpas_notify_network_selected(wpa_s, ssid);
eapol_supp_sm.c
/**
* eapol_sm_notify_config - Notification of EAPOL configuration change
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
* @config: Pointer to current network EAP configuration
* @conf: Pointer to EAPOL configuration data
*
* Notify EAPOL state machine that configuration has changed. config will be
* stored as a backpointer to network configuration. This can be %NULL to clear
* the stored pointed. conf will be copied to local EAPOL/EAP configuration
* data. If conf is %NULL, this part of the configuration change will be
* skipped.
*/
void eapol_sm_notify_config(struct eapol_sm *sm,
struct eap_peer_config *config,
const struct eapol_config *conf)
{
if (sm == NULL)
return;
sm->config = config;
#ifdef CONFIG_EAP_PROXY
sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
#endif /* CONFIG_EAP_PROXY */
if (conf == NULL)
return;
sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
sm->conf.required_keys = conf->required_keys;
sm->conf.fast_reauth = conf->fast_reauth;
sm->conf.workaround = conf->workaround;
sm->conf.wps = conf->wps;
#ifdef CONFIG_EAP_PROXY
if (sm->use_eap_proxy) {
/* Using EAP Proxy, so skip EAP state machine update */
return;
}
#endif /* CONFIG_EAP_PROXY */
if (sm->eap) {
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
eap_set_workaround(sm->eap, conf->workaround);
eap_set_force_disabled(sm->eap, conf->eap_disabled);
eap_set_external_sim(sm->eap, conf->external_sim);
}
}
void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
if (wpa_s->p2p_mgmt)
return;
wpas_dbus_signal_network_selected(wpa_s, ssid->id);
}
/**
* wpas_dbus_signal_network_selected - Send a network selected signal
* @wpa_s: %wpa_supplicant network interface data
* @id: network id
*
* Notify listeners about selecting a network
*/
void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id)
{
wpas_dbus_signal_network(wpa_s, id, \"NetworkSelected\", FALSE);
}
/**
* wpas_dbus_signal_network - Send a network related event signal
* @wpa_s: %wpa_supplicant network interface data
* @id: new network id
* @sig_name: signal name - NetworkAdded, NetworkRemoved or NetworkSelected
* @properties: determines if add second argument with object properties
*
* Notify listeners about event related with configured network
*/
static void wpas_dbus_signal_network(struct wpa_supplicant *wpa_s,
int id, const char *sig_name,
int properties)
{
struct wpas_dbus_priv *iface;
DBusMessage *msg;
DBusMessageIter iter;
char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
iface = wpa_s->global->dbus;
/* Do nothing if the control interface is not turned on */
if (iface == NULL || !wpa_s->dbus_new_path)
return;
os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
\"%s/\" WPAS_DBUS_NEW_NETWORKS_PART \"/%u\",
wpa_s->dbus_new_path, id);
msg = dbus_message_new_signal(wpa_s->dbus_new_path,
WPAS_DBUS_NEW_IFACE_INTERFACE,
sig_name);
if (msg == NULL)
return;
dbus_message_iter_init_append(msg, &iter);
path = net_obj_path;
if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
&path) ||
(properties &&
!wpa_dbus_get_object_properties(
iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
&iter)))
wpa_printf(MSG_ERROR, \"dbus: Failed to construct signal\");
else
dbus_connection_send(iface->con, msg, NULL);
dbus_message_unref(msg);
}
3.总结
又回到了一脸懵逼的状态,待续。。。
版权声明
本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。




