WiFi 连接过程

20 篇文章 5 订阅

1. 在 WifiNative 类中 connectNetwork 被调用用于连接,其主要工作为停止当前扫描过程,删除 wpa_supplicant 中的网络配置信息,并将新的配置传送给 wpa_supplicant 保存,这会触发对已有配置网络的 disconnect 操作,最后触发 reconnect 操作到 wpa_supplicant:

    /**
     * Add the provided network configuration to wpa_supplicant and initiate connection to it.
     * This method does the following:
     * 1. Abort any ongoing scan to unblock the connection request.
     * 2. Remove any existing network in wpa_supplicant(This implicitly triggers disconnect).
     * 3. Add a new network to wpa_supplicant.
     * 4. Save the provided configuration to wpa_supplicant.
     * 5. Select the new network in wpa_supplicant.
     * 6. Triggers reconnect command to wpa_supplicant.
     *
     * @param ifaceName Name of the interface.
     * @param configuration WifiConfiguration parameters for the provided network.
     * @return {@code true} if it succeeds, {@code false} otherwise
     */
    public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
        // Abort ongoing scan before connect() to unblock connection request.
        mWifiCondManager.abortScan(ifaceName);
        return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
    }

2. SupplicantStaIfaceHal 类中的 connectToNetwork 方法被调用:

    /**
     * Add the provided network configuration to wpa_supplicant and initiate connection to it.
     * This method does the following:
     * 1. If |config| is different to the current supplicant network, removes all supplicant
     * networks and saves |config|.
     * 2. Select the new network in wpa_supplicant.
     *
     * @param ifaceName Name of the interface.
     * @param config WifiConfiguration parameters for the provided network.
     * @return {@code true} if it succeeds, {@code false} otherwise
     */
    public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
        synchronized (mLock) {
            logd("connectToNetwork " + config.getKey());
            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 { /* 新旧配置对应的网络部是同一个,也有可能存在一个配置是 null */
                /* 删除 HashMap 中 ifaceName 对应的配置 */
                mCurrentNetworkRemoteHandles.remove(ifaceName);
                /* 删除 HashMap 中 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.getKey());
                    return false;
                }
                mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
                mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
            }
            SupplicantStaNetworkHal networkHandle =
                    checkSupplicantStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
            if (networkHandle == null) {
                loge("No valid remote network handle for network configuration: "
                        + config.getKey());
                return false;
            }

            PmkCacheStoreData pmkData = mPmkCacheEntries.get(config.networkId);
            if (pmkData != null
                    && !WifiConfigurationUtil.isConfigForPskNetwork(config)
                    && pmkData.expirationTimeInSec > mClock.getElapsedSinceBootMillis() / 1000) {
                logi("Set PMK cache for config id " + config.networkId);
                if (networkHandle.setPmkCache(pmkData.data)) {
                    mWifiMetrics.setConnectionPmkCache(true);
                }
            }

            if (!networkHandle.select()) {
                loge("Failed to select network configuration: " + config.getKey());
                return false;
            }
            return true;
        }
    }

3. 假设一开始配置为空,新增加了一条配置,则会进入 else 操作,重点进行分析,首先来看 removeAllNetworks 接口的操作:

    /**
     * Remove all networks from supplicant
     *
     * @param ifaceName Name of the interface.
     */
    public boolean removeAllNetworks(@NonNull String ifaceName) {
        synchronized (mLock) {
            ArrayList<Integer> networks = listNetworks(ifaceName);
            if (networks == null) {
                Log.e(TAG, "removeAllNetworks failed, got null networks");
                return false;
            }
            for (int id : networks) {
                if (!removeNetwork(ifaceName, id)) {
                    Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
                    return false;
                }
            }
            // Reset current network info.  Probably not needed once we add support to remove/reset
            // current network on receiving disconnection event from supplicant (b/32898136).
            mCurrentNetworkRemoteHandles.remove(ifaceName);
            mCurrentNetworkLocalConfigs.remove(ifaceName);
            return true;
        }
    }

4. 进而来看 listNetworks,因为这里面我们会进入到底层 Hal 以及 wpa_supplicant 的操作过程:

    /**
     * @return a list of SupplicantNetworkID ints for all networks controlled by supplicant, returns
     * null if the call fails
     */
    private java.util.ArrayList<Integer> listNetworks(@NonNull String ifaceName) {
        synchronized (mLock) {
            final String methodStr = "listNetworks";
            ISupplicantStaIface iface = checkSupplicantStaIfaceAndLogFailure(ifaceName, methodStr);
            if (iface == null) return null;
            Mutable<ArrayList<Integer>> networkIdList = new Mutable<>();
            try {
                iface.listNetworks((SupplicantStatus status, ArrayList<Integer> networkIds) -> {
                    if (checkStatusAndLogFailure(status, methodStr)) {
                        networkIdList.value = networkIds;
                    }
                });
            } catch (RemoteException e) {
                handleRemoteException(e, methodStr);
            }
            return networkIdList.value;
        }
    }

① ISupplicantStaIface 定义在 hardware/interfaces/wifi/supplicant/1.0/ISupplicantStaIface.hal 文件中,继承自 ISupplicantIface,定义在 hardware/interfaces/wifi/supplicant/1.0/ISupplicantIface.hal 文件中,在经过 HIDL 转化之后 Native 代码实现在 external/wpa_supplicant_8/wpa_supplicant/hidl/ 目录下,而 ISupplicantStaIface 对应的 cpp 实现是 StaIface 类,定义在 sta_iface.h,实现在 sta_iface.cpp

② 上面在 framework 层的实际处理过程会进入到 HIDL 转化后的服务层 Native 代码中,进而调用到 wpa_supplicant 中的接口展开响应的操作;

③ 通过 checkSupplicantStaIfaceAndLogFailure 获取到 iface 对象,调用其 listNetworks 进而进入到 Native 层的对应接口 StaIface::listNetworks,进一步调用 listNetworksInternal;

④ listNetworksInternal 等内部操作通过 struct wpa_supplicant 对象来获取相应的信息,这些信息即为底层 wpa_supplicant 内部维护的内容,每个 struct wpa_supplicant 对应一个 iface;

5. struct wpa_supplicant 的信息管理由 struct wpa_global 统一进行,而 struct wpa_global 是在 wpa_supplicant 初始化的时候由 wpa_supplicant_init() 进行初始化的,而 wpa_supplicant_init 则是直接在 main 函数中被调用,它完成了如下操作:

① wpa_supplicant_init 初始化之后进行 wpas_notify_supplicant_initialized 以告知所有可能的控制途径 wpa_global 已经初始化完成;

② 如果定义了 CONFIG_HIDL 则 wpas_notify_supplicant_initialized 会调用 wpas_hidl_init 初始化其类型为 struct wpas_hidl_priv 的 hidl 对象;

③ wpas_hidl_init 分配对应的对象并采用 wpa_global 进行其初始化,而这里面非常重要的一步是通过 HidlManager 的 registerHidlService 方法来注册 wpa_supplicant 对应的 HIDL 服务,在这里创建了 Supplicant 类对象,以初始化后的 wpa_global 类型的 global 为参数;

④ 可以看到在 wpa_supplicant 的管理过程中如前面需要获取网络配置对应的 struct wpa_supplicat 对象,调用了 wpa_supplicant_get_iface,都是需要以 struct wpa_global 为参数进行的

6. StaIface 类对象的创建和管理由 Supplicant 进行,创建过程中会将 struct wpa_global 对象作为参数传递,从而如上面我们通过 StaIface 的 listNetworks 方法可以直接调用 wpa_supplicant 内部的公共控制接口并将 struct wpa_global 对象作为参数直接传入;

7. 同样这里查询和操作的对应接口都是在 Supplicant 类中进行创建和管理的,位于 hidl 中的 supplicant.{h,cpp} 进行了定义和实现,如 addInterface 方法,然后调用了 addInterfaceInternal 内部方法,进而调用了 wpa_supplicant 的公共管理接口 wpa_supplicant_add_iface;

8. 返回前面主流程来,在 SupplicantStaIfaceHal 的方法 connectToNetwork 中继续执行 removeAllNetworks,将获取到的 list 进行遍历,依次对其进行 removeNetwork 操作,实际上还是调用了 StaIface 的 removeNetwork 方法进入 wpa_supplicant 进行操作;

9. 删除接口之后开始进入 addNetworkAndSaveConfig 操作:

    /**
     * Add a network configuration to wpa_supplicant.
     *
     * @param config Config corresponding to the network.
     * @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects
     * for the current network.
     */
    private Pair<SupplicantStaNetworkHal, WifiConfiguration>
            addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) {
        synchronized (mLock) {
            logi("addSupplicantStaNetwork via HIDL");
            if (config == null) {
                loge("Cannot add NULL network!");
                return null;
            }
            SupplicantStaNetworkHal network = addNetwork(ifaceName);
            if (network == null) {
                loge("Failed to add a network!");
                return null;
            }
            boolean saveSuccess = false;
            try {
                saveSuccess = network.saveWifiConfiguration(config);
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Exception while saving config params: " + config, e);
            }
            if (!saveSuccess) {
                loge("Failed to save variables for: " + config.getKey());
                if (!removeAllNetworks(ifaceName)) {
                    loge("Failed to remove all networks on failure.");
                }
                return null;
            }
            return new Pair(network, new WifiConfiguration(config));
        }
    }

这里重点是 addNetwork 方法,从此开始由 Iface 类型转换到 Network 类型的操作上,需要返回的是 SupplicantStaNetworkHal 对象,该对象是新创建,包含了 ISupplicantStaNetwork 的 HIDL 客户端对象,Context 信息以及 WifiMonitor 信息,而 ISupplicantStaNetwork 对象是在进行 iface 的 addNetwork 中创建的:

/* sta_iface.cpp,StaIface 类实现 */
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};
}

这里调用 wpa_supplicant_add_network 添加 network,并且通过 HidlManager 的 getStaNetworkHidlObjectByIfnameAndNetworkId 获取到对应的 network 信息返回;

10. network 对应 HIDL 服务端创建过程发生在 HidlManager::registerNetwork 方法中:

/**
 * 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;
}

对应的 StaNetwork 对象呗创建,并且添加到 sta_network_object_map_ 中,而 StaNetwork 类定义和实现在 sta_network.{h,cpp} 中,registerNetwork 是在 wpas_hidl_register_network 中被调用,继而被 wpas_notify_network_added 调用,调用时机是在 wpa_supplicant_add_network 内部添加了对应的 network 之后通知给监听和管理者;从而又回归到前面在分析的 StaIface::addNetworkInternal 中;

11. 继续返回到 Framework 层,addNetwork 创建 SupplicantStaNetworkHal 后将其返回,紧接着通过其 saveWiFiConfiguration 方法进行配置的保存,这里其实是调用了 SupplicantStaNetworkHal 中的接口通过 HIDL 将对应的信息配置到 wpa_supplicant 中维护的对应的 network 中,比如 ssid 信息;

12. 最终创建信息 WifiConfiguration 信息并与 network 配对之后返回 Pair<SupplicantStaNetworkHal, WifiConfiguration> 对象,WiFiConfiguration 对象为根据传递进来的 config 进行初始化的;

13. 再回到 connectToNetwork 中,将返回的 Pair 中两个配置信息分别加入到对应的 HashMap 中(mCurrentNetworkRemoteHandles 和 mCurrentNetworkLocalConfigs),更新缓存信息;

14. 紧接着调用了 SupplicantStaNetworkHal 类的 select 方法进行网络连接,实际上又回到其内部的 SupplicantStaNetwork 类,调用其 select 方法,进而调用到 Native 层 StaNetwork 类的 select 方法,继续回到 sta_network.cpp 中的 selectInternel 方法:

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”,尝试与对应的网络进行协商;

15. wpa_supplicant 连接过程会发生相应的状态变化,对应的变化过程需要通知给上层,而通知的回调则是在 SupplicantStaIfaceHal 类的 setupStaIface 接口中创建 SupplicantStaIface 的过程中注册的:

    /**
     * Helper function to set up StaIface with different HAL version.
     *
     * This helper function would try newer version recursively.
     * Once the latest version is found, it would register the callback
     * of the latest version and skip unnecessary older HAL init flow.
     *
     * New version callback will be extended from the older one, as a result,
     * older callback is always created regardless of the latest version.
     *
     * Uprev steps:
     * 1. add new helper function trySetupStaIfaceV1_Y.
     * 2. call newly added function in trySetupStaIfaceV1_X (X should be Y-1).
     */
    private ISupplicantStaIface setupStaIface(@NonNull String ifaceName,
            @NonNull ISupplicantIface ifaceHwBinder) throws RemoteException {
        /* Prepare base type for later cast. */
        ISupplicantStaIface iface = getStaIfaceMockable(ifaceHwBinder);

        /* try newer version first. */
        if (trySetupStaIfaceV1_1(ifaceName, iface)) {
            logd("Newer HAL is found, skip V1_0 remaining init flow.");
            return iface;
        }

        SupplicantStaIfaceHalCallback callback = new SupplicantStaIfaceHalCallback(ifaceName);
        if (!registerCallback(iface, callback)) {
            throw new RemoteException("Init StaIface V1_0 failed.");
        }
        /* keep this in a store to avoid recycling by garbage collector. */
        mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
        return iface;
    }

对应的网络相关的事件都会通过该回调进行反馈,hardware/interfaces/wifi/supplicant/1.0/ISupplicantStaNetwork.hal 中关于注册接口的说明如下:

  /**  
   * Register for callbacks from this network.
   *
   * These callbacks are invoked for events that are specific to this network.
   * Registration of multiple callback objects is supported. These objects must 
   * be automatically deleted when the corresponding client process is dead or
   * if this network is removed.
   *
   * @param callback An instance of the |ISupplicantStaNetworkCallback| HIDL 
   *        interface object.
   * @return status Status of the operation.
   *         Possible status codes:
   *         |SupplicantStatusCode.SUCCESS|,
   *         |SupplicantStatusCode.FAILURE_UNKNOWN|,
   *         |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
   */   
  registerCallback(ISupplicantStaNetworkCallback callback)
      generates (SupplicantStatus status);

 

Wireshark是一款流行的网络封包分析工具,它可以捕获和分析网络报文。在Wireshark中,我们可以使用它来抓取和分析WiFi连接过程的报文。 WiFi连接过程中涉及到的报文有以下几种: 1. Probe Request(探测请求):这是移动设备发送给周围WiFi网络的广播请求,表示设备想要连接到一个WiFi网络。这个报文包含设备的MAC地址、支持的加密算法等信息。 2. Probe Response(探测回应):当WiFi网络接收到Probe Request时,它会回复一个Probe Response报文。这个报文包含网络的SSID、加密方式、信号强度等信息,以供设备选择连接的网络。 3. Authentication(身份认证):此报文用于设备与WiFi网络之间的身份验证过程。它包含了设备和网络之间的认证协议和密钥等信息。 4. Association Request(关联请求):设备在通过身份验证后,会发送一个关联请求报文来请求与WiFi网络建立关联。这个报文包含设备的MAC地址、接入点的MAC地址等信息。 5. Association Response(关联回应):WiFi网络接收到关联请求后,会回复一个关联响应报文。这个报文包含了连接设备的地址、是否成功关联等信息。 通过分析这些报文,我们可以了解WiFi连接过程中的各种交互细节,例如探测到的网络、连接是否成功、认证协议等。这对于网络管理员和安全研究人员来说都是非常有用的,可以帮助他们分析和解决各种WiFi连接问题,同时也有助于提高WiFi网络的安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值