• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "dhcp_ipv4.h"
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <fcntl.h>
22 #include <time.h>
23 #include <errno.h>
24 #include <signal.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/socket.h>
28 #include <sys/file.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <netinet/if_ether.h>
32 #include <net/if_arp.h>
33 
34 #include "securec.h"
35 #include "dhcp_client.h"
36 #include "dhcp_options.h"
37 #include "dhcp_socket.h"
38 #include "dhcp_function.h"
39 
40 #undef LOG_TAG
41 #define LOG_TAG "WifiDhcpIpv4"
42 
43 struct ArpPacket {
44     struct ethhdr ethh;                 /* Ethernet header */
45     struct arphdr arph;                 /* Arp header */
46     u_char  sHaddr[6];                  /* sender's hardware address */
47     u_char  sInaddr[4];                 /* sender's IP address */
48     u_char  tHaddr[6];                  /* target's hardware address */
49     u_char  tInaddr[4];                 /* target's IP address */
50     u_char  pad[18];                    /* pad for min. Ethernet payload (60 bytes) */
51 };
52 
53 /* static defined */
54 static int g_dhcp4State = DHCP_STATE_INIT;
55 static int g_sockFd = -1;
56 static int g_sigSockFds[NUMBER_TWO];
57 static uint32_t g_sentPacketNum = 0;
58 static uint32_t g_timeoutTimestamp = 0;
59 static uint32_t g_renewalTimestamp = 0;
60 static uint32_t g_leaseTime = 0;
61 static uint32_t g_renewalSec = 0;
62 static uint32_t g_rebindSec = 0;
63 static uint32_t g_requestedIp4 = 0;
64 static uint32_t g_serverIp4 = 0;
65 static uint32_t g_socketMode = SOCKET_MODE_INVALID;
66 static uint32_t g_transID = 0;
67 
68 static struct DhcpClientCfg *g_cltCnf;
69 
GetPacketReadSockFd(void)70 int GetPacketReadSockFd(void)
71 {
72     return g_sockFd;
73 }
74 
GetSigReadSockFd(void)75 int GetSigReadSockFd(void)
76 {
77     return g_sigSockFds[0];
78 }
79 
GetDhcpTransID(void)80 uint32_t GetDhcpTransID(void)
81 {
82     return g_transID;
83 }
84 
85 /* Send signals. */
SignalHandler(int signum)86 static void SignalHandler(int signum)
87 {
88     switch (signum) {
89         case SIGTERM:
90             /* Send signal SIGTERM. */
91         case SIGUSR1:
92             /* Send signal SIGUSR1. */
93         case SIGUSR2:
94             /* Send signal SIGUSR2. */
95             send(g_sigSockFds[1], &signum, sizeof(signum), MSG_DONTWAIT);
96             break;
97         default:
98             break;
99     }
100 }
101 
102 /* Set the socket mode. */
SetSocketMode(uint32_t mode)103 void SetSocketMode(uint32_t mode)
104 {
105     close(g_sockFd);
106     g_sockFd = -1;
107     g_socketMode = mode;
108     LOGI("SetSocketMode() the socket mode %{public}s.", (mode == SOCKET_MODE_RAW) ? "raw"
109         : ((mode == SOCKET_MODE_KERNEL) ? "kernel" : "not valid"));
110 }
111 
112 /* Execution dhcp release. */
ExecDhcpRelease(void)113 int ExecDhcpRelease(void)
114 {
115     /* Ensure that we've received dhcp ack packet completely. */
116     if ((g_dhcp4State == DHCP_STATE_BOUND) || (g_dhcp4State == DHCP_STATE_RENEWING) ||
117         (g_dhcp4State == DHCP_STATE_REBINDING)) {
118         /* Unicast dhcp release packet. */
119         DhcpRelease(g_requestedIp4, g_serverIp4);
120     }
121 
122     g_dhcp4State = DHCP_STATE_RELEASED;
123     SetSocketMode(SOCKET_MODE_INVALID);
124 
125     /* Ensure that the function select() is always blocked and don't need to receive ip from dhcp server. */
126     g_timeoutTimestamp = SIGNED_INTEGER_MAX;
127 
128     LOGI("ExecDhcpRelease() enter released state...");
129     return DHCP_OPT_SUCCESS;
130 }
131 
132 /* Execution dhcp renew. */
ExecDhcpRenew(void)133 int ExecDhcpRenew(void)
134 {
135     /* Set socket mode and dhcp ipv4 state, make sure dhcp packets can be sent normally. */
136     switch (g_dhcp4State) {
137         case DHCP_STATE_INIT:
138         case DHCP_STATE_SELECTING:
139             LOGI("ExecDhcpRenew() dhcp ipv4 old state:%{public}d, no need change state.", g_dhcp4State);
140             break;
141         case DHCP_STATE_REQUESTING:
142         case DHCP_STATE_RELEASED:
143         case DHCP_STATE_RENEWED:
144             LOGI("ExecDhcpRenew() dhcp ipv4 old state:%{public}d, init state:INIT.", g_dhcp4State);
145             /* Init socket mode and dhcp ipv4 state. */
146             g_dhcp4State = DHCP_STATE_INIT;
147             SetSocketMode(SOCKET_MODE_RAW);
148             break;
149         case DHCP_STATE_BOUND:
150             /* Set socket mode, send unicast packet. */
151             SetSocketMode(SOCKET_MODE_KERNEL);
152         case DHCP_STATE_RENEWING:
153         case DHCP_STATE_REBINDING:
154             LOGI("ExecDhcpRenew() dhcp ipv4 old state:%{public}d, set state:RENEWED.", g_dhcp4State);
155             /* Set dhcp ipv4 state, send request packet. */
156             g_dhcp4State = DHCP_STATE_RENEWED;
157             break;
158         default:
159             break;
160     }
161 
162     /* Start record again, go back to init state. */
163     g_sentPacketNum = 0;
164     g_timeoutTimestamp = 0;
165 
166     LOGI("ExecDhcpRenew() a dhcp renew is executed...");
167     return DHCP_OPT_SUCCESS;
168 }
169 
170 /* Add dhcp option parameter request list. */
AddParamaterRequestList(struct DhcpPacket * packet)171 static void AddParamaterRequestList(struct DhcpPacket *packet)
172 {
173     int end = GetEndOptionIndex(packet->options);
174     int i;
175     int len = 0;
176     uint8_t arrReqCode[DHCP_REQ_CODE_NUM] = {SUBNET_MASK_OPTION,
177         ROUTER_OPTION,
178         DOMAIN_NAME_SERVER_OPTION,
179         HOST_NAME_OPTION,
180         DOMAIN_NAME_OPTION,
181         BROADCAST_ADDRESS_OPTION};
182 
183     packet->options[end + DHCP_OPT_CODE_INDEX] = PARAMETER_REQUEST_LIST_OPTION;
184     for (i = 0; i < DHCP_REQ_CODE_NUM; i++) {
185         if ((arrReqCode[i] > PAD_OPTION) && (arrReqCode[i] < END_OPTION)) {
186             packet->options[end + DHCP_OPT_DATA_INDEX + len++] = arrReqCode[i];
187         }
188     }
189     packet->options[end + DHCP_OPT_LEN_INDEX] = len;
190     packet->options[end + DHCP_OPT_DATA_INDEX + len] = END_OPTION;
191 }
192 
193 /* Init the socket fd. */
InitSocketFd(void)194 static void InitSocketFd(void)
195 {
196     if (g_sockFd < 0) {
197         if (g_socketMode == SOCKET_MODE_INVALID) {
198             return;
199         }
200 
201         bool bInitSuccess = true;
202         if (g_socketMode == SOCKET_MODE_RAW) {
203             if ((CreateRawSocket(&g_sockFd) != SOCKET_OPT_SUCCESS) ||
204                 (BindRawSocket(g_sockFd, g_cltCnf->ifaceIndex, NULL) != SOCKET_OPT_SUCCESS)) {
205                 LOGE("InitSocketFd() fd:%{public}d,index:%{public}d failed!", g_sockFd, g_cltCnf->ifaceIndex);
206                 bInitSuccess = false;
207             }
208         } else {
209             if ((CreateKernelSocket(&g_sockFd) != SOCKET_OPT_SUCCESS) ||
210                 (BindKernelSocket(g_sockFd, g_cltCnf->ifaceName, INADDR_ANY, BOOTP_CLIENT, true) !=
211                     SOCKET_OPT_SUCCESS)) {
212                 LOGE("InitSocketFd() fd:%{public}d,ifname:%{public}s failed!", g_sockFd, g_cltCnf->ifaceName);
213                 bInitSuccess = false;
214             }
215         }
216         if (!bInitSuccess || (g_sockFd < 0)) {
217             LOGE("InitSocketFd() %{public}d err:%{public}d, couldn't listen on socket!", g_sockFd, errno);
218             unlink(g_cltCnf->pidFile);
219             unlink(g_cltCnf->resultFile);
220             exit(EXIT_SUCCESS);
221         }
222     }
223 }
224 
225 /* Obtains a random number as the trans id. */
GetTransId(void)226 static uint32_t GetTransId(void)
227 {
228     static bool bSranded = false;
229     if (!bSranded) {
230         unsigned int uSeed = 0;
231         int nFd = -1;
232         if ((nFd = open("/dev/urandom", 0)) == -1) {
233             LOGE("GetTransId() open /dev/urandom failed, error:%{public}d!", errno);
234             uSeed = time(NULL);
235         } else {
236             if (read(nFd, &uSeed, sizeof(uSeed)) == -1) {
237                 LOGE("GetTransId() read /dev/urandom failed, error:%{public}d!", errno);
238                 uSeed = time(NULL);
239             }
240             LOGI("GetTransId() read /dev/urandom uSeed:%{public}u.", uSeed);
241             close(nFd);
242         }
243         srandom(uSeed);
244         bSranded = true;
245     }
246     return random();
247 }
248 
InitSelecting(time_t timestamp)249 static void InitSelecting(time_t timestamp)
250 {
251     if (g_sentPacketNum > TIMEOUT_TIMES_MAX) {
252         /* Send packet timed out, now exit process. */
253         LOGW("InitSelecting() send packet timed out %{public}u times, now exit process!", g_sentPacketNum);
254         g_timeoutTimestamp = timestamp + TIMEOUT_MORE_WAIT_SEC;
255         g_sentPacketNum = 0;
256         g_cltCnf->timeoutExit = true;
257         return;
258     }
259 
260     if (g_sentPacketNum == 0) {
261         g_transID = GetTransId();
262     }
263 
264     /* Broadcast dhcp discover packet. */
265     DhcpDiscover(g_transID, g_requestedIp4);
266     if (g_dhcp4State != DHCP_STATE_SELECTING) {
267         g_dhcp4State = DHCP_STATE_SELECTING;
268     }
269 
270     uint32_t uTimeoutSec = TIMEOUT_WAIT_SEC << g_sentPacketNum;
271     g_timeoutTimestamp = timestamp + uTimeoutSec;
272     LOGI("InitSelecting() DhcpDiscover g_sentPacketNum:%{public}u,timeoutSec:%{public}u,timestamp:%{public}u.",
273         g_sentPacketNum,
274         uTimeoutSec,
275         g_timeoutTimestamp);
276 
277     g_sentPacketNum++;
278 }
279 
ReadLease(void)280 static struct DhcpPacket *ReadLease(void)
281 {
282     if (g_cltCnf->leaseFile[0] == '\0') {
283         return NULL;
284     }
285 
286     int fd;
287     struct DhcpPacket *dhcp = NULL;
288     ssize_t rBytes;
289 
290     fd = open(g_cltCnf->leaseFile, O_RDONLY);
291     if (fd < 0) {
292         return NULL;
293     }
294 
295     dhcp = calloc(1, sizeof(*dhcp));
296     if (dhcp == NULL) {
297         close(fd);
298         return NULL;
299     }
300 
301     rBytes = read(fd, (uint8_t *)dhcp, sizeof(*dhcp));
302     close(fd);
303     if (rBytes <= 0 || (size_t)rBytes < offsetof(struct DhcpPacket, options)) {
304         free(dhcp);
305         dhcp = NULL;
306         return NULL;
307     }
308 
309     return dhcp;
310 }
311 
WriteLease(const struct DhcpPacket * pkt)312 static ssize_t WriteLease(const struct DhcpPacket *pkt)
313 {
314     if (pkt == NULL) {
315         return -1;
316     }
317 
318     if (g_cltCnf->leaseFile[0] == '\0') {
319         return -1;
320     }
321 
322     int fd;
323     ssize_t wBytes;
324 
325     fd = open(g_cltCnf->leaseFile, O_WRONLY | O_CREAT | O_TRUNC, RWMODE);
326     if (fd < 0) {
327         return -1;
328     }
329 
330     wBytes = write(fd, (uint8_t *)pkt, sizeof(*pkt));
331     close(fd);
332     return wBytes;
333 }
334 
AddParamaterRebootList(struct DhcpPacket * packet)335 static void AddParamaterRebootList(struct DhcpPacket *packet)
336 {
337     int end = GetEndOptionIndex(packet->options);
338     int i;
339     int len = 0;
340     uint8_t arrReqCode[DHCP_REQ_CODE_NUM] = {
341         SUBNET_MASK_OPTION,
342         STATIC_ROUTE_OPTION,
343         ROUTER_OPTION,
344         DOMAIN_NAME_SERVER_OPTION,
345         BROADCAST_ADDRESS_OPTION,
346         IP_ADDRESS_LEASE_TIME_OPTION,
347         RENEWAL_TIME_VALUE_OPTION,
348         REBINDING_TIME_VALUE_OPTION};
349 
350     packet->options[end + DHCP_OPT_CODE_INDEX] = PARAMETER_REQUEST_LIST_OPTION;
351     for (i = 0; i < DHCP_REQ_CODE_NUM; i++) {
352         if ((arrReqCode[i] > PAD_OPTION) && (arrReqCode[i] < END_OPTION)) {
353             packet->options[end + DHCP_OPT_DATA_INDEX + len++] = arrReqCode[i];
354         }
355     }
356     packet->options[end + DHCP_OPT_LEN_INDEX] = len;
357     packet->options[end + DHCP_OPT_DATA_INDEX + len] = END_OPTION;
358 }
359 
DhcpReboot(uint32_t transid,uint32_t reqip)360 static int DhcpReboot(uint32_t transid, uint32_t reqip)
361 {
362     LOGI("DhcpReboot() enter");
363     struct DhcpPacket packet;
364     if (memset_s(&packet, sizeof(struct DhcpPacket), 0, sizeof(struct DhcpPacket)) != EOK) {
365         return -1;
366     }
367 
368     /* Get packet header and common info. */
369     if (GetPacketHeaderInfo(&packet, DHCP_REQUEST) != DHCP_OPT_SUCCESS) {
370         return -1;
371     }
372 
373     if (memcpy_s(packet.chaddr, sizeof(packet.chaddr), g_cltCnf->ifaceMac, MAC_ADDR_LEN) != EOK) {
374         LOGE("DhcpReboot() failed, memcpy_s error!");
375         return -1;
376     }
377 
378     /* Get packet not common info. */
379     packet.xid = transid;
380     AddOptValueToOpts(packet.options, REQUESTED_IP_ADDRESS_OPTION, reqip);
381     AddOptValueToOpts(packet.options, MAXIMUM_DHCP_MESSAGE_SIZE_OPTION, MAX_MSG_SIZE);
382     AddOptValueToOpts(packet.options, FORCERENEW_NONCE_OPTION, 1);
383     AddParamaterRebootList(&packet);
384 
385     /* Begin broadcast dhcp request packet. */
386     char *pReqIp = Ip4IntConToStr(reqip, false);
387     if (pReqIp != NULL) {
388         LOGI("DhcpReboot() broadcast req packet, reqip: host %{private}u->%{private}s.", ntohl(reqip), pReqIp);
389         free(pReqIp);
390         pReqIp = NULL;
391     }
392     return SendToDhcpPacket(&packet, INADDR_ANY, INADDR_BROADCAST, g_cltCnf->ifaceIndex, (uint8_t *)MAC_BCAST_ADDR);
393 }
394 
SendReboot(struct DhcpPacket * p,time_t timestamp)395 void SendReboot(struct DhcpPacket *p, time_t timestamp)
396 {
397     if (p == NULL) {
398         return;
399     }
400 
401     g_requestedIp4 = p->yiaddr;
402 
403     free(p);
404     p = NULL;
405 
406     g_transID = GetTransId();
407     g_dhcp4State = DHCP_STATE_INITREBOOT;
408     g_sentPacketNum = 0;
409 
410     uint32_t uTimeoutSec = TIMEOUT_WAIT_SEC << g_sentPacketNum;
411     g_timeoutTimestamp = timestamp + uTimeoutSec;
412     DhcpReboot(g_transID, g_requestedIp4);
413 }
414 
Reboot(time_t timestamp)415 static void Reboot(time_t timestamp)
416 {
417     struct DhcpPacket *pkt = ReadLease();
418     if (pkt == NULL) {
419         return;
420     }
421 
422     uint32_t leaseTime;
423     uint32_t renewalTime;
424     uint32_t rebindTime;
425     uint32_t interval;
426     struct stat st;
427     if (!GetDhcpOptionUint32(pkt, IP_ADDRESS_LEASE_TIME_OPTION, &leaseTime)) {
428         leaseTime = ~0U;
429     }
430 
431     if (leaseTime != ~0U && stat(g_cltCnf->leaseFile, &st) == 0) {
432         if (timestamp == (time_t)-1 || timestamp < st.st_mtime || (time_t)leaseTime < timestamp - st.st_mtime) {
433             LOGI("Reboot read lease file leaseTime expire");
434             free(pkt);
435             pkt = NULL;
436             return;
437         } else {
438             interval = timestamp - st.st_mtime;
439             leaseTime -= interval;
440             renewalTime = leaseTime * RENEWAL_SEC_MULTIPLE;
441             rebindTime = leaseTime * REBIND_SEC_MULTIPLE;
442             LOGI("Reboot read lease file leaseTime:%{public}u, renewalTime:%{public}u, rebindTime:%{public}u",
443                 leaseTime, renewalTime, rebindTime);
444         }
445     } else {
446         LOGI("Reboot read lease file leaseTime option not found");
447         free(pkt);
448         pkt = NULL;
449         return;
450     }
451 
452     g_leaseTime = leaseTime;
453     g_renewalSec = renewalTime;
454     g_rebindSec = rebindTime;
455 
456     SendReboot(pkt, timestamp);
457 }
458 
Requesting(time_t timestamp)459 static void Requesting(time_t timestamp)
460 {
461     if (g_sentPacketNum > TIMEOUT_TIMES_MAX) {
462         /* Send packet timed out, now enter init state. */
463         g_dhcp4State = DHCP_STATE_INIT;
464         SetSocketMode(SOCKET_MODE_RAW);
465         g_sentPacketNum = 0;
466         g_timeoutTimestamp = timestamp;
467         return;
468     }
469 
470     if (g_dhcp4State == DHCP_STATE_RENEWED) {
471         /* Unicast dhcp request packet in the renew state. */
472         DhcpRenew(g_transID, g_requestedIp4, g_serverIp4);
473     } else {
474         /* Broadcast dhcp request packet in the requesting state. */
475         DhcpRequest(g_transID, g_requestedIp4, g_serverIp4);
476     }
477 
478     uint32_t uTimeoutSec = TIMEOUT_WAIT_SEC << g_sentPacketNum;
479     g_timeoutTimestamp = timestamp + uTimeoutSec;
480     LOGI("Requesting() DhcpRequest g_sentPacketNum:%{public}u,timeoutSec:%{public}u,g_timeoutTimestamp:%{public}u.",
481         g_sentPacketNum,
482         uTimeoutSec,
483         g_timeoutTimestamp);
484 
485     g_sentPacketNum++;
486 }
487 
Renewing(time_t timestamp)488 static void Renewing(time_t timestamp)
489 {
490     if ((g_renewalSec + TIME_INTERVAL_MAX) < g_rebindSec) {
491         /* Cur time is between renewal and rebind time, unicast dhcp request packet in the renew state. */
492         DhcpRenew(g_transID, g_requestedIp4, g_serverIp4);
493 
494         /* Set a new renewal time. */
495         g_renewalSec += (g_rebindSec - g_renewalSec) / NUMBER_TWO;
496         g_timeoutTimestamp = g_renewalTimestamp + g_renewalSec;
497         LOGI("Renewing() DhcpRenew unicast renewalTime:%{public}u,renewal:%{public}u,timeoutTime:%{public}u, "
498                   "rebind:%{public}u.",
499             g_renewalTimestamp,
500             g_renewalSec,
501             g_timeoutTimestamp,
502             g_rebindSec);
503     } else {
504         /* Cur time reaches rebind time, now enter rebinding state. */
505         g_dhcp4State = DHCP_STATE_REBINDING;
506         LOGI("Renewing() cur time reaches rebind time, now enter rebinding state...");
507         g_timeoutTimestamp = timestamp + (g_rebindSec - g_renewalSec);
508         LOGI("Renewing() timestamp:%{public}d,rebind:%{public}u,renewal:%{public}u, timeoutTime:%{public}u.",
509             (int)timestamp, g_rebindSec, g_renewalSec, g_timeoutTimestamp);
510     }
511 }
512 
Rebinding(time_t timestamp)513 static void Rebinding(time_t timestamp)
514 {
515     if ((g_rebindSec + TIME_INTERVAL_MAX) < g_leaseTime) {
516         /* Cur time is between rebind and lease time, broadcast dhcp request packet in the rebind state. */
517         DhcpRenew(g_transID, g_requestedIp4, 0);
518 
519         /* Set a new rebind time. */
520         g_rebindSec += (g_leaseTime - g_rebindSec) / NUMBER_TWO;
521         g_timeoutTimestamp = g_renewalTimestamp + g_rebindSec;
522         LOGI("Rebinding() DhcpRenew broadcast renewalTime:%{public}u,rebind:%{public}u,timeoutTime:%{public}u, "
523                   "lease:%{public}u.",
524             g_renewalTimestamp,
525             g_rebindSec,
526             g_timeoutTimestamp,
527             g_leaseTime);
528     } else {
529         /* Cur time reaches lease time, send packet timed out, now enter init state. */
530         LOGI("Rebinding() 555 cur time reaches lease time, now enter init state...");
531         g_dhcp4State = DHCP_STATE_INIT;
532         SetSocketMode(SOCKET_MODE_RAW);
533         g_sentPacketNum = 0;
534         g_timeoutTimestamp = timestamp;
535         return;
536     }
537 }
538 
DhcpRequestHandle(time_t timestamp)539 static void DhcpRequestHandle(time_t timestamp)
540 {
541     switch (g_dhcp4State) {
542         case DHCP_STATE_INIT:
543         case DHCP_STATE_SELECTING:
544             InitSelecting(timestamp);
545             break;
546         case DHCP_STATE_REQUESTING:
547         case DHCP_STATE_RENEWED:
548             Requesting(timestamp);
549             break;
550         case DHCP_STATE_BOUND:
551             /* Now the renewal time run out, ready to enter renewing state. */
552             LOGI("DhcpRequestHandle() 333 the renewal time run out, ready to enter renewing state...");
553             g_dhcp4State = DHCP_STATE_RENEWING;
554             SetSocketMode(SOCKET_MODE_KERNEL);
555         case DHCP_STATE_RENEWING:
556             Renewing(timestamp);
557             break;
558         case DHCP_STATE_REBINDING:
559             Rebinding(timestamp);
560             break;
561         case DHCP_STATE_INITREBOOT:
562             g_dhcp4State = DHCP_STATE_INIT;
563             break;
564         case DHCP_STATE_RELEASED:
565             /* Ensure that the function select() is always blocked and don't need to receive ip from dhcp server. */
566             g_timeoutTimestamp = SIGNED_INTEGER_MAX;
567             break;
568         default:
569             break;
570     }
571 }
572 
DhcpOfferPacketHandle(uint8_t type,const struct DhcpPacket * packet,time_t timestamp)573 static void DhcpOfferPacketHandle(uint8_t type, const struct DhcpPacket *packet, time_t timestamp)
574 {
575     if (type != DHCP_OFFER) {
576         LOGE("DhcpOfferPacketHandle() type:%{public}d error!", type);
577         return;
578     }
579 
580     if (packet == NULL) {
581         LOGE("DhcpOfferPacketHandle() type:%{public}d error, packet == NULL!", type);
582         return;
583     }
584 
585     uint32_t u32Data = 0;
586     if (!GetDhcpOptionUint32(packet, SERVER_IDENTIFIER_OPTION, &u32Data)) {
587         LOGE("DhcpOfferPacketHandle() type:%{public}d GetDhcpOptionUint32 SERVER_IDENTIFIER_OPTION failed!", type);
588         return;
589     }
590 
591     g_transID = packet->xid;
592     g_requestedIp4 = packet->yiaddr;
593     g_serverIp4 = htonl(u32Data);
594 
595     char *pReqIp = Ip4IntConToStr(g_requestedIp4, false);
596     if (pReqIp != NULL) {
597         LOGI(
598             "DhcpOfferPacketHandle() receive DHCP_OFFER, xid:%{public}u, requestIp: host %{private}u->%{private}s.",
599             g_transID,
600             ntohl(g_requestedIp4),
601             pReqIp);
602         free(pReqIp);
603         pReqIp = NULL;
604     }
605     char *pSerIp = Ip4IntConToStr(g_serverIp4, false);
606     if (pSerIp != NULL) {
607         LOGI("DhcpOfferPacketHandle() receive DHCP_OFFER, serverIp: host %{private}u->%{private}s.",
608             ntohl(g_serverIp4),
609             pSerIp);
610         free(pSerIp);
611         pSerIp = NULL;
612     }
613 
614     /* Receive dhcp offer packet finished, next send dhcp request packet. */
615     WriteLease(packet);
616     g_dhcp4State = DHCP_STATE_REQUESTING;
617     g_sentPacketNum = 0;
618     g_timeoutTimestamp = timestamp;
619 }
620 
ParseOtherNetworkInfo(const struct DhcpPacket * packet,struct DhcpResult * result)621 static void ParseOtherNetworkInfo(const struct DhcpPacket *packet, struct DhcpResult *result)
622 {
623     if ((packet == NULL) || (result == NULL)) {
624         LOGE("ParseOtherNetworkInfo() error, packet == NULL or result == NULL!");
625         return;
626     }
627 
628     uint32_t u32Data = 0;
629     uint32_t u32Data2 = 0;
630     if (GetDhcpOptionUint32n(packet, DOMAIN_NAME_SERVER_OPTION, &u32Data, &u32Data2)) {
631         char *pDnsIp = Ip4IntConToStr(u32Data, true);
632         if (pDnsIp != NULL) {
633             LOGI("ParseOtherNetworkInfo() recv DHCP_ACK 6, dns1: %{private}u->%{private}s.", u32Data, pDnsIp);
634             if (strncpy_s(result->strOptDns1, INET_ADDRSTRLEN, pDnsIp, INET_ADDRSTRLEN - 1) != EOK) {
635                 free(pDnsIp);
636                 pDnsIp = NULL;
637                 return;
638             }
639             free(pDnsIp);
640             pDnsIp = NULL;
641         }
642         if ((u32Data2 > 0) && ((pDnsIp = Ip4IntConToStr(u32Data2, true)) != NULL)) {
643             LOGI("ParseOtherNetworkInfo() recv DHCP_ACK 6, dns2: %{private}u->%{private}s.", u32Data2, pDnsIp);
644             if (strncpy_s(result->strOptDns2, INET_ADDRSTRLEN, pDnsIp, INET_ADDRSTRLEN - 1) != EOK) {
645                 LOGE("ParseOtherNetworkInfo() strncpy_s Failed.");
646             }
647             free(pDnsIp);
648             pDnsIp = NULL;
649             return;
650         }
651     }
652     return;
653 }
654 
ParseNetworkInfo(const struct DhcpPacket * packet,struct DhcpResult * result)655 static void ParseNetworkInfo(const struct DhcpPacket *packet, struct DhcpResult *result)
656 {
657     if ((packet == NULL) || (result == NULL)) {
658         LOGE("ParseNetworkInfo() error, packet == NULL or result == NULL!");
659         return;
660     }
661 
662     char *pReqIp = Ip4IntConToStr(g_requestedIp4, false);
663     if (pReqIp != NULL) {
664         LOGI("ParseNetworkInfo() recv DHCP_ACK yiaddr: %{private}u->%{private}s.", ntohl(g_requestedIp4), pReqIp);
665         if (strncpy_s(result->strYiaddr, INET_ADDRSTRLEN, pReqIp, INET_ADDRSTRLEN - 1) != EOK) {
666             LOGI("ParseNetworkInfo() strncpy_s failed!");
667             free(pReqIp);
668             pReqIp = NULL;
669             return;
670         }
671         free(pReqIp);
672         pReqIp = NULL;
673     }
674 
675     uint32_t u32Data = 0;
676     if (GetDhcpOptionUint32(packet, SUBNET_MASK_OPTION, &u32Data)) {
677         char *pSubIp = Ip4IntConToStr(u32Data, true);
678         if (pSubIp != NULL) {
679             LOGI("ParseNetworkInfo() recv DHCP_ACK 1, subnetmask: %{private}u->%{private}s.", u32Data, pSubIp);
680             if (strncpy_s(result->strOptSubnet, INET_ADDRSTRLEN, pSubIp, INET_ADDRSTRLEN - 1) != EOK) {
681                 free(pSubIp);
682                 pSubIp = NULL;
683                 return;
684             }
685             free(pSubIp);
686             pSubIp = NULL;
687         }
688     }
689 
690     u32Data = 0;
691     uint32_t u32Data2 = 0;
692     if (GetDhcpOptionUint32n(packet, ROUTER_OPTION, &u32Data, &u32Data2)) {
693         char *pRouterIp = Ip4IntConToStr(u32Data, true);
694         if (pRouterIp != NULL) {
695             LOGI("ParseNetworkInfo() recv DHCP_ACK 3, router1: %{private}u->%{private}s.", u32Data, pRouterIp);
696             if (strncpy_s(result->strOptRouter1, INET_ADDRSTRLEN, pRouterIp, INET_ADDRSTRLEN - 1) != EOK) {
697                 free(pRouterIp);
698                 pRouterIp = NULL;
699                 return;
700             }
701             free(pRouterIp);
702             pRouterIp = NULL;
703         }
704         if ((u32Data2 > 0) && ((pRouterIp = Ip4IntConToStr(u32Data2, true)) != NULL)) {
705             LOGI("ParseNetworkInfo() recv DHCP_ACK 3, router2: %{private}u->%{private}s.", u32Data2, pRouterIp);
706             if (strncpy_s(result->strOptRouter2, INET_ADDRSTRLEN, pRouterIp, INET_ADDRSTRLEN - 1) != EOK) {
707                 free(pRouterIp);
708                 pRouterIp = NULL;
709                 return;
710             }
711             free(pRouterIp);
712             pRouterIp = NULL;
713         }
714     }
715 
716     ParseOtherNetworkInfo(packet, result);
717 }
718 
FormatString(struct DhcpResult * result)719 static void FormatString(struct DhcpResult *result)
720 {
721     if (result == NULL) {
722         LOGE("FormatString() error, result == NULL!");
723         return;
724     }
725 
726     if (strlen(result->strYiaddr) == 0) {
727         if (strncpy_s(result->strYiaddr, INET_ADDRSTRLEN, "*", INET_ADDRSTRLEN - 1) != EOK) {
728             return;
729         }
730     }
731     if (strlen(result->strOptServerId) == 0) {
732         if (strncpy_s(result->strOptServerId, INET_ADDRSTRLEN, "*", INET_ADDRSTRLEN - 1) != EOK) {
733             return;
734         }
735     }
736     if (strlen(result->strOptSubnet) == 0) {
737         if (strncpy_s(result->strOptSubnet, INET_ADDRSTRLEN, "*", INET_ADDRSTRLEN - 1) != EOK) {
738             return;
739         }
740     }
741     if (strlen(result->strOptDns1) == 0) {
742         if (strncpy_s(result->strOptDns1, INET_ADDRSTRLEN, "*", INET_ADDRSTRLEN - 1) != EOK) {
743             return;
744         }
745     }
746     if (strlen(result->strOptDns2) == 0) {
747         if (strncpy_s(result->strOptDns2, INET_ADDRSTRLEN, "*", INET_ADDRSTRLEN - 1) != EOK) {
748             return;
749         }
750     }
751     if (strlen(result->strOptRouter1) == 0) {
752         if (strncpy_s(result->strOptRouter1, INET_ADDRSTRLEN, "*", INET_ADDRSTRLEN - 1) != EOK) {
753             return;
754         }
755     }
756     if (strlen(result->strOptRouter2) == 0) {
757         if (strncpy_s(result->strOptRouter2, INET_ADDRSTRLEN, "*", INET_ADDRSTRLEN - 1) != EOK) {
758             return;
759         }
760     }
761     if (strlen(result->strOptVendor) == 0) {
762         if (strncpy_s(result->strOptVendor, DHCP_FILE_MAX_BYTES, "*", DHCP_FILE_MAX_BYTES - 1) != EOK) {
763             return;
764         }
765     }
766 }
767 
WriteDhcpResult(struct DhcpResult * result)768 static int WriteDhcpResult(struct DhcpResult *result)
769 {
770     if (result == NULL) {
771         LOGE("WriteDhcpResult() error, result == NULL!");
772         return DHCP_OPT_FAILED;
773     }
774 
775     /* Format dhcp result. */
776     FormatString(result);
777 
778     uint32_t curTime = (uint32_t)time(NULL);
779     if ((time_t)curTime == (time_t)-1) {
780         return DHCP_OPT_FAILED;
781     }
782     LOGI("WriteDhcpResult() "
783          "result->strYiaddr:%{private}s,strOptServerId:%{private}s,strOptSubnet:%{private}s,uOptLeasetime:%{public}u,"
784          " curTime:%{public}u.",
785         result->strYiaddr, result->strOptServerId, result->strOptSubnet, result->uOptLeasetime, curTime);
786     FILE *pFile = fopen(g_cltCnf->resultFile, "w+");
787     if (pFile == NULL) {
788         LOGE("WriteDhcpResult fopen %{public}s err:%{public}d!", g_cltCnf->resultFile, errno);
789         return DHCP_OPT_FAILED;
790     }
791 
792     /* Lock the writing file. */
793     if (flock(fileno(pFile), LOCK_EX) != 0) {
794         LOGE("WriteDhcpResult() flock file:%{public}s LOCK_EX failed, error:%{public}d!", g_cltCnf->resultFile, errno);
795         fclose(pFile);
796         return DHCP_OPT_FAILED;
797     }
798 
799     /* Format: IP4 timestamp cliIp servIp subnet dns1 dns2 router1 router2 vendor lease. */
800     int nBytes = fprintf(pFile,
801         "IP4 %u %s %s %s %s %s %s %s %s %u\n",
802         curTime, result->strYiaddr, result->strOptServerId, result->strOptSubnet, result->strOptDns1,
803         result->strOptDns2, result->strOptRouter1, result->strOptRouter2, result->strOptVendor, result->uOptLeasetime);
804     if (nBytes <= 0) {
805         LOGE("WriteDhcpResult() fprintf %{public}s error:%{public}d!", g_cltCnf->resultFile, errno);
806         fclose(pFile);
807         return DHCP_OPT_FAILED;
808     }
809 
810     /* Unlock the writing file. */
811     if (flock(fileno(pFile), LOCK_UN) != 0) {
812         LOGE("WriteDhcpResult() flock file:%{public}s LOCK_UN failed, error:%{public}d!", g_cltCnf->resultFile, errno);
813         fclose(pFile);
814         return DHCP_OPT_FAILED;
815     }
816 
817     if (fclose(pFile) != 0) {
818         LOGE("WriteDhcpResult() fclose %{public}s error:%{public}d!", g_cltCnf->resultFile, errno);
819         return DHCP_OPT_FAILED;
820     }
821     LOGI("WriteDhcpResult() fprintf %{public}s success, nBytes:%{public}d.", g_cltCnf->resultFile, nBytes);
822     return DHCP_OPT_SUCCESS;
823 }
824 
SyncDhcpResult(const struct DhcpPacket * packet,struct DhcpResult * result)825 static int SyncDhcpResult(const struct DhcpPacket *packet, struct DhcpResult *result)
826 {
827     if ((packet == NULL) || (result == NULL)) {
828         LOGE("SyncDhcpResult() error, packet == NULL or result == NULL!");
829         return DHCP_OPT_FAILED;
830     }
831 
832     char *pVendor = GetDhcpOptionString(packet, VENDOR_SPECIFIC_INFO_OPTION);
833     if (pVendor == NULL) {
834         LOGW("SyncDhcpResult() recv DHCP_ACK 43, pVendor is NULL!");
835     } else {
836         LOGI("SyncDhcpResult() recv DHCP_ACK 43, pVendor is %{public}s.", pVendor);
837         if (strncpy_s(result->strOptVendor, DHCP_FILE_MAX_BYTES, pVendor, DHCP_FILE_MAX_BYTES - 1) != EOK) {
838             LOGE("SyncDhcpResult() error, strncpy_s pVendor failed!");
839             free(pVendor);
840             pVendor = NULL;
841             return DHCP_OPT_FAILED;
842         }
843         free(pVendor);
844         pVendor = NULL;
845     }
846 
847     /* Set the specified client process interface network info. */
848     if (SetLocalInterface(g_cltCnf->ifaceName, inet_addr(result->strYiaddr), inet_addr(result->strOptSubnet))
849         != DHCP_OPT_SUCCESS) {
850         LOGE("SyncDhcpResult() error, SetLocalInterface yiaddr:%{private}s failed!", result->strYiaddr);
851         return DHCP_OPT_FAILED;
852     }
853 
854     /* Write to the file. */
855     if (WriteDhcpResult(result) != DHCP_OPT_SUCCESS) {
856         LOGE("SyncDhcpResult() error, WriteDhcpResult result failed!");
857         return DHCP_OPT_FAILED;
858     }
859 
860     /* Publish dhcp success result event. */
861     if (PublishDhcpResultEvent(g_cltCnf->ifaceName, PUBLISH_CODE_SUCCESS, result) != DHCP_OPT_SUCCESS) {
862         LOGE("SyncDhcpResult() error, PublishDhcpResultEvent result failed!");
863         return DHCP_OPT_FAILED;
864     }
865 
866     LOGI("SyncDhcpResult() handle dhcp result success, ifaceName:%{public}s.", g_cltCnf->ifaceName);
867     return DHCP_OPT_SUCCESS;
868 }
869 
ParseDhcpAckPacket(const struct DhcpPacket * packet,time_t timestamp)870 static void ParseDhcpAckPacket(const struct DhcpPacket *packet, time_t timestamp)
871 {
872     if (packet == NULL) {
873         LOGE("ParseDhcpAckPacket() error, packet == NULL!");
874         return;
875     }
876 
877     struct DhcpResult dhcpResult;
878     if (memset_s(&dhcpResult, sizeof(struct DhcpResult), 0, sizeof(struct DhcpResult)) != EOK) {
879         LOGE("ParseDhcpAckPacket() error, memset_s failed!");
880         return;
881     }
882 
883     /* Set default leasetime. */
884     g_leaseTime = LEASETIME_DEFAULT * ONE_HOURS_SEC;
885     g_requestedIp4 = packet->yiaddr;
886     uint32_t u32Data = 0;
887     if (GetDhcpOptionUint32(packet, IP_ADDRESS_LEASE_TIME_OPTION, &u32Data)) {
888         g_leaseTime = u32Data;
889         LOGI("ParseDhcpAckPacket() recv DHCP_ACK 51, lease:%{public}u.", g_leaseTime);
890     }
891     g_renewalSec = g_leaseTime * RENEWAL_SEC_MULTIPLE;  /* First renewal seconds. */
892     g_rebindSec  = g_leaseTime * REBIND_SEC_MULTIPLE;   /* Second rebind seconds. */
893     g_renewalTimestamp = timestamp;   /* Record begin renewing or rebinding timestamp. */
894     dhcpResult.uOptLeasetime = g_leaseTime;
895     LOGI("Last get lease:%{public}u,renewal:%{public}u,rebind:%{public}u.", g_leaseTime, g_renewalSec, g_rebindSec);
896 
897     if (!GetDhcpOptionUint32(packet, SERVER_IDENTIFIER_OPTION, &u32Data)) {
898         LOGE("ParseDhcpAckPacket() GetDhcpOptionUint32 SERVER_IDENTIFIER_OPTION failed!");
899     } else {
900         g_serverIp4 = htonl(u32Data);
901         char *pSerIp = Ip4IntConToStr(g_serverIp4, false);
902         if (pSerIp != NULL) {
903             LOGI("ParseDhcpAckPacket() recv DHCP_ACK 54, serid: %{private}u->%{private}s.", u32Data, pSerIp);
904             if (strncpy_s(dhcpResult.strOptServerId, INET_ADDRSTRLEN, pSerIp, INET_ADDRSTRLEN - 1) != EOK) {
905                 free(pSerIp);
906                 pSerIp = NULL;
907                 return;
908             }
909             free(pSerIp);
910             pSerIp = NULL;
911         }
912     }
913 
914     /* Parse the specified client process interface network info. */
915     ParseNetworkInfo(packet, &dhcpResult);
916 
917     /* Sync the specified client process interface network info to the file. */
918     if (SyncDhcpResult(packet, &dhcpResult) != DHCP_OPT_SUCCESS) {
919         /* Publish dhcp failed result event. */
920         PublishDhcpResultEvent(g_cltCnf->ifaceName, PUBLISH_CODE_FAILED, NULL);
921         return;
922     }
923 
924     /* Receive dhcp ack packet finished, g_leaseTime * T1 later enter renewing state. */
925     g_dhcp4State = DHCP_STATE_BOUND;
926     SetSocketMode(SOCKET_MODE_INVALID);
927     g_timeoutTimestamp = timestamp + g_renewalSec;
928 }
929 
DhcpAckOrNakPacketHandle(uint8_t type,struct DhcpPacket * packet,time_t timestamp)930 static void DhcpAckOrNakPacketHandle(uint8_t type, struct DhcpPacket *packet, time_t timestamp)
931 {
932     if ((type != DHCP_ACK) && (type != DHCP_NAK)) {
933         LOGE("DhcpAckOrNakPacketHandle() type:%{public}d error!", type);
934         if (g_dhcp4State == DHCP_STATE_INITREBOOT) {
935             g_dhcp4State = DHCP_STATE_INIT;
936             g_timeoutTimestamp = timestamp;
937         }
938         return;
939     }
940 
941     if (packet == NULL) {
942         LOGE("DhcpAckOrNakPacketHandle() type:%{public}d error, packet == NULL!", type);
943         return;
944     }
945 
946     if (type == DHCP_NAK) {
947         /* If receive dhcp nak packet, init g_dhcp4State, resend dhcp discover packet. */
948         LOGI("DhcpAckOrNakPacketHandle() receive DHCP_NAK 53, init g_dhcp4State, resend dhcp discover packet!");
949         g_dhcp4State = DHCP_STATE_INIT;
950         SetSocketMode(SOCKET_MODE_RAW);
951         g_requestedIp4 = 0;
952         g_sentPacketNum = 0;
953         g_timeoutTimestamp = timestamp;
954 
955         /* Avoid excessive network traffic. */
956         LOGI("DhcpAckOrNakPacketHandle() receive DHCP_NAK 53, avoid excessive network traffic, need sleep!");
957         sleep(NUMBER_THREE);
958         return;
959     }
960 
961     LOGI("DhcpAckOrNakPacketHandle() recv DHCP_ACK 53.");
962 
963     /* Parse received dhcp ack packet. */
964     ParseDhcpAckPacket(packet, timestamp);
965 
966     /* ack packet success. */
967     if (g_dhcp4State == DHCP_STATE_BOUND) {
968         WriteLease(packet);
969     }
970 }
971 
DhcpResponseHandle(time_t timestamp)972 static void DhcpResponseHandle(time_t timestamp)
973 {
974     struct DhcpPacket packet;
975     int getLen;
976     uint8_t u8Message = 0;
977 
978     if (memset_s(&packet, sizeof(packet), 0, sizeof(packet)) != EOK) {
979         LOGE("DhcpResponseHandle() memset_s packet failed!");
980         return;
981     }
982     getLen = (g_socketMode == SOCKET_MODE_RAW) ? GetDhcpRawPacket(&packet, g_sockFd)
983                                                : GetDhcpKernelPacket(&packet, g_sockFd);
984     if (getLen < 0) {
985         if ((getLen == SOCKET_OPT_ERROR) && (errno != EINTR)) {
986             LOGE("DhcpResponseHandle() get packet read error, reopening socket!");
987             /* Reopen g_sockFd. */
988             SetSocketMode(g_socketMode);
989         }
990         LOGE("DhcpResponseHandle() get packet failed, error:%{public}d!", errno);
991         if (g_dhcp4State == DHCP_STATE_INITREBOOT) {
992             g_dhcp4State = DHCP_STATE_INIT;
993             g_timeoutTimestamp = timestamp;
994         }
995         return;
996     }
997     LOGI("DhcpResponseHandle() get packet success, getLen:%{public}d.", getLen);
998 
999     /* Check packet data. */
1000     if (packet.xid != g_transID) {
1001         LOGW("DhcpResponseHandle() get xid:%{public}u and g_transID:%{public}u not same!", packet.xid, g_transID);
1002         return;
1003     }
1004     if (!GetDhcpOptionUint8(&packet, DHCP_MESSAGE_TYPE_OPTION, &u8Message)) {
1005         LOGE("DhcpResponseHandle() GetDhcpOptionUint8 DHCP_MESSAGE_TYPE_OPTION failed!");
1006         return;
1007     }
1008 
1009     switch (g_dhcp4State) {
1010         case DHCP_STATE_SELECTING:
1011             DhcpOfferPacketHandle(u8Message, &packet, timestamp);
1012             break;
1013         case DHCP_STATE_REQUESTING:
1014         case DHCP_STATE_RENEWING:
1015         case DHCP_STATE_REBINDING:
1016         case DHCP_STATE_INITREBOOT:
1017         case DHCP_STATE_RENEWED:
1018             DhcpAckOrNakPacketHandle(u8Message, &packet, timestamp);
1019             break;
1020         case DHCP_STATE_BOUND:
1021         case DHCP_STATE_RELEASED:
1022             LOGW("DhcpResponseHandle() g_dhcp4State is BOUND or RELEASED, ignore all packets!");
1023             break;
1024         default:
1025             break;
1026     }
1027 }
1028 
1029 /* Receive signals. */
SignalReceiver(void)1030 static void SignalReceiver(void)
1031 {
1032     int signum;
1033     if (read(g_sigSockFds[0], &signum, sizeof(signum)) < 0) {
1034         LOGE("SignalReceiver() failed, g_sigSockFds[0]:%{public}d read error:%{public}d!", g_sigSockFds[0], errno);
1035         return;
1036     }
1037 
1038     switch (signum) {
1039         case SIGTERM:
1040             LOGW("SignalReceiver() SIGTERM!");
1041             SetSocketMode(SOCKET_MODE_INVALID);
1042             unlink(g_cltCnf->pidFile);
1043             unlink(g_cltCnf->resultFile);
1044             exit(EXIT_SUCCESS);
1045             break;
1046         case SIGUSR1:
1047             LOGW("SignalReceiver() SIGUSR1!");
1048             ExecDhcpRelease();
1049             break;
1050         case SIGUSR2:
1051             LOGW("SignalReceiver() SIGUSR2!");
1052             ExecDhcpRenew();
1053             break;
1054         default:
1055             break;
1056     }
1057 }
1058 
1059 
1060 /* Set dhcp ipv4 state. */
SetIpv4State(int state)1061 int SetIpv4State(int state)
1062 {
1063     if (state < 0) {
1064         LOGE("SetIpv4State() failed, state:%{public}d!", state);
1065         return DHCP_OPT_FAILED;
1066     }
1067 
1068     g_dhcp4State = state;
1069     return DHCP_OPT_SUCCESS;
1070 }
1071 
1072 /* Init signal handle function. */
InitSignalHandle(void)1073 int InitSignalHandle(void)
1074 {
1075     /* Create signal socket fd. */
1076     if (socketpair(AF_UNIX, SOCK_STREAM, 0, g_sigSockFds) != 0) {
1077         LOGE("InitSignalHandle() failed, socketpair error str:%{public}d!", errno);
1078         return DHCP_OPT_FAILED;
1079     }
1080 
1081     /* Register signal handlers. */
1082     if (signal(SIGTERM, SignalHandler) == SIG_ERR) {
1083         LOGE("InitSignalHandle() failed, signal SIGTERM error str:%{public}d!", errno);
1084         return DHCP_OPT_FAILED;
1085     }
1086 
1087     if (signal(SIGUSR1, SignalHandler) == SIG_ERR) {
1088         LOGE("InitSignalHandle() failed, signal SIGUSR1 error str:%{public}d!", errno);
1089         return DHCP_OPT_FAILED;
1090     }
1091 
1092     if (signal(SIGUSR2, SignalHandler) == SIG_ERR) {
1093         LOGE("InitSignalHandle() failed, signal SIGUSR2 error str:%{public}d!", errno);
1094         return DHCP_OPT_FAILED;
1095     }
1096 
1097     return DHCP_OPT_SUCCESS;
1098 }
1099 
1100 extern bool PublishDhcpIpv4ResultEvent(const int code, const char *data, const char *ifname);
PublishDhcpResultEvent(const char * ifname,const int code,struct DhcpResult * result)1101 int PublishDhcpResultEvent(const char *ifname, const int code, struct DhcpResult *result)
1102 {
1103     if (ifname == NULL) {
1104         LOGE("PublishDhcpResultEvent() failed, ifname == NULL!");
1105         return DHCP_OPT_FAILED;
1106     }
1107     if ((code != PUBLISH_CODE_SUCCESS) && (code != PUBLISH_CODE_FAILED)) {
1108         LOGE("PublishDhcpResultEvent() ifname:%{public}s failed, code:%{public}d error!", ifname, code);
1109         return DHCP_OPT_FAILED;
1110     }
1111     if ((code == PUBLISH_CODE_SUCCESS) && (result == NULL)) {
1112         LOGE("PublishDhcpResultEvent() ifname:%{public}s,code:%{public}d failed, result == NULL!", ifname, code);
1113         return DHCP_OPT_FAILED;
1114     }
1115 
1116     /* Data format - ipv4:ifname,time,cliIp,lease,servIp,subnet,dns1,dns2,router1,router2,vendor */
1117     int nBytes;
1118     uint32_t curTime = (uint32_t)time(NULL);
1119     char strData[STRING_MAX_LEN] = {0};
1120     if (code == PUBLISH_CODE_SUCCESS) {
1121         nBytes = snprintf_s(strData, STRING_MAX_LEN, STRING_MAX_LEN - 1, "ipv4:%s,%u,%s,%u,%s,%s,%s,%s,%s,%s,%s",
1122             ifname, curTime, result->strYiaddr, result->uOptLeasetime, result->strOptServerId, result->strOptSubnet,
1123             result->strOptDns1, result->strOptDns2, result->strOptRouter1, result->strOptRouter2, result->strOptVendor);
1124     } else {
1125         nBytes = snprintf_s(strData, STRING_MAX_LEN, STRING_MAX_LEN - 1, "ipv4:%s,%u,*,*,*,*,*,*,*,*,*",
1126             ifname, curTime);
1127     }
1128     if (nBytes < 0) {
1129         LOGE("PublishDhcpResultEvent() failed, snprintf_s %{public}s error:%{public}d!", ifname, errno);
1130         return DHCP_OPT_FAILED;
1131     }
1132 
1133     if (!PublishDhcpIpv4ResultEvent(code, strData, ifname)) {
1134         LOGE("PublishDhcpResultEvent() PublishDhcpIpv4ResultEvent %{public}d %{public}s failed!", code, strData);
1135         return DHCP_OPT_FAILED;
1136     }
1137     LOGI("PublishDhcpResultEvent() PublishDhcpIpv4ResultEvent %{public}d %{private}s success.", code, strData);
1138     return DHCP_OPT_SUCCESS;
1139 }
1140 
GetPacketHeaderInfo(struct DhcpPacket * packet,uint8_t type)1141 int GetPacketHeaderInfo(struct DhcpPacket *packet, uint8_t type)
1142 {
1143     if (packet == NULL) {
1144         LOGE("GetPacketHeaderInfo() failed, packet == NULL!");
1145         return DHCP_OPT_FAILED;
1146     }
1147 
1148     switch (type) {
1149         case DHCP_DISCOVER:
1150         case DHCP_REQUEST:
1151         case DHCP_DECLINE:
1152         case DHCP_RELEASE:
1153         case DHCP_INFORM:
1154             packet->op = BOOT_REQUEST;
1155             break;
1156         case DHCP_OFFER:
1157         case DHCP_ACK:
1158         case DHCP_NAK:
1159             packet->op = BOOT_REPLY;
1160             break;
1161         default:
1162             break;
1163     }
1164     packet->htype = ETHERNET_TYPE;
1165     packet->hlen = ETHERNET_LEN;
1166     packet->cookie = htonl(MAGIC_COOKIE);
1167     packet->options[0] = END_OPTION;
1168     AddOptValueToOpts(packet->options, DHCP_MESSAGE_TYPE_OPTION, type);
1169 
1170     return DHCP_OPT_SUCCESS;
1171 }
1172 
GetPacketCommonInfo(struct DhcpPacket * packet)1173 int GetPacketCommonInfo(struct DhcpPacket *packet)
1174 {
1175     if (packet == NULL) {
1176         LOGE("GetPacketCommonInfo() failed, packet == NULL!");
1177         return DHCP_OPT_FAILED;
1178     }
1179 
1180     /* Add packet client_cfg info. */
1181     if (memcpy_s(packet->chaddr, sizeof(packet->chaddr), g_cltCnf->ifaceMac, MAC_ADDR_LEN) != EOK) {
1182         LOGE("GetPacketCommonInfo() failed, memcpy_s error!");
1183         return DHCP_OPT_FAILED;
1184     }
1185     int nClientIdLen = DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES + g_cltCnf->pOptClientId[DHCP_OPT_LEN_INDEX];
1186     AddOptStrToOpts(packet->options, g_cltCnf->pOptClientId, nClientIdLen);
1187 
1188     /* Add packet vendor info, vendor format: pro-version. */
1189     char buf[VENDOR_MAX_LEN - DHCP_OPT_CODE_BYTES - DHCP_OPT_LEN_BYTES] = {0};
1190     unsigned char vendorId[VENDOR_MAX_LEN] = {0};
1191     unsigned char *pVendorId = vendorId;
1192     int nRes = snprintf_s(buf,
1193         VENDOR_MAX_LEN - DHCP_OPT_DATA_INDEX,
1194         VENDOR_MAX_LEN - DHCP_OPT_DATA_INDEX - 1,
1195         "%s-%s",
1196         DHCPC_NAME,
1197         DHCPC_VERSION);
1198     if (nRes < 0) {
1199         LOGE("GetPacketCommonInfo() failed, snprintf_s res:%{public}d error!", nRes);
1200         return DHCP_OPT_FAILED;
1201     }
1202     pVendorId[DHCP_OPT_CODE_INDEX] = VENDOR_SPECIFIC_INFO_OPTION;
1203     pVendorId[DHCP_OPT_LEN_INDEX] = strlen(buf);
1204     if (strncpy_s((char *)pVendorId + DHCP_OPT_DATA_INDEX, VENDOR_MAX_LEN - DHCP_OPT_DATA_INDEX, buf, strlen(buf)) !=
1205         EOK) {
1206         LOGE("GetPacketCommonInfo() failed, strncpy_s error!");
1207         return DHCP_OPT_FAILED;
1208     }
1209     if (strlen((char *)vendorId) > 0) {
1210         int nVendorIdLen = DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES + pVendorId[DHCP_OPT_LEN_INDEX];
1211         AddOptStrToOpts(packet->options, vendorId, nVendorIdLen);
1212     }
1213 
1214     return DHCP_OPT_SUCCESS;
1215 }
1216 
1217 /* Broadcast dhcp discover packet, discover dhcp servers that can provide ip address. */
DhcpDiscover(uint32_t transid,uint32_t requestip)1218 int DhcpDiscover(uint32_t transid, uint32_t requestip)
1219 {
1220     LOGI("DhcpDiscover() enter, transid:%{public}u,requestip:%{private}u.", transid, requestip);
1221 
1222     struct DhcpPacket packet;
1223     if (memset_s(&packet, sizeof(struct DhcpPacket), 0, sizeof(struct DhcpPacket)) != EOK) {
1224         return -1;
1225     }
1226 
1227     /* Get packet header and common info. */
1228     if ((GetPacketHeaderInfo(&packet, DHCP_DISCOVER) != DHCP_OPT_SUCCESS) ||
1229         (GetPacketCommonInfo(&packet) != DHCP_OPT_SUCCESS)) {
1230         return -1;
1231     }
1232 
1233     /* Get packet not common info. */
1234     packet.xid = transid;
1235     if (requestip > 0) {
1236         AddOptValueToOpts(packet.options, REQUESTED_IP_ADDRESS_OPTION, requestip);
1237     }
1238     AddParamaterRequestList(&packet);
1239 
1240     /* Begin broadcast dhcp discover packet. */
1241     LOGI("DhcpDiscover() discover, begin broadcast discover packet...");
1242     return SendToDhcpPacket(&packet, INADDR_ANY, INADDR_BROADCAST, g_cltCnf->ifaceIndex, (uint8_t *)MAC_BCAST_ADDR);
1243 }
1244 
1245 /* Broadcast dhcp request packet, tell dhcp servers that which ip address to choose. */
DhcpRequest(uint32_t transid,uint32_t reqip,uint32_t servip)1246 int DhcpRequest(uint32_t transid, uint32_t reqip, uint32_t servip)
1247 {
1248     LOGI("DhcpRequest() enter, transid:%{public}u,reqip:%{private}u.", transid, reqip);
1249 
1250     struct DhcpPacket packet;
1251     if (memset_s(&packet, sizeof(struct DhcpPacket), 0, sizeof(struct DhcpPacket)) != EOK) {
1252         return -1;
1253     }
1254 
1255     /* Get packet header and common info. */
1256     if ((GetPacketHeaderInfo(&packet, DHCP_REQUEST) != DHCP_OPT_SUCCESS) ||
1257         (GetPacketCommonInfo(&packet) != DHCP_OPT_SUCCESS)) {
1258         return -1;
1259     }
1260 
1261     /* Get packet not common info. */
1262     packet.xid = transid;
1263     AddOptValueToOpts(packet.options, REQUESTED_IP_ADDRESS_OPTION, reqip);
1264     AddOptValueToOpts(packet.options, SERVER_IDENTIFIER_OPTION, servip);
1265     AddParamaterRequestList(&packet);
1266 
1267     /* Begin broadcast dhcp request packet. */
1268     char *pReqIp = Ip4IntConToStr(reqip, false);
1269     if (pReqIp != NULL) {
1270         LOGI("DhcpRequest() broadcast req packet, reqip: host %{private}u->%{private}s.", ntohl(reqip), pReqIp);
1271         free(pReqIp);
1272         pReqIp = NULL;
1273     }
1274     char *pSerIp = Ip4IntConToStr(servip, false);
1275     if (pSerIp != NULL) {
1276         LOGI("DhcpRequest() broadcast req packet, servIp: host %{private}u->%{private}s.", ntohl(servip), pSerIp);
1277         free(pSerIp);
1278         pSerIp = NULL;
1279     }
1280     return SendToDhcpPacket(&packet, INADDR_ANY, INADDR_BROADCAST, g_cltCnf->ifaceIndex, (uint8_t *)MAC_BCAST_ADDR);
1281 }
1282 
1283 /* Unicast or broadcast dhcp request packet, request to extend the lease from the dhcp server. */
DhcpRenew(uint32_t transid,uint32_t clientip,uint32_t serverip)1284 int DhcpRenew(uint32_t transid, uint32_t clientip, uint32_t serverip)
1285 {
1286     LOGI("DhcpRenew() enter, transid:%{public}u,clientip:%{private}u.", transid, clientip);
1287 
1288     struct DhcpPacket packet;
1289     if (memset_s(&packet, sizeof(struct DhcpPacket), 0, sizeof(struct DhcpPacket)) != EOK) {
1290         return -1;
1291     }
1292 
1293     /* Get packet header and common info. */
1294     if ((GetPacketHeaderInfo(&packet, DHCP_REQUEST) != DHCP_OPT_SUCCESS) ||
1295         (GetPacketCommonInfo(&packet) != DHCP_OPT_SUCCESS)) {
1296         return -1;
1297     }
1298 
1299     /* Get packet not common info. */
1300     packet.xid = transid;
1301     packet.ciaddr = clientip;
1302     AddParamaterRequestList(&packet);
1303 
1304     /* Begin broadcast or unicast dhcp request packet. */
1305     if (serverip == 0) {
1306         LOGI("DhcpRenew() rebind, begin broadcast req packet");
1307         return SendToDhcpPacket(&packet, INADDR_ANY, INADDR_BROADCAST, g_cltCnf->ifaceIndex, (uint8_t *)MAC_BCAST_ADDR);
1308     }
1309     LOGI("DhcpRenew() renew, begin unicast request packet");
1310     return SendDhcpPacket(&packet, clientip, serverip);
1311 }
1312 
1313 /* Unicast dhcp release packet, releasing an ip address in Use from the dhcp server. */
DhcpRelease(uint32_t clientip,uint32_t serverip)1314 int DhcpRelease(uint32_t clientip, uint32_t serverip)
1315 {
1316     LOGI("DhcpRelease() enter, clientip:%{private}u.", clientip);
1317 
1318     struct DhcpPacket packet;
1319     if (memset_s(&packet, sizeof(struct DhcpPacket), 0, sizeof(struct DhcpPacket)) != EOK) {
1320         return -1;
1321     }
1322 
1323     /* Get packet header and common info. */
1324     if ((GetPacketHeaderInfo(&packet, DHCP_RELEASE) != DHCP_OPT_SUCCESS) ||
1325         (GetPacketCommonInfo(&packet) != DHCP_OPT_SUCCESS)) {
1326         return -1;
1327     }
1328 
1329     /* Get packet not common info. */
1330     packet.xid = GetTransId();
1331     AddOptValueToOpts(packet.options, REQUESTED_IP_ADDRESS_OPTION, clientip);
1332     AddOptValueToOpts(packet.options, SERVER_IDENTIFIER_OPTION, serverip);
1333 
1334     LOGI("DhcpRelease() release, begin unicast release packet, clientip:%{private}u, serverip:%{private}u", clientip,
1335         serverip);
1336     return SendDhcpPacket(&packet, clientip, serverip);
1337 }
1338 
DhcpInit(void)1339 static void DhcpInit(void)
1340 {
1341     g_cltCnf = GetDhcpClientCfg();
1342 
1343     /* Init dhcp ipv4 state. */
1344     g_dhcp4State = DHCP_STATE_INIT;
1345     SetSocketMode(SOCKET_MODE_RAW);
1346 
1347     InitSocketFd();
1348 
1349     time_t t = time(NULL);
1350     if (t == (time_t)-1) {
1351         return;
1352     }
1353     Reboot(t);
1354 }
1355 
StartIpv4(void)1356 int StartIpv4(void)
1357 {
1358     int nRet, nMaxFds;
1359     fd_set exceptfds;
1360     struct timeval timeout;
1361     time_t curTimestamp;
1362 
1363     DhcpInit();
1364 
1365     for (; ;) {
1366         if (g_cltCnf->timeoutExit) {
1367             LOGW("StartIpv4() send packet timed out, now break!");
1368             break;
1369         }
1370 
1371         FD_ZERO(&exceptfds);
1372         timeout.tv_sec = g_timeoutTimestamp - time(NULL);
1373         timeout.tv_usec = 0;
1374 
1375         InitSocketFd();
1376 
1377         if (g_sockFd >= 0) {
1378             FD_SET(g_sockFd, &exceptfds);
1379         }
1380         FD_SET(g_sigSockFds[0], &exceptfds);
1381 
1382         if (timeout.tv_sec <= 0) {
1383             LOGI("StartIpv4() already timed out, need send or resend packet...");
1384             nRet = 0;
1385         } else {
1386             LOGI("StartIpv4() waiting on select...");
1387             nMaxFds = (g_sigSockFds[0] > g_sockFd) ? g_sigSockFds[0] : g_sockFd;
1388             nRet = select(nMaxFds + 1, &exceptfds, NULL, NULL, &timeout);
1389         }
1390         if (nRet < 0) {
1391             if ((nRet == -1) && (errno == EINTR)) {
1392                 LOGW("StartIpv4() select err:%{public}d, a signal was caught!", errno);
1393             } else {
1394                 LOGE("StartIpv4() failed, select maxFds:%{public}d error:%{public}d!", nMaxFds, errno);
1395             }
1396             continue;
1397         }
1398 
1399         curTimestamp = time(NULL);
1400         if (nRet == 0) {
1401             DhcpRequestHandle(curTimestamp);
1402         } else if ((g_socketMode != SOCKET_MODE_INVALID) && FD_ISSET(g_sockFd, &exceptfds)) {
1403             DhcpResponseHandle(curTimestamp);
1404         } else if (FD_ISSET(g_sigSockFds[0], &exceptfds)) {
1405             SignalReceiver();
1406         } else {
1407             LOGW("StartIpv4() nRet:%{public}d, g_socketMode:%{public}d, continue select...", nRet, g_socketMode);
1408         }
1409     }
1410     return g_cltCnf->timeoutExit ? StopProcess(g_cltCnf->pidFile) : DHCP_OPT_SUCCESS;
1411 }
1412