wpa_supplicant-2.5源码解析转载
主程序
wpa_supplicant/main.c/main()
wpa_supplicant_init()
// 初始化wpa_global, eloop_data
wpa_supplicant_add_iface()
wpa_supplicant_run()
1. wpa_global对象描述全局上下文信息,
struct wpa_supplicant *ifaces:指向wpa_supplicant对象链表,
void **drv_priv = wpa_drivers[i]->global_init():包含driver所需要的全局上下文信息,
struct ctrl_iface_global_priv *ctrl_iface:对应全局控制接口,如果设置了该接口,其他wap_interface设置的控制接口将被代替。
2. 每个wpa_interface对象描述一个无线网络设备,对应一个wpa_supplicant,
confname配置文件名,driver对应的驱动名,ifname网络接口设备名,ctrl_interface控制接口路径。
3. wpa_supplicant对象,
struct wpa_config *conf
struct wpa_ssid *ssid // Head of the global network list
struct wpa_sm *wpa:WPA状态机
struct wpa_sm_ctx *ctx
struct eapol_sm *eapol
struct eapol_sm *eapol:
struct eapol_ctx *ctx
struct eap_sm *eap
void *drv_priv:包含driver所需要的全局上下文信息,由 wpa_s->driver->init2()/init()得到,
void *global_drv_priv = global->drv_priv[i]:
struct wpa_driver_ops *driver:
struct ctrl_iface_priv *ctrl_iface:控制接口
4. struct wpa_ssid代表一个network配置,配置文件中每个network会建立一个struct wpa_ssid。
struct wpa_bss代表一个真实的network,一个BSS。
SM通用宏:
SM_STATE(machine, state) 表示一个Entry Action,一个静态函数声明
SM_ENTRY(machine, state) 表示一段通用的入口代码
SM_ENTER(machine, state) 表示Entry Action的一次调用
SM_ENTER_GLOBAL(machine, state) 表示Entry Action的一次UCT调用,直接进入某个状态
SM_STEP(machine) 状态机运行的函数定义
SM_STEP_RUN(machine) 调用状态机运行函数
RFC 4137描述了EAP协议,Supplicant端和Authenticator端通过SM实现EAP处理流程。
RFC 4137将Supplicant端SM(SSM)分为三层:底层(EAP收发)-SSM层-Method层。EAP SM有13个状态。
EAPOL参考了IEEE 802.1X规范,实现了EAP协议的底层。802.1X为Supplicant定义了5个状态机:
Port Timers SM: Port超时控制状态机。PT SM,2个状态,wpa_supplicant用eapol_port_timers_tick()实现。
Supplicant PAE SM: 维护Port的状态,PAE即Port Access Entitiy。PAE SM,9个状态。
Supplicant Backend SM: 向Authenticator发送EAPOL回复消息。BE SM,8个状态。
The Key Receiver SM : 处理EAPOL-Key帧相关流程。TKR SM,2个状态。
The Supplicant Key Transmit SM: 非必选项, WPAS未实现
统称PACP( Port Access Control Protocol)State Machine。
wpa_supplicant_init
wpa_supplicant_init()
eap_register_methods() // 注册EAP方法
eloop_init() // 初始化eloop_data。处理5种事件:read/write/exception/timeout/signal
wpa_supplicant_global_ctrl_iface_init() // 初始化全局控制接口对象
wpas_notify_supplicant_initialized() // 初始化通知机制相关资源, 它和dbus有关
wpa_supplicant_init()主要功能是初始化wpa_global。有两个全局callback函数:wpa_msg_get_ifname_func, 有些输出信息中需要打印出网卡接口名, 该回调函数
用于获取网卡接口名;wpa_msg_cb_func: 除了打印输出信息外, 还可通过该回调函数进行一些特殊处理, 如把输出信息发送给客户端进行处理。
wpa_supplicant_add_iface
wpa_s = wpa_supplicant_add_iface() // 添加网卡
wpa_supplicant_init_iface() // 初始化网卡 wpa_config_read() // 读取网卡对应的配置文件 wpas_init_driver() // 初始化驱动 wpa_supplicant_set_driver() // 根据-Dnl80211、-Dwired等参数,确定驱动类型 select_driver() // 遍历wpa_drivers全局结构体,根据名字查找驱动 global->drv_priv[i] = wpa_drivers[i]->global_init() // 返回struct nl80211_global对象,全局上下文信息 nl80211_global_init() // 处理网卡状态变化事件:UP/DORMANT/REMOVED (struct nl80211_global *)global->netlink = netlink_init(cfg) netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE) bind(netlink->sock, (struct sockaddr *) &local, sizeof(local)) eloop_register_read_sock(netlink->sock, netlink_receive, netlink, NULL) wpa_driver_nl80211_init_nl_global(global) global->nl = nl_create_handle(global->nl_cb, "nl") // 用于发送netlink消息 global->nl_event = nl_create_handle(global->nl_cb, "event") // 用于接收netlink消息 // 设置netlink消息回调处理函数 nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_global_event, global) (struct nl80211_global *)global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0) wpa_s->driver = wpa_drivers[i] // (struct wpa_driver_ops *) wpa_s->global_drv_priv = global->drv_priv[i] // 一个struct nl80211_global *global对象 wpa_drv_init() // driver的局部上下文信息初始化 wpa_s->drv_priv = wpa_s->driver->init2()/init() // 返回struct i802_bss对象 wpa_driver_nl80211_init() => wpa_driver_nl80211_drv_init() wpa_driver_nl80211_capa(drv) // 获取无线网络设备的capability nl80211_init_bss(bss) // 设置bss事件处理回调函数,注意此时并没有创建nl_handle即nl_socket nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_bss_event, bss) /* rfkill代表radio frequency( RF) connector kill switch support, 它是Kernel中的 一个子系统( subsystem) 。 其功能是控制系统中射频设备的电源( 包括Wi-Fi、 GPS、 BlueTooth、 FM等设备。 注意, 这些设备驱动只有把自己注册到rfkill子系统中后, rfkill 才能对它们起作用) 的工作以避免浪费电力。 rfkill有软硬两种方式来禁止( block) RF设 备。 */ drv->rfkill = rfkill_init(rcfg) // 接收rfkill事件,查看无线设备是开启还是关闭。 eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL) linux_iface_up(drv->global->ioctl_sock, ifname) wpa_driver_nl80211_finish_drv_init() wpa_driver_nl80211_set_mode() // 设置接口类型为NL80211_IFTYPE_STATION ... wpa_supplicant_init_wpa() // 初始化wpa_sm相关的资源 wpa_sm_init() // 初始化wpa_sm状态机 wpa_drv_get_hw_feature_data() wpa_supplicant_driver_init() wpa_supplicant_update_mac_addr() wpa_s->l2 = l2_packet_init(ETH_P_EAPOL, wpa_supplicant_rx_eapol) // 接收EAPOL回调函数 eloop_register_read_sock() wpa_supplicant_req_scan() // 发起有效SSID的扫描 wpas_wps_init() wpa_supplicant_init_eapol() // 初始化EAPOL wpa_s->eapol = eapol_sm_init(ctx) sm->eap = eap_peer_sm_init() // 初始化EAP SM eloop_register_timeout(eapol_port_timers_tick) wpa_sm_set_eapol() wpa_supplicant_ctrl_iface_init() gas_query_init() wpas_p2p_init() wpa_bss_init() wpas_notify_network_added()
wpa_supplicant_init_iface() // 初始化网卡
wpa_config_read() // 读取网卡对应的配置文件
wpas_init_driver() // 初始化驱动
wpa_supplicant_set_driver() // 根据-Dnl80211、-Dwired等参数,确定驱动类型
select_driver() // 遍历wpa_drivers全局结构体,根据名字查找驱动
global->drv_priv[i] = wpa_drivers[i]->global_init() // 返回struct nl80211_global对象,全局上下文信息
nl80211_global_init()
// 处理网卡状态变化事件:UP/DORMANT/REMOVED
(struct nl80211_global *)global->netlink = netlink_init(cfg)
netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)
bind(netlink->sock, (struct sockaddr *) &local, sizeof(local))
eloop_register_read_sock(netlink->sock, netlink_receive, netlink, NULL)
wpa_driver_nl80211_init_nl_global(global)
global->nl = nl_create_handle(global->nl_cb, "nl") // 用于发送netlink消息
global->nl_event = nl_create_handle(global->nl_cb, "event") // 用于接收netlink消息
// 设置netlink消息回调处理函数
nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_global_event, global)
(struct nl80211_global *)global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0)
wpa_s->driver = wpa_drivers[i] // (struct wpa_driver_ops *)
wpa_s->global_drv_priv = global->drv_priv[i] // 一个struct nl80211_global *global对象
wpa_drv_init() // driver的局部上下文信息初始化
wpa_s->drv_priv = wpa_s->driver->init2()/init() // 返回struct i802_bss对象
wpa_driver_nl80211_init() => wpa_driver_nl80211_drv_init()
wpa_driver_nl80211_capa(drv) // 获取无线网络设备的capability
nl80211_init_bss(bss)
// 设置bss事件处理回调函数,注意此时并没有创建nl_handle即nl_socket
nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_bss_event, bss)
/*
rfkill代表radio frequency( RF) connector kill switch support, 它是Kernel中的
一个子系统( subsystem) 。 其功能是控制系统中射频设备的电源( 包括Wi-Fi、 GPS、
BlueTooth、 FM等设备。 注意, 这些设备驱动只有把自己注册到rfkill子系统中后, rfkill
才能对它们起作用) 的工作以避免浪费电力。 rfkill有软硬两种方式来禁止( block) RF设
备。
*/
drv->rfkill = rfkill_init(rcfg)
// 接收rfkill事件,查看无线设备是开启还是关闭。
eloop_register_read_sock(rfkill->fd, rfkill_receive, rfkill, NULL)
linux_iface_up(drv->global->ioctl_sock, ifname)
wpa_driver_nl80211_finish_drv_init()
wpa_driver_nl80211_set_mode() // 设置接口类型为NL80211_IFTYPE_STATION
...
wpa_supplicant_init_wpa() // 初始化wpa_sm相关的资源
wpa_sm_init() // 初始化wpa_sm状态机
wpa_drv_get_hw_feature_data()
wpa_supplicant_driver_init()
wpa_supplicant_update_mac_addr()
wpa_s->l2 = l2_packet_init(ETH_P_EAPOL, wpa_supplicant_rx_eapol) // 接收EAPOL回调函数
eloop_register_read_sock()
wpa_supplicant_req_scan() // 发起有效SSID的扫描
wpas_wps_init()
wpa_supplicant_init_eapol() // 初始化EAPOL
wpa_s->eapol = eapol_sm_init(ctx)
sm->eap = eap_peer_sm_init() // 初始化EAP SM
eloop_register_timeout(eapol_port_timers_tick)
wpa_sm_set_eapol()
wpa_supplicant_ctrl_iface_init()
gas_query_init()
wpas_p2p_init()
wpa_bss_init()
wpas_notify_network_added()
wpa_supplicant_run
wpa_supplicant_run()
eloop_run()
扫描
wpa_supplicant_req_scan()
wpa_supplicant_scan()
wpa_supplicant_trigger_scan()
wpas_trigger_scan_cb()
wpa_driver_nl80211_scan()
这里driver_nl80211发送NL80211_CMD_TRIGGER_SCAN命令给WiFi driver,通知它开始扫描周围的无线网络。
WiFi driver完成任务后,向注册的三个netlink组播之一的“scan”组播地址发送结果。
driver_nl8021对应的处理回调函数为process_global_event。
process_global_event()
do_process_drv_event()
case NL80211_CMD_TRIGGER_SCAN
wpa_supplicant_event(EVENT_SCAN_STARTED)
case EVENT_SCAN_STARTED
case NL80211_CMD_NEW_SCAN_RESULTS
send_scan_event()
wpa_supplicant_event(EVENT_SCAN_RESULTS)
case EVENT_SCAN_RESULTS
wpa_supplicant_event_scan_results() => _wpa_supplicant_event_scan_results()
scan_res = wpa_supplicant_get_scan_results()
wpa_drv_get_scan_results2()
wpa_s->driver->get_scan_results2() => wpa_driver_nl80211_get_scan_results()
qsort() // 对扫描结果进行排序, 排序函数是wpa_scan_result_compar
wpa_bss_update_scan_res() // 更新WPAS中保存的那些bss信息
wpas_notify_scan_done() // 通知客户端, 扫描结束
wpas_select_network_from_last_scan()
/*
根据scan_res(扫描结果)、 wpa_bss(代表一个真实BSS的信息)和
wpa_ssid( 代表用户设置的某个无线网络配置项)的匹配情况来选择合适的无线网络wpa_bss
*/
selected = wpa_supplicant_pick_network()
wpa_supplicant_need_to_roam() // 判断是否需要漫游
wpa_supplicant_connect()
wpa_supplicant_associate() // 发起关联
// 预认证处理,更新PMKSA缓存信息,和802.11中的Fast Transition有关
wpa_supplicant_rsn_preauth_scan_results()
关联
wpa_supplicant_associate()
struct wpa_driver_associate_params params // 主要目的是填充params的内容
radio_add_work(wpas_start_assoc_cb) // 增加assoc工作任务
wpas_start_assoc_cb() // 根据AP的情况选择合适的加密方法及认证方法
wpa_supplicant_cancel_sched_scan()
wpa_supplicant_cancel_scan()
wpa_sm_set_assoc_wpa_ie() // 清空上一次association时使用的WPA/RSN IE信息
/*
auth_alg为认证方法, 可取值有WPA_AUTH_ALG_OPEN、 WPA_AUTH_ALG_SHARED等。
如果要使用WPA的话, 在和AP关联时必须使用Open System(即WPA_AUTH_ALG_OPEN)
如果没有设置该值, 其值默认为0
*/
...
...
wpa_clear_keys() // 清除wlan driver中的key设置
wpa_supplicant_set_state(WPA_ASSOCIATING)
wpa_drv_associate() // 发起关联请求
wpa_s->driver->associate() => wpa_driver_nl80211_associate()
wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0) // 设置60s超时回调
eapol_sm_invalidate_cached_session(wpa_s->eapol) // 设置上一次eapol session无效
wpa_supplicant_rsn_supp_set_config() // 将加密/身份验证信息设置到wpa_sm对应的变量中去
wpa_supplicant_initiate_eapol() // 配置eapol sm和eap sm
wpa_driver_nl80211_associate()
wpa_driver_nl80211_connect()
wpa_driver_nl80211_try_connect()
nl80211_drv_msg(NL80211_CMD_CONNECT) // 构造NL80211_CMD_CONNECT消息
nl80211_connect_common()
send_and_recv_msgs() // 把CONNECT请求发给了驱动, 驱动将完成Authentication帧和Association Request帧的处理。
驱动会返回NL80211_CMD_CONNECT类型的消息。
process_global_event()
do_process_drv_event()
case NL80211_CMD_CONNECT
mlme_event_connect()
union wpa_event_data event
event.assoc_info.freq = nl80211_get_assoc_freq(drv) // 通过发送NL80211_GET_SCAN命令获取STA的工作频率
wpa_supplicant_event(EVENT_ASSOC)
case EVENT_ASSOC
wpa_supplicant_event_assoc()
ft_completed = wpa_ft_is_completed() // 判断Fast Transition是否完成
wpa_supplicant_event_associnfo() // 更新RSN/WPA IE信息
wpa_drv_get_bssid() // 从driver wrapper中获得bssid信息
wpa_supplicant_set_state(WPA_ASSOCIATED)
eapol_sm_notify_portEnabled(TRUE) // 触发状态机
wpa_supplicant_req_auth_timeout() // 注册认证超时函数
wpa_supplicant_cancel_scan(wpa_s) // 取消扫描任务
WPA
eapol_sm_notify_portEnabled(TRUE)
sm->portEnabled = enabled
eapol_sm_step(sm)
// 四个状态机状态PAE=DISCONNECTED、KR=NO_KEY_RECEIVER、BE=IDLE、EAP=DISABLD
SM_STEP_RUN(SUPP_PAE) => SM_STEP(SUPP_PAE)
SM_ENTER(SUPP_PAE, CONNECTING) => SM_STATE(SUPP_PAE, CONNECTING)
// 四个状态机状态PAE=CONNECTING、KR=NO_KEY_RECEIVER、BE=IDLE、EAP=DISABLD
SM_STEP_RUN(KEY_RX)
SM_STEP_RUN(SUPP_BE)
eap_peer_sm_step()
SM_STEP_RUN(EAP)
// 使用WPA-PSK时force_disabled变量为True,所以EAP SM进入Disabled
SM_ENTER_GLOBAL(EAP, DISABLED)
4-Way handshake,AP发送EAPOL 1/4 3/4给STA,STA接收并处理。
wpa_supplicant_rx_eapol()
wpa_supplicant_req_auth_timeout() // 设置认证请求超时函数
eapol_sm_rx_eapol() // 非WPA-PSK方法接收函数
wpa_sm_rx_eapol() // WPA-PSK方法接收函数
peerkey_rx_eapol_4way()
wpa_supplicant_process_3_of_4()
wpa_supplicant_send_4_of_4()
wpa_supplicant_install_ptk() // install PTK到HW
wpa_sm_set_state(WPA_GROUP_HANDSHAKE)
wpa_supplicant_pairwise_gtk() // 处理GTK
wpa_supplicant_install_gtk() // install GTK到HW
wpa_supplicant_key_neg_complete()
wpa_sm_set_state(WPA_COMPLETED)
eapol_sm_notify_portValid(TRUE)
eapol_sm_step()
eapol_sm_notify_eap_success(TRUE)
eap_notify_success()
eapol_sm_step()
wpa_supplicant_process_1_of_4()
wpa_sm_set_state(WPA_4WAY_HANDSHAKE)
wpa_derive_ptk()
wpa_supplicant_send_2_of_4()
wpa_eapol_key_send()
wpa_sm_ether_send()
WPS
wpa_supplicant_ctrl_iface_wps_pin()
wpas_wps_start_pin()
wpas_wps_start_dev_pw()
wpas_wps_add_network() // 初始化WPS的struct wpa_ssid
eloop_register_timeout(wpas_wps_timeout) // 注册超时处理函数,120s
wpas_wps_reassoc() // 重新关联
wpa_supplicant_req_scan() // 发起扫描、关联,如上所述
eapol_sm_notify_portEnabled(TRUE)
sm->portEnabled = enabled
eapol_sm_step(sm)
// 四个状态机状态PAE=DISCONNECTED、KR=NO_KEY_RECEIVER、BE=IDLE、EAP=DISABLD
SM_STEP_RUN(SUPP_PAE) => SM_STEP(SUPP_PAE)
case SUPP_PAE_DISCONNECTED
SM_ENTER(SUPP_PAE, CONNECTING) => SM_STATE(SUPP_PAE, CONNECTING)
sm->startWhen = 1
/*
PT SM使能后,会再次触发eapol_sm_step(sm),
再次执行SM_STATE(SUPP_PAE, CONNECTING) => eapol_sm_txStart(sm)
*/
eapol_enable_timer_tick()
eloop_register_timeout(eapol_port_timers_tick)
eapol_port_timers_tick()
eapol_sm_step(sm)
case SUPP_PAE_CONNECTING
SM_ENTER(SUPP_PAE, CONNECTING) => SM_STATE(SUPP_PAE, CONNECTING)
eapol_enable_timer_tick()
eapol_sm_txStart() // WPS第二次进入时发送EAP Start
sm->ctx->eapol_send(IEEE802_1X_TYPE_EAPOL_START) => wpa_supplicant_eapol_send()
// 四个状态机状态PAE=CONNECTING、KR=NO_KEY_RECEIVER、BE=IDLE、EAP=DISABLD
SM_STEP_RUN(KEY_RX)
SM_STEP_RUN(SUPP_BE)
eap_peer_sm_step()
SM_STEP_RUN(EAP)
// 使用WPA-PSK时force_disabled变量为True,所以EAP SM进入Disabled
SM_ENTER_GLOBAL(EAP, DISABLED)
eapol_sm_rx_eapol()
case IEEE802_1X_TYPE_EAP_PACKET
sm->eapolEap = TRUE
eapol_sm_step(sm)