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