1518678f8Sopenharmony_ci/*
2518678f8Sopenharmony_ci * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3518678f8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4518678f8Sopenharmony_ci * you may not use this file except in compliance with the License.
5518678f8Sopenharmony_ci * You may obtain a copy of the License at
6518678f8Sopenharmony_ci *
7518678f8Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8518678f8Sopenharmony_ci *
9518678f8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10518678f8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11518678f8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12518678f8Sopenharmony_ci * See the License for the specific language governing permissions and
13518678f8Sopenharmony_ci * limitations under the License.
14518678f8Sopenharmony_ci */
15518678f8Sopenharmony_ci
16518678f8Sopenharmony_ci#include "dhcp_s_server.h"
17518678f8Sopenharmony_ci#include <arpa/inet.h>
18518678f8Sopenharmony_ci#include <errno.h>
19518678f8Sopenharmony_ci#include <fcntl.h>
20518678f8Sopenharmony_ci#include <net/if.h>
21518678f8Sopenharmony_ci#include <netinet/in.h>
22518678f8Sopenharmony_ci#include <securec.h>
23518678f8Sopenharmony_ci#include <stdint.h>
24518678f8Sopenharmony_ci#include <stdio.h>
25518678f8Sopenharmony_ci#include <stdlib.h>
26518678f8Sopenharmony_ci#include <string.h>
27518678f8Sopenharmony_ci#include <sys/select.h>
28518678f8Sopenharmony_ci#include <sys/socket.h>
29518678f8Sopenharmony_ci#include <sys/time.h>
30518678f8Sopenharmony_ci#include <sys/types.h>
31518678f8Sopenharmony_ci#include <unistd.h>
32518678f8Sopenharmony_ci#include <pthread.h>
33518678f8Sopenharmony_ci#include "address_utils.h"
34518678f8Sopenharmony_ci#include "common_util.h"
35518678f8Sopenharmony_ci#include "dhcp_address_pool.h"
36518678f8Sopenharmony_ci#include "dhcp_binding.h"
37518678f8Sopenharmony_ci#include "dhcp_config.h"
38518678f8Sopenharmony_ci#include "dhcp_server_ipv4.h"
39518678f8Sopenharmony_ci#include "dhcp_logger.h"
40518678f8Sopenharmony_ci#include "dhcp_option.h"
41518678f8Sopenharmony_ci#include "dhcp_common_utils.h"
42518678f8Sopenharmony_ci
43518678f8Sopenharmony_ciDEFINE_DHCPLOG_DHCP_LABEL("DhcpServer");
44518678f8Sopenharmony_ci
45518678f8Sopenharmony_ci#ifndef DHCP_SEL_WAIT_TIMEOUTS
46518678f8Sopenharmony_ci#define DHCP_SEL_WAIT_TIMEOUTS 1000
47518678f8Sopenharmony_ci#endif
48518678f8Sopenharmony_ci#define OPT_MESSAGE_TYPE_LEGTH 1
49518678f8Sopenharmony_ci#define OPT_HEADER_LENGTH 2
50518678f8Sopenharmony_ci#define OPT_TIME_LENGTH 4
51518678f8Sopenharmony_ci#define OPT_TYPE_FIELD_LENGTH 1
52518678f8Sopenharmony_ci#define OPT_MAC_ADDR_LENGTH 6
53518678f8Sopenharmony_ci#define MAGIC_COOKIE_LENGTH 4
54518678f8Sopenharmony_ci#define OPT_BROADCAST_FLAG_ENABLE 0
55518678f8Sopenharmony_ci#define OFFER_MIN_INTERVAL_TIME 5
56518678f8Sopenharmony_ci
57518678f8Sopenharmony_ci#define PENDING_DEFAULT_TIMEOUT 1200
58518678f8Sopenharmony_ci#define PENDING_DEFAULT_INTERVAL 1
59518678f8Sopenharmony_ci#define PENDING_INTERVAL_CHECKING_ENABLE 1
60518678f8Sopenharmony_ci#define DHCP_MAGIC_COOKIE 0x63825363
61518678f8Sopenharmony_ci#define RECV_BUFFER_SIZE 2048
62518678f8Sopenharmony_ci#define ALLOW_NOBINDING_REQUEST 1
63518678f8Sopenharmony_ci#define REUSE_ADDRESS_ENABLE 1
64518678f8Sopenharmony_ci#define WAIT_STOPED_TIME 5
65518678f8Sopenharmony_ci#define DHCP_SERVER_SLEEP_TIMEOUTS 600000  // 600ms
66518678f8Sopenharmony_ci
67518678f8Sopenharmony_ci#define VNEDOR_OPEN_HARMONY "OPEN_HARMONY"
68518678f8Sopenharmony_ci
69518678f8Sopenharmony_ciconst uint8_t MAGIC_COOKIE_DATA[MAGIC_COOKIE_LENGTH] = {0x63, 0x82, 0x53, 0x63};  // Vendor Information "Magic Cookie"
70518678f8Sopenharmony_ci
71518678f8Sopenharmony_cienum AssignedNumbers {
72518678f8Sopenharmony_ci    ETHERNET = 1,               // Ethernet (10Mb)
73518678f8Sopenharmony_ci    EXPERIMENTAL_ETHERNET,      // Experimental Ethernet (3Mb)
74518678f8Sopenharmony_ci    AMATEUR_RADIO_AX_25,        // Amateur Radio AX.25
75518678f8Sopenharmony_ci    PROTEON_PRONET_TOKEN_RING,  // Proteon ProNET Token Ring
76518678f8Sopenharmony_ci    CHAOS,
77518678f8Sopenharmony_ci    IEEE802_NETWORKS,
78518678f8Sopenharmony_ci    ARCNET,
79518678f8Sopenharmony_ci    HYPERCHANNEL,
80518678f8Sopenharmony_ci    LANSTAR
81518678f8Sopenharmony_ci};
82518678f8Sopenharmony_ci
83518678f8Sopenharmony_cistruct ServerContext {
84518678f8Sopenharmony_ci    int broadCastFlagEnable;
85518678f8Sopenharmony_ci    DhcpAddressPool addressPool;
86518678f8Sopenharmony_ci    DhcpServerCallback callback;
87518678f8Sopenharmony_ci    DeviceConnectFun deviceConnectFun;
88518678f8Sopenharmony_ci    DhcpConfig config;
89518678f8Sopenharmony_ci    int serverFd;
90518678f8Sopenharmony_ci    int looperState;
91518678f8Sopenharmony_ci    int initialized;
92518678f8Sopenharmony_ci};
93518678f8Sopenharmony_ci
94518678f8Sopenharmony_cienum LooperState {
95518678f8Sopenharmony_ci    LS_IDLE = 0,
96518678f8Sopenharmony_ci    LS_STARING,
97518678f8Sopenharmony_ci    LS_RUNNING,
98518678f8Sopenharmony_ci    LS_RELOADNG,
99518678f8Sopenharmony_ci    LS_STOPING,
100518678f8Sopenharmony_ci    LS_STOPED
101518678f8Sopenharmony_ci};
102518678f8Sopenharmony_citypedef struct sockaddr_in sockaddr_in;
103518678f8Sopenharmony_ciint FillReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
104518678f8Sopenharmony_cistatic int OnReceivedDiscover(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
105518678f8Sopenharmony_cistatic int OnReceivedRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
106518678f8Sopenharmony_cistatic int OnReceivedDecline(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
107518678f8Sopenharmony_cistatic int OnReceivedRelease(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
108518678f8Sopenharmony_cistatic int OnReceivedInform(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply);
109518678f8Sopenharmony_cistatic int SendDhcpOffer(PDhcpServerContext ctx, PDhcpMsgInfo reply);
110518678f8Sopenharmony_cistatic int SendDhcpAck(PDhcpServerContext ctx, PDhcpMsgInfo reply);
111518678f8Sopenharmony_cistatic int SendDhcpNak(PDhcpServerContext ctx, PDhcpMsgInfo reply);
112518678f8Sopenharmony_cistatic int ParseMessageOptions(PDhcpMsgInfo msg);
113518678f8Sopenharmony_ci
114518678f8Sopenharmony_cistatic int ParseReplyOptions(PDhcpMsgInfo reply);
115518678f8Sopenharmony_cistruct sockaddr_in *BroadcastAddrIn(void);
116518678f8Sopenharmony_ci
117518678f8Sopenharmony_cistatic struct ServerContext *GetServerInstance(const DhcpServerContext *ctx)
118518678f8Sopenharmony_ci{
119518678f8Sopenharmony_ci    if (!ctx || !ctx->instance) {
120518678f8Sopenharmony_ci        return nullptr;
121518678f8Sopenharmony_ci    }
122518678f8Sopenharmony_ci    return (struct ServerContext *)ctx->instance;
123518678f8Sopenharmony_ci}
124518678f8Sopenharmony_ci
125518678f8Sopenharmony_ciint HasFixSocket(int fd)
126518678f8Sopenharmony_ci{
127518678f8Sopenharmony_ci    int flags;
128518678f8Sopenharmony_ci    if ((flags = fcntl(fd, F_GETFL)) == -1 || fcntl(fd, F_SETFL, static_cast<unsigned int>(flags) | O_NONBLOCK) == -1) {
129518678f8Sopenharmony_ci        return DHCP_FALSE;
130518678f8Sopenharmony_ci    }
131518678f8Sopenharmony_ci    return DHCP_TRUE;
132518678f8Sopenharmony_ci}
133518678f8Sopenharmony_ci
134518678f8Sopenharmony_citypedef struct ifreq ifreq;
135518678f8Sopenharmony_citypedef struct sockaddr sockaddr;
136518678f8Sopenharmony_ci
137518678f8Sopenharmony_ciint BindNetInterface(int fd, const char *ifname)
138518678f8Sopenharmony_ci{
139518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d   ifname = %{public}s ", __func__, __LINE__, ifname);
140518678f8Sopenharmony_ci    if (!fd || !ifname) {
141518678f8Sopenharmony_ci        return RET_FAILED;
142518678f8Sopenharmony_ci    }
143518678f8Sopenharmony_ci    ifreq iface;
144518678f8Sopenharmony_ci    if (memset_s(&iface, sizeof(iface), 0, sizeof(iface)) != EOK) {
145518678f8Sopenharmony_ci        return RET_FAILED;
146518678f8Sopenharmony_ci    }
147518678f8Sopenharmony_ci    ssize_t ifnameSize = strlen(ifname);
148518678f8Sopenharmony_ci    if (strncpy_s(iface.ifr_ifrn.ifrn_name, sizeof(iface.ifr_ifrn.ifrn_name), ifname, ifnameSize) != EOK) {
149518678f8Sopenharmony_ci        DHCP_LOGE("start %{public}s %{public}d   copy failed ", __func__, __LINE__);
150518678f8Sopenharmony_ci        return RET_FAILED;
151518678f8Sopenharmony_ci    };
152518678f8Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&iface, sizeof(iface)) == -1) {
153518678f8Sopenharmony_ci        DHCP_LOGE("failed to bind network device interface[%s].", ifname);
154518678f8Sopenharmony_ci        return RET_FAILED;
155518678f8Sopenharmony_ci    }
156518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d   success ", __func__, __LINE__);
157518678f8Sopenharmony_ci    return RET_SUCCESS;
158518678f8Sopenharmony_ci}
159518678f8Sopenharmony_ci
160518678f8Sopenharmony_ciint InitServer(const char *ifname)
161518678f8Sopenharmony_ci{
162518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d   ifname = %{public}s ", __func__, __LINE__, ifname);
163518678f8Sopenharmony_ci    sockaddr_in srvAddrIn = {0};
164518678f8Sopenharmony_ci    int optval = 1;
165518678f8Sopenharmony_ci    int optrval = 0;
166518678f8Sopenharmony_ci    srvAddrIn.sin_family = AF_INET;
167518678f8Sopenharmony_ci    srvAddrIn.sin_port = htons(DHCP_SERVER_PORT);
168518678f8Sopenharmony_ci    srvAddrIn.sin_addr.s_addr = INADDR_ANY;
169518678f8Sopenharmony_ci    int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
170518678f8Sopenharmony_ci    if (fd == -1) {
171518678f8Sopenharmony_ci        DHCP_LOGE("failed to create server socket!");
172518678f8Sopenharmony_ci        return -1;
173518678f8Sopenharmony_ci    }
174518678f8Sopenharmony_ci    if (!HasFixSocket(fd)) {
175518678f8Sopenharmony_ci        DHCP_LOGD("failed to fcntl O_NONBLOCK flag!");
176518678f8Sopenharmony_ci    }
177518678f8Sopenharmony_ci    if (BindNetInterface(fd, ifname) != RET_SUCCESS) {
178518678f8Sopenharmony_ci        close(fd);
179518678f8Sopenharmony_ci        return -1;
180518678f8Sopenharmony_ci    }
181518678f8Sopenharmony_ci    socklen_t optlen = sizeof(optrval);
182518678f8Sopenharmony_ci    if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&optrval, &optlen) == -1) {
183518678f8Sopenharmony_ci        DHCP_LOGI("failed to receive buffer size.");
184518678f8Sopenharmony_ci    } else {
185518678f8Sopenharmony_ci        DHCP_LOGI("receive buffer size is %d", optrval);
186518678f8Sopenharmony_ci    }
187518678f8Sopenharmony_ci    if (REUSE_ADDRESS_ENABLE && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval)) == -1) {
188518678f8Sopenharmony_ci        DHCP_LOGW("failed to setsockopt 'SO_REUSEADDR' for server socket!");
189518678f8Sopenharmony_ci    }
190518678f8Sopenharmony_ci    if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) == -1) {
191518678f8Sopenharmony_ci        DHCP_LOGE("failed to setsockopt 'SO_BROADCAST' for server socket!");
192518678f8Sopenharmony_ci        close(fd);
193518678f8Sopenharmony_ci        return -1;
194518678f8Sopenharmony_ci    }
195518678f8Sopenharmony_ci    if (int ret = bind(fd, (sockaddr *)&srvAddrIn, sizeof(sockaddr)) == -1) {
196518678f8Sopenharmony_ci        DHCP_LOGE("failed to bind server  %{public}d!", ret);
197518678f8Sopenharmony_ci        close(fd);
198518678f8Sopenharmony_ci        return -1;
199518678f8Sopenharmony_ci    }
200518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d   SUCCESSs ", __func__, __LINE__);
201518678f8Sopenharmony_ci    return fd;
202518678f8Sopenharmony_ci}
203518678f8Sopenharmony_ci
204518678f8Sopenharmony_cistruct sockaddr_in *BroadcastAddrIn(void)
205518678f8Sopenharmony_ci{
206518678f8Sopenharmony_ci    static struct sockaddr_in broadcastAddrIn = {0};
207518678f8Sopenharmony_ci    if (broadcastAddrIn.sin_port == 0) {
208518678f8Sopenharmony_ci        broadcastAddrIn.sin_port = htons(DHCP_CLIENT_PORT);
209518678f8Sopenharmony_ci        broadcastAddrIn.sin_family = AF_INET;
210518678f8Sopenharmony_ci        broadcastAddrIn.sin_addr.s_addr = INADDR_BROADCAST;
211518678f8Sopenharmony_ci    }
212518678f8Sopenharmony_ci    return &broadcastAddrIn;
213518678f8Sopenharmony_ci}
214518678f8Sopenharmony_ci
215518678f8Sopenharmony_cistruct sockaddr_in *SourceAddrIn(void)
216518678f8Sopenharmony_ci{
217518678f8Sopenharmony_ci    static struct sockaddr_in sourceAddrIn = {0};
218518678f8Sopenharmony_ci    sourceAddrIn.sin_port = htons(DHCP_CLIENT_PORT);
219518678f8Sopenharmony_ci    sourceAddrIn.sin_family = AF_INET;
220518678f8Sopenharmony_ci    sourceAddrIn.sin_addr.s_addr = INADDR_ANY;
221518678f8Sopenharmony_ci    return &sourceAddrIn;
222518678f8Sopenharmony_ci}
223518678f8Sopenharmony_ci
224518678f8Sopenharmony_cistruct sockaddr_in *ResetSourceAddr(void)
225518678f8Sopenharmony_ci{
226518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
227518678f8Sopenharmony_ci    struct sockaddr_in *srcAddr = SourceAddrIn();
228518678f8Sopenharmony_ci    srcAddr->sin_port = htons(DHCP_CLIENT_PORT);
229518678f8Sopenharmony_ci    srcAddr->sin_family = AF_INET;
230518678f8Sopenharmony_ci    srcAddr->sin_addr.s_addr = INADDR_ANY;
231518678f8Sopenharmony_ci    return srcAddr;
232518678f8Sopenharmony_ci}
233518678f8Sopenharmony_ci
234518678f8Sopenharmony_ciuint32_t SourceIpAddress(void)
235518678f8Sopenharmony_ci{
236518678f8Sopenharmony_ci    uint32_t srcIp = SourceAddrIn()->sin_addr.s_addr;
237518678f8Sopenharmony_ci    return srcIp;
238518678f8Sopenharmony_ci}
239518678f8Sopenharmony_cistruct sockaddr_in *DestinationAddrIn(void)
240518678f8Sopenharmony_ci{
241518678f8Sopenharmony_ci    static struct sockaddr_in destAddrIn = {0};
242518678f8Sopenharmony_ci    if (destAddrIn.sin_port == 0) {
243518678f8Sopenharmony_ci        destAddrIn.sin_port = htons(DHCP_CLIENT_PORT);
244518678f8Sopenharmony_ci        destAddrIn.sin_family = AF_INET;
245518678f8Sopenharmony_ci    }
246518678f8Sopenharmony_ci    return &destAddrIn;
247518678f8Sopenharmony_ci}
248518678f8Sopenharmony_ci
249518678f8Sopenharmony_cistruct sockaddr_in *DestinationAddr(uint32_t ipAddress)
250518678f8Sopenharmony_ci{
251518678f8Sopenharmony_ci    struct sockaddr_in *destAddr = DestinationAddrIn();
252518678f8Sopenharmony_ci    destAddr->sin_addr.s_addr = htonl(ipAddress);
253518678f8Sopenharmony_ci    return destAddr;
254518678f8Sopenharmony_ci}
255518678f8Sopenharmony_ci
256518678f8Sopenharmony_ciint ReceiveDhcpMessage(int sock, PDhcpMsgInfo msgInfo)
257518678f8Sopenharmony_ci{
258518678f8Sopenharmony_ci    static uint8_t recvBuffer[RECV_BUFFER_SIZE] = {0};
259518678f8Sopenharmony_ci    struct timeval tmt;
260518678f8Sopenharmony_ci    fd_set recvFd;
261518678f8Sopenharmony_ci    FD_ZERO(&recvFd);
262518678f8Sopenharmony_ci    FD_SET(sock, &recvFd);
263518678f8Sopenharmony_ci    tmt.tv_sec = 0;
264518678f8Sopenharmony_ci    tmt.tv_usec = DHCP_SERVER_SLEEP_TIMEOUTS; // 600ms
265518678f8Sopenharmony_ci    int ret = select(sock + 1, &recvFd, nullptr, nullptr, &tmt);
266518678f8Sopenharmony_ci    if (ret < 0) {
267518678f8Sopenharmony_ci        DHCP_LOGE("select error, %d", errno);
268518678f8Sopenharmony_ci        return ERR_SELECT;
269518678f8Sopenharmony_ci    }
270518678f8Sopenharmony_ci    if (ret == 0) {
271518678f8Sopenharmony_ci        return RET_SELECT_TIME_OUT;
272518678f8Sopenharmony_ci    }
273518678f8Sopenharmony_ci    if (!FD_ISSET(sock, &recvFd)) {
274518678f8Sopenharmony_ci        DHCP_LOGE("failed to select isset.");
275518678f8Sopenharmony_ci        return RET_ERROR;
276518678f8Sopenharmony_ci    }
277518678f8Sopenharmony_ci    socklen_t ssize = sizeof(sockaddr_in);
278518678f8Sopenharmony_ci    struct sockaddr_in *srcAddrIn = ResetSourceAddr();
279518678f8Sopenharmony_ci    srcAddrIn->sin_addr.s_addr = INADDR_ANY;
280518678f8Sopenharmony_ci    DHCP_LOGI("start recv from");
281518678f8Sopenharmony_ci    int rsize = recvfrom(sock, recvBuffer, RECV_BUFFER_SIZE, 0, (struct sockaddr *)srcAddrIn, (socklen_t *)&ssize);
282518678f8Sopenharmony_ci    if (!rsize) {
283518678f8Sopenharmony_ci        DHCP_LOGE("receive error, %d", errno);
284518678f8Sopenharmony_ci        return RET_FAILED;
285518678f8Sopenharmony_ci    }
286518678f8Sopenharmony_ci    if (rsize > (int)sizeof(DhcpMessage) || rsize < DHCP_MSG_HEADER_SIZE) {
287518678f8Sopenharmony_ci        DHCP_LOGW("message length error, received %d bytes.", rsize);
288518678f8Sopenharmony_ci        return RET_FAILED;
289518678f8Sopenharmony_ci    }
290518678f8Sopenharmony_ci    DHCP_LOGI("recv over");
291518678f8Sopenharmony_ci    msgInfo->length = rsize;
292518678f8Sopenharmony_ci    if (memcpy_s(&msgInfo->packet, sizeof(DhcpMessage), recvBuffer, rsize) != EOK) {
293518678f8Sopenharmony_ci        return RET_FAILED;
294518678f8Sopenharmony_ci    }
295518678f8Sopenharmony_ci    if (msgInfo->packet.op != BOOTREQUEST) {
296518678f8Sopenharmony_ci        DHCP_LOGW("dhcp message type error!");
297518678f8Sopenharmony_ci        return RET_FAILED;
298518678f8Sopenharmony_ci    }
299518678f8Sopenharmony_ci    if (msgInfo->packet.hlen > DHCP_HWADDR_LENGTH) {
300518678f8Sopenharmony_ci        DHCP_LOGW("hlen error!");
301518678f8Sopenharmony_ci        return RET_FAILED;
302518678f8Sopenharmony_ci    }
303518678f8Sopenharmony_ci    if (IsEmptyHWAddr(msgInfo->packet.chaddr)) {
304518678f8Sopenharmony_ci        DHCP_LOGW("client hardware address error!");
305518678f8Sopenharmony_ci        return RET_FAILED;
306518678f8Sopenharmony_ci    }
307518678f8Sopenharmony_ci    if (IsReserved(msgInfo->packet.chaddr)) {
308518678f8Sopenharmony_ci        DHCP_LOGD("ignore client, %s", ParseLogMac(msgInfo->packet.chaddr));
309518678f8Sopenharmony_ci        return RET_FAILED;
310518678f8Sopenharmony_ci    }
311518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d  return success", __func__, __LINE__);
312518678f8Sopenharmony_ci    return RET_SUCCESS;
313518678f8Sopenharmony_ci}
314518678f8Sopenharmony_ci
315518678f8Sopenharmony_civoid InitReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
316518678f8Sopenharmony_ci{
317518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
318518678f8Sopenharmony_ci    if (!reply) {
319518678f8Sopenharmony_ci        DHCP_LOGE("reply message pointer is null!");
320518678f8Sopenharmony_ci        return;
321518678f8Sopenharmony_ci    }
322518678f8Sopenharmony_ci    reply->packet.op = BOOTREPLY;
323518678f8Sopenharmony_ci    reply->packet.htype = ETHERNET;
324518678f8Sopenharmony_ci    reply->packet.hlen = OPT_MAC_ADDR_LENGTH;
325518678f8Sopenharmony_ci    reply->packet.secs = 0;
326518678f8Sopenharmony_ci    reply->packet.ciaddr = 0;
327518678f8Sopenharmony_ci    if (memset_s(reply->packet.sname, sizeof(reply->packet.sname), '\0', sizeof(reply->packet.sname)) != EOK) {
328518678f8Sopenharmony_ci        DHCP_LOGE("failed to reset message packet[sname]!");
329518678f8Sopenharmony_ci        return;
330518678f8Sopenharmony_ci    };
331518678f8Sopenharmony_ci    if (memset_s(reply->packet.file, sizeof(reply->packet.file), '\0', sizeof(reply->packet.file)) != EOK) {
332518678f8Sopenharmony_ci        DHCP_LOGE("failed to reset message packet[file]!");
333518678f8Sopenharmony_ci        return;
334518678f8Sopenharmony_ci    }
335518678f8Sopenharmony_ci
336518678f8Sopenharmony_ci    if (FillReply(ctx, received, reply) != RET_SUCCESS) {
337518678f8Sopenharmony_ci        DHCP_LOGW("failed to fill reply message.");
338518678f8Sopenharmony_ci    }
339518678f8Sopenharmony_ci}
340518678f8Sopenharmony_ci
341518678f8Sopenharmony_civoid OnUpdateServerConfig(PDhcpServerContext ctx)
342518678f8Sopenharmony_ci{
343518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
344518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
345518678f8Sopenharmony_ci    if (!srvIns) {
346518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
347518678f8Sopenharmony_ci        return;
348518678f8Sopenharmony_ci    }
349518678f8Sopenharmony_ci    if (srvIns->callback) {
350518678f8Sopenharmony_ci        srvIns->callback(ST_RELOADNG, 0, ctx->ifname);
351518678f8Sopenharmony_ci    }
352518678f8Sopenharmony_ci}
353518678f8Sopenharmony_ci
354518678f8Sopenharmony_cistatic void OnServerStoping(PDhcpServerContext ctx)
355518678f8Sopenharmony_ci{
356518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
357518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
358518678f8Sopenharmony_ci    if (!srvIns) {
359518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
360518678f8Sopenharmony_ci        return;
361518678f8Sopenharmony_ci    }
362518678f8Sopenharmony_ci    if (srvIns->callback) {
363518678f8Sopenharmony_ci        srvIns->callback(ST_STOPING, 0, ctx->ifname);
364518678f8Sopenharmony_ci    }
365518678f8Sopenharmony_ci}
366518678f8Sopenharmony_ci
367518678f8Sopenharmony_civoid OnServerStoped(PDhcpServerContext ctx, int code)
368518678f8Sopenharmony_ci{
369518678f8Sopenharmony_ci    DHCP_LOGI("OnServerStoped.");
370518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
371518678f8Sopenharmony_ci    if (!srvIns) {
372518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
373518678f8Sopenharmony_ci        return;
374518678f8Sopenharmony_ci    }
375518678f8Sopenharmony_ci    if (srvIns->callback) {
376518678f8Sopenharmony_ci        srvIns->callback(ST_STOPED, code, ctx->ifname);
377518678f8Sopenharmony_ci    }
378518678f8Sopenharmony_ci}
379518678f8Sopenharmony_ci
380518678f8Sopenharmony_ciint SendDhcpReply(PDhcpServerContext ctx, int replyType, PDhcpMsgInfo reply)
381518678f8Sopenharmony_ci{
382518678f8Sopenharmony_ci    if (!reply) {
383518678f8Sopenharmony_ci        DHCP_LOGE("reply message pointer is null.");
384518678f8Sopenharmony_ci        return RET_FAILED;
385518678f8Sopenharmony_ci    }
386518678f8Sopenharmony_ci    int sendRet = -1;
387518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
388518678f8Sopenharmony_ci    if (!srvIns) {
389518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
390518678f8Sopenharmony_ci        return RET_FAILED;
391518678f8Sopenharmony_ci    }
392518678f8Sopenharmony_ci    switch (replyType) {
393518678f8Sopenharmony_ci        case REPLY_OFFER:
394518678f8Sopenharmony_ci            DHCP_LOGD("<== send reply dhcp offer.");
395518678f8Sopenharmony_ci            sendRet = SendDhcpOffer(ctx, reply);
396518678f8Sopenharmony_ci            break;
397518678f8Sopenharmony_ci        case REPLY_ACK:
398518678f8Sopenharmony_ci            DHCP_LOGD("<== send reply dhcp ack.");
399518678f8Sopenharmony_ci            sendRet = SendDhcpAck(ctx, reply);
400518678f8Sopenharmony_ci            break;
401518678f8Sopenharmony_ci        case REPLY_NAK:
402518678f8Sopenharmony_ci            DHCP_LOGD("<== send reply dhcp nak.");
403518678f8Sopenharmony_ci            sendRet = SendDhcpNak(ctx, reply);
404518678f8Sopenharmony_ci            break;
405518678f8Sopenharmony_ci        default:
406518678f8Sopenharmony_ci            break;
407518678f8Sopenharmony_ci    }
408518678f8Sopenharmony_ci    if (replyType && sendRet != RET_SUCCESS) {
409518678f8Sopenharmony_ci        return RET_FAILED;
410518678f8Sopenharmony_ci    }
411518678f8Sopenharmony_ci    return  RET_SUCCESS;
412518678f8Sopenharmony_ci}
413518678f8Sopenharmony_ci
414518678f8Sopenharmony_cistatic int MessageProcess(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
415518678f8Sopenharmony_ci{
416518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
417518678f8Sopenharmony_ci    int replyType = REPLY_NONE;
418518678f8Sopenharmony_ci    if (!received) {
419518678f8Sopenharmony_ci        return replyType;
420518678f8Sopenharmony_ci    }
421518678f8Sopenharmony_ci    PDhcpOption opt = GetOption(&received->options, DHCP_MESSAGE_TYPE_OPTION);
422518678f8Sopenharmony_ci    if (!opt) {
423518678f8Sopenharmony_ci        DHCP_LOGE("error dhcp message, missing required message type option.");
424518678f8Sopenharmony_ci        return replyType;
425518678f8Sopenharmony_ci    }
426518678f8Sopenharmony_ci    uint8_t messageType = opt->data[0];
427518678f8Sopenharmony_ci    switch (messageType) {
428518678f8Sopenharmony_ci        case DHCPDISCOVER: {
429518678f8Sopenharmony_ci            DHCP_LOGD("==> Received DHCPDISCOVER message.");
430518678f8Sopenharmony_ci            replyType = OnReceivedDiscover(ctx, received, reply);
431518678f8Sopenharmony_ci            break;
432518678f8Sopenharmony_ci        }
433518678f8Sopenharmony_ci        case DHCPREQUEST: {
434518678f8Sopenharmony_ci            DHCP_LOGD("==> Received DHCPREQUEST message.");
435518678f8Sopenharmony_ci            replyType = OnReceivedRequest(ctx, received, reply);
436518678f8Sopenharmony_ci            break;
437518678f8Sopenharmony_ci        }
438518678f8Sopenharmony_ci        case DHCPDECLINE: {
439518678f8Sopenharmony_ci            DHCP_LOGD("==> Received DHCPDECLINE message.");
440518678f8Sopenharmony_ci            replyType = OnReceivedDecline(ctx, received, reply);
441518678f8Sopenharmony_ci            break;
442518678f8Sopenharmony_ci        }
443518678f8Sopenharmony_ci        case DHCPRELEASE: {
444518678f8Sopenharmony_ci            DHCP_LOGD("==> Received DHCPRELEASE message.");
445518678f8Sopenharmony_ci            replyType = OnReceivedRelease(ctx, received, reply);
446518678f8Sopenharmony_ci            break;
447518678f8Sopenharmony_ci        }
448518678f8Sopenharmony_ci        case DHCPINFORM: {
449518678f8Sopenharmony_ci            DHCP_LOGD("==> Received DHCPINFORM message.");
450518678f8Sopenharmony_ci            replyType = OnReceivedInform(ctx, received, reply);
451518678f8Sopenharmony_ci            break;
452518678f8Sopenharmony_ci        }
453518678f8Sopenharmony_ci        default:
454518678f8Sopenharmony_ci            break;
455518678f8Sopenharmony_ci    }
456518678f8Sopenharmony_ci    return replyType;
457518678f8Sopenharmony_ci}
458518678f8Sopenharmony_ci
459518678f8Sopenharmony_ciint SaveLease(PDhcpServerContext ctx)
460518678f8Sopenharmony_ci{
461518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
462518678f8Sopenharmony_ci    if (!srvIns) {
463518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
464518678f8Sopenharmony_ci        return RET_FAILED;
465518678f8Sopenharmony_ci    }
466518678f8Sopenharmony_ci    int saveRet = SaveBindingRecoders(&srvIns->addressPool, 1);
467518678f8Sopenharmony_ci    if (saveRet == RET_FAILED) {
468518678f8Sopenharmony_ci        DHCP_LOGD("failed to save lease recoders. total: %zu", srvIns->addressPool.leaseTable.size());
469518678f8Sopenharmony_ci    } else if (saveRet == RET_SUCCESS) {
470518678f8Sopenharmony_ci        DHCP_LOGD("lease recoders saved.");
471518678f8Sopenharmony_ci    }
472518678f8Sopenharmony_ci    return saveRet;
473518678f8Sopenharmony_ci}
474518678f8Sopenharmony_ci
475518678f8Sopenharmony_cistatic int OnLooperStateChanged(PDhcpServerContext ctx)
476518678f8Sopenharmony_ci{
477518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
478518678f8Sopenharmony_ci    if (!srvIns) {
479518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
480518678f8Sopenharmony_ci        return RET_FAILED;
481518678f8Sopenharmony_ci    }
482518678f8Sopenharmony_ci
483518678f8Sopenharmony_ci    if (srvIns->looperState == LS_RELOADNG) {
484518678f8Sopenharmony_ci        OnUpdateServerConfig(ctx);
485518678f8Sopenharmony_ci        srvIns->looperState = LS_RUNNING;
486518678f8Sopenharmony_ci    } else if (srvIns->looperState == LS_STOPING) {
487518678f8Sopenharmony_ci        OnServerStoping(ctx);
488518678f8Sopenharmony_ci        return RET_BREAK;
489518678f8Sopenharmony_ci    }
490518678f8Sopenharmony_ci    return RET_SUCCESS;
491518678f8Sopenharmony_ci}
492518678f8Sopenharmony_ci
493518678f8Sopenharmony_cistatic int ContinueReceive(PDhcpMsgInfo from, int recvRet)
494518678f8Sopenharmony_ci{
495518678f8Sopenharmony_ci    if (!from) {
496518678f8Sopenharmony_ci        return DHCP_TRUE;
497518678f8Sopenharmony_ci    }
498518678f8Sopenharmony_ci    if (recvRet != RET_SUCCESS) {
499518678f8Sopenharmony_ci        return DHCP_TRUE;
500518678f8Sopenharmony_ci    }
501518678f8Sopenharmony_ci    DHCP_LOGD("received, length:%{public}d", from->length);
502518678f8Sopenharmony_ci    if (ParseMessageOptions(from) != 0) {
503518678f8Sopenharmony_ci        DHCP_LOGE("invalid dhcp message.");
504518678f8Sopenharmony_ci        return DHCP_TRUE;
505518678f8Sopenharmony_ci    }
506518678f8Sopenharmony_ci    if (!GetOption(&from->options, DHCP_MESSAGE_TYPE_OPTION)) {
507518678f8Sopenharmony_ci        DHCP_LOGW("can't found 'message type' option.");
508518678f8Sopenharmony_ci        return DHCP_TRUE;
509518678f8Sopenharmony_ci    }
510518678f8Sopenharmony_ci    return DHCP_FALSE;
511518678f8Sopenharmony_ci}
512518678f8Sopenharmony_ci
513518678f8Sopenharmony_cistatic void *BeginLooper(void *argc) __attribute__((no_sanitize("cfi")))
514518678f8Sopenharmony_ci{
515518678f8Sopenharmony_ci    PDhcpServerContext ctx = (PDhcpServerContext)argc;
516518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
517518678f8Sopenharmony_ci    DhcpMsgInfo from;
518518678f8Sopenharmony_ci    DhcpMsgInfo reply;
519518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
520518678f8Sopenharmony_ci    if (!srvIns) {
521518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
522518678f8Sopenharmony_ci        return nullptr;
523518678f8Sopenharmony_ci    }
524518678f8Sopenharmony_ci    ctx->instance->serverFd = InitServer(ctx->ifname);
525518678f8Sopenharmony_ci    if (ctx->instance->serverFd < 0) {
526518678f8Sopenharmony_ci        DHCP_LOGE("failed to initialize server socket.");
527518678f8Sopenharmony_ci        return nullptr;
528518678f8Sopenharmony_ci    }
529518678f8Sopenharmony_ci    InitOptionList(&from.options);
530518678f8Sopenharmony_ci    InitOptionList(&reply.options);
531518678f8Sopenharmony_ci    srvIns->looperState = LS_RUNNING;
532518678f8Sopenharmony_ci    while (srvIns->looperState) {
533518678f8Sopenharmony_ci        if (OnLooperStateChanged(ctx) != RET_SUCCESS) {
534518678f8Sopenharmony_ci            DHCP_LOGI("OnLooperStateChanged break, looperState:%{public}d", srvIns->looperState);
535518678f8Sopenharmony_ci            break;
536518678f8Sopenharmony_ci        }
537518678f8Sopenharmony_ci        ClearOptions(&from.options);
538518678f8Sopenharmony_ci        ClearOptions(&reply.options);
539518678f8Sopenharmony_ci        int recvRet = ReceiveDhcpMessage(ctx->instance->serverFd, &from);
540518678f8Sopenharmony_ci        if (recvRet == RET_ERROR || recvRet == ERR_SELECT) {
541518678f8Sopenharmony_ci            DHCP_LOGI("ReceiveDhcpMessage");
542518678f8Sopenharmony_ci            continue;
543518678f8Sopenharmony_ci        }
544518678f8Sopenharmony_ci        if (ContinueReceive(&from, recvRet)) {
545518678f8Sopenharmony_ci            continue;
546518678f8Sopenharmony_ci        }
547518678f8Sopenharmony_ci        InitReply(ctx, &from, &reply);
548518678f8Sopenharmony_ci        int replyType = MessageProcess(ctx, &from, &reply);
549518678f8Sopenharmony_ci        if (replyType && SendDhcpReply(ctx, replyType, &reply) != RET_SUCCESS) {
550518678f8Sopenharmony_ci            DHCP_LOGE("failed to send reply message.");
551518678f8Sopenharmony_ci        }
552518678f8Sopenharmony_ci        NotifyConnetDeviceChanged(replyType, ctx);
553518678f8Sopenharmony_ci    }
554518678f8Sopenharmony_ci    FreeOptionList(&from.options);
555518678f8Sopenharmony_ci    FreeOptionList(&reply.options);
556518678f8Sopenharmony_ci    DHCP_LOGI("dhcp server message looper stopped.");
557518678f8Sopenharmony_ci    close(ctx->instance->serverFd);
558518678f8Sopenharmony_ci    ctx->instance->serverFd = -1;
559518678f8Sopenharmony_ci    srvIns->looperState = LS_STOPED;
560518678f8Sopenharmony_ci    return nullptr;
561518678f8Sopenharmony_ci}
562518678f8Sopenharmony_ci
563518678f8Sopenharmony_civoid NotifyConnetDeviceChanged(int replyType, PDhcpServerContext ctx)
564518678f8Sopenharmony_ci{
565518678f8Sopenharmony_ci    DHCP_LOGI("NotifyConnetDeviceChanged replyType:%{public}d", replyType);
566518678f8Sopenharmony_ci    if (replyType == REPLY_ACK || replyType == REPLY_OFFER) {
567518678f8Sopenharmony_ci        ServerContext *srvIns = GetServerInstance(ctx);
568518678f8Sopenharmony_ci        if (srvIns == nullptr) {
569518678f8Sopenharmony_ci            DHCP_LOGE("NotifyConnetDeviceChanged srvIns is nullptr");
570518678f8Sopenharmony_ci            return;
571518678f8Sopenharmony_ci        }
572518678f8Sopenharmony_ci        int saveRet = SaveBindingRecoders(&srvIns->addressPool, 1);
573518678f8Sopenharmony_ci        if (saveRet != RET_SUCCESS && saveRet != RET_WAIT_SAVE) {
574518678f8Sopenharmony_ci            DHCP_LOGW("SaveBindingRecoders failed to save lease recoders.");
575518678f8Sopenharmony_ci        }
576518678f8Sopenharmony_ci        if (replyType == REPLY_ACK && srvIns->deviceConnectFun != nullptr) {
577518678f8Sopenharmony_ci            DHCP_LOGI("NotifyConnetDeviceChanged deviceConnectFun");
578518678f8Sopenharmony_ci            srvIns->deviceConnectFun(ctx->ifname);
579518678f8Sopenharmony_ci        }
580518678f8Sopenharmony_ci    }
581518678f8Sopenharmony_ci}
582518678f8Sopenharmony_ci
583518678f8Sopenharmony_cistatic int CheckAddressRange(DhcpAddressPool *pool)
584518678f8Sopenharmony_ci{
585518678f8Sopenharmony_ci    uint32_t serverNetwork = NetworkAddress(pool->serverId, pool->netmask);
586518678f8Sopenharmony_ci    uint32_t firstNetwork = NetworkAddress(pool->addressRange.beginAddress, pool->netmask);
587518678f8Sopenharmony_ci    uint32_t secondNetwork = NetworkAddress(pool->addressRange.endAddress, pool->netmask);
588518678f8Sopenharmony_ci    if (!serverNetwork || !firstNetwork || !secondNetwork) {
589518678f8Sopenharmony_ci        DHCP_LOGE("network config error.");
590518678f8Sopenharmony_ci        return DHCP_FALSE;
591518678f8Sopenharmony_ci    }
592518678f8Sopenharmony_ci    if (serverNetwork != firstNetwork || serverNetwork != secondNetwork) {
593518678f8Sopenharmony_ci        DHCP_LOGE("server network and address pool network belong to different networks.");
594518678f8Sopenharmony_ci        return DHCP_FALSE;
595518678f8Sopenharmony_ci    }
596518678f8Sopenharmony_ci    return DHCP_TRUE;
597518678f8Sopenharmony_ci}
598518678f8Sopenharmony_ci
599518678f8Sopenharmony_civoid InitBindingRecoders(DhcpAddressPool *pool)
600518678f8Sopenharmony_ci{
601518678f8Sopenharmony_ci    if (!pool) {
602518678f8Sopenharmony_ci        DHCP_LOGE("address pool pointer is null.");
603518678f8Sopenharmony_ci        return;
604518678f8Sopenharmony_ci    }
605518678f8Sopenharmony_ci    uint32_t realLeaseTotal = 0;
606518678f8Sopenharmony_ci    for (auto current: pool->leaseTable) {
607518678f8Sopenharmony_ci        int invalidBindig;
608518678f8Sopenharmony_ci        AddressBinding *binding = &current.second;
609518678f8Sopenharmony_ci        if (binding && !IsEmptyHWAddr(binding->chaddr) && binding->ipAddress) {
610518678f8Sopenharmony_ci            AddBinding(binding);
611518678f8Sopenharmony_ci            realLeaseTotal++;
612518678f8Sopenharmony_ci            invalidBindig = 0;
613518678f8Sopenharmony_ci        } else {
614518678f8Sopenharmony_ci            DHCP_LOGE("bad binding recoder.");
615518678f8Sopenharmony_ci            invalidBindig = 1;
616518678f8Sopenharmony_ci        }
617518678f8Sopenharmony_ci        if (!invalidBindig && binding && pool->distribution < binding->ipAddress) {
618518678f8Sopenharmony_ci            pool->distribution = binding->ipAddress;
619518678f8Sopenharmony_ci        }
620518678f8Sopenharmony_ci    }
621518678f8Sopenharmony_ci    DHCP_LOGD("lease recoder total: %u", realLeaseTotal);
622518678f8Sopenharmony_ci}
623518678f8Sopenharmony_ci
624518678f8Sopenharmony_civoid InitLeaseFile(DhcpAddressPool *pool)
625518678f8Sopenharmony_ci{
626518678f8Sopenharmony_ci    const char *leasePath  = GetFilePath(DHCPD_LEASE_FILE);
627518678f8Sopenharmony_ci    if (!leasePath || strlen(leasePath) == 0) {
628518678f8Sopenharmony_ci        DHCP_LOGE("failed to get lease file path.");
629518678f8Sopenharmony_ci        return;
630518678f8Sopenharmony_ci    }
631518678f8Sopenharmony_ci    if (access(leasePath, 0) != 0) {
632518678f8Sopenharmony_ci        DHCP_LOGD("lease file path does not exist.");
633518678f8Sopenharmony_ci        if (!CreatePath(leasePath)) {
634518678f8Sopenharmony_ci            DHCP_LOGE("failed to create lease file directory.");
635518678f8Sopenharmony_ci            return;
636518678f8Sopenharmony_ci        } else {
637518678f8Sopenharmony_ci            DHCP_LOGD("lease file directory created.");
638518678f8Sopenharmony_ci        }
639518678f8Sopenharmony_ci    }
640518678f8Sopenharmony_ci    if (LoadBindingRecoders(pool) != RET_SUCCESS) {
641518678f8Sopenharmony_ci        DHCP_LOGW("failed to load lease recoders.");
642518678f8Sopenharmony_ci    }
643518678f8Sopenharmony_ci    InitBindingRecoders(pool);
644518678f8Sopenharmony_ci}
645518678f8Sopenharmony_ci
646518678f8Sopenharmony_cistatic void ExitProcess(void)
647518678f8Sopenharmony_ci{
648518678f8Sopenharmony_ci    DHCP_LOGD("dhcp server stopped.");
649518678f8Sopenharmony_ci}
650518678f8Sopenharmony_ci
651518678f8Sopenharmony_ciint StartDhcpServer(PDhcpServerContext ctx)
652518678f8Sopenharmony_ci{
653518678f8Sopenharmony_ci    DHCP_LOGI("%{public}s  %{public}d  start", __func__, __LINE__);
654518678f8Sopenharmony_ci    if (!ctx) {
655518678f8Sopenharmony_ci        DHCP_LOGE("server context pointer is null.");
656518678f8Sopenharmony_ci        return RET_FAILED;
657518678f8Sopenharmony_ci    }
658518678f8Sopenharmony_ci    if (strlen(ctx->ifname) == 0) {
659518678f8Sopenharmony_ci        DHCP_LOGE("context interface is null or empty.");
660518678f8Sopenharmony_ci        return RET_FAILED;
661518678f8Sopenharmony_ci    }
662518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
663518678f8Sopenharmony_ci    if (!srvIns) {
664518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context instance pointer is null.");
665518678f8Sopenharmony_ci        return RET_FAILED;
666518678f8Sopenharmony_ci    }
667518678f8Sopenharmony_ci    if (atexit(ExitProcess) != 0) {
668518678f8Sopenharmony_ci        DHCP_LOGW("failed to regiester exit process function.");
669518678f8Sopenharmony_ci    }
670518678f8Sopenharmony_ci    if (!srvIns->initialized) {
671518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server no initialized.");
672518678f8Sopenharmony_ci        return RET_FAILED;
673518678f8Sopenharmony_ci    }
674518678f8Sopenharmony_ci    DHCP_LOGD("bind interface: %{public}s, begin dhcp message looper", ctx->ifname);
675518678f8Sopenharmony_ci    if (srvIns->callback) {
676518678f8Sopenharmony_ci        srvIns->callback(ST_STARTING, 1, ctx->ifname);
677518678f8Sopenharmony_ci    }
678518678f8Sopenharmony_ci    pthread_t threadId;
679518678f8Sopenharmony_ci    int ret = pthread_create(&threadId, nullptr, BeginLooper, ctx);
680518678f8Sopenharmony_ci    if (ret != RET_SUCCESS) {
681518678f8Sopenharmony_ci        DHCP_LOGI("failed to start dhcp server.");
682518678f8Sopenharmony_ci        OnServerStoped(ctx, ret);
683518678f8Sopenharmony_ci        return RET_FAILED;
684518678f8Sopenharmony_ci    }
685518678f8Sopenharmony_ci    OnServerStoped(ctx, ret);
686518678f8Sopenharmony_ci    return RET_SUCCESS;
687518678f8Sopenharmony_ci}
688518678f8Sopenharmony_ci
689518678f8Sopenharmony_ciint StopDhcpServer(PDhcpServerContext ctx)
690518678f8Sopenharmony_ci{
691518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
692518678f8Sopenharmony_ci    if (!srvIns) {
693518678f8Sopenharmony_ci        DHCP_LOGE("StopDhcpServer GetServerInstance failed!");
694518678f8Sopenharmony_ci        return RET_FAILED;
695518678f8Sopenharmony_ci    }
696518678f8Sopenharmony_ci    srvIns->looperState = LS_STOPING;
697518678f8Sopenharmony_ci    DHCP_LOGI("StopDhcpServer looperState LS_STOPING!");
698518678f8Sopenharmony_ci    return RET_SUCCESS;
699518678f8Sopenharmony_ci}
700518678f8Sopenharmony_ci
701518678f8Sopenharmony_ciint GetServerStatus(PDhcpServerContext ctx)
702518678f8Sopenharmony_ci{
703518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
704518678f8Sopenharmony_ci    if (!srvIns) {
705518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
706518678f8Sopenharmony_ci        return -1;
707518678f8Sopenharmony_ci    }
708518678f8Sopenharmony_ci    return srvIns->looperState;
709518678f8Sopenharmony_ci}
710518678f8Sopenharmony_ci
711518678f8Sopenharmony_ciint FillReply(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
712518678f8Sopenharmony_ci{
713518678f8Sopenharmony_ci    if (!received || !reply) {
714518678f8Sopenharmony_ci        return RET_ERROR;
715518678f8Sopenharmony_ci    }
716518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
717518678f8Sopenharmony_ci    if (!srvIns) {
718518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
719518678f8Sopenharmony_ci        return RET_FAILED;
720518678f8Sopenharmony_ci    }
721518678f8Sopenharmony_ci    if (received->packet.ciaddr && received->packet.ciaddr != INADDR_BROADCAST) {
722518678f8Sopenharmony_ci        reply->packet.ciaddr = received->packet.ciaddr;
723518678f8Sopenharmony_ci    }
724518678f8Sopenharmony_ci    if (received->packet.flags) {
725518678f8Sopenharmony_ci        reply->packet.flags = received->packet.flags;
726518678f8Sopenharmony_ci    }
727518678f8Sopenharmony_ci    if (received->packet.xid) {
728518678f8Sopenharmony_ci        reply->packet.xid = received->packet.xid;
729518678f8Sopenharmony_ci    }
730518678f8Sopenharmony_ci    if (received->packet.siaddr && received->packet.siaddr != INADDR_BROADCAST) {
731518678f8Sopenharmony_ci        reply->packet.siaddr = received->packet.siaddr;
732518678f8Sopenharmony_ci    } else {
733518678f8Sopenharmony_ci        reply->packet.siaddr = srvIns->addressPool.serverId;
734518678f8Sopenharmony_ci    }
735518678f8Sopenharmony_ci    if (received->packet.giaddr && received->packet.giaddr != INADDR_BROADCAST) {
736518678f8Sopenharmony_ci        reply->packet.giaddr = received->packet.giaddr;
737518678f8Sopenharmony_ci    } else {
738518678f8Sopenharmony_ci        if (srvIns->addressPool.gateway) {
739518678f8Sopenharmony_ci            reply->packet.giaddr = srvIns->addressPool.gateway;
740518678f8Sopenharmony_ci        }
741518678f8Sopenharmony_ci    }
742518678f8Sopenharmony_ci    if (received->packet.hlen) {
743518678f8Sopenharmony_ci        reply->packet.hlen = received->packet.hlen;
744518678f8Sopenharmony_ci        DHCP_LOGD("fill reply - chaddr:%s", ParseLogMac(received->packet.chaddr));
745518678f8Sopenharmony_ci        if (memset_s(reply->packet.chaddr, sizeof(reply->packet.chaddr), 0, sizeof(reply->packet.chaddr)) != EOK) {
746518678f8Sopenharmony_ci            DHCP_LOGE("failed to reset message packet[chaddr]!");
747518678f8Sopenharmony_ci            return RET_ERROR;
748518678f8Sopenharmony_ci        }
749518678f8Sopenharmony_ci        if (memcpy_s(reply->packet.chaddr, sizeof(reply->packet.chaddr),
750518678f8Sopenharmony_ci            received->packet.chaddr, sizeof(received->packet.chaddr)) != EOK) {
751518678f8Sopenharmony_ci            DHCP_LOGE("failed to copy message packet[chaddr]!");
752518678f8Sopenharmony_ci            return RET_ERROR;
753518678f8Sopenharmony_ci        }
754518678f8Sopenharmony_ci    }
755518678f8Sopenharmony_ci    if (received->packet.giaddr) {
756518678f8Sopenharmony_ci        reply->packet.giaddr = received->packet.giaddr;
757518678f8Sopenharmony_ci    }
758518678f8Sopenharmony_ci    return 0;
759518678f8Sopenharmony_ci}
760518678f8Sopenharmony_ci
761518678f8Sopenharmony_ciint AppendReplyTimeOptions(PDhcpServerContext ctx, PDhcpOptionList options)
762518678f8Sopenharmony_ci{
763518678f8Sopenharmony_ci    if (!ctx || !options) {
764518678f8Sopenharmony_ci        DHCP_LOGE("server context or options pointer is null.");
765518678f8Sopenharmony_ci        return RET_FAILED;
766518678f8Sopenharmony_ci    }
767518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
768518678f8Sopenharmony_ci    if (!srvIns) {
769518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
770518678f8Sopenharmony_ci        return RET_FAILED;
771518678f8Sopenharmony_ci    }
772518678f8Sopenharmony_ci    uint32_t leaseTime = HostToNetwork(DHCP_LEASE_TIME);
773518678f8Sopenharmony_ci    if (srvIns->addressPool.leaseTime) {
774518678f8Sopenharmony_ci        leaseTime = HostToNetwork(srvIns->addressPool.leaseTime);
775518678f8Sopenharmony_ci    }
776518678f8Sopenharmony_ci    DhcpOption optLeaseTime = {IP_ADDRESS_LEASE_TIME_OPTION, OPT_TIME_LENGTH, {0}};
777518678f8Sopenharmony_ci    FillU32Option(&optLeaseTime, leaseTime);
778518678f8Sopenharmony_ci    PushBackOption(options, &optLeaseTime);
779518678f8Sopenharmony_ci
780518678f8Sopenharmony_ci    uint32_t t1Time = HostToNetwork(DHCP_RENEWAL_TIME);
781518678f8Sopenharmony_ci    if (srvIns->addressPool.renewalTime) {
782518678f8Sopenharmony_ci        t1Time = HostToNetwork(srvIns->addressPool.renewalTime);
783518678f8Sopenharmony_ci    }
784518678f8Sopenharmony_ci    DhcpOption optRenewTime = {RENEWAL_TIME_VALUE_OPTION, OPT_TIME_LENGTH, {0}};
785518678f8Sopenharmony_ci    FillU32Option(&optRenewTime, t1Time);
786518678f8Sopenharmony_ci    PushBackOption(options, &optRenewTime);
787518678f8Sopenharmony_ci
788518678f8Sopenharmony_ci    uint32_t t2Time = HostToNetwork(DHCP_REBINDING_TIME);
789518678f8Sopenharmony_ci    if (srvIns->addressPool.rebindingTime) {
790518678f8Sopenharmony_ci        t2Time = HostToNetwork(srvIns->addressPool.rebindingTime);
791518678f8Sopenharmony_ci    }
792518678f8Sopenharmony_ci    DhcpOption optRebindTime = {REBINDING_TIME_VALUE_OPTION, OPT_TIME_LENGTH, {0}};
793518678f8Sopenharmony_ci    FillU32Option(&optRebindTime, t2Time);
794518678f8Sopenharmony_ci    PushBackOption(options, &optRebindTime);
795518678f8Sopenharmony_ci
796518678f8Sopenharmony_ci    return RET_SUCCESS;
797518678f8Sopenharmony_ci}
798518678f8Sopenharmony_ci
799518678f8Sopenharmony_cistatic int Repending(DhcpAddressPool *pool, AddressBinding *binding)
800518678f8Sopenharmony_ci{
801518678f8Sopenharmony_ci    if (!pool) {
802518678f8Sopenharmony_ci        return REPLY_NONE;
803518678f8Sopenharmony_ci    }
804518678f8Sopenharmony_ci    uint32_t bindingIp = binding->ipAddress;
805518678f8Sopenharmony_ci    DHCP_LOGD(" binding found, bindIp:%s", ParseStrIp(bindingIp));
806518678f8Sopenharmony_ci    binding->pendingInterval = NextPendingInterval(binding->pendingInterval);
807518678f8Sopenharmony_ci    uint64_t tms = Tmspsec() - binding->pendingTime;
808518678f8Sopenharmony_ci    if (tms < binding->pendingInterval) {
809518678f8Sopenharmony_ci        binding->pendingTime = Tmspsec();
810518678f8Sopenharmony_ci        DHCP_LOGW("message interval is too short, ignore the message.");
811518678f8Sopenharmony_ci        return REPLY_NONE;
812518678f8Sopenharmony_ci    }
813518678f8Sopenharmony_ci    binding->pendingTime = Tmspsec();
814518678f8Sopenharmony_ci    binding->pendingInterval = 0;
815518678f8Sopenharmony_ci    binding->bindingStatus = BIND_PENDING;
816518678f8Sopenharmony_ci    uint32_t srcIp = SourceIpAddress();
817518678f8Sopenharmony_ci    if (srcIp && srcIp != INADDR_BROADCAST && bindingIp != INADDR_BROADCAST && srcIp != bindingIp) {
818518678f8Sopenharmony_ci        DHCP_LOGW("source ip address and bound ip address inconsistency.");
819518678f8Sopenharmony_ci        return REPLY_NAK;
820518678f8Sopenharmony_ci    }
821518678f8Sopenharmony_ci    if (srcIp && srcIp == bindingIp) {
822518678f8Sopenharmony_ci        if (pool->leaseTable.count(srcIp) == 0) {
823518678f8Sopenharmony_ci            DHCP_LOGD("can't find lease information.");
824518678f8Sopenharmony_ci            pool->leaseTable[srcIp] = *binding;
825518678f8Sopenharmony_ci        } else {
826518678f8Sopenharmony_ci            pool->leaseTable[srcIp] = *binding;
827518678f8Sopenharmony_ci        }
828518678f8Sopenharmony_ci    }
829518678f8Sopenharmony_ci    return REPLY_OFFER;
830518678f8Sopenharmony_ci}
831518678f8Sopenharmony_ci
832518678f8Sopenharmony_cistatic int Rebinding(DhcpAddressPool *pool, AddressBinding *binding)
833518678f8Sopenharmony_ci{
834518678f8Sopenharmony_ci    uint64_t pendingTime = binding->pendingTime;
835518678f8Sopenharmony_ci    int replyType = Repending(pool, binding);
836518678f8Sopenharmony_ci    binding->bindingStatus = BIND_ASSOCIATED;
837518678f8Sopenharmony_ci    if (!binding->leaseTime) {
838518678f8Sopenharmony_ci        binding->leaseTime = pool->leaseTime;
839518678f8Sopenharmony_ci    }
840518678f8Sopenharmony_ci    binding->bindingTime = Tmspsec();
841518678f8Sopenharmony_ci    binding->expireIn = binding->bindingTime + binding->leaseTime;
842518678f8Sopenharmony_ci    binding->pendingTime = pendingTime;
843518678f8Sopenharmony_ci    if (replyType == REPLY_OFFER) {
844518678f8Sopenharmony_ci        replyType = REPLY_ACK;
845518678f8Sopenharmony_ci    }
846518678f8Sopenharmony_ci    return replyType;
847518678f8Sopenharmony_ci}
848518678f8Sopenharmony_ci
849518678f8Sopenharmony_cistatic void AddAddressOption(PDhcpMsgInfo reply, uint8_t code, int32_t address)
850518678f8Sopenharmony_ci{
851518678f8Sopenharmony_ci    if (!reply) {
852518678f8Sopenharmony_ci        return;
853518678f8Sopenharmony_ci    }
854518678f8Sopenharmony_ci    DhcpOption optAddress = {0, 0, {0}};
855518678f8Sopenharmony_ci    optAddress.code = code;
856518678f8Sopenharmony_ci    if (AppendAddressOption(&optAddress, address) != RET_SUCCESS) {
857518678f8Sopenharmony_ci        DHCP_LOGE("failed to append address option.");
858518678f8Sopenharmony_ci        return;
859518678f8Sopenharmony_ci    };
860518678f8Sopenharmony_ci    PushBackOption(&reply->options, &optAddress);
861518678f8Sopenharmony_ci}
862518678f8Sopenharmony_ci
863518678f8Sopenharmony_ciint AddReplyServerIdOption(PDhcpOptionList options, uint32_t serverId)
864518678f8Sopenharmony_ci{
865518678f8Sopenharmony_ci    if (!options) {
866518678f8Sopenharmony_ci        DHCP_LOGE("option list pointer is null.");
867518678f8Sopenharmony_ci        return RET_FAILED;
868518678f8Sopenharmony_ci    }
869518678f8Sopenharmony_ci    if (!serverId || serverId == INADDR_BROADCAST) {
870518678f8Sopenharmony_ci        DHCP_LOGE("servier id error.");
871518678f8Sopenharmony_ci        return RET_FAILED;
872518678f8Sopenharmony_ci    }
873518678f8Sopenharmony_ci    DhcpOption optSrvId = {SERVER_IDENTIFIER_OPTION, 0, {0}};
874518678f8Sopenharmony_ci    if (AppendAddressOption(&optSrvId, serverId) != RET_SUCCESS) {
875518678f8Sopenharmony_ci        DHCP_LOGE("failed to append server id option.");
876518678f8Sopenharmony_ci        return RET_FAILED;
877518678f8Sopenharmony_ci    }
878518678f8Sopenharmony_ci    if (GetOption(options, SERVER_IDENTIFIER_OPTION)) {
879518678f8Sopenharmony_ci        DHCP_LOGD("server identifier option exists.");
880518678f8Sopenharmony_ci        return RET_SUCCESS;
881518678f8Sopenharmony_ci    }
882518678f8Sopenharmony_ci    PushBackOption(options, &optSrvId);
883518678f8Sopenharmony_ci    return RET_SUCCESS;
884518678f8Sopenharmony_ci}
885518678f8Sopenharmony_ci
886518678f8Sopenharmony_cistatic void AddReplyMessageTypeOption(PDhcpMsgInfo reply, uint8_t replyMessageType)
887518678f8Sopenharmony_ci{
888518678f8Sopenharmony_ci    if (!reply) {
889518678f8Sopenharmony_ci        return;
890518678f8Sopenharmony_ci    }
891518678f8Sopenharmony_ci    DhcpOption optMsgType = {DHCP_MESSAGE_TYPE_OPTION, OPT_MESSAGE_TYPE_LEGTH, {replyMessageType, 0}};
892518678f8Sopenharmony_ci    PushBackOption(&reply->options, &optMsgType);
893518678f8Sopenharmony_ci}
894518678f8Sopenharmony_ci
895518678f8Sopenharmony_ci
896518678f8Sopenharmony_ciAddressBinding *GetBinding(DhcpAddressPool *pool, PDhcpMsgInfo received)
897518678f8Sopenharmony_ci{
898518678f8Sopenharmony_ci    if (!pool) {
899518678f8Sopenharmony_ci        return nullptr;
900518678f8Sopenharmony_ci    }
901518678f8Sopenharmony_ci    if (!received) {
902518678f8Sopenharmony_ci        return nullptr;
903518678f8Sopenharmony_ci    }
904518678f8Sopenharmony_ci    AddressBinding *binding = pool->binding(received->packet.chaddr, &received->options);
905518678f8Sopenharmony_ci    if (!binding) {
906518678f8Sopenharmony_ci        binding = pool->newBinding(received->packet.chaddr, &received->options);
907518678f8Sopenharmony_ci        if (binding == nullptr) {
908518678f8Sopenharmony_ci            DHCP_LOGE("new binding is null");
909518678f8Sopenharmony_ci            return nullptr;
910518678f8Sopenharmony_ci        }
911518678f8Sopenharmony_ci        if (pool->leaseTime) {
912518678f8Sopenharmony_ci            binding->leaseTime = pool->leaseTime;
913518678f8Sopenharmony_ci        }
914518678f8Sopenharmony_ci        binding->ipAddress = pool->distribue(pool, received->packet.chaddr);
915518678f8Sopenharmony_ci        DHCP_LOGI("new binding ip");
916518678f8Sopenharmony_ci    } else {
917518678f8Sopenharmony_ci        DHCP_LOGI("rebinding ip");
918518678f8Sopenharmony_ci    }
919518678f8Sopenharmony_ci    return binding;
920518678f8Sopenharmony_ci}
921518678f8Sopenharmony_ci
922518678f8Sopenharmony_ciint ReplyCommontOption(PDhcpServerContext ctx, PDhcpMsgInfo reply)
923518678f8Sopenharmony_ci{
924518678f8Sopenharmony_ci    if (!reply) {
925518678f8Sopenharmony_ci        DHCP_LOGE("reply is nullptr!");
926518678f8Sopenharmony_ci        return REPLY_NONE;
927518678f8Sopenharmony_ci    }
928518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
929518678f8Sopenharmony_ci    if (!srvIns) {
930518678f8Sopenharmony_ci        DHCP_LOGE("srvIns is nullptr!");
931518678f8Sopenharmony_ci        return REPLY_NONE;
932518678f8Sopenharmony_ci    }
933518678f8Sopenharmony_ci    AddAddressOption(reply, SUBNET_MASK_OPTION, srvIns->addressPool.netmask);
934518678f8Sopenharmony_ci    if (srvIns->addressPool.gateway) {
935518678f8Sopenharmony_ci        AddAddressOption(reply, ROUTER_OPTION, srvIns->addressPool.gateway);
936518678f8Sopenharmony_ci    }
937518678f8Sopenharmony_ci    DhcpOption optVendorInfo = {VENDOR_SPECIFIC_INFO_OPTION, static_cast<uint8_t>(strlen(VNEDOR_OPEN_HARMONY)),
938518678f8Sopenharmony_ci        VNEDOR_OPEN_HARMONY};
939518678f8Sopenharmony_ci    PushBackOption(&reply->options, &optVendorInfo);
940518678f8Sopenharmony_ci    uint32_t netAddress = reply->packet.yiaddr & srvIns->addressPool.netmask;
941518678f8Sopenharmony_ci    uint32_t boastAddress = (~srvIns->addressPool.netmask) | netAddress;
942518678f8Sopenharmony_ci    AddAddressOption(reply, BROADCAST_ADDRESS_OPTION, boastAddress);
943518678f8Sopenharmony_ci    return REPLY_OFFER;
944518678f8Sopenharmony_ci}
945518678f8Sopenharmony_ci
946518678f8Sopenharmony_cistatic int DiscoverReplyLeaseMessage(PDhcpServerContext ctx, PDhcpMsgInfo reply, ServerContext *srvIns,
947518678f8Sopenharmony_ci    AddressBinding *binding)
948518678f8Sopenharmony_ci{
949518678f8Sopenharmony_ci    if (!ctx) {
950518678f8Sopenharmony_ci        DHCP_LOGE("ctx pointer is null.");
951518678f8Sopenharmony_ci        return REPLY_NONE;
952518678f8Sopenharmony_ci    }
953518678f8Sopenharmony_ci    if (!reply) {
954518678f8Sopenharmony_ci        DHCP_LOGE("reply message pointer is null.");
955518678f8Sopenharmony_ci        return REPLY_NONE;
956518678f8Sopenharmony_ci    }
957518678f8Sopenharmony_ci    if (!srvIns) {
958518678f8Sopenharmony_ci        DHCP_LOGE("get server instance is nullptr!");
959518678f8Sopenharmony_ci        return REPLY_NONE;
960518678f8Sopenharmony_ci    }
961518678f8Sopenharmony_ci    if (!binding) {
962518678f8Sopenharmony_ci        DHCP_LOGI("Discover binding is null, reply none");
963518678f8Sopenharmony_ci        return REPLY_NONE;
964518678f8Sopenharmony_ci    }
965518678f8Sopenharmony_ci    AddressBinding *lease = GetLease(&srvIns->addressPool, binding->ipAddress);
966518678f8Sopenharmony_ci    if (!lease) {
967518678f8Sopenharmony_ci        DHCP_LOGI("Discover add lease, binging ip:%{public}s mac:%{public}s",
968518678f8Sopenharmony_ci            OHOS::DHCP::IntIpv4ToAnonymizeStr(binding->ipAddress).c_str(), ParseLogMac(binding->chaddr));
969518678f8Sopenharmony_ci        AddLease(&srvIns->addressPool, binding);
970518678f8Sopenharmony_ci        lease = GetLease(&srvIns->addressPool, binding->ipAddress);
971518678f8Sopenharmony_ci    }
972518678f8Sopenharmony_ci    if (!lease) {
973518678f8Sopenharmony_ci        DHCP_LOGI("Discover lease is null, reply none");
974518678f8Sopenharmony_ci        return REPLY_NONE;
975518678f8Sopenharmony_ci    }
976518678f8Sopenharmony_ci    AddReplyMessageTypeOption(reply, DHCPOFFER);
977518678f8Sopenharmony_ci    reply->packet.yiaddr = lease->ipAddress;
978518678f8Sopenharmony_ci    ReplyCommontOption(ctx, reply);
979518678f8Sopenharmony_ci    DHCP_LOGI("Discover reply offer");
980518678f8Sopenharmony_ci    return REPLY_OFFER;
981518678f8Sopenharmony_ci}
982518678f8Sopenharmony_ci
983518678f8Sopenharmony_cistatic int OnReceivedDiscover(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
984518678f8Sopenharmony_ci{
985518678f8Sopenharmony_ci    if (!received || !reply) {
986518678f8Sopenharmony_ci        DHCP_LOGE("receive or reply message pointer is null.");
987518678f8Sopenharmony_ci        return REPLY_NONE;
988518678f8Sopenharmony_ci    }
989518678f8Sopenharmony_ci    DHCP_LOGI("received 'Discover' message from:%{public}s", ParseLogMac(received->packet.chaddr));
990518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
991518678f8Sopenharmony_ci    if (!srvIns) {
992518678f8Sopenharmony_ci        DHCP_LOGE("get server instance is nullptr!");
993518678f8Sopenharmony_ci        return REPLY_NONE;
994518678f8Sopenharmony_ci    }
995518678f8Sopenharmony_ci    uint32_t reqIp = 0;
996518678f8Sopenharmony_ci    PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
997518678f8Sopenharmony_ci    if (optReqIp) {
998518678f8Sopenharmony_ci        reqIp = ParseIp(optReqIp->data);
999518678f8Sopenharmony_ci        if (reqIp) {
1000518678f8Sopenharmony_ci            DHCP_LOGI("Discover request ip:%{public}s", OHOS::DHCP::IntIpv4ToAnonymizeStr(reqIp).c_str());
1001518678f8Sopenharmony_ci        }
1002518678f8Sopenharmony_ci    }
1003518678f8Sopenharmony_ci    uint32_t srcIp = SourceIpAddress();
1004518678f8Sopenharmony_ci    if (!srvIns->broadCastFlagEnable) {
1005518678f8Sopenharmony_ci        if (srcIp) {
1006518678f8Sopenharmony_ci            DHCP_LOGI("Discover client repending:%{public}s", OHOS::DHCP::IntIpv4ToAnonymizeStr(srcIp).c_str());
1007518678f8Sopenharmony_ci        } else {
1008518678f8Sopenharmony_ci            srcIp = INADDR_BROADCAST;
1009518678f8Sopenharmony_ci        }
1010518678f8Sopenharmony_ci        DestinationAddr(srcIp);
1011518678f8Sopenharmony_ci    }
1012518678f8Sopenharmony_ci    AddressBinding *binding = GetBinding(&srvIns->addressPool, received);
1013518678f8Sopenharmony_ci    if (!binding) {
1014518678f8Sopenharmony_ci        DHCP_LOGI("Discover binding is null, reply none");
1015518678f8Sopenharmony_ci        return REPLY_NONE;
1016518678f8Sopenharmony_ci    }
1017518678f8Sopenharmony_ci    if (!binding->ipAddress) {
1018518678f8Sopenharmony_ci        DHCP_LOGI("Discover binding ipAddress is null, reply none");
1019518678f8Sopenharmony_ci        return REPLY_NONE;
1020518678f8Sopenharmony_ci    }
1021518678f8Sopenharmony_ci    if (reqIp != 0 && reqIp != binding->ipAddress) {
1022518678f8Sopenharmony_ci        DHCP_LOGW("Discover package reqIp:%{public}s, binging ip:%{public}s",
1023518678f8Sopenharmony_ci            OHOS::DHCP::IntIpv4ToAnonymizeStr(reqIp).c_str(),
1024518678f8Sopenharmony_ci            OHOS::DHCP::IntIpv4ToAnonymizeStr(binding->ipAddress).c_str());
1025518678f8Sopenharmony_ci    }
1026518678f8Sopenharmony_ci    DeleteMacInLease(&srvIns->addressPool, binding);
1027518678f8Sopenharmony_ci    return DiscoverReplyLeaseMessage(ctx, reply, srvIns, binding);
1028518678f8Sopenharmony_ci}
1029518678f8Sopenharmony_ci
1030518678f8Sopenharmony_cistatic uint32_t GetRequestIpAddress(PDhcpMsgInfo received)
1031518678f8Sopenharmony_ci{
1032518678f8Sopenharmony_ci    uint32_t reqIp = 0;
1033518678f8Sopenharmony_ci    if (!received) {
1034518678f8Sopenharmony_ci        return reqIp;
1035518678f8Sopenharmony_ci    }
1036518678f8Sopenharmony_ci    PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
1037518678f8Sopenharmony_ci    if (optReqIp) {
1038518678f8Sopenharmony_ci        reqIp = ParseIp(optReqIp->data);
1039518678f8Sopenharmony_ci    }
1040518678f8Sopenharmony_ci    return reqIp;
1041518678f8Sopenharmony_ci}
1042518678f8Sopenharmony_ci
1043518678f8Sopenharmony_cistatic int GetYourIpAddress(PDhcpMsgInfo received, uint32_t *yourIpAddr, DhcpAddressPool *pool)
1044518678f8Sopenharmony_ci{
1045518678f8Sopenharmony_ci    uint32_t cliIp = received->packet.ciaddr;
1046518678f8Sopenharmony_ci    uint32_t srcIp = SourceIpAddress();
1047518678f8Sopenharmony_ci    uint32_t reqIp = GetRequestIpAddress(received);
1048518678f8Sopenharmony_ci    DHCP_LOGI("cliIp:%{public}s srcIp:%{public}s reqIp:%{public}s",
1049518678f8Sopenharmony_ci        OHOS::DHCP::IntIpv4ToAnonymizeStr(cliIp).c_str(), OHOS::DHCP::IntIpv4ToAnonymizeStr(srcIp).c_str(),
1050518678f8Sopenharmony_ci        OHOS::DHCP::IntIpv4ToAnonymizeStr(reqIp).c_str());
1051518678f8Sopenharmony_ci    if (cliIp && srcIp && cliIp != srcIp) {
1052518678f8Sopenharmony_ci        DHCP_LOGE("error dhcp request message, missing required request option.");
1053518678f8Sopenharmony_ci        return RET_FAILED;
1054518678f8Sopenharmony_ci    }
1055518678f8Sopenharmony_ci    if (reqIp && srcIp && reqIp != srcIp) {
1056518678f8Sopenharmony_ci        DHCP_LOGE("error dhcp request message, request ip error.");
1057518678f8Sopenharmony_ci        return RET_FAILED;
1058518678f8Sopenharmony_ci    }
1059518678f8Sopenharmony_ci    if (cliIp && reqIp && cliIp != reqIp) {
1060518678f8Sopenharmony_ci        DHCP_LOGE("error dhcp request message, client ip error.");
1061518678f8Sopenharmony_ci        return RET_FAILED;
1062518678f8Sopenharmony_ci    }
1063518678f8Sopenharmony_ci
1064518678f8Sopenharmony_ci    if (srcIp && srcIp != INADDR_BROADCAST) {
1065518678f8Sopenharmony_ci        *yourIpAddr = srcIp;
1066518678f8Sopenharmony_ci    } else if (cliIp && cliIp != INADDR_BROADCAST) {
1067518678f8Sopenharmony_ci        *yourIpAddr = cliIp;
1068518678f8Sopenharmony_ci    } else if (reqIp && reqIp != INADDR_BROADCAST) {
1069518678f8Sopenharmony_ci        *yourIpAddr = reqIp;
1070518678f8Sopenharmony_ci    }
1071518678f8Sopenharmony_ci
1072518678f8Sopenharmony_ci    if ((ntohl(*yourIpAddr) < ntohl(pool->addressRange.beginAddress))
1073518678f8Sopenharmony_ci            || (ntohl(*yourIpAddr) > ntohl(pool->addressRange.endAddress))) {
1074518678f8Sopenharmony_ci        return RET_FAILED;
1075518678f8Sopenharmony_ci    }
1076518678f8Sopenharmony_ci
1077518678f8Sopenharmony_ci    if (srcIp && srcIp != INADDR_BROADCAST) {
1078518678f8Sopenharmony_ci        DestinationAddr(srcIp);
1079518678f8Sopenharmony_ci    } else if (srcIp == INADDR_ANY) {
1080518678f8Sopenharmony_ci        DestinationAddr(INADDR_BROADCAST);
1081518678f8Sopenharmony_ci    }
1082518678f8Sopenharmony_ci    return RET_SUCCESS;
1083518678f8Sopenharmony_ci}
1084518678f8Sopenharmony_ci
1085518678f8Sopenharmony_cistatic int NotBindingRequest(DhcpAddressPool *pool, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1086518678f8Sopenharmony_ci{
1087518678f8Sopenharmony_ci    uint32_t yourIpAddr = 0;
1088518678f8Sopenharmony_ci    if (GetYourIpAddress(received, &yourIpAddr, pool) != RET_SUCCESS) {
1089518678f8Sopenharmony_ci        DHCP_LOGI("GetYourIpAddress REPLY_NONE");
1090518678f8Sopenharmony_ci        return REPLY_NONE;
1091518678f8Sopenharmony_ci    }
1092518678f8Sopenharmony_ci    AddressBinding *lease = GetLease(pool, yourIpAddr);
1093518678f8Sopenharmony_ci    if (!lease) {
1094518678f8Sopenharmony_ci        if (SourceIpAddress()) {
1095518678f8Sopenharmony_ci            DHCP_LOGI("SourceIpAddress True REPLY_ACK");
1096518678f8Sopenharmony_ci            return REPLY_ACK;
1097518678f8Sopenharmony_ci        }
1098518678f8Sopenharmony_ci        DHCP_LOGI("SourceIpAddress REPLY_NAK");
1099518678f8Sopenharmony_ci        return REPLY_NAK;
1100518678f8Sopenharmony_ci    }
1101518678f8Sopenharmony_ci    int sameAddr = AddrEquels(lease->chaddr, received->packet.chaddr, MAC_ADDR_LENGTH);
1102518678f8Sopenharmony_ci    if (lease->bindingStatus == BIND_ASSOCIATED && !sameAddr) {
1103518678f8Sopenharmony_ci        if (!IsExpire(lease)) {
1104518678f8Sopenharmony_ci            DHCP_LOGI("Not IsExpire REPLY_NAK");
1105518678f8Sopenharmony_ci            return REPLY_NAK;
1106518678f8Sopenharmony_ci        }
1107518678f8Sopenharmony_ci        DHCP_LOGI("RemoveLease lease");
1108518678f8Sopenharmony_ci        RemoveLease(pool, lease);
1109518678f8Sopenharmony_ci    }
1110518678f8Sopenharmony_ci    AddressBinding *binding = pool->newBinding(received->packet.chaddr, &received->options);
1111518678f8Sopenharmony_ci    if (binding == nullptr) {
1112518678f8Sopenharmony_ci        DHCP_LOGE("Not binding request binding is null.");
1113518678f8Sopenharmony_ci        return REPLY_NONE;
1114518678f8Sopenharmony_ci    }
1115518678f8Sopenharmony_ci    binding->ipAddress = yourIpAddr;
1116518678f8Sopenharmony_ci    if (pool->leaseTime) {
1117518678f8Sopenharmony_ci        binding->leaseTime = pool->leaseTime;
1118518678f8Sopenharmony_ci    }
1119518678f8Sopenharmony_ci    int replyType = Repending(pool, binding);
1120518678f8Sopenharmony_ci    if (replyType != REPLY_OFFER) {
1121518678f8Sopenharmony_ci        DHCP_LOGI("replyType != REPLY_OFFER");
1122518678f8Sopenharmony_ci        return replyType;
1123518678f8Sopenharmony_ci    }
1124518678f8Sopenharmony_ci    lease = GetLease(pool, yourIpAddr);
1125518678f8Sopenharmony_ci    if (!lease) {
1126518678f8Sopenharmony_ci        DHCP_LOGI("add new lease recoder.");
1127518678f8Sopenharmony_ci        AddLease(pool, binding);
1128518678f8Sopenharmony_ci        lease = GetLease(pool, binding->ipAddress);
1129518678f8Sopenharmony_ci    }
1130518678f8Sopenharmony_ci    if (!lease) {
1131518678f8Sopenharmony_ci        DHCP_LOGI("failed to get lease.");
1132518678f8Sopenharmony_ci        return REPLY_NONE;
1133518678f8Sopenharmony_ci    }
1134518678f8Sopenharmony_ci    lease->bindingStatus = BIND_ASSOCIATED;
1135518678f8Sopenharmony_ci    lease->bindingTime = Tmspsec();
1136518678f8Sopenharmony_ci    lease->expireIn = lease->bindingTime + binding->leaseTime;
1137518678f8Sopenharmony_ci    reply->packet.yiaddr = lease->ipAddress;
1138518678f8Sopenharmony_ci    DHCP_LOGI("NotBindingRequest REPLY_ACK");
1139518678f8Sopenharmony_ci    return REPLY_ACK;
1140518678f8Sopenharmony_ci}
1141518678f8Sopenharmony_ci
1142518678f8Sopenharmony_cistatic int ValidateRequestMessage(const PDhcpServerContext ctx, const PDhcpMsgInfo received,
1143518678f8Sopenharmony_ci    PDhcpMsgInfo reply, uint32_t *yourIp)
1144518678f8Sopenharmony_ci{
1145518678f8Sopenharmony_ci    if (!received || !reply) {
1146518678f8Sopenharmony_ci        DHCP_LOGE("receive or reply message pointer is null.");
1147518678f8Sopenharmony_ci        return REPLY_NONE;
1148518678f8Sopenharmony_ci    }
1149518678f8Sopenharmony_ci    DHCP_LOGI("received 'Request' message from:%{public}s", ParseLogMac(received->packet.chaddr));
1150518678f8Sopenharmony_ci    uint32_t yourIpAddr = INADDR_BROADCAST;
1151518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1152518678f8Sopenharmony_ci    if (!srvIns) {
1153518678f8Sopenharmony_ci        DHCP_LOGI("get server instance failed!");
1154518678f8Sopenharmony_ci        return RET_FAILED;
1155518678f8Sopenharmony_ci    }
1156518678f8Sopenharmony_ci    if (GetYourIpAddress(received, &yourIpAddr, &srvIns->addressPool) != RET_SUCCESS) {
1157518678f8Sopenharmony_ci        if (yourIpAddr && yourIpAddr != INADDR_BROADCAST) {
1158518678f8Sopenharmony_ci            AddressBinding *lease = GetLease(&srvIns->addressPool, yourIpAddr);
1159518678f8Sopenharmony_ci            if (lease) {
1160518678f8Sopenharmony_ci                RemoveLease(&srvIns->addressPool, lease);
1161518678f8Sopenharmony_ci                DHCP_LOGD("lease recoder has been removed.");
1162518678f8Sopenharmony_ci            } else {
1163518678f8Sopenharmony_ci                DHCP_LOGW("can't found lease recoder.");
1164518678f8Sopenharmony_ci            }
1165518678f8Sopenharmony_ci            RemoveBinding(received->packet.chaddr);
1166518678f8Sopenharmony_ci            return REPLY_NAK;
1167518678f8Sopenharmony_ci        }
1168518678f8Sopenharmony_ci        return REPLY_NONE;
1169518678f8Sopenharmony_ci    }
1170518678f8Sopenharmony_ci    PDhcpOption optReqSrvId = GetOption(&received->options, SERVER_IDENTIFIER_OPTION);
1171518678f8Sopenharmony_ci    if (optReqSrvId) {
1172518678f8Sopenharmony_ci        uint32_t reqSrvId = ParseIp(optReqSrvId->data);
1173518678f8Sopenharmony_ci        DHCP_LOGD(" reuquest server id is:%s", ParseStrIp(reqSrvId));
1174518678f8Sopenharmony_ci        if (reqSrvId != srvIns->addressPool.serverId) {
1175518678f8Sopenharmony_ci            DHCP_LOGW("other dhcp server process.");
1176518678f8Sopenharmony_ci            return REPLY_NONE;
1177518678f8Sopenharmony_ci        }
1178518678f8Sopenharmony_ci    } else {
1179518678f8Sopenharmony_ci        DHCP_LOGW("request message not specified server identifier option.");
1180518678f8Sopenharmony_ci    }
1181518678f8Sopenharmony_ci    *yourIp = yourIpAddr;
1182518678f8Sopenharmony_ci    return REPLY_ACK;
1183518678f8Sopenharmony_ci}
1184518678f8Sopenharmony_ci
1185518678f8Sopenharmony_cistatic int HasNobindgRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1186518678f8Sopenharmony_ci{
1187518678f8Sopenharmony_ci    if (!received || !reply) {
1188518678f8Sopenharmony_ci        DHCP_LOGE("receive or reply message pointer is null.");
1189518678f8Sopenharmony_ci        return REPLY_NONE;
1190518678f8Sopenharmony_ci    }
1191518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1192518678f8Sopenharmony_ci    if (!srvIns) {
1193518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
1194518678f8Sopenharmony_ci        return REPLY_NONE;
1195518678f8Sopenharmony_ci    }
1196518678f8Sopenharmony_ci    AddressBinding *binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1197518678f8Sopenharmony_ci    if (!binding && ALLOW_NOBINDING_REQUEST) {
1198518678f8Sopenharmony_ci        uint32_t srcIp = SourceIpAddress();
1199518678f8Sopenharmony_ci        uint32_t reqIp = GetRequestIpAddress(received);
1200518678f8Sopenharmony_ci        DHCP_LOGD("allow no binding request mode.");
1201518678f8Sopenharmony_ci        if (reqIp == 0 && srcIp == 0) {
1202518678f8Sopenharmony_ci            DHCP_LOGE("error dhcp message.");
1203518678f8Sopenharmony_ci            return REPLY_NONE;
1204518678f8Sopenharmony_ci        }
1205518678f8Sopenharmony_ci        if (!IpInNetwork(reqIp, srvIns->addressPool.serverId, srvIns->addressPool.netmask)) {
1206518678f8Sopenharmony_ci            DHCP_LOGE("error request ip.");
1207518678f8Sopenharmony_ci            return REPLY_NAK;
1208518678f8Sopenharmony_ci        }
1209518678f8Sopenharmony_ci        return NotBindingRequest(&srvIns->addressPool, received, reply);
1210518678f8Sopenharmony_ci    }
1211518678f8Sopenharmony_ci    return REPLY_NONE;
1212518678f8Sopenharmony_ci}
1213518678f8Sopenharmony_ci
1214518678f8Sopenharmony_ciint GetVendorIdentifierOption(PDhcpMsgInfo received)
1215518678f8Sopenharmony_ci{
1216518678f8Sopenharmony_ci    PDhcpOption optVendorIdentifier = GetOption(&received->options, VENDOR_CLASS_IDENTIFIER_OPTION);
1217518678f8Sopenharmony_ci    if (optVendorIdentifier) {
1218518678f8Sopenharmony_ci        char strVendorIdentifier[DEVICE_NAME_STRING_LENGTH] = {0};
1219518678f8Sopenharmony_ci        if (memcpy_s(strVendorIdentifier, DEVICE_NAME_STRING_LENGTH, (char*)optVendorIdentifier->data,
1220518678f8Sopenharmony_ci            optVendorIdentifier->length) != EOK) {
1221518678f8Sopenharmony_ci            DHCP_LOGE("GetVendorIdentifierOption strClientIdentifier memcpy_s failed!");
1222518678f8Sopenharmony_ci            return REPLY_NONE;
1223518678f8Sopenharmony_ci        }
1224518678f8Sopenharmony_ci        DHCP_LOGD("GetVendorIdentifierOption strClientIdentifier:%{public}s", strVendorIdentifier);
1225518678f8Sopenharmony_ci    } else {
1226518678f8Sopenharmony_ci        DHCP_LOGD("GetVendorIdentifierOption pClientIdentifier is null");
1227518678f8Sopenharmony_ci    }
1228518678f8Sopenharmony_ci    return REPLY_NAK;
1229518678f8Sopenharmony_ci}
1230518678f8Sopenharmony_ci
1231518678f8Sopenharmony_ciint GetHostNameOption(PDhcpMsgInfo received, AddressBinding *bindin)
1232518678f8Sopenharmony_ci{
1233518678f8Sopenharmony_ci    if (!bindin) {
1234518678f8Sopenharmony_ci        DHCP_LOGE("GetHostNameOption bindin is nullptr!");
1235518678f8Sopenharmony_ci        return REPLY_NONE;
1236518678f8Sopenharmony_ci    }
1237518678f8Sopenharmony_ci    PDhcpOption optHostName = GetOption(&received->options, HOST_NAME_OPTION);
1238518678f8Sopenharmony_ci    if (optHostName) {
1239518678f8Sopenharmony_ci        if (memcpy_s(bindin->deviceName, DEVICE_NAME_STRING_LENGTH, (char*)optHostName->data,
1240518678f8Sopenharmony_ci            optHostName->length) != EOK) {
1241518678f8Sopenharmony_ci            DHCP_LOGE("GetHostNameOption pHost memcpy_s failed!");
1242518678f8Sopenharmony_ci            return REPLY_NONE;
1243518678f8Sopenharmony_ci        }
1244518678f8Sopenharmony_ci        DHCP_LOGI("GetHostNameOption deviceName:%{public}s", bindin->deviceName);
1245518678f8Sopenharmony_ci    } else {
1246518678f8Sopenharmony_ci        DHCP_LOGD("GetHostNameOption pHost is null");
1247518678f8Sopenharmony_ci    }
1248518678f8Sopenharmony_ci    return REPLY_NAK;
1249518678f8Sopenharmony_ci}
1250518678f8Sopenharmony_ci
1251518678f8Sopenharmony_ciint GetUserClassOption(PDhcpMsgInfo received, AddressBinding *bindin)
1252518678f8Sopenharmony_ci{
1253518678f8Sopenharmony_ci    if (!bindin) {
1254518678f8Sopenharmony_ci        DHCP_LOGE("GetUserClassOption bindin is nullptr!");
1255518678f8Sopenharmony_ci        return REPLY_NONE;
1256518678f8Sopenharmony_ci    }
1257518678f8Sopenharmony_ci    PDhcpOption option = GetOption(&received->options, USER_CLASS_OPTION);
1258518678f8Sopenharmony_ci    if (option) {
1259518678f8Sopenharmony_ci        if (memcpy_s(bindin->userClass, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1260518678f8Sopenharmony_ci            DHCP_LOGE("GetUserClassOption memcpy_s failed!");
1261518678f8Sopenharmony_ci            return REPLY_NONE;
1262518678f8Sopenharmony_ci        }
1263518678f8Sopenharmony_ci        DHCP_LOGD("GetUserClassOption userClass:%{public}s", bindin->userClass);
1264518678f8Sopenharmony_ci    } else {
1265518678f8Sopenharmony_ci        DHCP_LOGD("GetUserClassOption pHost is null");
1266518678f8Sopenharmony_ci    }
1267518678f8Sopenharmony_ci    return REPLY_ACK;
1268518678f8Sopenharmony_ci}
1269518678f8Sopenharmony_ci
1270518678f8Sopenharmony_ciint GetRapidCommitOption(PDhcpMsgInfo received, AddressBinding *bindin)
1271518678f8Sopenharmony_ci{
1272518678f8Sopenharmony_ci    if (!bindin) {
1273518678f8Sopenharmony_ci        DHCP_LOGE("GetRapidCommitOption bindin is nullptr!");
1274518678f8Sopenharmony_ci        return REPLY_NONE;
1275518678f8Sopenharmony_ci    }
1276518678f8Sopenharmony_ci    PDhcpOption option = GetOption(&received->options, RAPID_COMMIT_OPTION);
1277518678f8Sopenharmony_ci    if (option) {
1278518678f8Sopenharmony_ci        char value[DEVICE_NAME_STRING_LENGTH] = {0};
1279518678f8Sopenharmony_ci        if (memcpy_s(value, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1280518678f8Sopenharmony_ci            DHCP_LOGE("GetRapidCommitOption memcpy_s failed!");
1281518678f8Sopenharmony_ci            return REPLY_NONE;
1282518678f8Sopenharmony_ci        }
1283518678f8Sopenharmony_ci        DHCP_LOGD("GetRapidCommitOption value:%{public}s", value);
1284518678f8Sopenharmony_ci    } else {
1285518678f8Sopenharmony_ci        DHCP_LOGD("GetRapidCommitOption pHost is null");
1286518678f8Sopenharmony_ci    }
1287518678f8Sopenharmony_ci    return REPLY_ACK;
1288518678f8Sopenharmony_ci}
1289518678f8Sopenharmony_ci
1290518678f8Sopenharmony_ciint GetOnlyIpv6Option(PDhcpMsgInfo received, AddressBinding *bindin)
1291518678f8Sopenharmony_ci{
1292518678f8Sopenharmony_ci    if (!bindin) {
1293518678f8Sopenharmony_ci        DHCP_LOGE("GetOnlyIpv6Option bindin is nullptr!");
1294518678f8Sopenharmony_ci        return REPLY_NONE;
1295518678f8Sopenharmony_ci    }
1296518678f8Sopenharmony_ci    PDhcpOption option = GetOption(&received->options, IPV6_ONLY_PREFERRED_OPTION);
1297518678f8Sopenharmony_ci    if (option) {
1298518678f8Sopenharmony_ci        char value[DEVICE_NAME_STRING_LENGTH] = {0};
1299518678f8Sopenharmony_ci        if (memcpy_s(value, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1300518678f8Sopenharmony_ci            DHCP_LOGE("GetOnlyIpv6Option memcpy_s failed!");
1301518678f8Sopenharmony_ci            return REPLY_NONE;
1302518678f8Sopenharmony_ci        }
1303518678f8Sopenharmony_ci        DHCP_LOGD("GetOnlyIpv6Option value:%{public}s", value);
1304518678f8Sopenharmony_ci    } else {
1305518678f8Sopenharmony_ci        DHCP_LOGD("GetOnlyIpv6Option pHost is null");
1306518678f8Sopenharmony_ci    }
1307518678f8Sopenharmony_ci    return REPLY_ACK;
1308518678f8Sopenharmony_ci}
1309518678f8Sopenharmony_ci
1310518678f8Sopenharmony_ciint GetPortalUrlOption(PDhcpMsgInfo received, AddressBinding *bindin)
1311518678f8Sopenharmony_ci{
1312518678f8Sopenharmony_ci    if (!bindin) {
1313518678f8Sopenharmony_ci        DHCP_LOGE("GetPortalUrlOption bindin is nullptr!");
1314518678f8Sopenharmony_ci        return REPLY_NONE;
1315518678f8Sopenharmony_ci    }
1316518678f8Sopenharmony_ci    PDhcpOption option = GetOption(&received->options, IPV6_ONLY_PREFERRED_OPTION);
1317518678f8Sopenharmony_ci    if (option) {
1318518678f8Sopenharmony_ci        char value[DEVICE_NAME_STRING_LENGTH] = {0};
1319518678f8Sopenharmony_ci        if (memcpy_s(value, DEVICE_NAME_STRING_LENGTH, (char*)option->data, option->length) != EOK) {
1320518678f8Sopenharmony_ci            DHCP_LOGE("GetPortalUrlOption memcpy_s failed!");
1321518678f8Sopenharmony_ci            return REPLY_NONE;
1322518678f8Sopenharmony_ci        }
1323518678f8Sopenharmony_ci        DHCP_LOGD("GetPortalUrlOption value:%{public}s", value);
1324518678f8Sopenharmony_ci    } else {
1325518678f8Sopenharmony_ci        DHCP_LOGD("GetPortalUrlOption pHost is null");
1326518678f8Sopenharmony_ci    }
1327518678f8Sopenharmony_ci    return REPLY_ACK;
1328518678f8Sopenharmony_ci}
1329518678f8Sopenharmony_ci
1330518678f8Sopenharmony_ciint ParseDhcpOption(PDhcpMsgInfo received, AddressBinding *bindin)
1331518678f8Sopenharmony_ci{
1332518678f8Sopenharmony_ci    if (!bindin) {
1333518678f8Sopenharmony_ci        DHCP_LOGE("ParseDhcpOption bindin is nullptr!");
1334518678f8Sopenharmony_ci        return REPLY_NONE;
1335518678f8Sopenharmony_ci    }
1336518678f8Sopenharmony_ci    DHCP_LOGE("enter ParseDhcpOption");
1337518678f8Sopenharmony_ci    GetHostNameOption(received, bindin);
1338518678f8Sopenharmony_ci    GetVendorIdentifierOption(received);
1339518678f8Sopenharmony_ci    GetUserClassOption(received, bindin);
1340518678f8Sopenharmony_ci    GetRapidCommitOption(received, bindin);
1341518678f8Sopenharmony_ci    GetOnlyIpv6Option(received, bindin);
1342518678f8Sopenharmony_ci    GetPortalUrlOption(received, bindin);
1343518678f8Sopenharmony_ci    return REPLY_ACK;
1344518678f8Sopenharmony_ci}
1345518678f8Sopenharmony_ci
1346518678f8Sopenharmony_cistatic int OnReceivedRequest(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1347518678f8Sopenharmony_ci{
1348518678f8Sopenharmony_ci    int ret;
1349518678f8Sopenharmony_ci    uint32_t yourIpAddr;
1350518678f8Sopenharmony_ci    if ((ret = ValidateRequestMessage(ctx, received, reply, &yourIpAddr)) != REPLY_ACK) {
1351518678f8Sopenharmony_ci        DHCP_LOGE("Request validateRequestMessage ret:%{public}d", ret);
1352518678f8Sopenharmony_ci        return ret;
1353518678f8Sopenharmony_ci    }
1354518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1355518678f8Sopenharmony_ci    if (srvIns == nullptr) {
1356518678f8Sopenharmony_ci        DHCP_LOGE("OnReceivedRequest, srvIns is null");
1357518678f8Sopenharmony_ci        return REPLY_NONE;
1358518678f8Sopenharmony_ci    }
1359518678f8Sopenharmony_ci    AddressBinding *binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1360518678f8Sopenharmony_ci    if (binding == nullptr) {
1361518678f8Sopenharmony_ci        DHCP_LOGI("Request enter HasNobindgRequest!");
1362518678f8Sopenharmony_ci        return HasNobindgRequest(ctx, received, reply);
1363518678f8Sopenharmony_ci    }
1364518678f8Sopenharmony_ci    Rebinding(&srvIns->addressPool, binding);
1365518678f8Sopenharmony_ci    AddressBinding *lease = GetLease(&srvIns->addressPool, yourIpAddr);
1366518678f8Sopenharmony_ci    if (lease) {
1367518678f8Sopenharmony_ci        ParseDhcpOption(received, lease);
1368518678f8Sopenharmony_ci        DHCP_LOGI("request in lease, yourIpAddr:%{public}s, mac:%{public}s",
1369518678f8Sopenharmony_ci            OHOS::DHCP::IntIpv4ToAnonymizeStr(yourIpAddr).c_str(), ParseLogMac(lease->chaddr));
1370518678f8Sopenharmony_ci        int sameAddr = AddrEquels(lease->chaddr, received->packet.chaddr, MAC_ADDR_LENGTH);
1371518678f8Sopenharmony_ci        if (!sameAddr && !IsExpire(lease)) {
1372518678f8Sopenharmony_ci            DHCP_LOGW("invalid request ip address, reply nak, sameAddr:%{public}d", sameAddr);
1373518678f8Sopenharmony_ci            return REPLY_NAK;
1374518678f8Sopenharmony_ci        }
1375518678f8Sopenharmony_ci        if (!sameAddr && IsExpire(lease)) {
1376518678f8Sopenharmony_ci            if (memcpy_s(lease->chaddr, DHCP_HWADDR_LENGTH, binding->chaddr, MAC_ADDR_LENGTH) != EOK) {
1377518678f8Sopenharmony_ci                DHCP_LOGW("failed to update lease client address, sameAddr:%{public}d", sameAddr);
1378518678f8Sopenharmony_ci            }
1379518678f8Sopenharmony_ci        }
1380518678f8Sopenharmony_ci        lease->bindingStatus = BIND_ASSOCIATED;
1381518678f8Sopenharmony_ci        lease->bindingTime = binding->bindingTime;
1382518678f8Sopenharmony_ci        lease->expireIn = binding->expireIn;
1383518678f8Sopenharmony_ci        DHCP_LOGI("Request found lease recoder, sameAddr:%{public}d", sameAddr);
1384518678f8Sopenharmony_ci    } else {
1385518678f8Sopenharmony_ci        DHCP_LOGW("Request can not found lease recoder.");
1386518678f8Sopenharmony_ci    }
1387518678f8Sopenharmony_ci    uint32_t bindingIp = binding->ipAddress;
1388518678f8Sopenharmony_ci    if (bindingIp && yourIpAddr != INADDR_BROADCAST && yourIpAddr != bindingIp) {
1389518678f8Sopenharmony_ci        DHCP_LOGE("error request ip binding. reply nak");
1390518678f8Sopenharmony_ci        return REPLY_NAK;
1391518678f8Sopenharmony_ci    }
1392518678f8Sopenharmony_ci    reply->packet.yiaddr = bindingIp;
1393518678f8Sopenharmony_ci    ReplyCommontOption(ctx, reply);
1394518678f8Sopenharmony_ci    DHCP_LOGI("Request reply ack!");
1395518678f8Sopenharmony_ci    return REPLY_ACK;
1396518678f8Sopenharmony_ci}
1397518678f8Sopenharmony_ci
1398518678f8Sopenharmony_cistatic int OnReceivedDecline(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1399518678f8Sopenharmony_ci{
1400518678f8Sopenharmony_ci    if (!received || !reply) {
1401518678f8Sopenharmony_ci        return REPLY_NONE;
1402518678f8Sopenharmony_ci    }
1403518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1404518678f8Sopenharmony_ci    if (!srvIns) {
1405518678f8Sopenharmony_ci        return REPLY_NONE;
1406518678f8Sopenharmony_ci    }
1407518678f8Sopenharmony_ci    DHCP_LOGI("received 'Decline' message from: %s.", ParseLogMac(received->packet.chaddr));
1408518678f8Sopenharmony_ci    uint32_t reqIp = 0;
1409518678f8Sopenharmony_ci    PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
1410518678f8Sopenharmony_ci    if (optReqIp) {
1411518678f8Sopenharmony_ci        reqIp = ParseIp(optReqIp->data);
1412518678f8Sopenharmony_ci    }
1413518678f8Sopenharmony_ci    if (!reqIp) {
1414518678f8Sopenharmony_ci        DHCP_LOGD("invalid request ip address.");
1415518678f8Sopenharmony_ci        return REPLY_NONE;
1416518678f8Sopenharmony_ci    }
1417518678f8Sopenharmony_ci    AddressBinding* binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1418518678f8Sopenharmony_ci    if (!binding) {
1419518678f8Sopenharmony_ci        DHCP_LOGD("client not binding.");
1420518678f8Sopenharmony_ci        return REPLY_NONE;
1421518678f8Sopenharmony_ci    }
1422518678f8Sopenharmony_ci    if (binding->ipAddress != reqIp) {
1423518678f8Sopenharmony_ci        DHCP_LOGD("invalid request ip address.");
1424518678f8Sopenharmony_ci        return REPLY_NONE;
1425518678f8Sopenharmony_ci    }
1426518678f8Sopenharmony_ci    if (srvIns->addressPool.leaseTable.count(reqIp) > 0) {
1427518678f8Sopenharmony_ci        AddressBinding *lease = &srvIns->addressPool.leaseTable[reqIp];
1428518678f8Sopenharmony_ci        if (lease) {
1429518678f8Sopenharmony_ci            lease->bindingStatus = BIND_MODE_RESERVED;
1430518678f8Sopenharmony_ci            lease->expireIn = Tmspsec() + lease->leaseTime;
1431518678f8Sopenharmony_ci        } else {
1432518678f8Sopenharmony_ci            DHCP_LOGE("failed to get lease info.");
1433518678f8Sopenharmony_ci        }
1434518678f8Sopenharmony_ci    }
1435518678f8Sopenharmony_ci    RemoveBinding(received->packet.chaddr);
1436518678f8Sopenharmony_ci    return REPLY_NONE;
1437518678f8Sopenharmony_ci}
1438518678f8Sopenharmony_ci
1439518678f8Sopenharmony_cistatic int OnReceivedRelease(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1440518678f8Sopenharmony_ci{
1441518678f8Sopenharmony_ci    if (!received || !reply) {
1442518678f8Sopenharmony_ci        return REPLY_NONE;
1443518678f8Sopenharmony_ci    }
1444518678f8Sopenharmony_ci    DHCP_LOGI("received 'Release' message from: %s", ParseLogMac(received->packet.chaddr));
1445518678f8Sopenharmony_ci    if (!ctx || !ctx->instance) {
1446518678f8Sopenharmony_ci        return RET_FAILED;
1447518678f8Sopenharmony_ci    }
1448518678f8Sopenharmony_ci    PDhcpOption optReqIp = GetOption(&received->options, REQUESTED_IP_ADDRESS_OPTION);
1449518678f8Sopenharmony_ci    if (!optReqIp) {
1450518678f8Sopenharmony_ci        DHCP_LOGW("missing required request option.");
1451518678f8Sopenharmony_ci    }
1452518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1453518678f8Sopenharmony_ci    if (!srvIns) {
1454518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
1455518678f8Sopenharmony_ci        return RET_FAILED;
1456518678f8Sopenharmony_ci    }
1457518678f8Sopenharmony_ci    AddressBinding *binding = srvIns->addressPool.binding(received->packet.chaddr, &received->options);
1458518678f8Sopenharmony_ci    if (!binding) {
1459518678f8Sopenharmony_ci        DHCP_LOGD("client not binding.");
1460518678f8Sopenharmony_ci        return REPLY_NONE;
1461518678f8Sopenharmony_ci    }
1462518678f8Sopenharmony_ci    uint32_t bindIp = binding->ipAddress;
1463518678f8Sopenharmony_ci    uint32_t reqIp = 0;
1464518678f8Sopenharmony_ci    if (optReqIp) {
1465518678f8Sopenharmony_ci        reqIp = ParseIp(optReqIp->data);
1466518678f8Sopenharmony_ci    }
1467518678f8Sopenharmony_ci    uint32_t srcIp = SourceIpAddress();
1468518678f8Sopenharmony_ci    if (srcIp != 0 && reqIp != 0 && reqIp != srcIp) {
1469518678f8Sopenharmony_ci        DHCP_LOGE("error release message, invalid request ip address.");
1470518678f8Sopenharmony_ci        return REPLY_NONE;
1471518678f8Sopenharmony_ci    }
1472518678f8Sopenharmony_ci    if (bindIp != 0 && reqIp != 0 && reqIp != bindIp) {
1473518678f8Sopenharmony_ci        DHCP_LOGE("error release message, invalid request ip address.");
1474518678f8Sopenharmony_ci        return REPLY_NONE;
1475518678f8Sopenharmony_ci    }
1476518678f8Sopenharmony_ci    AddressBinding *lease = GetLease(&srvIns->addressPool, bindIp);
1477518678f8Sopenharmony_ci    if (lease) {
1478518678f8Sopenharmony_ci        RemoveLease(&srvIns->addressPool, lease);
1479518678f8Sopenharmony_ci        DHCP_LOGD("lease recoder has been removed.");
1480518678f8Sopenharmony_ci    } else {
1481518678f8Sopenharmony_ci        DHCP_LOGW("can't found lease recoder.");
1482518678f8Sopenharmony_ci    }
1483518678f8Sopenharmony_ci
1484518678f8Sopenharmony_ci    if (ReleaseBinding(received->packet.chaddr) != RET_SUCCESS) {
1485518678f8Sopenharmony_ci        DHCP_LOGW("failed to release client[%s] bind.", ParseLogMac(received->packet.chaddr));
1486518678f8Sopenharmony_ci    }
1487518678f8Sopenharmony_ci    DHCP_LOGD("client released.");
1488518678f8Sopenharmony_ci    return REPLY_NONE;
1489518678f8Sopenharmony_ci}
1490518678f8Sopenharmony_ci
1491518678f8Sopenharmony_cistatic int OnReceivedInform(PDhcpServerContext ctx, PDhcpMsgInfo received, PDhcpMsgInfo reply)
1492518678f8Sopenharmony_ci{
1493518678f8Sopenharmony_ci    if (!received || !reply) {
1494518678f8Sopenharmony_ci        return REPLY_NONE;
1495518678f8Sopenharmony_ci    }
1496518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1497518678f8Sopenharmony_ci    if (!srvIns) {
1498518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
1499518678f8Sopenharmony_ci        return RET_FAILED;
1500518678f8Sopenharmony_ci    }
1501518678f8Sopenharmony_ci    DHCP_LOGI("received 'Inform' message from: %s", ParseLogMac(received->packet.chaddr));
1502518678f8Sopenharmony_ci    if (IsEmptyHWAddr(received->packet.chaddr)) {
1503518678f8Sopenharmony_ci        DHCP_LOGD("error dhcp 'Inform' message.");
1504518678f8Sopenharmony_ci    }
1505518678f8Sopenharmony_ci    return REPLY_ACK;
1506518678f8Sopenharmony_ci}
1507518678f8Sopenharmony_ci
1508518678f8Sopenharmony_cistatic int AppendFixedOptions(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1509518678f8Sopenharmony_ci{
1510518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1511518678f8Sopenharmony_ci    if (!srvIns) {
1512518678f8Sopenharmony_ci        return RET_FAILED;
1513518678f8Sopenharmony_ci    }
1514518678f8Sopenharmony_ci    if (!reply) {
1515518678f8Sopenharmony_ci        return RET_FAILED;
1516518678f8Sopenharmony_ci    }
1517518678f8Sopenharmony_ci    if (srvIns->addressPool.fixedOptions.size > 0) {
1518518678f8Sopenharmony_ci        DhcpOptionNode *pNode = srvIns->addressPool.fixedOptions.first->next;
1519518678f8Sopenharmony_ci        for (size_t i = 0; pNode != nullptr && i < srvIns->addressPool.fixedOptions.size; i++) {
1520518678f8Sopenharmony_ci            PDhcpOption opt = nullptr;
1521518678f8Sopenharmony_ci            if (pNode->option.code) {
1522518678f8Sopenharmony_ci                opt = GetOption(&reply->options, pNode->option.code);
1523518678f8Sopenharmony_ci            }
1524518678f8Sopenharmony_ci            if (opt == nullptr) {
1525518678f8Sopenharmony_ci                PushBackOption(&reply->options, &pNode->option);
1526518678f8Sopenharmony_ci            }
1527518678f8Sopenharmony_ci            pNode = pNode->next;
1528518678f8Sopenharmony_ci        }
1529518678f8Sopenharmony_ci    }
1530518678f8Sopenharmony_ci    return RET_SUCCESS;
1531518678f8Sopenharmony_ci}
1532518678f8Sopenharmony_ciint AppendReplyTypeOption(PDhcpMsgInfo reply, int replyType)
1533518678f8Sopenharmony_ci{
1534518678f8Sopenharmony_ci    if (!reply) {
1535518678f8Sopenharmony_ci        return RET_FAILED;
1536518678f8Sopenharmony_ci    }
1537518678f8Sopenharmony_ci    if (!replyType) {
1538518678f8Sopenharmony_ci        return RET_FAILED;
1539518678f8Sopenharmony_ci    }
1540518678f8Sopenharmony_ci    uint8_t msgType = 0;
1541518678f8Sopenharmony_ci    switch (replyType) {
1542518678f8Sopenharmony_ci        case REPLY_OFFER:
1543518678f8Sopenharmony_ci            msgType = DHCPOFFER;
1544518678f8Sopenharmony_ci            break;
1545518678f8Sopenharmony_ci        case REPLY_ACK:
1546518678f8Sopenharmony_ci            msgType = DHCPACK;
1547518678f8Sopenharmony_ci            break;
1548518678f8Sopenharmony_ci        case REPLY_NAK:
1549518678f8Sopenharmony_ci            msgType = DHCPNAK;
1550518678f8Sopenharmony_ci            break;
1551518678f8Sopenharmony_ci        default:
1552518678f8Sopenharmony_ci            break;
1553518678f8Sopenharmony_ci    }
1554518678f8Sopenharmony_ci    PDhcpOption pOptMsgType = GetOption(&reply->options, DHCP_MESSAGE_TYPE_OPTION);
1555518678f8Sopenharmony_ci    if (!pOptMsgType) {
1556518678f8Sopenharmony_ci        DHCP_LOGD("append message type option for reply message, type:%hhu", msgType);
1557518678f8Sopenharmony_ci        DhcpOption optMsgType = {DHCP_MESSAGE_TYPE_OPTION, OPT_MESSAGE_TYPE_LEGTH, {msgType, 0}};
1558518678f8Sopenharmony_ci        PushFrontOption(&reply->options, &optMsgType);
1559518678f8Sopenharmony_ci    } else {
1560518678f8Sopenharmony_ci        if (pOptMsgType->data[0] != msgType) {
1561518678f8Sopenharmony_ci            DHCP_LOGD("error dhcp nak message type.");
1562518678f8Sopenharmony_ci            return RET_FAILED;
1563518678f8Sopenharmony_ci        }
1564518678f8Sopenharmony_ci    }
1565518678f8Sopenharmony_ci    return RET_SUCCESS;
1566518678f8Sopenharmony_ci}
1567518678f8Sopenharmony_ci
1568518678f8Sopenharmony_cistatic int SendDhcpOffer(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1569518678f8Sopenharmony_ci{
1570518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1571518678f8Sopenharmony_ci    if (!srvIns) {
1572518678f8Sopenharmony_ci        DHCP_LOGE("failed to get server instance");
1573518678f8Sopenharmony_ci        return RET_FAILED;
1574518678f8Sopenharmony_ci    }
1575518678f8Sopenharmony_ci    if (AppendReplyTypeOption(reply, REPLY_OFFER) != RET_SUCCESS) {
1576518678f8Sopenharmony_ci        DHCP_LOGE("failed to append reply type options");
1577518678f8Sopenharmony_ci        return RET_FAILED;
1578518678f8Sopenharmony_ci    }
1579518678f8Sopenharmony_ci    if (AppendReplyTimeOptions(ctx, &reply->options) != RET_SUCCESS ||
1580518678f8Sopenharmony_ci        AddReplyServerIdOption(&reply->options, srvIns->addressPool.serverId) != RET_SUCCESS) {
1581518678f8Sopenharmony_ci        DHCP_LOGE("failed to append reply time options");
1582518678f8Sopenharmony_ci        return RET_FAILED;
1583518678f8Sopenharmony_ci    }
1584518678f8Sopenharmony_ci    if (AppendFixedOptions(ctx, reply) != RET_SUCCESS) {
1585518678f8Sopenharmony_ci        DHCP_LOGW("failed to append fixed reply options.");
1586518678f8Sopenharmony_ci    }
1587518678f8Sopenharmony_ci    if (ParseReplyOptions(reply) != RET_SUCCESS) {
1588518678f8Sopenharmony_ci        DHCP_LOGE("failed to parse reply options.");
1589518678f8Sopenharmony_ci        return RET_FAILED;
1590518678f8Sopenharmony_ci    }
1591518678f8Sopenharmony_ci    int ret;
1592518678f8Sopenharmony_ci    struct sockaddr_in *bcastAddrIn = BroadcastAddrIn();
1593518678f8Sopenharmony_ci    struct sockaddr_in *destAddrIn = DestinationAddrIn();
1594518678f8Sopenharmony_ci    if (srvIns->broadCastFlagEnable == 1 && destAddrIn) {
1595518678f8Sopenharmony_ci        int broadCastFlag = 1;
1596518678f8Sopenharmony_ci        if (reply->packet.flags && (reply->packet.flags >> (DHCP_MESSAGE_FLAG_LENGTH - 1)) == 0) {
1597518678f8Sopenharmony_ci            broadCastFlag = 0;
1598518678f8Sopenharmony_ci        }
1599518678f8Sopenharmony_ci        if (!broadCastFlag && destAddrIn->sin_addr.s_addr) {
1600518678f8Sopenharmony_ci            ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)destAddrIn,
1601518678f8Sopenharmony_ci                sizeof(*destAddrIn));
1602518678f8Sopenharmony_ci        } else {
1603518678f8Sopenharmony_ci            ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)bcastAddrIn,
1604518678f8Sopenharmony_ci                sizeof(*bcastAddrIn));
1605518678f8Sopenharmony_ci        }
1606518678f8Sopenharmony_ci    } else {
1607518678f8Sopenharmony_ci        ret = sendto(
1608518678f8Sopenharmony_ci            srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)bcastAddrIn, sizeof(*bcastAddrIn));
1609518678f8Sopenharmony_ci    }
1610518678f8Sopenharmony_ci    if (!ret) {
1611518678f8Sopenharmony_ci        DHCP_LOGD("failed to send dhcp offer message.");
1612518678f8Sopenharmony_ci        return RET_FAILED;
1613518678f8Sopenharmony_ci    }
1614518678f8Sopenharmony_ci    DHCP_LOGI("send reply offer, length:%d", reply->length);
1615518678f8Sopenharmony_ci    return RET_SUCCESS;
1616518678f8Sopenharmony_ci}
1617518678f8Sopenharmony_ci
1618518678f8Sopenharmony_cistatic int SendDhcpAck(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1619518678f8Sopenharmony_ci{
1620518678f8Sopenharmony_ci    if (AppendReplyTypeOption(reply, REPLY_ACK) != RET_SUCCESS) {
1621518678f8Sopenharmony_ci        DHCP_LOGE("failed to append reply type options");
1622518678f8Sopenharmony_ci        return RET_FAILED;
1623518678f8Sopenharmony_ci    }
1624518678f8Sopenharmony_ci    if (AppendFixedOptions(ctx, reply) != RET_SUCCESS) {
1625518678f8Sopenharmony_ci        DHCP_LOGW("failed to append fixed reply options.");
1626518678f8Sopenharmony_ci    }
1627518678f8Sopenharmony_ci    if (!ctx || !ctx->instance) {
1628518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
1629518678f8Sopenharmony_ci        return RET_FAILED;
1630518678f8Sopenharmony_ci    }
1631518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1632518678f8Sopenharmony_ci
1633518678f8Sopenharmony_ci    if (AppendReplyTimeOptions(ctx, &reply->options) != RET_SUCCESS) {
1634518678f8Sopenharmony_ci        DHCP_LOGE("failed to append reply time options");
1635518678f8Sopenharmony_ci        return RET_FAILED;
1636518678f8Sopenharmony_ci    }
1637518678f8Sopenharmony_ci    if (AddReplyServerIdOption(&reply->options, srvIns->addressPool.serverId) != RET_SUCCESS) {
1638518678f8Sopenharmony_ci        DHCP_LOGE("failed to add reply server options");
1639518678f8Sopenharmony_ci        return RET_FAILED;
1640518678f8Sopenharmony_ci    }
1641518678f8Sopenharmony_ci    if (ParseReplyOptions(reply) != RET_SUCCESS) {
1642518678f8Sopenharmony_ci        DHCP_LOGE("failed to parse reply options");
1643518678f8Sopenharmony_ci        return RET_FAILED;
1644518678f8Sopenharmony_ci    }
1645518678f8Sopenharmony_ci    sockaddr_in *destAddrIn = DestinationAddrIn();
1646518678f8Sopenharmony_ci    int ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)destAddrIn,
1647518678f8Sopenharmony_ci        sizeof(*destAddrIn));
1648518678f8Sopenharmony_ci    if (!ret) {
1649518678f8Sopenharmony_ci        DHCP_LOGD("failed to send dhcp ack message.");
1650518678f8Sopenharmony_ci        return RET_FAILED;
1651518678f8Sopenharmony_ci    }
1652518678f8Sopenharmony_ci    DHCP_LOGI("send reply ack, size:%d", reply->length);
1653518678f8Sopenharmony_ci    return RET_SUCCESS;
1654518678f8Sopenharmony_ci}
1655518678f8Sopenharmony_ci
1656518678f8Sopenharmony_cistatic int SendDhcpNak(PDhcpServerContext ctx, PDhcpMsgInfo reply)
1657518678f8Sopenharmony_ci{
1658518678f8Sopenharmony_ci    if (AppendReplyTypeOption(reply, REPLY_NAK) != RET_SUCCESS) {
1659518678f8Sopenharmony_ci        DHCP_LOGE("failed to append reply type options");
1660518678f8Sopenharmony_ci        return RET_FAILED;
1661518678f8Sopenharmony_ci    }
1662518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1663518678f8Sopenharmony_ci    if (srvIns == nullptr) {
1664518678f8Sopenharmony_ci        DHCP_LOGE("SendDhcpNak, srvIns is null");
1665518678f8Sopenharmony_ci        return RET_FAILED;
1666518678f8Sopenharmony_ci    }
1667518678f8Sopenharmony_ci    if (AddReplyServerIdOption(&reply->options, srvIns->addressPool.serverId) != RET_SUCCESS) {
1668518678f8Sopenharmony_ci        DHCP_LOGE("SendDhcpNak serverId fail!");
1669518678f8Sopenharmony_ci        return RET_FAILED;
1670518678f8Sopenharmony_ci    }
1671518678f8Sopenharmony_ci    DhcpOption optVendorInfo = {MESSAGE_OPTION, static_cast<uint8_t>(strlen("wrong network")), "wrong network"};
1672518678f8Sopenharmony_ci    PushBackOption(&reply->options, &optVendorInfo);
1673518678f8Sopenharmony_ci    if (ParseReplyOptions(reply) != RET_SUCCESS) {
1674518678f8Sopenharmony_ci        DHCP_LOGE("failed to parse reply options");
1675518678f8Sopenharmony_ci        return RET_FAILED;
1676518678f8Sopenharmony_ci    }
1677518678f8Sopenharmony_ci
1678518678f8Sopenharmony_ci    struct sockaddr_in *destAddrIn = BroadcastAddrIn();
1679518678f8Sopenharmony_ci    int ret = sendto(srvIns->serverFd, &reply->packet, reply->length, 0, (struct sockaddr *)destAddrIn,
1680518678f8Sopenharmony_ci        sizeof(*destAddrIn));
1681518678f8Sopenharmony_ci    if (!ret) {
1682518678f8Sopenharmony_ci        DHCP_LOGD("failed to send dhcp ack message.");
1683518678f8Sopenharmony_ci        return RET_FAILED;
1684518678f8Sopenharmony_ci    }
1685518678f8Sopenharmony_ci    DHCP_LOGI("send reply nak, size:%d", reply->length);
1686518678f8Sopenharmony_ci    return RET_SUCCESS;
1687518678f8Sopenharmony_ci}
1688518678f8Sopenharmony_ci
1689518678f8Sopenharmony_cistatic int ParseMessageOptions(PDhcpMsgInfo msg)
1690518678f8Sopenharmony_ci{
1691518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d", __func__, __LINE__);
1692518678f8Sopenharmony_ci    if (msg->length < (DHCP_MSG_HEADER_SIZE + MAGIC_COOKIE_LENGTH)) {
1693518678f8Sopenharmony_ci        return RET_FAILED;
1694518678f8Sopenharmony_ci    }
1695518678f8Sopenharmony_ci    DhcpOption *current, *end;
1696518678f8Sopenharmony_ci    current = (DhcpOption *)msg->packet.options;
1697518678f8Sopenharmony_ci    end = (DhcpOption *)(((uint8_t *)msg->packet.options) + (msg->length - DHCP_MSG_HEADER_SIZE));
1698518678f8Sopenharmony_ci
1699518678f8Sopenharmony_ci    if (memcmp(current, MAGIC_COOKIE_DATA, sizeof(MAGIC_COOKIE_DATA)) != 0) {
1700518678f8Sopenharmony_ci        DHCP_LOGD("bad magic cookie.");
1701518678f8Sopenharmony_ci        return RET_FAILED;
1702518678f8Sopenharmony_ci    }
1703518678f8Sopenharmony_ci
1704518678f8Sopenharmony_ci    current = (DhcpOption *)(((uint8_t *)current) + MAGIC_COOKIE_LENGTH);
1705518678f8Sopenharmony_ci    uint8_t *pos = (((uint8_t *)current) + MAGIC_COOKIE_LENGTH);
1706518678f8Sopenharmony_ci    uint8_t *maxPos = (((uint8_t *)current) + (DHCP_OPTION_SIZE - MAGIC_COOKIE_LENGTH - OPT_HEADER_LENGTH -1));
1707518678f8Sopenharmony_ci    int optTotal = 0;
1708518678f8Sopenharmony_ci    while (current < end && current->code != END_OPTION) {
1709518678f8Sopenharmony_ci        if (((uint8_t *)end) - ((uint8_t *)current) < OPT_HEADER_LENGTH) {
1710518678f8Sopenharmony_ci            DHCP_LOGE("current->code out of option range.");
1711518678f8Sopenharmony_ci            return RET_FAILED;
1712518678f8Sopenharmony_ci        }
1713518678f8Sopenharmony_ci        pos += (OPT_HEADER_LENGTH + current->length);
1714518678f8Sopenharmony_ci        if (pos >= maxPos) {
1715518678f8Sopenharmony_ci            DHCP_LOGD("out of option max pos.");
1716518678f8Sopenharmony_ci            return RET_FAILED;
1717518678f8Sopenharmony_ci        }
1718518678f8Sopenharmony_ci        if (PushBackOption(&msg->options, current) != RET_SUCCESS) {
1719518678f8Sopenharmony_ci            DHCP_LOGD("failed to PushOption.");
1720518678f8Sopenharmony_ci        }
1721518678f8Sopenharmony_ci        current = (DhcpOption *)(((uint8_t *)current) + OPT_HEADER_LENGTH + current->length);
1722518678f8Sopenharmony_ci        optTotal++;
1723518678f8Sopenharmony_ci    }
1724518678f8Sopenharmony_ci    if (current < end && current->code == END_OPTION) {
1725518678f8Sopenharmony_ci        DHCP_LOGD("option list size:%zu xid:%u", msg->options.size, msg->packet.xid);
1726518678f8Sopenharmony_ci        return RET_SUCCESS;
1727518678f8Sopenharmony_ci    }
1728518678f8Sopenharmony_ci
1729518678f8Sopenharmony_ci    DHCP_LOGD("option list parse failed.");
1730518678f8Sopenharmony_ci    return RET_FAILED;
1731518678f8Sopenharmony_ci}
1732518678f8Sopenharmony_ci
1733518678f8Sopenharmony_cistatic int ResetMessageOptions(PDhcpMsgInfo reply)
1734518678f8Sopenharmony_ci{
1735518678f8Sopenharmony_ci    if (!reply || reply->options.size == 0) {
1736518678f8Sopenharmony_ci        DHCP_LOGE("message pointer is null.");
1737518678f8Sopenharmony_ci        return RET_ERROR;
1738518678f8Sopenharmony_ci    }
1739518678f8Sopenharmony_ci    if (memset_s(reply->packet.options, DHCP_OPTIONS_SIZE, 0, DHCP_OPTIONS_SIZE) != EOK) {
1740518678f8Sopenharmony_ci        DHCP_LOGE("failed to reset message options!");
1741518678f8Sopenharmony_ci        return RET_ERROR;
1742518678f8Sopenharmony_ci    }
1743518678f8Sopenharmony_ci    return RET_SUCCESS;
1744518678f8Sopenharmony_ci}
1745518678f8Sopenharmony_ci
1746518678f8Sopenharmony_cistatic int ValidateReplyOptions(PDhcpMsgInfo reply)
1747518678f8Sopenharmony_ci{
1748518678f8Sopenharmony_ci    if (!reply) {
1749518678f8Sopenharmony_ci        DHCP_LOGE("reply message pointer is null.");
1750518678f8Sopenharmony_ci        return RET_FAILED;
1751518678f8Sopenharmony_ci    }
1752518678f8Sopenharmony_ci    int ret = RET_FAILED;
1753518678f8Sopenharmony_ci    if ((ret = ResetMessageOptions(reply)) != RET_SUCCESS) {
1754518678f8Sopenharmony_ci        return ret;
1755518678f8Sopenharmony_ci    }
1756518678f8Sopenharmony_ci    reply->length = DHCP_MSG_HEADER_SIZE;
1757518678f8Sopenharmony_ci    PDhcpOptionNode pNode = reply->options.first;
1758518678f8Sopenharmony_ci    if (!pNode) {
1759518678f8Sopenharmony_ci        return RET_ERROR;
1760518678f8Sopenharmony_ci    }
1761518678f8Sopenharmony_ci    PDhcpOption pOptMsgType = GetOption(&reply->options, DHCP_MESSAGE_TYPE_OPTION);
1762518678f8Sopenharmony_ci    if (!pOptMsgType) {
1763518678f8Sopenharmony_ci        DHCP_LOGE("unknown reply message type.");
1764518678f8Sopenharmony_ci        return ret;
1765518678f8Sopenharmony_ci    }
1766518678f8Sopenharmony_ci    return RET_SUCCESS;
1767518678f8Sopenharmony_ci}
1768518678f8Sopenharmony_ci
1769518678f8Sopenharmony_cistatic int ParseReplyOptions(PDhcpMsgInfo reply)
1770518678f8Sopenharmony_ci{
1771518678f8Sopenharmony_ci    int ret = RET_FAILED;
1772518678f8Sopenharmony_ci    if ((ret = ValidateReplyOptions(reply)) != RET_SUCCESS) {
1773518678f8Sopenharmony_ci        return ret;
1774518678f8Sopenharmony_ci    }
1775518678f8Sopenharmony_ci    PDhcpOptionNode pNode = reply->options.first->next;
1776518678f8Sopenharmony_ci    DhcpOption endOpt = {END_OPTION, 0, {0}};
1777518678f8Sopenharmony_ci    PushBackOption(&reply->options, &endOpt);
1778518678f8Sopenharmony_ci    int replyOptsLength = 0;
1779518678f8Sopenharmony_ci    uint8_t *current = reply->packet.options, olen = MAGIC_COOKIE_LENGTH;
1780518678f8Sopenharmony_ci    size_t remainingSize = sizeof(reply->packet.options);
1781518678f8Sopenharmony_ci    uint32_t cookie = htonl(DHCP_MAGIC_COOKIE);
1782518678f8Sopenharmony_ci    if (memcpy_s(current, remainingSize, &cookie, olen) != EOK) {
1783518678f8Sopenharmony_ci        DHCP_LOGE("memcpy cookie out of options buffer!");
1784518678f8Sopenharmony_ci        return RET_FAILED;
1785518678f8Sopenharmony_ci    }
1786518678f8Sopenharmony_ci    replyOptsLength += olen;
1787518678f8Sopenharmony_ci    remainingSize -= olen;
1788518678f8Sopenharmony_ci    current += olen;
1789518678f8Sopenharmony_ci    ret = RET_SUCCESS;
1790518678f8Sopenharmony_ci    while (pNode && (uint32_t)pNode->option.length < DHCP_OPTION_SIZE) {
1791518678f8Sopenharmony_ci        if ((uint32_t)pNode->option.code == END_OPTION) {
1792518678f8Sopenharmony_ci            olen = OPT_HEADER_LENGTH + 1;
1793518678f8Sopenharmony_ci        } else {
1794518678f8Sopenharmony_ci            olen = OPT_HEADER_LENGTH + pNode->option.length;
1795518678f8Sopenharmony_ci        }
1796518678f8Sopenharmony_ci        if (memcpy_s(current, remainingSize, &pNode->option, olen) != EOK) {
1797518678f8Sopenharmony_ci            DHCP_LOGE("memcpy current option out of options buffer!");
1798518678f8Sopenharmony_ci            ret = RET_FAILED;
1799518678f8Sopenharmony_ci            break;
1800518678f8Sopenharmony_ci        }
1801518678f8Sopenharmony_ci        remainingSize -= olen;
1802518678f8Sopenharmony_ci        current += olen;
1803518678f8Sopenharmony_ci        replyOptsLength += olen;
1804518678f8Sopenharmony_ci        if ((uint32_t)pNode->option.code == END_OPTION) {
1805518678f8Sopenharmony_ci            break;
1806518678f8Sopenharmony_ci        }
1807518678f8Sopenharmony_ci        pNode = pNode->next;
1808518678f8Sopenharmony_ci        if (replyOptsLength >= DHCP_OPTIONS_SIZE) {
1809518678f8Sopenharmony_ci            DHCP_LOGE("current option out of options buffer!");
1810518678f8Sopenharmony_ci            ret = RET_FAILED;
1811518678f8Sopenharmony_ci            break;
1812518678f8Sopenharmony_ci        }
1813518678f8Sopenharmony_ci    }
1814518678f8Sopenharmony_ci    reply->length += replyOptsLength;
1815518678f8Sopenharmony_ci    return ret;
1816518678f8Sopenharmony_ci}
1817518678f8Sopenharmony_ci
1818518678f8Sopenharmony_civoid RegisterDhcpCallback(PDhcpServerContext ctx, DhcpServerCallback callback)
1819518678f8Sopenharmony_ci{
1820518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s   %{public}d.", __func__, __LINE__);
1821518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1822518678f8Sopenharmony_ci    if (!srvIns) {
1823518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
1824518678f8Sopenharmony_ci        return;
1825518678f8Sopenharmony_ci    }
1826518678f8Sopenharmony_ci    srvIns->callback = callback;
1827518678f8Sopenharmony_ci}
1828518678f8Sopenharmony_ci
1829518678f8Sopenharmony_civoid RegisterDeviceChangedCallback(PDhcpServerContext ctx, DeviceConnectFun func)
1830518678f8Sopenharmony_ci{
1831518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s %{public}d.", __func__, __LINE__);
1832518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1833518678f8Sopenharmony_ci    if (!srvIns) {
1834518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
1835518678f8Sopenharmony_ci        return;
1836518678f8Sopenharmony_ci    }
1837518678f8Sopenharmony_ci    srvIns->deviceConnectFun = func;
1838518678f8Sopenharmony_ci}
1839518678f8Sopenharmony_ci
1840518678f8Sopenharmony_cistatic int InitServerContext(DhcpConfig *config, DhcpServerContext *ctx)
1841518678f8Sopenharmony_ci{
1842518678f8Sopenharmony_ci    if (!config) {
1843518678f8Sopenharmony_ci        DHCP_LOGE("server configure pointer is null.");
1844518678f8Sopenharmony_ci        return RET_FAILED;
1845518678f8Sopenharmony_ci    }
1846518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1847518678f8Sopenharmony_ci    if (!srvIns) {
1848518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
1849518678f8Sopenharmony_ci        return RET_FAILED;
1850518678f8Sopenharmony_ci    }
1851518678f8Sopenharmony_ci    if (InitAddressPool(&srvIns->addressPool, config->ifname, nullptr) != RET_SUCCESS) {
1852518678f8Sopenharmony_ci        DHCP_LOGD("failed to init address pool.");
1853518678f8Sopenharmony_ci        return RET_FAILED;
1854518678f8Sopenharmony_ci    }
1855518678f8Sopenharmony_ci    if (memcpy_s(ctx->ifname, sizeof(ctx->ifname), config->ifname, strlen(config->ifname)) != EOK) {
1856518678f8Sopenharmony_ci        DHCP_LOGD("failed to set interface name.");
1857518678f8Sopenharmony_ci        return RET_FAILED;
1858518678f8Sopenharmony_ci    }
1859518678f8Sopenharmony_ci    srvIns->serverFd = 0;
1860518678f8Sopenharmony_ci    srvIns->callback = 0;
1861518678f8Sopenharmony_ci    srvIns->looperState = LS_IDLE;
1862518678f8Sopenharmony_ci    srvIns->broadCastFlagEnable = static_cast<int>(config->broadcast);
1863518678f8Sopenharmony_ci    srvIns->addressPool.serverId = config->serverId;
1864518678f8Sopenharmony_ci    srvIns->addressPool.netmask = config->netmask;
1865518678f8Sopenharmony_ci    srvIns->addressPool.gateway = config->gateway;
1866518678f8Sopenharmony_ci    if (config->pool.beginAddress && config->pool.endAddress) {
1867518678f8Sopenharmony_ci        srvIns->addressPool.addressRange.beginAddress = config->pool.beginAddress;
1868518678f8Sopenharmony_ci        srvIns->addressPool.addressRange.endAddress = config->pool.endAddress;
1869518678f8Sopenharmony_ci    } else {
1870518678f8Sopenharmony_ci        srvIns->addressPool.addressRange.beginAddress = FirstIpAddress(config->serverId, config->netmask);
1871518678f8Sopenharmony_ci        srvIns->addressPool.addressRange.endAddress = LastIpAddress(config->serverId, config->netmask);
1872518678f8Sopenharmony_ci    }
1873518678f8Sopenharmony_ci    if (memcpy_s(srvIns->addressPool.ifname, sizeof(srvIns->addressPool.ifname),
1874518678f8Sopenharmony_ci        config->ifname, strlen(config->ifname)) != EOK) {
1875518678f8Sopenharmony_ci        DHCP_LOGD("failed to set interface name.");
1876518678f8Sopenharmony_ci        return RET_FAILED;
1877518678f8Sopenharmony_ci    }
1878518678f8Sopenharmony_ci    if (!CheckAddressRange(&srvIns->addressPool)) {
1879518678f8Sopenharmony_ci        DHCP_LOGE("failed to validate address range.");
1880518678f8Sopenharmony_ci        return RET_FAILED;
1881518678f8Sopenharmony_ci    }
1882518678f8Sopenharmony_ci    InitLeaseFile(&srvIns->addressPool);
1883518678f8Sopenharmony_ci    srvIns->addressPool.leaseTime = config->leaseTime;
1884518678f8Sopenharmony_ci    srvIns->addressPool.renewalTime = config->renewalTime;
1885518678f8Sopenharmony_ci    srvIns->addressPool.rebindingTime = config->rebindingTime;
1886518678f8Sopenharmony_ci    return RET_SUCCESS;
1887518678f8Sopenharmony_ci}
1888518678f8Sopenharmony_ci
1889518678f8Sopenharmony_ciint InitServerFixedOptions(DhcpConfig *config, DhcpServerContext *ctx)
1890518678f8Sopenharmony_ci{
1891518678f8Sopenharmony_ci    if (!config) {
1892518678f8Sopenharmony_ci        DHCP_LOGE("server configure pointer is null.");
1893518678f8Sopenharmony_ci        return RET_FAILED;
1894518678f8Sopenharmony_ci    }
1895518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(ctx);
1896518678f8Sopenharmony_ci    if (!srvIns) {
1897518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
1898518678f8Sopenharmony_ci        return RET_FAILED;
1899518678f8Sopenharmony_ci    }
1900518678f8Sopenharmony_ci
1901518678f8Sopenharmony_ci    if (!HasInitialized(&config->options)) {
1902518678f8Sopenharmony_ci        DHCP_LOGE("dhcp configure has not been initialized.");
1903518678f8Sopenharmony_ci        return RET_FAILED;
1904518678f8Sopenharmony_ci    }
1905518678f8Sopenharmony_ci    if (InitOptionList(&srvIns->addressPool.fixedOptions) != RET_SUCCESS) {
1906518678f8Sopenharmony_ci        return RET_FAILED;
1907518678f8Sopenharmony_ci    }
1908518678f8Sopenharmony_ci    if (config->options.first != nullptr && config->options.size > 0) {
1909518678f8Sopenharmony_ci        DhcpOptionNode *pNode = config->options.first->next;
1910518678f8Sopenharmony_ci        for (size_t i = 0; pNode != nullptr && i < config->options.size; i++) {
1911518678f8Sopenharmony_ci            PushBackOption(&srvIns->addressPool.fixedOptions, &pNode->option);
1912518678f8Sopenharmony_ci            DHCP_LOGD("append fixed option ==> %hhu,%d", pNode->option.code,
1913518678f8Sopenharmony_ci                pNode->option.length);
1914518678f8Sopenharmony_ci            pNode = pNode->next;
1915518678f8Sopenharmony_ci        }
1916518678f8Sopenharmony_ci    }
1917518678f8Sopenharmony_ci    return RET_SUCCESS;
1918518678f8Sopenharmony_ci}
1919518678f8Sopenharmony_ci
1920518678f8Sopenharmony_ciPDhcpServerContext InitializeServer(DhcpConfig *config)
1921518678f8Sopenharmony_ci{
1922518678f8Sopenharmony_ci    DHCP_LOGI("start %{public}s   %{public}d.", __func__, __LINE__);
1923518678f8Sopenharmony_ci    DhcpServerContext *context = nullptr;
1924518678f8Sopenharmony_ci    if (!config) {
1925518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server config pointer is null.");
1926518678f8Sopenharmony_ci        return nullptr;
1927518678f8Sopenharmony_ci    }
1928518678f8Sopenharmony_ci    if (strlen(config->ifname) == 0) {
1929518678f8Sopenharmony_ci        DHCP_LOGE("can't found interface name config.");
1930518678f8Sopenharmony_ci        return nullptr;
1931518678f8Sopenharmony_ci    }
1932518678f8Sopenharmony_ci    if (!config->serverId || !config->netmask) {
1933518678f8Sopenharmony_ci        DHCP_LOGE("missing required parameter or config item: \"serverId\", \"netmask\"");
1934518678f8Sopenharmony_ci        return nullptr;
1935518678f8Sopenharmony_ci    }
1936518678f8Sopenharmony_ci    if ((context = (DhcpServerContext *)calloc(1, sizeof(DhcpServerContext))) == nullptr) {
1937518678f8Sopenharmony_ci        DHCP_LOGE("failed to calloc server context.");
1938518678f8Sopenharmony_ci        return nullptr;
1939518678f8Sopenharmony_ci    }
1940518678f8Sopenharmony_ci    if ((context->instance = (ServerContext *)calloc(1, sizeof(ServerContext))) == nullptr) {
1941518678f8Sopenharmony_ci        DHCP_LOGE("failed to calloc server instance.");
1942518678f8Sopenharmony_ci        FreeServerContext(&context);
1943518678f8Sopenharmony_ci        return nullptr;
1944518678f8Sopenharmony_ci    }
1945518678f8Sopenharmony_ci    if (InitServerContext(config, context) != RET_SUCCESS) {
1946518678f8Sopenharmony_ci        DHCP_LOGE("failed initialize dhcp server context.");
1947518678f8Sopenharmony_ci        FreeServerContext(&context);
1948518678f8Sopenharmony_ci        return nullptr;
1949518678f8Sopenharmony_ci    }
1950518678f8Sopenharmony_ci    if (InitServerFixedOptions(config, context) != RET_SUCCESS) {
1951518678f8Sopenharmony_ci        DHCP_LOGE("failed initialize dhcp server fixed options.");
1952518678f8Sopenharmony_ci        FreeServerContext(&context);
1953518678f8Sopenharmony_ci        return nullptr;
1954518678f8Sopenharmony_ci    }
1955518678f8Sopenharmony_ci    DHCP_LOGI("server id: %{private}s", ParseStrIp(config->serverId));
1956518678f8Sopenharmony_ci    DHCP_LOGI("netmask: %{private}s", ParseStrIp(config->netmask));
1957518678f8Sopenharmony_ci    if (config->gateway) {
1958518678f8Sopenharmony_ci        DHCP_LOGI("gateway: %{private}s", ParseStrIp(config->gateway));
1959518678f8Sopenharmony_ci    }
1960518678f8Sopenharmony_ci    DHCP_LOGI("address range begin of: %{private}s", ParseStrIp(config->pool.beginAddress));
1961518678f8Sopenharmony_ci    DHCP_LOGI("address range end of: %{private}s", ParseStrIp(config->pool.endAddress));
1962518678f8Sopenharmony_ci    context->instance->initialized = 1;
1963518678f8Sopenharmony_ci    return context;
1964518678f8Sopenharmony_ci}
1965518678f8Sopenharmony_ci
1966518678f8Sopenharmony_ciint FreeServerContext(PDhcpServerContext *ctx)
1967518678f8Sopenharmony_ci{
1968518678f8Sopenharmony_ci    if (ctx == nullptr || *ctx == nullptr) {
1969518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server context pointer is null.");
1970518678f8Sopenharmony_ci        return RET_FAILED;
1971518678f8Sopenharmony_ci    }
1972518678f8Sopenharmony_ci    ServerContext *srvIns = GetServerInstance(*ctx);
1973518678f8Sopenharmony_ci    if (!srvIns) {
1974518678f8Sopenharmony_ci        DHCP_LOGE("dhcp server instance pointer is null.");
1975518678f8Sopenharmony_ci        return RET_FAILED;
1976518678f8Sopenharmony_ci    }
1977518678f8Sopenharmony_ci    int times = 5;
1978518678f8Sopenharmony_ci    while (srvIns->looperState != LS_STOPED && srvIns->looperState != LS_IDLE) {
1979518678f8Sopenharmony_ci        DHCP_LOGE("FreeServerContext wait 300ms.");
1980518678f8Sopenharmony_ci        usleep(300000);
1981518678f8Sopenharmony_ci        times--;
1982518678f8Sopenharmony_ci        if (times <= 0) {
1983518678f8Sopenharmony_ci            return RET_FAILED;
1984518678f8Sopenharmony_ci        }
1985518678f8Sopenharmony_ci    }
1986518678f8Sopenharmony_ci    FreeAddressPool(&srvIns->addressPool);
1987518678f8Sopenharmony_ci    if ((*ctx)->instance != nullptr) {
1988518678f8Sopenharmony_ci        free((*ctx)->instance);
1989518678f8Sopenharmony_ci        (*ctx)->instance = nullptr;
1990518678f8Sopenharmony_ci    }
1991518678f8Sopenharmony_ci    free(*ctx);
1992518678f8Sopenharmony_ci    *ctx = nullptr;
1993518678f8Sopenharmony_ci    return RET_SUCCESS;
1994518678f8Sopenharmony_ci}
1995