鸿蒙 WiFi 连接 流程

那当界面上显示扫描到的所有Ap时,我们选择其中的一个Ap发起连接,看下代码流程是怎样的。

// applications/standard/settings/product/phone/src/main/ets/model/wifiImpl/WifiModel.tsconnectWiFi(password: string) {let apInfo = this.userSelectedAp.getApInfo();let ret = false;let connectParam: any = {"ssid": apInfo.ssid,"bssid": apInfo.bssid,"preSharedKey": password,"isHiddenSsid": false, // we don't support connect to hidden ap yet"securityType": apInfo.securityType};LogUtil.info(MODULE_TAG + 'disconnect WiFi isConnected is ' + wifi.isConnected());     ---》当前如果没有连接就是falseif (wifi.isConnected() === true) {ret = wifi.disconnect();LogUtil.info(MODULE_TAG + 'disconnect WiFi ret is ' + ret);this.registerWiFiConnectionObserver((code: Number) => {if (code === 0) {ret = wifi.connectToDevice(connectParam);this.unregisterWiFiConnectionObserver();}})}else{ret = wifi.connectToDevice(connectParam);                        ---> 就会走这里发起连接LogUtil.info(MODULE_TAG + 'connect WiFi ret is ' + ret);}return ret;}
// 有了前面的基础我们知道Wifi_Device的实现是wifi_device_impl, 然后在通过代理和服务端交互,所以我们直接看服务端的实现即可,调用流程这里就省略掉
// foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_device_service_impl.cpp
ErrCode WifiDeviceServiceImpl::ConnectToDevice(const WifiDeviceConfig &config)
{if (!WifiAuthCenter::IsSystemAppByToken()) {WIFI_LOGE("ConnectToDevice:NOT System APP, PERMISSION_DENIED!");return WIFI_OPT_NON_SYSTEMAPP;}if (WifiPermissionUtils::VerifySetWifiInfoPermission() == PERMISSION_DENIED) {WIFI_LOGE("ConnectToDevice:VerifySetWifiInfoPermission PERMISSION_DENIED!");return WIFI_OPT_PERMISSION_DENIED;}if (WifiPermissionUtils::VerifyWifiConnectionPermission() == PERMISSION_DENIED) {WIFI_LOGE("ConnectToDevice:VerifyWifiConnectionPermission PERMISSION_DENIED!");return WIFI_OPT_PERMISSION_DENIED;}if (WifiPermissionUtils::VerifySetWifiConfigPermission() == PERMISSION_DENIED) {WIFI_LOGE("ConnectToDevice:VerifySetWifiConfigPermission PERMISSION_DENIED!");return WIFI_OPT_PERMISSION_DENIED;}if (!CheckConfigPwd(config)) {WIFI_LOGE("CheckConfigPwd failed!");return WIFI_OPT_INVALID_PARAM;}if (!IsStaServiceRunning()) {WIFI_LOGE("ConnectToDevice: sta service is not running!");return WIFI_OPT_STA_NOT_OPENED;}IStaService *pService = WifiServiceManager::GetInstance().GetStaServiceInst();if (pService == nullptr) {WIFI_LOGE("ConnectToNetwork: pService is nullptr!");return WIFI_OPT_STA_NOT_OPENED;}return pService->ConnectToDevice(config);
}// foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_interface.cpp
ErrCode StaInterface::ConnectToDevice(const WifiDeviceConfig &config)
{LOGD("Enter StaInterface::Connect.\n");CHECK_NULL_AND_RETURN(pStaService, WIFI_OPT_FAILED);if (pStaService->ConnectToDevice(config) != WIFI_OPT_SUCCESS) {LOGD("ConnectTo failed.\n");return WIFI_OPT_FAILED;}return WIFI_OPT_SUCCESS;
}// foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_service.cpp
ErrCode StaService::ConnectToDevice(const WifiDeviceConfig &config) const
{LOGI("Enter StaService::ConnectToDevice, ssid = %{public}s.\n", SsidAnonymize(config.ssid).c_str());CHECK_NULL_AND_RETURN(pStaStateMachine, WIFI_OPT_FAILED);int netWorkId = AddDeviceConfig(config);       ---》 对于新的AP,先添加,和Android都是一样的if(netWorkId == INVALID_NETWORK_ID) {LOGD("StaService::ConnectToDevice, AddDeviceConfig failed!");return WIFI_OPT_FAILED;}LOGI("StaService::ConnectToDevice, netWorkId: %{public}d", netWorkId);pStaStateMachine->SendMessage(WIFI_SVR_CMD_STA_CONNECT_NETWORK, netWorkId, NETWORK_SELECTED_BY_USER);    ---> 让状态机处理连接return WIFI_OPT_SUCCESS;
}

这里主要是两个函数:
一个是 AddDeviceConfig ,
一个是SendMessage(WIFI_SVR_CMD_STA_CONNECT_NETWORK, netWorkId, NETWORK_SELECTED_BY_USER)
流程都是一样的,通过,通过RPC访问HAL层,然后再把命令发给wpa,wpa收到命令后触发相应动作,这里我们看后者,状态机处理消息
// foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/wifi_sta/sta_state_machine.cpp

// 调用的这个函数:
void StaStateMachine::DealConnectToUserSelectedNetwork(InternalMessage *msg)
{LOGI("enter DealConnectToUserSelectedNetwork.\n");if (msg == nullptr) {LOGE("msg is null.\n");return;}int networkId = msg->GetParam1();int connTriggerMode = msg->GetParam2();if (connTriggerMode != NETWORK_SELECTED_BY_RETRY) {linkedInfo.retryedConnCount = 0;}if (networkId == linkedInfo.networkId) {if (linkedInfo.connState == ConnState::CONNECTED) {staCallback.OnStaConnChanged(OperateResState::CONNECT_AP_CONNECTED, linkedInfo);WIFI_LOGI("This network is in use and does not need to be reconnected.\n");return;}if (linkedInfo.connState == ConnState::CONNECTING &&linkedInfo.detailedState == DetailedState::OBTAINING_IPADDR) {WIFI_LOGI("This network is connecting and does not need to be reconnected.\n");return;}}/* Save connection information. */SaveDiscReason(DisconnectedReason::DISC_REASON_DEFAULT);SaveLinkstate(ConnState::CONNECTING, DetailedState::CONNECTING);/* Callback result to InterfaceService. */staCallback.OnStaConnChanged(OperateResState::CONNECT_CONNECTING, linkedInfo);if (StartConnectToNetwork(networkId) != WIFI_OPT_SUCCESS) {     ---》 继续看这个流程OnConnectFailed(networkId);return;}/* Sets network status. */WifiSettings::GetInstance().EnableNetwork(networkId, connTriggerMode == NETWORK_SELECTED_BY_USER);WifiSettings::GetInstance().SetDeviceAfterConnect(networkId);WifiSettings::GetInstance().SetDeviceState(networkId, (int)WifiDeviceConfigStatus::ENABLED, false);
}//
ErrCode StaStateMachine::StartConnectToNetwork(int networkId)
{targetNetworkId = networkId;SetRandomMac(targetNetworkId);     ---> 随机mac地址WifiDeviceConfig deviceConfig;if (WifiSettings::GetInstance().GetDeviceConfig(networkId, deviceConfig) != 0) {LOGE("StartConnectToNetwork get GetDeviceConfig failed!");return WIFI_OPT_FAILED;}WifiStaHalInterface::GetInstance().SetBssid(networkId, deviceConfig.userSelectBssid.c_str());// 使能apif (WifiStaHalInterface::GetInstance().EnableNetwork(targetNetworkId) != WIFI_IDL_OPT_OK) {LOGE("EnableNetwork() failed!");return WIFI_OPT_FAILED;}// 连接if (WifiStaHalInterface::GetInstance().Connect(targetNetworkId) != WIFI_IDL_OPT_OK) {LOGE("Connect failed!");staCallback.OnStaConnChanged(OperateResState::CONNECT_SELECT_NETWORK_FAILED, linkedInfo);return WIFI_OPT_FAILED;}// 保存if (WifiStaHalInterface::GetInstance().SaveDeviceConfig() != WIFI_IDL_OPT_OK) {/* OHOS's wpa don't support save command, so don't judge as failure */LOGE("SaveDeviceConfig() failed!");}StopTimer(static_cast<int>(CMD_NETWORK_CONNECT_TIMEOUT));StartTimer(static_cast<int>(CMD_NETWORK_CONNECT_TIMEOUT), STA_NETWORK_CONNECTTING_DELAY);return WIFI_OPT_SUCCESS;// 上面的三步骤和Android都差不多,基本上大家都熟悉
// foundation/communication/wifi/wifi/services/wifi_standard/wifi_framework/wifi_manage/idl_client/wifi_sta_hal_interface.cpp
WifiErrorNo WifiStaHalInterface::Connect(int networkId)
{CHECK_NULL_AND_RETURN(mIdlClient, WIFI_IDL_OPT_FAILED);return mIdlClient->ReqConnect(networkId);
}
// idl_client , 前面几篇都讲过了,这里直接贴HAL层的代码了
// foundation/communication/wifi/wifi/services/wifi_standard/wifi_hal/wifi_hal_crpc_sta.c
int RpcConnect(RpcServer *server, Context *context)
{if (server == NULL || context == NULL) {return HAL_FAILURE;}int networkId = 0;if (ReadInt(context, &networkId) < 0) {return HAL_FAILURE;}WifiErrorNo err = Connect(networkId);    ---> 看这个的实现WriteBegin(context, 0);WriteInt(context, err);WriteEnd(context);return HAL_SUCCESS;
}// foundation/communication/wifi/wifi/services/wifi_standard/wifi_hal/wifi_hal_sta_interface.c
WifiErrorNo Connect(int networkId)
{LOGD("Connect() networkid %{public}d", networkId);WifiWpaStaInterface *pStaIfc = GetWifiStaInterface(0);if (pStaIfc == NULL) {return WIFI_HAL_SUPPLICANT_NOT_INIT;}int ret = pStaIfc->wpaCliCmdSelectNetwork(pStaIfc, networkId);if (ret < 0) {LOGE("WpaCliCmdSelectNetwork failed! ret=%{public}d", ret);return WIFI_HAL_FAILED;}return WIFI_HAL_SUCCESS;
}

继续看 pStaIfc->wpaCliCmdSelectNetwork 的调用,

//foundation/communication/wifi/wifi/services/wifi_standard/wifi_hal/wifi_hal_module/wpa_supplicant_hal/wpa_sta_hal/wifi_supplicant_hal.c 
static int WpaCliCmdSelectNetwork(WifiWpaStaInterface *this, int networkId)
{if (this == NULL) {return -1;}char cmd[CMD_BUFFER_SIZE] = {0};char buf[REPLY_BUF_SMALL_LENGTH] = {0};if (snprintf_s(cmd, sizeof(cmd), sizeof(cmd) - 1, "IFNAME=%s SELECT_NETWORK %d", this->ifname, networkId) < 0) {LOGE("snprintf err");return -1;}return WpaCliCmd(cmd, buf, sizeof(buf));
}// foundation/communication/wifi/wifi/services/wifi_standard/wifi_hal/wifi_hal_module/wpa_supplicant_hal/wifi_wpa_common.cint WpaCliCmd(const char *cmd, char *buf, size_t bufLen)
{if (cmd == NULL || buf == NULL || bufLen <= 0) {LOGE("WpaCliCmd, invalid parameters!");return -1;}WpaCtrl *ctrl = GetWpaCtrl();if (ctrl == NULL || ctrl->pSend == NULL) {LOGE("WpaCliCmd, ctrl/ctrl->pSend is NULL!");return -1;}size_t len = bufLen - 1;LOGI("wpa_ctrl_request -> cmd: %{private}s", cmd);int ret = wpa_ctrl_request(ctrl->pSend, cmd, strlen(cmd), buf, &len, NULL);    ---》 发送给wpaif (ret == WPA_CMD_RETURN_TIMEOUT) {LOGE("[%{private}s] command timed out.", cmd);return WPA_CMD_RETURN_TIMEOUT;} else if (ret < 0) {LOGE("[%{private}s] command failed.", cmd);return -1;}buf[len] = '\0';LOGI("wpa_ctrl_request -> buf: %{private}s", buf);if (strncmp(buf, "FAIL\n", strlen("FAIL\n")) == 0 ||strncmp(buf, "UNKNOWN COMMAND\n", strlen("UNKNOWN COMMAND\n")) == 0) {LOGE("%{private}s request success, but response %{public}s", cmd, buf);return -1;}return 0;
}

至此,连接的命令就发给wpa了,接下来就是协议上的连接了(四次握手),由wpa去交互完成,连接成功后,wpa上报 CTRL-EVENT-CONNECTED 事件,上层就收到,就开始走DHCP/或者是静态ip的流程,下一篇继续梳理这个。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/674562.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cpu指令集

CPU指令集架构是指计算机中央处理器&#xff08;CPU&#xff09;的指令集的设计和组织方式。它定义了CPU能够理解和执行的指令集合&#xff0c;包括指令的格式、操作码&#xff08;Opcode&#xff09;、寻址模式和操作数等。指令集架构决定了CPU的功能和行为&#xff0c;以及如…

springboot项目启动报错:dynamic-datasource can not find primary datasource

项目启动报错信息 Caused by: com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException: dynamic-datasource can not find primary datasourceat com.baomidou.dynamic.datasource.DynamicRoutingDataSource.determinePrimaryDataSource(DynamicRoutingDat…

编程实例分享,手表养护维修软件钟表维修开单管理系统教程

编程实例分享&#xff0c;手表养护维修软件钟表维修开单管理系统教程 一、前言 以下教程以 佳易王钟表维护维修管理系统软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 左侧为导航栏&#xff0c; 1、系统设置&#xff1a;可以设置打…

【深度学习】pytorch 与 PyG 安装(pip安装)

【深度学习】pytorch 与 PyG 安装&#xff08;pip安装&#xff09; 一、PyTorch安装和配置&#xff08;一&#xff09;、安装 CUDA&#xff08;二&#xff09;、安装torch、torchvision、torchaudio三个组件&#xff08;1&#xff09;下载镜像文件&#xff08;2&#xff09;创建…

Java基础常见面试题总结-集合(二)

迭代器 Iterator 是什么&#xff1f; Iterator模式用同一种逻辑来遍历集合。它可以把访问逻辑从不同类型的集合类中抽象出来&#xff0c;不需要了解集合内部实现便可以遍历集合元素&#xff0c;统一使用 Iterator 提供的接口去遍历。它的特点是更加安全&#xff0c;因为它可以…

【网络技术】【Kali Linux】Nmap嗅探(二)多设备扫描

上期实验博文&#xff1a;&#xff08;一&#xff09;简单扫描 一、实验环境 本次实验进行Nmap多设备扫描&#xff0c;实验使用 Kali Linux 虚拟机&#xff08;扫描端&#xff09;、Ubuntu 22.04虚拟机&#xff08;被扫描端1&#xff09;、Ubuntu 18.04虚拟机&#xff08;被扫…

【力扣】移动零,双指针法

移动零原题地址 方法一&#xff1a;传统双指针法 本题要求把非零元素移动到左边&#xff0c;零移动到右边&#xff0c;这跟快速排序的单趟非常相似。 定义左右指针 left 和 right &#xff0c; right 指针负责探测所有元素&#xff0c;如果遇到非零元素&#xff0c;则左右指…

网课:N皇后问题——牛客(题解和疑问)

题目描述 给出一个nnn\times nnn的国际象棋棋盘&#xff0c;你需要在棋盘中摆放nnn个皇后&#xff0c;使得任意两个皇后之间不能互相攻击。具体来说&#xff0c;不能存在两个皇后位于同一行、同一列&#xff0c;或者同一对角线。请问共有多少种摆放方式满足条件。 输入描述: …

梯度提升树系列5——使用GBDT进行特征选择

特征选择是机器学习和数据科学中至关重要的一环,它不仅可以提高模型的性能,还能显著减少模型训练所需的时间和资源。本文将深入探讨如何使用梯度提升决策树(Gradient Boosting Decision Tree, GBDT)进行特征选择,并强调这一方法在实践中的重要性和效果。 写在开头 特征选…

【力扣】快乐数,哈希集合 + 快慢指针 + 数学

快乐数原题地址 方法一&#xff1a;哈希集合 定义函数 getNext(n) &#xff0c;返回 n 的所有位的平方和。一直执行 ngetNext(n) &#xff0c;最终只有 2 种可能&#xff1a; n 停留在 1 。无限循环且不为 1 。 证明&#xff1a;情况 1 是存在的&#xff0c;如力扣的示例一…

嵌入式学习之Linux入门篇笔记——15,Linux编写第一个自己的命令

配套视频学习链接&#xff1a;http://【【北京迅为】嵌入式学习之Linux入门篇】 https://www.bilibili.com/video/BV1M7411m7wT/?p4&share_sourcecopy_web&vd_sourcea0ef2c4953d33a9260910aaea45eaec8 1.什么是命令&#xff1f; 命令就是可执行程序。 比如 ls -a…

C#静态数组删除数组元素不改变数组长度 vs 动态数组删除数组元素改变数组长度

目录 一、使用的方法 1.对静态数组删除指定长度并不改变数长度的方法 &#xff08;1&#xff09;静态数组 &#xff08;2&#xff09;对静态数组删除元素不得改变其长度 2.对动态数组删除指定长度并改变数长度的方法 &#xff08;1&#xff09;动态数组 &#xff08;2&a…

Golang 并发 Cond条件变量

Golang 并发 Cond条件变量 背景 编写代码过程中&#xff0c; 通常有主协程和多个子协程进行协作的过程&#xff0c;比如通过 WaitGroup 可以实现当所有子协程完成之后&#xff0c; 主协程再继续执行。 如上的场景是主协程等待子协程达到某个状态再继续运行。 但是反过来怎么…

Xilinx FPGA——在线升级

同以前单片机在线升级的做法一样&#xff0c;本质就是通信Flash操作跳转。 一、通信驱动 我使用的是UDP有线传输&#xff0c; 二、Flash芯片驱动 规划Flash芯片的区域&#xff0c;一般bootloader放在起始位置&#xff0c;APP放在bootloader之后的空白区域。 2.1 Flash擦除 我…

Java算法练习6

Java算法练习6 1.15 [506. 相对名次](https://leetcode.cn/problems/relative-ranks/)1.16 [215. 数组中的第K个最大元素](https://leetcode.cn/problems/kth-largest-element-in-an-array/)1.17 [23. 合并 K 个升序链表](https://leetcode.cn/problems/merge-k-sorted-lists/)…

【大模型上下文长度扩展】MedGPT:解决遗忘 + 永久记忆 + 无限上下文

MedGPT&#xff1a;解决遗忘 永久记忆 无限上下文 问题&#xff1a;如何提升语言模型在长对话中的记忆和处理能力&#xff1f;子问题1&#xff1a;有限上下文窗口的限制子问题2&#xff1a;复杂文档处理的挑战子问题3&#xff1a;长期记忆的维护子问题4&#xff1a;即时信息检…

javaEE - 20( 18000字 Tomcat 和 HTTP 协议入门 -1)

一&#xff1a; HTTP 协议 1.1. HTTP 是什么 HTTP (全称为 “超文本传输协议”) 是一种应用非常广泛的 应用层协议. HTTP 诞生与1991年. 目前已经发展为最主流使用的一种应用层协议. 最新的 HTTP 3 版本也正在完善中, 目前 Google / Facebook 等公司的产品已经支持了. HTT…

美赛结束后,还可以转学术论文发表!

美赛论文转学术论文 写在前面学术论文发表的意义论文发表指导 写在前面 2024年美赛已经顺利结束了&#xff0c;美赛虽然画上了句号&#xff0c;但大家的科研竞赛之路才刚刚开始。 大家都在赛事中完成了一份具有发表基础的文章&#xff0c;想要这篇文章价值最大化&#xff0c;…

2.8作业

程序代码&#xff1a; CCgcc EXEhello OBJS$(patsubst %.c,%.o,$(wildcard *.c)) CFLAGS-c -oall:$(EXE)$(EXE):$(OBJS)$(CC) $^ -o $%.o:%.c$(CC) $(CFLAGS) $ $^.PHONY:cleanclean:rm $(OBJS) $(EXE) 程序代码&#xff1a; #include<stdio.h> #include<string.h&…

机器学习--K-近邻算法常见的几种距离算法详解

文章目录 距离度量1 欧式距离(Euclidean Distance)2 曼哈顿距离(Manhattan Distance)3 切比雪夫距离 (Chebyshev Distance)4 闵可夫斯基距离(Minkowski Distance)5 标准化欧氏距离 (Standardized EuclideanDistance)6 余弦距离(Cosine Distance)7 汉明距离(Hamming Distance)【…