wpa_supplicant 服務啓動:
service wpa_supplicant /system/bin/wpa_supplicant \
-iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \
-I/system/etc/wifi/wpa_supplicant_overlay.conf \
-O/data/misc/wifi/sockets -dd \
-e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0
# we will start as root and wpa_supplicant will switch to user wifi
# after setting up the capabilities required for WEXT
# user wifi
# group wifi inet keystore
class main
socket wpa_wlan0 dgram 660 wifi wifi
disabled
oneshot
external\wpa_supplicant_8\wpa_supplicant\main.c main函數:
int main(int argc, char *argv[])
{
int c, i;
struct wpa_interface *ifaces, *iface;
int iface_count, exitcode = -1;
struct wpa_params params;
struct wpa_global *global;
/*設置wpa_supplicant在android系統的一些權限,防止通過wpa_supplicant服務來獲取root權限*/
if (os_program_init())
return -1;
os_memset(¶ms, 0, sizeof(params));
params.wpa_debug_level = MSG_INFO;
iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
if (ifaces == NULL)
return -1;
iface_count = 1;
//輸入輸出重定向到 /dev/null
wpa_supplicant_fd_workaround(1);
for (;;) {
c = getopt(argc, argv,
"b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
if (c < 0)
break;
switch (c) {
case 'b':
iface->bridge_ifname = optarg;
break;
case 'B':
params.daemonize++;
break;
case 'c':
iface->confname = optarg;
break;
case 'C':
iface->ctrl_interface = optarg;
break;
case 'D':
iface->driver = optarg;
break;
case 'd':
#ifdef CONFIG_NO_STDOUT_DEBUG
printf("Debugging disabled with "
"CONFIG_NO_STDOUT_DEBUG=y build time "
"option.\n");
goto out;
#else /* CONFIG_NO_STDOUT_DEBUG */
params.wpa_debug_level--;
break;
#endif /* CONFIG_NO_STDOUT_DEBUG */
case 'e':
params.entropy_file = optarg;
break;
#ifdef CONFIG_DEBUG_FILE
case 'f':
params.wpa_debug_file_path = optarg;
break;
#endif /* CONFIG_DEBUG_FILE */
case 'g':
params.ctrl_interface = optarg;
break;
case 'G':
params.ctrl_interface_group = optarg;
break;
case 'h':
usage();
exitcode = 0;
goto out;
case 'i':
iface->ifname = optarg;
break;
case 'I':
iface->confanother = optarg;
break;
case 'K':
params.wpa_debug_show_keys++;
break;
case 'L':
license();
exitcode = 0;
goto out;
#ifdef CONFIG_P2P
case 'm':
params.conf_p2p_dev = optarg;
break;
#endif /* CONFIG_P2P */
case 'o':
params.override_driver = optarg;
break;
case 'O':
params.override_ctrl_interface = optarg;
break;
case 'p':
iface->driver_param = optarg;
break;
case 'P':
os_free(params.pid_file);
params.pid_file = os_rel2abs_path(optarg);
break;
case 'q':
params.wpa_debug_level++;
break;
#ifdef CONFIG_DEBUG_SYSLOG
case 's':
params.wpa_debug_syslog++;
break;
#endif /* CONFIG_DEBUG_SYSLOG */
#ifdef CONFIG_DEBUG_LINUX_TRACING
case 'T':
params.wpa_debug_tracing++;
break;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
case 't':
params.wpa_debug_timestamp++;
break;
#ifdef CONFIG_DBUS
case 'u':
params.dbus_ctrl_interface = 1;
break;
#endif /* CONFIG_DBUS */
case 'v':
printf("%s\n", wpa_supplicant_version);
exitcode = 0;
goto out;
case 'W':
params.wait_for_monitor++;
break;
#ifdef CONFIG_MATCH_IFACE
case 'M':
params.match_iface_count++;
iface = os_realloc_array(params.match_ifaces,
params.match_iface_count,
sizeof(struct wpa_interface));
if (!iface)
goto out;
params.match_ifaces = iface;
iface = ¶ms.match_ifaces[params.match_iface_count -
1];
os_memset(iface, 0, sizeof(*iface));
break;
#endif /* CONFIG_MATCH_IFACE */
case 'N':
iface_count++;
iface = os_realloc_array(ifaces, iface_count,
sizeof(struct wpa_interface));
if (iface == NULL)
goto out;
ifaces = iface;
iface = &ifaces[iface_count - 1];
os_memset(iface, 0, sizeof(*iface));
break;
default:
usage();
exitcode = 0;
goto out;
}
}
exitcode = 0;
/*
wpa_supplicant_init函數的主要功能師初始化wpa_global以及一些與整個程序相關的資源
包括隨機數資源,eloop事件循環機制以及設置消息全局回調函數。
全局回調函數:
wpa_supplicant_msg_ifname_cb: 用於獲取網卡接口名
*/
// 根據傳入的參數創建並初始化一個wpa_global對象
global = wpa_supplicant_init(¶ms);
if (global == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
exitcode = -1;
goto out;
} else {
wpa_printf(MSG_INFO, "Successfully initialized "
"wpa_supplicant");
}
if (fst_global_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize FST");
exitcode = -1;
goto out;
}
#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
if (!fst_global_add_ctrl(fst_ctrl_cli))
wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
#endif
for (i = 0; exitcode == 0 && i < iface_count; i++) {
struct wpa_supplicant *wpa_s;
if ((ifaces[i].confname == NULL &&
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
if (iface_count == 1 && (params.ctrl_interface ||
#ifdef CONFIG_MATCH_IFACE
params.match_iface_count ||
#endif /* CONFIG_MATCH_IFACE */
params.dbus_ctrl_interface))
break;
usage();
exitcode = -1;
break;
}
/* WPAS支持操作多個無線網絡設備,此處需將它們一一添加到WPAS中 WPAS內部將初始化這些設備 */
wpa_s = wpa_supplicant_add_iface(global, &ifaces[i], NULL);
if (wpa_s == NULL) {
exitcode = -1;
break;
}
}
#ifdef CONFIG_MATCH_IFACE
if (exitcode == 0)
exitcode = wpa_supplicant_init_match(global);
#endif /* CONFIG_MATCH_IFACE */
if (exitcode == 0)
exitcode = wpa_supplicant_run(global);
wpa_supplicant_deinit(global);
fst_global_deinit();
out:
wpa_supplicant_fd_workaround(0);
os_free(ifaces);
#ifdef CONFIG_MATCH_IFACE
os_free(params.match_ifaces);
#endif /* CONFIG_MATCH_IFACE */
os_free(params.pid_file);
os_program_deinit();
return exitcode;
}
struct wpa_interface :結構體用來描述一個無線網絡設備,在main函數初始化的時候使用。 啓動服務解析參數後保存在wpa_interface結構體中。
struct wpa_global:是一個全局性質的上下文信息。它通過ifaces變量指向一個wpa_supplicant對象,
struct wpa_supplicant:是wpa_supplicant的核心數據結構。 一個interface對應一個wpa_supplicant對象。
struct ctrl_iface_global_priv: 是全局控制接口的信息,內部包含一個用於通信的socket句柄。
wpa_supplicant_init函數:
**
* wpa_supplicant_init - Initialize %wpa_supplicant
* @params: Parameters for %wpa_supplicant
* Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
*
* This function is used to initialize %wpa_supplicant. After successful
* initialization, the returned data pointer can be used to add and remove
* network interfaces, and eventually, to deinitialize %wpa_supplicant.
*/
struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
{
struct wpa_global *global;
int ret, i;
if (params == NULL)
return NULL;
#ifdef CONFIG_DRIVER_NDIS
{
void driver_ndis_init_ops(void);
driver_ndis_init_ops();
}
#endif /* CONFIG_DRIVER_NDIS */
#ifndef CONFIG_NO_WPA_MSG
//設置全局回調函數 wpa_msg_ifname_cb = wpa_supplicant_msg_ifname_cb
wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
#endif /* CONFIG_NO_WPA_MSG */
//根據服務啓動參數,決定是否開啓輸出日誌文件
if (params->wpa_debug_file_path)
wpa_debug_open_file(params->wpa_debug_file_path);
else
wpa_debug_setup_stdout();
if (params->wpa_debug_syslog)
wpa_debug_open_syslog();
if (params->wpa_debug_tracing) {
ret = wpa_debug_open_linux_tracing();
if (ret) {
wpa_printf(MSG_ERROR,
"Failed to enable trace logging");
return NULL;
}
}
// 註冊EAP方法
ret = eap_register_methods();
if (ret) {
wpa_printf(MSG_ERROR, "Failed to register EAP methods");
if (ret == -2)
wpa_printf(MSG_ERROR, "Two or more EAP methods used "
"the same EAP type.");
return NULL;
}
//創建一個wpa_global對象
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
/* 以下爲對wpa_global對象初始化*/
dl_list_init(&global->p2p_srv_bonjour);
dl_list_init(&global->p2p_srv_upnp);
global->params.daemonize = params->daemonize;
global->params.wait_for_monitor = params->wait_for_monitor;
global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
if (params->pid_file)
global->params.pid_file = os_strdup(params->pid_file);
if (params->ctrl_interface)
global->params.ctrl_interface =
os_strdup(params->ctrl_interface);
if (params->ctrl_interface_group)
global->params.ctrl_interface_group =
os_strdup(params->ctrl_interface_group);
if (params->override_driver)
global->params.override_driver =
os_strdup(params->override_driver);
if (params->override_ctrl_interface)
global->params.override_ctrl_interface =
os_strdup(params->override_ctrl_interface);
#ifdef CONFIG_MATCH_IFACE
global->params.match_iface_count = params->match_iface_count;
if (params->match_iface_count) {
global->params.match_ifaces =
os_calloc(params->match_iface_count,
sizeof(struct wpa_interface));
os_memcpy(global->params.match_ifaces,
params->match_ifaces,
params->match_iface_count *
sizeof(struct wpa_interface));
}
#endif /* CONFIG_MATCH_IFACE */
#ifdef CONFIG_P2P
if (params->conf_p2p_dev)
global->params.conf_p2p_dev =
os_strdup(params->conf_p2p_dev);
#endif /* CONFIG_P2P */
wpa_debug_level = global->params.wpa_debug_level =
params->wpa_debug_level;
wpa_debug_show_keys = global->params.wpa_debug_show_keys =
params->wpa_debug_show_keys;
wpa_debug_timestamp = global->params.wpa_debug_timestamp =
params->wpa_debug_timestamp;
wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
// 初始化事件循環機制
if (eloop_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
wpa_supplicant_deinit(global);
return NULL;
}
// 初始化隨機數相關資源
random_init(params->entropy_file);
// 初始化全局控制接口對象,
global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
if (global->ctrl_iface == NULL) {
wpa_supplicant_deinit(global);
return NULL;
}
// 初始化通訊機制相關資源,它和dbus有關?
if (wpas_notify_supplicant_initialized(global)) {
wpa_supplicant_deinit(global);
return NULL;
}
for (i = 0; wpa_drivers[i]; i++)
global->drv_count++;
if (global->drv_count == 0) {
wpa_printf(MSG_ERROR, "No drivers enabled");
wpa_supplicant_deinit(global);
return NULL;
}
//分配全局 driver wrapper 上下文信息數組
global->drv_priv = os_calloc(global->drv_count, sizeof(void *));
if (global->drv_priv == NULL) {
wpa_supplicant_deinit(global);
return NULL;
}
#ifdef CONFIG_WIFI_DISPLAY
if (wifi_display_init(global) < 0) {
wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
wpa_supplicant_deinit(global);
return NULL;
}
#endif /* CONFIG_WIFI_DISPLAY */
eloop_register_timeout(WPA_SUPPLICANT_CLEANUP_INTERVAL, 0,
wpas_periodic, global, NULL);
return global;
}
wpa_supplicant_init函數的主要功能師初始化wpa_global以及一些與整個程序相關的資源
包括隨機數資源,eloop事件循環機制以及設置消息全局回調函數。
全局回調函數:
wpa_supplicant_msg_ifname_cb: 用於獲取網卡接口名
wpa_supplicant_init函數中的eloop_init主要功能初始化wpa_supplicant中事件驅動的核心數據結構體eloop_data。
wpa_supplicant的事件驅動機制支持5中類型event:
- read event: 讀事件 例如來自socket的可讀事件;
- write event: 寫事件,例如來自socket的寫事件;
- exception event: 異常事件,如果socket操作發生錯誤,則由錯誤事件處理。
- timeout event:定時事件, 通過select的等待超時機制來實現定時事件。
- signal:信號事件,信號事件來源於kernel,wpa_supplicant允許爲一些特定信號設置處理函數。
wpa_drivers數組:定義如下:
const struct wpa_driver_ops *const wpa_drivers[] =
{
#ifdef CONFIG_DRIVER_NL80211
&wpa_driver_nl80211_ops,
#endif /* CONFIG_DRIVER_NL80211 */
#ifdef CONFIG_DRIVER_WEXT
&wpa_driver_wext_ops,
#endif /* CONFIG_DRIVER_WEXT */
#ifdef CONFIG_DRIVER_HOSTAP
&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
#ifdef CONFIG_DRIVER_BSD
&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
#ifdef CONFIG_DRIVER_OPENBSD
&wpa_driver_openbsd_ops,
#endif /* CONFIG_DRIVER_OPENBSD */
#ifdef CONFIG_DRIVER_NDIS
&wpa_driver_ndis_ops,
#endif /* CONFIG_DRIVER_NDIS */
#ifdef CONFIG_DRIVER_WIRED
&wpa_driver_wired_ops,
#endif /* CONFIG_DRIVER_WIRED */
#ifdef CONFIG_DRIVER_MACSEC_QCA
&wpa_driver_macsec_qca_ops,
#endif /* CONFIG_DRIVER_MACSEC_QCA */
#ifdef CONFIG_DRIVER_ROBOSWITCH
&wpa_driver_roboswitch_ops,
#endif /* CONFIG_DRIVER_ROBOSWITCH */
#ifdef CONFIG_DRIVER_ATHEROS
&wpa_driver_atheros_ops,
#endif /* CONFIG_DRIVER_ATHEROS */
#ifdef CONFIG_DRIVER_NONE
&wpa_driver_none_ops,
#endif /* CONFIG_DRIVER_NONE */
NULL
};
wpa_drivers數組成員指向一個wpa_driver_ops類型的對象。 wpa_driver_ops是driver i/f模塊的核心數據結構。 定義了很多函數指針。
wpa_driver_nl80211_ops定義:
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,
.sched_scan = wpa_driver_nl80211_sched_scan,
.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
.abort_scan = wpa_driver_nl80211_abort_scan,
.deauthenticate = driver_nl80211_deauthenticate,
.authenticate = driver_nl80211_authenticate,
.associate = wpa_driver_nl80211_associate,
.global_init = nl80211_global_init,
.global_deinit = nl80211_global_deinit,
.init2 = wpa_driver_nl80211_init,
.deinit = driver_nl80211_deinit,
.get_capa = wpa_driver_nl80211_get_capa,
.set_operstate = wpa_driver_nl80211_set_operstate,
.set_supp_port = wpa_driver_nl80211_set_supp_port,
.set_country = wpa_driver_nl80211_set_country,
.get_country = wpa_driver_nl80211_get_country,
.set_ap = wpa_driver_nl80211_set_ap,
.set_acl = wpa_driver_nl80211_set_acl,
.if_add = wpa_driver_nl80211_if_add,
.if_remove = driver_nl80211_if_remove,
.send_mlme = driver_nl80211_send_mlme,
.get_hw_feature_data = nl80211_get_hw_feature_data,
.sta_add = wpa_driver_nl80211_sta_add,
.sta_remove = driver_nl80211_sta_remove,
.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
.hapd_init = i802_init,
.hapd_deinit = i802_deinit,
.set_wds_sta = i802_set_wds_sta,
.get_seqnum = i802_get_seqnum,
.flush = i802_flush,
.get_inact_sec = i802_get_inact_sec,
.sta_clear_stats = i802_sta_clear_stats,
.set_rts = i802_set_rts,
.set_frag = i802_set_frag,
.set_tx_queue_params = i802_set_tx_queue_params,
.set_sta_vlan = driver_nl80211_set_sta_vlan,
.sta_deauth = i802_sta_deauth,
.sta_disassoc = i802_sta_disassoc,
.read_sta_data = driver_nl80211_read_sta_data,
.set_freq = i802_set_freq,
.send_action = driver_nl80211_send_action,
.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
.cancel_remain_on_channel =
wpa_driver_nl80211_cancel_remain_on_channel,
.probe_req_report = driver_nl80211_probe_req_report,
.deinit_ap = wpa_driver_nl80211_deinit_ap,
.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
.resume = wpa_driver_nl80211_resume,
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
.send_frame = nl80211_send_frame,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
.add_pmkid = nl80211_add_pmkid,
.remove_pmkid = nl80211_remove_pmkid,
.flush_pmkid = nl80211_flush_pmkid,
.set_rekey_info = nl80211_set_rekey_info,
.poll_client = nl80211_poll_client,
.set_p2p_powersave = nl80211_set_p2p_powersave,
.start_dfs_cac = nl80211_start_radar_detection,
.stop_ap = wpa_driver_nl80211_stop_ap,
#ifdef CONFIG_TDLS
.send_tdls_mgmt = nl80211_send_tdls_mgmt,
.tdls_oper = nl80211_tdls_oper,
.tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
.tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
#endif /* CONFIG_TDLS */
.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
.get_mac_addr = wpa_driver_nl80211_get_macaddr,
.get_survey = wpa_driver_nl80211_get_survey,
.status = wpa_driver_nl80211_status,
.switch_channel = nl80211_switch_channel,
#ifdef ANDROID_P2P
.set_noa = wpa_driver_set_p2p_noa,
.get_noa = wpa_driver_get_p2p_noa,
.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
#endif /* ANDROID_P2P */
#ifdef ANDROID
#ifndef ANDROID_LIB_STUB
.driver_cmd = wpa_driver_nl80211_driver_cmd,
#endif /* !ANDROID_LIB_STUB */
#endif /* ANDROID */
.vendor_cmd = nl80211_vendor_cmd,
.set_qos_map = nl80211_set_qos_map,
.set_wowlan = nl80211_set_wowlan,
#ifdef CONFIG_DRIVER_NL80211_QCA
.roaming = nl80211_roaming,
#endif /* CONFIG_DRIVER_NL80211_QCA */
.set_mac_addr = nl80211_set_mac_addr,
#ifdef CONFIG_MESH
.init_mesh = wpa_driver_nl80211_init_mesh,
.join_mesh = wpa_driver_nl80211_join_mesh,
.leave_mesh = wpa_driver_nl80211_leave_mesh,
#endif /* CONFIG_MESH */
.br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
.br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
.br_port_set_attr = wpa_driver_br_port_set_attr,
.br_set_net_param = wpa_driver_br_set_net_param,
.add_tx_ts = nl80211_add_ts,
.del_tx_ts = nl80211_del_ts,
.get_ifindex = nl80211_get_ifindex,
#ifdef CONFIG_DRIVER_NL80211_QCA
.do_acs = wpa_driver_do_acs,
.set_band = nl80211_set_band,
.get_pref_freq_list = nl80211_get_pref_freq_list,
.set_prob_oper_freq = nl80211_set_prob_oper_freq,
.p2p_lo_start = nl80211_p2p_lo_start,
.p2p_lo_stop = nl80211_p2p_lo_stop,
.set_default_scan_ies = nl80211_set_default_scan_ies,
.set_tdls_mode = nl80211_set_tdls_mode,
#endif /* CONFIG_DRIVER_NL80211_QCA */
.get_ext_capab = nl80211_get_ext_capab,
};
wpa_supplicant_add_iface函數:
wpa_supplicant_add_iface函數作用,向wpa_supplicant添加接口設備。 對這些設備鏡像初始化。
主要數據結構:
struct wpa_ssid : 用於存儲某個無線網絡的配置信息(如所支持的安全類型,優先等級)。它其實是wpa_supplicant.conf中無線網絡配置項在代碼中的反映。 conf中的network項都對應一個wpa_ssid對象。
wpa_supplicant_init_iface函數:
所先從配置文件中讀取數據,保存到 wpa_config和wpa_ssid中, wpa_ssid保存的是ssid信息。