Android Q wifi connect

wifi连接流程

->wifi连接过程中app可见的操作流程:

列表中选择一个可用AP -> 弹出对话框 -> 输入AP密码点击保存 -> 底层处理连接流程

->底层处理概述

WifiStateMachine处理SAVE_NETWORK消息 -> 状态机发送CMD_START_CONNECT并处理 -> wifinative.connectToNetwork 被调用处理连接消息 -> suplicantstaIfaceHal.connectToNetwork -> addnetwork ->associate -> authentication 4次握手 -> connect

 

->app

在WifiSettings界面选择了一个AP

->AP是没有加密的,就保存并进行连接

->AP已经保存过,直接连接这个AP

->AP加过密,并且未保存,会显示配置AP参数的对话框。

"accroding the select ap , showDialog or connect ..."
@Override
public boolean onPreferenceTreeClick(Preference preference) {
    // If the preference has a fragment set, open that
    if (preference.getFragment() != null) {
        preference.setOnPreferenceClickListener(null);
        return super.onPreferenceTreeClick(preference);
    }
 
    if (preference instanceof LongPressAccessPointPreference) {
        mSelectedAccessPoint = ((LongPressAccessPointPreference) preference).getAccessPoint();
        if (mSelectedAccessPoint == null) {
            return false;
        }
        if (mSelectedAccessPoint.isActive()) {
            return super.onPreferenceTreeClick(preference);
        }
        /**
        * Bypass dialog and connect to unsecured networks, or previously connected saved
        * networks, or Passpoint provided networks.
        */
        WifiConfiguration config = mSelectedAccessPoint.getConfig();
        if (mSelectedAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE) {
            mSelectedAccessPoint.generateOpenNetworkConfig();
            connect(mSelectedAccessPoint.getConfig(), mSelectedAccessPoint.isSaved());
        } else if (mSelectedAccessPoint.isSaved() && config != null
                && config.getNetworkSelectionStatus() != null
                && config.getNetworkSelectionStatus().getHasEverConnected()) {
            connect(config, true /* isSavedNetwork */);
        } else if (mSelectedAccessPoint.isPasspoint()) {
            // Access point provided by an installed Passpoint provider, connect using
            // the associated config.
            connect(config, true /* isSavedNetwork */);
        } else {
            showDialog(mSelectedAccessPoint, WifiConfigUiBase.MODE_CONNECT);
        }
    } else if (preference == mAddPreference) {
        onAddNetworkPressed();
    } else {
        return super.onPreferenceTreeClick(preference);
    }
    return true;

}

本次分析首次配置AP密码流程,这种情况调用showDialog方法

->showDialog


private void showDialog(AccessPoint accessPoint, int dialogMode) {
    if (accessPoint != null) {
        WifiConfiguration config = accessPoint.getConfig();
        if (WifiUtils.isNetworkLockedDown(getActivity(), config) && accessPoint.isActive()) {
            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
                    RestrictedLockUtils.getDeviceOwner(getActivity()));
            return;
        }
    }
 
    if (mDialog != null) {
        removeDialog(WIFI_DIALOG_ID);
        mDialog = null;
    }
 
    // Save the access point and edit mode
    mDlgAccessPoint = accessPoint;
    mDialogMode = dialogMode;
 
    showDialog(WIFI_DIALOG_ID);

}

public Dialog onCreateDialog(int dialogId) {
    switch (dialogId) {
        case WIFI_DIALOG_ID:
            if (mDlgAccessPoint == null && mAccessPointSavedState == null) {
                // add new network
                mDialog = WifiDialog
                        .createFullscreen(getActivity(), this, mDlgAccessPoint, mDialogMode);
            } else {
                // modify network
                if (mDlgAccessPoint == null) {
                    // restore AP from save state
                    mDlgAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
                    // Reset the saved access point data
                    mAccessPointSavedState = null;
                }
                mDialog = WifiDialog
                        .createModal(getActivity(), this, mDlgAccessPoint, mDialogMode);
            }
 
            mSelectedAccessPoint = mDlgAccessPoint;
            return mDialog;
        case WRITE_NFC_DIALOG_ID:
            if (mSelectedAccessPoint != null) {
                mWifiToNfcDialog = new WriteWifiConfigToNfcDialog(
                        getActivity(),
                        mSelectedAccessPoint.getSecurity());
            } else if (mWifiNfcDialogSavedState != null) {
                mWifiToNfcDialog = new WriteWifiConfigToNfcDialog(getActivity(),
                           mWifiNfcDialogSavedState);
            }
 
            return mWifiToNfcDialog;
    }
    return super.onCreateDialog(dialogId);

}

以上是app弹出对话框的代码:获取选择的的AP信息 -> 创建窗口并显示

接下来需要我么手动输入AP的密码,并点击保存按钮,进入正式的链接流程

 

窗口被创建以后,保存按钮会一直被监听,监听到点击动作,立即调用onSubmit方法进行响应

" 检测到监听动作后的调用 "

public void onSubmit(WifiDialog dialog) {
    if (mDialog != null) {
        submit(mDialog.getController());
    }
}


void submit(WifiConfigController configController) {
 
    final WifiConfiguration config = configController.getConfig();
 
    if (config == null) {
        if (mSelectedAccessPoint != null
                && mSelectedAccessPoint.isSaved()) {
            connect(mSelectedAccessPoint.getConfig(), true /* isSavedNetwork */);
        }
    } else if (configController.getMode() == WifiConfigUiBase.MODE_MODIFY) {
        mWifiManager.save(config, mSaveListener);
    } else {
        mWifiManager.save(config, mSaveListener);
        if (mSelectedAccessPoint != null) { // Not an "Add network"
            connect(config, false /* isSavedNetwork */);
        }
    }
 
    mWifiTracker.resumeScanning();
}

这里就需要根据AP是否被保存过进行分类处理,如果没有保存就先进行保存,然后在进行连接处理。

接下来根据代码:mwifimanager.save(),接下来的处理会被framework层处理了

 

->Framework

framework层的处理如下:

 wifiMannager异步消息发送SAVE NETWORK 

-> wifiServiceImpl 处理消息

->wifiStateMachine

      1.保存网络配置信息

      2.CMD_START_ CONNECT处理

-> wifiNative 处理连接任务

-> wpa_supplicant

      1.connect network

      2.addnetworkandsaveconfig

      3.addnetwork

->wlan driver

 

一、关联阶段

1. WifiSettings.submit – > WifiManager

  • WifiSettings 干的事情比较简单,当在dialog完成ssid 以及密码填充后,直接call WifiManager save 
  • WifiManager 收到Save 之后,wifi的链接流程正式开始

->frameworks/base/wifi/java/android/net/wifi/WifiManager.java 

public void save(WifiConfiguration config, ActionListener listener) {
    if (config == null) throw new IllegalArgumentException("config cannot be null");
    getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);

在wifiManager中使用了异步通信给wifiservice发送了消息,将工作传递下去

 

->frameworks/base/wifi/java/android/net/wifi/WifiServiceImpl.java

"key log SAVE nid= config=  "
 public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            ...
            case WifiManager.SAVE_NETWORK: {
                if (checkChangePermissionAndReplyIfNotAuthorized(
                        msg, WifiManager.SAVE_NETWORK_FAILED)) {
                    WifiConfiguration config = (WifiConfiguration) msg.obj;
                    int networkId = msg.arg1;
                    Slog.d(TAG, "SAVE"
                            + " nid=" + Integer.toString(networkId)
                            + " config=" + config
                            + " uid=" + msg.sendingUid
                            + " name="
                            + mContext.getPackageManager().getNameForUid(msg.sendingUid));
                    if (config != null) {
                        /* Command is forwarded to state machine */
                        ClientModeImpl.sendMessage(Message.obtain(msg));
                    } else {
                        Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
                        replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
                                WifiManager.INVALID_ARGS);
                    }
                }
                break;
            }
            ...
        }
    }
    ...
}

AsyncChannel 用于两个Handler 之间的通信,具体的通信方式为源Handler 通过sendMessage 向目标Handler 发送消息,而目标Handler 通过replyToMessage 回复源Handler 处理结果;这两个Handler 可位于同一个进程,也可分属于两个不同的进程.

此处有关键log打印可供调试:SAVE ......

 

 接下来就开始将任务交给了WifiStateMachine

                 

->frameworks/base/wifi/java/android/net/wifi/ClientModempl.java

"状态机需要触发两个关键工作:->saveNetworkConfig  ->startconnectToNetwork"
"在进行连接工作前,keylog: SAVE_NETWORK credential changed for config= ..."
case WifiManager.SAVE_NETWORK:
                result = saveNetworkConfigAndSendReply(message);
                netId = result.getNetworkId();
                if (result.isSuccess() && mWifiInfo.getNetworkId() == netId) {
                    if (result.hasCredentialChanged()) {
                        config = (WifiConfiguration) message.obj;
                 // The network credentials changed and we're connected to this network,
                 // start a new connection with the updated credentials.
                  logi("SAVE_NETWORK credential changed for config=" + config.configKey()
                                + ", Reconnecting.");
                  startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
                    } else {
                        if (result.hasProxyChanged()) {
                            log("Reconfiguring proxy on connection");
                            mIpClient.setHttpProxy(
                                    getCurrentWifiConfiguration().getHttpProxy());
                        }
                        if (result.hasIpChanged()) {
                        // The current connection configuration was changed
                        // We switched from DHCP to static or from static to DHCP, or the
                        // static IP address has changed.
                            log("Reconfiguring IP on connection");
                       // TODO(b/36576642): clear addresses and disable IPv6
                       // to simplify obtainingIpState.
                            transitionTo(mObtainingIpState);
                        }
                    }
                }
                break;

状态机当前处于Disconnected状态,当接受到wifiserviceimpl调用状态机的发送的SAVE_NETWORK消息后,当前状态无法处理此消息,会追朔到其父类ConnectModeState来处理,处理方式就是上文的代码所示。

->saveNetworkConfigAndSendReply(message)

状态机主要的工作之一:保存网络配置

"->保存并更新config并广播 <没有成功会打印错误log>"
"->enable network"

private NetworkUpdateResult saveNetworkConfigAndSendReply(Message message) {
    WifiConfiguration config = (WifiConfiguration) message.obj;
    if (config == null) {
        loge("SAVE_NETWORK with null configuration "
                + mSupplicantStateTracker.getSupplicantStateName()
                + " my state " + getCurrentState().getName());
        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
        return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
    }
    NetworkUpdateResult result =
            mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
    if (!result.isSuccess()) {
        loge("SAVE_NETWORK adding/updating config=" + config + " failed");
        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
        return result;
    }
    if (!mWifiConfigManager.enableNetwork(
            result.getNetworkId(), false, message.sendingUid)) {
        loge("SAVE_NETWORK enabling config=" + config + " failed");
        messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
        replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
        return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
    }
    broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
    replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
    return result;
}

->startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);

状态机主要工作之二:开始链接AP


public void startConnectToNetwork(int networkId, int uid, String bssid) {
    sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
}


"ConnectModeState handle the message "
"key log CMD_START_CONNECT sup state..."
"key log Connecting with currentMacAddress  " 

case CMD_START_CONNECT:
    /* connect command coming from auto-join */
    netId = message.arg1;
    int uid = message.arg2;
    bssid = (String) message.obj;
 
    synchronized (mWifiReqCountLock) {
        if (!hasConnectionRequests()) {
            if (mNetworkAgent == null) {
                loge("CMD_START_CONNECT but no requests and not connected,"
                            + " bailing");
                break;
            } else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
                loge("CMD_START_CONNECT but no requests and connected, but app "
                            + "does not have sufficient permissions, bailing");
            break;
            }
        }
    }
 
    config = mWifiConfigManager.getConfiguredNetworkWithoutMasking(netId);
    logd("CMD_START_CONNECT sup state "
                    + mSupplicantStateTracker.getSupplicantStateName()
                    + " my state " + getCurrentState().getName()
                    + " nid=" + Integer.toString(netId)
                    + " roam=" + Boolean.toString(mIsAutoRoaming));
    if (config == null) {
        loge("CMD_START_CONNECT and no config, bail out...");
        break;
    }
    mTargetNetworkId = netId;
    setTargetBssid(config, bssid);
 
    if (mEnableConnectedMacRandomization.get()) {
        configureRandomizedMacAddress(config);
    }
 
    String currentMacAddress = mWifiNative.getMacAddress(mInterfaceName);
    mWifiInfo.setMacAddress(currentMacAddress);
    Log.i(TAG, "Connecting with " + currentMacAddress + " as the mac address");
 
    reportConnectionAttemptStart(config, mTargetRoamBSSID,
                    WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
    if (mWifiNative.connectToNetwork(mInterfaceName, config)) {
        mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config);
        lastConnectAttemptTimestamp = mClock.getWallClockMillis();
        targetWificonfiguration = config;
        mIsAutoRoaming = false;
        if (getCurrentState() != mDisconnectedState) {
            transitionTo(mDisconnectingState);
        }
        } else {
            loge("CMD_START_CONNECT Failed to start connection to network " + config);
            reportConnectionAttemptEnd(
                        WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
                        WifiMetricsProto.ConnectionEvent.HLF_NONE);
            replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
                        WifiManager.ERROR);
            break;
    }
    break;

?mid=&wid=51824&sid=&tid=8731&rid=LOADED&custom1=mp.csdn.net&custom2=%2Fconsole%2Feditor%2Fhtml%2F104880829&custom3=clipsold.com&t=1584409962756?mid=&wid=51824&sid=&tid=8731&rid=FINISHED&custom1=mp.csdn.net&t=1584409962757startConnectToNetwork() 是给自己发送了CMD_START_CONNECT消息,ConnectModeState状态去出处理这个消息;

之前的链接流程都没有做太多的的处理,到这里开始作对链接初步检测:

->检查链接请求

->检查权限

->随机mac地址检查以及设置

->调用Native继续处理链接流程

 

->frameworks/base/wifi/java/android/net/wifi/WifiNative.java

public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
    // Abort ongoing scan before connect() to unblock connection request.
    mWificondControl.abortScan(ifaceName);
    return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
}

开始链接之前wifinative关闭了wifi的扫描 -> 调用supplicatStaIfaceHal处理跟多的链接细节

->supplicentStaIfaceHal

1. 中止任何正在进行的扫描来不阻塞连接请求

2.删除wpa_supplicant中的任何现有网络(这会隐式触发断开连接)

3.在wpa_supplicant中添加一个新的网络

4.在wpa_supplicant中保存提供的configuration

5.在wpa_supplicant中选择新的网络

6.触发wpa_supplicant 的重新连接命令
 

->frameworks/base/wifi/java/android/net/wifi/SupplicantStaIfaceHal.java

"key log: connectToNetwork  AP_name protocol"

public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
    synchronized (mLock) {
        logd("connectToNetwork " + config.configKey());
        WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
        if (WifiConfigurationUtil.isSameNetwork(config, currentConfig)) {
            String networkSelectionBSSID = config.getNetworkSelectionStatus()
                    .getNetworkSelectionBSSID();
            String networkSelectionBSSIDCurrent =
                    currentConfig.getNetworkSelectionStatus().getNetworkSelectionBSSID();
            if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) {
                logd("Network is already saved, will not trigger remove and add operation.");
            } else {
                logd("Network is already saved, but need to update BSSID.");
                if (!setCurrentNetworkBssid(
                        ifaceName,
                        config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) {
                    loge("Failed to set current network BSSID.");
                    return false;
                }
                mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config));
            }
        } else {
            mCurrentNetworkRemoteHandles.remove(ifaceName);
            mCurrentNetworkLocalConfigs.remove(ifaceName);
            if (!removeAllNetworks(ifaceName)) {
                loge("Failed to remove existing networks");
                return false;
            }
            Pair<SupplicantStaNetworkHal, WifiConfiguration> pair =
                    addNetworkAndSaveConfig(ifaceName, config);
            if (pair == null) {
                loge("Failed to add/save network configuration: " + config.configKey());
                return false;
            }
            mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
            mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
        }
        SupplicantStaNetworkHal networkHandle =
                checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
        if (networkHandle == null || !networkHandle.select()) {
            loge("Failed to select network configuration: " + config.configKey());
            return false;
        }
        return true;
    }
}

看下此阶段的相关log

"12-21 10:54:37.899   984  2216 D SupplicantStaIfaceHal: connectToNetwork WINGTECH-GUEST WPA_PSK isAscii=true"
12-21 10:54:37.900 23453 23453 I wpa_supplicant: getCapabilitiesInternal capabilities: NONE IEEE8021X WPA-EAP WPA-PSK WPA-EAP-SUITE-B WPA-EAP-SUITE-B-192 OWE DPP FILS-SHA256 FILS-SHA384 FT-PSK
12-21 10:54:37.902 23453 23453 I wpa_supplicant: getCapabilitiesInternal capabilities: NONE IEEE8021X WPA-EAP WPA-PSK WPA-EAP-SUITE-B WPA-EAP-SUITE-B-192 OWE DPP FILS-SHA256 FILS-SHA384 FT-PSK
12-21 10:54:37.902   984  2216 I SupplicantStaIfaceHal: addSupplicantStaNetwork via HIDL
12-21 10:54:37.909   984  2216 I System.out: stanetwork getId >>0
12-21 10:54:37.909   984  2216 E SupplicantStaNetworkHal: set ISupplicantVendorStaNetwork successfull
12-21 10:54:37.918 24377 24377 I Perf    : Connecting to perf service.
12-21 10:54:37.918   984  1103 I system_server: Background concurrent copying GC freed 67248(2899KB) AllocSpace objects, 65(6452KB) LOS objects, 42% free, 11MB/19MB, paused 142us total 135.163ms
12-21 10:54:37.924   984  2216 E SupplicantStaNetworkHal: Invalid VendorKeyMgmtMask bit in keyMgmt: 1
12-21 10:54:37.924   984  2216 E SupplicantStaNetworkHal: Invalid VendorKeyMgmtMask bit in keyMgmt: 11
12-21 10:54:37.924   984  2216 E SupplicantStaNetworkHal: Vendor Key Management 0
12-21 10:54:37.924 23453 23453 I wpa_supplicant: Vendor key_mgmt: 0x142
12-21 10:54:37.925   984  2216 E SupplicantStaNetworkHal: Invalid protoMask bit in wificonfig: 0
12-21 10:54:37.925   984  2216 E SupplicantStaNetworkHal: Invalid protoMask bit in wificonfig: 1
12-21 10:54:37.926 23453 23453 I wpa_supplicant: Vendor Proto: 0x3
12-21 10:54:37.929 23453 23453 I wpa_supplicant: getCapabilitiesInternal capabilities: NONE IEEE8021X WPA-EAP WPA-PSK WPA-EAP-SUITE-B WPA-EAP-SUITE-B-192 OWE DPP FILS-SHA256 FILS-SHA384 FT-PSK
12-21 10:54:37.931 23453 23453 E wpa_supplicant: eap_proxy: eap_proxy_notify_config
12-21 10:54:37.933 23453 23453 I wpa_supplicant: wlan0: Trying to associate with SSID 'WINGTECH-GUEST'

 log:SupplicantStaIfaceHal: addSupplicantStaNetwork via HIDL 这是 SaddNetworkAndSaveConfig里面打出来的log

两件任务需要被做:1、保存config到supplicant中  2、调用selcet方法调用,通过HIDL到HAL层

1、保存config到supplicant中

->SaddNetworkAndSaveConfig

"key log:  addSupplicantStaNetwork via HIDL"  

 private Pair<SupplicantStaNetworkHal, WifiConfiguration>
            addNetworkAndSaveConfig(WifiConfiguration config) {
        synchronized (mLock) {
            logi("addSupplicantStaNetwork via HIDL");
            if (config == null) {
                loge("Cannot add NULL network!");
                return null;
            }
            SupplicantStaNetworkHal network = addNetwork();
            if (network == null) {
                loge("Failed to add a network!");
                return null;
            }
            network.getId();
            network.setVendorStaNetwork(getVendorNetwork (ifaceName, network.getNetworkId()))
            "will print set ISupplicantVendorStaNetwork successfull"
            boolean saveSuccess = false;
            try {
                saveSuccess = network.saveWifiConfiguration(config);"在config 中设置各种属性 "
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Exception while saving config params: " + config, e);
            }
            if (!saveSuccess) {
                loge("Failed to save variables for: " + config.configKey());
                if (!removeAllNetworks()) {
                    loge("Failed to remove all networks on failure.");
                }
                return null;
            }
            return new Pair(network, new WifiConfiguration(config));
        }
    }

->本地调用addnetwork

  private SupplicantStaNetworkHal addNetwork() {
        synchronized (mLock) {
            final String methodStr = "addNetwork";
            if (!checkSupplicantStaIfaceAndLogFailure(methodStr)) return null;
            Mutable<ISupplicantNetwork> newNetwork = new Mutable<>();
            try {
                mISupplicantStaIface.addNetwork((SupplicantStatus status,
                        ISupplicantNetwork network) -> {
                    if (checkStatusAndLogFailure(status, methodStr)) {
                        newNetwork.value = network;
                    }
                });
            } catch (RemoteException e) {
                handleRemoteException(e, methodStr);
            }
            if (newNetwork.value != null) {
                return getStaNetworkMockable(
                        ISupplicantStaNetwork.asInterface(newNetwork.value.asBinder()));
            } else {
                return null;
            }
        }
    }

mISupplicantStaIface是连接supplicant成功后framework保留下来的服务器对象即ISupplicantStaIface应该是对应sta_iface.cpp的引用。

接下来save config流程通过hidl重java走到了c++的hidl代码。

 

->HIDL

external/wpa_supplicant_8/wpa_supplicant/hidl/1.0/sta_iface.cpp


Return<void> StaIface::addNetwork(addNetwork_cb _hidl_cb)
{
	return validateAndCall(
	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
	    &StaIface::addNetworkInternal, _hidl_cb);
}
 
std::pair<SupplicantStatus, sp<ISupplicantNetwork>>
StaIface::addNetworkInternal()
{
	android::sp<ISupplicantStaNetwork> network;
	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
	struct wpa_ssid *ssid = wpa_supplicant_add_network(wpa_s);
	if (!ssid) {
		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
	}
	HidlManager *hidl_manager = HidlManager::getInstance();
	if (!hidl_manager ||
	    hidl_manager->getStaNetworkHidlObjectByIfnameAndNetworkId(
		wpa_s->ifname, ssid->id, &network)) {
		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, network};
	}
	return {{SupplicantStatusCode::SUCCESS, ""}, network};
}
 

HIDL通信的C++接口实现处,将保存网络的任务传递给了wpa_supplicat,wpa_supplicant_add_network(wpa_s);

->wpa_supplicant.c

/**
 * wpa_supplicant_add_network - Add a new network
 * @wpa_s: wpa_supplicant structure for a network interface
 * Returns: The new network configuration or %NULL if operation failed
 *
 * This function performs the following operations:
 * 1. Adds a new network.
 * 2. Send network addition notification.
 * 3. Marks the network disabled.
 * 4. Set network default parameters.
 */
struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s)
{
	struct wpa_ssid *ssid;
 
	ssid = wpa_config_add_network(wpa_s->conf);
	if (!ssid)
		return NULL;
	wpas_notify_network_added(wpa_s, ssid);
	ssid->disabled = 1;
	wpa_config_set_network_defaults(ssid);
 
	return ssid;
}

wpa_supplicant添加网络,做了如下四个工作

1.添加新的网络

2.发出网络添加通知

3.将该网络标记为disable

4.设置网络默认参数

->1.1wpa_config_add_network(conf)

external/wpa_supplicant8/wpa_supplicat/config.c


struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
{
	int id;
	struct wpa_ssid *ssid, *last = NULL;
 
	id = -1;
	ssid = config->ssid;
	while (ssid) {
		if (ssid->id > id)
			id = ssid->id;
		last = ssid;
		ssid = ssid->next;
	}
	id++;
 
	ssid = os_zalloc(sizeof(*ssid));
	if (ssid == NULL)
		return NULL;
	ssid->id = id;
	dl_list_init(&ssid->psk_list);
	if (last)
		last->next = ssid;
	else
		config->ssid = ssid;
 
	wpa_config_update_prio_list(config);
 
	return ssid;
}

在config.c的处理中,可以看到ssid是存在一个链表之中的。

1、while循环中是为了计算出当前我们需要保存的网络的id号,在最后的id++执行后,就是当前我们的网络的id号

2、last->next = ssid; 此处插入了一个空的ssid,

3、wpa_config_update_prio_list(config)


/**
 * wpa_config_update_prio_list - Update network priority list
 * @config: Configuration data from wpa_config_read()
 * Returns: 0 on success, -1 on failure
 *
 * This function is called to update the priority list of networks in the
 * configuration when a network is being added or removed. This is also called
 * if a priority for a network is changed.
 */
int wpa_config_update_prio_list(struct wpa_config *config)
{
	struct wpa_ssid *ssid;
	int ret = 0;
 
	os_free(config->pssid);
	config->pssid = NULL;
	config->num_prio = 0;
 
	ssid = config->ssid;
	while (ssid) {
		ssid->pnext = NULL;
		if (wpa_config_add_prio_network(config, ssid) < 0)
			ret = -1;
		ssid = ssid->next;
	}
 
	return ret;
}
 
/**
 * wpa_config_add_prio_network - Add a network to priority lists
 * @config: Configuration data from wpa_config_read()
 * @ssid: Pointer to the network configuration to be added to the list
 * Returns: 0 on success, -1 on failure
 *
 * This function is used to add a network block to the priority list of
 * networks. This must be called for each network when reading in the full
 * configuration. In addition, this can be used indirectly when updating
 * priorities by calling wpa_config_update_prio_list().
 */
int wpa_config_add_prio_network(struct wpa_config *config,
				struct wpa_ssid *ssid)
{
	int prio;
	struct wpa_ssid *prev, **nlist;
 
	/*
	 * Add to an existing priority list if one is available for the
	 * configured priority level for this network.
	 */
	for (prio = 0; prio < config->num_prio; prio++) {
		prev = config->pssid[prio];
		if (prev->priority == ssid->priority) {
			while (prev->pnext)
				prev = prev->pnext;
			prev->pnext = ssid;
			return 0;
		}
	}
 
	/* First network for this priority - add a new priority list */
	nlist = os_realloc_array(config->pssid, config->num_prio + 1,
				 sizeof(struct wpa_ssid *));
	if (nlist == NULL)
		return -1;
 
	for (prio = 0; prio < config->num_prio; prio++) {
		if (nlist[prio]->priority < ssid->priority) {
			os_memmove(&nlist[prio + 1], &nlist[prio],
				   (config->num_prio - prio) *
				   sizeof(struct wpa_ssid *));
			break;
		}
	}
 
	nlist[prio] = ssid;
	config->num_prio++;
	config->pssid = nlist;
 
	return 0;
}

每添加一个新的网络,都会重新初始化一下pssid队列,相同priority的网络会接续在之前队列后面,否则在nlist里新建一个优先级元素

->1.1添加新的网络总结:添加新的网络最后在config.c中完成,主要有两件事情:1、ssid链表中加入新的节点  2、更新优先级链表

->1.2发出网络添加通知

->notify.c


void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
			       struct wpa_ssid *ssid)
{
	if (wpa_s->p2p_mgmt)
		return;
 
	/*
	 * Networks objects created during any P2P activities should not be
	 * exposed out. They might/will confuse certain non-P2P aware
	 * applications since these network objects won't behave like
	 * regular ones.
	 */
	if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s) {
		wpas_dbus_register_network(wpa_s, ssid);
		wpas_hidl_register_network(wpa_s, ssid);
	}
}

->hidl.cpp


int wpas_hidl_register_network(
    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
	if (!wpa_s || !wpa_s->global->hidl || !ssid)
		return 1;
 
	wpa_printf(
	    MSG_DEBUG, "Registering network to hidl control: %d", ssid->id);
 
	HidlManager *hidl_manager = HidlManager::getInstance();
	if (!hidl_manager)
		return 1;
 
	return hidl_manager->registerNetwork(wpa_s, ssid);
}

->hidl_manager.cpp

/**
 * Register a network to hidl manager.
 *
 * @param wpa_s |wpa_supplicant| struct corresponding to the interface on which
 * the network is added.
 * @param ssid |wpa_ssid| struct corresponding to the network being added.
 *
 * @return 0 on success, 1 on failure.
 */
int HidlManager::registerNetwork(
    struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
{
	if (!wpa_s || !ssid)
		return 1;
 
	// Generate the key to be used to lookup the network.
	const std::string network_key =
	    getNetworkObjectMapKey(wpa_s->ifname, ssid->id);
 
	if (isP2pIface(wpa_s)) {
		if (addHidlObjectToMap<P2pNetwork>(
			network_key,
			new P2pNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
			p2p_network_object_map_)) {
			wpa_printf(
			    MSG_ERROR,
			    "Failed to register P2P network with HIDL "
			    "control: %d",
			    ssid->id);
			return 1;
		}
		p2p_network_callbacks_map_[network_key] =
		    std::vector<android::sp<ISupplicantP2pNetworkCallback>>();
		// Invoke the |onNetworkAdded| method on all registered
		// callbacks.
		callWithEachP2pIfaceCallback(
		    wpa_s->ifname,
		    std::bind(
			&ISupplicantP2pIfaceCallback::onNetworkAdded,
			std::placeholders::_1, ssid->id));
	} else {
		if (addHidlObjectToMap<StaNetwork>(
			network_key,
			new StaNetwork(wpa_s->global, wpa_s->ifname, ssid->id),
			sta_network_object_map_)) {
			wpa_printf(
			    MSG_ERROR,
			    "Failed to register STA network with HIDL "
			    "control: %d",
			    ssid->id);
			return 1;
		}
		sta_network_callbacks_map_[network_key] =
		    std::vector<android::sp<ISupplicantStaNetworkCallback>>();
		// Invoke the |onNetworkAdded| method on all registered
		// callbacks.
		callWithEachStaIfaceCallback(
		    wpa_s->ifname,
		    std::bind(
			&ISupplicantStaIfaceCallback::onNetworkAdded,
			std::placeholders::_1, ssid->id));
	}
	return 0;
}
 
/**
 * Creates a unique key for the network using the provided |ifname| and
 * |network_id| to be used in the internal map of |ISupplicantNetwork| objects.
 * This is of the form |ifname|_|network_id|. For ex: "wlan0_1".
 *
 * @param ifname Name of the corresponding interface.
 * @param network_id ID of the corresponding network.
 */
const std::string getNetworkObjectMapKey(
    const std::string &ifname, int network_id)
{
	return ifname + "_" + std::to_string(network_id);
}
 
	// Map of all the STA network specific hidl objects controlled by
	// wpa_supplicant. This map is keyed in by the corresponding
	// |ifname| & |network_id|.
	std::map<const std::string, android::sp<StaNetwork>>
	    sta_network_object_map_;

对应getStaNetworkHidlObjectByIfnameAndNetworkId获得的network就是

new StaNetwork(wpa_s->global, wpa_s->ifname, ssid->id)

 

->2、选择网络

    /**
     * Trigger a connection to this network.
     *
     * @return true if it succeeds, false otherwise.
     */
    public boolean select() {
        synchronized (mLock) {
            final String methodStr = "select";
            if (!checkISupplicantStaNetworkAndLogFailure(methodStr)) return false;
            try {
                SupplicantStatus status =  mISupplicantStaNetwork.select();
                return checkStatusAndLogFailure(status, methodStr);
            } catch (RemoteException e) {
                handleRemoteException(e, methodStr);
                return false;
            }
        }
    }

wpa_suoppliant处理完保存往网络的任务后,又回到发framework层,还是继续通过HIDL通信将任务下发到C++

->sta_network.cpp  HIDL接口实现文件


Return<void> StaNetwork::select(select_cb _hidl_cb)
{
	return validateAndCall(
	    this, SupplicantStatusCode::FAILURE_NETWORK_INVALID,
	    &StaNetwork::selectInternal, _hidl_cb);
}
 
SupplicantStatus StaNetwork::selectInternal()
{
	struct wpa_ssid *wpa_ssid = retrieveNetworkPtr();
	if (wpa_ssid->disabled == 2) {
		return {SupplicantStatusCode::FAILURE_UNKNOWN, ""};
	}
	struct wpa_supplicant *wpa_s = retrieveIfacePtr();
	wpa_s->scan_min_time.sec = 0;
	wpa_s->scan_min_time.usec = 0;
	wpa_supplicant_select_network(wpa_s, wpa_ssid);
	return {SupplicantStatusCode::SUCCESS, ""};
}
/**
 * wpa_supplicant_select_network - Attempt association with a network
 * @wpa_s: wpa_supplicant structure for a network interface
 * @ssid: wpa_ssid structure for a configured network or %NULL for any network
 */
void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
				   struct wpa_ssid *ssid)
{
 
	struct wpa_ssid *other_ssid;
	int disconnected = 0;
 
	if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
		if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
			wpa_s->own_disconnect_req = 1;
		wpa_supplicant_deauthenticate(
			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
		disconnected = 1;
	}
//若当前已连接或正处于连接状态,则取消当前连接,方便进行最新下发的连接请求
 
	if (ssid)
		wpas_clear_temp_disabled(wpa_s, ssid, 1);
 
	/*
	 * Mark all other networks disabled or mark all networks enabled if no
	 * network specified.
	 */
	for (other_ssid = wpa_s->conf->ssid; other_ssid;
	     other_ssid = other_ssid->next) {
		int was_disabled = other_ssid->disabled;
		if (was_disabled == 2)
			continue; /* do not change persistent P2P group data */
 
		other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
		if (was_disabled && !other_ssid->disabled)
			wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
 
		if (was_disabled != other_ssid->disabled)
			wpas_notify_network_enabled_changed(wpa_s, other_ssid);
	}
//禁用其他所有网络或者当ssid为空时启用所有网络
	if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid &&
	    wpa_s->wpa_state >= WPA_AUTHENTICATING) {
		/* We are already associated with the selected network */
		wpa_printf(MSG_DEBUG, "Already associated with the "
			   "selected network - do nothing");
		return;
	}
//若当前要连接的网络已经开始连接,则直接返回
	if (ssid) {
		wpa_s->current_ssid = ssid;
		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
		wpa_s->connect_without_scan =
			(ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
 
		/*
		 * Don't optimize next scan freqs since a new ESS has been
		 * selected.
		 */
		os_free(wpa_s->next_scan_freqs);
		wpa_s->next_scan_freqs = NULL;
	} else {
		wpa_s->connect_without_scan = NULL;
	}
 
	wpa_s->disconnected = 0;
	wpa_s->reassociate = 1;
 
	if (wpa_s->connect_without_scan ||
	    wpa_supplicant_fast_associate(wpa_s) != 1) {
		wpa_s->scan_req = NORMAL_SCAN_REQ;
		wpas_scan_reset_sched_scan(wpa_s);
		wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
	}
 
	if (ssid)
		wpas_notify_network_selected(wpa_s, ssid);
}

1、wpa_s->connect_without_scan =(ssid->mode == WPAS_MODE_MESH) ? ssid : NULL

这里的ssid->mode 指的是mode - IEEE 802.11 operation mode (Infrastucture/IBSS),代表网络模式。

	/**
	 * mode - IEEE 802.11 operation mode (Infrastucture/IBSS)
	 *
	 * 0 = infrastructure (Managed) mode, i.e., associate with an AP.
//https://baike.baidu.com/item/infrastructure/7975967?fr=aladdin
//基础结构
基础设施;基础建设;也是是无线站点STA的一种工作模式;另外一种工作模式是Ad-hoc 模式。
Infrastructure模式无线局域网是指通过AP互连工作模式,把AP看做传统局域网中集线器功能。
类似传统有线星型拓扑方案,此种模式需要有一台符合IEEE 802.11b/g模式的AP或无线路由器存在,所有通信通过AP或无线路由器作连接,就如同有线网络下利用集线器来作连接,该模式下的无线网可以通过AP或无线路由器的以太网口与有线网相连。此种方式是大家最为经常用到的方式。
区别:
1:Infrastructure基础架构是需要固定的中心控制的,但AD-HOC不需要;
2:自组织能力差,AD-HOC可实现自我接入网络的能力;
3:在实现多条路由的功能时,AD-HOC只需要普通的路由节点即可实现,而Infrastructure需要专用的路由器完成;
4:拓扑结构:Infrastructure一般是传统的拓扑形式,如 星型,环形等,但是静态设置的;而AD-HOC是动态实现的。
	 *
	 * 1 = IBSS (ad-hoc, peer-to-peer)
https://baike.baidu.com/item/IBSS/2634980?fr=aladdin
"IBSS(Independent Basic Service Set)独立基本服务集,IBSS是一种无线拓扑结构,IEEE802.11标准的模式·IBSS模式,又称作独立广播卫星服务,也称为特设模式,是专为点对点连接。
IBSS模式没有无线基础设施骨干,但至少需要2台wireless station。
特设模式,让用户自发地形成一个无线局域网。为了分享文件,如演示图表和电子表格,我们可以轻易把手上网卡,以特设方式,在会议室迅速建立一个小型无线局域网。"
	 *
	 * 2 = AP (access point)
	 *
	 * 3 = P2P Group Owner (can be set in the configuration file)
	 *
	 * 4 = P2P Group Formation (used internally; not in configuration
	 * files)
	 *
	 * 5 = Mesh
https://baike.baidu.com/item/mesh
"Mesh网络即”无线网格网络”,它是“多跳(multi-hop)”网络,是由ad hoc网络发展而来,是解决“最后一公里”问题的关键技术之一。在向下一代网络演进的过程中,无线是一个不可缺的技术。无线mesh可以与其它网络协同通信。是一个动态的可以不断扩展的网络架构,任意的两个设备均可以保持无线互联。"
A mesh network (or simply meshnet) is a local network topology in which the infrastructure nodes (i.e. bridges, switches and other infrastructure devices) connect directly, dynamically and non-hierarchically to as many other nodes as possible and cooperate with one another to efficiently route data from/to clients. This lack of dependency on one node allows for every node to participate in the relay of information. Mesh networks dynamically self-organize and self-configure, which can reduce installation overhead. The ability to self-configure enables dynamic distribution of workloads, particularly in the event that a few nodes should fail. This in turn contributes to fault-tolerance and reduced maintenance costs.
	 *
	 * Note: IBSS can only be used with key_mgmt NONE (plaintext and static
	 * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE
	 * (fixed group key TKIP/CCMP) is available for backwards compatibility,
	 * but its use is deprecated. WPA-None requires following network block
	 * options: proto=WPA, key_mgmt=WPA-NONE, pairwise=NONE, group=TKIP (or
	 * CCMP, but not both), and psk must also be set (either directly or
	 * using ASCII passphrase).
	 */
	enum wpas_mode {
		WPAS_MODE_INFRA = 0,
		WPAS_MODE_IBSS = 1,
		WPAS_MODE_AP = 2,
		WPAS_MODE_P2P_GO = 3,
		WPAS_MODE_P2P_GROUP_FORMATION = 4,
		WPAS_MODE_MESH = 5,
	} mode

网络初始化wpa_config_set_network_defaults(config.c)的时候未对mode进行特殊赋值,所以网络默认mode为WPAS_MODE_INFRA,这意味着wpa_s->connect_without_scan将被赋值为NULL,

if (wpa_s->connect_without_scan ||
	    wpa_supplicant_fast_associate(wpa_s) != 1) {
		wpa_s->scan_req = NORMAL_SCAN_REQ;
		wpas_scan_reset_sched_scan(wpa_s);
		wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
	}

从这段逻辑来看mesh模式是不需要基于搜索结果的,其他模式需要基于搜索结果,即普通连接wpa_supplicant_fast_associate是会被执行的,当associate失败,会再次扫描

->/external/wpa_supplicant8/wpa_supplicat/events.c

int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s)
{
#ifdef CONFIG_NO_SCAN_PROCESSING
	return -1;
#else /* CONFIG_NO_SCAN_PROCESSING */
	struct os_reltime now;
 
	wpa_s->ignore_post_flush_scan_res = 0;
 
	if (wpa_s->last_scan_res_used == 0)
		return -1;
 
	os_get_reltime(&now);
	if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) {
		wpa_printf(MSG_DEBUG, "Fast associate: Old scan results");
		return -1;
	}
 
	return wpas_select_network_from_last_scan(wpa_s, 0, 1);
#endif /* CONFIG_NO_SCAN_PROCESSING */
}

看下什么情况下会打印" Fast associate: Old scan results " 从log看应该是对扫描结果是否有效的判断。


static inline int os_reltime_expired(struct os_reltime *now,
				     struct os_reltime *ts,
				     os_time_t timeout_secs)
{
	struct os_reltime age;
 
	os_reltime_sub(now, ts, &age);
	return (age.sec > timeout_secs) ||
	       (age.sec == timeout_secs && age.usec > 0);
}
 
static inline void os_reltime_sub(struct os_reltime *a, struct os_reltime *b,
				  struct os_reltime *res)
{
	res->sec = a->sec - b->sec;
	res->usec = a->usec - b->usec;
	if (res->usec < 0) {
		res->sec--;
		res->usec += 1000000;
	}

sec是指秒,usec是指μs,这段逻辑简单来说就是连接时机如果是在最新的一次扫描结果5s之后下发,就被认为是旧的扫描结果,不继续下发连接指令,也就是说扫描结果的有效性是5s。

接着继续看选择网络的流程

->wpas_select_network_from_last_scan(wpas,0,1)


static int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s,
					      int new_scan, int own_request)
{
	struct wpa_bss *selected;
	struct wpa_ssid *ssid = NULL;
	int time_to_reenable = wpas_reenabled_network_time(wpa_s);
 
	if (time_to_reenable > 0) {
		wpa_dbg(wpa_s, MSG_DEBUG,
			"Postpone network selection by %d seconds since all networks are disabled",
			time_to_reenable);
		eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL);
		eloop_register_timeout(time_to_reenable, 0,
				       wpas_network_reenabled, wpa_s, NULL);
		return 0;
	}
 
	if (wpa_s->p2p_mgmt)
		return 0; /* no normal connection on p2p_mgmt interface */
 
	selected = wpa_supplicant_pick_network(wpa_s, &ssid);
 
#ifdef CONFIG_MESH
	if (wpa_s->ifmsh) {
		wpa_msg(wpa_s, MSG_INFO,
			"Avoiding join because we already joined a mesh group");
		return 0;
	}
#endif /* CONFIG_MESH */
 
	if (selected) {
		int skip;
		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
		if (skip) {
			if (new_scan)
				wpa_supplicant_rsn_preauth_scan_results(wpa_s);
			return 0;
		}
 
		if (ssid != wpa_s->current_ssid &&
		    wpa_s->wpa_state >= WPA_AUTHENTICATING) {
			wpa_s->own_disconnect_req = 1;
			wpa_supplicant_deauthenticate(
				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
		}
 
		if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) {
			wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
			return -1;
		}
		if (new_scan)
			wpa_supplicant_rsn_preauth_scan_results(wpa_s);
		/*
		 * Do not allow other virtual radios to trigger operations based
		 * on these scan results since we do not want them to start
		 * other associations at the same time.
		 */
		return 1;
	} else {
		wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
		ssid = wpa_supplicant_pick_new_network(wpa_s);
		if (ssid) {
			wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
			wpa_supplicant_associate(wpa_s, NULL, ssid);
			if (new_scan)
				wpa_supplicant_rsn_preauth_scan_results(wpa_s);
		} else if (own_request) {
			/*
			 * No SSID found. If SCAN results are as a result of
			 * own scan request and not due to a scan request on
			 * another shared interface, try another scan.
			 */
			int timeout_sec = wpa_s->scan_interval;
			int timeout_usec = 0;
#ifdef CONFIG_P2P
			int res;
 
			res = wpas_p2p_scan_no_go_seen(wpa_s);
			if (res == 2)
				return 2;
			if (res == 1)
				return 0;
 
			if (wpa_s->p2p_in_provisioning ||
			    wpa_s->show_group_started ||
			    wpa_s->p2p_in_invitation) {
				/*
				 * Use shorter wait during P2P Provisioning
				 * state and during P2P join-a-group operation
				 * to speed up group formation.
				 */
				timeout_sec = 0;
				timeout_usec = 250000;
				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
							    timeout_usec);
				return 0;
			}
#endif /* CONFIG_P2P */
#ifdef CONFIG_INTERWORKING
			if (wpa_s->conf->auto_interworking &&
			    wpa_s->conf->interworking &&
			    wpa_s->conf->cred) {
				wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: "
					"start ANQP fetch since no matching "
					"networks found");
				wpa_s->network_select = 1;
				wpa_s->auto_network_select = 1;
				interworking_start_fetch_anqp(wpa_s);
				return 1;
			}
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_WPS
			if (wpa_s->after_wps > 0 || wpas_wps_searching(wpa_s)) {
				wpa_dbg(wpa_s, MSG_DEBUG, "Use shorter wait during WPS processing");
				timeout_sec = 0;
				timeout_usec = 500000;
				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
							    timeout_usec);
				return 0;
			}
#endif /* CONFIG_WPS */
			if (wpa_supplicant_req_sched_scan(wpa_s))
				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
							    timeout_usec);
 
			wpa_msg_ctrl(wpa_s, MSG_INFO,
				     WPA_EVENT_NETWORK_NOT_FOUND);
		}
	}
	return 0;

}

 

->wpa_supplicant_connect


int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
			   struct wpa_bss *selected,
			   struct wpa_ssid *ssid)
{
	if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
			"PBC session overlap");
		wpas_notify_wps_event_pbc_overlap(wpa_s);
#ifdef CONFIG_P2P
		if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT ||
		    wpa_s->p2p_in_provisioning) {
			eloop_register_timeout(0, 0, wpas_p2p_pbc_overlap_cb,
					       wpa_s, NULL);
			return -1;
		}
#endif /* CONFIG_P2P */
 
#ifdef CONFIG_WPS
		wpas_wps_pbc_overlap(wpa_s);
		wpas_wps_cancel(wpa_s);
#endif /* CONFIG_WPS */
		return -1;
	}
 
	wpa_msg(wpa_s, MSG_DEBUG,
		"Considering connect request: reassociate: %d  selected: "
		MACSTR "  bssid: " MACSTR "  pending: " MACSTR
		"  wpa_state: %s  ssid=%p  current_ssid=%p",
		wpa_s->reassociate, MAC2STR(selected->bssid),
		MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
		wpa_supplicant_state_txt(wpa_s->wpa_state),
		ssid, wpa_s->current_ssid);
 
	/*
	 * Do not trigger new association unless the BSSID has changed or if
	 * reassociation is requested. If we are in process of associating with
	 * the selected BSSID, do not trigger new attempt.
	 */
	if (wpa_s->reassociate ||
	    (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
	     ((wpa_s->wpa_state != WPA_ASSOCIATING &&
	       wpa_s->wpa_state != WPA_AUTHENTICATING) ||
	      (!is_zero_ether_addr(wpa_s->pending_bssid) &&
	       os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
	       0) ||
	      (is_zero_ether_addr(wpa_s->pending_bssid) &&
	       ssid != wpa_s->current_ssid)))) {
		if (wpa_supplicant_scard_init(wpa_s, ssid)) {
			wpa_supplicant_req_new_scan(wpa_s, 10, 0);
			return 0;
		}
		wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR,
			MAC2STR(selected->bssid));
		wpa_supplicant_associate(wpa_s, selected, ssid);
	} else {
		wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to "
			"connect with the selected AP");
	}
 
	return 0;
}

-> wpa_supplicant_associate

/**
 * wpa_supplicant_associate - Request association
 * @wpa_s: Pointer to wpa_supplicant data
 * @bss: Scan results for the selected BSS, or %NULL if not available
 * @ssid: Configuration data for the selected network
 *
 * This function is used to request %wpa_supplicant to associate with a BSS.
 */
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
			      struct wpa_bss *bss, struct wpa_ssid *ssid)
{
	struct wpa_connect_work *cwork;
	int rand_style;
 
	wpa_s->own_disconnect_req = 0;
 
	/*
	 * If we are starting a new connection, any previously pending EAPOL
	 * RX cannot be valid anymore.
	 */
	wpabuf_free(wpa_s->pending_eapol_rx);
	wpa_s->pending_eapol_rx = NULL;
 
	if (ssid->mac_addr == -1)
		rand_style = wpa_s->conf->mac_addr;
	else
		rand_style = ssid->mac_addr;
 
	wmm_ac_clear_saved_tspecs(wpa_s);
	wpa_s->reassoc_same_bss = 0;
	wpa_s->reassoc_same_ess = 0;
#ifdef CONFIG_TESTING_OPTIONS
	wpa_s->testing_resend_assoc = 0;
#endif /* CONFIG_TESTING_OPTIONS */
 
	if (wpa_s->last_ssid == ssid) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
		wpa_s->reassoc_same_ess = 1;
		if (wpa_s->current_bss && wpa_s->current_bss == bss) {
			wmm_ac_save_tspecs(wpa_s);
			wpa_s->reassoc_same_bss = 1;
		}
	}
 
	if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
		if (wpas_update_random_addr(wpa_s, rand_style) < 0)
			return;
		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
	} else if (rand_style == 0 && wpa_s->mac_addr_changed) {
		if (wpa_drv_set_mac_addr(wpa_s, NULL) < 0) {
			wpa_msg(wpa_s, MSG_INFO,
				"Could not restore permanent MAC address");
			return;
		}
		wpa_s->mac_addr_changed = 0;
		if (wpa_supplicant_update_mac_addr(wpa_s) < 0) {
			wpa_msg(wpa_s, MSG_INFO,
				"Could not update MAC address information");
			return;
		}
		wpa_msg(wpa_s, MSG_DEBUG, "Using permanent MAC address");
	}
	wpa_s->last_ssid = ssid;
 
#ifdef CONFIG_IBSS_RSN
	ibss_rsn_deinit(wpa_s->ibss_rsn);
	wpa_s->ibss_rsn = NULL;
#else /* CONFIG_IBSS_RSN */
	if (ssid->mode == WPAS_MODE_IBSS &&
	    !(ssid->key_mgmt & (WPA_KEY_MGMT_NONE | WPA_KEY_MGMT_WPA_NONE))) {
		wpa_msg(wpa_s, MSG_INFO,
			"IBSS RSN not supported in the build");
		return;
	}
#endif /* CONFIG_IBSS_RSN */
 
	if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
	    ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
#ifdef CONFIG_AP
		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
			wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP "
				"mode");
			return;
		}
		if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
			if (ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
				wpas_p2p_ap_setup_failed(wpa_s);
			return;
		}
		wpa_s->current_bss = bss;
#else /* CONFIG_AP */
		wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
			"the build");
#endif /* CONFIG_AP */
		return;
	}
 
	if (ssid->mode == WPAS_MODE_MESH) {
#ifdef CONFIG_MESH
		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
			wpa_msg(wpa_s, MSG_INFO,
				"Driver does not support mesh mode");
			return;
		}
		if (bss)
			ssid->frequency = bss->freq;
		if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
			wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
			return;
		}
		wpa_s->current_bss = bss;
		wpa_msg(wpa_s, MSG_INFO, MESH_GROUP_STARTED "ssid=\"%s\" id=%d",
			wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
			ssid->id);
		wpas_notify_mesh_group_started(wpa_s, ssid);
#else /* CONFIG_MESH */
		wpa_msg(wpa_s, MSG_ERROR,
			"mesh mode support not included in the build");
#endif /* CONFIG_MESH */
		return;
	}
 
	/*
	 * Set WPA state machine configuration to match the selected network now
	 * so that the information is available before wpas_start_assoc_cb()
	 * gets called. This is needed at least for RSN pre-authentication where
	 * candidate APs are added to a list based on scan result processing
	 * before completion of the first association.
	 */
	wpa_supplicant_rsn_supp_set_config(wpa_s, ssid);
 
#ifdef CONFIG_DPP
	if (wpas_dpp_check_connect(wpa_s, ssid, bss) != 0)
		return;
#endif /* CONFIG_DPP */
 
#ifdef CONFIG_TDLS
	if (bss)
		wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
				bss->ie_len);
#endif /* CONFIG_TDLS */
 
	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
	    ssid->mode == IEEE80211_MODE_INFRA) {
		sme_authenticate(wpa_s, bss, ssid);
		return;
	}
 
	if (wpa_s->connect_work) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since connect_work exist");
		return;
	}
 
	if (radio_work_pending(wpa_s, "connect")) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Reject wpa_supplicant_associate() call since pending work exist");
		return;
	}
 
#ifdef CONFIG_SME
	if (ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) {
		/* Clear possibly set auth_alg, if any, from last attempt. */
		wpa_s->sme.auth_alg = WPA_AUTH_ALG_OPEN;
	}
#endif /* CONFIG_SME */
 
	wpas_abort_ongoing_scan(wpa_s);
 
	cwork = os_zalloc(sizeof(*cwork));
	if (cwork == NULL)
		return;
 
	cwork->bss = bss;
	cwork->ssid = ssid;
 
	if (radio_add_work(wpa_s, bss ? bss->freq : 0, "connect", 1,
			   wpas_start_assoc_cb, cwork) < 0) {
		os_free(cwork);
	}
}

->radio_add_work 里面带了一个wpa_start_assoc_cb的参数

先看radio_add_work


/**
 * radio_add_work - Add a radio work item
 * @wpa_s: Pointer to wpa_supplicant data
 * @freq: Frequency of the offchannel operation in MHz or 0
 * @type: Unique identifier for each type of work
 * @next: Force as the next work to be executed
 * @cb: Callback function for indicating when radio is available
 * @ctx: Context pointer for the work (work->ctx in cb())
 * Returns: 0 on success, -1 on failure
 *
 * This function is used to request time for an operation that requires
 * exclusive radio control. Once the radio is available, the registered callback
 * function will be called. radio_work_done() must be called once the exclusive
 * radio operation has been completed, so that the radio is freed for other
 * operations. The special case of deinit=1 is used to free the context data
 * during interface removal. That does not allow the callback function to start
 * the radio operation, i.e., it must free any resources allocated for the radio
 * work and return.
 *
 * The @freq parameter can be used to indicate a single channel on which the
 * offchannel operation will occur. This may allow multiple radio work
 * operations to be performed in parallel if they apply for the same channel.
 * Setting this to 0 indicates that the work item may use multiple channels or
 * requires exclusive control of the radio.
 */
int radio_add_work(struct wpa_supplicant *wpa_s, unsigned int freq,
		   const char *type, int next,
		   void (*cb)(struct wpa_radio_work *work, int deinit),
		   void *ctx)
{
	struct wpa_radio *radio = wpa_s->radio;
	struct wpa_radio_work *work;
	int was_empty;
 
	work = os_zalloc(sizeof(*work));
	if (work == NULL)
		return -1;
	wpa_dbg(wpa_s, MSG_DEBUG, "Add radio work '%s'@%p", type, work);
	os_get_reltime(&work->time);
	work->freq = freq;
	work->type = type;
	work->wpa_s = wpa_s;
	work->cb = cb;
	work->ctx = ctx;
 
	if (freq)
		work->bands = wpas_freq_to_band(freq);
	else if (os_strcmp(type, "scan") == 0 ||
		 os_strcmp(type, "p2p-scan") == 0)
		work->bands = wpas_get_bands(wpa_s,
					     ((struct wpa_driver_scan_params *)
					      ctx)->freqs);
	else
		work->bands = wpas_get_bands(wpa_s, NULL);
 
	was_empty = dl_list_empty(&wpa_s->radio->work);
	if (next)
		dl_list_add(&wpa_s->radio->work, &work->list);
	else
		dl_list_add_tail(&wpa_s->radio->work, &work->list);
	if (was_empty) {
		wpa_dbg(wpa_s, MSG_DEBUG, "First radio work item in the queue - schedule start immediately");
		radio_work_check_next(wpa_s);
	} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS)
		   && radio->num_active_works < MAX_ACTIVE_WORKS) {
		wpa_dbg(wpa_s, MSG_DEBUG,
			"Try to schedule a radio work (num_active_works=%u)",
			radio->num_active_works);
		radio_work_check_next(wpa_s);
	}
 
	return 0;
}

->wpa_start_assoc_cb

static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
{
	struct wpa_connect_work *cwork = work->ctx;
	struct wpa_bss *bss = cwork->bss;
	struct wpa_ssid *ssid = cwork->ssid;
	struct wpa_supplicant *wpa_s = work->wpa_s;
	u8 *wpa_ie;
	int use_crypt, ret, i, bssid_changed;
	unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
	struct wpa_driver_associate_params params;
	int wep_keys_set = 0;
	int assoc_failed = 0;
	struct wpa_ssid *old_ssid;
	u8 prev_bssid[ETH_ALEN];
#ifdef CONFIG_HT_OVERRIDES
	struct ieee80211_ht_capabilities htcaps;
	struct ieee80211_ht_capabilities htcaps_mask;
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
       struct ieee80211_vht_capabilities vhtcaps;
       struct ieee80211_vht_capabilities vhtcaps_mask;
#endif /* CONFIG_VHT_OVERRIDES */
 
	if (deinit) {
		if (work->started) {
			wpa_s->connect_work = NULL;
 
			/* cancel possible auth. timeout */
			eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s,
					     NULL);
		}
		wpas_connect_work_free(cwork);
		return;
	}
 
	wpa_s->connect_work = work;
 
	if (cwork->bss_removed || !wpas_valid_bss_ssid(wpa_s, bss, ssid) ||
	    wpas_network_disabled(wpa_s, ssid)) {
		wpa_dbg(wpa_s, MSG_DEBUG, "BSS/SSID entry for association not valid anymore - drop connection attempt");
		wpas_connect_work_done(wpa_s);
		return;
	}
 
	os_memcpy(prev_bssid, wpa_s->bssid, ETH_ALEN);
	os_memset(&params, 0, sizeof(params));
	wpa_s->reassociate = 0;
	wpa_s->eap_expected_failure = 0;
	if (bss &&
	    (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
#ifdef CONFIG_IEEE80211R
		const u8 *ie, *md = NULL;
#endif /* CONFIG_IEEE80211R */
		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
			" (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
			wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
		bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
		os_memset(wpa_s->bssid, 0, ETH_ALEN);
		os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
		if (bssid_changed)
			wpas_notify_bssid_changed(wpa_s);
#ifdef CONFIG_IEEE80211R
		ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
		if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
			md = ie + 2;
		wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
		if (md) {
			/* Prepare for the next transition */
			wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
		}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_WPS
	} else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
		   wpa_s->conf->ap_scan == 2 &&
		   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
		/* Use ap_scan==1 style network selection to find the network
		 */
		wpas_connect_work_done(wpa_s);
		wpa_s->scan_req = MANUAL_SCAN_REQ;
		wpa_s->reassociate = 1;
		wpa_supplicant_req_scan(wpa_s, 0, 0);
		return;
#endif /* CONFIG_WPS */
	} else {
		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
			wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
		if (bss)
			os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
		else
			os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
	}
	if (!wpa_s->pno)
		wpa_supplicant_cancel_sched_scan(wpa_s);
 
	wpa_supplicant_cancel_scan(wpa_s);
 
	/* Starting new association, so clear the possibly used WPA IE from the
	 * previous association. */
	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
 
	wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
	if (!wpa_ie) {
		wpas_connect_work_done(wpa_s);
		return;
	}
 
	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
	use_crypt = 1;
	cipher_pairwise = wpa_s->pairwise_cipher;
	cipher_group = wpa_s->group_cipher;
	cipher_group_mgmt = wpa_s->mgmt_group_cipher;
	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
		if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
			use_crypt = 0;
		if (wpa_set_wep_keys(wpa_s, ssid)) {
			use_crypt = 1;
			wep_keys_set = 1;
		}
	}
	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
		use_crypt = 0;
 
#ifdef IEEE8021X_EAPOL
	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
		if ((ssid->eapol_flags &
		     (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
		      EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 &&
		    !wep_keys_set) {
			use_crypt = 0;
		} else {
			/* Assume that dynamic WEP-104 keys will be used and
			 * set cipher suites in order for drivers to expect
			 * encryption. */
			cipher_pairwise = cipher_group = WPA_CIPHER_WEP104;
		}
	}
#endif /* IEEE8021X_EAPOL */
 
	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
		/* Set the key before (and later after) association */
		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
	}
 
	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
	if (bss) {
		params.ssid = bss->ssid;
		params.ssid_len = bss->ssid_len;
		if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set ||
		    wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
			wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
				   MACSTR " freq=%u MHz based on scan results "
				   "(bssid_set=%d wps=%d)",
				   MAC2STR(bss->bssid), bss->freq,
				   ssid->bssid_set,
				   wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
			params.bssid = bss->bssid;
			params.freq.freq = bss->freq;
		}
		params.bssid_hint = bss->bssid;
		params.freq_hint = bss->freq;
		params.pbss = bss_is_pbss(bss);
	} else {
		if (ssid->bssid_hint_set)
			params.bssid_hint = ssid->bssid_hint;
 
		params.ssid = ssid->ssid;
		params.ssid_len = ssid->ssid_len;
		params.pbss = (ssid->pbss != 2) ? ssid->pbss : 0;
	}
 
	if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
	    wpa_s->conf->ap_scan == 2) {
		params.bssid = ssid->bssid;
		params.fixed_bssid = 1;
	}
 
	/* Initial frequency for IBSS/mesh */
	if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
	    ssid->frequency > 0 && params.freq.freq == 0)
		ibss_mesh_setup_freq(wpa_s, ssid, &params.freq);
 
	if (ssid->mode == WPAS_MODE_IBSS) {
		params.fixed_freq = ssid->fixed_freq;
		if (ssid->beacon_int)
			params.beacon_int = ssid->beacon_int;
		else
			params.beacon_int = wpa_s->conf->beacon_int;
	}
 
	params.pairwise_suite = cipher_pairwise;
	params.group_suite = cipher_group;
	params.mgmt_group_suite = cipher_group_mgmt;
	params.key_mgmt_suite = wpa_s->key_mgmt;
	params.wpa_proto = wpa_s->wpa_proto;
	wpa_s->auth_alg = params.auth_alg;
	params.mode = ssid->mode;
	params.bg_scan_period = ssid->bg_scan_period;
	for (i = 0; i < NUM_WEP_KEYS; i++) {
		if (ssid->wep_key_len[i])
			params.wep_key[i] = ssid->wep_key[i];
		params.wep_key_len[i] = ssid->wep_key_len[i];
	}
	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
 
	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
	    (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;
	}
 
	if (wpa_s->conf->key_mgmt_offload) {
		if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
			params.req_key_mgmt_offload =
				ssid->proactive_key_caching < 0 ?
				wpa_s->conf->okc : ssid->proactive_key_caching;
		else
			params.req_key_mgmt_offload = 1;
 
		if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
		     params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
		     params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
		    ssid->psk_set)
			params.psk = ssid->psk;
	}
 
	params.drop_unencrypted = use_crypt;
 
#ifdef CONFIG_IEEE80211W
	params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid);
	if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
		struct wpa_ie_data ie;
		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
		    ie.capabilities &
		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports "
				"MFP: require MFP");
			params.mgmt_frame_protection =
				MGMT_FRAME_PROTECTION_REQUIRED;
		}
	}
#endif /* CONFIG_IEEE80211W */
 
	params.p2p = ssid->p2p_group;
 
	if (wpa_s->p2pdev->set_sta_uapsd)
		params.uapsd = wpa_s->p2pdev->sta_uapsd;
	else
		params.uapsd = -1;
 
#ifdef CONFIG_HT_OVERRIDES
	os_memset(&htcaps, 0, sizeof(htcaps));
	os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
	params.htcaps = (u8 *) &htcaps;
	params.htcaps_mask = (u8 *) &htcaps_mask;
	wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_HT_OVERRIDES */
#ifdef CONFIG_VHT_OVERRIDES
	os_memset(&vhtcaps, 0, sizeof(vhtcaps));
	os_memset(&vhtcaps_mask, 0, sizeof(vhtcaps_mask));
	params.vhtcaps = &vhtcaps;
	params.vhtcaps_mask = &vhtcaps_mask;
	wpa_supplicant_apply_vht_overrides(wpa_s, ssid, &params);
#endif /* CONFIG_VHT_OVERRIDES */
 
#ifdef CONFIG_P2P
	/*
	 * If multi-channel concurrency is not supported, check for any
	 * frequency conflict. In case of any frequency conflict, remove the
	 * least prioritized connection.
	 */
	if (wpa_s->num_multichan_concurrent < 2) {
		int freq, num;
		num = get_shared_radio_freqs(wpa_s, &freq, 1);
		if (num > 0 && freq > 0 && freq != params.freq.freq) {
			wpa_printf(MSG_DEBUG,
				   "Assoc conflicting freq found (%d != %d)",
				   freq, params.freq.freq);
			if (wpas_p2p_handle_frequency_conflicts(
				    wpa_s, params.freq.freq, ssid) < 0) {
				wpas_connect_work_done(wpa_s);
				os_free(wpa_ie);
				return;
			}
		}
	}
#endif /* CONFIG_P2P */
 
	if (wpa_s->reassoc_same_ess && !is_zero_ether_addr(prev_bssid) &&
	    wpa_s->current_ssid)
		params.prev_bssid = prev_bssid;
 
	ret = wpa_drv_associate(wpa_s, &params);
	os_free(wpa_ie);
	if (ret < 0) {
		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
			"failed");
		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) {
			/*
			 * The driver is known to mean what is saying, so we
			 * can stop right here; the association will not
			 * succeed.
			 */
			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
			os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
			return;
		}
		/* try to continue anyway; new association will be tried again
		 * after timeout */
		assoc_failed = 1;
	}
 
	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
		/* Set the key after the association just in case association
		 * cleared the previously configured key. */
		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
		/* No need to timeout authentication since there is no key
		 * management. */
		wpa_supplicant_cancel_auth_timeout(wpa_s);
		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
#ifdef CONFIG_IBSS_RSN
	} else if (ssid->mode == WPAS_MODE_IBSS &&
		   wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
		   wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
		/*
		 * RSN IBSS authentication is per-STA and we can disable the
		 * per-BSSID authentication.
		 */
		wpa_supplicant_cancel_auth_timeout(wpa_s);
#endif /* CONFIG_IBSS_RSN */
	} else {
		/* Timeout for IEEE 802.11 authentication and association */
		int timeout = 60;
 
		if (assoc_failed) {
			/* give IBSS a bit more time */
			timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5;
		} else if (wpa_s->conf->ap_scan == 1) {
			/* give IBSS a bit more time */
			timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10;
		}
		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
	}
 
	if (wep_keys_set &&
	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) {
		/* Set static WEP keys again */
		wpa_set_wep_keys(wpa_s, ssid);
	}
 
	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
		/*
		 * Do not allow EAP session resumption between different
		 * network configurations.
		 */
		eapol_sm_invalidate_cached_session(wpa_s->eapol);
	}
	old_ssid = wpa_s->current_ssid;
	wpa_s->current_ssid = ssid;
 
	if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
		wpa_s->current_bss = bss;
#ifdef CONFIG_HS20
		hs20_configure_frame_filters(wpa_s);
#endif /* CONFIG_HS20 */
	}
 
	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
	wpa_supplicant_initiate_eapol(wpa_s);
	if (old_ssid != wpa_s->current_ssid)
		wpas_notify_network_changed(wpa_s);
}

 

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值