跟一下wpa_supplicant---init & enable & connect

http://blog.chinaunix.net/uid-20514606-id-3259402.html

环境:
  android 2.3.4
  wpa_supplicant 0.8
 
一切从 main.c 开始: (=>表示第1级, 那么==>表示下一级,类推)
os_program_init => 参数解析& 获取
=> wpa_supplicant_init(&params)
   ==> 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.,
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 {中的
=> 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 多播
 
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);
 
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  进入 !!!
 
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);
 
5. scan 结果,过期处理?
  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);

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 (src\p2p):   eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
P2p.c (src\p2p):   eloop_register_timeout(sec, usec, p2p_state_timeout, p2p, NULL);
P2p.c (src\p2p):   eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
P2p.c (src\p2p):   eloop_register_timeout(timeout, 0, p2p_find_timeout,
P2p.c (src\p2p):   eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
P2p.c (src\p2p):   eloop_register_timeout(0, 0, p2p_go_neg_start, p2p, NULL);
P2p.c (src\p2p):   eloop_register_timeout(0, 0, p2p_invite_start, p2p, NULL);
P2p.c (src\p2p):   eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
P2p.c (src\p2p):   eloop_register_timeout(p2p->ext_listen_interval_sec,
P2p.c (src\p2p):   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,
 
画个结构关联图:
(*x) --表示注释
 

跟一下wpa_supplicant-----wifi enable 

http://blog.chinaunix.net/uid-20514606-id-3259410.html

* 在wifi setting 中 check enanble 开始继续

1.  收到MESSAGE_ENABLE_WIFI
setWifiEnabledBlocking(wifiService.java)
  => mWifiStateTracker.loadDriver
  => mWifiStateTracker.startSupplicant()
     ==> WifiNative.startSupplicant (WifiNative.java)
         ===> android_net_wifi_startSupplicant(android_net_wifi_Wifi.cpp JNI)
              ====> wifi_start_supplicant (wifi.c hardware wifi lib)
             就是去启动wpa_supplicant 命令行
  => mWifiStateTracker.startEventLoop(); (WifiStateTracker.java)
     ==> mWifiMonitor.startMonitoring();
         Monitoring thread 中:
  ===>connectToSupplicant() 判断是否连上,该函数还打开两个wpa_cli的控制
    1. ctrl_conn ,用于JNI 通过wpa_cli往下发命令
    2. monitor_conn 在wifi_wait_for_event (call by JNI
                           android_net_wifi_waitForEvent)
             接收event ,java 层就是通过call 该JNI 来获得wpa的event
             一来一去都有了,java 和 wpa 通讯建立成功
        ===>连接成功后,发消息 EVENT_SUPPLICANT_CONNECTION
     mWifiStateTracker.notifySupplicantConnection();
              接收处理 EVENT_SUPPLICANT_CONNECTION 部分见下面分支 4.
            接下来进入循环接收event
     String eventStr = WifiNative.waitForEvent();
             /* 就是监听上面connectToSupplicant 中的monitor_conn */
      然后将event string 转换成int,然后
      handleEvent(event, eventData);
      主要有下面event:
               event =CONNECTED;
               event = DISCONNECTED;
               event = STATE_CHANGE;
               event = SCAN_RESULTS;
               event = LINK_SPEED;
               event = TERMINATING;
               event = DRIVER_STATE;
               event = DRIVER_STATE
        event = LINK_SPEED 等等
    
  => setWifiEnabledState(eventualWifiState, uid);(wifiService.java)
     eventualWifiState 为 WIFI_STATE_ENABLED
     ==> mWifiStateTracker.setWifiState(WIFI_STATE_ENABLED);
         boardcast WIFI_STATE_CHANGED_ACTION  + WIFI_STATE_ENABLED
  处理接收该wifi 状态广播的分支见 3.

2. settings\wifi\WifiEnabler.java
   => class WifiEnabler
      BroadcastReceiver mReceiver = new BroadcastReceiver()
      if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
         handleWifiStateChanged(intent.getIntExtra(
             WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
    这部分就是处理wifi enable check  界面的 disable,和 打上勾的处理
 
3.packages\apps\Settings\src\com\android\settings\wifi\WifiSettings.java
  接收处理前面1.最后提到的
  boardcast WIFI_STATE_CHANGED_ACTION  + WIFI_STATE_ENABLED
  直接看代码:
  => handleEvent(Intent intent) {
     String action = intent.getAction();
     if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
     ==> updateWifiState(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
            WifiManager.WIFI_STATE_UNKNOWN));
         由 WIFI_STATE_ENABLED 走到下面
  ===> mScanner.resume(); ( sendEmptyMessage(0);)
       ====> handleMessage
             =====> mWifiManager.startScanActive() (wifiManager.java)
             ======> mService.startScan(true);
              MESSAGE_START_SCAN
       通过下面函数发出:
                   Message.obtain(mWifiHandler, MESSAGE_START_SCAN,
                                     forceActive ? 1 : 0, 0).sendToTarget();
         ===> updateAccessPoints();  读conf network 配置,并设置到 java层的AP类
接收处理MESSAGE_START_SCAN的在 wifiService.java
    handleMessage(MESSAGE_START_SCAN)
      => mWifiStateTracker.scan(forceActive);  然后到下面的分支7.!!!
    
ESSAGE_START_SCAN 另外一条路是
   wifiService.java: updateWifiState
         -> MESSAGE_UPDATE_STATE
      -> doUpdateWifiState
          ->  sendStartMessage(MESSAGE_START_SCAN)
具体不展开了
 
4. 前面分支2.中 EVENT_SUPPLICANT_CONNECTION
     消息被WifiStateTracker处理
=> handleMessage(EVENT_SUPPLICANT_CONNECTION)
     ==> checkUseStaticIp 检测是否是static ip 连接
     ==> 发Intend :
         Intent(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
       change 的内容为 EXTRA_SUPPLICANT_CONNECTED
    
     ==> dhcpThread.start(); 启动dhcp thread 并block 住,等待AP连上,在继续运行
     ==> 判断 complete 并 得到接入点的BSSID(MAC addr) 通过 GetBSSID()
                                     AP custom name   通过 GetSSID()
     ==> initializeMulticastFiltering (wifiService.java)
         ===> startPacketFiltering ->JNI 可看到debug message :
  D/wpa_supplicant( 1468): nl80211_priv_driver_cmd RXFILTER-ADD 0 len = 4096
  D/wpa_supplicant( 1468): nl80211_priv_driver_cmd RXFILTER-ADD 1 len = 4096
  D/wpa_supplicant( 1468): nl80211_priv_driver_cmd RXFILTER-ADD 3 len = 4096
  D/wpa_supplicant( 1468): nl80211_priv_driver_cmd RXFILTER-START len = 4096
     ==> setBluetoothScanMode
         ===> setBluetoothCoexistenceModeCommand
     ==> setNumAllowedChannels
     /*  Set the number of radio frequency channels that are allowed
         to be used in the current regulatory domain */
      如果你有什么想法,就去动动Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS参数

5. WPA_SUPPLICANT 部分开始蠢蠢欲动了:
   可以看到这样的debug message:
       RTM_NEWLINK: operstate=0 ifi_flags=0x1043 ([UP][RUNNING])
 =>wpa_driver_nl80211_event_rtm_newlink 被event 驱动,看代码:
   /* 如果上次 disable 本次enable 发这个event! */
   if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
   ==> wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
   ==> wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
       ==> wpa_supplicant_req_scan(wpa_s, 0, 0);
      if_disabled 不满足所以没走到这里,所以发起scan 不在这里开始的.小插曲
6. 同时可以看到这样的消息 :Event 5 received on interface wlan0
   在下面函数打出
   => wpa_driver_nl80211_event_link ==>
      ==> wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
               event =EVENT_INTERFACE_ADDED
           ===> wpa_supplicant_event_interface_status
                if (!wpa_s->interface_removed)
   break; 什么也没做     
   (new link 部分处理没有启动scan,还是由java部分启动的,就是前面3.分支中的)
    mWifiStateTracker.scan

7. 前面3.分支最后 开始mWifiStateTracker.scan(forceActive)
 到WifiStateTracker.java,找到全名如下:
=> public synchronized boolean scan(boolean forceActive)
   ==> WifiNative.scanCommand
       ===> doSetScanMode(true);
         从debug message (Unsupported command: SCAN-ACTIVE) 看来
 主动扫描不支持???
                   
 ===> doBooleanCommand("SCAN", "OK");
      ====> doCommand
                   =====> wifi_command(wifi.c)
                  执行到(wpa_supplicant中的ctrl_iface.c)代码如下:
                  else if (os_strcmp(buf, "SCAN") == 0)
         ======> wpa_supplicant_req_scan(wpa_s, 0, 0);
                 马上调度一个 scan =>
           eloop_register_timeout(sec, usec,
         wpa_supplicant_scan, wpa_s, NULL);
         接下来到分支8.就在下面
                        
8.
 下面是eloop 部分,因为前面分支7.中eloop timeout 为0,
马上执行下面部分:
=> wpa_supplicant_scan:
   ==> wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
    从 debugmsage: State: INACTIVE -> SCANNING可以看出从inactive 进入scanning
    该函数会调用wpas_notify_state_changed,往下又调用了wpas_notify_state_changed
    然后再到 wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
    最后到 wpa_msg_cb,一函数指针,指向那个函数呢,请望下看:
    wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 
    该函数 msg debug call back func 通过前面monitor_conn,发给java的 WifiMonior
    如果有时看到WifiMonitor的消息:
    Event [CTRL-EVENT-STATE-CHANGE id=-1 state=2 BSSID=00:00:00:00:00:00]
    就是这么一层一层然后发出来的
  ==> wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard SSID");
  ==> wpa_supplicant_extra_ies
      ===> wps_build_probe_req_ie
          关联参数到 request probe ie (构建一个主动探测IE 的帧)
     上面说的Unsupported command: SCAN-ACTIVE,和这里描述矛盾吗?
      ===> params->extra_ies = wpabuf_head(wps_ie);
      ===> params->extra_ies_len = wpabuf_len(wps_ie);
  ==> params.freqs = wpa_s->next_scan_freqs;  设置scan channel 到 params
  ==> wpa_supplicant_build_filter_ssids 设置过滤的ap到params
  ==> wpa_supplicant_trigger_scan(params)终于到了真正的带参数扫描了!
       ===> wpa_drv_scan(wpa_s, params);  具体到nl80211 driver的
           wpa_driver_nl80211_scan,终于潜到wpa_supplicant 的最底了
           ====> 在wpa_driver_nl80211_scan 最后有如下调用:
          =====> eloop_register_timeout(timeout, 0,
         wpa_driver_nl80211_scan_timeout,drv, drv->ctx);
接下来干什么,网撒出去了,该等着收网的时候了
10秒后timeout ,应该不会等到timeout 时间到,wifi compat driver
就会发event 来通知 scan result,eloop call back下面函数
=> wpa_driver_nl80211_scan_timeout:
   ==> wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
       其中代码:
       case EVENT_SCAN_RESULTS:
       ===> wpa_supplicant_event_scan_results(wpa_s, data);
           ====> _wpa_supplicant_event_scan_results
          这时你该能看到如下wpa_supplicant message:
   看不到的话,要不是设备坏了的话,那就是进入无人区了
 Received scan results (9 BSSes) 
 BSS: Start scan result update 1
 BSS: Add new id 0 BSSID 00:1f:33:b9:5d:e0 SSID 'RD-test'
 BSS: Add new id 1 BSSID 04:21:b0:e0:20:20 SSID 'xxxxx1'
 BSS: Add new id 2 BSSID 00:22:b0:e0:20:20 SSID 'xxxxx2'
 BSS: Add new id 3 BSSID 00:22:b0:e0:20:e8 SSID 'xxxx3'
 BSS: Add new id 4 BSSID 00:22:b0:e0:20:1d SSID 'xxxx4'
 BSS: Add new id 5 BSSID 04:21:b0:e0:20:1d SSID 'G-B-U-5'
 BSS: Add new id 6 BSSID 0e:4c:39:78:01:94 SSID 'ChinaNet-WGEc'
 BSS: Add new id 7 BSSID 5c:63:bf:a6:e4:50 SSID 'xxxxx'
 BSS: Add new id 8 BSSID 04:27:b0:e0:20:20 SSID 'xxxxx'
 New scan results available

另外还有下面这条分支也会接收扫描结果,可能是driver 主动发上来的
貌似如下:
这个 event 由eloops 中 注册的:
    eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
               wpa_driver_nl80211_event_receive, drv, drv->nl_handle_event);
=> wpa_driver_nl80211_event_receive
  通过process_event callback 来继续处理 NL80211_CMD_NEW_SCAN_RESULTS 如下:
  这时会: eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
          取消前面的10s scan timeout eloop
   ==> send_scan_event
       ===> wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
            ===> wpa_supplicant_event_scan_results
  ====> _wpa_supplicant_event_scan_results
        如果driver 没有横插1杠,前面也会走到下面:
        =====> wpa_supplicant_get_scan_results 获得ap info
                           ======> wpa_bss_update_scan_res
                                     =======> wpa_bss_add
                      =====> wpa_msg_ctrl(wpa_s, MSG_INFO,
                   WPA_EVENT_SCAN_RESULTS);
                      =====> wpas_notify_scan_results(wpa_s);
               ======> wpas_wps_notify_scan_results
                =======> wpas_wps_notify_scan_results
        到这里wpa_supplicant_event(EVENT_SCAN_RESULTS)  处理结束
下面这段messsage是由上面 wpa_bss_add
                         => wpas_notify_bss_added
       ==> wpa_msg_ctrl(wpa_s, MSG_INFO,
                       WPA_EVENT_BSS_ADDED "%u " MACSTR,
引发monitor 接收 scan result 前的消息
D/wpa_supplicant( 1468): Event 5 received on interface wlan0
V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 0 00:1f:33:b9:5d:e0]
V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 1 04:21:b0:e0:20:20]
V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 2 00:22:b0:e0:20:20]
V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 3 00:22:b0:e0:20:e8]
V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 4 00:22:b0:e0:20:1d]
V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 5 04:21:b0:e0:20:1d]
V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 6 0e:4c:39:78:01:94]
V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 7 5c:63:bf:a6:e4:50]
V/WifiMonitor( 1172): Event [CTRL-EVENT-BSS-ADDED 8 04:27:b0:e0:20:20]
                                               
接下来还有收到这样1条msg:
V/WifiMonitor( 1172): Event [WPS-AP-AVAILABLE ]
再跟下:
=> wpa_supplicant_event_scan_results
   ==> _wpa_supplicant_event_scan_results =>
       wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
       wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
    
马上结束,最后再回到java部分,上面发的WPA_EVENT_SCAN_RESULTS 被monitor接收:
=> handleEvent(int event, String remainder)(WifiMonitor.java)
    case SCAN_RESULTS
    ==>mWifiStateTracker.notifyScanResultsAvailable();
       ===>  setScanResultHandling(SUPPL_SCAN_HANDLING_NORMAL);
             ====> wifiStateTracker.setScanResultHandling
       ===>  sendEmptyMessage(EVENT_SCAN_RESULTS_AVAILABLE);
       接下来WifiStateTracker中的handleMessage会处理该消息
wpa_supplicant_get_scan_results中有对scan result排序,
一般按RSSI 强度来排, 如果有什么想法,可以动下
另外还有network group priority ,后面会提到
enable 部分基本就这样了,结束

 

跟一下wpa_supplicant----connect AP

WPA-PSK连接

从packages\apps\Settings\src\com\android\settings\wifi\WifiSettings.java
  和 WifiDialog.java 开始
1.
如果你点中某个AP
=> onClick执行 (WifiSettings.java)
   代码如下:

点击(此处)折叠或打开

  1. button == WifiDialog.BUTTON_SUBMIT
  2.    WifiConfiguration config = mDialog.getConfig();(WifiDialog.java中)
  3.    WifiDialog getConfig =>( 因为才你自己选的某个AP 有网络ID,
  4.                              所以network id !=-1,mSelected!=null)
  5.    if (config.networkId!=-1){
  6.         if (mSelected!=null){/* 走到这里 */
  7.        /*下面函数 到2.分支继续分析 */
  8.               mWifiManager.updateNetwork(config);
  9.               /*下面函数 到4.分支继续分析 */
  10.               saveNetworks();
  11.         }
  12.     } else{
  13.         int networkId = mWifiManager.addNetwork(config);
  14.         if (networkId!=-1){
  15.             mWifiManager.enableNetwork(networkId, false);
  16.             config.networkId= networkId;
  17.             if (mDialog.edit || requireKeyStore(config)){
  18.                saveNetworks();
  19.             } else {
  20.                connect(networkId);
  21.             }
  22.          }
  23.     }


2. 接上面分支1.的 mWifiManager.updateNetwork(config); 继续分析
=> addOrUpdateNetwork (wifiManager.java)
   ==> mService.addOrUpdateNetwork(config);
       (wifi manager 对wifi service function 的访问)
       ===> mWifiStateTracker.addNetwork()
            ====> WifiNative.addNetworkCommand();
           (上面这句执行完成到 setVariables: 部分 ,分支3.继续)
           =====> JNI 执行 doIntCommand("ADD_NETWORK");
      上面是andorid ,下面就执行 wpa_cli的命令
      ---------------------------------------------------------
=> wpa_supplicant_ctrl_iface_add_network
   ==> wpa_config_add_network
       ===> wpa_config_update_prio_list
            更新 wpa prioty list! 就是conf文件设置的priority 组
看下解释:
# priority: Priority group
# By default, all networks and credentials get the same priority group
# (0). This field can be used to give higher priority for credentials
# (and similarly in struct wpa_ssid for network blocks) to change the
# Interworking automatic networking selection behavior. The matching
# network (based on either an enabled network block or a credential)
# with the highest priority value will be selected.
   ==> wpas_notify_network_added(wpa_s,
           ssid);  (dbus 部分,没有用)
   ==> wpa_config_set_network_defaults ,设置network(ssid) 如下default 值:
        #define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
        #define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \
           EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
        #define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
        #define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
        #define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
        #define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \
                 WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
        #define DEFAULT_FRAGMENT_SIZE 1398
        就是加密算法,密钥管理,及EAPOL等等,struct wpa_ssid结构中注释很全
 android 发起的一条ADD_NETWORK命令完成了!

3. 又回到java,刚才2.分支中mService.addOrUpdateNetwork部分
=> mService.addOrUpdateNetwork(config);继续往下执行代码如下:
   setVariables: { 设置网络变量如下
   ==> mWifiStateTracker.setNetworkVariable(netId, 
      WifiConfiguration.ssidVarName,  config.SSID) 
        debugmessage:  CTRL_IFACE: SET_NETWORK id=0 name='ssid'
      ===> WifiNative.setNetworkVariableCommand(netId, name, value);
            (这中间还JNI部分,最后总是到 wpa_cli 执行set network命令)
    ====>到 wpa_supplicant wpa_supplicant_ctrl_iface_set_network
         =====> wpa_config_set(ssid, name, value, 0) 更新ssid_fields
                =====> wpa_config_update_psk 更新 wpa-psk的密码
        /* 密码由SHA1 生成psk */
                =====> wpa_config_update_prio_list 更新prioty
               根据命令set network 命令参数内容:
       <network id> <variable name> <value>
      如果variable name 还会再设置prioty,
      就是说,除了conf文件1开始设置好,后面根据命令也还可以变
      你可以在java 中自己临时改变network 部分的 priority
      wpa_cli完成后,下面又返回java
      ===> mWifiStateTracker.setNetworkVariable(netId,
              WifiConfiguration.KeyMgmt.varName, allowedKeyManagementString)
       debugmessage: CTRL_IFACE: SET_NETWORK id=0 name='key_mgmt'
       一看就知道设置id=0 的netword 的key manager 变量
      ===> mWifiStateTracker.setNetworkVariable( netId,
               WifiConfiguration.priorityVarName,
                  Integer.toString(config.priority)
        会跑到刚才说的wpa_config_update_prio_list,

   ==> mWifiManager.enableNetwork(networkId, false);
       ==> mWifiStateTracker.enableNetwork(netId, false);
           ===> enableNetworkCommand(netId, false);
         ====> 到 wpa_cli 的 ENABLE_NETWORK 处理部分
        wpa_supplicant_ctrl_iface_enable_network
            (dbgmessage: CTRL_IFACE: ENABLE_NETWORK id=0)
        =====> wpa_supplicant_enable_network(wpa_s, ssid);
              第1次,if (wpa_s->current_ssid == NULL) 满足
                            1. wpa_supplicant_req_sched_scan
               请求dirver 进行周期scan
       (wpa_driver_nl80211_sched_scan NL80211_CMD_START_SCHED_SCAN)
                     scan paramater 比如ssids,filter_ssids
       基本来自于将conf文件读到内存的wpa_s->conf
       带着参数调用 wpa_supplicant_start_sched_scan
       去执行nl80211 driver 的 sched_scan
                            2. wpa_supplicant_req_scan(wpa_s, 2, 0); 
          到eloop_register_timeout(sec, usec,
             wpa_supplicant_scan, wpa_s, NULL);
                      2秒后 
        wpa_driver_nl80211_scan通过NL80211_CMD_TRIGGER_SCAN命令
                以及给定参数触发1个新的scan
                  wpa_supplicant_trigger_scan
      wpa_drv_scan 到nl80211 driver 的 scan2
kerneldoc : http://linuxwireless.org/en/developers/Documentation/nl80211/kerneldoc
解释如下:
 NL80211_CMD_START_SCHED_SCAN:
  start a scheduled scan at certain intervals, as specified by NL80211_ATTR_SCHED_SCAN_INTERVAL. Like with normal scans,
  if SSIDs (NL80211_ATTR_SCAN_SSIDS) are passed, they are used in the probe requests. For broadcast,
  a broadcast SSID must be passed (ie. an empty string). If no SSID is passed,
  no probe requests are sent and a passive scan is performed. NL80211_ATTR_SCAN_FREQUENCIES,
  if passed, define which channels should be scanned; if not passed, all channels allowed for the current regulatory domain are used.
  Extra IEs can also be passed from the userspace by using the NL80211_ATTR_IE attribute
  上面的意思就是让STA driver开始1个在sched scan interval 时间间隔的scan,
  如果有已经设置的网络,就发probe request,如果没有那么执行
  被动扫描(接收AP的beacon), 并根据设置的通道梳洗来判断,scan 所有channel
  还是某些
NL80211_CMD_TRIGGER_SCAN
  trigger a new scan with the given parameters NL80211_ATTR_TX_NO_CCK_RATE is
  used to decide whether to send the probe requests at CCK rate or not.
  wpa_supplicant_req_sched_scan   wpa_supplicant_req_scan 区别:
  就是 sched_scan 和scan2的区别 请看代码中的注释
         /**
  * scan2 - Request the driver to initiate scan
  * @priv: private driver interface data
  * @params: Scan parameters
  *
  * Returns: 0 on success, -1 on failure
  *
  * Once the scan results are ready, the driver should report scan
  * results event for wpa_supplicant which will eventually request the
  * results with wpa_driver_get_scan_results2().
  */
         /**
  * sched_scan - Request the driver to initiate scheduled scan
  * @priv: private driver interface data
  * @params: Scan parameters
  * @interval: interval between scan cycles
  *
  * Returns: 0 on success, -1 on failure
  *
  * This operation should be used for scheduled scan offload to
  * the hardware.  Every time scan results are available, the
  * driver should report scan results event for wpa_supplicant
  * which will eventually request the results with
  * wpa_driver_get_scan_results2().  This operation is optional
  * and if not provided or if it returns -1, we fall back to
  * normal host-scheduled scans.
  */
  sched scan 就是所启动一个定时扫描循环,然后scan2 触发一个scan,
  这样driver 就在scan2 后按时间间隔循环scan
      接下来到4.分支继续
 
到这里已经是连接上AP后的处理部分了
=> saveNetworks(); (wifisettings.java)
   ==> enableNetworks();  (loop mAccessPoints.getPreferenceCount )
   ==> mWifiManager.saveConfiguration();
       能看到如下message 表示在保存建立连接的network设置
       Writing configuration file '/data/misc/wifi/wpa_supplicant.conf'
       ===>mService.saveConfiguration
            ====> mWifiStateTracker.saveConfig
           =====> wpa_cli AP_SCAN 1 + wpa_cli SAVE_CONFIG
            ====> mWifiStateTracker.reloadConfig
     ------------------------------------------
           wpa_cli RECONFIGURE 命令
                  =====> wpa_supplicant_reload_configuration(), message 如下:

点击(此处)折叠或打开

  1. D/wpa_supplicant( 2129): Reading configuration file'/data/misc/wifi/wpa_supplicant.conf'
  2. D/wpa_supplicant( 2129): ctrl_interface='wlan0:0'
  3.                   wpa_config_read, wpa_config_process_global
  4. D/wpa_supplicant( 2129): update_config=1
  5.                   wpa_config_read, wpa_config_process_global
  6. D/wpa_supplicant( 2129): Line: 5- start of a new network block
  7.                   wpa_config_read ,wpa_config_read_network
  8. D/wpa_supplicant( 2129): key_mgmt: 0x2
  9. D/wpa_supplicant( 2129): priority=1(0x1)
  10. D/wpa_supplicant( 2129): Priority group 1
  11.                 wpa_config_read ,wpa_config_debug_dump_networks
  12. D/wpa_supplicant( 2129): id=0 ssid='RD-Test

  
                wpa_config_read ,wpa_config_debug_dump_networks
                  =====> wpa_sm_set_config(wpa_s->wpa, NULL);
        wpa 状态机 init,并将config 中相关内容设置到wpa状态机
                  =====> wpa_supplicant_update_config 的 message :
D/wpa_supplicant( 2129): WPS: Set UUID for interface wlan0 
                     对应  wpa_supplicant_update_config ,wpas_wps_set_uuid
D/wpa_supplicant( 2129): wlan0: P2P: Intra BSS distribution enabled
V/WifiMonitor( 1363): Event [CTRL-EVENT-STATE-CHANGE id=-1 state=0 BSSID=00:00:00:00:00:00]
V/WifiStateTracker( 1363): Changing supplicant state: SCANNING ==> DISCONNECTED
D/wpa_supplicant( 2129): Setting scan request: 2 sec 0 usec
D/wpa_supplicant( 2129): Reconfiguration completed
                  =====> wpa_supplicant_clear_status !
            ----------------------------------------------
     又回到java
            ====> boardcast  NETWORK_IDS_CHANGED_ACTION
   ==> updateAccessPoints();
上面 mWifiManager.enableNetwork(networkId, false);
       => WifiNative.enableNetworkCommand 发 ENABLE_NETWORK命令
          ==> wpa_supplicant_ctrl_iface_enable_network
       ===> wpa_supplicant_enable_network
           ===> 继续scan
 
4. 接上面3.分支继续
这时你会看到driver的消息:
 Association completed. (bss_info_changed)
字面上看关联成功? 还没发requet associate ?
那么在那里发的request associate ?
前面3.分支,开始我们SET_NETWORK,之后我们又ENABLE_NETWORK
最后发起对我们选择的AP,进行scan2,scan之后就需要等待接收结果
在前面wap_supplicant init 部分
曾经做过这个动作 wpa_driver_nl80211_init_nl
该函数最后调用:
eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
     wpa_driver_nl80211_event_receive, drv,
     drv->nl_handle_event);
前面解释过是用来接收scan result,mlme,regulator 相关的多播包
其实前面wifi eanalbe 时这部分应该也做,并且如果conf中有Network
它也会去pick network,然后开始连接过程,
现在你是第1次手动连接,同样也是从scan result 中
找到你选择的那个AP,进行连接,看下面:
=>wpa_driver_nl80211_event_receive
通过process_event callback 来继续处理 NL80211_CMD_NEW_SCAN_RESULTS 如下:
这时先会 eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
取消前面的10s scan timeout eloop
   ==> send_scan_event
       ===> wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
            ====> wpa_supplicant_event_scan_results
                 =====> _wpa_supplicant_event_scan_results
                       ======>wpas_notify_scan_results(wpa_s);
                =======> wpas_wps_notify_scan_results
                "Event [WPS-AP-AVAILABLE]"
                       ======> wpa_supplicant_pick_network
                从scan results 中选择AP,
                     根据scan 到的new ap 去匹配 (有prori等)
        其中执行 wpa_supplicant_select_bss
          可以看到: Selecting BSS from priority group 1:
                             wpa_supplicant_pick_network最后返回一个
        struct wpa_bss 结构的pointer,包含该AP的info
                      
                       ======> wpa_supplicant_rsn_preauth_scan_results
                  对scan results 启动预身份验证
    注意 WPA 不支持预先身份验证,WPA2才支持
                ======> wpa_supplicant_connect 开始连接AP
终于要开始连接了,这是应该会看到下面的msg:
wlan0: Request association: reassociate: 1 
       selected: 00:1f:33:b9:5d:e0 
       bssid: 00:00:00:00:00:00 
       pending: 00:00:00:00:00:00 
       wpa_state: SCANNING
wpa_supplicant_connect 去调用
=======> wpa_supplicant_associate(wpa_s, selected, ssid);
         ========> sme_authenticate(struct wpa_supplicant *wpa_s,
                     struct wpa_bss *bss, struct wpa_ssid *ssid)
                   开始设置一堆参数为driver层auth 调用做准备
     就提下params.auth_alg = WPA_AUTH_ALG_OPEN;
     其他看代码
     /* WPA 802.11 author 使用OPEN !!! */
                   =========>wpa_supplicant_set_suites
                    (struct wpa_supplicant *wpa_s,
                    struct wpa_bss *bss, struct wpa_ssid *ssid,
      u8 *wpa_ie, size_t *wpa_ie_len)
              它设置认证和加密的参数,这些参数从
       这个AP scan result 发过的被处理后挂在
        struct wpa_bss 的最后的IE部分获得
         获得 WPA IE ,RSN IE 后就知道了,从message看:
WPA: Selected cipher suites: group WPA_CIPHER_TKIP,
                             pairwise WPA_CIPHER_CCMP,
        key_mgmt WPA_KEY_MGMT_PSK
        proto WPA_PROTO_RSN
表示:
group 使用TKIP, 成对密钥 使用CCMP, key manager wpa_psk,
协议为RSN ,就是强健安全网络(RSN)的标准
                            调用两次wpa_sm_set_param
                            设置proto,proto enanble 到 wpa state machine结构
       struct wpa_sm 的,proto 和 rsn_enabled
                           
       还在wpa_supplicant_set_suites中,接下来通过
       wpa_sm_set_assoc_wpa_ie_default去生成关联需要
       的WPA/RSN IE,放到struct wpa_sm->assoc_wpa_ie
                            最后 wpa_sm_set_pmk 将预共享密钥PSK,copy到
       struct wpa_sm->pmk,后面要用

                   =========> wpa_supplicant_cancel_sched_scan
                wpa_supplicant_cancel_scan
        开始认证时要取消sched scan ,并canle 当前scan
                   =========> wpa_msg(wpa_s, MSG_INFO,
               "SME: Trying to authenticate with "
               MACSTR (SSID='%s' freq=%d MHz)",
         MAC2STR(params.bssid),
        wpa_ssid_txt(params.ssid, params.ssid_len),
        params.freq);
                             对应可以看到WifiMonitor msg:
                         Event [SME: Trying to authenticate with 00:1f:33:b9:5d:e0
       (SSID='RD-Test' freq=2462 MHz)]
                             由wpa_supplicant_ctrl_iface_send发到
                             wifi monitor 被 parse 为 UNKNOWN,
        monitor 不关心
                    =========> wpa_supplicant_set_state(wpa_s,
                                      WPA_AUTHENTICATING);
                    =========> wpa_s->new_connection = 1;
                    =========> wpa_drv_set_operstate(wpa_s, 0);
                 /* 设置到IF_OPER_DORMANT */
                    =========> wpa_supplicant_stop_bgscan 停止back groud scan
                    =========> wpas_notify_state_changed
          ==========> wpa_msg_ctrl(wpa_s, MSG_INFO,
          WPA_EVENT_STATE_CHANGE 给wifi monitor 发:
           Event [SME: Trying to authenticate with 00:1f:33:b9:5d:e0 (SSID='RD-Test'
    freq=2462 MHz)]
                    =========> wpa_supplicant_rsn_supp_set_config
        注释如下:
        Notify WPA state machine that configuration has changed
                      配置的网络上下文就是
        struct wpa_ssid - Network configuration data
        还有 PTK 生命周期
                    =========> wpa_supplicant_initiate_eapol
          配置EAPOL 状态机器, 启动 EAPOL,EAP 状态机器
                               调用 eapol_sm_notify_eap_success
          清除EAP success
                               调用 eapol_sm_notify_eap_fail
          清除 EAP failure
                                调用eapol_sm_notify_portControl(Auto)
    设置prot control 为自动,其他还有
    ForceUnauthorized, ForceAuthorized
       每个类似的eapol sm notify 函数中都
                     eapol_sm_step(sm); 这句很重要!
       虽然简单,但却是状态机的驱动中枢!
                   =========>wpas_notify_network_changed
                   =========> wpa_drv_authenticate
               前面一大堆,为的就是这句,这数执行nl80211 driver
        authenticate,发出后等driver 响应
        到分支5.继续
              
                   =========>eloop_register_timeout(callback=>sme_auth_timer)
            认证超时失败处理


                   =========> eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
                             eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
        注释如下:
/*
* Set portEnabled first to FALSE in order to get EAP state machine out
* of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
* state machine may transit to AUTHENTICATING state based on obsolete
* eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
* AUTHENTICATED without ever giving chance to EAP state machine to
* reset the state.
*/

5. 接分支4.
authenticate response 来了
和前面一样:
wpa_driver_nl80211_event_receive到
=> process_event
   收到 NL80211_CMD_AUTHENTICATE=37
   ==> mlme_event (37)
       ===> mlme_event_auth
            authenticate response 管理帧中的AP mac 是我们感兴趣的,
     收了它,放wpa_driver_nl80211_data 的auth_bssid
            并放到wpa_event_data->auth_info->peer
     ====> wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
           Event 11 received on interface wlan0 被扔出来
          =====> sme_event_auth(wpa_s, data);
                       紧接着
         D/wpa_supplicant( 2129): SME: Authentication response:
                        peer=00:1f:33:b9:5d:e0 auth_type=0 status_code=0
                       被扔出来
                       ======> eloop_cancel_timeout(sme_auth_timer,
                     wpa_s, NULL);
                               取消auth 失败的警戒,可以进城了
                       ======> sme_associate(wpa_s, ssid->mode,
                  data->auth.peer, data->auth.auth_type);
    启动关联
                               =======>wpa_supplicant_set_state(wpa_s,
                    WPA_ASSOCIATING);
                               ========> wpa_s->new_connection = 1;
                               ========> wpa_drv_set_operstate(wpa_s, 0);
                   /* 设置到IF_OPER_DORMANT */
                               ========> wpa_s->wpa_state = state;
                               ========> wpas_notify_state_changed(wpa_s,
             wpa_s->wpa_state, old_state);
        如果 oldstate  不同情况下执行
                               =======> 设置参数等,ie
                               =======> wpa_drv_associate(wpa_s, &params)
                                wpa_driver_nl80211_associate  driver interface
           通过netlink 给dirver 发assoc request
                                wpa_printf(MSG_DEBUG, "nl80211:
       Association request send "  "successfully");
                                发完了应该,别忘警戒下:
                       =======> eloop_register_timeout(SME_ASSOC_TIMEOUT,
                                 0, sme_assoc_timer, wpa_s,  NULL);
                                 /* 关联超时失败处理*/
       
                             接下来到分支6.
6. 接分支5.
38 event 来了!
wpa_driver_nl80211_event_receive到
=> process_event
   ==> mlme_event (38= NL80211_CMD_ASSOCIATE)
       asscoicate response 来了
      ===> mlme_event_assoc(drv, nla_data(frame),
             nla_len(frame));
      这里的 frame 应该就是关联响应帧
             去读下rp frame state 判断response为成功
          ====> drv->associated = 1;
          ====> 获得resp 中的IE们 到 event.assoc_info.resp_ies
          ====> event.assoc_info.freq = drv->assoc_freq;
        关联时的频率放到 struct assoc_info
         有了IE,就象口袋有钱,可以来事了,EVENT_ASSOC发出去
          ====> wpa_supplicant_event(drv->ctx, EVENT_ASSOC,&event);
               =====> wpa_supplicant_event_assoc(wpa_s, data);
                     ======> wpa_supplicant_event_associnfo
                            获取AP 的assoc info!
       就是挖掘前面说的已经存到event.assoc_info的resp ie
       其中如果挖到PMKID,是要注意
       去call wpa_find_assoc_pmkid
       干什么? 如果忘记了,到第1篇搜索:
       '成对主蜜钥安全关联'字样,我就不讲了
                     ======> wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
                             State: ASSOCIATING -> ASSOCIATED
                     ======> wpa_clear_keys (clear driver config key)
                     ======> wpa_supplicant_select_config
              我们设置为AP_SCAN =1(让wpa_supplciant选择AP)
       所以它什么也不做,return
                     ======> wpa_sm_notify_assoc(wpa_s->wpa, bssid);
                            WPA state machine 的rx_replay_counter_set 清0,
       的renew_snonce 置1
       比较下是否是在preauth的ap 的mac,是的话就deinit它
       最后清下wap state machine 的 old PTK
       这么做是因为人家IEEE 802.11协议8.4.10部分说了
                            Delete PTK SA on (re)association if this is not
          part of a Fast BSS Transition.
                           
                            PTK 有两种格式,TKIP,和CCMP
                     ======> eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
                     ======>eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
       ======> if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
                                   ft_completed)
                          eapol_sm_notify_eap_success(wpa_s->eapol,
                                FALSE);  
                      到这里PAE还没变化,下面就要变了
                     ======> eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
                            portEnabled=1
       PAE状态要发生变化了,从disconnect 变到connecting
                            这个disconnect是在 eapol_sm_init,开始设置的
       之后一直保持该状态
       EAP状态一直为disable,因为我们是WPA-psk,所以
       没有EAP,他就一直处于disable
                     ======> /* Timeout for receiving the first
                  EAPOL packet */
                       wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
         /* 10  秒后没收到第1个 eapol packet 后 ,
         就处理auth 失败 */
                     ======> wpa_supplicant_cancel_sched_scan(wpa_s);
       /* 要做正事了, 就先停sched scan ,scan  */
                  wpa_supplicant_cancel_scan(wpa_s);
                     ======> wpa_supplicant_event_assoc中
                接下来的部分不会执行到

到这里已经关联已经完成,在AP 发来EAPOL frame 前,我们会收到
NL80211_CMD_CONNECT 通知,根据cmd注释,可以了解该命令是在不分开进行认证
和关联的情况下,来请求连接到一个指点网络的,连接完成会收到NL80211_CMD_CONNECT
的response,目前的driver capa里设置了WPA_DRIVER_FLAGS_SME,表示driver 支持
auth 和associate 分开的命令,所以能收到NL80211_CMD_CONNECT,但不处理
为什么呢? 注释里已经写了,为了避免2次报告关联事件,引起核心代码混乱
/** Avoid reporting two association events that would confuse
 * the core code.
 */
                   进入7. 继续
7. 前面6.中完成asscicate 后,讲过就会等待EAPOL FRAME到来
  在wpa init 中 wpa_supplicant_driver_init 会注册 l2 rx callback
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
     wpa_drv_get_mac_addr(wpa_s),
     ETH_P_EAPOL,
     wpa_supplicant_rx_eapol, wpa_s, 0);
可以看出收到l2 packet 后call back wpa_supplicant_rx_eapol,就从它开始
=> wpa_supplicant_rx_eapol:
   ==> wpa_supplicant_req_auth_timeout(wpa_s,
              (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
       wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA
               || wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ? 70 : 10, 0);
        和前面associate最后设置的10s timeout 一样,这里只是收到
 第1个,reset 下一次认证超时为10s
   ==> wpa_s->eapol_received++;  是第1次,eapol_received++ 后等于1
   ==> wpa_drv_poll(wpa_s);
   ==> if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
          ===> wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
              该函数处理收到的 EAPOL frame
              分析可得:
                * type =2 时 EAPOL-Key
  * key_info =0x8a
     (ver=2 keyidx=0 rsvd=0 Pairwise Ack)
  * key length =16, key data lenght 22
key_info 各bit 所代表的内容在:
wpa_comm.h中定义如下:

点击(此处)折叠或打开

  1. /* IEEE 802.11, 8.5.2 EAPOL-Key frames */
  2. #define WPA_KEY_INFO_TYPE_MASK ((u16)(BIT(0)| BIT(1)| BIT(2)))
  3. #define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
  4. #define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
  5. #define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
  6. #define WPA_KEY_INFO_KEY_TYPE BIT(3)/* 1= Pairwise, 0= Group key */
  7. /* bit4..5is usedin WPA, butis reservedin IEEE 802.11i/RSN*/
  8. #define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4)| BIT(5))
  9. #define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
  10. #define WPA_KEY_INFO_INSTALL BIT(6)/* pairwise*/
  11. #define WPA_KEY_INFO_TXRX BIT(6)/* group*/
  12. #define WPA_KEY_INFO_ACK BIT(7)
  13. #define WPA_KEY_INFO_MIC BIT(8)
  14. #define WPA_KEY_INFO_SECURE BIT(9)
  15. #define WPA_KEY_INFO_ERROR BIT(10)
  16. #define WPA_KEY_INFO_REQUEST BIT(11)
  17. #define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12)/* IEEE 802.11i/RSN only*/
  18. #define WPA_KEY_INFO_SMK_MESSAGE BIT(13)


第1个发过来的eapol frame 表示4次握手的第1次握手已经开始了!!!
   ==> 接下来就是部分4 way handle 的代码,直接贴上:

点击(此处)折叠或打开

  1. if (key_info & WPA_KEY_INFO_KEY_TYPE){
  2.      /* 走到这里, WPA_KEY_INFO_KEY_TYPE,pairwise,or group key!!!*/
  3.    if (key_info& WPA_KEY_INFO_KEY_INDEX_MASK){
  4.  wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
  5.  "WPA: Ignored EAPOL-Key (Pairwise) with "
  6.  "non-zero key index");
  7.  goto out;
  8.    }
  9.    if (peerkey){/* 如果4way 的第1次没有peerkey*/
  10.       /* PeerKey 4-Way Handshake*/
  11.   peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
  12.    } elseif(key_info& WPA_KEY_INFO_MIC){
  13.      /* 3/4 4-Way Handshake*/
  14.      wpa_supplicant_process_3_of_4(sm, key, ver);
  15.    } else{
  16.        /* 1/4 4-Way Handshake*/
  17.  wpa_supplicant_process_1_of_4(sm, src_addr, key, ver);
  18.    }
  19. } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
  20.      /* PeerKey SMK Handshake*/
  21.      peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,ver);
  22. } else {
  23.  if (key_info& WPA_KEY_INFO_MIC){
  24.  /* 1/2 Group Key Handshake*/
  25.  wpa_supplicant_process_1_of_2(sm, src_addr, key, extra_len, ver);
  26.   } else{
  27.          wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
  28.         "WPA: EAPOL-Key (Group) without Mic bit - "
  29.   "dropped");
  30.  }
  31. }

 
wpa_supplicant_process_1_of_4(sm, src_addr, key, ver);
wpa_supplicant_process_3_of_4(sm, key, ver);
是我们关心的
为什么没有0_of_4, 2_of_4? 不是没有,4次握手的第1,3次都在AP端处理
我们不管了,所以目前阶段,直接跑到1_fo_4,处理如下
 
       ===> wpa_supplicant_process_1_of_4(sm, src_addr, key,  ver);
            ====> wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
                  wap state 变化了 , ASSOCIATED -> 4WAY_HANDSHAKE
            ====> wpa_supplicant_parse_ies(_buf, len, &ie);
                  将buf 内容解析到 struct wpa_eapol_ie_parse
                  包括我们下面要用的pmkid
            ====> wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
       如果pmksa cashe 不空,
       先从PMKSA cache中根据传来的ie.pmkid 去匹配
       然后获得PMK,它是计算 PTK必须的,但现在cur_pmksa
       为空,那如何获得pmk ,其实上面已经设置了,
       在wpa_supplicant_associate 的
       最后 wpa_sm_set_pmk 将预共享密钥PSK,copy到
        struct wpa_sm->pmk
                   
            ====> ptk = &sm->tptk;
            ====> wpa_derive_ptk(sm, src_addr, key, ptk);
                  计算方法:
               wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
                  sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
                  (u8 *) ptk, ptk_len,
                  wpa_key_mgmt_sha256(sm->key_mgmt));
                  公式:
                  * PTK = PRF-X(PMK, "Pairwise key expansion",
                  *             Min(AA, SA) || Max(AA, SA) ||
                  *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
            ====> wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver,
         sm->snonce, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, ptk)
                  =====> wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
            NULL, sizeof(*reply) + wpa_ie_len, &rlen,
     (void *) &reply);
                       os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
                       wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, 
             rbuf, rlen, reply->key_mic);
                      /* 发出去,然后等下次 wpa_supplicant_rx_eapol*/
                   接下来到8.
 
8.
l2 packet 又来了
=> wpa_supplicant_rx_eapol:
   ==> wpa_drv_poll(wpa_s);
   ==> if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
        wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
        该函数处理收到的 EAPOL frame
        分析可得:
        * type =2 时 EAPOL-Key
 * key_info =0x13ca
    (ver=2 keyidx=0 rsvd=0 Pairwise Install Ack MIC Secure Encr)
 * key length =16, key data lenght 80
   ==>  else if (key_info & WPA_KEY_INFO_MIC) {
         /*wpa_commom.h #define WPA_KEY_INFO_MIC BIT(8)*/
  /* 3/4 4-Way Handshake */
   ==>  wpa_supplicant_process_3_of_4(sm, key, ver);
       其中key 就是 EAPOL-KEY 内容
struct wpa_eapol_key {   /* EAPOL-KEY 结构!!! */
 u8 type;
 /* Note: key_info, key_length, and key_data_length are unaligned */
 u8 key_info[2]; /* big endian */
 u8 key_length[2]; /* big endian */
 u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
 u8 key_nonce[WPA_NONCE_LEN];
 u8 key_iv[16];
 u8 key_rsc[WPA_KEY_RSC_LEN];
 u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
 u8 key_mic[16];
 u8 key_data_length[2]; /* big endian */
 /* followed by key_data_length bytes of key_data */
} STRUCT_PACKED;
        下面对eapol key data 部分进行处理,将获得的ie,放到
 struct wpa_eapol_ie_parse
        ===> pos = (const u8 *) (key + 1);  eapol key 后就是ie
             len = WPA_GET_BE16(key->key_data_length);   
             wpa_supplicant_parse_ies(pos, len, &ie);
                    
        ===> wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
                      NULL, 0, &sm->ptk)
             ====> wpa_sm_alloc_eapol ,init epaol packet
                   =====> wpa_eapol_key_send(sm, ptk->kck, ver, dst,
               ETH_P_EAPOL,  rbuf, rlen, reply->key_mic);
        一个ACK ,没有什么实质内容,也不加密
        ===> wpa_supplicant_install_ptk (struct wpa_sm *sm,
                   const struct wpa_eapol_key *key)
              ====> 设置driver key !!! wpa_sm_set_key
                    wpa_driver_nl80211_set_key  (nl80211 driver)
                    wap_supplicant 的 终极目标,终于看到了!
      PTK 安装好了,稍侯片刻,马上结束
        ===> eapol_sm_notify_portValid(sm->eapol, TRUE);
               前面associate 成功后 PAE 处于 CONNECTING
               到这里 portValid = TRUE, 但PAE 状态没发生变化
        ===> wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
             WPA State 从 4WAY_HANDSHAKE -> GROUP_HANDSHAKE
        ===> wpa_supplicant_pairwise_gtk(sm, key, ie.gtk,ie.gtk_len,
                                    key_info)
             从代码中看加密的GTK 3/4 way  中的IE部分就发来了!!!
             wpa_supplicant_check_group_cipher
      用双方都已知道的PTK 的 EPAOL KEK 加的密 )现在解开来
             ====> wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)
            安装组密码
             ====> wpa_supplicant_key_neg_complete   key 协商完成
                   =====> wpa_sm_cancel_auth_timeout(sm);
            将前面设置的认证超时处理取消
                   =====> wpa_sm_set_state(sm, WPA_COMPLETED);
             wpa state 从 GROUP_HANDSHAKE -> COMPLETED
                   =====> if (secure) {
                            ......
                     eapol_sm_notify_portValid(sm->eapol, TRUE);
                     eapol_sm_notify_eap_success(sm->eapol, TRUE);
       PAE 进入AUTHENTICATING
       BE  进入success
       EAP 返回diable
       PAE 最终进入AUTHENTICATED
         然后eapol_sm_set_port_authorized
                              然后wpa_supplicant_port_cb
         然后wpa_drv_set_supp_port
         设置driver NL80211_STA_FLAG_AUTHORIZED
到此为止,认证完成
整个过程的WPA State变化如下:
(wpa_supplicant)
DISCONNECTED    -> SCANNING
SCANNING        -> AUTHENTICATING      (802.11身份认证 )
AUTHENTICATING  -> ASSOCIATING
SCANNING        -> ASSOCIATING
ASSOCIATING     -> ASSOCIATED    
     
ASSOCIATED      -> 4WAY_HANDSHAKE
4WAY_HANDSHAKE  -> 4WAY_HANDSHAKE
4WAY_HANDSHAKE  -> GROUP_HANDSHAKE
GROUP_HANDSHAKE -> COMPLETED
PAE supplicant 端状态图
 
 
结束
 
  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值