Android Wi-Fi源码分析之wpa_supplicant初始化(一)

一. wpa_supplicant配置编译

将对应的平台的wpa_supplicant包解压改名为wpa_supplicant_8替换掉external下的wpa_supplicant_8目录
执行:
source build/envsetup.sh
lunch qiyang_6dq-user

根据平台定制所需要的wpa_supplican版本,
修改: BoardConfig.mk指明wpa_supplicant_8;指明所使用的驱动;指明wlan芯片对应的静态库
执行:
mmm hardware/Broadcom/wlan/bcmdhd/ wpa_supplicant_8_lib/
mmm external/wpa_supplicant_8
执行完之后把编译好的wpa_supplican放入目标板并设置权限为可执行.
结语: 除了修改BoardConfig.mk外, wpa_supplicant也定义了自己的android.config. 严格来说, android.cfg应该是唯一的编译控制文件. 但由于wlan芯片不同, wpa_supplicant可能还依赖其它模块.
Anadroid系统中, wpa_supplicant启动是通过 “setprop ctrl.start wpa_supplicant” 来触发init进程去fork一个子进程来完成的. wpa_supplicant在init配置文件中定义为一个service.
路径:qiyang-android442\device\fsl\qiyang_6dq\init.rc

service wpa_supplicant /system/bin/wpa_supplicant \
    -iwlan0 -Dnl80211 -c/data/misc/wifi/wpa_supplicant.conf \

最重要的是通过”-c” 参数指定的wpa_supplicant启动配置文件, 该配置文件路径名为/data/misc/wifi/wpa_supplicant.conf .
wpa_supplicant源代码中包含一个启动配置文件的模板, 该文件路径为:external/wpa_supplicant_8/wpa_supplicant/wpa_supplicant.conf

network={
    ssid="example"
    proto=RSN
    key_mgmt=WPA-EAP
    pairwise=CCMP TKIP
    group=CCMP TKIP
    eap=TLS
    identity="user@example.com"
    ca_cert="/etc/cert/ca.pem"
    client_cert="/etc/cert/user.pem"
    private_key="/etc/cert/user.prv"
    private_key_passwd="password"
    priority=1
}

其中:
ctrl_interface=/var/run/wpa_supplicant 指明了控制接口unix域socket的文件名.

二. main函数分析

Android平台中, main函数定义于main.c中.

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;

    /* Android平台中, 下面这个函数的实现在os_unix.c中. Android对其做了一些修改, * 主要是权限方面的设置防止某些情况下被破解者利用权限漏洞以获得root权限. */
    if (os_program_init())
        return -1;

    os_memset(&params, 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;
    /*关键函数1:根据传入的参数,创建并初始化一个wpa_global对象*/
    global = wpa_supplicant_init(&params);
    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;
        }
        /* 关键函数2:wpa_supplicant支持操作多个无线网络设备,此处将它们一一添加到 * wpa_supplicant中, wpa_supplicant内部将初始化这些设备*/
        wpa_s = wpa_supplicant_add_iface(global, &ifaces[i]);
        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 */
    }

    /*Android平台中, wpa_supplicant通过select或epoll方式实现多路I/O复用*/
    if (exitcode == 0)
        exitcode = wpa_supplicant_run(global);

    wpa_supplicant_deinit(global);

out:
    wpa_supplicant_fd_workaround(0);
    os_free(ifaces);
    os_free(params.pid_file);

os_program_deinit();

return exitcode;
}   

三. wpa_supplicant_init函数分析

路径:external/wpa_supplicant_8/wpa_supplicant/wpa_supplicant.c

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
    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();/*1. 注册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));/*创建一个wpa_global对象*/
    if (global == NULL)
        return NULL;

    /*初始化global中的其它参数*/
    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);
    /*2. 初始化事件循环机制*/
    if (eloop_init()) {
        wpa_printf(MSG_ERROR, "Failed to initialize event loop");
        wpa_supplicant_deinit(global);
        return NULL;
    }

    /*初始化随机数相关资源, 用于提升后续随机数生成的随机性*/
    random_init(params->entropy_file);

    /*初始化全局控制接口对象. */
    global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
    if (global->ctrl_iface == NULL) {
        wpa_supplicant_deinit(global);
        return NULL;
    }

    /*初始化通知机制相关资源, 它和dbus有关.*/
    if (wpas_notify_supplicant_initialized(global)) {
        wpa_supplicant_deinit(global);
        return NULL;
    }

    /*wpa_drivers是全局变量*/
    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; } /*分配全局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事件循环机制以及设置消息全局回调函数.这里的回调函数有两个.:
wpa_msg_get_ifname_func: 某些输出信息中需要打印出网卡接口名. 该回调函数用于获取网卡接口名.
wpa_msg_cb_func:特殊处理, 把输出信息发给客户端进行处理.

1. wpa_debug.c分析

void wpa_msg_register_cb(wpa_msg_cb_func func)
{
    wpa_msg_cb = func;/*wpa_msg_cb的实现函数是wpa_supplicant_ctrl_ifname_msg_cb, 他将输出信息发送给客户端*/
}


static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;/*wpa_msg_ifname_cb用于获取无线网卡接口;wpa_supplicant的实现函数为wpa_supplicant_msg_ifname_cb*/

void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func)
{
    wpa_msg_ifname_cb = func;
}

后面再来看wpa_supplicant_init中列出的三个关键点.

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/u013256622/article/details/72900828
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞