环境:
android 2.3.4
wpa_supplicant 0.8
android 2.3.4
wpa_supplicant 0.8
一切从 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_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;
==> 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 多播的事件,这个又如何解释???
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,什么也没做
===> 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];
根据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
分配内存给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
设置的 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.
设置 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设备不会掉线
主要有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
成员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"
可以通过命令行-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). */
其他情况什么也不做,代码注释如下:
/*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 结构中
设置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);
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.,
based on scan results). The other rule for expiring entries is based on
new scan results: expire an entry if it has not been seen in last
WPA_BSS_EXPIRATION_SCAN_COUNT (2). The latter one will eventually be
improved to handle partial scans (i.e., only some channels/SSIDs being
scanned; those should only expire matching BSS entries). In addition,
there is a maximum limit on the BSS entries (200) and new BSS entries
added above that will end up getting the oldest entry getting removed.
(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.,
based on scan results). The other rule for expiring entries is based on
new scan results: expire an entry if it has not been seen in last
WPA_BSS_EXPIRATION_SCAN_COUNT (2). The latter one will eventually be
improved to handle partial scans (i.e., only some channels/SSIDs being
scanned; those should only expire matching BSS entries). In addition,
there is a maximum limit on the BSS entries (200) and new BSS entries
added above that will end up getting the oldest entry getting removed.
These values will likely end up being configurable at some point and I
have also considered providing options for controlling the BSS list
updating "mode". For example, wpa_supplicant could be requested to keep
the BSS table more frequently up-to-date for all BSSes or for specific
ESSes. This could have some connections with the bgscan mechanism. In
addition, this could get more input from things like Microsoft Wireless
Provisioning Services (multi-SSID/hidden SSID) and IEEE 802.11k neighbor
reports, etc.
==> wpas_notify_iface_added /* 不支持dbus,什么也不做*/
==> 读init.rc 设置supplicant_scan_interval
wifi无线局域网扫描间隔时间,单位为秒。调大这个值可节约耗电。
如果不设置,就用 wpa_supplicant_alloc 设置的5 秒 (wpa_s->scan_interval = 5;)
==> wpas_notify_network_addedstruct wpa_supplicant *wpa_s,struct wpa_ssid *ssid)
把conf 文件中的 network {中的
have also considered providing options for controlling the BSS list
updating "mode". For example, wpa_supplicant could be requested to keep
the BSS table more frequently up-to-date for all BSSes or for specific
ESSes. This could have some connections with the bgscan mechanism. In
addition, this could get more input from things like Microsoft Wireless
Provisioning Services (multi-SSID/hidden SSID) and IEEE 802.11k neighbor
reports, etc.
==> wpas_notify_iface_added /* 不支持dbus,什么也不做*/
==> 读init.rc 设置supplicant_scan_interval
wifi无线局域网扫描间隔时间,单位为秒。调大这个值可节约耗电。
如果不设置,就用 wpa_supplicant_alloc 设置的5 秒 (wpa_s->scan_interval = 5;)
==> wpas_notify_network_addedstruct wpa_supplicant *wpa_s,struct wpa_ssid *ssid)
把conf 文件中的 network {中的
=> wpa_supplicant_run -> eloop_run(); 开始epool 大循环 ,进行event 处理(callback)
下面简但列下 eloop_run 相关handle
eloop_register_read_sock , eloop_register_timeout
1. nl_handle_event :
注册nl_handle_event 的sock 到eloop reads table 而nl_handle_event
加入多播scan ,mlme,regulator组
eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
wpa_driver_nl80211_event_receive, drv, drv->nl_handle_event);
和compat driver 通讯 接收scan,mlme,regulator 多播
eloop_register_read_sock , eloop_register_timeout
1. nl_handle_event :
注册nl_handle_event 的sock 到eloop reads table 而nl_handle_event
加入多播scan ,mlme,regulator组
eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
wpa_driver_nl80211_event_receive, drv, drv->nl_handle_event);
和compat driver 通讯 接收scan,mlme,regulator 多播
2.netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
netlink目前使用最广泛的是通过NETLINK_ROUTE 这个选项来获取网络设备或者网址的一些信息
注册到NETLINK_ROUTE socket 到eloop reads table
eloop_register_read_sock(netlink->sock, netlink_receive, netlink, NULL);
netlink目前使用最广泛的是通过NETLINK_ROUTE 这个选项来获取网络设备或者网址的一些信息
注册到NETLINK_ROUTE socket 到eloop reads table
eloop_register_read_sock(netlink->sock, netlink_receive, netlink, NULL);
3. l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, htons(protocol)); /* l2 socket !!! */
eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); eloop 读l2 packet 进入 !!!
eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL); eloop 读l2 packet 进入 !!!
4. 每隔1s 执行eapol_port_timers_tick
/ * This statemachine is implemented as a function that will be called
* once a second as a registered event loop timeout.
*/
eloop_register_timeout(1, 0, eapol_port_timers_tick/*PAE 端口认证实体,EAP 端口超时*/, NULL, sm);
/ * This statemachine is implemented as a function that will be called
* once a second as a registered event loop timeout.
*/
eloop_register_timeout(1, 0, eapol_port_timers_tick/*PAE 端口认证实体,EAP 端口超时*/, NULL, sm);
5. scan 结果,过期处理?
eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, wpa_bss_timeout, wpa_s, NULL);
eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0, wpa_bss_timeout, wpa_s, NULL);
6.wpa ctrl 命令处理:
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);
7. scan timeout when driver
eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,drv, drv->ctx);
wpa_driver_nl80211_scan_timeout:
/* This function can be used as registered timeout when starting a scan to
* generate a scan completed event if the driver does not report this.
*/
8. P2P: 主要有下面这些
P2p.c (srcp2p): eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
P2p.c (srcp2p): eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
P2p.c (srcp2p): eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
P2p.c (srcp2p): eloop_register_timeout(timeout, 0, p2p_find_timeout,
P2p.c (srcp2p): eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
P2p.c (srcp2p): eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
P2p.c (srcp2p): eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
P2p.c (srcp2p): eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
P2p.c (srcp2p): eloop_register_timeout(p2p->ext_listen_interval_sec,
P2p.c (srcp2p): eloop_register_timeout(p2p->ext_listen_interval_sec,
P2p_supplicant.c: eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
P2p_supplicant.c: eloop_register_timeout(15 + res->peer_config_timeout / 100,
P2p_supplicant.c: eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
P2p_supplicant.c: eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
P2p_supplicant.c: eloop_register_timeout(60, 0, wpas_p2p_group_formation_timeout,
P2p_supplicant.c: eloop_register_timeout(timeout, 0,
P2p_supplicant.c: eloop_register_timeout(wpa_s->conf->p2p_group_idle, 0,
P2p.c (srcp2p): eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
P2p.c (srcp2p): eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
P2p.c (srcp2p): eloop_register_timeout(timeout, 0, p2p_find_timeout,
P2p.c (srcp2p): eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
P2p.c (srcp2p): eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
P2p.c (srcp2p): eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
P2p.c (srcp2p): eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
P2p.c (srcp2p): eloop_register_timeout(p2p->ext_listen_interval_sec,
P2p.c (srcp2p): eloop_register_timeout(p2p->ext_listen_interval_sec,
P2p_supplicant.c: eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
P2p_supplicant.c: eloop_register_timeout(15 + res->peer_config_timeout / 100,
P2p_supplicant.c: eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
P2p_supplicant.c: eloop_register_timeout(1, 0, wpas_p2p_join_scan, wpa_s, NULL);
P2p_supplicant.c: eloop_register_timeout(60, 0, wpas_p2p_group_formation_timeout,
P2p_supplicant.c: eloop_register_timeout(timeout, 0,
P2p_supplicant.c: eloop_register_timeout(wpa_s->conf->p2p_group_idle, 0,
![](https://img-my.csdn.net/uploads/201301/16/1358318543_7365.jpg)