现在的位置: 首页 > 综合 > 正文

android wpa_supplicant 流程分析

2013年04月09日 ⁄ 综合 ⁄ 共 17743字 ⁄ 字号 评论关闭

以下分析基于 wpa_supplicant 0.5.11 版本

1、wpa_supplicant简介

    wpa_supplicant is an implementation of the WPA Supplicant component,
i.e., the part that runs in the client stations. It implements WPA key
negotiation with a WPA Authenticator and EAP authentication with
Authentication Server. In addition, it controls the roaming and IEEE
802.11 authentication/association of the wlan driver.
    wpa_supplicant is designed to be a "daemon" program that runs in the
background and acts as the backend component controlling the wireless
connection. wpa_supplicant supports separate frontend programs and an
example text-based frontend, wpa_cli, is included with wpa_supplicant.
    Following steps are used when associating with an AP using WPA:
      - wpa_supplicant requests the kernel driver to scan neighboring BSSes
      - wpa_supplicant selects a BSS based on its configuration
      - wpa_supplicant requests the kernel driver to associate with the chosen BSS
      - If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP
  authentication with the authentication server (proxied by theAuthenticator in the AP)
      - If WPA-EAP: master key is received from the IEEE 802.1X Supplicant
      - If WPA-PSK: wpa_supplicant uses PSK as the master session key
      - wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake
  with the Authenticator (AP)
      - wpa_supplicant configures encryption keys for unicast and broadcast
      - normal data packets can be transmitted and received

2、启动命令

    You will need to make a configuration file, e.g.,
/etc/wpa_supplicant.conf, with network configuration for the networks
you are going to use. Configuration file section below includes
explanation fo the configuration file format and includes various
examples. Once the configuration is ready, you can test whether the
configuration work by first running wpa_supplicant with following
command to start it on foreground with debugging enabled:
      wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d


    Assuming everything goes fine, you can start using following command
to start wpa_supplicant on background without debugging:
      wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B


    Please note that if you included more than one driver interface in the
build time configuration (.config), you may need to specify which
interface to use by including -D<driver name> option on the command
line. See following section for more details on command line options
for wpa_supplicant.

    Command line options
--------------------
usage:
  wpa_supplicant [-BddfhKLqqtuvwW] [-P<pid file>] [-g<global ctrl>] \
        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
        [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
        [-p<driver_param>] [-b<br_ifname>] ...]

options:
  -b = optional bridge interface name
  -B = run daemon in the background
  -c = Configuration file
  -C = ctrl_interface parameter (only used if -c is not)
  -i = interface name
  -d = increase debugging verbosity (-dd even more)
  -D = driver name
  -f = Log output to default log location (normally /tmp)
  -g = global ctrl_interface
  -K = include keys (passwords, etc.) in debug output
  -t = include timestamp in debug messages
  -h = show this help text
  -L = show license (GPL and BSD)
  -p = driver parameters
  -P = PID file
  -q = decrease debugging verbosity (-qq even less)
  -v = show version
  -w = wait for interface to be added, if needed
  -W = wait for a control interface monitor before starting
  -N = start describing new interface

drivers:
  hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
(this can also be used with Linuxant DriverLoader)
  hermes = Agere Systems Inc. driver (Hermes-I/Hermes-II)
  madwifi = MADWIFI 802.11 support (Atheros, etc.)
  atmel = ATMEL AT76C5XXx (USB, PCMCIA)
  wext = Linux wireless extensions (generic)
  ndiswrapper = Linux ndiswrapper
  broadcom = Broadcom wl.o driver
  ipw = Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 or newer)
  wired = wpa_supplicant wired Ethernet driver
  bsd = BSD 802.11 support (Atheros, etc.)
  ndis = Windows NDIS driver

In most common cases, wpa_supplicant is started with

wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -iwlan0


    This makes the process fork into background and wait for the wlan0
interface if it is not available at startup time.
    The easiest way to debug problems, and to get debug log for bug
reports, is to start wpa_supplicant on foreground with debugging
enabled:
      wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d

    wpa_supplicant can control multiple interfaces (radios) either by
running one process for each interface separately or by running just
one process and list of options at command line. Each interface is
separated with -N argument. As an example, following command would
start wpa_supplicant for two interfaces:
    wpa_supplicant \
    -c wpa1.conf -i wlan0 -D hostap -N \
    -c wpa2.conf -i ath0 -D madwifi

    If the interface is added in a Linux bridge (e.g., br0), the bridge
interface needs to be configured to wpa_supplicant in addition to the
main interface:
      wpa_supplicant -cw.conf -Dmadwifi -iath0 -bbr0

3、结构体介绍

struct  wpa_interface      struct  wpa_params  
   
struct  wpa_global

    struct wpa_interface - Parameters for wpa_supplicant_add_iface().

    struct wpa_global - Internal, global data for all %wpa_supplicant interfaces.
This structure is initialized by calling wpa_supplicant_init() when starting %wpa_supplicant.

    struct wpa_params - Parameters for wpa_supplicant_init().

    wpa_params主要记录一些与网卡本身没关的参数设置,而wpa_interface对应网络接口,

因为wpa_supplicant支持多个网络接口,所以可能有多个wpa_interface结构体,可以通过命令行

指定不同的接口,wpa_supplicant在main函数开始的地方会进行遍历!(参考代码main.c)

struct wpa_global {
struct wpa_supplicant *ifaces;
struct wpa_params params;
struct ctrl_iface_global_priv *ctrl_iface;
struct ctrl_iface_dbus_priv *dbus_ctrl_iface;
};

struct wpa_supplicant - Internal data for wpa_supplicant interface.

每个网络接口都有一个对应的wpa_supplicant数据结构,该指针指向最近加入的一个,在wpa_supplicant数据结构中有指针指向next

struct ctrl_iface_global_priv - Global control interface

struct ctrl_iface_dbus_priv - DBUS control interface

4、理解main.c

在这个函数中,主要做了四件事。
    a. android平台进程wpa_supplicant权限及结构体初始化,解析命令行参数
    b. 调用wpa_supplicant_init()函数,主要初始化struct wpa_global *global这个局部结构体同时传递给static struct     eloop_data eloop这个全局结构体并返回这个局部结构体(详解见下)
    c. for循环中调用wpa_supplicant_add_iface()函数,注册可能有的一个或多个网卡接口
    d. 调用wpa_supplicant_run()函数,这其中如果失败将会走到out或者是通过goto跳转到out.

下面详细介绍这四个过程:

4.1 初步初始化及解析命令行参数

    最开始调用了os_program_init函数,来给wpa_supplicant进程分配权限,这里的进程一般是在init.rc中有个service,然后通过在wifi.c中的函数由UI settings设置通过jni调用下来从而会把service调用起来!跟踪这个函数到达了os_unix.c,见到了我们熟悉的setuid函数给它设为AID_WIFI(user / group).

    然后下面初始化两大结构体wpa_params和wpa_interface,再然后就开始解析命令行的参数了,这里不再详述了


4.2 wpa_supplicant_init(&params)

    我们先看下这个函数的说明:

/**
 * wpa_supplicant_init - Initialize %wpa_supplicant
 * @params: Parameters for %wpa_supplicant
 * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
 *
 * This function is used to initialize %wpa_supplicant. After successful
 * initialization, the returned data pointer can be used to add and remove
 * network interfaces, and eventually, to deinitialize %wpa_supplicant.
 */

    这个函数先分配了struct wpa_global *global这个局部指向结构体指针的内存空间,然后通过传递的params参数填充global指向的结构体中内嵌的struct wpa_params对象,紧接着把global这个指针传递给static
struct eloop_data  eloop这个全局结构体对象!

    下面分别调用global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global); /* ctrl_iface_unix.c */

    对于第一个接口的初始化,实际上通过socket进行了内部进程间通信,如下

priv->sock = android_get_control_socket(global->params.ctrl_interface);

 /* 此处通过getenv获得了sockfd(android平台),相当于如果本身有了fd的话,将直接跳转到havesock,如果没有的话,将创建连接,如下所示 */

priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0); /* PF_UNIX 代表内部进程间通信 */

下面bind或者connect,错误基本上也是goto到fail.到这里控制接口初始化结束.

    下面初始化第二个接口dbus

global->dbus_ctrl_iface = wpa_supplicant_dbus_ctrl_iface_init(global); / *初始化dbus控制接口ctrl_iface_dbus.c */

    再下面调用wpa_supplicant_daemon(global->params.pid_file)); 再调用os_daemonize函数写pid(os_unix.c) ,最后返回局部变量global,到此初始化过程结束了!


4.3 wpa_supplicant_add_iface(global, &ifaces[i])

    还是先看下这个函数注释:

/**
 * wpa_supplicant_add_iface - Add a new network interface
 * @global: Pointer to global data from wpa_supplicant_init()
 * @iface: Interface configuration options
 * Returns: Pointer to the created interface or %NULL on failure
 *
 * This function is used to add new network interfaces for %wpa_supplicant.
 * This can be called before wpa_supplicant_run() to add interfaces before the
 * main event loop has been started. In addition, new interfaces can be added
 * dynamically while %wpa_supplicant is already running. This could happen,
 * e.g., when a hotplug network adapter is inserted.
 */


a.分配struct wpa_supplicant *wpa_s局部指针空间

b.init iface and iface2

wpa_supplicant_init_iface(wpa_s, iface) || wpa_supplicant_init_iface2(wpa_s, global->params.wait_for_interface)

    这两个函数很重要,将调用到驱动,下面我们分析下这两个函数的调用过程

 b1) wpa_supplicant_init_iface

   b1.1)wpa_supplicant_set_driver(wpa_s, iface->driver)        

   
此函数很重要,调用过程如下所示

   
  wpa_s->driver = wpa_supplicant_drivers[i]; /* wpa_supplicant.c */

后者在drivers.c中 struct wpa_driver_ops *wpa_supplicant_drivers[ ] = { &wpa_driver_wext_ops,
NULL };

ops这个结构体对象注册了一系列wext(我们采用wext的驱动类型)相关的函数指针,从而提供了相应的驱动接口!同时android增加了

       #ifdef ANDROID
        .driver_cmd = wpa_driver_priv_driver_cmd,
        #endif

     b1.2) 读配置文件
    读取配置文件,并将其中的信息设置到wpa_supplicant数据结构中的conf 指针指向的数据结构,它是一个wpa_config类型

    命令行设置的控制接口ctrl_interface和驱动参数driver_param覆盖配置文件里设置,命令行中的优先;

 
  对 于网络配置块有两个链表描述它,一个是 config->ssid,它按照配置文件中的顺序依次挂载在这个链表上,还有一个是pssid,它是一个二级指针,指向一个指针数组,该指针数组 按照优先级从高到底的顺序依次保存wpa_ssid指针,相同优先级的在同一链表中挂载。

    wpa_s->conf = wpa_config_read(wpa_s->confname);  /*
此函数在wpa_supplicant.c中,而实现在conf_file.c中,这里内容比较多,没细看 */

     b1.3) 将函数传递的指向结构体wpa_interface的指针中的相关的ifname传递给指向wpa_supplicant结构体的指针,调用结束.


    b2) wpa_supplicant_init_iface2

      调用wpa_supplicant_init_eapol()函数来初始化eapol;(eapol 网上查了下意思是:局域网扩展协议,请高手指点下这个是做什么用的?)
      调用相应类型的driver的init()函数,我们的是wext;(即.init = wpa_driver_wext_init,在driver_wext.c)

	/* RSNA Supplicant Key Management - INITIALIZE */
	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);

	/* Initialize driver interface and register driver event handler before
	 * L2 receive handler so that association events are processed before
	 * EAPOL-Key packets if both become available for the same select()
	 * call. */
	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);

/* driver_ops 调用方式都和下面的类似 */

static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s,
 const char *ifname)
{
    if (wpa_s->driver->init) {
        return wpa_s->driver->init(wpa_s, ifname);
    }
    return NULL;
}

      设置driver的param参数;(即.set_param = wpa_driver_wext_set_param)
      调用wpa_drv_get_ifname()函数获得网络接口的名称,对于wext类型的driver,没有这个接口函数(忽略它)
      调用wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)函数来初始化struct wpa_sm *wpa,并做相应的初始化工作;

static int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_WPA
	struct wpa_sm_ctx *ctx;
	ctx = os_zalloc(sizeof(*ctx));
	if (ctx == NULL) {
		wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
		return -1;
	}

	ctx->ctx = wpa_s;
	ctx->set_state = _wpa_supplicant_set_state;
	ctx->get_state = _wpa_supplicant_get_state;
	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
	ctx->disassociate = _wpa_supplicant_disassociate;
	ctx->set_key = wpa_supplicant_set_key;
	ctx->scan = wpa_supplicant_scan;
	ctx->get_ssid = _wpa_supplicant_get_ssid;
	ctx->get_bssid = wpa_supplicant_get_bssid;
	ctx->ether_send = _wpa_ether_send;
	ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
	ctx->alloc_eapol = _wpa_alloc_eapol;
	ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
	ctx->add_pmkid = wpa_supplicant_add_pmkid;
	ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
	ctx->set_config_blob = wpa_supplicant_set_config_blob;
	ctx->get_config_blob = wpa_supplicant_get_config_blob;
	ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;

	wpa_s->wpa = wpa_sm_init(ctx);
	if (wpa_s->wpa == NULL) {
		wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
			   "machine");
		return -1;
	}
#endif /* CONFIG_NO_WPA */

	return 0;
}

上面这些函数指针,目前还不太理解,希望高手可以补充?

      调用wpa_supplicant_driver_init()函数,来初始化driver接口参数,如下所示:

/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095)
 * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the
 * parameter that is being set/get to; value will be read/written to
 * struct iw_param value field) */
#define IW_AUTH_WPA_VERSION		0
#define IW_AUTH_CIPHER_PAIRWISE		1
#define IW_AUTH_CIPHER_GROUP		2
#define IW_AUTH_KEY_MGMT		3
#define IW_AUTH_TKIP_COUNTERMEASURES	4
#define IW_AUTH_DROP_UNENCRYPTED	5
#define IW_AUTH_80211_AUTH_ALG		6
#define IW_AUTH_WPA_ENABLED		7
#define IW_AUTH_RX_UNENCRYPTED_EAPOL	8
#define IW_AUTH_ROAMING_CONTROL		9
#define IW_AUTH_PRIVACY_INVOKED		10

/**
 * wpa_supplicant_driver_init - Initialize driver interface parameters
 * @wpa_s: Pointer to wpa_supplicant data
 * @wait_for_interface: 0 = do not wait for the interface (reports a failure if
 * the interface is not present), 1 = wait until the interface is available
 * Returns: 0 on success, -1 on failure
 *
 * This function is called to initialize driver interface parameters.
 * wpa_drv_init() must have been called before this function to initialize the
 * driver interface.
 */
int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
			       int wait_for_interface)
{
	static int interface_count = 0;

	for (;;) {
		if (wpa_s->driver->send_eapol) {
			const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
			if (addr)
				os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
			break;
		}
		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);
		if (wpa_s->l2)
			break;
		else if (!wait_for_interface)
			return -1;
		wpa_printf(MSG_DEBUG, "Waiting for interface..");
		os_sleep(5, 0);
	}

	if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
		wpa_printf(MSG_ERROR, "Failed to get own L2 address");
		return -1;
	}

	wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR,
		   MAC2STR(wpa_s->own_addr));

	if (wpa_s->bridge_ifname[0]) {
		wpa_printf(MSG_DEBUG, "Receiving packets from bridge interface"
			   " '%s'", wpa_s->bridge_ifname);
		wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
					      wpa_s->own_addr,
					      ETH_P_EAPOL,
					      wpa_supplicant_rx_eapol, wpa_s,
					      0);
		if (wpa_s->l2_br == NULL) {
			wpa_printf(MSG_ERROR, "Failed to open l2_packet "
				   "connection for the bridge interface '%s'",
				   wpa_s->bridge_ifname);
			return -1;
		}
	}

	/* Backwards compatibility call to set_wpa() handler. This is called
	 * only just after init and just before deinit, so these handler can be
	 * used to implement same functionality. */
	if (wpa_drv_set_wpa(wpa_s, 1) < 0) {
		struct wpa_driver_capa capa;
		if (wpa_drv_get_capa(wpa_s, &capa) < 0 ||
		    !(capa.flags & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
				    WPA_DRIVER_CAPA_KEY_MGMT_WPA2))) {
			wpa_printf(MSG_DEBUG, "Driver does not support WPA.");
			/* Continue to allow non-WPA modes to be used. */
		} else {
			wpa_printf(MSG_ERROR, "Failed to enable WPA in the "
				"driver.");
			return -1;
		}
	}

	wpa_clear_keys(wpa_s, NULL); 
        // 几个ioctl调用都是调用ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr)
        // #define SIOCSIWAUTH	0x8B32		
        /* set authentication mode params */
        // 根据上面的宏通过iwr这个参数传递给内核相应的get / set



	/* Make sure that TKIP countermeasures are not left enabled (could
	 * happen if wpa_supplicant is killed during countermeasures. */
	wpa_drv_set_countermeasures(wpa_s, 0); 

	wpa_drv_set_drop_unencrypted(wpa_s, 1);

	wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
	wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
	interface_count++;

	return 0;
}

在该函数的最后会
      wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
      wpa_supplicant_req_scan(wpa_s, interface_count, 100000); 来主动发起scan,这个地方刚刚开始一直没能理解清楚如何去scan,然后又是如何终止的,后来发现其实就是用了signal的方式来处理,下面是run scan的过程,代码封装的相当好,真正的执行是在最后一个wpa_supplicant_run函数!

/**
 * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
 * @wpa_s: Pointer to wpa_supplicant data
 * @sec: Number of seconds after which to scan
 * @usec: Number of microseconds after which to scan
 *
 * This function is used to schedule a scan for neighboring access points after
 * the specified time.
 */
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
	wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
		sec, usec);
	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
	eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
}

		/* check if some registered timeouts have occurred */
		if (eloop.timeout) {
			struct eloop_timeout *tmp;

			os_get_time(&now);
			if (!os_time_before(&now, &eloop.timeout->time)) {
				tmp = eloop.timeout;
				eloop.timeout = eloop.timeout->next;
				tmp->handler(tmp->eloop_data,
					     tmp->user_data);
				os_free(tmp);
			}

		}

这样这个wpa_supplicant_driver_init(wpa_s, wait_for_interface)函数就说完了!

 下面再调用wpa_supplicant_ctrl_iface_init()函数,来初始化控制接口;对于UNIX SOCKET这种方式,其本地socket文件是由配置文件里的
    ctrl_interface参数指定的路径加上网络接口名称;

	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);

	wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
	if (wpa_s->ctrl_iface == NULL) {
		wpa_printf(MSG_ERROR,
			   "Failed to initialize control interface '%s'.\n"
			   "You may have another wpa_supplicant process "
			   "already running or the file was\n"
			   "left by an unclean termination of wpa_supplicant "
			   "in which case you will need\n"
			   "to manually remove this file before starting "
			   "wpa_supplicant again.\n",
			   wpa_s->conf->ctrl_interface);
		return -1;
	}

这个函数的错误信息,我调试中有遇到过,确实是有多个进程的时候会报。

这样就讲完了这个牛逼函数,下面就是注册dbus,不再详解了,看代码:

	wpa_s->global = global;

	/* Register the interface with the dbus control interface */
	if (wpas_dbus_register_iface(wpa_s)) {
		wpa_supplicant_deinit_iface(wpa_s);
		os_free(wpa_s);
		return NULL;
	}
#ifdef ANDROID
	char scan_prop[PROPERTY_VALUE_MAX];
	char *endp;
	if (property_get("wifi.supplicant_scan_interval", scan_prop, "5") != 0) {
		wpa_s->scan_interval = (int)strtol(scan_prop, &endp, 0);
		if (endp == scan_prop) {
			wpa_s->scan_interval = 5;
		}
	}
#endif
	wpa_s->next = global->ifaces;
	global->ifaces = wpa_s;

	wpa_printf(MSG_DEBUG, "Added interface %s", wpa_s->ifname);

	return wpa_s;

再下面就是把结果该传递的传递,该返回的返回,最后return,下面就到wpa_supplicant_run函数了!


4.4 wpa_supplicant_run()函数

初始化完成之后,让wpa_supplicant的main event loop run起来。
在 wpa_supplicant中,有许多与外界通信的socket,它们都是需要注册到eloop event模块中的,具体地说,就是在eloop_sock_table中增加一项记录,其中包括了sock_fd, handle, eloop_data, user_data。
eloop event模块就是将这些socket组织起来,统一管理,然后在eloop_run中利用select机制来管理socket的通信。

/**
 * wpa_supplicant_run - Run the %wpa_supplicant main event loop
 * @global: Pointer to global data from wpa_supplicant_init()
 * Returns: 0 after successful event loop run, -1 on failure
 *
 * This function starts the main event loop and continues running as long as
 * there are any remaining events. In most cases, this function is running as
 * long as the %wpa_supplicant process in still in use.
 */
int wpa_supplicant_run(struct wpa_global *global)
{
	struct wpa_supplicant *wpa_s;

	if (!global->params.wait_for_interface && global->params.daemonize &&
	    wpa_supplicant_daemon(global->params.pid_file))
		return -1;

	if (global->params.wait_for_monitor) {
		for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
			if (wpa_s->ctrl_iface)
				wpa_supplicant_ctrl_iface_wait(
					wpa_s->ctrl_iface);
	}

	eloop_register_signal_terminate(wpa_supplicant_terminate, NULL);
	eloop_register_signal_reconfig(wpa_supplicant_reconfig, NULL);

	eloop_run();

	return 0;
}

这个地方的真正执行过程还没理解清楚,只能以后有时间再理解了!

wpa_supplicant
的对外接口分析

对于wpa_supplicant模块的对外接口,主要有以下几种:
5.1. global control interface: 用于配置(增加或删除)网络接口。
5.2. ctrl interface: 与其他外部模块交互的控制接口。

例 如,在初始化时,android 平台的wifi.c中的 wifi_connect_to_supplicant函数调用wpa_ctrl_open函数创建两个socket,一个是ctrl interface,另一个就是monitor interface,monitor interface这个接口用于监测从wpa_supplicant发出的event事件。

这两个socket创建成功后,monitor interface 会发送ATTACH到wpa_supplicant模块,wpa_supplicant模块收到后,会将该客户端的socket信息记录下来,用于以后发送事件时用(由于用的是DGRAM的方式)。
5.3. socket for ioctl: 发送命令到kernel space。
5.4. socket (netlink) for interact between kernel and userspace(AF_NETLINK, NETLINK_ROUTE): 接受kernel发送上来的event。
5.5. socket for l2 packet(PF_PACKET): 处理802.1x报文。




抱歉!评论已关闭.