Android4.4 wpa

    xiaoxiao2021-04-15  245

    Android系统中,wpa_supplicant启动是通过“setprop ctrl.start wpa_supplicant”来触发init进程去fork一个子进程来完成的。wpa_supplicant在init配置文件中被定义为一个service。

    [cpp]  view plain  copy   service wpa_supplicant /system/bin/wpa_supplicant \       -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \       -I/system/etc/wifi/wpa_supplicant_overlay.conf \       -O/data/misc/wifi/sockets \       -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0       #   we will start as root and wpa_supplicant will switch to user wifi       #   after setting up the capabilities required for WEXT       #   user wifi       #   group wifi inet keystore       class main       socket wpa_wlan0 dgram 660 wifi wifi       disabled       oneshot   以上众多启动参数中,最重要的是通过“-c“参数制定的wpa_supplicant启动配置文件。 [cpp]  view plain  copy   ctrl_interface=/data/misc/wifi/sockets   driver_param=use_p2p_group_interface=1p2p_device=1   update_config=1   device_name=********   manufacturer=BROADCOM   model_name=*********   model_number=*********   serial_number=   device_type=10-0050F204-5   config_methods=physical_display virtual_push_button   p2p_listen_reg_class=81   p2p_listen_channel=11   p2p_oper_reg_class=81   p2p_oper_channel=11   p2p_ssid_postfix=-Android_7006   persistent_reconnect=1      network={       ssid="AP_5D34E3"       psk="12345678"       key_mgmt=WPA-PSK       priority=1   }      network={       ssid="Android-02"       psk="android.com"       key_mgmt=WPA-PSK       priority=2   }  

    (1)ctrl_interface知名控制接口Unix域socket的文件名。

    (2)update_config表示如果wpa_supplicant运行过程中修改了配置信息,则需要把它们保存到此wpa_supplicant文件中。

    (3)从device_name到config_methods都和wpa_supplicant设置有关。

    (4)p2p等选项和WiFi P2P有关。

    (5)wpa_supplicant运行过程中得到的无线网络信息都会通过”network“配置项保存到配置文件中。如果该信息完整,一旦wpa_supplicant找到该无线网络就会尝试用保存的信息去加入它。(这也是手机能自动加入周围某个曾经的路过的无线网络的原因)。

    (6)network项包括的内容比较多。network项展示了该无线网络的ssid、密钥管理方法(key management)、身份认证方法及密码等信息。network中的priority表示无线网络的优先级。其作用是,如果同时存在多个可用的无线网络,wpa_supplicant有限选择priority搞得那一个。

    main函数分析[-->main.c::main]

    [cpp]  view plain  copy   int main(int argc, char *argv[])   {       int c, i;       struct wpa_interface *ifaces, *iface;       int iface_count, exitcode = -1;       struct wpa_params params;       struct wpa_global *global;          if (os_program_init())           return -1;          os_memset(¶ms, 0, sizeof(params));       params.wpa_debug_level = MSG_INFO;          iface = ifaces = os_zalloc(sizeof(struct wpa_interface));       if (ifaces == NULL)           return -1;       iface_count = 1;          wpa_supplicant_fd_workaround(1);  //输入输出重定向到/dev/null设备          for (;;) {           c = getopt(argc, argv,                  "b:Bc:C:D:de:f:g:G:hi:I:KLNo:O:p:P:qsTtuvW");           if (c < 0)               break;           switch (c) {           case 'b':               iface->bridge_ifname = optarg;               break;           case 'B':               params.daemonize++;               break;           case 'c':               iface->confname = optarg;    //指定配置文件名。注意,该参数赋值给了wpa_interface中的变量               break;           case 'C':               iface->ctrl_interface = optarg;               break;           case 'D':               iface->driver = optarg;         //指定driver名称。注意,该参数赋值给了wpa_interface中的变量               break;           case 'd':   #ifdef CONFIG_NO_STDOUT_DEBUG               printf("Debugging disabled with "                      "CONFIG_NO_STDOUT_DEBUG=y build time "                      "option.\n");               goto out;   #else /* CONFIG_NO_STDOUT_DEBUG */               params.wpa_debug_level--;               break;   #endif /* CONFIG_NO_STDOUT_DEBUG */           case 'e':               params.entropy_file = optarg;  //制定初始随机数文件,用于后续随机数的生成               break;   #ifdef CONFIG_DEBUG_FILE           case 'f':               params.wpa_debug_file_path = optarg;               break;   #endif /* CONFIG_DEBUG_FILE */           case 'g':               params.ctrl_interface = optarg;               break;           case 'G':               params.ctrl_interface_group = optarg;               break;           case 'h':               usage();               exitcode = 0;               goto out;           case 'i':               iface->ifname = optarg;  //指定网络设备接口名,本例是"wlan0"               break;           case 'I':               iface->confanother = optarg;               break;           case 'K':               params.wpa_debug_show_keys++;               break;           case 'L':               license();               exitcode = 0;               goto out;           case 'o':               params.override_driver = optarg;               break;           case 'O':               params.override_ctrl_interface = optarg;               break;           case 'p':               iface->driver_param = optarg;               break;           case 'P':               os_free(params.pid_file);               params.pid_file = os_rel2abs_path(optarg);               break;           case 'q':               params.wpa_debug_level++;               break;   #ifdef CONFIG_DEBUG_SYSLOG           case 's':               params.wpa_debug_syslog++;               break;   #endif /* CONFIG_DEBUG_SYSLOG */   #ifdef CONFIG_DEBUG_LINUX_TRACING           case 'T':               params.wpa_debug_tracing++;               break;   #endif /* CONFIG_DEBUG_LINUX_TRACING */           case 't':               params.wpa_debug_timestamp++;               break;   #ifdef CONFIG_DBUS           case 'u':               params.dbus_ctrl_interface = 1;               break;   #endif /* CONFIG_DBUS */           case 'v':               printf("%s\n", wpa_supplicant_version);               exitcode = 0;               goto out;           case 'W':               params.wait_for_monitor++;               break;           case 'N':               iface_count++;               iface = os_realloc_array(ifaces, iface_count,                            sizeof(struct wpa_interface));               if (iface == NULL)                   goto out;               ifaces = iface;               iface = &ifaces[iface_count - 1];                os_memset(iface, 0, sizeof(*iface));               break;           default:               usage();               exitcode = 0;               goto out;           }       }          exitcode = 0;       global = wpa_supplicant_init(¶ms);  //关键函数,根据传入的参数,创建并初始化一个wpa_global对象       if (global == NULL) {           wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");           exitcode = -1;           goto out;       } else {           wpa_printf(MSG_INFO, "Successfully initialized "                  "wpa_supplicant");       }          for (i = 0; exitcode == 0 && i < iface_count; i++) {           struct wpa_supplicant *wpa_s;              if ((ifaces[i].confname == NULL &&                ifaces[i].ctrl_interface == NULL) ||               ifaces[i].ifname == NULL) {               if (iface_count == 1 && (params.ctrl_interface ||                            params.dbus_ctrl_interface))                   break;               usage();               exitcode = -1;               break;           }           wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]);   //关键函数,wpa_supplicant支持操作多个无线网络设备,此处需将它们一一添加到wpa_supplicant中,wpa_supplicant内部将初始化这些设备。           if (wpa_s == NULL) {               exitcode = -1;               break;           }   #ifdef CONFIG_P2P           if (wpa_s->global->p2p == NULL &&               (wpa_s->drv_flags &                WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&               wpas_p2p_add_p2pdev_interface(wpa_s) < 0)               exitcode = -1;   #endif /* CONFIG_P2P */       }          if (exitcode == 0)           exitcode = wpa_supplicant_run(global);  //android平台中,wpa_supplicant通过select或epoll或方式实现多路I/O复用。          wpa_supplicant_deinit(global);      out:       wpa_supplicant_fd_workaround(0);       os_free(ifaces);       os_free(params.pid_file);          os_program_deinit();          return exitcode;   }   main函数中重要的数据结构

    struct wpa_interface+confname:const char* //该接口对应的配置文件名 +ctrl_interface: const char* //控制接口unix域socket地址 +driver:const char* //该接口对应的驱动名 +driver_param:const char* //该接口对应驱动的参数 +ifname:const char* //指定网络接口设备名 +bridge_ifname:const char* //当接口用作桥接设备时,其桥接设备名本例中: confname = "/data/misc/wifi/wpa_supplicant.conf" ifname = "wlan0" driver = "nl80211"

     

     

     

    struct wpa_global+ifaces:struct wpa_supplicant*  //见下文解释 +params:struct wpa_params  //运行参数 +ctrl_ifaces:struct ctrl_iface_global_priv*  //全局控制接口 +drv_priv:void**  //driver wrapper对应的全局上下文信息 +drv_count:size_t  //driver wrapper的个数 

     

     

     

     

     

    struct ctrl_iface_global_privstruct wpa_supplicant+global:struct wpa_global* +socket:int+global:struct wpa_global* +next:struct wpa_supplicant*

     

     

     

    (1)wpa_interface用于描述一个无线设备。该参数在初始化时用到。

    (2)wpa_global是一个全局性质的上下文信息。它通过ifaces变量指向一个wpa_supplicant对象。

    (3)wpa_supplicant是wpa_supplicant的核心数据结构。一个interface对应一个wpa_supplicant对象,其内部包含非常多的成员变量。

    (4)ctrl_iface_global_priv是全局控制接口的信息,内部包含一个用于通信的socket句柄。

    wpa_supplicant_init函数分析

    [-->wpa_supplicant.c::wpa_supplicant_init]

    [cpp]  view plain  copy   struct wpa_global * wpa_supplicant_init(struct wpa_params *params)   {       struct wpa_global *global;       int ret, i;          if (params == NULL)           return NULL;      #ifdef CONFIG_DRIVER_NDIS       {           void driver_ndis_init_ops(void);           driver_ndis_init_ops();       }   #endif /* CONFIG_DRIVER_NDIS */      #ifndef CONFIG_NO_WPA_MSG   [cpp]  view plain  copy   <span style="white-space:pre">    </span>//设置全局回调函数       wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);   #endif /* CONFIG_NO_WPA_MSG */          wpa_debug_open_file(params->wpa_debug_file_path);       if (params->wpa_debug_syslog)           wpa_debug_open_syslog();       if (params->wpa_debug_tracing) {           ret = wpa_debug_open_linux_tracing();           if (ret) {               wpa_printf(MSG_ERROR,                      "Failed to enable trace logging");               return NULL;           }       }          ret = eap_register_methods();<span style="white-space:pre">   </span>//注册EAP方法       if (ret) {           wpa_printf(MSG_ERROR, "Failed to register EAP methods");           if (ret == -2)               wpa_printf(MSG_ERROR, "Two or more EAP methods used "                      "the same EAP type.");           return NULL;       }          global = os_zalloc(sizeof(*global));       if (global == NULL)           return NULL;       dl_list_init(&global->p2p_srv_bonjour);       dl_list_init(&global->p2p_srv_upnp);       global->params.daemonize = params->daemonize;       global->params.wait_for_monitor = params->wait_for_monitor;       global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;       if (params->pid_file)           global->params.pid_file = os_strdup(params->pid_file);       if (params->ctrl_interface)           global->params.ctrl_interface =               os_strdup(params->ctrl_interface);       if (params->ctrl_interface_group)           global->params.ctrl_interface_group =               os_strdup(params->ctrl_interface_group);       if (params->override_driver)           global->params.override_driver =               os_strdup(params->override_driver);       if (params->override_ctrl_interface)           global->params.override_ctrl_interface =               os_strdup(params->override_ctrl_interface);       wpa_debug_level = global->params.wpa_debug_level =           params->wpa_debug_level;       wpa_debug_show_keys = global->params.wpa_debug_show_keys =           params->wpa_debug_show_keys;       wpa_debug_timestamp = global->params.wpa_debug_timestamp =           params->wpa_debug_timestamp;          wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);   <span style="white-space:pre">    </span>//初始化事件循环机制       if (eloop_init()) {           wpa_printf(MSG_ERROR, "Failed to initialize event loop");           wpa_supplicant_deinit(global);           return NULL;       }   <span style="white-space:pre">    </span>//初始化随机数相关资源,用于提升后续随机数生成的随机性       random_init(params->entropy_file);   <span style="white-space:pre">    </span>//初始化全局控制接口对象       global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);       if (global->ctrl_iface == NULL) {           wpa_supplicant_deinit(global);           return NULL;       }          if (wpas_notify_supplicant_initialized(global)) {           wpa_supplicant_deinit(global);           return NULL;       }   <span style="white-space:pre">    </span>//wpa_driver是一个全局变量。       for (i = 0; wpa_drivers[i]; i++)           global->drv_count++;       if (global->drv_count == 0) {           wpa_printf(MSG_ERROR, "No drivers enabled");           wpa_supplicant_deinit(global);           return NULL;       }   [cpp]  view plain  copy   <span style="white-space:pre">    </span>//分配全局driver wrapper上下文信息数组       global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));       if (global->drv_priv == NULL) {           wpa_supplicant_deinit(global);           return NULL;       }      #ifdef CONFIG_WIFI_DISPLAY       if (wifi_display_init(global) < 0) {           wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");           wpa_supplicant_deinit(global);           return NULL;       }   #endif /* CONFIG_WIFI_DISPLAY */          return global;   }  

    wpa_supplicant_init函数的主要功能是初始化wpa_global以及一些与整个程序相关的资源,包括随机数资源、eloop事件循环机制以及设置消息全局回调函数。

    (1)wpa_msg_get_ifname_func:有些输出信息中需要打印出网卡接口名。该回调函数用于获取网卡接口名。

    (2)wpa_msg_cb_func:除了打印输出信息外,还可通过该回调函数进行一些特殊处理,如把输出信息发送给客户端进行处理。

    [-->wpa_debug.c]

    [cpp]  view plain  copy   void wpa_msg_register_cb(wpa_msg_cb_func func)   {       wpa_msg_cb = func;   }         static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;   [cpp]  view plain  copy   static wpa_msg_cb_func wpa_msg_cb = NULL;      void wpa_msg_register_cb(wpa_msg_cb_func func)   {       wpa_msg_cb = func;   }  

    wpa_supplicant_init中列出了三个关键点,分别是eap_register_method函数、eloop_init函数及event loop模块、wpa_drivers数组和driver i/f模块

    1、eap_register_method函数

    主要根据编译时的配置项来初始化不同的eap方法。

    [-->eap-register.c::eap_register_methods]

    [cpp]  view plain  copy   int eap_register_methods(void)   {       int ret = 0;      #ifdef EAP_MD5<span style="white-space:pre">      </span>//作为supplicant端,编译时将定义EAP_MD5       if (ret == 0)           ret = eap_peer_md5_register();   #endif /* EAP_MD5 */      #ifdef EAP_TLS       if (ret == 0)           ret = eap_peer_tls_register();   #endif /* EAP_TLS */      #ifdef EAP_UNAUTH_TLS       if (ret == 0)           ret = eap_peer_unauth_tls_register();   #endif /* EAP_UNAUTH_TLS */      #ifdef EAP_MSCHAPv2       if (ret == 0)           ret = eap_peer_mschapv2_register();   #endif /* EAP_MSCHAPv2 */      #ifdef EAP_PEAP       if (ret == 0)           ret = eap_peer_peap_register();   #endif /* EAP_PEAP */      #ifdef EAP_TTLS       if (ret == 0)           ret = eap_peer_ttls_register();   #endif /* EAP_TTLS */      #ifdef EAP_GTC       if (ret == 0)           ret = eap_peer_gtc_register();   #endif /* EAP_GTC */      #ifdef EAP_OTP       if (ret == 0)           ret = eap_peer_otp_register();   #endif /* EAP_OTP */      #ifdef EAP_SIM       if (ret == 0)           ret = eap_peer_sim_register();   #endif /* EAP_SIM */      #ifdef EAP_LEAP       if (ret == 0)           ret = eap_peer_leap_register();   #endif /* EAP_LEAP */      #ifdef EAP_PSK       if (ret == 0)           ret = eap_peer_psk_register();   #endif /* EAP_PSK */      #ifdef EAP_AKA       if (ret == 0)           ret = eap_peer_aka_register();   #endif /* EAP_AKA */      #ifdef EAP_AKA_PRIME       if (ret == 0)           ret = eap_peer_aka_prime_register();   #endif /* EAP_AKA_PRIME */      #ifdef EAP_FAST       if (ret == 0)           ret = eap_peer_fast_register();   #endif /* EAP_FAST */      #ifdef EAP_PAX       if (ret == 0)           ret = eap_peer_pax_register();   #endif /* EAP_PAX */      #ifdef EAP_SAKE       if (ret == 0)           ret = eap_peer_sake_register();   #endif /* EAP_SAKE */      #ifdef EAP_GPSK       if (ret == 0)           ret = eap_peer_gpsk_register();   #endif /* EAP_GPSK */      #ifdef EAP_WSC       if (ret == 0)           ret = eap_peer_wsc_register();   #endif /* EAP_WSC */      #ifdef EAP_IKEV2       if (ret == 0)           ret = eap_peer_ikev2_register();   #endif /* EAP_IKEV2 */      #ifdef EAP_VENDOR_TEST       if (ret == 0)           ret = eap_peer_vendor_test_register();   #endif /* EAP_VENDOR_TEST */      #ifdef EAP_TNC       if (ret == 0)           ret = eap_peer_tnc_register();   #endif /* EAP_TNC */      #ifdef EAP_PWD       if (ret == 0)           ret = eap_peer_pwd_register();   #endif /* EAP_PWD */      #ifdef EAP_EKE       if (ret == 0)           ret = eap_peer_eke_register();   #endif /* EAP_EKE */      #ifdef EAP_SERVER_IDENTITY       if (ret == 0)           ret = eap_server_identity_register();   #endif /* EAP_SERVER_IDENTITY */      #ifdef EAP_SERVER_MD5<span style="white-space:pre">           </span>//作为Authenticator端,编译时将定义EAP_SERVER_MD5       if (ret == 0)           ret = eap_server_md5_register();   #endif /* EAP_SERVER_MD5 */      #ifdef EAP_SERVER_TLS       if (ret == 0)           ret = eap_server_tls_register();   #endif /* EAP_SERVER_TLS */      #ifdef EAP_SERVER_UNAUTH_TLS       if (ret == 0)           ret = eap_server_unauth_tls_register();   #endif /* EAP_SERVER_UNAUTH_TLS */      #ifdef EAP_SERVER_MSCHAPV2       if (ret == 0)           ret = eap_server_mschapv2_register();   #endif /* EAP_SERVER_MSCHAPV2 */      #ifdef EAP_SERVER_PEAP       if (ret == 0)           ret = eap_server_peap_register();   #endif /* EAP_SERVER_PEAP */      #ifdef EAP_SERVER_TLV       if (ret == 0)           ret = eap_server_tlv_register();   #endif /* EAP_SERVER_TLV */      #ifdef EAP_SERVER_GTC       if (ret == 0)           ret = eap_server_gtc_register();   #endif /* EAP_SERVER_GTC */      #ifdef EAP_SERVER_TTLS       if (ret == 0)           ret = eap_server_ttls_register();   #endif /* EAP_SERVER_TTLS */      #ifdef EAP_SERVER_SIM       if (ret == 0)           ret = eap_server_sim_register();   #endif /* EAP_SERVER_SIM */      #ifdef EAP_SERVER_AKA       if (ret == 0)           ret = eap_server_aka_register();   #endif /* EAP_SERVER_AKA */      #ifdef EAP_SERVER_AKA_PRIME       if (ret == 0)           ret = eap_server_aka_prime_register();   #endif /* EAP_SERVER_AKA_PRIME */      #ifdef EAP_SERVER_PAX       if (ret == 0)           ret = eap_server_pax_register();   #endif /* EAP_SERVER_PAX */      #ifdef EAP_SERVER_PSK       if (ret == 0)           ret = eap_server_psk_register();   #endif /* EAP_SERVER_PSK */      #ifdef EAP_SERVER_SAKE       if (ret == 0)           ret = eap_server_sake_register();   #endif /* EAP_SERVER_SAKE */      #ifdef EAP_SERVER_GPSK       if (ret == 0)           ret = eap_server_gpsk_register();   #endif /* EAP_SERVER_GPSK */      #ifdef EAP_SERVER_VENDOR_TEST       if (ret == 0)           ret = eap_server_vendor_test_register();   #endif /* EAP_SERVER_VENDOR_TEST */      #ifdef EAP_SERVER_FAST       if (ret == 0)           ret = eap_server_fast_register();   #endif /* EAP_SERVER_FAST */      #ifdef EAP_SERVER_WSC       if (ret == 0)           ret = eap_server_wsc_register();   #endif /* EAP_SERVER_WSC */      #ifdef EAP_SERVER_IKEV2       if (ret == 0)           ret = eap_server_ikev2_register();   #endif /* EAP_SERVER_IKEV2 */      #ifdef EAP_SERVER_TNC       if (ret == 0)           ret = eap_server_tnc_register();   #endif /* EAP_SERVER_TNC */      #ifdef EAP_SERVER_PWD       if (ret == 0)           ret = eap_server_pwd_register();   #endif /* EAP_SERVER_PWD */          return ret;   }   2、eloop_init函数及event loop模块

    初始化了wpa_supplicant中事件驱动的核心数据结构体

    从事件角度来看,wpa_supplicant的事件驱动机制支持5中类型event:

    (1)read event:读事件,例如来自socket的可读事件

    (2)write event:写事件

    (3)exception event:异常事件

    (4)timeout event:定时事件

    (5)signal:信号时间,信号时间来源于Kernel。

    [-->eloop.c::eloop_run]

    [cpp]  view plain  copy   void eloop_run(void)   {   #ifdef CONFIG_ELOOP_POLL       int num_poll_fds;       int timeout_ms = 0;   #else /* CONFIG_ELOOP_POLL */       fd_set *rfds, *wfds, *efds;       struct timeval _tv;   #endif /* CONFIG_ELOOP_POLL */       int res;       struct os_time tv, now;      #ifndef CONFIG_ELOOP_POLL       rfds = os_malloc(sizeof(*rfds));       wfds = os_malloc(sizeof(*wfds));       efds = os_malloc(sizeof(*efds));       if (rfds == NULL || wfds == NULL || efds == NULL)           goto out;   #endif /* CONFIG_ELOOP_POLL */   <span style="white-space:pre">    </span>//事件驱动循环       while (!eloop.terminate &&              (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||           eloop.writers.count > 0 || eloop.exceptions.count > 0)) {           struct eloop_timeout *timeout;           timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,                       list);           if (timeout) {               os_get_time(&now);               if (os_time_before(&now, &timeout->time))                   os_time_sub(&timeout->time, &now, &tv);               else                   tv.sec = tv.usec = 0;   #ifdef CONFIG_ELOOP_POLL               timeout_ms = tv.sec * 1000 + tv.usec / 1000;   #else /* CONFIG_ELOOP_POLL */               _tv.tv_sec = tv.sec;               _tv.tv_usec = tv.usec;   #endif /* CONFIG_ELOOP_POLL */           }      #ifdef CONFIG_ELOOP_POLL           num_poll_fds = eloop_sock_table_set_fds(               &eloop.readers, &eloop.writers, &eloop.exceptions,               eloop.pollfds, eloop.pollfds_map,               eloop.max_pollfd_map);           res = poll(eloop.pollfds, num_poll_fds,                  timeout ? timeout_ms : -1);              if (res < 0 && errno != EINTR && errno != 0) {               perror("poll");               goto out;           }   #else /* CONFIG_ELOOP_POLL */           eloop_sock_table_set_fds(&eloop.readers, rfds);           eloop_sock_table_set_fds(&eloop.writers, wfds);           eloop_sock_table_set_fds(&eloop.exceptions, efds);           res = select(eloop.max_sock + 1, rfds, wfds, efds,                    timeout ? &_tv : NULL);           if (res < 0 && errno != EINTR && errno != 0) {               perror("select");               goto out;           }   #endif /* CONFIG_ELOOP_POLL */           eloop_process_pending_signals();<span style="white-space:pre">    </span>//先处理信号事件              /* check if some registered timeouts have occurred */           timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,                       list);           if (timeout) {               os_get_time(&now);               if (!os_time_before(&now, &timeout->time)) {                   void *eloop_data = timeout->eloop_data;                   void *user_data = timeout->user_data;                   eloop_timeout_handler handler =                       timeout->handler;                   eloop_remove_timeout(timeout);                   handler(eloop_data, user_data);               }              }              if (res <= 0)               continue;      #ifdef CONFIG_ELOOP_POLL           eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,                         &eloop.exceptions, eloop.pollfds_map,                         eloop.max_pollfd_map);   #else /* CONFIG_ELOOP_POLL */           eloop_sock_table_dispatch(&eloop.readers, rfds);           eloop_sock_table_dispatch(&eloop.writers, wfds);           eloop_sock_table_dispatch(&eloop.exceptions, efds);   #endif /* CONFIG_ELOOP_POLL */       }          eloop.terminate = 0;   out:   #ifndef CONFIG_ELOOP_POLL       os_free(rfds);       os_free(wfds);       os_free(efds);   #endif /* CONFIG_ELOOP_POLL */       return;   }   eloop_run中的while循环是wpa_supplicant进程的运行中枢。

    3、wpa_drivers数组和driver i/f模块

    wpa_drivers是一个全局数组变量,它通过extern方式声明于main.c中,其定义却在drivers.c:

    [-->drivers.c::wpa_drivers定义]

    [cpp]  view plain  copy   struct wpa_driver_ops *wpa_drivers[] =   {   #ifdef CONFIG_DRIVER_NL80211       &wpa_driver_nl80211_ops,   #endif /* CONFIG_DRIVER_NL80211 */   #ifdef CONFIG_DRIVER_WEXT       &wpa_driver_wext_ops,   #endif /* CONFIG_DRIVER_WEXT */   #ifdef CONFIG_DRIVER_HOSTAP       &wpa_driver_hostap_ops,   #endif /* CONFIG_DRIVER_HOSTAP */   #ifdef CONFIG_DRIVER_MADWIFI       &wpa_driver_madwifi_ops,   #endif /* CONFIG_DRIVER_MADWIFI */   #ifdef CONFIG_DRIVER_BSD       &wpa_driver_bsd_ops,   #endif /* CONFIG_DRIVER_BSD */   #ifdef CONFIG_DRIVER_OPENBSD       &wpa_driver_openbsd_ops,   #endif /* CONFIG_DRIVER_OPENBSD */   #ifdef CONFIG_DRIVER_NDIS       &wpa_driver_ndis_ops,   #endif /* CONFIG_DRIVER_NDIS */   #ifdef CONFIG_DRIVER_WIRED       &wpa_driver_wired_ops,   #endif /* CONFIG_DRIVER_WIRED */   #ifdef CONFIG_DRIVER_TEST       &wpa_driver_test_ops,   #endif /* CONFIG_DRIVER_TEST */   #ifdef CONFIG_DRIVER_ROBOSWITCH       &wpa_driver_roboswitch_ops,   #endif /* CONFIG_DRIVER_ROBOSWITCH */   #ifdef CONFIG_DRIVER_ATHEROS       &wpa_driver_atheros_ops,   #endif /* CONFIG_DRIVER_ATHEROS */   #ifdef CONFIG_DRIVER_NONE       &wpa_driver_none_ops,   #endif /* CONFIG_DRIVER_NONE */       NULL   };   wpa_drivers数组成员指向一个wpa_driver_ops类型的对象。wpa_driver_ops是driver i/f模块的核心数据结构,其内部定义了很多函数指针。

    [-->driver_nl80211.c::wpa_driver_nl80211_ops]

    [cpp]  view plain  copy   const struct wpa_driver_ops wpa_driver_nl80211_ops = {       .name = "nl80211",       .desc = "Linux nl80211/cfg80211",       .get_bssid = wpa_driver_nl80211_get_bssid,       .get_ssid = wpa_driver_nl80211_get_ssid,       .set_key = driver_nl80211_set_key,       .scan2 = driver_nl80211_scan2,       .sched_scan = wpa_driver_nl80211_sched_scan,       .stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,       .get_scan_results2 = wpa_driver_nl80211_get_scan_results,       .deauthenticate = driver_nl80211_deauthenticate,       .authenticate = driver_nl80211_authenticate,       .associate = wpa_driver_nl80211_associate,       .global_init = nl80211_global_init,       .global_deinit = nl80211_global_deinit,       .init2 = wpa_driver_nl80211_init,       .deinit = driver_nl80211_deinit,       .get_capa = wpa_driver_nl80211_get_capa,       .set_operstate = wpa_driver_nl80211_set_operstate,       .set_supp_port = wpa_driver_nl80211_set_supp_port,       .set_country = wpa_driver_nl80211_set_country,       .set_ap = wpa_driver_nl80211_set_ap,       .set_acl = wpa_driver_nl80211_set_acl,       .if_add = wpa_driver_nl80211_if_add,       .if_remove = driver_nl80211_if_remove,       .send_mlme = driver_nl80211_send_mlme,       .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,       .sta_add = wpa_driver_nl80211_sta_add,       .sta_remove = driver_nl80211_sta_remove,       .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,       .sta_set_flags = wpa_driver_nl80211_sta_set_flags,   #ifdef HOSTAPD       .hapd_init = i802_init,       .hapd_deinit = i802_deinit,       .set_wds_sta = i802_set_wds_sta,   #endif /* HOSTAPD */   #if defined(HOSTAPD) || defined(CONFIG_AP)       .get_seqnum = i802_get_seqnum,       .flush = i802_flush,       .get_inact_sec = i802_get_inact_sec,       .sta_clear_stats = i802_sta_clear_stats,       .set_rts = i802_set_rts,       .set_frag = i802_set_frag,       .set_tx_queue_params = i802_set_tx_queue_params,       .set_sta_vlan = driver_nl80211_set_sta_vlan,       .sta_deauth = i802_sta_deauth,       .sta_disassoc = i802_sta_disassoc,   #endif /* HOSTAPD || CONFIG_AP */       .read_sta_data = driver_nl80211_read_sta_data,       .set_freq = i802_set_freq,       .send_action = driver_nl80211_send_action,       .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,       .remain_on_channel = wpa_driver_nl80211_remain_on_channel,       .cancel_remain_on_channel =       wpa_driver_nl80211_cancel_remain_on_channel,       .probe_req_report = driver_nl80211_probe_req_report,       .deinit_ap = wpa_driver_nl80211_deinit_ap,       .deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,       .resume = wpa_driver_nl80211_resume,       .send_ft_action = nl80211_send_ft_action,       .signal_monitor = nl80211_signal_monitor,       .signal_poll = nl80211_signal_poll,       .send_frame = nl80211_send_frame,       .shared_freq = wpa_driver_nl80211_shared_freq,       .set_param = nl80211_set_param,       .get_radio_name = nl80211_get_radio_name,       .add_pmkid = nl80211_add_pmkid,       .remove_pmkid = nl80211_remove_pmkid,       .flush_pmkid = nl80211_flush_pmkid,       .set_rekey_info = nl80211_set_rekey_info,       .poll_client = nl80211_poll_client,       .set_p2p_powersave = nl80211_set_p2p_powersave,       .start_dfs_cac = nl80211_start_radar_detection,       .stop_ap = wpa_driver_nl80211_stop_ap,   #ifdef CONFIG_TDLS       .send_tdls_mgmt = nl80211_send_tdls_mgmt,       .tdls_oper = nl80211_tdls_oper,   #endif /* CONFIG_TDLS */       .update_ft_ies = wpa_driver_nl80211_update_ft_ies,       .get_mac_addr = wpa_driver_nl80211_get_macaddr,       .get_survey = wpa_driver_nl80211_get_survey,   #ifdef ANDROID_P2P       .set_noa = wpa_driver_set_p2p_noa,       .get_noa = wpa_driver_get_p2p_noa,       .set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,   #endif   #ifdef ANDROID       .driver_cmd = wpa_driver_nl80211_driver_cmd,   #endif   };   待续。。。
    转载请注明原文地址: https://ju.6miu.com/read-670762.html

    最新回复(0)