logo资料库

wpa_supplicant代码流程.docx

第1页 / 共42页
第2页 / 共42页
第3页 / 共42页
第4页 / 共42页
第5页 / 共42页
第6页 / 共42页
第7页 / 共42页
第8页 / 共42页
资料共42页,剩余部分请下载后查看
一切从 main.c 开始: (=>表示第 1 级, 那么==>表示下一级,类推) os_program_init => 参数解析& 获取 => wpa_supplicant_init(¶ms) ==> eap_register_methods /* 注册 EAP method ,比如 EAP-PSK, EAP-TLS */ ==> global->params 获取, 比如 daemonize-是否在后台运行 wpa, ctrl_interface-wpa_cli 命名 socket ==> eloop_init , static struct eloop_data eloop; 结构清 0 ==> wpa_supplicant_global_ctrl_iface_init (init.rc wpa socket file regist to eloop table) 在 init.rc 中 wpa service 启动命令中声明的 socket 如下: service wpa_supplicant /system/bin/wpa_supplicant socket wpa_wlan0:0 通过 android_get_control_socket 函数(android 特有的)和 socket 名 获得 socket 句柄,放入 struct wpa_global 的 ctrl_iface 变量中 ==> wpas_notify_supplicant_initialized 其中进行 dbus init 但 CONFIG_CTRL_IFACE_DBUS 没有设置! 什么也不做 ==> wpa_drivers[i]->global_init(); 目前 wpa_drivers 包含 wext,和 nl80211 其中 nl80211 是 nl80211_global_init 分配生成 struct nl80211_global { struct dl_list interfaces; }; 接口双向 list init ,然后给出 pointer ==> 最后返回前面已经 init 的 struct wpa_global *global => wpa_supplicant_add_iface (如其名,添加接口,就是 wlan0) ==> struct wpa_supplicant wpa_s = wpa_supplicant_alloc(); 给 struct wpa_supplicant *wpa_s 分配内存,并对下面这些变量 init /* scan_req =1,表示手动 scan ,即使没有网络在 conf 文件中配置 除了 0, 还可以设置为 2,好象设置 2 时不做关联请求(associate req)*/ wpa_s->scan_req = 1; /* time in sec between scans to find suitable AP 可见这个参数决定了 ap 是否在线的判断,但是 要省电时可以设置了长点*/ wpa_s->scan_interval = 5; /* driver 参数,可见 kerneldoc 解释如下: http://linuxwireless.org/en/developers/Documentation/nl80211/kerneldoc
NL80211_ATTR_SCHED_SCAN_INTERVAL Interval between scheduled scan cycles, in msecs. 这个参数看来必须小于上面的 scan_interval*/ wpa_s->sched_scan_interval = 3; wpa_s->new_connection = 1; wpa_s->parent = wpa_s; wpa_s->sched_scanning = 0; wpa_s->override_sched_scan = 0; scan_interval 就是设置 driver 调度 scan 的间隔时间 scan_req 就是 wpa 定时去读 driver scan 到的结果 但是 eloop 中 scan 多播的事件,这个又如何解释??? ==> wpa_supplicant_init_iface ===> struct wpa_config * wpa_config_read(wpa_s->confname); 读/data/misc/wifi/wpa_supplicant.conf 并解析到 wpa_config 结构 config.h 有 default 设置,某些可以通过 wpa_cli 设置 全部读到 struct wpa_supplicant 结构的 wpa_s->conf (命令行-c /data/misc/wifi/wpa_supplicant.conf) ===> eapol_sm_notify_portEnabled, eapol_sm_notify_portValid init eapol state machine ,但是目前 sm==NULL,什么也没做 ===> wpa_supplicant_set_driver (确定 wpa_s->driver = wpa_drivers[i];) 根据 driver name = 'nl80211' 查到 wpa_drivers 中的某 1 个做下面动作: wpa_s->driver = wpa_drivers[i]; /* 指向某个 struct wpa_driver_ops */ /*drv_priv 是前面 wpa_drivers[i]->global_init()时获得的 struct nl80211_global {struct dl_list interfaces;}; 以后 driver init 时将 init 好的 driver data 挂到该双向 list 上 可参考 wpa_drv_init wpa_driver_nl80211_init, 其实不用以后,下面马上开始 wpa_drv_init */ wpa_s->global_drv_priv = wpa_s->global->drv_priv[i]; ===> wpa_drv_init ====> init2 (wpa_driver_nl80211_init) 分配内存给 struct wpa_driver_nl80211_data * drv 然后对各结构成员 init : drv->global = global_priv; 还记得前面那个 dl list 挂接口用的 有了这个参数传入,driver 就可以访问该 list ,做接口 init 后挂表动作了
drv->ctx = ctx; /* ctx 就是 struct wpa_supplicant *wpa_s 这样 driver opt function 中也能访问到 此结构*/ ====> wpa_driver_nl80211_init_nl 这部分主要是生成两个结构指针: struct nl_handle * nl_hanlde nl_handle 和 nl_handle_event nl_handle 用于向 nl80211 netlink 写, nl_handle_event 表示接收,scan,mlme,regulatory 等多播包,并把 nl_handle_event 注册到 eloop reads table ====> /sys/class/net/wlan0/phy80211/name 去读 drv->phyname ====> drv->ioctl_sock 创建用于 访问网络接口 kernel ioctl socket 看下下面这段注释:(比如 up,down 接口使用该 socket 去做) /*The usual method in Unix to set and get parameters from a network device is through ioctl. Ioctl are usually operations performed on a file descriptor, but they also apply on network sockets. The ioctl is a kernel system call. The arguments of the ioctl define the operations to be done, the parameters of these operations and the device they applies to. */ ====> drv->netlink = netlink_init(cfg) 进行 driver data 部分的 netlink config 设置 netlink_init 注册 NETLINK_ROUTE socket 到 eloop reads table,其中 handle cb func 为 netlink_receive netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 创建用于 NETLINK_ROUTE socket netlink 目前使用最广泛的是通过 NETLINK_ROUTE 这个选项来获取 网络设备或者网址的一些信息,比如获得接口状态: IFF_RUNNING 接收 newlink, dellink 两个 event ,然后使用 cfg 设置的 callback 函数: * wpa_driver_nl80211_event_rtm_newlink : 如果是 if disable 到 enable 就执行 wpa_supplicant_event (drv->ctx, EVENT_INTERFACE_ENABLED, NULL); 该事件发生,引发 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); 还有就是请求 scan (wpa_supplicant_req_scan), 要等待 iface up 时
* wpa_driver_nl80211_event_rtm_dellink, 处理 iface down 的 event,并更新 wpa_s 的状态 ====> rfkill_init /dev/rfkill 不存在,什么也没做 ====> wpa_driver_nl80211_finish_drv_init wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) 通过 NL80211_CMD_SET_INTERFACE 设置 compat driver 接口为 station, 如果 wlan0 没有 up 就 linux_set_iface_flags 让它 up) netlink_send_oper_ifla 设置接口连接 mode=1, operstate =5 (operstate 参考 RFC 2863 operational status) 可以通过/sys/class/net/wlan0(也与可能是其他名字)/operstate 查看 operstate 的可能取值如下: IF_OPER_UNKNOWN, IF_OPER_NOTPRESENT, IF_OPER_DOWN, IF_OPER_LOWERLAYERDOWN, IF_OPER_TESTING, IF_OPER_DORMANT, =5 表示休眠的操作状态 IF_OPER_UP, 对应到 RFC2863 兼容状态的策略 link_mode IF_LINK_MODE_DEFAULT, IF_LINK_MODE_DORMANT, =1 对应上面的 5 -> IF_OPER_DORMANT wpa_driver_nl80211_capa : 设置 key manager 能力,比如有 WAP2,WPA_PSK,WAP2_PSK 设置 加密方法 : WEP40, TKIP,CCMP 设置 设置 802.11 认证方式,比如 open,(注意不是 802.1X 认证) 接下来通过 wpa_driver_nl80211_get_info 获取 driver 的 max_scan_ssids, max_sched_scan_ssids sched_scan_supported 等等 , 还有其他 WPA_DRIVER_FLAGS_SME, WPA_DRIVER_FLAGS_P2P_CAPABLE 通过 SIOCGIFHWADDR 获得 mac addr (记住在这里获得 mac 地址) 所以你可以不改 driver ,在这里修改 mac addr nl80211_register_action_frame :
NL80211_CMD_REGISTER_ACTION NL80211_CMD_REGISTER_FRAME 看下面注释就知道该函数做了什么 Register for receiving certain mgmt frames (via NL80211_CMD_FRAME) for processing in userspace. This command requires an interface index, a frame type attribute (optional for backward compatibility reasons, if not given assumes action frames) and a match attribute containing the first few bytes of the frame that should match, e.g. a single byte for only a category match or four bytes for vendor frames including the OUI. The registration cannot be dropped, but is removed automatically when the netlink socket is closed. Multiple registrations can be made. 注册 user 层接收的一些管理帧,注册后由 user 层处理 主要有 P2P 的 Generic Advertisement Services frame , P2P Action 802.11W 部分相关的 SA Query Response FT Action frames ,Fast BSS Transition 相关(802.11r),用于 VOIP 的多点 AP ,快速漫游,小于 50ms VOIP 设备不会掉线 ====> driver init 完成了,通过 struct wpa_driver_nl80211_data 中的 成员 list,将 driver data 挂到前面所讲的 global->drv_priv 在 wpa_supplicant_set_driver 函数中 最后返回 1 个 struct i802_bss *bss 主要包含 struct wpa_driver_nl80211_data ===> wpa_drv_set_param -> nl80211_set_param 可以通过命令行-p ,或者 conf 文件来设置 Driver interface parameters: This field can be used to configure arbitrary driver interace parameters. The format is specific to the selected driver interface. This field is not used in most cases. driver_param="field=value" 如果 p2p 支持 就处理 use_p2p_group_interface=1, 其他情况什么也不做,代码注释如下: /*When this is added(use_p2p_group_interface=1), start the supplicant normally on wlan0 like above. Then, when P2P negotiation finishes, it will create a new interface for the group (called "p2p-wlan0-0") and put it into the appropriate mode (GO or P2P client). */
===> wpa_supplicant_init_wpa 设置 struct wpa_sm_ctx 相关 function (处理 wpa 状态机变化的 func !!!) ====>wpa_sm_init(ctx); wpa state machine 初始化 =====> pmksa_cache_init ( 专门有 show PMKSA cache 的命令 ???) 下面聊下 PMKSA The Pairwise Master Key Security Association (PMKSA) 成对主蜜钥安全关联 在 802.11i 中成对主蜜钥是工作站和 AP 成功认证产生的结果. PMK 的生命周期和唯一标识被称为 PMKID。 这些信息的集合被称为成对主蜜钥安全关联 工作站判断是否是 1 个有效的目标 AP 的 PMK,通过检查是否 PMKSA 和目标 AP 的 mac 地址匹配,如果这样的 PMK 不存在,就和 AP 使用 EAP 进行认证 如果存在这样 1 个目标 AP 的 PMK,那么工作站就试图使用 PMK,通过将 PMKID 放入到关联 请求消息的 RSN IE 中,当 AP 接收到关联请求中包含 PMKID,AP 就检查是否是1个有效的 PMKSA,其中有 相同的 PMKID,如果有,开始的 4 次握手就使用已经协商的 PMKSA. 根据上面解释下面这 3 个 pmksa_cache_init 参数,应就可以理解了 sm->dot11RSNAConfigPMKLifetime = 43200; /* 超过生命周期的%70,需要进行 re auth */ sm->dot11RSNAConfigPMKReauthThreshold = 70; /*生命周期*/ /*Security association timeout 就是进行上面说的安全关联的建立应该在 60s 内完成*/ sm->dot11RSNAConfigSATimeout = 60; ===> wpa_sm_set_ifname, wpa_sm_set_fast_reauth ===> wpa_sm_set_param 1.RSNA_PMK_LIFETIME 2. RSNA_PMK_REAUTH_THRESHOLD 3. RSNA_SA_TIMEOUT 这 3 个参数前面已经解释过了,同样设置和上面 wpa_drv_set_param 不同处是现在只是将这些参数保存到 wpa_sm 结构中 ===> wpa_drv_get_capa 取 driver 的 capability 然后设置到 struct wpa_supplicant 的 max_scan_ssids 等 member ===> wpa_supplicant_driver_init ====> l2_packet_init (ifname,macaddr,ETH_P_PAE, wpa_supplicant_rx_eapol(rx cb)
直接看代码: /* create l2 socket fd!!! l2 就是链路层,所以上面 init 传了 mac 地址 */ l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,htons(protocol)); ll.sll_family = PF_PACKET; ll.sll_ifindex = ifr.ifr_ifindex; ll.sll_protocol = htons(protocol); /* l2 socket addr !!! */ if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) { /* 注册 eloop 读入 l2 packet 事件,callback l2_packet_receive!!! */ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); ====> wpa_clear_keys =====> wpa_drv_set_key ======> wpa_driver_nl80211_set_key 清除 key key-index 0-3 ??? why 4key ====> wpa_drv_set_countermeasures /* TKIP countermeasures*/ ====> wpa_drv_flush_pmkid -> nl80211 driver 没有该接口??? ====> wpa_supplicant_delayed_sched_scan 对 conf 文件中的 network 设置 进行扫描调度,如果不支持(sched_scan_supported==0) 100ms 后 wpa_supplicant_req_scan,如果 conf 没有 network , 那么需要设置 inactive state 如下: ====> /* Inactive state (wpa_supplicant disabled)*/ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE); /* 上面函数中 后台 scan 进行的判断标准是:4-Way Handshake 结束后就是 wpa_complete ,这之前停止后台 scan !!! */ =====> netlink_send_oper_ifla (??????) =====> wpas_notify_state_changed ===> wpa_drv_set_country(wpa_s, wpa_s->conf->country) ====>wpa_driver_nl80211_set_country if (wpa_s->conf->country[0] && wpa_s->conf->country[1] /* 上面这句的意思 country 已经通过 CRDA 获得了才设置 */ ===> wpa_sm_set_own_addr ===> wpa_supplicant_init_eapol(struct wpa_supplicant *wps)
和 wpa_supplicant_init_wpa 类似 设置 struct eapol_ctx 相关 function (处理 eapol 状态机变化的 func !!!) ====> eapol_sm_init Initialize EAPOL state machine (RFC4137,) ====> eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf); =====> tls_init (tls openssl 的 init) ====> eloop_register_timeout(1, 0, eapol_port_timers_tick /* PAE 端口认证实体,EAP 端口超时处理 */, NULL, sm); ===> wpa_sm_set_eapol (/* wpa-sm 与 eapol -sm 关联起来*/) ===> wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s); (wpa_cli) 1. 根据 conf ctrl_iface=wlan0:0 设置 在/data/misc/wifi/wlan0:0 (android init.rc 中已经做了) 2. eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv); 3. wpa_msg_register_cb (wpa_supplicant_ctrl_iface_msg_cb); /* 注册 msg debug call back func*/ 由 wpa_msg_ctrl 回调 wpa_supplicant_ctrl_iface_msg_cb -> wpa_supplicant_ctrl_iface_send ( Send a control interface packet to monitors) 发给 V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 3 04:21:b0:e0:20:20] sendmsg(priv->sock, &msg, 0) ,priv 就是 init.rc 中 priv->sock = android_get_control_socket(addr.sun_path); socket wpa_wlan0:0 dgram 660 wifi wifi ===> wpas_p2p_init (struct wpa_global * (wpa_s->global), struct wpa_supplicant * wpa_s) p2p 相关,以后再看,已经不行了 ===> wpa_bss_init eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, wpa_bss_timeout, wpa_s, NULL); 关于上面看下面这段话,可能和 bss(网络或 AP)的过期与定期更新有关 Currently, this is very simple: check every WPA_BSS_EXPIRATION_PERIOD (10 sec by default) whether there are entries that are over WPA_BSS_EXPIRATION_AGE (180 seconds) old and expire them if they are ot in use (BSS entry age is the time from the last update in it, e.g.,
分享到:
收藏