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