• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 #include <strings.h>
16 #include <stdlib.h>
17 #include <sys/types.h>
18 #include <signal.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <sys/stat.h>
22 #include <stdio.h>
23 #include <errno.h>
24 #include <ctype.h>
25 
26 #include "securec.h"
27 #include "dhcp_client.h"
28 #include "dhcp_function.h"
29 
30 #undef LOG_TAG
31 #define LOG_TAG "WifiDhcpMain"
32 
33 /* Static declared. */
34 static int Usage(void);
35 static int RunChildProcess(void);
36 static int CreateDaemon(void);
37 static int CheckClientProParam(const int argc, char *argv[]);
38 static int GetClientOption(int argc, char *argv[]);
39 static int InitSpecifiedClientCfg(int argc, char *argv[]);
40 static int ExecClientProAction(const char *action);
41 static int GetClientNetworkInfo(void);
42 
43 static struct DhcpClientCfg *g_cltCfg;
44 
45 /* Static defined. */
Usage(void)46 static int Usage(void)
47 {
48     printf("\nUsage:  dhcp_client_service ACTION INTERFACE [OPTION]\n");
49     printf("  ACTION = start|stop|status|help|ver\n");
50     printf("    start     - start INTERFACE's network interface service\n");
51     printf("    stop      - stop INTERFACE's network interface service\n");
52     printf("    status    - show INTERFACE's service status and exit\n");
53     printf("    help      - displays usage info, INTERFACE is optional\n");
54     printf("    ver       - displays client version, INTERFACE is optional\n");
55     printf("  INTERFACE = ifname, eg: wlan0\n");
56     printf("  OPTION = -w <directory>|-a or -4\n");
57     printf("    -w <directory> - specify the client's working directory\n");
58     printf("    -a - handle dhcp v4 and v6\n");
59     printf("    -4 - only handle dhcp v4\n");
60     printf("\n========== running process operate ==========\n");
61     printf("  send dhcp release packet  =  kill -USR1 <pid>  \n");
62     printf("  send dhcp renew   packet  =  kill -USR2 <pid>  \n\n");
63     return DHCP_OPT_SUCCESS;
64 }
65 
RunChildProcess(void)66 static int RunChildProcess(void)
67 {
68     if (setpgrp() == -1) {
69         LOGE("RunChildProcess() can not change process group, return!");
70         return DHCP_OPT_FAILED;
71     }
72 
73     if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
74         LOGE("RunChildProcess() signal SIGHUP SIG_ERR, return!");
75         return DHCP_OPT_FAILED;
76     }
77 
78     /* Ensure we can never get a controlling terminal. */
79     pid_t childPid;
80     switch (childPid = fork()) {
81         case -1:
82             LOGE("RunChildProcess() fork grandchild failed, return!");
83             return DHCP_OPT_FAILED;
84         case 0:
85             /* Grandchild process continue run. */
86             break;
87         default:
88             /* Child process exit now. */
89             exit(EXIT_SUCCESS);
90     }
91     LOGI("RunChildProcess() child: fork grand suc, childPid:%{public}d,pid():%{public}d,ppid():%{public}d.",
92         childPid, getpid(), getppid());
93     return DHCP_OPT_SUCCESS;
94 }
95 
CreateDaemon(void)96 static int CreateDaemon(void)
97 {
98     LOGI("CreateDaemon() enter, pid:%{public}d, ppid:%{public}d.", getpid(), getppid());
99 
100     /* A daemon process need close all open files. */
101     if (fclose(stdin) != 0) {
102         LOGE("CreateDaemon() fclose stdin error:%{public}d!", errno);
103         return DHCP_OPT_FAILED;
104     }
105     if (fclose(stdout) != 0) {
106         LOGE("CreateDaemon() fclose stdout error:%{public}d!", errno);
107         return DHCP_OPT_FAILED;
108     }
109     if (fclose(stderr) != 0) {
110         LOGE("CreateDaemon() fclose stderr error:%{public}d!", errno);
111         return DHCP_OPT_FAILED;
112     }
113 
114     /* Ensure that the process is not a fork subprocess, init process id is 1. */
115     if (getppid() == 1) {
116         LOGI("CreateDaemon() getppid() == 1, the process's parent is already init process!");
117         /* Set default permissions for files and directories. */
118         umask(DEFAULT_UMASK);
119         return DHCP_OPT_SUCCESS;
120     }
121 
122     pid_t pid;
123     switch (pid = fork()) {
124         case -1:
125             LOGE("CreateDaemon() fork first child failed, return!");
126             return DHCP_OPT_FAILED;
127         case 0:
128             if (RunChildProcess() != DHCP_OPT_SUCCESS) {
129                 LOGE("CreateDaemon() RunChildProcess failed, return!");
130                 return DHCP_OPT_FAILED;
131             };
132             /* Child process continue run. */
133             break;
134         default:
135             /* Parent process exit now. */
136             exit(EXIT_SUCCESS);
137     }
138 
139     /* We have forked, setpgrp, forked once more, from now on, we are a daemon process. */
140     LOGI("CreateDaemon() grandchild continue run, pid:%{public}d,getpid():%{public}d,getppid():%{public}d.",
141         pid, getpid(), getppid());
142     umask(DEFAULT_UMASK);
143     return DHCP_OPT_SUCCESS;
144 }
145 
CheckClientProParam(const int argc,char * argv[])146 static int CheckClientProParam(const int argc, char *argv[])
147 {
148     if (argc <= NUMBER_ONE) {
149         printf("CheckClientProParam() argc:%d error, please input valid ACTION!\n", argc);
150         Usage();
151         return -1;
152     }
153 
154     /* Check client process param ACTION "help","ver". */
155     const char *cmdParam = argv[NUMBER_ONE];
156     if (strncasecmp(cmdParam, "help", NUMBER_FOUR) == 0) {
157         Usage();
158         return 1;
159     } else if (strncasecmp(cmdParam, "ver", NUMBER_THREE) == 0) {
160         printf("%s, version %s\n", DHCPC_NAME, DHCPC_VERSION);
161         return 1;
162     } else {
163         /* Check client process param ACTION "start","stop","status". */
164         if ((strncasecmp(cmdParam, "start", NUMBER_FIVE) != 0) && (strncasecmp(cmdParam, "stop", NUMBER_FOUR) != 0) &&
165             (strncasecmp(cmdParam, "status", NUMBER_FIVE) != 0)) {
166             printf("CheckClientProParam() argv[1]:%s error, please input valid ACTION!\n", cmdParam);
167             Usage();
168             return -1;
169         }
170         /* Check client process running argc. */
171         if (argc <= NUMBER_TWO) {
172             printf("CheckClientProParam() argc:%d error, please input valid INTERFACE!\n", argc);
173             Usage();
174             return -1;
175         }
176     }
177     return 0;
178 }
179 
GetClientOption(int argc,char * argv[])180 static int GetClientOption(int argc, char *argv[])
181 {
182     int ch;
183     while ((ch = getopt(argc - NUMBER_TWO, argv + NUMBER_TWO, "w:a46")) != -1) {
184         switch (ch) {
185             case 'w':   /* Specify the client's working directory. */
186                 LOGI("GetClientOption() cur workDir:%{public}s, optarg:%{public}s", g_cltCfg->workDir, optarg);
187                 if (strncpy_s(g_cltCfg->workDir, sizeof(g_cltCfg->workDir), optarg, DIR_MAX_LEN - 1) != EOK) {
188                     return -1;
189                 }
190                 break;
191             case 'a':    /* Handle dhcp v4 and v6. */
192                 g_cltCfg->getMode = DHCP_IP_TYPE_ALL;
193                 break;
194             case '4':    /* Only handle dhcp v4. */
195                 LOGI("GetClientOption() cur getMode:%{public}u, optarg:%{public}s", g_cltCfg->getMode, optarg);
196                 g_cltCfg->getMode = DHCP_IP_TYPE_V4;
197                 break;
198             case '6':    /* Only handle dhcp v6. */
199                 g_cltCfg->getMode = DHCP_IP_TYPE_V6;
200                 break;
201             default:
202                 printf("GetClientOption() please input valid OPTION!\n");
203                 Usage();
204                 return -1;
205         }
206     }
207     return 0;
208 }
209 
CheckIfaceNameIsLegal(const char * argv)210 static int CheckIfaceNameIsLegal(const char *argv)
211 {
212     if (argv == NULL) {
213         LOGE("parameter error, argv is NULL!");
214         return DHCP_OPT_FAILED;
215     }
216 
217     char ifaceName[INFNAME_SIZE] = {0};
218     if (strncpy_s(ifaceName, INFNAME_SIZE, argv, INFNAME_SIZE - 1) != EOK) {
219         LOGE("call strncpy_s fail!");
220         return DHCP_OPT_FAILED;
221     }
222 
223     if (strlen(ifaceName) == 0) {
224         LOGE("parameter error, ifaceName len is zero!");
225         return DHCP_OPT_FAILED;
226     }
227 
228     for (int i = 0; i < strlen(ifaceName) - 1; ++i) {
229         if ((isalnum(ifaceName[i]) == 0) && ifaceName[i] != '-' && ifaceName[i] != '_') {
230             LOGE("parameter error, ifaceName is illegal!");
231             return DHCP_OPT_FAILED;
232         }
233     }
234 
235     return DHCP_OPT_SUCCESS;
236 }
237 
InitSpecifiedClientCfg(int argc,char * argv[])238 static int InitSpecifiedClientCfg(int argc, char *argv[])
239 {
240     if (argc < NUMBER_TWO + 1) {
241         LOGE("parameter error!");
242         return DHCP_OPT_FAILED;
243     }
244 
245     if (CheckIfaceNameIsLegal(argv[NUMBER_TWO]) != DHCP_OPT_SUCCESS) {
246         LOGE("parameter error, CheckIfaceNameIsLegal fail!");
247         return DHCP_OPT_FAILED;
248     }
249 
250     g_cltCfg = GetDhcpClientCfg();
251     if ((strncpy_s(g_cltCfg->workDir, sizeof(g_cltCfg->workDir), WORKDIR, DIR_MAX_LEN - 1) != EOK) ||
252         (strncpy_s(g_cltCfg->ifaceName, sizeof(g_cltCfg->ifaceName), argv[NUMBER_TWO], INFNAME_SIZE - 1) != EOK)) {
253         return DHCP_OPT_FAILED;
254     }
255     g_cltCfg->getMode = DHCP_IP_TYPE_ALL;
256     if ((argc > NUMBER_THREE) && (GetClientOption(argc, argv) != 0)) {
257         LOGE("InitSpecifiedClientCfg() GetClientOption failed!");
258         return DHCP_OPT_FAILED;
259     }
260 
261     if (strlen(g_cltCfg->workDir) == 0) {
262         LOGE("InitSpecifiedClientCfg() g_cltCfg->workDir:%{public}s error!", g_cltCfg->workDir);
263         return DHCP_OPT_FAILED;
264     }
265     if (CreateDirs(g_cltCfg->workDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != DHCP_OPT_SUCCESS) {
266         LOGE("InitSpecifiedClientCfg() CreateDirs %{public}s failed!", g_cltCfg->workDir);
267         return DHCP_OPT_FAILED;
268     }
269 
270     if (snprintf_s(g_cltCfg->confFile, DIR_MAX_LEN, DIR_MAX_LEN - 1, "%s%s", g_cltCfg->workDir, DHCPC_CONF) < 0) {
271         return DHCP_OPT_FAILED;
272     }
273 
274     if (snprintf_s(g_cltCfg->pidFile, DIR_MAX_LEN, DIR_MAX_LEN - 1, "%s%s.pid",
275         g_cltCfg->workDir, g_cltCfg->ifaceName) < 0) {
276         return DHCP_OPT_FAILED;
277     }
278 
279     if (snprintf_s(g_cltCfg->resultFile, DIR_MAX_LEN, DIR_MAX_LEN - 1, "%s%s.result",
280         g_cltCfg->workDir, g_cltCfg->ifaceName) < 0) {
281         return DHCP_OPT_FAILED;
282     }
283 
284     if (snprintf_s(g_cltCfg->leaseFile, DIR_MAX_LEN, DIR_MAX_LEN - 1, "%sdhcp_client_service-%s.lease",
285         g_cltCfg->workDir, g_cltCfg->ifaceName) < 0) {
286         return DHCP_OPT_FAILED;
287     }
288 
289     LOGD("InitSpecifiedClientCfg: "
290         "g_cltCfg->workDir:%{public}s,confFile:%{public}s,pidFile:%{public}s,resultFile:%{public}s,getMode:%{public}d",
291         g_cltCfg->workDir, g_cltCfg->confFile, g_cltCfg->pidFile, g_cltCfg->resultFile, g_cltCfg->getMode);
292 
293     return DHCP_OPT_SUCCESS;
294 }
295 
ExecClientProAction(const char * action)296 static int ExecClientProAction(const char *action)
297 {
298     /* Stop the specified network interface service. */
299     if (strncasecmp(action, "stop", NUMBER_FOUR) == 0) {
300         if (StopProcess(g_cltCfg->pidFile) != DHCP_OPT_SUCCESS) {
301             LOGD("ExecClientProAction() StopProcess pidFile:%{public}s not success.", g_cltCfg->pidFile);
302         } else {
303             LOGD("ExecClientProAction() StopProcess pidFile:%{public}s success.", g_cltCfg->pidFile);
304         }
305         return 1;
306     }
307 
308     /* Get the specified client process running status. */
309     int proStatus = GetProStatus(g_cltCfg->pidFile);
310     if (strncasecmp(action, "status", NUMBER_FIVE) == 0) {
311         LOGI("ExecClientProAction() action:%{public}s GetProStatus proStatus:%{public}d.", action, proStatus);
312         return 1;
313     }
314 
315     /* Check the specified client process param ACTION. */
316     if (strncasecmp(action, "start", NUMBER_FIVE) != 0) {
317         LOGE("ExecClientProAction() argv[1]:%{public}s error, please input valid ACTION!", action);
318         Usage();
319         return -1;
320     }
321     if (proStatus == 1) {
322         LOGI("ExecClientProAction() the specified client process is already started!");
323         return 1;
324     }
325 
326     /* Record the parent process id that creates the daemon */
327     g_cltCfg->parentProcessId = getppid();
328 
329     /* Create a daemon process. */
330     if (CreateDaemon() != DHCP_OPT_SUCCESS) {
331         LOGE("ExecClientProAction() CreateDaemon failed!");
332         return -1;
333     }
334 
335     /* Init the specified client process id info. */
336     if (InitPidfile(g_cltCfg->workDir, g_cltCfg->pidFile, getpid()) != DHCP_OPT_SUCCESS) {
337         LOGE("ExecClientProAction() InitPidfile failed, ifaceName:%{public}s.", g_cltCfg->ifaceName);
338         return -1;
339     }
340 
341     return 0;
342 }
343 
GetClientNetworkInfo(void)344 static int GetClientNetworkInfo(void)
345 {
346     if (GetLocalInterface(g_cltCfg->ifaceName, &g_cltCfg->ifaceIndex, g_cltCfg->ifaceMac, NULL) != DHCP_OPT_SUCCESS) {
347         LOGE("GetClientNetworkInfo() GetLocalInterface failed, ifaceName:%{public}s.", g_cltCfg->ifaceName);
348         return DHCP_OPT_FAILED;
349     }
350     char macAddr[MAC_ADDR_LEN * MAC_ADDR_CHAR_NUM];
351     if (memset_s(macAddr, sizeof(macAddr), 0, sizeof(macAddr)) != EOK) {
352         return DHCP_OPT_FAILED;
353     }
354     MacChConToMacStr(g_cltCfg->ifaceMac, MAC_ADDR_LEN, macAddr, sizeof(macAddr));
355     LOGD("GetClientNetworkInfo() g_cltCfg->ifaceName:%{public}s -> ifaceIndex:%{private}d,ifaceMac:%{private}s.",
356         g_cltCfg->ifaceName, g_cltCfg->ifaceIndex, macAddr);
357 
358     if (GetLocalIp(g_cltCfg->ifaceName, &g_cltCfg->ifaceIpv4) != DHCP_OPT_SUCCESS) {
359         LOGE("GetClientNetworkInfo() failed, g_cltCfg->ifaceName:%{public}s.", g_cltCfg->ifaceName);
360         return DHCP_OPT_FAILED;
361     }
362     char *cIp = Ip4IntConToStr(g_cltCfg->ifaceIpv4, true);
363     if (cIp == NULL) {
364         LOGE("GetClientNetworkInfo() Ip4IntConToStr g_cltCfg->ifaceIpv4 failed!");
365         return DHCP_OPT_FAILED;
366     }
367     LOGD("GetClientNetworkInfo() GetLocalIp ifaceName:%{public}s -> ifaceIpv4:%{private}u - %{private}s.",
368         g_cltCfg->ifaceName, g_cltCfg->ifaceIpv4, cIp);
369     free(cIp);
370     cIp = NULL;
371 
372     /* Generate clientid for the specified client process interface. */
373     if (g_cltCfg->pOptClientId == NULL) {
374         g_cltCfg->pOptClientId = malloc(DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES + MAC_ADDR_LEN + 1);
375         if (g_cltCfg->pOptClientId == NULL) {
376             LOGE("GetClientNetworkInfo() g_cltCfg->pOptClientId malloc failed!");
377             return DHCP_OPT_FAILED;
378         }
379         g_cltCfg->pOptClientId[DHCP_OPT_CODE_INDEX] = CLIENT_IDENTIFIER_OPTION;
380         g_cltCfg->pOptClientId[DHCP_OPT_LEN_INDEX] = MAC_ADDR_LEN + 1;
381         /* Generate format: 1 + ifaceMac. */
382         g_cltCfg->pOptClientId[DHCP_OPT_DATA_INDEX] = NUMBER_ONE;
383         if (memcpy_s(g_cltCfg->pOptClientId + DHCP_OPT_DATA_INDEX + 1,
384             MAC_ADDR_LEN,
385             g_cltCfg->ifaceMac,
386             MAC_ADDR_LEN) != EOK) {
387             return DHCP_OPT_FAILED;
388         }
389     }
390 
391     return DHCP_OPT_SUCCESS;
392 }
393 
main(int argc,char * argv[])394 int main(int argc, char *argv[])
395 {
396     /* Check client process running param ACTION. */
397     int nCheck = CheckClientProParam(argc, argv);
398     if (nCheck != 0) {
399         return (nCheck == 1) ? EXIT_SUCCESS : EXIT_FAILURE;
400     }
401 
402     /* Init the specified client process config. */
403     if (InitSpecifiedClientCfg(argc, argv) != DHCP_OPT_SUCCESS) {
404         LOGE("main() InitSpecifiedClientCfg failed!");
405         return EXIT_FAILURE;
406     }
407 
408     /* Exec the specified client process ACTION. */
409     if (argc < NUMBER_ONE + 1) {
410         LOGE("parameter number is error!");
411         return EXIT_FAILURE;
412     }
413     const char *cmdParam = argv[NUMBER_ONE];
414     int nExec = ExecClientProAction(cmdParam);
415     if (nExec != 0) {
416         return (nExec == 1) ? EXIT_SUCCESS : EXIT_FAILURE;
417     }
418 
419     /* Get the specified client process interface network info. */
420     if (GetClientNetworkInfo() != DHCP_OPT_SUCCESS) {
421         LOGE("main() GetClientNetworkInfo failed!");
422         return EXIT_FAILURE;
423     }
424 
425     /* Start the specified network interface service. */
426     if (StartProcess() != DHCP_OPT_SUCCESS) {
427         LOGE("main() StartProcess failed!");
428         return EXIT_FAILURE;
429     }
430 
431     LOGI("main() end, argc:%{public}d.", argc);
432     return EXIT_SUCCESS;
433 }
434