1 /*
2 * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "wifi_hal_module_manage.h"
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <dirent.h>
21 #include <dlfcn.h>
22 #include <unistd.h>
23 #include <sys/prctl.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include "securec.h"
27 #include "wifi_hal_define.h"
28 #include "wifi_log.h"
29 #include "wifi_wpa_hal.h"
30 #include "wifi_hostapd_hal.h"
31
32 #undef LOG_TAG
33 #define LOG_TAG "WifiHalModuleManage"
34
35 static ModuleInfo *g_halModuleList = NULL;
36
37 #define MAX_WPA_MAIN_ARGC_NUM 20
38 #define MAX_WPA_MAIN_ARGV_LEN 128
39 #define REFERENCE_CNT_MAX 3
40
41 struct StWpaMainParam {
42 int argc;
43 char argv[MAX_WPA_MAIN_ARGC_NUM][MAX_WPA_MAIN_ARGV_LEN];
44 };
45
SplitCmdString(const char * startCmd,struct StWpaMainParam * pParam)46 static void SplitCmdString(const char *startCmd, struct StWpaMainParam *pParam)
47 {
48 if (pParam == NULL) {
49 return;
50 }
51 if (startCmd == NULL) {
52 pParam->argc = 0;
53 return;
54 }
55 const char *p = startCmd;
56 int i = 0;
57 int j = 0;
58 while (*p != '\0') {
59 if (*p == ' ') {
60 if (j <= MAX_WPA_MAIN_ARGV_LEN - 1) {
61 pParam->argv[i][j] = '\0';
62 } else {
63 pParam->argv[i][MAX_WPA_MAIN_ARGV_LEN - 1] = '\0';
64 }
65 ++i;
66 j = 0;
67 if (i >= MAX_WPA_MAIN_ARGC_NUM) {
68 break;
69 }
70 } else {
71 if (j < MAX_WPA_MAIN_ARGV_LEN - 1) {
72 pParam->argv[i][j] = *p;
73 ++j;
74 }
75 }
76 ++p;
77 }
78 if (i >= MAX_WPA_MAIN_ARGC_NUM) {
79 pParam->argc = MAX_WPA_MAIN_ARGC_NUM;
80 } else {
81 pParam->argc = i + 1;
82 }
83 return;
84 }
85
WpaThreadMain(void * p)86 static void *WpaThreadMain(void *p)
87 {
88 if (p == NULL) {
89 return NULL;
90 }
91 const char *startCmd = (const char *)p;
92 struct StWpaMainParam param = {0};
93 SplitCmdString(startCmd, ¶m);
94 #ifdef OHOS_ARCH_LITE
95 void *handleLibWpa = dlopen("libwpa.so", RTLD_NOW | RTLD_LOCAL);
96 #else
97 #if defined(__aarch64__) || defined(__x86_64__)
98 void *handleLibWpa = dlopen("libwpa_sys.z.so", RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE);
99 #else
100 void *handleLibWpa = dlopen("libwpa_sys.z.so", RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE);
101 #endif
102 #endif
103 if (handleLibWpa == NULL) {
104 LOGE("dlopen libwpa failed.");
105 return NULL;
106 }
107 int (*func)(int, char **) = NULL;
108 if (strcmp(param.argv[0], "wpa_supplicant") == 0) {
109 func = (int (*)(int, char **))dlsym(handleLibWpa, "wpa_main");
110 } else {
111 func = (int (*)(int, char **))dlsym(handleLibWpa, "ap_main");
112 }
113 if (func == NULL) {
114 dlclose(handleLibWpa);
115 LOGE("dlsym wpa_main failed.");
116 return NULL;
117 }
118 char *tmpArgv[MAX_WPA_MAIN_ARGC_NUM] = {0};
119 for (int i = 0; i < param.argc; i++) {
120 tmpArgv[i] = param.argv[i];
121 }
122 int ret = func(param.argc, tmpArgv);
123 LOGD("run wpa_main ret:%{public}d.\n", ret);
124 if (dlclose(handleLibWpa) != 0) {
125 LOGE("dlclose libwpa failed.");
126 return NULL;
127 }
128 return NULL;
129 }
130
StartModuleInternal(const char * moduleName,const char * startCmd,pid_t * pProcessId)131 int StartModuleInternal(const char *moduleName, const char *startCmd, pid_t *pProcessId)
132 {
133 if (moduleName == NULL || startCmd == NULL || pProcessId == NULL) {
134 return HAL_FAILURE;
135 }
136 pid_t pid = fork();
137 if (pid < 0) {
138 LOGE("Create wpa process failed!");
139 return HAL_FAILURE;
140 }
141 if (pid == 0) { /* sub process */
142 // The child process will receive the exit signal when the parent process exits.
143 prctl(PR_SET_PDEATHSIG, SIGKILL);
144 pthread_t tid;
145 int ret = pthread_create(&tid, NULL, WpaThreadMain, (void *)startCmd);
146 if (ret != 0) {
147 LOGE("Create wpa thread failed!");
148 return HAL_FAILURE;
149 }
150 pthread_setname_np(tid, "WpaMainThread");
151 pthread_join(tid, NULL);
152 exit(0);
153 } else {
154 LOGE("Create wpa process id is [%{public}d], cmd:%{private}s", pid, startCmd);
155 *pProcessId = pid;
156 }
157 return HAL_SUCCESS;
158 }
159
StopModuleInternalKillProcess(pid_t processId)160 static int StopModuleInternalKillProcess(pid_t processId)
161 {
162 LOGI("Stop module kill process: %{public}d", processId);
163 if (kill(processId, SIGTERM) == -1) {
164 if (ESRCH == errno) {
165 LOGI("kill [%{public}d] success, pid no exist", processId);
166 return HAL_SUCCESS;
167 }
168 LOGE("kill [%{public}d] failed", processId);
169 return HAL_FAILURE;
170 }
171 return HAL_SUCCESS;
172 }
173
StopModuleInternalCheckProcess(const char * moduleName,pid_t processId)174 static int StopModuleInternalCheckProcess(const char *moduleName, pid_t processId)
175 {
176 if (moduleName == NULL) {
177 return HAL_SUCCESS;
178 }
179 LOGI("Stop module internal check wpa process: %{public}d", processId);
180 const int STOP_MODULE_TRY_TIMES = 30;
181 const int SLEEP_TIME_US = 1000 * 100; // 100ms
182 int tryTimes = STOP_MODULE_TRY_TIMES;
183 while (tryTimes-- >= 0) {
184 int ret = waitpid(processId, NULL, WNOHANG);
185 if (ret <= 0) {
186 LOGI("Waitpid %{public}d ret %{public}d, tryTimes %{public}d and retry", processId, ret, tryTimes);
187 usleep(SLEEP_TIME_US);
188 continue;
189 } else {
190 LOGI("Stop wpa process [%{public}d] success, tryTimes %{public}d", processId, tryTimes);
191 return HAL_SUCCESS;
192 }
193 }
194 LOGE("Stop wpa process [%{public}d] failed for timeout, try to kill process", processId);
195 StopModuleInternalKillProcess(processId);
196 return HAL_SUCCESS;
197 }
198
StopModuleInternalSendTerminate(void)199 static int StopModuleInternalSendTerminate(void)
200 {
201 WifiWpaInterface *pWpaInterface = GetWifiWapGlobalInterface();
202 if (pWpaInterface == NULL) {
203 LOGE("Get wpa global interface failed!");
204 return HAL_FAILURE;
205 }
206 int ret = pWpaInterface->wpaCliTerminate();
207 return (ret == 0 ? HAL_SUCCESS : HAL_FAILURE);
208 }
209
StopModuleInternalSoftAp(void)210 static int StopModuleInternalSoftAp(void)
211 {
212 int id = 0;
213 WifiHostapdHalDevice *hostapdHalDevice = GetWifiHostapdDev(id);
214 if (hostapdHalDevice == NULL) {
215 LOGE("Get hostap dev interface failed!");
216 return WIFI_HAL_FAILED;
217 }
218 if (hostapdHalDevice->terminateAp(id) != 0) {
219 LOGE("terminateAp failed!");
220 return WIFI_HAL_FAILED;
221 }
222 return WIFI_HAL_SUCCESS;
223 }
224
StopModuleInternal(const char * moduleName,pid_t processId,bool isHostapd)225 int StopModuleInternal(const char *moduleName, pid_t processId, bool isHostapd)
226 {
227 int ret;
228 if (isHostapd) {
229 ret = StopModuleInternalSoftAp();
230 } else {
231 ret = StopModuleInternalSendTerminate();
232 }
233 if (ret != HAL_SUCCESS) {
234 LOGE("Send stop module command failed!");
235 }
236 return StopModuleInternalCheckProcess(moduleName, processId);
237 }
238
GetStartedModule(void)239 ModuleInfo *GetStartedModule(void)
240 {
241 ModuleInfo *p = g_halModuleList;
242 while (p != NULL) {
243 if (p->referenceCount > 0) {
244 break;
245 } else {
246 p = p->next;
247 }
248 }
249 return p;
250 }
251
FindModule(const char * moduleName)252 ModuleInfo *FindModule(const char *moduleName)
253 {
254 if (moduleName == NULL) {
255 return NULL;
256 }
257 ModuleInfo *p = g_halModuleList;
258 while (p != NULL) {
259 if (strcmp(p->szModuleName, moduleName) == 0) {
260 break;
261 } else {
262 p = p->next;
263 }
264 }
265 return p;
266 }
267
StartModule(const char * moduleName,const char * startCmd)268 ModuleManageRetCode StartModule(const char *moduleName, const char *startCmd)
269 {
270 if (moduleName == NULL || startCmd == NULL) {
271 return MM_FAILED;
272 }
273 ModuleInfo *p = FindModule(moduleName);
274 if (p != NULL) {
275 p->referenceCount += 1;
276 if (p->referenceCount > REFERENCE_CNT_MAX) {
277 p->referenceCount = REFERENCE_CNT_MAX;
278 }
279 LOGI("module %{public}s has been started, current reference is %{public}d", moduleName, p->referenceCount);
280 return MM_SUCCESS;
281 }
282 p = (ModuleInfo *)calloc(1, sizeof(ModuleInfo));
283 if (p == NULL) {
284 return MM_FAILED;
285 }
286 if (strcpy_s(p->szModuleName, sizeof(p->szModuleName), moduleName) != EOK) {
287 free(p);
288 p = NULL;
289 return MM_FAILED;
290 }
291 int ret = StartModuleInternal(moduleName, startCmd, &(p->processId));
292 if (ret != 0) { /* start module failed! */
293 free(p);
294 p = NULL;
295 return MM_FAILED;
296 }
297 p->referenceCount = 1;
298 p->next = g_halModuleList;
299 g_halModuleList = p;
300 return MM_SUCCESS;
301 }
302
StopModule(const char * moduleName,bool isHostapd)303 ModuleManageRetCode StopModule(const char *moduleName, bool isHostapd)
304 {
305 if (moduleName == NULL) {
306 return MM_FAILED;
307 }
308 ModuleInfo *p = FindModule(moduleName);
309 if (p == NULL) {
310 return MM_SUCCESS;
311 }
312 if (isHostapd) {
313 p->referenceCount = 0;
314 } else {
315 p->referenceCount -= 1;
316 }
317 if (p->referenceCount > 0) {
318 LOGI("module %{public}s reference left %{public}d, return ok", moduleName, p->referenceCount);
319 return MM_REDUCE_REFERENCE;
320 } else if (p->referenceCount < 0) {
321 p->referenceCount = 1;
322 }
323 int ret = StopModuleInternal(p->szModuleName, p->processId, isHostapd);
324 if (ret != 0) { /* stop module failed! */
325 p->referenceCount += 1;
326 return MM_FAILED;
327 }
328 if (p == g_halModuleList) {
329 g_halModuleList = p->next;
330 } else {
331 ModuleInfo *q = g_halModuleList;
332 while (q != NULL && q->next != p) {
333 q = q->next;
334 }
335 if (q != NULL) {
336 q->next = p->next;
337 }
338 }
339 free(p);
340 p = NULL;
341 return MM_SUCCESS;
342 }
343