Android wpa_supplicant源码分析–连接AP过程

本文详细介绍了使用WPA-PSK加密方式时,STA(Station)如何连接AP(Access Point)。连接过程分为链路认证和接入认证两个阶段,其中链路认证包括发送ASSOC帧并接收响应,而接入认证则涉及四次握手以建立安全连接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

连接网络过程

STA连接AP的过程可以参考该文章,http://support.huawei.com/ecommunity/bbs/10232527.html

STA需要认证后才可以接入AP,认证过程分为链路认证(associate)和接入认证(authentication),根据AP的加密方式 associate 和 authentication采用的认证方式不同。
上述网页中列出了各种加密方式的认证方式。
这里写图片描述
下面以wpa-psk加密方式为例,讲解wpa_supplicant连接AP的过程

1、链路认证(associate)过程

LOG:
wpa_supplicant: wlan0: State: SCANNING -> ASSOCIATING
wpa_supplicant: wlan0: State: ASSOCIATING -> ASSOCIATED

wpa_supplicant接收到上层命令由扫描过程变为关联过程,向指定的AP发送 ASSOC 帧,由于此处的认证方式为open,AP在接收到STA的帧后,直接回复STA关联成功。

1.1 添加associate的radio_work

//选择网络(已经在conf中保存), 通过id选取,也可以传入 “any” 后续还可以加入频率的设置" freq="
os_strncmp(buf, "SELECT_NETWORK ", 15)
static int wpa_supplicant_ctrl_iface_select_network(struct wpa_supplicant *wpa_s, char *cmd)
{
    //从conf中选取ssid网络
    struct wpa_ssid *ssid = wpa_config_get_network(wpa_s->conf, id);

    //选择网络
    wpa_supplicant_select_network(wpa_s, ssid);
    {
        //太狠了,把conf文件中的其他ssid全部设置disable=1
        for (other_ssid = wpa_s->conf->ssid; other_ssid; other_ssid = other_ssid->next)
            other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;

        wpa_s->current_ssid = ssid;
        wpa_s->reassociate = 1;

        //快速连接,select 的ssid 已经设置为 wpa_s->current_ssid
        wpa_supplicant_fast_associate(wpa_s)
            //直接调用,从扫描结果中选取要连接的bss网络
            wpas_select_network_from_last_scan(wpa_s, 0, 1)
            {
                //返回要连接的bss网络(scan), ssid返回conf中的ssid
                struct wpa_bss *selected = wpa_supplicant_pick_network(wpa_s,struct wpa_ssid &ssid(null));
                {
                    //根据priority的优先级匹配bss, 不合适的conf中的ssid网络已经被disable,不会选取
                    //返回的select 就是要 连接的bss 网络
                    for (prio = 0; prio < wpa_s->conf->num_prio; prio++)
                        selected = wpa_supplicant_select_bss(wpa_s, wpa_s->conf->pssid[prio], selected_ssid, 0);
                }

                //连接选取的网络 关联所需的网络, 
                //selected-----要连接的bss网络, ssid----conf中保存的ssid
                if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0)
                    //打了句log就调用关联函数了,“Request association with ” 这句log挺常见的
                    wpa_supplicant_associate(wpa_s, selected, ssid);
                    {
                        //一个ssid有5中模式,手机连接某个网络时,mode为 
                        * 0 = infrastructure (Managed) mode, i.e., associate with an AP.
                        * 1 = IBSS (ad-hoc, peer-to-peer)
                        * 2 = AP (access point)
                        * 3 = P2P Group Owner (can be set in the configuration file)
                        * 4 = P2P Group Formation (used internally; not in configuration

                        //将wpas_start_assoc_cb 添加到 radio work中
                        if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1, wpas_start_assoc_cb, cwork) < 0)
                    }

            }
    }
}

1.2 通过驱动发出associate 帧

//真正的连接过程
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
{
    //认证方法
    int algs = WPA_AUTH_ALG_OPEN;
    //关联的参数
    struct wpa_driver_associate_params params;

    //关联所需要的ie域
    u8 wpa_ie[200];
    size_t wpa_ie_len;
    //关联所需要的ie域,先清除一下
    wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);

    //根据key_mgmt中规定的认证方式,设置参数
    //在conf文件中的key_mgmt在wpa_config_parse_key_mgmt()中会解析成相应的值

    //判断bss是是够支持wpa
    if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || wpa_bss_get_ie(bss, WLAN_EID_RSN)) && wpa_key_mgmt_wpa(ssid->key_mgmt))
    {
        //设置相关的wpa_ie
        if (wpa_supplicant_set_suites(wpa_s, bss, ssid, wpa_ie, &wpa_ie_len))
    }
    //判断bss是否支持 8021x
    else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss && wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)){}

    //判断bss是否支持WPS
    else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS){}

    //判断bss是够为open的网络
    if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA){}

    //设置wpa_s的状态为 正在关联
    wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);


    //填充关联参数    
    params.wpa_ie = wpa_ie;
    。。。
    params.key_mgmt_suite = wpa_s->key_mgmt;

    //以wpa-psk的加密方式为例,psk密码最高为32位
    params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
         params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
        params.passphrase = ssid->passphrase;
        if (ssid->psk_set)
            params.psk = ssid->psk;
    }

    //调用驱动的关联方法,传入之前设置好的参数params
    ret = wpa_drv_associate(wpa_s, &params);

    //关联的超时处理,如果超时后还没有关联,那就会调用wpa_supplicant_timeout方法,例如将该bss加入 blacklist
    wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}



//驱动的关联函数
wpa_s->driver->associate(wpa_s->drv_priv, params)
static int wpa_driver_nl80211_associate(void *priv, struct wpa_driver_associate_params *params)
{
    //进入判断,直接调用链接的函数
    if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)){
        return wpa_driver_nl80211_connect(drv, params);
        {
            //调用发送关联帧的函数
            int ret = wpa_driver_nl80211_try_connect(drv, params);
            {
                //想组合好的帧发送到驱动中
                ret = send_and_recv_msgs(drv, msg, NULL, NULL);
                wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
            }
        }
    }
}

1.3 关联成功

//接收到驱动上传的ASSOC的event

mlme_event_connect(drv, cmd,
                   tb[NL80211_ATTR_STATUS_CODE],
                   tb[NL80211_ATTR_MAC],
                   tb[NL80211_ATTR_REQ_IE],
                   tb[NL80211_ATTR_RESP_IE]);
{
    //调用event处理函数
    wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
    {
        wpa_supplicant_event_assoc(wpa_s, data);
        {
            //设置wpa_s的状态
            wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);

            /*设置超时10s,等待AP发送 EAPOL包 Timeout for receiving the first EAPOL packet */
            wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
        }
    }
}

2、接入认证(authentication)(WPA-PSK为例)

采用PSK认证时,需要与AP交换4次信息,生成需要的密钥,俗称4次握手
https://en.wikipedia.org/wiki/IEEE_802.11i-2004#The_Four-Way_Handshake
wiki图片:
这里写图片描述

对用的相应的log为

wpa_supplicant: wlan0: State: ASSOCIATED -> 4WAY_HANDSHAKE
wpa_supplicant: wlan0: State: 4WAY_HANDSHAKE -> 4WAY_HANDSHAKE
wpa_supplicant: wlan0: State: 4WAY_HANDSHAKE -> GROUP_HANDSHAKE
wpa_supplicant: wlan0: State: GROUP_HANDSHAKE -> COMPLETED

4次握手的第一帧是由AP发起的,wpa_supplicant在收到后,会根据帧中的信息,判定需要的加密方式,并采用相应的处理函数。
wpa_supplicant支持的加密方式如下图
图片:
这里写图片描述
L2_packet的4次握手过程:

//处理接收到 L2 EAPOL FRAME 用作auth过程
wpa_supplicant_rx_eapol()
{
    //打印一些log
    wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
    //做一些判断,然后通过 eapol_sm_rx_eapol 处理接收到 frame(8021x认证的会通过此路径)
    if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
        eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)

    //wpa加密方式的通过此路径
    if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
        wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
        {
            //这个应该会设置 wap的状态,具体还不他清楚。。
            eapol_sm_notify_lower_layer_success(sm->eapol, 0);
            //依次调用握手处理函数 共4次,第一次 /* 1/4 4-Way Handshake */
            wpa_supplicant_process_1_of_4(sm, src_addr, key, ver, key_data, key_data_len);
            {
                //发送第二次握手信息到AP
                wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce, kde, kde_len, ptk))
            }

            //再次受到L2 packet 处理/* 3/4 4-Way Handshake */
            wpa_supplicant_process_3_of_4(sm, key, ver, key_data, key_data_len);
            {
                //发送第四次握手
                wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,&sm->ptk))
                //设置wpa_s状态  wlan0: State: 4WAY_HANDSHAKE -> GROUP_HANDSHAKE
                wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
                //这一部分的代码变化还是挺大的,4.4的和6.0就不一样 
                //这里会设置状态为 complete
                wpa_supplicant_key_neg_complete(sm, sm->bssid, key_info & WPA_KEY_INFO_SECURE);

                //设置rekey的offload,具体由驱动还是芯片处理,需要继续看
                wpa_sm_set_rekey_offload(sm);               

                //至此整个连接过程完毕
            }
        }
}

3 流程图

这里写图片描述

<think>我们正在解决wpa_supplicant中禁用BSSTransition(BSS过渡)的问题。BSSTransition是802.11v标准的一部分,允许AP请求客户端漫游到另一个AP。在某些情况下,我们可能需要禁用此功能。根据用户提供的引用,我们了解到wpa_supplicant的AIDL接口实现(StaNetwork)以及编译相关的问题,但用户当前的问题是关于禁用BSSTransition的配置或错误解决方案。在wpa_supplicant中,BSSTransition通常由WNM(WirelessNetworkManagement)功能管理。我们可以通过配置来禁用BSSTransition。步骤:1.在wpa_supplicant配置文件中,我们可以通过设置`disable_btm`(禁用BSSTransitionManagement)来关闭BSSTransition功能。2.另外,我们也可以禁用整个WNM功能,但这样可能会影响其他网络管理功能。具体配置:在`wpa_supplicant.conf`的网络配置块中,添加以下行:```disable_btm=1```或者```wnm_sleep_mode=0#这会禁用WNM睡眠模式,但可能不会完全禁用BSSTransition,所以首选disable_btm```如果是在运行时,我们可以使用`wpa_cli`命令来动态设置:```bashwpa_cli-iwlan0setdisable_btm1```另外,如果遇到与BSSTransition相关的编译错误,比如引用了未定义的符号(如引用[2]中提到的P2P相关函数),我们可以通过注释掉相关代码来解决,但这种情况通常是在编译wpa_supplicant时出现的。如果我们的问题是在编译时出现与BSSTransition相关的错误,可能需要检查配置选项或源代码。但是,用户的问题是关于配置禁用BSSTransition,所以我们重点放在配置上。如果用户想要在代码级别永久禁用BSSTransition,可以修改源代码。在wpa_supplicant的源代码中,可以搜索与BSSTransition相关的代码(如wnm_btm.c)并条件编译掉相关功能。但这种方法需要重新编译,且不推荐,除非有特殊需求。总结解决方案:1.在配置文件(wpa_supplicant.conf)中针对特定网络设置`disable_btm=1`。2.使用wpa_cli在运行时禁用。注意:禁用BSSTransition后,AP将无法请求客户端漫游,这可能会导致客户端在信号弱的AP上停留时间过长。因此,在禁用前请确保了解其影响。如果用户遇到的是错误而非配置需求,请提供具体的错误信息以便进一步分析。根据引用[1]中提到的wpa_supplicant的AIDL接口,我们也可以考虑在HAL层或framework层进行配置,但通常直接在wpa_supplicant配置文件中设置更为直接。如果用户是在Android系统中,可能需要修改framework的配置,但最终会传递到wpa_supplicant的配置中。在Android中,可以通过叠加层(overlay)的方式修改wpa_supplicant的配置文件,或者在初始化脚本中设置。相关问题:1.如何验证BSSTransition功能已被禁用?2.禁用BSSTransition对漫游有什么影响?3.wpa_supplicant中还有哪些与漫游相关的配置参数?</think>### 解决 wpa_supplicant 中禁用 BSS Transition 的问题 #### 问题分析 BSS Transition(BSS过渡)是802.11v标准中的关键功能,允许AP引导客户端漫游到更优的接入点。当需要禁用此功能时,常见场景包括: 1. **兼容性问题**:旧设备或特殊设备不支持802.11v 2. **网络稳定性**:避免激进漫游导致的连接中断 3. **调试需求**:隔离漫游相关问题 #### 解决方案 ##### 1. 配置文件禁用 (推荐) 在 `wpa_supplicant.conf` 中添加以下参数: ```conf network={ ssid="your_SSID" # 禁用BSS Transition Management disable_btm=1 # 同时禁用相关功能 wnm_sleep_mode=0 } ``` **生效方式**:重启wpa_supplicant服务 ```bash sudo systemctl restart wpa_supplicant ``` ##### 2. 运行时动态禁用 使用 `wpa_cli` 实时控制: ```bash wpa_cli -i wlan0 set disable_btm 1 # 禁用BSS过渡管理 wpa_cli -i wlan0 set wnm_sleep_mode 0 # 禁用WNM睡眠模式 wpa_cli -i wlan0 reconfigure # 立即生效 ``` ##### 3. 编译时永久禁用 修改源码后重新编译(参考引用[2][3]): 1. 编辑 `wpa_supplicant/.config`: ```config CONFIG_WNM=y # 改为 CONFIG_WNM=n CONFIG_INTERWORKING=y # 改为 CONFIG_INTERWORKING=n ``` 2. 注释相关代码(参考引用[2]方法): ```c // 在wnm_sta.c中注释BSS Transition处理 /* void wnm_handle_bss_trans_mgmt(struct wpa_supplicant *wpa_s, ...) { ... } */ ``` 3. 交叉编译注意事项(参考引用[3]): ```bash CFLAGS += -I/path/to/libnl/include LIBS += -L/path/to/libnl/lib -lnl-3 -lnl-genl-3 ``` #### 验证方法 ```bash # 检查当前配置 wpa_cli -i wlan0 status | grep "btm|wnm" # 测试AP请求(预期应失败) sudo iw dev wlan0 vendor send 0x00 0x00 0x00 0x01 ``` #### 常见错误处理 | 错误现象 | 解决方案 | |---------|---------| | `Unsupported parameter: disable_btm` | 升级wpa_supplicant到2.9+版本 | | `WNM: Failed to disable BSS Transition` | 检查驱动支持:`iw phy0 info \| grep 802.11v` | | 编译错误(参考引用[2]) | 在`.config`中添加`CONFIG_P2P=n`并注释相关代码 | #### 进阶配置建议 ```conf # 同时优化漫游行为 network={ ... # 禁用自动扫描 bgscan="" # 固定连接当前AP bssid=00:11:22:33:44:55 # 提高漫游阈值 scan_freq=5180 # 指定固定信道 } ```
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值