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, &param);
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