玩转「Wi-Fi」系列之wpa_supplicant - main分析(九)

命令启动

wpa_supplicnt 一般通过如下参数进行启动:

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

其中比较主要的是-c参数, 指定启动配置文件。配置文件的模板路径为 wpa_supplicant/wpa_supplicant.conf官网有对该文件参数的详细描述 。

主要的参数含义:

  • ctrl_interface=/var/run/wpa_supplicant : 控制接口unix socket 文件名
  • update_config=1 运行过程中服务端wpa_supplicant修改了配置信息,需要重新更新配置文件信息
  • priority 网络连接优先级
  • ap_scan=1 AP扫描/选择,默认情况下,wpa_supplicant请求驱动程序执行AP扫描,然后
    使用扫描结果选择合适的AP。 ap_scan = 1是使用nl80211进行优化的工作。
    为了找到使用隐藏SSID的网络,网络块中的scan_ssid = 1可以
    与nl80211一起使用。
  • network 选项, 配网成功之后,配置文件中会有一个network选项, 包括SSID,PSK,KEY 等信息
network={
    ssid="simple"
    psk="very secret passphrase"
    priority=5
}

分析完命令的启动参数,下面进入命令的源码的分析,一步一步剖析, 入口函数: main

main函数

int main(int argc, char *argv[])
{
    int c, i;
    // 重要的数据结构1 
    struct wpa_interface *ifaces, *iface;
    int iface_count, exitcode = -1;
    struct wpa_params params;
    // 重要的数据结构2
    struct wpa_global *global;

    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;

    //输入输出重定向到/dev/null 
    wpa_supplicant_fd_workaround(1);

    //参数解析
    for (;;) {
        c = getopt(argc, argv,
               "b:Bc:C:D:de:f:g:G:hi:I:KLMm:No:O:p:P:qsTtuvW");
        if (c < 0)
            break;
        switch (c) {
        ... 
        // -c 指定的配置文件wpa_supplicant.conf 
        case 'c':
            iface->confname = optarg;
            break;
        ... 
        // -D 驱动名称
        case 'D':
            iface->driver = optarg;
            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;
        ... 
        //网络接口名称
        case 'i':
            iface->ifname = optarg;
            break;

        default:
            usage();
            exitcode = 0;
            goto out;
        }
    }
    exitcode = 0;
    //主要函数1 : 创建并初始化一个global 
    global = wpa_supplicant_init(&params);
    // fst 初始化
    fst_global_init()
#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
    if (!fst_global_add_ctrl(fst_ctrl_cli))
        wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
#endif
    for (i = 0; exitcode == 0 && i < iface_count; i++) {
        struct wpa_supplicant *wpa_s;
        // 主要函数2 : 支持多个无线网络设备,
        wpa_s = wpa_supplicant_add_iface(global, &ifaces[i], NULL);
    }

#ifdef CONFIG_MATCH_IFACE
    if (exitcode == 0)
        exitcode = wpa_supplicant_init_match(global);
#endif /* CONFIG_MATCH_IFACE */

    // 启动, wpa_supplicant 通过epoll 方式实现多路I/O复用
    if (exitcode == 0)
        exitcode = wpa_supplicant_run(global);

    // 释放相关资源 
    wpa_supplicant_deinit(global);

    fst_global_deinit();

out:
    wpa_supplicant_fd_workaround(0);
    os_free(ifaces);
#ifdef CONFIG_MATCH_IFACE
    os_free(params.match_ifaces);
#endif /* CONFIG_MATCH_IFACE */
    os_free(params.pid_file);

    os_program_deinit();

    return exitcode;
}

main 函数中出现的几个重要的数据接口和主要函数做进一步分析 :

首先看下wpa_interface数据接口,每个变量名有相应的注释,比较好明白意思

数据结构 wpa_interface
/**
 * struct wpa_interface - Parameters for wpa_supplicant_add_iface()
 */
struct wpa_interface {
    /**
     * confname - Configuration name (file or profile) name
     *
     * This can also be %NULL when a configuration file is not used. In
     * that case, ctrl_interface must be set to allow the interface to be
     * configured.
     */
     // 配置文件名,也就是-c 指定的wpa_supplicant.conf
    const char *confname;

    /**
     * confanother - Additional configuration name (file or profile) name
     *
     * This can also be %NULL when the additional configuration file is not
     * used.
     */
    const char *confanother;

    /**
     * ctrl_interface - Control interface parameter
     *
     * If a configuration file is not used, this variable can be used to
     * set the ctrl_interface parameter that would have otherwise been read
     * from the configuration file. If both confname and ctrl_interface are
     * set, ctrl_interface is used to override the value from configuration
     * file.
     */
     // 控制接口unix socket 地址,配置文件中ctrl_interface指定的
    const char *ctrl_interface;

    /**
     * driver - Driver interface name, or %NULL to use the default driver
     */
     //驱动接口,代表nl80211
    const char *driver;

    /**
     * driver_param - Driver interface parameters
     *
     * If a configuration file is not used, this variable can be used to
     * set the driver_param parameters that would have otherwise been read
     * from the configuration file. If both confname and driver_param are
     * set, driver_param is used to override the value from configuration
     * file.
     */
    const char *driver_param;

    /**
     * ifname - Interface name
     */
     //网络接口设备,代表wlan0 
    const char *ifname;

    /**
     * bridge_ifname - Optional bridge interface name
     *
     * If the driver interface (ifname) is included in a Linux bridge
     * device, the bridge interface may need to be used for receiving EAPOL
     * frames. This can be enabled by setting this variable to enable
     * receiving of EAPOL frames from an additional interface.
     */
    const char *bridge_ifname;

    /**
     * p2p_mgmt - Interface used for P2P management (P2P Device operations)
     *
     * Indicates whether wpas_p2p_init() must be called for this interface.
     * This is used only when the driver supports a dedicated P2P Device
     * interface that is not a network interface.
     */
    int p2p_mgmt;
};
数据结构 wpa_global
/**
 * 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_global {
    //核心数据结构
    struct wpa_supplicant *ifaces; 
    //运行时参数 
    struct wpa_params params;
    //全局控制接口
    struct ctrl_iface_global_priv *ctrl_iface;
    //dbug通信, 暂时用不到 
    struct wpas_dbus_priv *dbus;
    struct wpas_binder_priv *binder;
    //driver wrapper上下文信息 
    void **drv_priv;
    //driver wrapper个数
    size_t drv_count;
    struct os_time suspend_time;
    struct p2p_data *p2p;
    struct wpa_supplicant *p2p_init_wpa_s;
    struct wpa_supplicant *p2p_group_formation;
    struct wpa_supplicant *p2p_invite_group;
    u8 p2p_dev_addr[ETH_ALEN];
    struct os_reltime p2p_go_wait_client;
    struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
    struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
    int p2p_disabled;
    int cross_connection;
    struct wpa_freq_range_list p2p_disallow_freq;
    struct wpa_freq_range_list p2p_go_avoid_freq;
    enum wpa_conc_pref {
        WPA_CONC_PREF_NOT_SET,
        WPA_CONC_PREF_STA,
        WPA_CONC_PREF_P2P
    } conc_pref;
    unsigned int p2p_per_sta_psk:1;
    unsigned int p2p_fail_on_wps_complete:1;
    unsigned int p2p_24ghz_social_channels:1;
    unsigned int pending_p2ps_group:1;
    unsigned int pending_group_iface_for_p2ps:1;
    unsigned int pending_p2ps_group_freq;

#ifdef CONFIG_WIFI_DISPLAY
    int wifi_display;
#define MAX_WFD_SUBELEMS 10
    struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
#endif /* CONFIG_WIFI_DISPLAY */

    struct psk_list_entry *add_psk; /* From group formation */
};
  • wpa_global 的一个全局性质的上下文信息,它通过iface变量指向一个wpa_supplicant对象。

  • drv_priv 包含driver wrapper 所需要全局上下文信息。其中drv_conut 代表当前编译到系统中driver wrapper的个数

  • wpa_supplciant属于核心数据结构,一个interface 对应有一个wpa_supplicant 对象,系统中所有wpa_supplicant对象都通过next变量链接在一起, 内部还有很多的成员变量,后续分析中会做详细介绍。

下一篇文章会继续针对关键函数wpa_supplicant_init 进行分析。

猜你喜欢

转载自blog.csdn.net/z2066411585/article/details/80809078