[Android]Android P(9) WIFI学习笔记 - HAL (1)
目录
- 前文回顾
- 前言
- 入口
- WifiNative
- 初始化
- 打开WIFI
- IWifiChip
- IWifiCond
- ISupplicant
前文回顾
- WIFI学习笔记 - Framework (1)
- WIFI学习笔记 - Framework (2)
前言
- 基于Android P源码学习;
- 代码片为了方便阅读段经过删、裁减,请以实际源码为准;
入口
根据前两篇的分析结果,调用栈都汇聚到了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
)
- 负责通过Binder与
WifiMonitor mWifiMonitor
- 一个负责收集、分发wpa_supplicant状态的工具类;
INetworkManagementService
:mNwManagementService
INetworkManagementService
实现类的的客户端实例
PropertyService
:mPropertyService
- 类型为
PropertyService
的接口,实现类型为SystemPropertyService
,本质是对android.os.SystemProperties
的get
/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,因此后续以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返回nullif (!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_
向量中保存了所有创建的WifiStaIface
,created_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.cpp
中wifi_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恒为trueif (create) {nl80211_iftype type;//WifiChip::createStaIfaceInternal()调用过来恒为IfaceType::STAswitch(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的信息,如果通信失败,直接返回falseif (!RefreshWiphyIndex()) {return false;}//注册监听netlink_utils_->SubscribeRegDomainChange(wiphy_index_,std::bind(&Server::OnRegDomainChanged,this,_1));interfaces_.clear();//通过Netlink获取对应的ifaceif (!netlink_utils_->GetInterfaces(wiphy_index_, &interfaces_)) {return false;}//如果名字匹配,则返回truefor (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 = {};//驱动默认nl80211iface_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,否则返回-1if (wpas_notify_iface_added(wpa_s)) {//由于无法通知状态,因此无效化该ifacewpa_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;//设置CountryCodeif (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_serverwpa_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的时候再着重介绍;
最后,再附上一个合体的时序图:
[Android]Android P(9) WIFI学习笔记 - HAL (1)相关推荐
- Android开源项目SlidingMenu本学习笔记(两)
我们已经出台SlidingMenu使用:Android开源项目SlidingMenu本学习笔记(一个),接下来再深入学习下.依据滑出项的Menu切换到相应的页面 文件夹结构: 点击Bluetooth能 ...
- Android Jetpack Components of LiveData 学习笔记
Android Jetpack Components of Lifecycle 学习笔记 Android Jetpack Components of LiveData 学习笔记 Android Jet ...
- Android Jetpack Components of ViewModel 学习笔记
Android Jetpack Components of Lifecycle 学习笔记 Android Jetpack Components of LiveData 学习笔记 Android Jet ...
- android spi读写不通,Android-SPI学习笔记
概述 SPI(Service Provider Interface, 服务提供方接口),服务通常是指一个接口或者一个抽象类,服务提供方是对这个接口或者抽象类的具体实现,由第三方来实现接口提供具体的服务 ...
- 《Android开发高手课》学习笔记
最近在学习张绍文老师的<Android开发高手课>课程,学习到了很多的干货,特别是在处理问题的策略和知识的广度方面给了我很多的启发,对未来的学习也提供了方向. 目前,技术的发展有两个趋势. ...
- Android 中的WiFi学习笔记(转载)----WIFI启动 代码流程走读---网络连接流程
Android的WiFi 我们通常看到WiFi的守护进程wpa_supplicant在我们的ps的进程列表中,这个就是我们的wifi守护进程.wpa_supplicant在external/wpa_s ...
- android studio 远程调试,Unity3D学习笔记——Android远程真机调试(Unity Remote)
前言:当使用Unity开发移动端的游戏,特别是使用到手机的传感器,如重力感应等,调试的时候,很麻烦, 因为每次都需要编译成APK后安装到手机中测试,而Unity Remote便能很好的解决这个问题,U ...
- Android推送进阶课程学习笔记
今天在慕课网学习了Android进阶课程推送的server端处理回执的消息 . 这集课程主要介绍了,当server往client推送消息的时候,client须要发送一个回执回来确认收到了推送消息才算一 ...
- Android工程师进阶34讲学习笔记
最近发现一个技术提升的平台,很多课程对于技术提升都多有益处,很多是实际上的项目实战并对底层原理讲解透彻.前几个月已经学习完了<Android 工程师进阶 34 讲>,现在重学一遍并做些总结 ...
最新文章
- 2021 年第十一届 MathorCup 高校数学建模挑战赛A题分析
- React+TypeScript练手小项目
- sqlite3admin触发器创建
- openlayer右键菜单_使用OpenLayers3 添加地图鼠标右键菜单
- kFreeBSD有活过来的迹象?UbuntuBSD
- 特征工程完全手册 - 从预处理、构造、选择、降维、不平衡处理
- 云计算时代,互联网金融背后的想象空间
- iOS开发编译错误:std::terminate(), referenced from:
- 最全攻略:利用LightSeq加速你的深度学习模型
- 17-基于51单片机的银行排队叫号系统设计
- 万恶的ie(还好只是ie11)
- 南邮-2022年6月电子商务练习自整理 - 选择篇
- 苹果计算机格式化磁盘,MAC格式化移动硬盘
- oracle其他数据对象 --- 视图(10级学员 韩晓爽课堂总结)
- 致敬柳传志三网合一的佳沃品牌之路
- python tensorflow2 deeplearning 音频处理 声学事件检测
- 第006话 皮皮和月亮石!
- 运动控制卡课程:固高,凌华,雷赛,(单一款学习时间45天,要求有C语言基础)凭良学校
- 修改mmsegmentation框架(deeplabV3+中加入注意力机制)
- 学习任务01-配置自己ssh config
热门文章
- 陀螺仪工作原理及创新应用
- 计算机瑞士留学经验,瑞士留学生活分享
- OffiSmart Summit智慧办公及空间管理上海线下峰会精彩亮点抢先看
- 计算机软考最佳时间,软考报名时间是什么时候?软考有哪些意义?
- 水平仪算公式计算机,水准仪的使用及计算方法
- linux java -cp lt; .txt_补交 20155202 蓝墨云班课 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能...
- [转载]自动机器学习(AutoML)领域论文合集
- Unity3D 基于XLua框架实现Lua组件化开发方式(一)----基于C#调用Lua
- Koalas - 入门基本操作
- html制作心形状图片,把多张图片拼接成一个爱心的形状 爱心形状的图片效果 爱心拼接照...