1/*
2 * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "dhcp_s_server.h"
17#include <arpa/inet.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <net/if.h>
21#include <netinet/in.h>
22#include <securec.h>
23#include <stdint.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <sys/select.h>
28#include <sys/socket.h>
29#include <sys/time.h>
30#include <sys/types.h>
31#include <unistd.h>
32#include <pthread.h>
33#include "address_utils.h"
34#include "common_util.h"
35#include "dhcp_address_pool.h"
36#include "dhcp_binding.h"
37#include "dhcp_config.h"
38#include "dhcp_server_ipv4.h"
39#include "dhcp_logger.h"
40#include "dhcp_option.h"
41#include "dhcp_common_utils.h"
42
43DEFINE_DHCPLOG_DHCP_LABEL("DhcpServer");
44
45#ifndef DHCP_SEL_WAIT_TIMEOUTS
46#define DHCP_SEL_WAIT_TIMEOUTS 1000
47#endif
48#define OPT_MESSAGE_TYPE_LEGTH 1
49#define OPT_HEADER_LENGTH 2
50#define OPT_TIME_LENGTH 4
51#define OPT_TYPE_FIELD_LENGTH 1
52#define OPT_MAC_ADDR_LENGTH 6
53#define MAGIC_COOKIE_LENGTH 4
54#define OPT_BROADCAST_FLAG_ENABLE 0
55#define OFFER_MIN_INTERVAL_TIME 5
56
57#define PENDING_DEFAULT_TIMEOUT 1200
58#define PENDING_DEFAULT_INTERVAL 1
59#define PENDING_INTERVAL_CHECKING_ENABLE 1
60#define DHCP_MAGIC_COOKIE 0x63825363
61#define RECV_BUFFER_SIZE 2048
62#define ALLOW_NOBINDING_REQUEST 1
63#define REUSE_ADDRESS_ENABLE 1
64#define WAIT_STOPED_TIME 5
65#define DHCP_SERVER_SLEEP_TIMEOUTS 600000  // 600ms
66
67#define VNEDOR_OPEN_HARMONY "OPEN_HARMONY"
68
69const uint8_t MAGIC_COOKIE_DATA[MAGIC_COOKIE_LENGTH] = {0x63, 0x82, 0x53, 0x63};  // Vendor Information "Magic Cookie"
70
71enum AssignedNumbers {
72    ETHERNET = 1,               // Ethernet (10Mb)
73    EXPERIMENTAL_ETHERNET,      // Experimental Ethernet (3Mb)
74    AMATEUR_RADIO_AX_25,        // Amateur Radio AX.25
75    PROTEON_PRONET_TOKEN_RING,  // Proteon ProNET Token Ring
76    CHAOS,
77    IEEE802_NETWORKS,
78    ARCNET,
79    HYPERCHANNEL,
80    LANSTAR
81};
82
83struct ServerContext {
84    int broadCastFlagEnable;
85    DhcpAddressPool addressPool;
86    DhcpServerCallback callback;
87    DeviceConnectFun deviceConnectFun;
88    DhcpConfig config;
89    int serverFd;
90    int looperState;
91    int initialized;
92};
93
94enum LooperState {
95    LS_IDLE = 0,
96    LS_STARING,
97    LS_RUNNING,
98    LS_RELOADNG,
99    LS_STOPING,
100    LS_STOPED
101};
102typedef struct sockaddr_in sockaddr_in;
103int FillReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
104static int OnReceivedDiscover(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
105static int OnReceivedRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
106static int OnReceivedDecline(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
107static int OnReceivedRelease(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
108static int OnReceivedInform(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
109static int SendDhcpOffer(PDhcpServerContext ctx, PDhcpMsgInfo reply);
110static int SendDhcpAck(PDhcpServerContext ctx, PDhcpMsgInfo reply);
111static int SendDhcpNak(PDhcpServerContext ctx, PDhcpMsgInfo reply);
112static int ParseMessageOptions(PDhcpMsgInfo msg);
113
114static int ParseReplyOptions(PDhcpMsgInfo reply);
115struct sockaddr_in *BroadcastAddrIn(void);
116
117static struct ServerContext *GetServerInstance(const DhcpServerContext *ctx)
118{
119    if (!ctx || !ctx->instance) {
120        return nullptr;
121    }
122    return (struct ServerContext *)ctx->instance;
123}
124
125int HasFixSocket(int fd)
126{
127    int flags;
128    if ((flags = fcntl(fd, F_GETFL)) == -1 || fcntl(fd, F_SETFL, static_cast<unsigned int>(flags) | O_NONBLOCK) == -1) {
129        return DHCP_FALSE;
130    }
131    return DHCP_TRUE;
132}
133
134typedef struct ifreq ifreq;
135typedef struct sockaddr sockaddr;
136
137int BindNetInterface(int fd, const char *ifname)
138{
139    DHCP_LOGI("start %{public}s %{public}d   ifname = %{public}s ", __func__, __LINE__, ifname);
140    if (!fd || !ifname) {
141        return RET_FAILED;
142    }
143    ifreq iface;
144    if (memset_s(&iface, sizeof(iface), 0, sizeof(iface)) != EOK) {
145        return RET_FAILED;
146    }
147    ssize_t ifnameSize = strlen(ifname);
148    if (strncpy_s(iface.ifr_ifrn.ifrn_name, sizeof(iface.ifr_ifrn.ifrn_name), ifname, ifnameSize) != EOK) {
149        DHCP_LOGE("start %{public}s %{public}d   copy failed ", __func__, __LINE__);
150        return RET_FAILED;
151    };
152    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&iface, sizeof(iface)) == -1) {
153        DHCP_LOGE("failed to bind network device interface[%s].", ifname);
154        return RET_FAILED;
155    }
156    DHCP_LOGI("start %{public}s %{public}d   success ", __func__, __LINE__);
157    return RET_SUCCESS;
158}
159
160int InitServer(const char *ifname)
161{
162    DHCP_LOGI("start %{public}s %{public}d   ifname = %{public}s ", __func__, __LINE__, ifname);
163    sockaddr_in srvAddrIn = {0};
164    int optval = 1;
165    int optrval = 0;
166    srvAddrIn.sin_family = AF_INET;
167    srvAddrIn.sin_port = htons(DHCP_SERVER_PORT);
168    srvAddrIn.sin_addr.s_addr = INADDR_ANY;
169    int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
170    if (fd == -1) {
171        DHCP_LOGE("failed to create server socket!");
172        return -1;
173    }
174    if (!HasFixSocket(fd)) {
175        DHCP_LOGD("failed to fcntl O_NONBLOCK flag!");
176    }
177    if (BindNetInterface(fd, ifname) != RET_SUCCESS) {
178        close(fd);
179        return -1;
180    }
181    socklen_t optlen = sizeof(optrval);
182    if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&optrval, &optlen) == -1) {
183        DHCP_LOGI("failed to receive buffer size.");
184    } else {
185        DHCP_LOGI("receive buffer size is %d", optrval);
186    }
187    if (REUSE_ADDRESS_ENABLE && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) {
188        DHCP_LOGW("failed to setsockopt 'SO_REUSEADDR' for server socket!");
189    }
190    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) {
191        DHCP_LOGE("failed to setsockopt 'SO_BROADCAST' for server socket!");
192        close(fd);
193        return -1;
194    }
195    if (int ret = bind(fd, (sockaddr *)&srvAddrIn, sizeof(sockaddr)) == -1) {
196        DHCP_LOGE("failed to bind server  %{public}d!", ret);
197        close(fd);
198        return -1;
199    }
200    DHCP_LOGI("start %{public}s %{public}d   SUCCESSs ", __func__, __LINE__);
201    return fd;
202}
203
204struct sockaddr_in *BroadcastAddrIn(void)
205{
206    static struct sockaddr_in broadcastAddrIn = {0};
207    if (broadcastAddrIn.sin_port == 0) {
208        broadcastAddrIn.sin_port = htons(DHCP_CLIENT_PORT);
209        broadcastAddrIn.sin_family = AF_INET;
210        broadcastAddrIn.sin_addr.s_addr = INADDR_BROADCAST;
211    }
212    return &broadcastAddrIn;
213}
214
215struct sockaddr_in *SourceAddrIn(void)
216{
217    static struct sockaddr_in sourceAddrIn = {0};
218    sourceAddrIn.sin_port = htons(DHCP_CLIENT_PORT);
219    sourceAddrIn.sin_family = AF_INET;
220    sourceAddrIn.sin_addr.s_addr = INADDR_ANY;
221    return &sourceAddrIn;
222}
223
224struct sockaddr_in *ResetSourceAddr(void)
225{
226    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
227    struct sockaddr_in *srcAddr = SourceAddrIn();
228    srcAddr->sin_port = htons(DHCP_CLIENT_PORT);
229    srcAddr->sin_family = AF_INET;
230    srcAddr->sin_addr.s_addr = INADDR_ANY;
231    return srcAddr;
232}
233
234uint32_t SourceIpAddress(void)
235{
236    uint32_t srcIp = SourceAddrIn()->sin_addr.s_addr;
237    return srcIp;
238}
239struct sockaddr_in *DestinationAddrIn(void)
240{
241    static struct sockaddr_in destAddrIn = {0};
242    if (destAddrIn.sin_port == 0) {
243        destAddrIn.sin_port = htons(DHCP_CLIENT_PORT);
244        destAddrIn.sin_family = AF_INET;
245    }
246    return &destAddrIn;
247}
248
249struct sockaddr_in *DestinationAddr(uint32_t ipAddress)
250{
251    struct sockaddr_in *destAddr = DestinationAddrIn();
252    destAddr->sin_addr.s_addr = htonl(ipAddress);
253    return destAddr;
254}
255
256int ReceiveDhcpMessage(int sock, PDhcpMsgInfo msgInfo)
257{
258    static uint8_t recvBuffer[RECV_BUFFER_SIZE] = {0};
259    struct timeval tmt;
260    fd_set recvFd;
261    FD_ZERO(&recvFd);
262    FD_SET(sock, &recvFd);
263    tmt.tv_sec = 0;
264    tmt.tv_usec = DHCP_SERVER_SLEEP_TIMEOUTS; // 600ms
265    int ret = select(sock + 1, &recvFd, nullptr, nullptr, &tmt);
266    if (ret < 0) {
267        DHCP_LOGE("select error, %d", errno);
268        return ERR_SELECT;
269    }
270    if (ret == 0) {
271        return RET_SELECT_TIME_OUT;
272    }
273    if (!FD_ISSET(sock, &recvFd)) {
274        DHCP_LOGE("failed to select isset.");
275        return RET_ERROR;
276    }
277    socklen_t ssize = sizeof(sockaddr_in);
278    struct sockaddr_in *srcAddrIn = ResetSourceAddr();
279    srcAddrIn->sin_addr.s_addr = INADDR_ANY;
280    DHCP_LOGI("start recv from");
281    int rsize = recvfrom(sock, recvBuffer, RECV_BUFFER_SIZE, 0, (struct sockaddr *)srcAddrIn, (socklen_t *)&ssize);
282    if (!rsize) {
283        DHCP_LOGE("receive error, %d", errno);
284        return RET_FAILED;
285    }
286    if (rsize > (int)sizeof(DhcpMessage) || rsize < DHCP_MSG_HEADER_SIZE) {
287        DHCP_LOGW("message length error, received %d bytes.", rsize);
288        return RET_FAILED;
289    }
290    DHCP_LOGI("recv over");
291    msgInfo->length = rsize;
292    if (memcpy_s(&msgInfo->packet, sizeof(DhcpMessage), recvBuffer, rsize) != EOK) {
293        return RET_FAILED;
294    }
295    if (msgInfo->packet.op != BOOTREQUEST) {
296        DHCP_LOGW("dhcp message type error!");
297        return RET_FAILED;
298    }
299    if (msgInfo->packet.hlen > DHCP_HWADDR_LENGTH) {
300        DHCP_LOGW("hlen error!");
301        return RET_FAILED;
302    }
303    if (IsEmptyHWAddr(msgInfo->packet.chaddr)) {
304        DHCP_LOGW("client hardware address error!");
305        return RET_FAILED;
306    }
307    if (IsReserved(msgInfo->packet.chaddr)) {
308        DHCP_LOGD("ignore client, %s", ParseLogMac(msgInfo->packet.chaddr));
309        return RET_FAILED;
310    }
311    DHCP_LOGI("start %{public}s %{public}d  return success", __func__, __LINE__);
312    return RET_SUCCESS;
313}
314
315void InitReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
316{
317    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
318    if (!reply) {
319        DHCP_LOGE("reply message pointer is null!");
320        return;
321    }
322    reply->packet.op = BOOTREPLY;
323    reply->packet.htype = ETHERNET;
324    reply->packet.hlen = OPT_MAC_ADDR_LENGTH;
325    reply->packet.secs = 0;
326    reply->packet.ciaddr = 0;
327    if (memset_s(reply->packet.sname, sizeof(reply->packet.sname), '\0', sizeof(reply->packet.sname)) != EOK) {
328        DHCP_LOGE("failed to reset message packet[sname]!");
329        return;
330    };
331    if (memset_s(reply->packet.file, sizeof(reply->packet.file), '\0', sizeof(reply->packet.file)) != EOK) {
332        DHCP_LOGE("failed to reset message packet[file]!");
333        return;
334    }
335
336    if (FillReply(ctx, received, reply) != RET_SUCCESS) {
337        DHCP_LOGW("failed to fill reply message.");
338    }
339}
340
341void OnUpdateServerConfig(PDhcpServerContext ctx)
342{
343    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
344    ServerContext *srvIns = GetServerInstance(ctx);
345    if (!srvIns) {
346        DHCP_LOGE("dhcp server context pointer is null.");
347        return;
348    }
349    if (srvIns->callback) {
350        srvIns->callback(ST_RELOADNG, 0, ctx->ifname);
351    }
352}
353
354static void OnServerStoping(PDhcpServerContext ctx)
355{
356    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
357    ServerContext *srvIns = GetServerInstance(ctx);
358    if (!srvIns) {
359        DHCP_LOGE("dhcp server context pointer is null.");
360        return;
361    }
362    if (srvIns->callback) {
363        srvIns->callback(ST_STOPING, 0, ctx->ifname);
364    }
365}
366
367void OnServerStoped(PDhcpServerContext ctx, int code)
368{
369    DHCP_LOGI("OnServerStoped.");
370    ServerContext *srvIns = GetServerInstance(ctx);
371    if (!srvIns) {
372        DHCP_LOGE("dhcp server context pointer is null.");
373        return;
374    }
375    if (srvIns->callback) {
376        srvIns->callback(ST_STOPED, code, ctx->ifname);
377    }
378}
379
380int SendDhcpReply(PDhcpServerContext ctx, int replyType, PDhcpMsgInfo reply)
381{
382    if (!reply) {
383        DHCP_LOGE("reply message pointer is null.");
384        return RET_FAILED;
385    }
386    int sendRet = -1;
387    ServerContext *srvIns = GetServerInstance(ctx);
388    if (!srvIns) {
389        DHCP_LOGE("dhcp server context pointer is null.");
390        return RET_FAILED;
391    }
392    switch (replyType) {
393        case REPLY_OFFER:
394            DHCP_LOGD("<== send reply dhcp offer.");
395            sendRet = SendDhcpOffer(ctx, reply);
396            break;
397        case REPLY_ACK:
398            DHCP_LOGD("<== send reply dhcp ack.");
399            sendRet = SendDhcpAck(ctx, reply);
400            break;
401        case REPLY_NAK:
402            DHCP_LOGD("<== send reply dhcp nak.");
403            sendRet = SendDhcpNak(ctx, reply);
404            break;
405        default:
406            break;
407    }
408    if (replyType && sendRet != RET_SUCCESS) {
409        return RET_FAILED;
410    }
411    return  RET_SUCCESS;
412}
413
414static int MessageProcess(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
415{
416    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
417    int replyType = REPLY_NONE;
418    if (!received) {
419        return replyType;
420    }
421    PDhcpOption opt = GetOption(&received->options, DHCP_MESSAGE_TYPE_OPTION);
422    if (!opt) {
423        DHCP_LOGE("error dhcp message, missing required message type option.");
424        return replyType;
425    }
426    uint8_t messageType = opt->data[0];
427    switch (messageType) {
428        case DHCPDISCOVER: {
429            DHCP_LOGD("==> Received DHCPDISCOVER message.");
430            replyType = OnReceivedDiscover(ctx, received, reply);
431            break;
432        }
433        case DHCPREQUEST: {
434            DHCP_LOGD("==> Received DHCPREQUEST message.");
435            replyType = OnReceivedRequest(ctx, received, reply);
436            break;
437        }
438        case DHCPDECLINE: {
439            DHCP_LOGD("==> Received DHCPDECLINE message.");
440            replyType = OnReceivedDecline(ctx, received, reply);
441            break;
442        }
443        case DHCPRELEASE: {
444            DHCP_LOGD("==> Received DHCPRELEASE message.");
445            replyType = OnReceivedRelease(ctx, received, reply);
446            break;
447        }
448        case DHCPINFORM: {
449            DHCP_LOGD("==> Received DHCPINFORM message.");
450            replyType = OnReceivedInform(ctx, received, reply);
451            break;
452        }
453        default:
454            break;
455    }
456    return replyType;
457}
458
459int SaveLease(PDhcpServerContext ctx)
460{
461    ServerContext *srvIns = GetServerInstance(ctx);
462    if (!srvIns) {
463        DHCP_LOGE("dhcp server context pointer is null.");
464        return RET_FAILED;
465    }
466    int saveRet = SaveBindingRecoders(&srvIns->addressPool, 1);
467    if (saveRet == RET_FAILED) {
468        DHCP_LOGD("failed to save lease recoders. total: %zu", srvIns->addressPool.leaseTable.size());
469    } else if (saveRet == RET_SUCCESS) {
470        DHCP_LOGD("lease recoders saved.");
471    }
472    return saveRet;
473}
474
475static int OnLooperStateChanged(PDhcpServerContext ctx)
476{
477    ServerContext *srvIns = GetServerInstance(ctx);
478    if (!srvIns) {
479        DHCP_LOGE("dhcp server context pointer is null.");
480        return RET_FAILED;
481    }
482
483    if (srvIns->looperState == LS_RELOADNG) {
484        OnUpdateServerConfig(ctx);
485        srvIns->looperState = LS_RUNNING;
486    } else if (srvIns->looperState == LS_STOPING) {
487        OnServerStoping(ctx);
488        return RET_BREAK;
489    }
490    return RET_SUCCESS;
491}
492
493static int ContinueReceive(PDhcpMsgInfo from, int recvRet)
494{
495    if (!from) {
496        return DHCP_TRUE;
497    }
498    if (recvRet != RET_SUCCESS) {
499        return DHCP_TRUE;
500    }
501    DHCP_LOGD("received, length:%{public}d", from->length);
502    if (ParseMessageOptions(from) != 0) {
503        DHCP_LOGE("invalid dhcp message.");
504        return DHCP_TRUE;
505    }
506    if (!GetOption(&from->options, DHCP_MESSAGE_TYPE_OPTION)) {
507        DHCP_LOGW("can't found 'message type' option.");
508        return DHCP_TRUE;
509    }
510    return DHCP_FALSE;
511}
512
513static void *BeginLooper(void *argc) __attribute__((no_sanitize("cfi")))
514{
515    PDhcpServerContext ctx = (PDhcpServerContext)argc;
516    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
517    DhcpMsgInfo from;
518    DhcpMsgInfo reply;
519    ServerContext *srvIns = GetServerInstance(ctx);
520    if (!srvIns) {
521        DHCP_LOGE("dhcp server context pointer is null.");
522        return nullptr;
523    }
524    ctx->instance->serverFd = InitServer(ctx->ifname);
525    if (ctx->instance->serverFd < 0) {
526        DHCP_LOGE("failed to initialize server socket.");
527        return nullptr;
528    }
529    InitOptionList(&from.options);
530    InitOptionList(&reply.options);
531    srvIns->looperState = LS_RUNNING;
532    while (srvIns->looperState) {
533        if (OnLooperStateChanged(ctx) != RET_SUCCESS) {
534            DHCP_LOGI("OnLooperStateChanged break, looperState:%{public}d", srvIns->looperState);
535            break;
536        }
537        ClearOptions(&from.options);
538        ClearOptions(&reply.options);
539        int recvRet = ReceiveDhcpMessage(ctx->instance->serverFd, &from);
540        if (recvRet == RET_ERROR || recvRet == ERR_SELECT) {
541            DHCP_LOGI("ReceiveDhcpMessage");
542            continue;
543        }
544        if (ContinueReceive(&from, recvRet)) {
545            continue;
546        }
547        InitReply(ctx, &from, &reply);
548        int replyType = MessageProcess(ctx, &from, &reply);
549        if (replyType && SendDhcpReply(ctx, replyType, &reply) != RET_SUCCESS) {
550            DHCP_LOGE("failed to send reply message.");
551        }
552        NotifyConnetDeviceChanged(replyType, ctx);
553    }
554    FreeOptionList(&from.options);
555    FreeOptionList(&reply.options);
556    DHCP_LOGI("dhcp server message looper stopped.");
557    close(ctx->instance->serverFd);
558    ctx->instance->serverFd = -1;
559    srvIns->looperState = LS_STOPED;
560    return nullptr;
561}
562
563void NotifyConnetDeviceChanged(int replyType, PDhcpServerContext ctx)
564{
565    DHCP_LOGI("NotifyConnetDeviceChanged replyType:%{public}d", replyType);
566    if (replyType == REPLY_ACK || replyType == REPLY_OFFER) {
567        ServerContext *srvIns = GetServerInstance(ctx);
568        if (srvIns == nullptr) {
569            DHCP_LOGE("NotifyConnetDeviceChanged srvIns is nullptr");
570            return;
571        }
572        int saveRet = SaveBindingRecoders(&srvIns->addressPool, 1);
573        if (saveRet != RET_SUCCESS && saveRet != RET_WAIT_SAVE) {
574            DHCP_LOGW("SaveBindingRecoders failed to save lease recoders.");
575        }
576        if (replyType == REPLY_ACK && srvIns->deviceConnectFun != nullptr) {
577            DHCP_LOGI("NotifyConnetDeviceChanged deviceConnectFun");
578            srvIns->deviceConnectFun(ctx->ifname);
579        }
580    }
581}
582
583static int CheckAddressRange(DhcpAddressPool *pool)
584{
585    uint32_t serverNetwork = NetworkAddress(pool->serverId, pool->netmask);
586    uint32_t firstNetwork = NetworkAddress(pool->addressRange.beginAddress, pool->netmask);
587    uint32_t secondNetwork = NetworkAddress(pool->addressRange.endAddress, pool->netmask);
588    if (!serverNetwork || !firstNetwork || !secondNetwork) {
589        DHCP_LOGE("network config error.");
590        return DHCP_FALSE;
591    }
592    if (serverNetwork != firstNetwork || serverNetwork != secondNetwork) {
593        DHCP_LOGE("server network and address pool network belong to different networks.");
594        return DHCP_FALSE;
595    }
596    return DHCP_TRUE;
597}
598
599void InitBindingRecoders(DhcpAddressPool *pool)
600{
601    if (!pool) {
602        DHCP_LOGE("address pool pointer is null.");
603        return;
604    }
605    uint32_t realLeaseTotal = 0;
606    for (auto current: pool->leaseTable) {
607        int invalidBindig;
608        AddressBinding *binding = &current.second;
609        if (binding && !IsEmptyHWAddr(binding->chaddr) && binding->ipAddress) {
610            AddBinding(binding);
611            realLeaseTotal++;
612            invalidBindig = 0;
613        } else {
614            DHCP_LOGE("bad binding recoder.");
615            invalidBindig = 1;
616        }
617        if (!invalidBindig && binding && pool->distribution < binding->ipAddress) {
618            pool->distribution = binding->ipAddress;
619        }
620    }
621    DHCP_LOGD("lease recoder total: %u", realLeaseTotal);
622}
623
624void InitLeaseFile(DhcpAddressPool *pool)
625{
626    const char *leasePath  = GetFilePath(DHCPD_LEASE_FILE);
627    if (!leasePath || strlen(leasePath) == 0) {
628        DHCP_LOGE("failed to get lease file path.");
629        return;
630    }
631    if (access(leasePath, 0) != 0) {
632        DHCP_LOGD("lease file path does not exist.");
633        if (!CreatePath(leasePath)) {
634            DHCP_LOGE("failed to create lease file directory.");
635            return;
636        } else {
637            DHCP_LOGD("lease file directory created.");
638        }
639    }
640    if (LoadBindingRecoders(pool) != RET_SUCCESS) {
641        DHCP_LOGW("failed to load lease recoders.");
642    }
643    InitBindingRecoders(pool);
644}
645
646static void ExitProcess(void)
647{
648    DHCP_LOGD("dhcp server stopped.");
649}
650
651int StartDhcpServer(PDhcpServerContext ctx)
652{
653    DHCP_LOGI("%{public}s  %{public}d  start", __func__, __LINE__);
654    if (!ctx) {
655        DHCP_LOGE("server context pointer is null.");
656        return RET_FAILED;
657    }
658    if (strlen(ctx->ifname) == 0) {
659        DHCP_LOGE("context interface is null or empty.");
660        return RET_FAILED;
661    }
662    ServerContext *srvIns = GetServerInstance(ctx);
663    if (!srvIns) {
664        DHCP_LOGE("dhcp server context instance pointer is null.");
665        return RET_FAILED;
666    }
667    if (atexit(ExitProcess) != 0) {
668        DHCP_LOGW("failed to regiester exit process function.");
669    }
670    if (!srvIns->initialized) {
671        DHCP_LOGE("dhcp server no initialized.");
672        return RET_FAILED;
673    }
674    DHCP_LOGD("bind interface: %{public}s, begin dhcp message looper", ctx->ifname);
675    if (srvIns->callback) {
676        srvIns->callback(ST_STARTING, 1, ctx->ifname);
677    }
678    pthread_t threadId;
679    int ret = pthread_create(&threadId, nullptr, BeginLooper, ctx);
680    if (ret != RET_SUCCESS) {
681        DHCP_LOGI("failed to start dhcp server.");
682        OnServerStoped(ctx, ret);
683        return RET_FAILED;
684    }
685    OnServerStoped(ctx, ret);
686    return RET_SUCCESS;
687}
688
689int StopDhcpServer(PDhcpServerContext ctx)
690{
691    ServerContext *srvIns = GetServerInstance(ctx);
692    if (!srvIns) {
693        DHCP_LOGE("StopDhcpServer GetServerInstance failed!");
694        return RET_FAILED;
695    }
696    srvIns->looperState = LS_STOPING;
697    DHCP_LOGI("StopDhcpServer looperState LS_STOPING!");
698    return RET_SUCCESS;
699}
700
701int GetServerStatus(PDhcpServerContext ctx)
702{
703    ServerContext *srvIns = GetServerInstance(ctx);
704    if (!srvIns) {
705        DHCP_LOGE("dhcp server context pointer is null.");
706        return -1;
707    }
708    return srvIns->looperState;
709}
710
711int FillReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
712{
713    if (!received || !reply) {
714        return RET_ERROR;
715    }
716    ServerContext *srvIns = GetServerInstance(ctx);
717    if (!srvIns) {
718        DHCP_LOGE("dhcp server context pointer is null.");
719        return RET_FAILED;
720    }
721    if (received->packet.ciaddr && received->packet.ciaddr != INADDR_BROADCAST) {
722        reply->packet.ciaddr = received->packet.ciaddr;
723    }
724    if (received->packet.flags) {
725        reply->packet.flags = received->packet.flags;
726    }
727    if (received->packet.xid) {
728        reply->packet.xid = received->packet.xid;
729    }
730    if (received->packet.siaddr && received->packet.siaddr != INADDR_BROADCAST) {
731        reply->packet.siaddr = received->packet.siaddr;
732    } else {
733        reply->packet.siaddr = srvIns->addressPool.serverId;
734    }
735    if (received->packet.giaddr && received->packet.giaddr != INADDR_BROADCAST) {
736        reply->packet.giaddr = received->packet.giaddr;
737    } else {
738        if (srvIns->addressPool.gateway) {
739            reply->packet.giaddr = srvIns->addressPool.gateway;
740        }
741    }
742    if (received->packet.hlen) {
743        reply->packet.hlen = received->packet.hlen;
744        DHCP_LOGD("fill reply - chaddr:%s", ParseLogMac(received->packet.chaddr));
745        if (memset_s(reply->packet.chaddr, sizeof(reply->packet.chaddr), 0, sizeof(reply->packet.chaddr)) != EOK) {
746            DHCP_LOGE("failed to reset message packet[chaddr]!");
747            return RET_ERROR;
748        }
749        if (memcpy_s(reply->packet.chaddr, sizeof(reply->packet.chaddr),
750            received->packet.chaddr, sizeof(received->packet.chaddr)) != EOK) {
751            DHCP_LOGE("failed to copy message packet[chaddr]!");
752            return RET_ERROR;
753        }
754    }
755    if (received->packet.giaddr) {
756        reply->packet.giaddr = received->packet.giaddr;
757    }
758    return 0;
759}
760
761int AppendReplyTimeOptions(PDhcpServerContext ctx, PDhcpOptionList options)
762{
763    if (!ctx || !options) {
764        DHCP_LOGE("server context or options pointer is null.");
765        return RET_FAILED;
766    }
767    ServerContext *srvIns = GetServerInstance(ctx);
768    if (!srvIns) {
769        DHCP_LOGE("dhcp server context pointer is null.");
770        return RET_FAILED;
771    }
772    uint32_t leaseTime = HostToNetwork(DHCP_LEASE_TIME);
773    if (srvIns->addressPool.leaseTime) {
774        leaseTime = HostToNetwork(srvIns->addressPool.leaseTime);
775    }
776    DhcpOption optLeaseTime = {IP_ADDRESS_LEASE_TIME_OPTION, OPT_TIME_LENGTH, {0}};
777    FillU32Option(&optLeaseTime, leaseTime);
778    PushBackOption(options, &optLeaseTime);
779
780    uint32_t t1Time = HostToNetwork(DHCP_RENEWAL_TIME);
781    if (srvIns->addressPool.renewalTime) {
782        t1Time = HostToNetwork(srvIns->addressPool.renewalTime);
783    }
784    DhcpOption optRenewTime = {RENEWAL_TIME_VALUE_OPTION, OPT_TIME_LENGTH, {0}};
785    FillU32Option(&optRenewTime, t1Time);
786    PushBackOption(options, &optRenewTime);
787
788    uint32_t t2Time = HostToNetwork(DHCP_REBINDING_TIME);
789    if (srvIns->addressPool.rebindingTime) {
790        t2Time = HostToNetwork(srvIns->addressPool.rebindingTime);
791    }
792    DhcpOption optRebindTime = {REBINDING_TIME_VALUE_OPTION, OPT_TIME_LENGTH, {0}};
793    FillU32Option(&optRebindTime, t2Time);
794    PushBackOption(options, &optRebindTime);
795
796    return RET_SUCCESS;
797}
798
799static int Repending(DhcpAddressPool *pool, AddressBinding *binding)
800{
801    if (!pool) {
802        return REPLY_NONE;
803    }
804    uint32_t bindingIp = binding->ipAddress;
805    DHCP_LOGD(" binding found, bindIp:%s", ParseStrIp(bindingIp));
806    binding->pendingInterval = NextPendingInterval(binding->pendingInterval);
807    uint64_t tms = Tmspsec() - binding->pendingTime;
808    if (tms < binding->pendingInterval) {
809        binding->pendingTime = Tmspsec();
810        DHCP_LOGW("message interval is too short, ignore the message.");
811        return REPLY_NONE;
812    }
813    binding->pendingTime = Tmspsec();
814    binding->pendingInterval = 0;
815    binding->bindingStatus = BIND_PENDING;
816    uint32_t srcIp = SourceIpAddress();
817    if (srcIp && srcIp != INADDR_BROADCAST && bindingIp != INADDR_BROADCAST && srcIp != bindingIp) {
818        DHCP_LOGW("source ip address and bound ip address inconsistency.");
819        return REPLY_NAK;
820    }
821    if (srcIp && srcIp == bindingIp) {
822        if (pool->leaseTable.count(srcIp) == 0) {
823            DHCP_LOGD("can't find lease information.");
824            pool->leaseTable[srcIp] = *binding;
825        } else {
826            pool->leaseTable[srcIp] = *binding;
827        }
828    }
829    return REPLY_OFFER;
830}
831
832static int Rebinding(DhcpAddressPool *pool, AddressBinding *binding)
833{
834    uint64_t pendingTime = binding->pendingTime;
835    int replyType = Repending(pool, binding);
836    binding->bindingStatus = BIND_ASSOCIATED;
837    if (!binding->leaseTime) {
838        binding->leaseTime = pool->leaseTime;
839    }
840    binding->bindingTime = Tmspsec();
841    binding->expireIn = binding->bindingTime + binding->leaseTime;
842    binding->pendingTime = pendingTime;
843    if (replyType == REPLY_OFFER) {
844        replyType = REPLY_ACK;
845    }
846    return replyType;
847}
848
849static void AddAddressOption(PDhcpMsgInfo reply, uint8_t code, int32_t address)
850{
851    if (!reply) {
852        return;
853    }
854    DhcpOption optAddress = {0, 0, {0}};
855    optAddress.code = code;
856    if (AppendAddressOption(&optAddress, address) != RET_SUCCESS) {
857        DHCP_LOGE("failed to append address option.");
858        return;
859    };
860    PushBackOption(&reply->options, &optAddress);
861}
862
863int AddReplyServerIdOption(PDhcpOptionList options, uint32_t serverId)
864{
865    if (!options) {
866        DHCP_LOGE("option list pointer is null.");
867        return RET_FAILED;
868    }
869    if (!serverId || serverId == INADDR_BROADCAST) {
870        DHCP_LOGE("servier id error.");
871        return RET_FAILED;
872    }
873    DhcpOption optSrvId = {SERVER_IDENTIFIER_OPTION, 0, {0}};
874    if (AppendAddressOption(&optSrvId, serverId) != RET_SUCCESS) {
875        DHCP_LOGE("failed to append server id option.");
876        return RET_FAILED;
877    }
878    if (GetOption(options, SERVER_IDENTIFIER_OPTION)) {
879        DHCP_LOGD("server identifier option exists.");
880        return RET_SUCCESS;
881    }
882    PushBackOption(options, &optSrvId);
883    return RET_SUCCESS;
884}
885
886static void AddReplyMessageTypeOption(PDhcpMsgInfo reply, uint8_t replyMessageType)
887{
888    if (!reply) {
889        return;
890    }
891    DhcpOption optMsgType = {DHCP_MESSAGE_TYPE_OPTION, OPT_MESSAGE_TYPE_LEGTH, {replyMessageType, 0}};
892    PushBackOption(&reply->options, &optMsgType);
893}
894
895
896AddressBinding *GetBinding(DhcpAddressPool *pool, PDhcpMsgInfo received)
897{
898    if (!pool) {
899        return nullptr;
900    }
901    if (!received) {
902        return nullptr;
903    }
904    AddressBinding *binding = pool->binding(received->packet.chaddr, &received->options);
905    if (!binding) {
906        binding = pool->newBinding(received->packet.chaddr, &received->options);
907        if (binding == nullptr) {
908            DHCP_LOGE("new binding is null");
909            return nullptr;
910        }
911        if (pool->leaseTime) {
912            binding->leaseTime = pool->leaseTime;
913        }
914        binding->ipAddress = pool->distribue(pool, received->packet.chaddr);
915        DHCP_LOGI("new binding ip");
916    } else {
917        DHCP_LOGI("rebinding ip");
918    }
919    return binding;
920}
921
922int ReplyCommontOption(PDhcpServerContext ctx, PDhcpMsgInfo reply)
923{
924    if (!reply) {
925        DHCP_LOGE("reply is nullptr!");
926        return REPLY_NONE;
927    }
928    ServerContext *srvIns = GetServerInstance(ctx);
929    if (!srvIns) {
930        DHCP_LOGE("srvIns is nullptr!");
931        return REPLY_NONE;
932    }
933    AddAddressOption(reply, SUBNET_MASK_OPTION, srvIns->addressPool.netmask);
934    if (srvIns->addressPool.gateway) {
935        AddAddressOption(reply, ROUTER_OPTION, srvIns->addressPool.gateway);
936    }
937    DhcpOption optVendorInfo = {VENDOR_SPECIFIC_INFO_OPTION, static_cast<uint8_t>(strlen(VNEDOR_OPEN_HARMONY)),
938        VNEDOR_OPEN_HARMONY};
939    PushBackOption(&reply->options, &optVendorInfo);
940    uint32_t netAddress = reply->packet.yiaddr & srvIns->addressPool.netmask;
941    uint32_t boastAddress = (~srvIns->addressPool.netmask) | netAddress;
942    AddAddressOption(reply, BROADCAST_ADDRESS_OPTION, boastAddress);
943    return REPLY_OFFER;
944}
945
946static int DiscoverReplyLeaseMessage(PDhcpServerContext ctx, PDhcpMsgInfo reply, ServerContext *srvIns,
947    AddressBinding *binding)
948{
949    if (!ctx) {
950        DHCP_LOGE("ctx pointer is null.");
951        return REPLY_NONE;
952    }
953    if (!reply) {
954        DHCP_LOGE("reply message pointer is null.");
955        return REPLY_NONE;
956    }
957    if (!srvIns) {
958        DHCP_LOGE("get server instance is nullptr!");
959        return REPLY_NONE;
960    }
961    if (!binding) {
962        DHCP_LOGI("Discover binding is null, reply none");
963        return REPLY_NONE;
964    }
965    AddressBinding *lease = GetLease(&srvIns->addressPool, binding->ipAddress);
966    if (!lease) {
967        DHCP_LOGI("Discover add lease, binging ip:%{public}s mac:%{public}s",
968            OHOS::DHCP::IntIpv4ToAnonymizeStr(binding->ipAddress).c_str(), ParseLogMac(binding->chaddr));
969        AddLease(&srvIns->addressPool, binding);
970        lease = GetLease(&srvIns->addressPool, binding->ipAddress);
971    }
972    if (!lease) {
973        DHCP_LOGI("Discover lease is null, reply none");
974        return REPLY_NONE;
975    }
976    AddReplyMessageTypeOption(reply, DHCPOFFER);
977    reply->packet.yiaddr = lease->ipAddress;
978    ReplyCommontOption(ctx, reply);
979    DHCP_LOGI("Discover reply offer");
980    return REPLY_OFFER;
981}
982
983static int OnReceivedDiscover(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
984{
985    if (!received || !reply) {
986        DHCP_LOGE("receive or reply message pointer is null.");
987        return REPLY_NONE;
988    }
989    DHCP_LOGI("received 'Discover' message from:%{public}s", ParseLogMac(received->packet.chaddr));
990    ServerContext *srvIns = GetServerInstance(ctx);
991    if (!srvIns) {
992        DHCP_LOGE("get server instance is nullptr!");
993        return REPLY_NONE;
994    }
995    uint32_t reqIp = 0;
996    PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
997    if (optReqIp) {
998        reqIp = ParseIp(optReqIp->data);
999        if (reqIp) {
1000            DHCP_LOGI("Discover request ip:%{public}s", OHOS::DHCP::IntIpv4ToAnonymizeStr(reqIp).c_str());
1001        }
1002    }
1003    uint32_t srcIp = SourceIpAddress();
1004    if (!srvIns->broadCastFlagEnable) {
1005        if (srcIp) {
1006            DHCP_LOGI("Discover client repending:%{public}s", OHOS::DHCP::IntIpv4ToAnonymizeStr(srcIp).c_str());
1007        } else {
1008            srcIp = INADDR_BROADCAST;
1009        }
1010        DestinationAddr(srcIp);
1011    }
1012    AddressBinding *binding = GetBinding(&srvIns->addressPool, received);
1013    if (!binding) {
1014        DHCP_LOGI("Discover binding is null, reply none");
1015        return REPLY_NONE;
1016    }
1017    if (!binding->ipAddress) {
1018        DHCP_LOGI("Discover binding ipAddress is null, reply none");
1019        return REPLY_NONE;
1020    }
1021    if (reqIp != 0 && reqIp != binding->ipAddress) {
1022        DHCP_LOGW("Discover package reqIp:%{public}s, binging ip:%{public}s",
1023            OHOS::DHCP::IntIpv4ToAnonymizeStr(reqIp).c_str(),
1024            OHOS::DHCP::IntIpv4ToAnonymizeStr(binding->ipAddress).c_str());
1025    }
1026    DeleteMacInLease(&srvIns->addressPool, binding);
1027    return DiscoverReplyLeaseMessage(ctx, reply, srvIns, binding);
1028}
1029
1030static uint32_t GetRequestIpAddress(PDhcpMsgInfo received)
1031{
1032    uint32_t reqIp = 0;
1033    if (!received) {
1034        return reqIp;
1035    }
1036    PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
1037    if (optReqIp) {
1038        reqIp = ParseIp(optReqIp->data);
1039    }
1040    return reqIp;
1041}
1042
1043static int GetYourIpAddress(PDhcpMsgInfo received, uint32_t *yourIpAddr, DhcpAddressPool *pool)
1044{
1045    uint32_t cliIp = received->packet.ciaddr;
1046    uint32_t srcIp = SourceIpAddress();
1047    uint32_t reqIp = GetRequestIpAddress(received);
1048    DHCP_LOGI("cliIp:%{public}s srcIp:%{public}s reqIp:%{public}s",
1049        OHOS::DHCP::IntIpv4ToAnonymizeStr(cliIp).c_str(), OHOS::DHCP::IntIpv4ToAnonymizeStr(srcIp).c_str(),
1050        OHOS::DHCP::IntIpv4ToAnonymizeStr(reqIp).c_str());
1051    if (cliIp && srcIp && cliIp != srcIp) {
1052        DHCP_LOGE("error dhcp request message, missing required request option.");
1053        return RET_FAILED;
1054    }
1055    if (reqIp && srcIp && reqIp != srcIp) {
1056        DHCP_LOGE("error dhcp request message, request ip error.");
1057        return RET_FAILED;
1058    }
1059    if (cliIp && reqIp && cliIp != reqIp) {
1060        DHCP_LOGE("error dhcp request message, client ip error.");
1061        return RET_FAILED;
1062    }
1063
1064    if (srcIp && srcIp != INADDR_BROADCAST) {
1065        *yourIpAddr = srcIp;
1066    } else if (cliIp && cliIp != INADDR_BROADCAST) {
1067        *yourIpAddr = cliIp;
1068    } else if (reqIp && reqIp != INADDR_BROADCAST) {
1069        *yourIpAddr = reqIp;
1070    }
1071
1072    if ((ntohl(*yourIpAddr) < ntohl(pool->addressRange.beginAddress))
1073            || (ntohl(*yourIpAddr) > ntohl(pool->addressRange.endAddress))) {
1074        return RET_FAILED;
1075    }
1076
1077    if (srcIp && srcIp != INADDR_BROADCAST) {
1078        DestinationAddr(srcIp);
1079    } else if (srcIp == INADDR_ANY) {
1080        DestinationAddr(INADDR_BROADCAST);
1081    }
1082    return RET_SUCCESS;
1083}
1084
1085static int NotBindingRequest(DhcpAddressPool *pool, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1086{
1087    uint32_t yourIpAddr = 0;
1088    if (GetYourIpAddress(received, &yourIpAddr, pool) != RET_SUCCESS) {
1089        DHCP_LOGI("GetYourIpAddress REPLY_NONE");
1090        return REPLY_NONE;
1091    }
1092    AddressBinding *lease = GetLease(pool, yourIpAddr);
1093    if (!lease) {
1094        if (SourceIpAddress()) {
1095            DHCP_LOGI("SourceIpAddress True REPLY_ACK");
1096            return REPLY_ACK;
1097        }
1098        DHCP_LOGI("SourceIpAddress REPLY_NAK");
1099        return REPLY_NAK;
1100    }
1101    int sameAddr = AddrEquels(lease->chaddr, received->packet.chaddr, MAC_ADDR_LENGTH);
1102    if (lease->bindingStatus == BIND_ASSOCIATED && !sameAddr) {
1103        if (!IsExpire(lease)) {
1104            DHCP_LOGI("Not IsExpire REPLY_NAK");
1105            return REPLY_NAK;
1106        }
1107        DHCP_LOGI("RemoveLease lease");
1108        RemoveLease(pool, lease);
1109    }
1110    AddressBinding *binding = pool->newBinding(received->packet.chaddr, &received->options);
1111    if (binding == nullptr) {
1112        DHCP_LOGE("Not binding request binding is null.");
1113        return REPLY_NONE;
1114    }
1115    binding->ipAddress = yourIpAddr;
1116    if (pool->leaseTime) {
1117        binding->leaseTime = pool->leaseTime;
1118    }
1119    int replyType = Repending(pool, binding);
1120    if (replyType != REPLY_OFFER) {
1121        DHCP_LOGI("replyType != REPLY_OFFER");
1122        return replyType;
1123    }
1124    lease = GetLease(pool, yourIpAddr);
1125    if (!lease) {
1126        DHCP_LOGI("add new lease recoder.");
1127        AddLease(pool, binding);
1128        lease = GetLease(pool, binding->ipAddress);
1129    }
1130    if (!lease) {
1131        DHCP_LOGI("failed to get lease.");
1132        return REPLY_NONE;
1133    }
1134    lease->bindingStatus = BIND_ASSOCIATED;
1135    lease->bindingTime = Tmspsec();
1136    lease->expireIn = lease->bindingTime + binding->leaseTime;
1137    reply->packet.yiaddr = lease->ipAddress;
1138    DHCP_LOGI("NotBindingRequest REPLY_ACK");
1139    return REPLY_ACK;
1140}
1141
1142static int ValidateRequestMessage(const PDhcpServerContext ctx, const PDhcpMsgInfo received,
1143    PDhcpMsgInfo reply, uint32_t *yourIp)
1144{
1145    if (!received || !reply) {
1146        DHCP_LOGE("receive or reply message pointer is null.");
1147        return REPLY_NONE;
1148    }
1149    DHCP_LOGI("received 'Request' message from:%{public}s", ParseLogMac(received->packet.chaddr));
1150    uint32_t yourIpAddr = INADDR_BROADCAST;
1151    ServerContext *srvIns = GetServerInstance(ctx);
1152    if (!srvIns) {
1153        DHCP_LOGI("get server instance failed!");
1154        return RET_FAILED;
1155    }
1156    if (GetYourIpAddress(received, &yourIpAddr, &srvIns->addressPool) != RET_SUCCESS) {
1157        if (yourIpAddr && yourIpAddr != INADDR_BROADCAST) {
1158            AddressBinding *lease = GetLease(&srvIns->addressPool, yourIpAddr);
1159            if (lease) {
1160                RemoveLease(&srvIns->addressPool, lease);
1161                DHCP_LOGD("lease recoder has been removed.");
1162            } else {
1163                DHCP_LOGW("can't found lease recoder.");
1164            }
1165            RemoveBinding(received->packet.chaddr);
1166            return REPLY_NAK;
1167        }
1168        return REPLY_NONE;
1169    }
1170    PDhcpOption optReqSrvId = GetOption(&received->options, SERVER_IDENTIFIER_OPTION);
1171    if (optReqSrvId) {
1172        uint32_t reqSrvId = ParseIp(optReqSrvId->data);
1173        DHCP_LOGD(" reuquest server id is:%s", ParseStrIp(reqSrvId));
1174        if (reqSrvId != srvIns->addressPool.serverId) {
1175            DHCP_LOGW("other dhcp server process.");
1176            return REPLY_NONE;
1177        }
1178    } else {
1179        DHCP_LOGW("request message not specified server identifier option.");
1180    }
1181    *yourIp = yourIpAddr;
1182    return REPLY_ACK;
1183}
1184
1185static int HasNobindgRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1186{
1187    if (!received || !reply) {
1188        DHCP_LOGE("receive or reply message pointer is null.");
1189        return REPLY_NONE;
1190    }
1191    ServerContext *srvIns = GetServerInstance(ctx);
1192    if (!srvIns) {
1193        DHCP_LOGE("dhcp server context pointer is null.");
1194        return REPLY_NONE;
1195    }
1196    AddressBinding *binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1197    if (!binding && ALLOW_NOBINDING_REQUEST) {
1198        uint32_t srcIp = SourceIpAddress();
1199        uint32_t reqIp = GetRequestIpAddress(received);
1200        DHCP_LOGD("allow no binding request mode.");
1201        if (reqIp == 0 && srcIp == 0) {
1202            DHCP_LOGE("error dhcp message.");
1203            return REPLY_NONE;
1204        }
1205        if (!IpInNetwork(reqIp, srvIns->addressPool.serverId, srvIns->addressPool.netmask)) {
1206            DHCP_LOGE("error request ip.");
1207            return REPLY_NAK;
1208        }
1209        return NotBindingRequest(&srvIns->addressPool, received, reply);
1210    }
1211    return REPLY_NONE;
1212}
1213
1214int GetVendorIdentifierOption(PDhcpMsgInfo received)
1215{
1216    PDhcpOption optVendorIdentifier = GetOption(&received->options, VENDOR_CLASS_IDENTIFIER_OPTION);
1217    if (optVendorIdentifier) {
1218        char strVendorIdentifier[DEVICE_NAME_STRING_LENGTH] = {0};
1219        if (memcpy_s(strVendorIdentifier, DEVICE_NAME_STRING_LENGTH, (char*)optVendorIdentifier->data,
1220            optVendorIdentifier->length) != EOK) {
1221            DHCP_LOGE("GetVendorIdentifierOption strClientIdentifier memcpy_s failed!");
1222            return REPLY_NONE;
1223        }
1224        DHCP_LOGD("GetVendorIdentifierOption strClientIdentifier:%{public}s", strVendorIdentifier);
1225    } else {
1226        DHCP_LOGD("GetVendorIdentifierOption pClientIdentifier is null");
1227    }
1228    return REPLY_NAK;
1229}
1230
1231int GetHostNameOption(PDhcpMsgInfo received, AddressBinding *bindin)
1232{
1233    if (!bindin) {
1234        DHCP_LOGE("GetHostNameOption bindin is nullptr!");
1235        return REPLY_NONE;
1236    }
1237    PDhcpOption optHostName = GetOption(&received->options, HOST_NAME_OPTION);
1238    if (optHostName) {
1239        if (memcpy_s(bindin->deviceName, DEVICE_NAME_STRING_LENGTH, (char*)optHostName->data,
1240            optHostName->length) != EOK) {
1241            DHCP_LOGE("GetHostNameOption pHost memcpy_s failed!");
1242            return REPLY_NONE;
1243        }
1244        DHCP_LOGI("GetHostNameOption deviceName:%{public}s", bindin->deviceName);
1245    } else {
1246        DHCP_LOGD("GetHostNameOption pHost is null");
1247    }
1248    return REPLY_NAK;
1249}
1250
1251int GetUserClassOption(PDhcpMsgInfo received, AddressBinding *bindin)
1252{
1253    if (!bindin) {
1254        DHCP_LOGE("GetUserClassOption bindin is nullptr!");
1255        return REPLY_NONE;
1256    }
1257    PDhcpOption option = GetOption(&received->options, USER_CLASS_OPTION);
1258    if (option) {
1259        if (memcpy_s(bindin->userClass, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1260            DHCP_LOGE("GetUserClassOption memcpy_s failed!");
1261            return REPLY_NONE;
1262        }
1263        DHCP_LOGD("GetUserClassOption userClass:%{public}s", bindin->userClass);
1264    } else {
1265        DHCP_LOGD("GetUserClassOption pHost is null");
1266    }
1267    return REPLY_ACK;
1268}
1269
1270int GetRapidCommitOption(PDhcpMsgInfo received, AddressBinding *bindin)
1271{
1272    if (!bindin) {
1273        DHCP_LOGE("GetRapidCommitOption bindin is nullptr!");
1274        return REPLY_NONE;
1275    }
1276    PDhcpOption option = GetOption(&received->options, RAPID_COMMIT_OPTION);
1277    if (option) {
1278        char value[DEVICE_NAME_STRING_LENGTH] = {0};
1279        if (memcpy_s(value, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1280            DHCP_LOGE("GetRapidCommitOption memcpy_s failed!");
1281            return REPLY_NONE;
1282        }
1283        DHCP_LOGD("GetRapidCommitOption value:%{public}s", value);
1284    } else {
1285        DHCP_LOGD("GetRapidCommitOption pHost is null");
1286    }
1287    return REPLY_ACK;
1288}
1289
1290int GetOnlyIpv6Option(PDhcpMsgInfo received, AddressBinding *bindin)
1291{
1292    if (!bindin) {
1293        DHCP_LOGE("GetOnlyIpv6Option bindin is nullptr!");
1294        return REPLY_NONE;
1295    }
1296    PDhcpOption option = GetOption(&received->options, IPV6_ONLY_PREFERRED_OPTION);
1297    if (option) {
1298        char value[DEVICE_NAME_STRING_LENGTH] = {0};
1299        if (memcpy_s(value, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1300            DHCP_LOGE("GetOnlyIpv6Option memcpy_s failed!");
1301            return REPLY_NONE;
1302        }
1303        DHCP_LOGD("GetOnlyIpv6Option value:%{public}s", value);
1304    } else {
1305        DHCP_LOGD("GetOnlyIpv6Option pHost is null");
1306    }
1307    return REPLY_ACK;
1308}
1309
1310int GetPortalUrlOption(PDhcpMsgInfo received, AddressBinding *bindin)
1311{
1312    if (!bindin) {
1313        DHCP_LOGE("GetPortalUrlOption bindin is nullptr!");
1314        return REPLY_NONE;
1315    }
1316    PDhcpOption option = GetOption(&received->options, IPV6_ONLY_PREFERRED_OPTION);
1317    if (option) {
1318        char value[DEVICE_NAME_STRING_LENGTH] = {0};
1319        if (memcpy_s(value, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1320            DHCP_LOGE("GetPortalUrlOption memcpy_s failed!");
1321            return REPLY_NONE;
1322        }
1323        DHCP_LOGD("GetPortalUrlOption value:%{public}s", value);
1324    } else {
1325        DHCP_LOGD("GetPortalUrlOption pHost is null");
1326    }
1327    return REPLY_ACK;
1328}
1329
1330int ParseDhcpOption(PDhcpMsgInfo received, AddressBinding *bindin)
1331{
1332    if (!bindin) {
1333        DHCP_LOGE("ParseDhcpOption bindin is nullptr!");
1334        return REPLY_NONE;
1335    }
1336    DHCP_LOGE("enter ParseDhcpOption");
1337    GetHostNameOption(received, bindin);
1338    GetVendorIdentifierOption(received);
1339    GetUserClassOption(received, bindin);
1340    GetRapidCommitOption(received, bindin);
1341    GetOnlyIpv6Option(received, bindin);
1342    GetPortalUrlOption(received, bindin);
1343    return REPLY_ACK;
1344}
1345
1346static int OnReceivedRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1347{
1348    int ret;
1349    uint32_t yourIpAddr;
1350    if ((ret = ValidateRequestMessage(ctx, received, reply, &yourIpAddr)) != REPLY_ACK) {
1351        DHCP_LOGE("Request validateRequestMessage ret:%{public}d", ret);
1352        return ret;
1353    }
1354    ServerContext *srvIns = GetServerInstance(ctx);
1355    if (srvIns == nullptr) {
1356        DHCP_LOGE("OnReceivedRequest, srvIns is null");
1357        return REPLY_NONE;
1358    }
1359    AddressBinding *binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1360    if (binding == nullptr) {
1361        DHCP_LOGI("Request enter HasNobindgRequest!");
1362        return HasNobindgRequest(ctx, received, reply);
1363    }
1364    Rebinding(&srvIns->addressPool, binding);
1365    AddressBinding *lease = GetLease(&srvIns->addressPool, yourIpAddr);
1366    if (lease) {
1367        ParseDhcpOption(received, lease);
1368        DHCP_LOGI("request in lease, yourIpAddr:%{public}s, mac:%{public}s",
1369            OHOS::DHCP::IntIpv4ToAnonymizeStr(yourIpAddr).c_str(), ParseLogMac(lease->chaddr));
1370        int sameAddr = AddrEquels(lease->chaddr, received->packet.chaddr, MAC_ADDR_LENGTH);
1371        if (!sameAddr && !IsExpire(lease)) {
1372            DHCP_LOGW("invalid request ip address, reply nak, sameAddr:%{public}d", sameAddr);
1373            return REPLY_NAK;
1374        }
1375        if (!sameAddr && IsExpire(lease)) {
1376            if (memcpy_s(lease->chaddr, DHCP_HWADDR_LENGTH, binding->chaddr, MAC_ADDR_LENGTH) != EOK) {
1377                DHCP_LOGW("failed to update lease client address, sameAddr:%{public}d", sameAddr);
1378            }
1379        }
1380        lease->bindingStatus = BIND_ASSOCIATED;
1381        lease->bindingTime = binding->bindingTime;
1382        lease->expireIn = binding->expireIn;
1383        DHCP_LOGI("Request found lease recoder, sameAddr:%{public}d", sameAddr);
1384    } else {
1385        DHCP_LOGW("Request can not found lease recoder.");
1386    }
1387    uint32_t bindingIp = binding->ipAddress;
1388    if (bindingIp && yourIpAddr != INADDR_BROADCAST && yourIpAddr != bindingIp) {
1389        DHCP_LOGE("error request ip binding. reply nak");
1390        return REPLY_NAK;
1391    }
1392    reply->packet.yiaddr = bindingIp;
1393    ReplyCommontOption(ctx, reply);
1394    DHCP_LOGI("Request reply ack!");
1395    return REPLY_ACK;
1396}
1397
1398static int OnReceivedDecline(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1399{
1400    if (!received || !reply) {
1401        return REPLY_NONE;
1402    }
1403    ServerContext *srvIns = GetServerInstance(ctx);
1404    if (!srvIns) {
1405        return REPLY_NONE;
1406    }
1407    DHCP_LOGI("received 'Decline' message from: %s.", ParseLogMac(received->packet.chaddr));
1408    uint32_t reqIp = 0;
1409    PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
1410    if (optReqIp) {
1411        reqIp = ParseIp(optReqIp->data);
1412    }
1413    if (!reqIp) {
1414        DHCP_LOGD("invalid request ip address.");
1415        return REPLY_NONE;
1416    }
1417    AddressBinding* binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1418    if (!binding) {
1419        DHCP_LOGD("client not binding.");
1420        return REPLY_NONE;
1421    }
1422    if (binding->ipAddress != reqIp) {
1423        DHCP_LOGD("invalid request ip address.");
1424        return REPLY_NONE;
1425    }
1426    if (srvIns->addressPool.leaseTable.count(reqIp) > 0) {
1427        AddressBinding *lease = &srvIns->addressPool.leaseTable[reqIp];
1428        if (lease) {
1429            lease->bindingStatus = BIND_MODE_RESERVED;
1430            lease->expireIn = Tmspsec() + lease->leaseTime;
1431        } else {
1432            DHCP_LOGE("failed to get lease info.");
1433        }
1434    }
1435    RemoveBinding(received->packet.chaddr);
1436    return REPLY_NONE;
1437}
1438
1439static int OnReceivedRelease(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1440{
1441    if (!received || !reply) {
1442        return REPLY_NONE;
1443    }
1444    DHCP_LOGI("received 'Release' message from: %s", ParseLogMac(received->packet.chaddr));
1445    if (!ctx || !ctx->instance) {
1446        return RET_FAILED;
1447    }
1448    PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
1449    if (!optReqIp) {
1450        DHCP_LOGW("missing required request option.");
1451    }
1452    ServerContext *srvIns = GetServerInstance(ctx);
1453    if (!srvIns) {
1454        DHCP_LOGE("dhcp server context pointer is null.");
1455        return RET_FAILED;
1456    }
1457    AddressBinding *binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1458    if (!binding) {
1459        DHCP_LOGD("client not binding.");
1460        return REPLY_NONE;
1461    }
1462    uint32_t bindIp = binding->ipAddress;
1463    uint32_t reqIp = 0;
1464    if (optReqIp) {
1465        reqIp = ParseIp(optReqIp->data);
1466    }
1467    uint32_t srcIp = SourceIpAddress();
1468    if (srcIp != 0 && reqIp != 0 && reqIp != srcIp) {
1469        DHCP_LOGE("error release message, invalid request ip address.");
1470        return REPLY_NONE;
1471    }
1472    if (bindIp != 0 && reqIp != 0 && reqIp != bindIp) {
1473        DHCP_LOGE("error release message, invalid request ip address.");
1474        return REPLY_NONE;
1475    }
1476    AddressBinding *lease = GetLease(&srvIns->addressPool, bindIp);
1477    if (lease) {
1478        RemoveLease(&srvIns->addressPool, lease);
1479        DHCP_LOGD("lease recoder has been removed.");
1480    } else {
1481        DHCP_LOGW("can't found lease recoder.");
1482    }
1483
1484    if (ReleaseBinding(received->packet.chaddr) != RET_SUCCESS) {
1485        DHCP_LOGW("failed to release client[%s] bind.", ParseLogMac(received->packet.chaddr));
1486    }
1487    DHCP_LOGD("client released.");
1488    return REPLY_NONE;
1489}
1490
1491static int OnReceivedInform(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1492{
1493    if (!received || !reply) {
1494        return REPLY_NONE;
1495    }
1496    ServerContext *srvIns = GetServerInstance(ctx);
1497    if (!srvIns) {
1498        DHCP_LOGE("dhcp server context pointer is null.");
1499        return RET_FAILED;
1500    }
1501    DHCP_LOGI("received 'Inform' message from: %s", ParseLogMac(received->packet.chaddr));
1502    if (IsEmptyHWAddr(received->packet.chaddr)) {
1503        DHCP_LOGD("error dhcp 'Inform' message.");
1504    }
1505    return REPLY_ACK;
1506}
1507
1508static int AppendFixedOptions(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1509{
1510    ServerContext *srvIns = GetServerInstance(ctx);
1511    if (!srvIns) {
1512        return RET_FAILED;
1513    }
1514    if (!reply) {
1515        return RET_FAILED;
1516    }
1517    if (srvIns->addressPool.fixedOptions.size > 0) {
1518        DhcpOptionNode *pNode = srvIns->addressPool.fixedOptions.first->next;
1519        for (size_t i = 0; pNode != nullptr && i < srvIns->addressPool.fixedOptions.size; i++) {
1520            PDhcpOption opt = nullptr;
1521            if (pNode->option.code) {
1522                opt = GetOption(&reply->options, pNode->option.code);
1523            }
1524            if (opt == nullptr) {
1525                PushBackOption(&reply->options, &pNode->option);
1526            }
1527            pNode = pNode->next;
1528        }
1529    }
1530    return RET_SUCCESS;
1531}
1532int AppendReplyTypeOption(PDhcpMsgInfo reply, int replyType)
1533{
1534    if (!reply) {
1535        return RET_FAILED;
1536    }
1537    if (!replyType) {
1538        return RET_FAILED;
1539    }
1540    uint8_t msgType = 0;
1541    switch (replyType) {
1542        case REPLY_OFFER:
1543            msgType = DHCPOFFER;
1544            break;
1545        case REPLY_ACK:
1546            msgType = DHCPACK;
1547            break;
1548        case REPLY_NAK:
1549            msgType = DHCPNAK;
1550            break;
1551        default:
1552            break;
1553    }
1554    PDhcpOption pOptMsgType = GetOption(&reply->options, DHCP_MESSAGE_TYPE_OPTION);
1555    if (!pOptMsgType) {
1556        DHCP_LOGD("append message type option for reply message, type:%hhu", msgType);
1557        DhcpOption optMsgType = {DHCP_MESSAGE_TYPE_OPTION, OPT_MESSAGE_TYPE_LEGTH, {msgType, 0}};
1558        PushFrontOption(&reply->options, &optMsgType);
1559    } else {
1560        if (pOptMsgType->data[0] != msgType) {
1561            DHCP_LOGD("error dhcp nak message type.");
1562            return RET_FAILED;
1563        }
1564    }
1565    return RET_SUCCESS;
1566}
1567
1568static int SendDhcpOffer(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1569{
1570    ServerContext *srvIns = GetServerInstance(ctx);
1571    if (!srvIns) {
1572        DHCP_LOGE("failed to get server instance");
1573        return RET_FAILED;
1574    }
1575    if (AppendReplyTypeOption(reply, REPLY_OFFER) != RET_SUCCESS) {
1576        DHCP_LOGE("failed to append reply type options");
1577        return RET_FAILED;
1578    }
1579    if (AppendReplyTimeOptions(ctx, &reply->options) != RET_SUCCESS ||
1580        AddReplyServerIdOption(&reply->options, srvIns->addressPool.serverId) != RET_SUCCESS) {
1581        DHCP_LOGE("failed to append reply time options");
1582        return RET_FAILED;
1583    }
1584    if (AppendFixedOptions(ctx, reply) != RET_SUCCESS) {
1585        DHCP_LOGW("failed to append fixed reply options.");
1586    }
1587    if (ParseReplyOptions(reply) != RET_SUCCESS) {
1588        DHCP_LOGE("failed to parse reply options.");
1589        return RET_FAILED;
1590    }
1591    int ret;
1592    struct sockaddr_in *bcastAddrIn = BroadcastAddrIn();
1593    struct sockaddr_in *destAddrIn = DestinationAddrIn();
1594    if (srvIns->broadCastFlagEnable == 1 && destAddrIn) {
1595        int broadCastFlag = 1;
1596        if (reply->packet.flags && (reply->packet.flags >> (DHCP_MESSAGE_FLAG_LENGTH - 1)) == 0) {
1597            broadCastFlag = 0;
1598        }
1599        if (!broadCastFlag && destAddrIn->sin_addr.s_addr) {
1600            ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)destAddrIn,
1601                sizeof(*destAddrIn));
1602        } else {
1603            ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)bcastAddrIn,
1604                sizeof(*bcastAddrIn));
1605        }
1606    } else {
1607        ret = sendto(
1608            srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)bcastAddrIn, sizeof(*bcastAddrIn));
1609    }
1610    if (!ret) {
1611        DHCP_LOGD("failed to send dhcp offer message.");
1612        return RET_FAILED;
1613    }
1614    DHCP_LOGI("send reply offer, length:%d", reply->length);
1615    return RET_SUCCESS;
1616}
1617
1618static int SendDhcpAck(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1619{
1620    if (AppendReplyTypeOption(reply, REPLY_ACK) != RET_SUCCESS) {
1621        DHCP_LOGE("failed to append reply type options");
1622        return RET_FAILED;
1623    }
1624    if (AppendFixedOptions(ctx, reply) != RET_SUCCESS) {
1625        DHCP_LOGW("failed to append fixed reply options.");
1626    }
1627    if (!ctx || !ctx->instance) {
1628        DHCP_LOGE("dhcp server context pointer is null.");
1629        return RET_FAILED;
1630    }
1631    ServerContext *srvIns = GetServerInstance(ctx);
1632
1633    if (AppendReplyTimeOptions(ctx, &reply->options) != RET_SUCCESS) {
1634        DHCP_LOGE("failed to append reply time options");
1635        return RET_FAILED;
1636    }
1637    if (AddReplyServerIdOption(&reply->options, srvIns->addressPool.serverId) != RET_SUCCESS) {
1638        DHCP_LOGE("failed to add reply server options");
1639        return RET_FAILED;
1640    }
1641    if (ParseReplyOptions(reply) != RET_SUCCESS) {
1642        DHCP_LOGE("failed to parse reply options");
1643        return RET_FAILED;
1644    }
1645    sockaddr_in *destAddrIn = DestinationAddrIn();
1646    int ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)destAddrIn,
1647        sizeof(*destAddrIn));
1648    if (!ret) {
1649        DHCP_LOGD("failed to send dhcp ack message.");
1650        return RET_FAILED;
1651    }
1652    DHCP_LOGI("send reply ack, size:%d", reply->length);
1653    return RET_SUCCESS;
1654}
1655
1656static int SendDhcpNak(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1657{
1658    if (AppendReplyTypeOption(reply, REPLY_NAK) != RET_SUCCESS) {
1659        DHCP_LOGE("failed to append reply type options");
1660        return RET_FAILED;
1661    }
1662    ServerContext *srvIns = GetServerInstance(ctx);
1663    if (srvIns == nullptr) {
1664        DHCP_LOGE("SendDhcpNak, srvIns is null");
1665        return RET_FAILED;
1666    }
1667    if (AddReplyServerIdOption(&reply->options, srvIns->addressPool.serverId) != RET_SUCCESS) {
1668        DHCP_LOGE("SendDhcpNak serverId fail!");
1669        return RET_FAILED;
1670    }
1671    DhcpOption optVendorInfo = {MESSAGE_OPTION, static_cast<uint8_t>(strlen("wrong network")), "wrong network"};
1672    PushBackOption(&reply->options, &optVendorInfo);
1673    if (ParseReplyOptions(reply) != RET_SUCCESS) {
1674        DHCP_LOGE("failed to parse reply options");
1675        return RET_FAILED;
1676    }
1677
1678    struct sockaddr_in *destAddrIn = BroadcastAddrIn();
1679    int ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)destAddrIn,
1680        sizeof(*destAddrIn));
1681    if (!ret) {
1682        DHCP_LOGD("failed to send dhcp ack message.");
1683        return RET_FAILED;
1684    }
1685    DHCP_LOGI("send reply nak, size:%d", reply->length);
1686    return RET_SUCCESS;
1687}
1688
1689static int ParseMessageOptions(PDhcpMsgInfo msg)
1690{
1691    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
1692    if (msg->length < (DHCP_MSG_HEADER_SIZE + MAGIC_COOKIE_LENGTH)) {
1693        return RET_FAILED;
1694    }
1695    DhcpOption *current, *end;
1696    current = (DhcpOption *)msg->packet.options;
1697    end = (DhcpOption *)(((uint8_t *)msg->packet.options) + (msg->length - DHCP_MSG_HEADER_SIZE));
1698
1699    if (memcmp(current, MAGIC_COOKIE_DATA, sizeof(MAGIC_COOKIE_DATA)) != 0) {
1700        DHCP_LOGD("bad magic cookie.");
1701        return RET_FAILED;
1702    }
1703
1704    current = (DhcpOption *)(((uint8_t *)current) + MAGIC_COOKIE_LENGTH);
1705    uint8_t *pos = (((uint8_t *)current) + MAGIC_COOKIE_LENGTH);
1706    uint8_t *maxPos = (((uint8_t *)current) + (DHCP_OPTION_SIZE - MAGIC_COOKIE_LENGTH - OPT_HEADER_LENGTH -1));
1707    int optTotal = 0;
1708    while (current < end && current->code != END_OPTION) {
1709        if (((uint8_t *)end) - ((uint8_t *)current) < OPT_HEADER_LENGTH) {
1710            DHCP_LOGE("current->code out of option range.");
1711            return RET_FAILED;
1712        }
1713        pos += (OPT_HEADER_LENGTH + current->length);
1714        if (pos >= maxPos) {
1715            DHCP_LOGD("out of option max pos.");
1716            return RET_FAILED;
1717        }
1718        if (PushBackOption(&msg->options, current) != RET_SUCCESS) {
1719            DHCP_LOGD("failed to PushOption.");
1720        }
1721        current = (DhcpOption *)(((uint8_t *)current) + OPT_HEADER_LENGTH + current->length);
1722        optTotal++;
1723    }
1724    if (current < end && current->code == END_OPTION) {
1725        DHCP_LOGD("option list size:%zu xid:%u", msg->options.size, msg->packet.xid);
1726        return RET_SUCCESS;
1727    }
1728
1729    DHCP_LOGD("option list parse failed.");
1730    return RET_FAILED;
1731}
1732
1733static int ResetMessageOptions(PDhcpMsgInfo reply)
1734{
1735    if (!reply || reply->options.size == 0) {
1736        DHCP_LOGE("message pointer is null.");
1737        return RET_ERROR;
1738    }
1739    if (memset_s(reply->packet.options, DHCP_OPTIONS_SIZE, 0, DHCP_OPTIONS_SIZE) != EOK) {
1740        DHCP_LOGE("failed to reset message options!");
1741        return RET_ERROR;
1742    }
1743    return RET_SUCCESS;
1744}
1745
1746static int ValidateReplyOptions(PDhcpMsgInfo reply)
1747{
1748    if (!reply) {
1749        DHCP_LOGE("reply message pointer is null.");
1750        return RET_FAILED;
1751    }
1752    int ret = RET_FAILED;
1753    if ((ret = ResetMessageOptions(reply)) != RET_SUCCESS) {
1754        return ret;
1755    }
1756    reply->length = DHCP_MSG_HEADER_SIZE;
1757    PDhcpOptionNode pNode = reply->options.first;
1758    if (!pNode) {
1759        return RET_ERROR;
1760    }
1761    PDhcpOption pOptMsgType = GetOption(&reply->options, DHCP_MESSAGE_TYPE_OPTION);
1762    if (!pOptMsgType) {
1763        DHCP_LOGE("unknown reply message type.");
1764        return ret;
1765    }
1766    return RET_SUCCESS;
1767}
1768
1769static int ParseReplyOptions(PDhcpMsgInfo reply)
1770{
1771    int ret = RET_FAILED;
1772    if ((ret = ValidateReplyOptions(reply)) != RET_SUCCESS) {
1773        return ret;
1774    }
1775    PDhcpOptionNode pNode = reply->options.first->next;
1776    DhcpOption endOpt = {END_OPTION, 0, {0}};
1777    PushBackOption(&reply->options, &endOpt);
1778    int replyOptsLength = 0;
1779    uint8_t *current = reply->packet.options, olen = MAGIC_COOKIE_LENGTH;
1780    size_t remainingSize = sizeof(reply->packet.options);
1781    uint32_t cookie = htonl(DHCP_MAGIC_COOKIE);
1782    if (memcpy_s(current, remainingSize, &cookie, olen) != EOK) {
1783        DHCP_LOGE("memcpy cookie out of options buffer!");
1784        return RET_FAILED;
1785    }
1786    replyOptsLength += olen;
1787    remainingSize -= olen;
1788    current += olen;
1789    ret = RET_SUCCESS;
1790    while (pNode && (uint32_t)pNode->option.length < DHCP_OPTION_SIZE) {
1791        if ((uint32_t)pNode->option.code == END_OPTION) {
1792            olen = OPT_HEADER_LENGTH + 1;
1793        } else {
1794            olen = OPT_HEADER_LENGTH + pNode->option.length;
1795        }
1796        if (memcpy_s(current, remainingSize, &pNode->option, olen) != EOK) {
1797            DHCP_LOGE("memcpy current option out of options buffer!");
1798            ret = RET_FAILED;
1799            break;
1800        }
1801        remainingSize -= olen;
1802        current += olen;
1803        replyOptsLength += olen;
1804        if ((uint32_t)pNode->option.code == END_OPTION) {
1805            break;
1806        }
1807        pNode = pNode->next;
1808        if (replyOptsLength >= DHCP_OPTIONS_SIZE) {
1809            DHCP_LOGE("current option out of options buffer!");
1810            ret = RET_FAILED;
1811            break;
1812        }
1813    }
1814    reply->length += replyOptsLength;
1815    return ret;
1816}
1817
1818void RegisterDhcpCallback(PDhcpServerContext ctx, DhcpServerCallback callback)
1819{
1820    DHCP_LOGI("start %{public}s   %{public}d.", __func__, __LINE__);
1821    ServerContext *srvIns = GetServerInstance(ctx);
1822    if (!srvIns) {
1823        DHCP_LOGE("dhcp server context pointer is null.");
1824        return;
1825    }
1826    srvIns->callback = callback;
1827}
1828
1829void RegisterDeviceChangedCallback(PDhcpServerContext ctx, DeviceConnectFun func)
1830{
1831    DHCP_LOGI("start %{public}s %{public}d.", __func__, __LINE__);
1832    ServerContext *srvIns = GetServerInstance(ctx);
1833    if (!srvIns) {
1834        DHCP_LOGE("dhcp server context pointer is null.");
1835        return;
1836    }
1837    srvIns->deviceConnectFun = func;
1838}
1839
1840static int InitServerContext(DhcpConfig *config, DhcpServerContext *ctx)
1841{
1842    if (!config) {
1843        DHCP_LOGE("server configure pointer is null.");
1844        return RET_FAILED;
1845    }
1846    ServerContext *srvIns = GetServerInstance(ctx);
1847    if (!srvIns) {
1848        DHCP_LOGE("dhcp server context pointer is null.");
1849        return RET_FAILED;
1850    }
1851    if (InitAddressPool(&srvIns->addressPool, config->ifname, nullptr) != RET_SUCCESS) {
1852        DHCP_LOGD("failed to init address pool.");
1853        return RET_FAILED;
1854    }
1855    if (memcpy_s(ctx->ifname, sizeof(ctx->ifname), config->ifname, strlen(config->ifname)) != EOK) {
1856        DHCP_LOGD("failed to set interface name.");
1857        return RET_FAILED;
1858    }
1859    srvIns->serverFd = 0;
1860    srvIns->callback = 0;
1861    srvIns->looperState = LS_IDLE;
1862    srvIns->broadCastFlagEnable = static_cast<int>(config->broadcast);
1863    srvIns->addressPool.serverId = config->serverId;
1864    srvIns->addressPool.netmask = config->netmask;
1865    srvIns->addressPool.gateway = config->gateway;
1866    if (config->pool.beginAddress && config->pool.endAddress) {
1867        srvIns->addressPool.addressRange.beginAddress = config->pool.beginAddress;
1868        srvIns->addressPool.addressRange.endAddress = config->pool.endAddress;
1869    } else {
1870        srvIns->addressPool.addressRange.beginAddress = FirstIpAddress(config->serverId, config->netmask);
1871        srvIns->addressPool.addressRange.endAddress = LastIpAddress(config->serverId, config->netmask);
1872    }
1873    if (memcpy_s(srvIns->addressPool.ifname, sizeof(srvIns->addressPool.ifname),
1874        config->ifname, strlen(config->ifname)) != EOK) {
1875        DHCP_LOGD("failed to set interface name.");
1876        return RET_FAILED;
1877    }
1878    if (!CheckAddressRange(&srvIns->addressPool)) {
1879        DHCP_LOGE("failed to validate address range.");
1880        return RET_FAILED;
1881    }
1882    InitLeaseFile(&srvIns->addressPool);
1883    srvIns->addressPool.leaseTime = config->leaseTime;
1884    srvIns->addressPool.renewalTime = config->renewalTime;
1885    srvIns->addressPool.rebindingTime = config->rebindingTime;
1886    return RET_SUCCESS;
1887}
1888
1889int InitServerFixedOptions(DhcpConfig *config, DhcpServerContext *ctx)
1890{
1891    if (!config) {
1892        DHCP_LOGE("server configure pointer is null.");
1893        return RET_FAILED;
1894    }
1895    ServerContext *srvIns = GetServerInstance(ctx);
1896    if (!srvIns) {
1897        DHCP_LOGE("dhcp server context pointer is null.");
1898        return RET_FAILED;
1899    }
1900
1901    if (!HasInitialized(&config->options)) {
1902        DHCP_LOGE("dhcp configure has not been initialized.");
1903        return RET_FAILED;
1904    }
1905    if (InitOptionList(&srvIns->addressPool.fixedOptions) != RET_SUCCESS) {
1906        return RET_FAILED;
1907    }
1908    if (config->options.first != nullptr && config->options.size > 0) {
1909        DhcpOptionNode *pNode = config->options.first->next;
1910        for (size_t i = 0; pNode != nullptr && i < config->options.size; i++) {
1911            PushBackOption(&srvIns->addressPool.fixedOptions, &pNode->option);
1912            DHCP_LOGD("append fixed option ==> %hhu,%d", pNode->option.code,
1913                pNode->option.length);
1914            pNode = pNode->next;
1915        }
1916    }
1917    return RET_SUCCESS;
1918}
1919
1920PDhcpServerContext InitializeServer(DhcpConfig *config)
1921{
1922    DHCP_LOGI("start %{public}s   %{public}d.", __func__, __LINE__);
1923    DhcpServerContext *context = nullptr;
1924    if (!config) {
1925        DHCP_LOGE("dhcp server config pointer is null.");
1926        return nullptr;
1927    }
1928    if (strlen(config->ifname) == 0) {
1929        DHCP_LOGE("can't found interface name config.");
1930        return nullptr;
1931    }
1932    if (!config->serverId || !config->netmask) {
1933        DHCP_LOGE("missing required parameter or config item: \"serverId\", \"netmask\"");
1934        return nullptr;
1935    }
1936    if ((context = (DhcpServerContext *)calloc(1, sizeof(DhcpServerContext))) == nullptr) {
1937        DHCP_LOGE("failed to calloc server context.");
1938        return nullptr;
1939    }
1940    if ((context->instance = (ServerContext *)calloc(1, sizeof(ServerContext))) == nullptr) {
1941        DHCP_LOGE("failed to calloc server instance.");
1942        FreeServerContext(&context);
1943        return nullptr;
1944    }
1945    if (InitServerContext(config, context) != RET_SUCCESS) {
1946        DHCP_LOGE("failed initialize dhcp server context.");
1947        FreeServerContext(&context);
1948        return nullptr;
1949    }
1950    if (InitServerFixedOptions(config, context) != RET_SUCCESS) {
1951        DHCP_LOGE("failed initialize dhcp server fixed options.");
1952        FreeServerContext(&context);
1953        return nullptr;
1954    }
1955    DHCP_LOGI("server id: %{private}s", ParseStrIp(config->serverId));
1956    DHCP_LOGI("netmask: %{private}s", ParseStrIp(config->netmask));
1957    if (config->gateway) {
1958        DHCP_LOGI("gateway: %{private}s", ParseStrIp(config->gateway));
1959    }
1960    DHCP_LOGI("address range begin of: %{private}s", ParseStrIp(config->pool.beginAddress));
1961    DHCP_LOGI("address range end of: %{private}s", ParseStrIp(config->pool.endAddress));
1962    context->instance->initialized = 1;
1963    return context;
1964}
1965
1966int FreeServerContext(PDhcpServerContext *ctx)
1967{
1968    if (ctx == nullptr || *ctx == nullptr) {
1969        DHCP_LOGE("dhcp server context pointer is null.");
1970        return RET_FAILED;
1971    }
1972    ServerContext *srvIns = GetServerInstance(*ctx);
1973    if (!srvIns) {
1974        DHCP_LOGE("dhcp server instance pointer is null.");
1975        return RET_FAILED;
1976    }
1977    int times = 5;
1978    while (srvIns->looperState != LS_STOPED && srvIns->looperState != LS_IDLE) {
1979        DHCP_LOGE("FreeServerContext wait 300ms.");
1980        usleep(300000);
1981        times--;
1982        if (times <= 0) {
1983            return RET_FAILED;
1984        }
1985    }
1986    FreeAddressPool(&srvIns->addressPool);
1987    if ((*ctx)->instance != nullptr) {
1988        free((*ctx)->instance);
1989        (*ctx)->instance = nullptr;
1990    }
1991    free(*ctx);
1992    *ctx = nullptr;
1993    return RET_SUCCESS;
1994}
1995