鸿蒙 WiFi 连接 流程
那当界面上显示扫描到的所有Ap时,我们选择其中的一个Ap发起连接,看下代码流程是怎样的。
// applications/standard/settings/product/phone/src/main/ets/model/wifiImpl/WifiModel.ts
connectWiFi(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()); ---》当前如果没有连接就是false
if (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());
// 使能ap
if (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.c
int 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); ---》 发送给wpa
if (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的流程,下一篇继续梳理这个。