Android wpa_supplcant 启动之--网络接口初始化

  1. wpa_supplicant结构体与网络接口

在手机adb中运行 netcfg或者ifconfig可以看到相关的网络接口的ip,掩码,mac地址等信息

Wpa_supplicant为每个网络接口都分配了一个struct wpa_supplicant, 该结构体存储了一些必要信息例如 struct dl_list bss(扫描结果); struct wpa_config *conf(配置文件)等等。

每一个网络接口的扫描,连接等操作都是通过struct wpa_supplicant中定义的相关函数和数据来实现的。下面是结构体中一些重要的元素介绍

struct wpa_supplicant{
    //接口的名字和mac地址
    unsigned char own_addr[ETH_ALEN];
    char ifname[100];

    /**************************************/    

    //外部控制wpa_s的socket
    struct ctrl_iface_priv *ctrl_iface;

    //网络接口当前的状态,断开/关联/连接的bssid ssid等
    enum wpa_states wpa_state;
    u8 bssid[ETH_ALEN];
    u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
                     * field contains the target BSSID. */
    int reassociate; /* reassociation requested */
    int disconnected; /* all connections disabled; i.e., do no reassociate
               * before this has been cleared */
    struct wpa_ssid *current_ssid;
    struct wpa_bss *current_bss;
    int ap_ies_from_associnfo;
    unsigned int assoc_freq;

    //是否支持2.4G/5G
    enum { WPA_SETBAND_AUTO, WPA_SETBAND_5G, WPA_SETBAND_2G } setband;

    /**************************************/

    //配置文件
    struct wpa_config *conf;
    //配置文件中的ESS网络的信息
    /* Selected configuration (based on Beacon/ProbeResp WPA IE) */
    int pairwise_cipher;
    int group_cipher;
    int key_mgmt;
    int wpa_proto;
    int mgmt_group_cipher;

    /**************************************/

    //扫描结果的处理,每次扫描后的结果都会做相应的更新
    void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
                 struct wpa_scan_results *scan_res);
    struct dl_list bss; /* struct wpa_bss::list */
    struct dl_list bss_id; /* struct wpa_bss::list_id */
    size_t num_bss;
    unsigned int bss_update_idx;
    unsigned int bss_next_id;
    //黑名单
    struct wpa_blacklist *blacklist;

    /**************************************/

    //底层相关,驱动的操作函数
    struct wpa_driver_ops *driver;
    int interface_removed; /* whether the network interface has been removed */
    void *drv_priv; /* private data used by driver_ops */
    void *global_drv_priv;

    //用来处理密钥相关netlink socket和处理方法
    struct l2_packet_data *l2;
    struct l2_packet_data *l2_br;

    /**************************************/

    //扫描相关的一些信息
    struct wpa_radio_work *scan_work;
    int scanning;
    int sched_scanning;
    struct os_reltime scan_trigger_time, scan_start_time;
    int scan_runs; /* number of scan runs since WPS was started */
    int *next_scan_freqs;
    int scan_interval; /* time in sec between scans to find suitable AP */
    int normal_scans; /* normal scans run before sched_scan */
    int scan_for_connection; /* whether the scan request was triggered for
                  * finding a connection */

    //sched_scan
    struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */
    int sched_scan_timeout;
    int sched_scan_interval;
    int first_sched_scan;
    int sched_scan_timed_out;

    //pno扫描
    int pno;
    int pno_sched_pending;
}
  1. 初始化网络接口配置

在wpa_s的main()函数中,进行完全局初始化后,会调用 wpa_supplicant_add_iface(),为wpa_s运行时传入的每个网络接口分配wpa_supplicant结构体,并进行相应的初始化

struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
                         struct wpa_interface *iface)
{
    struct wpa_supplicant *wpa_s = wpa_supplicant_alloc();
    wpa_s->global = global;

    //网络接口的初始化,与底层通信的socket,密钥数据包的socket,wpa_s的初始状态等
    if (wpa_supplicant_init_iface(wpa_s, &t_iface))
    {

        //读取两个conf配置文件
        //wpa_s允许提供两个配置文件,一个是原始的一个overlay,在overlay中的文件可以重新一些参数的值
        wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
        wpa_config_read(wpa_s->confanother, wpa_s->conf);

        //初始化驱动接口,并注册接收驱动event的函数 nl80211
        if (wpas_init_driver(wpa_s, iface) < 0)
        {
            //根据传进来的-inl80211选定对应的wpa_driver_ops(driver_nl80211.c),里面定义了驱动的操作方法,同时调用对应的global_init()进行初始化
            if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
            ...
  1. 列表内容

驱动初始化

下一步是初始化相关驱动的操作参数和与驱动通信的socket

wpa_supplicant支持多种架构的驱动,Android中多使用的是nl80211架构,相关操作函数在文件drivers_ml80211.c中

//根据名称选择网络ops,创建于driver通信的socket
select_driver(wpa_s, i)
{
    //调用对应的global_init(),void * nl80211_global_init(void)
    global->drv_priv[i] = wpa_drivers[i]->global_init();
    {
        //初始化netlink socket,设置两个消息处理函数,netlink_receive中使用
        cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
        cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
        //创建一个接收kernel中 route 子系统的消息socket
        global->netlink = netlink_init(cfg);
        {
            //*****该socket用于接收 kernel中
            netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
            bind(netlink->sock, (struct sockaddr *) &local, sizeof(local));
            //注册内核消息接收函数, 根据接收到的消息type选择以下两个处理函数
            eloop_register_read_sock(netlink->sock, netlink_receive, netlink, NULL);
            static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
            {
                char buf[8192]; //接收消息的字节数,
                left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen);
                //buf中是一个netlink消息,符合netlink规范,根据消息type选在相应的处理函数 newlink 和 dellink
            }
        }

        //创建 global结构体中的 nl_cb(接收消息处理)和nl(发送消息)
        if (wpa_driver_nl80211_init_nl_global(global) < 0)
        {
            //创建连接到 GENERIC_NETLINK 的socket
            global->nl = nl_create_handle(global->nl_cb, "nl");
            //将nl连接到 内核中的nl80211模块
            global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");

            //创建接收消息的event socket, 并分别加入到组播组scan mlme regulatory vendor 中
            global->nl_event = nl_create_handle(global->nl_cb, "event");
            ret = nl_get_multicast_id(global, "nl80211", "scan");
            ret = nl_socket_add_membership(global->nl_event, ret);

            //设置nl_cb的回调函数 process_global_event(), 该函数又会调用 wpa_supplicant_event() 做进一步处理
            nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_global_event, global);
            //为nl_event注册接收函数, 通过nl_recvmsgs()调用 process_global_event()
            nl80211_register_eloop_read(&global->nl_event, wpa_driver_nl80211_event_receive, global->nl_cb);
        }

        //创建一个 ioctl_sock, 还不知道干啥用,该sock用于通过ioctl方式向底层发送命令
        global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
    }
}
  1. 网络接口初始配置

例如up对应的接口

//调用对应的初始化函数wpa_driver_nl80211_drv_init(),传入的ifname名称为 wlan0
wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, void *global_priv, int hostapd, const u8 *set_addr)
{
    //挺重要的一个结构体
    struct wpa_driver_nl80211_data *drv;

    //添加了回调函数drv->nl_cb process_drv_event(),最终会调用 wpa_supplicant_event()
    if (wpa_driver_nl80211_init_nl(drv))
    //添加bss回调函数bss->nl_cb,看着没啥用,最终处理 wpa_supplicant_event(),这两个回调函数没有和socket绑定,目前不清楚调用地方
    if (nl80211_init_bss(bss))

    //RF射频省电相关,读取节点“/dev/rfkill”只是接受消息打印log,不做任何操作
    rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
    rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
    drv->rfkill = rfkill_init(rcfg);

    //检查当前接口是否为UP状态
    linux_iface_up(drv->global->ioctl_sock, ifname)

    //主要为操作网卡wlan0
    wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1)
    {
        //得知网卡地址和设置网口为UP
        if (set_addr && (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) || linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, set_addr)))
        //获取网口能力,具体能力请查阅struct wpa_driver_capa
        if (wpa_driver_nl80211_capa(drv))
        //设置网口信息 IF_OPER_DORMANT
        netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT);
        //获取网口地址
        if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, bss->addr))
    }

    //创建一个socket,并注册接收函数wpa_driver_nl80211_handle_eapol_tx_status
    drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
    eloop_register_read_sock(drv->eapol_tx_sock, wpa_driver_nl80211_handle_eapol_tx_status, drv, NULL);
}

5 密钥处理数据包收发socekt

由netlink创建

//初始化驱动,主要完成了l2_paket回掉函数的初始化,与4次握手相关
if (wpa_supplicant_driver_init(wpa_s) < 0)
{
    //主要函数,该函数会初始化l2_packet,并注册回掉函数,与4次握手相关
    if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
    {
        //wpa_supplicant_rx_eapol()就是4次握手的处理函数了
        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);
        {
            //新建socket
            struct l2_packet_data *l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, htons(protocol));
            //bind
            if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0)
            //将socket与回掉函数l2_packet_receive相关联,内部实际会调用 wpa_supplicant_rx_eapol()
            eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
            {
                //相关步骤请看eloop_data结构体,所有的回掉函数和回掉所用的数据都在保存在该结构体中
                res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, &fromlen);
                l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
            }
        }
    }
}
  1. wap_cli控制socket

在linux中可以通过wpa_supplicant提供的wpa_cli工具控制wpa_supplicant,在android中也可以通过wpa_cli在没有framework的情况下实现扫描连接工作

下述代码就是创建需要的socket和接收发送函数。

在android手机中打开wifi后再 /data/misc/wifi/sockets下的wlan0 和p2p0 就是该段代码生成的

wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
{
    //分配空间,然后执行真正的初始化工作
    struct ctrl_iface_priv *priv;
    if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0)
    {
        //android上运行不会执行以下两行代码
        //os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s", wpa_s->conf->ctrl_interface);
        //priv->sock = android_get_control_socket(addr.sun_path);

        //新建sock
        priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
        //bind,地址为,/data/misc/wifi/sockets/wlan0,这个地址是新生成的
        bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr))
        //注册接收socket的函数wpa_supplicant_ctrl_iface_receive, 其核心调用函数是 wpa_supplicant_ctrl_iface_process
        eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);
        //向socket上传event的函数
        wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
    }
}

通过wpa_cli工具使用连接网络的步骤:

  1. 添加接口过程中的全部代码
struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
                         struct wpa_interface *iface)
{
    struct wpa_supplicant *wpa_s;
    struct wpa_interface t_iface;
    struct wpa_ssid *ssid;

    struct wpa_supplicant *wpa_s = wpa_supplicant_alloc();
    wpa_s->global = global;

    //网络接口的初始化,与底层通信的socket,密钥数据包的socket,wpa_s的初始状态等
    if (wpa_supplicant_init_iface(wpa_s, &t_iface))
    {
        //读取两个conf配置文件
        wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
        wpa_config_read(wpa_s->confanother, wpa_s->conf);

        //初始化驱动接口,并注册接收驱动event的函数 nl80211
        if (wpas_init_driver(wpa_s, iface) < 0)
        {
            //根据传进来的-inl80211选定对应的wpa_driver_ops(driver_nl80211.c),里面定义了驱动的操作方法(),同时调用对应的global_init()进行初始化
            if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
            {
                //根据名称选择网络ops
                select_driver(wpa_s, i)
                {
                    //调用对应的global_init(),void * nl80211_global_init(void)
                    global->drv_priv[i] = wpa_drivers[i]->global_init();
                    {
                        //初始化netlink socket,设置两个消息处理函数,netlink_receive中使用
                        cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
                        cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
                        //创建一个接收kernel中 route 子系统的消息socket
                        global->netlink = netlink_init(cfg);
                        {
                            //*****该socket用于接收 kernel中
                            netlink->sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
                            bind(netlink->sock, (struct sockaddr *) &local, sizeof(local));
                            //注册内核消息接收函数, 根据接收到的消息type选择以下两个处理函数
                            eloop_register_read_sock(netlink->sock, netlink_receive, netlink, NULL);
                            static void netlink_receive(int sock, void *eloop_ctx, void *sock_ctx)
                            {
                                char buf[8192]; //接收消息的字节数,
                                left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *) &from, &fromlen);
                                //buf中是一个netlink消息,符合netlink规范,根据消息type选在相应的处理函数 newlink 和 dellink
                            }
                        }

                        //创建 global结构体中的 nl_cb(接收消息处理)和nl(发送消息)
                        if (wpa_driver_nl80211_init_nl_global(global) < 0)
                        {
                            //创建连接到 GENERIC_NETLINK 的socket
                            global->nl = nl_create_handle(global->nl_cb, "nl");
                            //将nl连接到 内核中的nl80211模块
                            global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");

                            //创建接收消息的event socket, 并分别加入到组播组scan mlme regulatory vendor 中
                            global->nl_event = nl_create_handle(global->nl_cb, "event");
                            ret = nl_get_multicast_id(global, "nl80211", "scan");
                            ret = nl_socket_add_membership(global->nl_event, ret);

                            //设置nl_cb的回调函数 process_global_event(), 该函数又会调用 wpa_supplicant_event() 做进一步处理
                            nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_global_event, global);
                            //为nl_event注册接收函数, 通过nl_recvmsgs()调用 process_global_event()
                            nl80211_register_eloop_read(&global->nl_event, wpa_driver_nl80211_event_receive, global->nl_cb);
                        }

                        //创建一个 ioctl_sock, 还不知道干啥用,该sock用于通过ioctl方式向底层发送命令
                        global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
                    }
                }
            }

            //调用对应的初始化函数wpa_driver_nl80211_drv_init(),传入的ifname名称为 wlan0
            wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
                static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname, void *global_priv, int hostapd, const u8 *set_addr)
                {
                    //挺重要的一个结构体
                    struct wpa_driver_nl80211_data *drv;

                    //添加了回调函数drv->nl_cb process_drv_event(),最终会调用 wpa_supplicant_event()
                    if (wpa_driver_nl80211_init_nl(drv))
                    //添加bss回调函数bss->nl_cb,看着没啥用,最终处理 wpa_supplicant_event(),这两个回调函数没有和socket绑定,目前不清楚调用地方
                    if (nl80211_init_bss(bss))

                    //RF射频省电相关,读取节点“/dev/rfkill”只是接受消息打印log,不做任何操作
                    rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
                    rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
                    drv->rfkill = rfkill_init(rcfg);

                    //检查当前接口是否为UP状态
                    linux_iface_up(drv->global->ioctl_sock, ifname)

                    //主要为操作网卡wlan0
                    wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1)
                    {
                        //得知网卡地址和设置网口为UP
                        if (set_addr && (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) || linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, set_addr)))
                        //获取网口能力,具体能力请查阅struct wpa_driver_capa
                        if (wpa_driver_nl80211_capa(drv))
                        //设置网口信息 IF_OPER_DORMANT
                        netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 1, IF_OPER_DORMANT);
                        //获取网口地址
                        if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, bss->addr))
                    }

                    。。创建一个socket,并注册接收函数wpa_driver_nl80211_handle_eapol_tx_status
                    drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
                    eloop_register_read_sock(drv->eapol_tx_sock, wpa_driver_nl80211_handle_eapol_tx_status, drv, NULL);
                }

        }

        //初始化wpa_s,主要设置 wpa 状态机
        if (wpa_supplicant_init_wpa(wpa_s) < 0)
        {
            //设置一些操作函数,请查看结构体 struct wpa_sm_ctx
            。。。
            //
            struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
            {
                //主要是3个变量值
                sm->dot11RSNAConfigPMKLifetime = 43200; //PMK的生存时间(秒)(12小时),超时后要重新计算
                sm->dot11RSNAConfigPMKReauthThreshold = 70;  //PMK超时多少(70%)后,需要重新身份认证
                sm->dot11RSNAConfigSATimeout = 60;      //进行身份验证的最长时间(秒)
            }
        }

        //初始化驱动,主要完成了l2_paket回掉函数的初始化,与4次握手相关
        if (wpa_supplicant_driver_init(wpa_s) < 0)
        {
            //主要函数,该函数会初始化l2_packet,并注册回掉函数,与4次握手相关
            if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
            {
                //wpa_supplicant_rx_eapol()就是4次握手的处理函数了
                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);
                {
                    //新建socket
                    struct l2_packet_data *l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM, htons(protocol));
                    //bind
                    if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0)
                    //将socket与回掉函数l2_packet_receive相关联,内部实际会调用 wpa_supplicant_rx_eapol()
                    eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
                    {
                        //相关步骤请看eloop_data结构体,所有的回掉函数和回掉所用的数据都在保存在该结构体中
                        res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll, &fromlen);
                        l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
                    }
                }
            }
        }

        //设置国家码到驱动中
        wpa_drv_set_country(wpa_s, wpa_s->conf->country))

        //wpa_s中的 struct wps_context *wps 节点
        if (wpas_wps_init(wpa_s))
        {
            //wps_context *wps中定义了一些方法,具体请查看注释,没什么逻辑处理的问题
        }

        //初始化 EAPOOL,参考eapol模块信息
        wpa_supplicant_init_eapol(wpa_s)
        {
            //设置一些方法
            。。。
            ctx->eapol_send = wpa_supplicant_eapol_send;
            。。。
            //初始化eapol状态机
            wpa_s->eapol = eapol_sm_init(ctx);
        }

        //初始化与FWKS的通信的socket???
        wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
        {
            //分配空间,然后执行真正的初始化工作
            struct ctrl_iface_priv *priv;
            if (wpas_ctrl_iface_open_sock(wpa_s, priv) < 0)
            {
                //参数通过启动参数传入wlan0的名称,然后获取init.rc中wpa_wlan0的socket
                //android上运行不会执行以下两行代码
                //os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s", wpa_s->conf->ctrl_interface);
                //priv->sock = android_get_control_socket(addr.sun_path);

                //新建sock
                priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
                //bind,地址为,/data/misc/wifi/sockets/wlan0,这个地址是新生成的
                bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr))
                //注册接收socket 命令的函数wpa_supplicant_ctrl_iface_receive, 其核心调用函数是 wpa_supplicant_ctrl_iface_process
                eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, wpa_s, priv);
                //向socket上传event的函数
                wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
            }
        }

        //初始化bss相关,主要是wpa_s中的两个链表
        if (wpa_bss_init(wpa_s) < 0)
        {
            //初始化wpa_s中bss和bssid链表
            dl_list_init(&wpa_s->bss);
            dl_list_init(&wpa_s->bss_id);
            //注册超时函数 ,每隔10秒刷新下bss,去掉无用的bss
            eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD=10, wpa_bss_timeout, wpa_s, NULL);
        }

        //sim卡 sd卡相关
        if (pcsc_reader_init(wpa_s) < 0)

        //不知道做什么用的
        if (wpas_init_ext_pw(wpa_s) < 0)
    }

    /* Notify the control interfaces about new iface */
    if (wpas_notify_iface_added(wpa_s)) {
        wpa_supplicant_deinit_iface(wpa_s, 1, 0);
        return NULL;
    }

    for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
        wpas_notify_network_added(wpa_s, ssid);

    //设置wpas状态
    wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
    return wpa_s;
}
  1. 流程图

其中虚线表示数据的传递,深棕色部分表示创建的socket以及收发函数

下一篇为wpa_supplicant中的两个重要的结构体bss和conf

bss中保存着扫描结果, conf中为wpa_s的参数和保存的网络

时间: 2024-10-08 10:34:47

Android wpa_supplcant 启动之--网络接口初始化的相关文章

Android wpa_supplcant 启动之--全局初始化

wpa_supplicant简介 wpa_supplicant是用来用来支持无线中各种加密方式的,包括WEP.WPA/WPA2和WAPI(中国特有).EAP(8021x).wpa_s通过socket与上层(framework)和底层(driver)通信,向上接收命令和传递当前状态,向下发送命令到驱动并接收驱动上传的各种event,严格来讲wap_s和driver中还有一层cfg80211,cfg80211可以理解为linux定义的80211管理控制层的框架,例如扫描.连接这些通用的过程,各个厂商

Android init language (安卓初始化语言)

目前在研究framework框架,AIL是Android初始化语言,以下是根据官方文档进行的翻译有助于研究Android启动过程: Android初始化语言包含了四种类型的声明:Actions(行动).Commands(命令).Services(服务)和Options(选项). 所有这些都是以行为单位的,各种记号由空格来隔开.C语言风格的反斜杠号可用于在记号间插入空格.双引号也可用于防止字符串被空格分割成多个记号.行末的反斜杠用于折行. 注释行以井号(#)开头(允许以空格开头). Actions

Android WIFI 启动流程

参考:http://blog.chinaunix.net/uid-26215986-id-3260413.html 一. WIFI 工作步骤 1. Wifi模块初始化 2. Wifi启动 3. 查找热点(AP) 4. 配置AP 5. 配置AP参数 6. Wifi连接 7. IP地址配置 二. WIFI 核心模块 1. WifiService 由SystemServer启动的ConnecttivityService创建, 负责启动关闭wpa_supplicant, WifiMonitor线程, 把

杂谈——Android从启动到程序运行发生的事情

转载请注明出处 博客地址:http://blog.csdn.net/JonsTank2013/article/details/51118563 作者:李中权 前言 好久没有写博客了,瞬间感觉好多学了的东西不进行一个自我的总结与消化总归变不成自己的.通过博客可能还可以找到一些当初在学习的时候没有想到的问题.想了半天,从大二上学期自学Android以来还没有对Android从启动到程序运行期间进行一个完整的归纳,刚好最近又学到了一些新东西,那就以这篇博客为媒介,总结一下从Android启动到程序运行

Android从启动到程序运行整个过程的整理

1Android是基于Linux的一个操作系统,它可以分为五层,下面是它的层次架构图,可以记一下,因为后面应该会总结到SystemServer这些Application Framework层的东西 Android的五层架构从上到下依次是:应用层,应用框架层,库层,运行时层,Linux内核层. 而在Linux中,它的启动可以归为一下几个流程: Boot Loader——>初始化内核——>...... 当初始化内核之后,就会启动一个相当重要的祖先进程,也就是init进程,在Linux中所有的进程都

Android开机启动过程分析

首先android是基于Linux的内核,只有先加载了kernel才能启动安卓,对于Linux来说android只是其上的一个应用程序.Android的启动大致可以形象的划分为三个过程: Init->init.rc->zygote.从事嵌入式开发的人都知道,Linux加载完内核驱动后会挂载'/'根文件系统,挂载完成后会执行'/init'二进制程序,这也是内核启动后执行的第一个用户程序,android里面也是这样.这个程序的main函数位于android/system/core/init/ini

Android WebView启动Chromium渲染引擎的过程分析

Android WebView加载了Chromium动态库之后,就可以启动Chromium渲染引擎了.Chromium渲染引擎由Browser.Render和GPU三端组成.其中,Browser端负责将网页UI合成在屏幕上,Render端负责加载网页的URL和渲染网页的UI,GPU端负责执行Browser端和Render端请求的GPU命令.本文接下来详细分析Chromium渲染引擎三端的启动过程. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! Andro

Android 框架启动流程

As we all know,Android手机系统本质上是一个基于Linux的应用程序,它以Linux系统为内核.因此系统的启动过程包括Linux内核启动和Android框架启动两个阶段. Linux内核启动 1.装载引导程序bootloader Linux内核启动时首先装载执行bootloader引导程序,装载完成后进入内核程序. 2.加载Linux内核 Linux内核加载主要包括初始化kernel核心(内存初始化,打开中断,初始化进程表等).初始化驱动.启动内核后台(daemons)线程.

【转】Android kernel启动流程

;font-family:Arial, Console, Verdana, 'Courier New';line-height:normal;white-space:normal;background-color:#FFFFFF;"> linuxandroidmakefileimagecachealignment 虽然这里的Arm Linux kernel前面加上了Android,但实际上还是和普遍Arm linux kernel启动的过程一样的,这里只是结合一下Android的Makef