Android wpa_supplicant源码分析--启动之全局初始化

1. wpa_supplicant简介

wpa_supplicant是用来用来支持无线中各种加密方式的,包括WEP、WPA/WPA2和WAPI(中国特有)、EAP(8021x)。wpa_s通过socket与上层(framework)和底层(driver)通信,向上接收命令和传递当前状态,向下发送命令到驱动并接收驱动上传的各种event,严格来讲wap_s和driver中还有一层cfg80211,cfg80211可以理解为linux定义的80211管理控制层的框架,例如扫描、连接这些通用的过程,各个厂商按照cfg80211提供的框架编写各自的驱动,实现具体的帧发送与接收。wpa_s是如何处理各个socket中数据的请看 eloop sun章节。
下图是网页(http://zwz94.blog.163.com/blog/static/3206039520120149580531/)上的一张图片,可以清晰的看到wpa_s早整个wifi架构中的位置
Android wpa_supplicant源码分析--启动之全局初始化_第1张图片

2. wpa_supplicant的启动

在Android手机中,wpa_supplicant的启动是由framework控制的,frameowork设置property来启动写在init rc文件的中service, 同时会生成两条socket,一条向wpa_s发送命令,一条接收wpa_s上传的event

service p2p_supplicant /system/bin/wpa_supplicant \
    -ip2p0 -Dnl80211 -c/data/misc/wifi/p2p_supplicant.conf \
    -I/system/etc/wifi/p2p_supplicant_overlay.conf -N \
    -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \
    -I/system/etc/wifi/wpa_supplicant_overlay.conf \
    -O/data/misc/wifi/sockets -puse_p2p_group_interface=1 -dd \
    -e/data/misc/wifi/entropy.bin -g@android:wpa_wlan0
    class main
    socket wpa_wlan0 dgram 660 wifi wifi
    disabled
    oneshot

其中 socket wpa_wlan0 dgram 660 wifi wifi创建了一个socket,wpa_s使用该socket接收framework的命令和向上传递event。framework同样会调用连接该socket,后面会讲到

3. wpa_supplicant启动参数

wpa_s允许传入很多参数, 参数区分大小写
参数一共有3中类型,

3.1 不带后续内容的参数

有 –BdhKLqstuvW
-h:帮助文件
-L:输出license
-q:提升wpa_s调试级别(输出log减少),与-d相反
-v:输出wpa_s版本号
-W:等到control interface monitor再运行
-N:当需要设置两个network interface时,需要在两个网口参数中间插入 –N, 例如 一个网口为p2p0,需要插入-N后,再新添加另一个wlan0
wpa_supplicant通过为每一个网络接口设置不同的参数的方式,来实现对多网卡的支持。

3.2 带后续内容的全局参数

结构体 wpa_params在调用 wpa_supplicant_init() 初始化wpa_s使用,控制wpa_s运行

struct wpa_params {
    //-B:当做守护进程运行在后台
    int daemonize;
    //-W:等到control interface monitor再运行
    int wait_for_monitor;
    //-P: pid_file - Path to a PID (process ID) file
    char *pid_file;

    //-d:输出log的级别,-d为默认级别,-dd级别降低一级(输出log会增加一级),依次类推,设置代码为params.wpa_debug_level
    int wpa_debug_level;
    //-K:在log中打印key
    int wpa_debug_show_keys;
    //-t:调试信息中增加时间戳
    int wpa_debug_timestamp;

    //ctrl_interface - Global ctrl_iface path/parameter
    //-g:global ctrl_interface(字符串为@android+SOCK_NAME, SOCK_NAME是由init.rc)
    char *ctrl_interface;
    //ctrl_interface_group - Global ctrl_iface group
    //-G:global ctrl_interface group
    char *ctrl_interface_group;

    //-u:支持dbus控制接口
    int dbus_ctrl_interface;
    //-f:将log输出到file中
    const char *wpa_debug_file_path;
    //-s:输出log到 syslog, 默认输出到stdout
    int wpa_debug_syslog;

    //-T:log增加linux trace
    int wpa_debug_tracing;
    //-o:设置linux网口的目录
    char *override_driver;
    //-O:设置wpa_s控制sockets的目录
    char *override_ctrl_interface;
    //-e:entropy_file - Optional entropy file
    char *entropy_file;
};

3.3 带后续内容的网络接口参数

存放到结构体 struct wpa_interface 中,运行wpa_supplicant_add_iface()需要传入该结构体

struct wpa_interface {
    //-c:conf配置文件,里面定义了一些参数和一些network节点,一般为wpa_supplicant.conf
    const char *confname;
    //-I:conf配置文件的补充选项,一般为wpa_supplicant_overlay.conf/
    const char *confanother;
    //-m:p2p网口的配置文件
    const char *conf_p2p_dev;
    //-C:控制端口socket的参数
    //功能等同conf 文件
    const char *ctrl_interface;
    //-D:driver的类型,可以设置多个,例如 nl80211,wext
    const char *driver;

    //driver_param - Driver interface parameters
    const char *driver_param;
    //-i:linux的网口,可以定义多个,例如wlan0
    const char *ifname;
    //-b:桥接的interface
    const char *bridge_ifname;

    //p2p_mgmt - Interface used for P2P management (P2P Device operations)
    int p2p_mgmt;
};

4. wpa_supplicant全局初始化

主要包括 EAP各种方法的注册,eloop(wpa_s运行的主体)参数,与framework通信socket的初始化

struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
{
    //全局信息,params中的内容都会拷贝到该结构体中
    struct wpa_global *global;

    //初始化eap方法,每种eap方式都有对应的方法
    ret = eap_register_methods();

    //将params中的信息复制到global中
    global = os_zalloc(sizeof(*global));

    //初始化 struct eloop_data,该结构体是个全局变量
    if (eloop_init()) 

    random_init(params->entropy_file);

    //连接与FWKS通信socket(init.rc中定义的),并注册接收cmd的函数
    global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
    {
        //初始化控制socket
        wpas_global_ctrl_iface_open_sock(global, priv) < 0)
        {   
            //获取-g传进来的socket名称,与init.rc中相对应
            os_strncmp(ctrl, "@android:", 9) == 0) {
                priv->sock = android_get_control_socket(ctrl + 9);
            //注册接收socket数据的函数,分发处理传入的命令
            eloop_register_read_sock(priv->sock, wpa_supplicant_global_ctrl_iface_receive, global, priv);   
            //注册发送event到FWKS的函数wpa_supplicant_ctrl_iface_send
            wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
        }
    }
    return global;
}

下图是简易的全局初始化过程
Android wpa_supplicant源码分析--启动之全局初始化_第2张图片

wpa_supplicant_global_ctrl_iface_receive()可以接受两类命令,接口命令和全局命令。一类命令前面有“IFNAME= ”指明处理该命令的接口,然后调用每个接口对应的 wpa_supplicant_ctrl_iface_process()来进行相应处理。另一类未指定接口,由wpa_supplicant_global_ctrl_iface_process()直接处理。

5 Framework与wpa_supplicant通信

framework新建了两条socket,并与init rc中的socket相关联,一条用于发送CMD,一条用接收event
代码在wifi.c中。

//path 内容为"@android:wpa_wlan0", wpa_wlan0是由init.rc启动的socket
int wifi_connect_on_socket_path(const char *path)
{
    ctrl_conn = wpa_ctrl_open(path);
    monitor_conn = wpa_ctrl_open(path);
}

在该函数中会调用wpa_ctrl_open()在wpa_s中,具体操作如下

static struct wpa_ctrl *ctrl_conn = wpa_ctrl_open(path);
{
    //新建一个UNIX域的socket
    struct wpa_ctrl *ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);

    //socket与文件系统的地址绑定,就是手机目录下的 /data/misc/wifi/sockets
    os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), CONFIG_CTRL_IFACE_CLIENT_DIR "/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d", (int) getpid(), counter);

    bind(ctrl->s, (struct sockaddr *) &ctrl->local, sizeof(ctrl->local))

    //将新创建的socket和init.rc启动的socket连接起来
    socket_local_client_connect( ctrl->s, ctrl_path + 9, NDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM)
}

wifi_send_command()用于向wpa_s发送命令
wifi_wait_on_socket()接收wpa_s向上传递的event
Android wpa_supplicant源码分析--启动之全局初始化_第3张图片

你可能感兴趣的:(Android,WiFi)