wpa_supplicant與kernel交互的操做,通常須要先明確驅動接口,以及用戶態和kernel態的接口函數,以此來進行調用操做。這裏分爲4個步驟討論。sass
1.首先須要明確指定的驅動接口。由於有較多的驅動接口能夠使用,如wext、nl80211等。指定了以後,才能調用相應接口的方法。app
2.保存驅動接口less
3.接口函數的實現(分爲用戶態和kernel態)。系統已經定義了,咱們只需找到定義的地方,瞭解有哪些函數。socket
4.交互async
(a)用戶態向kernel態發送請求(經過ioctl)函數
(b)kernel態向用戶態發送事件通知(經過netlink)oop
1.首先須要明確指定的驅動接口spa
(1)查看init.XX.rc中指定的driver的命令參數;code
(2)根據命令參數,在wpa_driver_ops *wpa_drivers[] 中查找對應接口。接口
wpa_drivers[]的定義是在[-->external/wpa_supplicant_8/src/drivers/drivers.c]
2.保存驅動接口
在wpa_supplicant初始化過程當中,在wpa_supplicant_init_iface方法中會調用wpa_supplicant_set_driver方法。該方法中又會調用select_driver方法。
static int select_driver(struct wpa_supplicant *wpa_s, int i) { struct wpa_global *global = wpa_s->global;if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) { //調用global_init方法,這與driver選擇wext調用的流程不一樣了 global->drv_priv[i] = wpa_drivers[i]->global_init(); if (global->drv_priv[i] == NULL) { wpa_printf(MSG_ERROR, "Failed to initialize driver " "'%s'", wpa_drivers[i]->name); return -1; } } // 根據name進行匹配,並最後保存到wpa_supplicant->dirver中 wpa_s->driver = wpa_drivers[i]; wpa_s->global_drv_priv = global->drv_priv[i]; return 0; }
3.接口操做函數實現
3.1用戶態
代碼:/external/wpa_supplicant_8/wpa_supplicant/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 = wpa_driver_nl80211_set_key, .scan2 = wpa_driver_nl80211_scan, .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, .deauthenticate = wpa_driver_nl80211_deauthenticate, .disassociate = wpa_driver_nl80211_disassociate, .authenticate = wpa_driver_nl80211_authenticate, .associate = wpa_driver_nl80211_associate, .global_init = nl80211_global_init, .global_deinit = nl80211_global_deinit, .init2 = wpa_driver_nl80211_init, .deinit = wpa_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, .set_ap = wpa_driver_nl80211_set_ap, .if_add = wpa_driver_nl80211_if_add, .if_remove = wpa_driver_nl80211_if_remove, .send_mlme = wpa_driver_nl80211_send_mlme, .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data, .sta_add = wpa_driver_nl80211_sta_add, .sta_remove = wpa_driver_nl80211_sta_remove, .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol, #ifdef ANDROID_QCOM_PATCH .hapd_set_countermeasures = wpa_driver_nl80211_set_countermeasures,#endif .sta_set_flags = wpa_driver_nl80211_sta_set_flags, #ifdef HOSTAPD .hapd_init = i802_init, .hapd_deinit = i802_deinit, .set_wds_sta = i802_set_wds_sta,#endif /* HOSTAPD */#if defined(HOSTAPD) || defined(CONFIG_AP) .get_seqnum = i802_get_seqnum, .flush = i802_flush, .read_sta_data = i802_read_sta_data, .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 = i802_set_sta_vlan, .sta_deauth = i802_sta_deauth, .sta_disassoc = i802_sta_disassoc,#endif /* HOSTAPD || CONFIG_AP */ .set_freq = i802_set_freq, .send_action = wpa_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 = wpa_driver_nl80211_probe_req_report, .deinit_ap = wpa_driver_nl80211_deinit_ap, .resume = wpa_driver_nl80211_resume, .send_ft_action = nl80211_send_ft_action, .signal_monitor = nl80211_signal_monitor, .signal_poll = nl80211_signal_poll, .send_frame = nl80211_send_frame, .shared_freq = wpa_driver_nl80211_shared_freq, .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, #ifdef CONFIG_TDLS .send_tdls_mgmt = nl80211_send_tdls_mgmt, .tdls_oper = nl80211_tdls_oper,#endif /* CONFIG_TDLS */#ifdef ANDROID_P2P .set_noa = wpa_driver_set_p2p_noa,#endif#ifdef ANDROID .driver_cmd = wpa_driver_nl80211_driver_cmd, //處理DRIVER開頭的命令#endif};
ps:driver_cmd用於處理DRIVER的命令,調用流程以下:
wpa_supplicant_ctrl_iface_process-> (根據命令字符串調用對應的函數) wpa_supplicant_driver_cmd->wpa_drv_driver_cmd->wpa_s->driver->driver_cmd->wpa_driver_nl80211_driver_cmd -> (User) ... cfg80211...
3.2 kernel態實現
Kernel態實現的操做函數,實現代碼見:net/wireless/wext-compat.c
static const iw_handler cfg80211_handlers[] = { [IW_IOCTL_IDX(SIOCGIWNAME)] = (iw_handler) cfg80211_wext_giwname, [IW_IOCTL_IDX(SIOCSIWFREQ)] = (iw_handler) cfg80211_wext_siwfreq, [IW_IOCTL_IDX(SIOCGIWFREQ)] = (iw_handler) cfg80211_wext_giwfreq, [IW_IOCTL_IDX(SIOCSIWMODE)] = (iw_handler) cfg80211_wext_siwmode, [IW_IOCTL_IDX(SIOCGIWMODE)] = (iw_handler) cfg80211_wext_giwmode, [IW_IOCTL_IDX(SIOCGIWRANGE)] = (iw_handler) cfg80211_wext_giwrange, [IW_IOCTL_IDX(SIOCSIWAP)] = (iw_handler) cfg80211_wext_siwap, [IW_IOCTL_IDX(SIOCGIWAP)] = (iw_handler) cfg80211_wext_giwap, [IW_IOCTL_IDX(SIOCSIWMLME)] = (iw_handler) cfg80211_wext_siwmlme, [IW_IOCTL_IDX(SIOCSIWSCAN)] = (iw_handler) cfg80211_wext_siwscan, [IW_IOCTL_IDX(SIOCGIWSCAN)] = (iw_handler) cfg80211_wext_giwscan, [IW_IOCTL_IDX(SIOCSIWESSID)] = (iw_handler) cfg80211_wext_siwessid, [IW_IOCTL_IDX(SIOCGIWESSID)] = (iw_handler) cfg80211_wext_giwessid, [IW_IOCTL_IDX(SIOCSIWRATE)] = (iw_handler) cfg80211_wext_siwrate, [IW_IOCTL_IDX(SIOCGIWRATE)] = (iw_handler) cfg80211_wext_giwrate, [IW_IOCTL_IDX(SIOCSIWRTS)] = (iw_handler) cfg80211_wext_siwrts, [IW_IOCTL_IDX(SIOCGIWRTS)] = (iw_handler) cfg80211_wext_giwrts, [IW_IOCTL_IDX(SIOCSIWFRAG)] = (iw_handler) cfg80211_wext_siwfrag, [IW_IOCTL_IDX(SIOCGIWFRAG)] = (iw_handler) cfg80211_wext_giwfrag, [IW_IOCTL_IDX(SIOCSIWTXPOW)] = (iw_handler) cfg80211_wext_siwtxpower, [IW_IOCTL_IDX(SIOCGIWTXPOW)] = (iw_handler) cfg80211_wext_giwtxpower, [IW_IOCTL_IDX(SIOCSIWRETRY)] = (iw_handler) cfg80211_wext_siwretry, [IW_IOCTL_IDX(SIOCGIWRETRY)] = (iw_handler) cfg80211_wext_giwretry, [IW_IOCTL_IDX(SIOCSIWENCODE)] = (iw_handler) cfg80211_wext_siwencode, [IW_IOCTL_IDX(SIOCGIWENCODE)] = (iw_handler) cfg80211_wext_giwencode, [IW_IOCTL_IDX(SIOCSIWPOWER)] = (iw_handler) cfg80211_wext_siwpower, [IW_IOCTL_IDX(SIOCGIWPOWER)] = (iw_handler) cfg80211_wext_giwpower, [IW_IOCTL_IDX(SIOCSIWGENIE)] = (iw_handler) cfg80211_wext_siwgenie, [IW_IOCTL_IDX(SIOCSIWAUTH)] = (iw_handler) cfg80211_wext_siwauth, [IW_IOCTL_IDX(SIOCGIWAUTH)] = (iw_handler) cfg80211_wext_giwauth, [IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext, [IW_IOCTL_IDX(SIOCSIWPMKSA)] = (iw_handler) cfg80211_wext_siwpmksa, };const struct iw_handler_def cfg80211_wext_handler = { .num_standard = ARRAY_SIZE(cfg80211_handlers), .standard = cfg80211_handlers, .get_wireless_stats = cfg80211_wireless_stats, };
4.用戶態和kernel態交互
4.1初始化
首先說明下用戶態和kernel態交互的方式,以下所述:
a.用戶態向kernel態發送請求時,經過ioctl來實現
b.kernel態向用戶態發送事件通知,經過netlink實現
交互的初始化有兩部分組成:nl80211_global_init和wpa_driver_nl80211_init方法。以上a/b兩點中ioctl和netlink是在nl80211_global_init方法中建立。
(1) nl80211_global_init方法
由於在」2.保存驅動接口」,select_driver方法中調用了global_init方法(會根據用戶態的結構體wpa_driver_nl80211_ops中查找對應方法,即nl80211_global_init)。
static void * nl80211_global_init(void) { struct nl80211_global *global; struct netlink_config *cfg; global = os_zalloc(sizeof(*global)); if (global == NULL) return NULL; global->ioctl_sock = -1; dl_list_init(&global->interfaces); global->if_add_ifindex = -1; cfg = os_zalloc(sizeof(*cfg)); if (cfg == NULL) goto err; cfg->ctx = global; cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink; cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink; global->netlink = netlink_init(cfg); //初始化netlink,並註冊事件接收函數 if (global->netlink == NULL) { os_free(cfg); goto err; } if (wpa_driver_nl80211_init_nl_global(global) < 0) goto err;// 此global->ioctl_sock用做爲ioctl命令的fd global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0); if (global->ioctl_sock < 0) { perror("socket(PF_INET,SOCK_DGRAM)"); goto err; } return global; err: nl80211_global_deinit(global); return NULL; }
在nl80211_global_init方法中,有兩條關鍵語句:
(a)// 初始化netlink,並註冊事件接收函數 global->netlink = netlink_init(cfg); (b)// 此global->ioctl_sock用做爲ioctl命令的fdglobal->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
分析以上兩句:
(a)netlink_init方法中建立了一個socket,並添加到eloop_run方法中的rfds中。用於從kernel態發送事件給用戶態
netlink->sock =->sock, netlink_receive, netlink,NULL);
(b)該socket用於從用戶態發送請求給kernel態
(2)wpa_driver_nl80211_init方法
在wpa_supplicant_init_iface方法中有語句:
if (wpa_supplicant_set_driver(wpa_s, driver) < 0) return -1; wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
在設置完驅動後,會調用wpa_drv_init方法,其方法體中會調用init2方法,即wpa_driver_nl80211_init。該方法用來Initialize nl80211 driver interface.
4.2 用戶態和kernel態交互之ioctl實現
在用戶態可簡單執行一個ioctl(fd,cmd,...)命令便可。
先看下socket.c文件
/* * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear in the operation structures but are done directly via the socketcall() multiplexor. */static const struct file_operations socket_file_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .aio_read = sock_aio_read, .aio_write = sock_aio_write, .poll = sock_poll, .unlocked_ioctl = sock_ioctl, // 這個就是被執行的ioctl #ifdef CONFIG_COMPAT .compat_ioctl = compat_sock_ioctl,#endif .mmap = sock_mmap, .open = sock_no_open, /* special open code to disallow open via /proc */ .release = sock_close, .fasync = sock_fasync, .sendpage = sock_sendpage, .splice_write = generic_splice_sendpage, .splice_read = sock_splice_read, };
從用戶態調用sock_ioctl到kernel態調用iw_handler的執行流程以下:
sock_ioctl-> (kernel/net/socket.c) dev_ioctl-> (kernel/net/core/dev.c) 下面的方法都在/net/wireless/wext-core.c中 wext_handle_ioctl-> (把執行結果從kernel態copy到用戶態) wext_ioctl_dispatch->(參數包括cmd/ioctl_standard_call/ioctl_private_call) wireless_process_ioctl-> get_handler-> (根據cmd來判斷調用standard或是private,即ioctl_standard_call或是ioctl_private_call方法) ioctl_standard_call (執行cmd指定的iw_handler<cfg80211_handlers中定義的>,並返回結果)
這樣就完成了」經過ioctl,用戶態向kernel態發送請求」。
這個流程的代碼稍後貼出。
sock_ioctl
dev_ioctl
wext_handle_ioctl
wext_ioctl_dispatch
wireless_process_ioctl
ioctl_standard_call