[Android]Android P(9) WIFI学习笔记 - HAL (1)

前文回顾

前言

  1. 基于Android P源码学习;
  2. 代码片为了方便阅读段经过删、裁减,请以实际源码为准;

入口

根据前两篇的分析结果,调用栈都汇聚到了WifiNative:

打开Wifi:
mWifiNative.setupInterfaceForClientMode(false, mWifiNativeInterfaceCallback)
关闭Wifi:
mWifiNative.teardownInterface(mClientInterfaceName);

因此我们从WifiNative开始;

照例,我仍以“打开Wifi”为例分析(后续会补上“关闭Wifi”的部分,但仅会重点介绍差异部分)

WifiNative

初始化

构造方法只有一个:

    public WifiNative(WifiVendorHal vendorHal,
                      SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal,
                      WificondControl condControl, WifiMonitor wifiMonitor,
                      INetworkManagementService nwService,
                      PropertyService propertyService, WifiMetrics wifiMetrics,
                      Handler handler) {...}

构造WifiNative对象的地方依旧是WifiInjector:

        mWifiNative = new WifiNative(
                mWifiVendorHal, mSupplicantStaIfaceHal, mHostapdHal, mWificondControl,
                mWifiMonitor, mNwManagementService, mPropertyService, mWifiMetrics,
                new Handler(mWifiStateMachineHandlerThread.getLooper()));

这里参数很多,需要逐一介绍下,以便于后续深入HAL的分析:

  • WifiVendorHal:mWifiVendorHal

    • android.hardware.wifi@1.0的HAL实现服务交互的工具类;
  • SupplicantStaIfaceHal:mSupplicantStaIfaceHal

    • android.hardware.wifi.supplicant@1.0的HAL实现服务交互的工具类;
    • 与vendor自定义的,有相关功能的HAL交互,例如vendor.qti.hardware.wifi.supplicant@2.0
  • HostapdHal:mHostapdHal

    • android.hardware.wifi.hostapd@1.0的HAL实现服务交互的工具类;
    • 与vendor自定义的,有相关功能的HAL交互,例如vendor.qti.hardware.wifi.hostapd@1.0
  • WificondControl:mWificondControl

    • 负责通过Binder与wificond进程交互(IWificond
  • WifiMonitor mWifiMonitor

    • 一个负责收集、分发wpa_supplicant状态的工具类;
  • INetworkManagementService:mNwManagementService

    • INetworkManagementService实现类的的客户端实例
  • PropertyService:mPropertyService

    • 类型为PropertyService的接口,实现类型为SystemPropertyService,本质是对android.os.SystemPropertiesget/set方法进行非静态封装;
  • WifiMetrics:mWifiMetrics

    • 用于记录WIFI行为,包括连接、断开事件,已保存网络个数,开放网络个数等的业务类;
  • Handler:new Handler(mWifiStateMachineHandlerThread.getLooper())

    • 用于处理异步消息的Handler

由此可见,负责与HAL交互的,更多是前面4个参数:mWifiVendorHal,mSupplicantStaIfaceHal,mHostapdHal,mWificondControl

关于这些模块的详细分析计划在后期再更新,当前仅着眼于开、关WIFI调用栈的HAL部分;

打开WIFI

即:setupInterfaceForClientMode()

public String setupInterfaceForClientMode(boolean lowPrioritySta,
            @NonNull InterfaceCallback interfaceCallback) {
        synchronized (mLock) {
			...
			/*
			 * mIfaceMgr为IfaceManager的实例对象,内部维护了一个HashMap<Integer, Iface>,
			 * 用于管理Iface的增、删、查等操作;
			 * allocateIface方法即为上述的“增”。
			 * 但是需要注意,这里的“增”只是Framework层面的构造了一个Iface对象并添加到HashMap
			 * 中,并没有发送请求到HAL去真正创建一个Iface。
			 */
            Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA);
			...
            iface.externalListener = interfaceCallback;
            /*
             * 创建Iface名称,如果Vendor HAL不存在,则取属性"wifi.interface"
             * 如果属性没设置,返回"wlan0"
             */
            iface.name = createStaIface(iface, lowPrioritySta);
			...
            /*
             * 通知wificond调用createClientInterface创建iface,返回类型为IClientInterface
             * 的实例对象;
             */
            if (mWificondControl.setupInterfaceForClientMode(iface.name) == null) {
                teardownInterface(iface.name);
                return null;
            }
            /*
             * 根据不同的wpa_supplicant HAL版本决定不同的逻辑:
             *  - v1.1会构造一个ISupplicant.IfaceInfo,并通过addInterface添加到
             *    wpa_supplicant interfaces,并从其返回结果中获取到对应的
             *    ISupplicantIface;
             *  - v1.0会通过listInterfaces获取所有的ISupplicant.IfaceInfo并
             *    遍历,以找到匹配的结果,并再通过getInterface获取对应的
             *    ISupplicantIface;
             * 然后,创建一个事件监听回调,并传递给wpa_supplicant,使其在STA模式
             * 下状态发生改变时会触发回调,而该回调会进一步通知到WifiMonitor;
             * 
             */
            if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
                teardownInterface(iface.name);
                return null;
            }
            iface.networkObserver = new NetworkObserverInternal(iface.id);
            /*
             * 调用INetworkManagementService的registerObserver注册连接状态事件回调
             */
            if (!registerNetworkObserver(iface.networkObserver)) {
                teardownInterface(iface.name);
                return null;
            }
            //注册WifiMonitor回调
            mWifiMonitor.startMonitoring(iface.name);
			//立即上报一次iface的状态;
            onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
            //重置一些状态,包括IPv4地址、IPv6扩展支持等;
            initializeNwParamsForClientInterface(iface.name);
            return iface.name;
        }
    }

调用时序图参考如下:
在这里插入图片描述
可见,打开WIFI的调用过程中,有三个地方需要与HAL交互:

  • IWifiChip.createStaIface()
  • IWificond.createClientInterface()
  • ISupplicant:
    • (V1.1) ISupplicant.addInterface()
    • (V1.0) ISupplicant.listInterfaces() / ISupplicant.getInterfaces()

目前使用的机器走的是V1.1,因此后续以V1.1为例进行分析;

接下来逐一介绍:

IWifiChip

实现IWifiChip接口的代码路径为:hardware/interfaces/wifi/1.2/default/wifi_chip.cpp

Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
	return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
			              &WifiChip::createStaIfaceInternal, hidl_status_cb);
}

validateAndCall()是一个模板函数:

// Use for HIDL methods which return instance of WifiStatus and a single return
// value.
template <typename ObjT, typename WorkFuncT, typename ReturnT, typename... Args>
Return<void> validateAndCall(
    ObjT* obj, WifiStatusCode status_code_if_invalid, WorkFuncT&& work,
    const std::function<void(const WifiStatus&, ReturnT)>& hidl_cb,
    Args&&... args) {
    const auto lock = hidl_sync_util::acquireGlobalLock();
    if (obj->isValid()) {
        const auto& ret_pair = (obj->*work)(std::forward<Args>(args)...);
        const WifiStatus& status = std::get<0>(ret_pair);
        const auto& ret_value = std::get<1>(ret_pair);
        hidl_cb(status, ret_value);
    } else {
        hidl_cb(createWifiStatus(status_code_if_invalid),
                typename std::remove_reference<ReturnT>::type());
    }
    return Void();
}

直接展开模板函数可得:

Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
    const auto lock = hidl_sync_util::acquireGlobalLock();
    if (isValid()) {
        const auto& ret_pair = createStaIfaceInternal();
        const WifiStatus& status = std::get<0>(ret_pair);
        const auto& ret_value = std::get<1>(ret_pair);
        hidl_status_cb(status, ret_value);
    } else {
        hidl_status_cb(createWifiStatus(WifiStatusCode::ERROR_WIFI_CHIP_INVALID),
                typename std::remove_reference<ReturnT>::type());
    }
    return Void();
}

可见,返回结果是由createStaIfaceInternal()函数提供;

std::pair<WifiStatus, sp<IWifiStaIface>> WifiChip::createStaIfaceInternal() {
	//如果当前工作模式不支持指定类型(此处为STA),则返回状态码ERROR_NOT_AVAILABLE,iface返回null
    if (!canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
    }
    bool iface_created = false;
    /*
     * 获取iface名称,默认返回wlan0(属性wifi.interface),如果wlan0已经被使用,返回
     * wlan1(属性wifi.concurrent.interface)
     * 若wlan1被使用,则返回wlan2(属性wifi.interface.2)
     * 这里介绍下被使用的情况:
     *     wlan0被ap热点占用(部分设备支持ap与wifi同时打开,这种情况下就会出现一个wlan0,
     * 一个wlan1)
     *     wlan0被2.4G热点占用,wlan1被5G热点占用,此时打开wifi就会走wlan2
     */
    std::string ifname = allocateApOrStaIfaceName();
    /* 
     * 检查这个iface名称是否有效,返回0表示:
     * 1. socket通信建立失败 (低概率)
     * 2. iface尚未创建
     */
    if (!if_nametoindex(ifname.c_str())) {
        legacy_hal::wifi_error legacy_status =
            legacy_hal_.lock()->QcAddInterface(getWlan0IfaceName(), ifname,
                                               (uint32_t)IfaceType::STA);
        if (legacy_status != legacy_hal::WIFI_SUCCESS) {
            return {createWifiStatusFromLegacyError(legacy_status), {}};
        }
        iface_created = true;
    }
    //构造返回需要的IWifiIface(IWifiStaIface)
    sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_);
    sta_ifaces_.push_back(iface);
    //如果是新创建的iface,则添加到created_sta_ifaces_向量中
    if (iface_created) created_sta_ifaces_.push_back(iface);
    for (const auto& callback : event_cb_handler_.getCallbacks()) {
        if (!callback->onIfaceAdded(IfaceType::STA, ifname).isOk()) {
            LOG(ERROR) << "Failed to invoke onIfaceAdded callback";
        }
    }
    //返回SUCCESS状态码以及iface实例
    return {createWifiStatus(WifiStatusCode::SUCCESS), iface};
}

如上分析可知:

  • 创建iface的核心方法在QcAddInterface()函数中
  • sta_ifaces_向量中保存了所有创建的WifiStaIfacecreated_sta_ifaces_向量中仅保存随之创建了iface的WifiStaIface

继续查看QcAddInterface()函数实现:
代码路径:hardware/interfaces/wifi/1.2/default/wifi_legacy_hal.cpp

wifi_error WifiLegacyHal::QcAddInterface(const std::string& iface_name,
                                         const std::string& new_ifname,
                                         uint32_t type) {
    //global_func_table_.wifi_add_or_remove_virtual_intf即为wificonfig.cpp中
    //wifi_add_or_remove_virtual_intf函数实现;
    wifi_error status = global_func_table_.wifi_add_or_remove_virtual_intf(
                           getIfaceHandle(iface_name),
                           new_ifname.c_str(), type, true);

    if (status == WIFI_SUCCESS) {
        // refresh list of handlers now.
        iface_name_to_handle_.clear();
        status = retrieveIfaceHandles();
    }
    return status;
}

继续查看wificonfig.cppwifi_add_or_remove_virtual_intf()函数:
关于global_func_table_中的函数指针怎么对应到wificonfig.cpp中的wifi_add_or_remove_virtual_intf()函数的,可以移步这里

代码路径:qcom/wlan/qcwcn/wifi_hal/wificonfig.cpp

#ifdef WCNSS_QTI_AOSP
wifi_error wifi_add_or_remove_virtual_intf(wifi_interface_handle iface,
                                           const char* ifname, u32 iface_type,
                                           bool create)
{
    wifi_error ret;
    WiFiConfigCommand *wifiConfigCommand;
    //下方两个函数实现在hardware/qcom/wlan/qcwcn/wifi_hal/common.cpp
    //强制类型转换
    interface_info *ifaceInfo = getIfaceInfo(iface);
    //强制类型转换为interface_info后取handle字段
    wifi_handle wifiHandle = getWifiHandle(iface);

	//构造一个WiFiConfigCommand,
    wifiConfigCommand = new WiFiConfigCommand(wifiHandle, get_requestid(), 0, 0);

	//QcAddInterface调用过来create恒为true
    if (create) {
        nl80211_iftype type;
        //WifiChip::createStaIfaceInternal()调用过来恒为IfaceType::STA
        switch(iface_type) {
            case 0:    /* IfaceType:STA */
                type = NL80211_IFTYPE_STATION;
                break;
            case 1:    /* IfaceType:AP */
                type = NL80211_IFTYPE_AP;
                break;
            case 2:    /* IfaceType:P2P */
                type = NL80211_IFTYPE_P2P_DEVICE;
                break;
            default:
                ALOGE("%s: Wrong interface type %u", __FUNCTION__, iface_type);
                ret = WIFI_ERROR_UNKNOWN;
                goto done;
                break;
        }
        //封装信息内容
        wifiConfigCommand->create_generic(NL80211_CMD_NEW_INTERFACE);
        wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX, ifaceInfo->id);
        wifiConfigCommand->put_string(NL80211_ATTR_IFNAME, ifname);
        wifiConfigCommand->put_u32(NL80211_ATTR_IFTYPE, type);
    } else {
        wifiConfigCommand->create_generic(NL80211_CMD_DEL_INTERFACE);
        wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX, if_nametoindex(ifname));
    }

    //通过Netlink发送消息到驱动侧
    wifiConfigCommand->waitForRsp(false);
    ret = wifiConfigCommand->requestEvent();
    if (ret != WIFI_SUCCESS) {
        ALOGE("wifi_add_or_remove_virtual_intf: requestEvent Error:%d", ret);
    }

done:
    delete wifiConfigCommand;
    return ret;
}

后面就是驱动层的实现了,这里暂不讨论;
可见,IWifiChip.createStaIface这一步主要是通知WIFI网卡驱动创建一个可用的(STA模式)Iface,如果已经创建,则直接使用即可;

这部分的流程比较简单,时序图参考如下:

在这里插入图片描述

IWifiCond

IWificond.createClientInterface()的实现在wificond进程中:
代码路径:system/connectivity/wificond/server.cpp

Status Server::createClientInterface(const std::string& iface_name,
                                     sp<IClientInterface>* created_interface) {
  InterfaceInfo interface;
  //如果setup失败,则直接返回,created_interface为空;
  if (!SetupInterface(iface_name, &interface)) {
    return Status::ok();
  }

  //构建一个ClientInterfaceImpl,并封装需要通过Netlink Socket发送的数据结构;
  unique_ptr<ClientInterfaceImpl> client_interface(new ClientInterfaceImpl(
      wiphy_index_,
      interface.name,
      interface.index,
      interface.mac_address,
      if_tool_.get(),
      netlink_utils_,
      scan_utils_));
  *created_interface = client_interface->GetBinder();
  BroadcastClientInterfaceReady(client_interface->GetBinder());
  client_interfaces_[iface_name] = std::move(client_interface);

  return Status::ok();
}

这里需要重点关注这个SetupInterface()函数:

bool Server::SetupInterface(const std::string& iface_name,
                            InterfaceInfo* interface) {
  //通过Netlink与内核通信,获取iface的信息,如果通信失败,直接返回false
  if (!RefreshWiphyIndex()) {
    return false;
  }

  //注册监听
  netlink_utils_->SubscribeRegDomainChange(
          wiphy_index_,
          std::bind(&Server::OnRegDomainChanged,
          this,
          _1));

  interfaces_.clear();

  //通过Netlink获取对应的iface
  if (!netlink_utils_->GetInterfaces(wiphy_index_, &interfaces_)) {
    return false;
  }

  //如果名字匹配,则返回true
  for (const auto& iface : interfaces_) {
    if (iface.name == iface_name) {
      *interface = iface;
      return true;
    }
  }

  return false;
}

重点在于RefreshWiphyIndex()NetlinkUtils::GetInterfaces()两个函数:

  • RefreshWiphyIndex()会调用NetlinkUtils::GetWiphyIndex(),向内核发送NL80211_CMD_GET_WIPHY请求,获取Wiphy的下标,如果获取成功则返回true,反之返回false
  • NetlinkUtils::GetInterfaces()则是通过向内核发送NL80211_CMD_GET_INTERFACE请求,附带wiphy_index作为属性,尝试获取对应的InterfaceInfo,获取成功返回true,反之返回false

关于Wiphy

  • 指的是Wireless Physical Layer,即linux内核net子系统中的无线网络(wireless)物理层;

HAL就到此为止,后面是内核部分的逻辑了,会单独写一篇介绍;

IWifiCond部分时序示意图如下:

在这里插入图片描述

ISupplicant

上面提到,ISupplicant在此题中讨论V1.1版本的逻辑,因此对应的HAL实现也应该看V1.1的wpa_supplicant:

代码路径:external/wpa_supplicant_8/wpa_supplicant/hidl/1.1/supplicant.cpp

Return<void> Supplicant::addInterface(
    const IfaceInfo& iface_info, addInterface_cb _hidl_cb)
{
	return validateAndCall(
	    this, SupplicantStatusCode::FAILURE_IFACE_INVALID,
	    &Supplicant::addInterfaceInternal, _hidl_cb, iface_info);
}

validateAndCall()同样是一个模板函数,照例展开:

Return<void> Supplicant::addInterface(
    const IfaceInfo& iface_info, addInterface_cb _hidl_cb)
{
	if (this->isValid()) {
		const auto& ret_pair =
		    addInterfaceInternal(iface_info);
		const SupplicantStatus& status = std::get<0>(ret_pair);
		const sp<ISupplicantIface> ret_value = std::get<1>(ret_pair);
		hidl_cb(status, ret_value);
	} else {
		hidl_cb(
		    {SupplicantStatusCode::FAILURE_IFACE_INVALID, ""},
		    typename std::remove_reference<sp<ISupplicantIface>>::type());
	}
	return Void();
}

核心函数为addInterfaceInternal()

std::pair<SupplicantStatus, sp<ISupplicantIface>>
Supplicant::addInterfaceInternal(const IfaceInfo& iface_info)
{
	android::sp<ISupplicantIface> iface;
	...
	//通过getInterfaceInternal尝试获取现有匹配的interface,如果已经存在,直接返回
	SupplicantStatus status;
	std::tie(status, iface) = getInterfaceInternal(iface_info);
	if (status.code == SupplicantStatusCode::SUCCESS) {
		return {{SupplicantStatusCode::FAILURE_IFACE_EXISTS, ""},
			iface};
	}

	struct wpa_interface iface_params = {};
	//驱动默认nl80211
	iface_params.driver = kIfaceDriverName;
	//由于传入的参数为IfaceType::STA,此处不讨论P2P的逻辑
	if (iface_info.type == IfaceType::P2P) {
		...
	} else {
		/*
		 * 确认配置文件是否存在,主要逻辑有如下几步:
		 *  - 优先确认"/data/vendor/wifi/wpa/wpa_supplicant.conf"
		 *    是否存在且可写(RW),如果不可写,尝试chmod,如果失败,则返回-1,成功则返回0;
		 *  - 如果前者不存在,则判断"/data/misc/wifi/wpa_supplicant.conf"是否存在,
		 *    如果存在则将其拷贝到"/data/vendor/wifi/wpa/wpa_supplicant.conf",
		 *    成功返回0,失败返回-1;如果文件不存在或不可读,返回1;
		 *  - 如果前者返回1,则尝试拷贝"/vendor/etc/wifi/wpa_supplicant.conf"到
		 *    "/data/vendor/wifi/wpa/wpa_supplicant.conf",同理成功返回0,
		 *    失败返回-1;如果文件不存在或不可读,返回1;
		 *  - 如果前者返回1,则尝试拷贝"/system/etc/wifi/wpa_supplicant.conf"到
		 *    "/data/vendor/wifi/wpa/wpa_supplicant.conf",同理成功返回0,
		 *    失败返回-1;如果文件不存在或不可读,返回1;
		 *  - 如果前者依旧返回1,此时已经没有任何不就措施,函数返回-1
		 */
		if (ensureConfigFileExists(
			kStaIfaceConfPath, kOldStaIfaceConfPath) != 0) {
			//表示配置文件未就绪,或为权限问题,或为文件不存在,HIDL状态码返回
			//FAILURE_UNKNOWN,数据返回null;
			return {{SupplicantStatusCode::FAILURE_UNKNOWN,
				 "Conf file does not exist"},
				{}};
		}
		//读取配置文件,如果存在overlay,则使用confanother变量保存overlay文件路径:
		//"/vendor/etc/wifi/wpa_supplicant_overlay.conf"
		iface_params.confname = kStaIfaceConfPath;
		int ret = access(kStaIfaceConfOverlayPath, R_OK);
		if (ret == 0) {
			iface_params.confanother = kStaIfaceConfOverlayPath;
		}
	}
	iface_params.ifname = iface_info.name.c_str();
	//核心调用,wpa_supplicant添加STA iface的关键函数;
	struct wpa_supplicant* wpa_s =
	    wpa_supplicant_add_iface(wpa_global_, &iface_params, NULL);
	if (!wpa_s) {
		return {{SupplicantStatusCode::FAILURE_UNKNOWN, ""}, {}};
	}
	
	最后通过getInterfaceInternal获取对应的对象返回;
	return getInterfaceInternal(iface_info);
}

可见,创建iface的工作在wpa_supplicant_add_iface()中完成,这部分是wpa_supplicant的逻辑了:

struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
						 struct wpa_interface *iface,
						 struct wpa_supplicant *parent)
{
	struct wpa_supplicant *wpa_s;
	struct wpa_interface t_iface;
	struct wpa_ssid *ssid;
	...
	//初始化一个wpa_s 对象,Android中会调用calloc进行内存分配;
	wpa_s = wpa_supplicant_alloc(parent);
	...

	wpa_s->global = global;

	t_iface = *iface;
	//global->params中各个参数的值是main函数中解析cmdline中参数时确定的
	//以具体的cmdline为准;
	if (global->params.override_driver) {
		...
		t_iface.driver = global->params.override_driver;
	}
	if (global->params.override_ctrl_interface) {
		...
		t_iface.ctrl_interface =
			global->params.override_ctrl_interface;
	}
	//初始化完成返回0,否则返回-1,这里是关键代码,且逻辑比较复杂
	if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
		...
		//由于wpa_supplicant_init_iface流程很长,需要deinit来重置各种中间状态
		wpa_supplicant_deinit_iface(wpa_s, 0, 0);
		return NULL;
	}

	//顺利完成返回0,否则返回-1
	if (wpas_notify_iface_added(wpa_s)) {
		//由于无法通知状态,因此无效化该iface
		wpa_supplicant_deinit_iface(wpa_s, 1, 0);
		return NULL;
	}

	...
	wpa_s->next = global->ifaces;
	global->ifaces = wpa_s;

	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);

#ifdef CONFIG_P2P
	...
#endif /* CONFIG_P2P */

	return wpa_s;
}

有上面分析可知,wpa_supplicant部分的处理关键在于wpa_supplicant_init_iface()函数,后者展开就比较多了(350+行的函数)。

受限于篇幅,我这对函数实现进行了大量裁剪,以便于快速获取关键信息:

static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
				     const struct wpa_interface *iface)
{
	struct wpa_driver_capa capa;
	int capa_res;
	u8 dfs_domain;

	if (iface->confname) {
		...
		//读取配置文件与overlay文件,路径定义见上方ensureConfigFileExists()函数附近分析
		wpa_s->conf = wpa_config_read(wpa_s->confname, NULL);
		...
		wpa_s->confanother = os_rel2abs_path(iface->confanother);
		if (wpa_s->confanother &&
		    !wpa_config_read(wpa_s->confanother, wpa_s->conf)) {
			...
			return -1;
		}
		...
		//如果ctrl_interface已经由cmdline指定,则此处不再取conf文件中的配置项
		if (iface->ctrl_interface) {
			os_free(wpa_s->conf->ctrl_interface);
			wpa_s->conf->ctrl_interface =
				os_strdup(iface->ctrl_interface);
		}
		...
	}

	//如果ifname过长,会导致拷贝失败,因此需要此处判断,如果字符串长度合理,则拷贝到wpa_s->ifname中;
	if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
		return -1;
	}
	os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
	...
	//初始化驱动并注册事件监听、处理的Handler,android采用linux内核,这里驱动就是nl80211;
	//由于涉及到与内核交互,这里暂且不展开了,待驱动层分析时再继续
	if (wpas_init_driver(wpa_s, iface) < 0)
		return -1;
	//初始化一些函数指针的映射;
	if (wpa_supplicant_init_wpa(wpa_s) < 0)
		return -1;

	//将wpa_s中的部分信息通知到wpa_sm中,后者是一个cpp编写的状态机,实现的功能与JAVA层的StateMachine类似;
	wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
			  wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
			  NULL);
	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);

	//通过与驱动层(Android基于Linux内核,此处则为nl80211)通信,获取硬件的一些特性,包括支持的频段、通道、带宽、频率等信息;
	wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
						      &wpa_s->hw.num_modes,
						      &wpa_s->hw.flags,
						      &dfs_domain);
	if (wpa_s->hw.modes) {
		u16 i;
		//遍历所有的支持模式,获取其最高的频率支持情况,并设置hw_capab(CAPAB_VHT > CAPAB_HT40 > CAPAB_HT)
		for (i = 0; i < wpa_s->hw.num_modes; i++) {
			if (wpa_s->hw.modes[i].vht_capab) {
				wpa_s->hw_capab = CAPAB_VHT;
				break;
			}

			if (wpa_s->hw.modes[i].ht_capab &
			    HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
				wpa_s->hw_capab = CAPAB_HT40;
			else if (wpa_s->hw.modes[i].ht_capab &&
				 wpa_s->hw_capab == CAPAB_NO_HT_VHT)
				wpa_s->hw_capab = CAPAB_HT;
		}
	}

	//通过与驱动交互,获取一些能力支持情况,主要包括加密、认证的算法支持情况;
	capa_res = wpa_drv_get_capa(wpa_s, &capa);
	//返回0表示获取成功,则将capa中获取的信息保存到wpa_s中;
	if (capa_res == 0) {
		wpa_s->drv_capa_known = 1;
		wpa_s->drv_flags = capa.flags;
		wpa_s->drv_enc = capa.enc;
		wpa_s->drv_smps_modes = capa.smps_modes;
		wpa_s->drv_rrm_flags = capa.rrm_flags;
		wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
		wpa_s->max_scan_ssids = capa.max_scan_ssids;
		wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
		wpa_s->max_sched_scan_plans = capa.max_sched_scan_plans;
		wpa_s->max_sched_scan_plan_interval =
			capa.max_sched_scan_plan_interval;
		wpa_s->max_sched_scan_plan_iterations =
			capa.max_sched_scan_plan_iterations;
		wpa_s->sched_scan_supported = capa.sched_scan_supported;
		wpa_s->max_match_sets = capa.max_match_sets;
		wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
		wpa_s->max_stations = capa.max_stations;
		wpa_s->extended_capa = capa.extended_capa;
		wpa_s->extended_capa_mask = capa.extended_capa_mask;
		wpa_s->extended_capa_len = capa.extended_capa_len;
		wpa_s->num_multichan_concurrent =
			capa.num_multichan_concurrent;
		wpa_s->wmm_ac_supported = capa.wmm_ac_supported;

		//mac地址随机化的支持情况,在驱动中是单独的变量记录,
		//但是在wpa_s中是以标志位mac_addr_rand_supported 存放的,因此需要做转换
		if (capa.mac_addr_rand_scan_supported)
			wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
		if (wpa_s->sched_scan_supported &&
		    capa.mac_addr_rand_sched_scan_supported)
			wpa_s->mac_addr_rand_supported |=
				(MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
	}

	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
		wpa_s->p2p_mgmt = iface->p2p_mgmt;
	...
	//初始化wpa_supplicant层一些接口和参数
	if (wpa_supplicant_driver_init(wpa_s) < 0)
		return -1;

	//初始化TDLS,该技术用于同一网络下设备间进行直连通信,需在驱动初始化后进行
	if (!iface->p2p_mgmt && wpa_tdls_init(wpa_s->wpa))
		return -1;

	//设置CountryCode
	if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
	    wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
		return -1;
	}

	//初始化WPA(Wi-Fi Protected Access)
	if (wpas_wps_init(wpa_s))
		return -1;

	//初始化GAS(Generic advertisement service) server - struct gas_server
	wpa_s->gas_server = gas_server_init(wpa_s, wpas_gas_server_tx);
	...
	//初始化DPP(Device Provision Protocol)
	if (wpas_dpp_init(wpa_s) < 0)
		return -1;

	//初始化eapol,其会作为后续连接时四次握手的传输协议使用
	if (wpa_supplicant_init_eapol(wpa_s) < 0)
		return -1;
	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);

	wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
	if (wpa_s->ctrl_iface == NULL) {
		return -1;
	}

	wpa_s->gas = gas_query_init(wpa_s);
	if (wpa_s->gas == NULL) {
		return -1;
	}

	if ((!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) ||
	     wpa_s->p2p_mgmt) &&
	    wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
		return -1;
	}

	if (wpa_bss_init(wpa_s) < 0)
		return -1;

	if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
		return -1;

	if (pcsc_reader_init(wpa_s) < 0)
		return -1;

	if (wpas_init_ext_pw(wpa_s) < 0)
		return -1;

	wpas_rrm_reset(wpa_s);

	wpas_sched_scan_plans_set(wpa_s, wpa_s->conf->sched_scan_plans);

	hs20_init(wpa_s);

	wpa_supplicant_set_default_scan_ies(wpa_s);

	return 0;
}

wpa_supplicant_init_iface()这个函数调用的东西非常多。篇幅有限,这里无法一一展开分析,先上一个大致的时序图,后续分析wpa_supplicant的时候再着重介绍;

在这里插入图片描述
最后,再附上一个合体的时序图:

在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值