1518678f8Sopenharmony_ci/*
2518678f8Sopenharmony_ci * Copyright (C) 2021 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#include "dhcp_socket.h"
16518678f8Sopenharmony_ci
17518678f8Sopenharmony_ci#include <stdio.h>
18518678f8Sopenharmony_ci#include <unistd.h>
19518678f8Sopenharmony_ci#include <string.h>
20518678f8Sopenharmony_ci#include <errno.h>
21518678f8Sopenharmony_ci#include <sys/types.h>
22518678f8Sopenharmony_ci#include <sys/socket.h>
23518678f8Sopenharmony_ci#include <netpacket/packet.h>
24518678f8Sopenharmony_ci#include <net/ethernet.h>
25518678f8Sopenharmony_ci#include <net/if.h>
26518678f8Sopenharmony_ci#include <arpa/inet.h>
27518678f8Sopenharmony_ci
28518678f8Sopenharmony_ci#include "dhcp_options.h"
29518678f8Sopenharmony_ci#include "securec.h"
30518678f8Sopenharmony_ci#include "dhcp_logger.h"
31518678f8Sopenharmony_ci
32518678f8Sopenharmony_ciDEFINE_DHCPLOG_DHCP_LABEL("DhcpSocket");
33518678f8Sopenharmony_ci
34518678f8Sopenharmony_cistatic uint16_t GetCheckSum(uint16_t *pData, int nBytes)
35518678f8Sopenharmony_ci{
36518678f8Sopenharmony_ci    uint32_t uTotalSum = 0;
37518678f8Sopenharmony_ci
38518678f8Sopenharmony_ci    /* Calculates the network checksum by 2 bytes. */
39518678f8Sopenharmony_ci    while (nBytes >= DHCP_UINT16_BYTES)  {
40518678f8Sopenharmony_ci        uTotalSum += *pData++;
41518678f8Sopenharmony_ci        nBytes -= DHCP_UINT16_BYTES;
42518678f8Sopenharmony_ci    }
43518678f8Sopenharmony_ci    /* Calculate the network checksum based on the remaining bytes. */
44518678f8Sopenharmony_ci    if (nBytes > 0) {
45518678f8Sopenharmony_ci        uint16_t u16Sum;
46518678f8Sopenharmony_ci        *(uint8_t *)(&u16Sum) = *(uint8_t *)pData;
47518678f8Sopenharmony_ci        uTotalSum += u16Sum;
48518678f8Sopenharmony_ci    }
49518678f8Sopenharmony_ci    /* Checksum conversion from 32-bit to 16-bit. */
50518678f8Sopenharmony_ci    while (uTotalSum >> DHCP_UINT16_BITS) {
51518678f8Sopenharmony_ci        uTotalSum = (uTotalSum & 0xffff) + (uTotalSum >> DHCP_UINT16_BITS);
52518678f8Sopenharmony_ci    }
53518678f8Sopenharmony_ci
54518678f8Sopenharmony_ci    return (uint16_t)(~uTotalSum);
55518678f8Sopenharmony_ci}
56518678f8Sopenharmony_ci
57518678f8Sopenharmony_ci/* Raw socket can receive data frames or data packets from the local network interface. */
58518678f8Sopenharmony_ciint CreateRawSocket(int *rawFd)
59518678f8Sopenharmony_ci{
60518678f8Sopenharmony_ci    int sockFd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
61518678f8Sopenharmony_ci    if (sockFd == -1) {
62518678f8Sopenharmony_ci        DHCP_LOGE("CreateRawSocket() failed, socket error:%{public}d.", errno);
63518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
64518678f8Sopenharmony_ci    }
65518678f8Sopenharmony_ci    *rawFd = sockFd;
66518678f8Sopenharmony_ci    return SOCKET_OPT_SUCCESS;
67518678f8Sopenharmony_ci}
68518678f8Sopenharmony_ci
69518678f8Sopenharmony_ci/* Kernel socket can receive data frames or data packets from the local network interface, ip and port. */
70518678f8Sopenharmony_ciint CreateKernelSocket(int *sockFd)
71518678f8Sopenharmony_ci{
72518678f8Sopenharmony_ci    if (sockFd == NULL) {
73518678f8Sopenharmony_ci        DHCP_LOGE("CreateKernelSocket() failed, sockFd is NULL!");
74518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
75518678f8Sopenharmony_ci    }
76518678f8Sopenharmony_ci    int nFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
77518678f8Sopenharmony_ci    if (nFd == -1) {
78518678f8Sopenharmony_ci        DHCP_LOGE("CreateKernelSocket() failed, socket error:%{public}d.", errno);
79518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
80518678f8Sopenharmony_ci    }
81518678f8Sopenharmony_ci    *sockFd = nFd;
82518678f8Sopenharmony_ci    return SOCKET_OPT_SUCCESS;
83518678f8Sopenharmony_ci}
84518678f8Sopenharmony_ci
85518678f8Sopenharmony_ciint BindRawSocket(const int rawFd, const int ifaceIndex, const uint8_t *ifaceAddr)
86518678f8Sopenharmony_ci{
87518678f8Sopenharmony_ci    if (rawFd < 0) {
88518678f8Sopenharmony_ci        DHCP_LOGE("BindRawSocket() failed, rawFd:%{public}d error!", rawFd);
89518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
90518678f8Sopenharmony_ci    }
91518678f8Sopenharmony_ci
92518678f8Sopenharmony_ci    struct sockaddr_ll rawAddr;
93518678f8Sopenharmony_ci    if (memset_s(&rawAddr, sizeof(rawAddr), 0, sizeof(rawAddr)) != EOK) {
94518678f8Sopenharmony_ci        DHCP_LOGE("BindRawSocket() failed, memset_s rawAddr error!");
95518678f8Sopenharmony_ci        close(rawFd);
96518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
97518678f8Sopenharmony_ci    }
98518678f8Sopenharmony_ci    rawAddr.sll_ifindex = ifaceIndex;
99518678f8Sopenharmony_ci    rawAddr.sll_protocol = htons(ETH_P_IP);
100518678f8Sopenharmony_ci    rawAddr.sll_family = AF_PACKET;
101518678f8Sopenharmony_ci    if (ifaceAddr != NULL) {
102518678f8Sopenharmony_ci        rawAddr.sll_halen = MAC_ADDR_LEN;
103518678f8Sopenharmony_ci        if (memcpy_s(rawAddr.sll_addr, sizeof(rawAddr.sll_addr), ifaceAddr, MAC_ADDR_LEN) != EOK) {
104518678f8Sopenharmony_ci            DHCP_LOGE("BindRawSocket() failed, memcpy_s rawAddr.sll_addr error!");
105518678f8Sopenharmony_ci            close(rawFd);
106518678f8Sopenharmony_ci            return SOCKET_OPT_FAILED;
107518678f8Sopenharmony_ci        }
108518678f8Sopenharmony_ci    }
109518678f8Sopenharmony_ci    int nRet = bind(rawFd, (struct sockaddr *)&rawAddr, sizeof(rawAddr));
110518678f8Sopenharmony_ci    if (nRet == -1) {
111518678f8Sopenharmony_ci        DHCP_LOGE("BindRawSocket() index:%{public}d failed, bind error:%{public}d.", ifaceIndex, errno);
112518678f8Sopenharmony_ci        close(rawFd);
113518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
114518678f8Sopenharmony_ci    }
115518678f8Sopenharmony_ci
116518678f8Sopenharmony_ci    return SOCKET_OPT_SUCCESS;
117518678f8Sopenharmony_ci}
118518678f8Sopenharmony_ci
119518678f8Sopenharmony_ciint BindKernelSocket(const int sockFd, const char *ifaceName, const uint32_t sockIp, const int sockPort, bool bCast)
120518678f8Sopenharmony_ci{
121518678f8Sopenharmony_ci    if (sockFd < 0) {
122518678f8Sopenharmony_ci        DHCP_LOGE("BindKernelSocket() failed, sockFd:%{public}d error!", sockFd);
123518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
124518678f8Sopenharmony_ci    }
125518678f8Sopenharmony_ci
126518678f8Sopenharmony_ci    /* Bind the specified interface. */
127518678f8Sopenharmony_ci    if (ifaceName != NULL) {
128518678f8Sopenharmony_ci        struct ifreq ifaceReq;
129518678f8Sopenharmony_ci        if (strncpy_s(ifaceReq.ifr_name, sizeof(ifaceReq.ifr_name), ifaceName, strlen(ifaceName)) != EOK) {
130518678f8Sopenharmony_ci            close(sockFd);
131518678f8Sopenharmony_ci            return SOCKET_OPT_FAILED;
132518678f8Sopenharmony_ci        }
133518678f8Sopenharmony_ci        if (setsockopt(sockFd, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifaceReq, sizeof(ifaceReq)) == -1) {
134518678f8Sopenharmony_ci            DHCP_LOGE("BindKernelSocket() %{public}s SO_BINDTODEVICE error:%{public}d.", ifaceName, errno);
135518678f8Sopenharmony_ci            close(sockFd);
136518678f8Sopenharmony_ci            return SOCKET_OPT_FAILED;
137518678f8Sopenharmony_ci        }
138518678f8Sopenharmony_ci    }
139518678f8Sopenharmony_ci
140518678f8Sopenharmony_ci    /* Set the broadcast feature of the data sent by the socket. */
141518678f8Sopenharmony_ci    if (bCast) {
142518678f8Sopenharmony_ci        int broadcast = 1;
143518678f8Sopenharmony_ci        if (setsockopt(sockFd, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(int)) == -1) {
144518678f8Sopenharmony_ci            DHCP_LOGE("BindKernelSocket() sockFd:%{public}d SO_BROADCAST error:%{public}d.", sockFd, errno);
145518678f8Sopenharmony_ci            close(sockFd);
146518678f8Sopenharmony_ci            return SOCKET_OPT_FAILED;
147518678f8Sopenharmony_ci        }
148518678f8Sopenharmony_ci    }
149518678f8Sopenharmony_ci
150518678f8Sopenharmony_ci    /* Allow multiple sockets to use the same port number. */
151518678f8Sopenharmony_ci    int bReuseaddr = 1;
152518678f8Sopenharmony_ci    if (setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, (const char *)&bReuseaddr, sizeof(bReuseaddr)) == -1) {
153518678f8Sopenharmony_ci        DHCP_LOGE("BindKernelSocket() sockFd:%{public}d SO_REUSEADDR error:%{public}d.", sockFd, errno);
154518678f8Sopenharmony_ci        close(sockFd);
155518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
156518678f8Sopenharmony_ci    }
157518678f8Sopenharmony_ci
158518678f8Sopenharmony_ci    struct sockaddr_in kernelAddr;
159518678f8Sopenharmony_ci    if (memset_s(&kernelAddr, sizeof(kernelAddr), 0, sizeof(kernelAddr)) != EOK) {
160518678f8Sopenharmony_ci        close(sockFd);
161518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
162518678f8Sopenharmony_ci    }
163518678f8Sopenharmony_ci    kernelAddr.sin_addr.s_addr = sockIp;
164518678f8Sopenharmony_ci    kernelAddr.sin_port = htons(sockPort);
165518678f8Sopenharmony_ci    kernelAddr.sin_family = AF_INET;
166518678f8Sopenharmony_ci    int nRet = bind(sockFd, (struct sockaddr *)&kernelAddr, sizeof(kernelAddr));
167518678f8Sopenharmony_ci    if (nRet == -1) {
168518678f8Sopenharmony_ci        DHCP_LOGE("BindKernelSocket() sockFd:%{public}d failed, bind error:%{public}d.", sockFd, errno);
169518678f8Sopenharmony_ci        close(sockFd);
170518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
171518678f8Sopenharmony_ci    }
172518678f8Sopenharmony_ci
173518678f8Sopenharmony_ci    return SOCKET_OPT_SUCCESS;
174518678f8Sopenharmony_ci}
175518678f8Sopenharmony_ci
176518678f8Sopenharmony_ciint SendToDhcpPacket(
177518678f8Sopenharmony_ci    const struct DhcpPacket *sendPacket, uint32_t srcIp, uint32_t destIp, int destIndex, const uint8_t *destHwaddr)
178518678f8Sopenharmony_ci{
179518678f8Sopenharmony_ci    DHCP_LOGI("SendToDhcpPacket enter, destIndex:%{public}d, destHwaddr:%{public}d", destIndex, *destHwaddr);
180518678f8Sopenharmony_ci    int nFd = -1;
181518678f8Sopenharmony_ci    if (CreateRawSocket(&nFd) != SOCKET_OPT_SUCCESS) {
182518678f8Sopenharmony_ci        DHCP_LOGE("SendToDhcpPacket CreateRawSocket fail.");
183518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
184518678f8Sopenharmony_ci    }
185518678f8Sopenharmony_ci
186518678f8Sopenharmony_ci    struct sockaddr_ll rawAddr;
187518678f8Sopenharmony_ci    if ((memset_s(&rawAddr, sizeof(rawAddr), 0, sizeof(rawAddr)) != EOK) ||
188518678f8Sopenharmony_ci        (memcpy_s(rawAddr.sll_addr, sizeof(rawAddr.sll_addr), destHwaddr, MAC_ADDR_LEN) != EOK)) {
189518678f8Sopenharmony_ci        close(nFd);
190518678f8Sopenharmony_ci        DHCP_LOGE("SendToDhcpPacket memcpy_s fail.");
191518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
192518678f8Sopenharmony_ci    }
193518678f8Sopenharmony_ci    rawAddr.sll_ifindex = destIndex;
194518678f8Sopenharmony_ci    rawAddr.sll_protocol = htons(ETH_P_IP);
195518678f8Sopenharmony_ci    rawAddr.sll_family = AF_PACKET;
196518678f8Sopenharmony_ci    rawAddr.sll_halen = MAC_ADDR_LEN;
197518678f8Sopenharmony_ci    if (bind(nFd, (struct sockaddr *)&rawAddr, sizeof(rawAddr)) == -1) {
198518678f8Sopenharmony_ci        close(nFd);
199518678f8Sopenharmony_ci        DHCP_LOGE("SendToDhcpPacket bind fail.");
200518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
201518678f8Sopenharmony_ci    }
202518678f8Sopenharmony_ci
203518678f8Sopenharmony_ci    /* Filling the structure information. */
204518678f8Sopenharmony_ci    struct UdpDhcpPacket udpPackets;
205518678f8Sopenharmony_ci    if (memset_s(&udpPackets, sizeof(udpPackets), 0, sizeof(udpPackets)) != EOK) {
206518678f8Sopenharmony_ci        close(nFd);
207518678f8Sopenharmony_ci        DHCP_LOGE("SendToDhcpPacket memset_s udpPackets fail.");
208518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
209518678f8Sopenharmony_ci    }
210518678f8Sopenharmony_ci    /* get append options length , include endpoint length(2) */
211518678f8Sopenharmony_ci    int optionLen = GetEndOptionIndex(sendPacket->options) + DHCP_APPEND_LEN;
212518678f8Sopenharmony_ci    int sendLen = sizeof(udpPackets) - sizeof(udpPackets.data.options) + optionLen;
213518678f8Sopenharmony_ci    int dhcpPackLen = sizeof(struct DhcpPacket) - sizeof(udpPackets.data.options) + optionLen;
214518678f8Sopenharmony_ci    udpPackets.udp.source = htons(BOOTP_CLIENT);
215518678f8Sopenharmony_ci    udpPackets.udp.dest = htons(BOOTP_SERVER);
216518678f8Sopenharmony_ci    udpPackets.udp.len = htons(sizeof(udpPackets.udp) + dhcpPackLen);
217518678f8Sopenharmony_ci    udpPackets.ip.tot_len = udpPackets.udp.len;
218518678f8Sopenharmony_ci    udpPackets.ip.protocol = IPPROTO_UDP;
219518678f8Sopenharmony_ci    udpPackets.ip.saddr = srcIp;
220518678f8Sopenharmony_ci    udpPackets.ip.daddr = destIp;
221518678f8Sopenharmony_ci    if (memcpy_s(&(udpPackets.data), sizeof(struct DhcpPacket), sendPacket, sizeof(struct DhcpPacket)) != EOK) {
222518678f8Sopenharmony_ci        close(nFd);
223518678f8Sopenharmony_ci        DHCP_LOGE("SendToDhcpPacket memcpy_s sendPacket fail.");
224518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
225518678f8Sopenharmony_ci    }
226518678f8Sopenharmony_ci    udpPackets.udp.check = GetCheckSum((uint16_t *)&udpPackets, sizeof(struct UdpDhcpPacket));
227518678f8Sopenharmony_ci    udpPackets.ip.ihl = sizeof(udpPackets.ip) >> DHCP_UINT16_BYTES;
228518678f8Sopenharmony_ci    udpPackets.ip.version = IPVERSION;
229518678f8Sopenharmony_ci    udpPackets.ip.tot_len = htons(sendLen);
230518678f8Sopenharmony_ci    udpPackets.ip.ttl = IPDEFTTL;
231518678f8Sopenharmony_ci    udpPackets.ip.check = GetCheckSum((uint16_t *)&(udpPackets.ip), sizeof(udpPackets.ip));
232518678f8Sopenharmony_ci
233518678f8Sopenharmony_ci    ssize_t nBytes = sendto(nFd, &udpPackets, sendLen, 0, (struct sockaddr *)&rawAddr, sizeof(rawAddr));
234518678f8Sopenharmony_ci    if (nBytes <= 0) {
235518678f8Sopenharmony_ci        DHCP_LOGE("SendToDhcpPacket optionLen:%{public}d sendLen:%{public}d, "
236518678f8Sopenharmony_ci            "dhcpPackLen:%{public}d fd:%{public}d failed, sendto error:%{public}d.",
237518678f8Sopenharmony_ci            optionLen, sendLen, dhcpPackLen, nFd, errno);
238518678f8Sopenharmony_ci    } else {
239518678f8Sopenharmony_ci        DHCP_LOGI("SendToDhcpPacket optionLen:%{public}d sendLen:%{public}d, "
240518678f8Sopenharmony_ci            "dhcpPackLen:%{public}d fd:%{public}d, index:%{public}d, bytes:%{public}d.",
241518678f8Sopenharmony_ci            optionLen, sendLen, dhcpPackLen, nFd, destIndex, static_cast<int>(nBytes));
242518678f8Sopenharmony_ci    }
243518678f8Sopenharmony_ci    close(nFd);
244518678f8Sopenharmony_ci    return (nBytes <= 0) ? SOCKET_OPT_FAILED : SOCKET_OPT_SUCCESS;
245518678f8Sopenharmony_ci}
246518678f8Sopenharmony_ci
247518678f8Sopenharmony_ciint SendDhcpPacket(struct DhcpPacket *sendPacket, uint32_t srcIp, uint32_t destIp)
248518678f8Sopenharmony_ci{
249518678f8Sopenharmony_ci    int nFd = -1;
250518678f8Sopenharmony_ci    if ((CreateKernelSocket(&nFd) != SOCKET_OPT_SUCCESS) ||
251518678f8Sopenharmony_ci        (BindKernelSocket(nFd, NULL, srcIp, BOOTP_CLIENT, false) != SOCKET_OPT_SUCCESS)) {
252518678f8Sopenharmony_ci        DHCP_LOGE("SendDhcpPacket fd:%{public}d failed!", nFd);
253518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
254518678f8Sopenharmony_ci    }
255518678f8Sopenharmony_ci
256518678f8Sopenharmony_ci    struct sockaddr_in kernelAddr;
257518678f8Sopenharmony_ci    if (memset_s(&kernelAddr, sizeof(kernelAddr), 0, sizeof(kernelAddr)) != EOK) {
258518678f8Sopenharmony_ci        close(nFd);
259518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
260518678f8Sopenharmony_ci    }
261518678f8Sopenharmony_ci    kernelAddr.sin_addr.s_addr = destIp;
262518678f8Sopenharmony_ci    kernelAddr.sin_port = htons(BOOTP_SERVER);
263518678f8Sopenharmony_ci    kernelAddr.sin_family = AF_INET;
264518678f8Sopenharmony_ci    int nRet = connect(nFd, (struct sockaddr *)&kernelAddr, sizeof(kernelAddr));
265518678f8Sopenharmony_ci    if (nRet == -1) {
266518678f8Sopenharmony_ci        DHCP_LOGE("SendDhcpPacket nFd:%{public}d failed, connect error:%{public}d.", nFd, errno);
267518678f8Sopenharmony_ci        close(nFd);
268518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
269518678f8Sopenharmony_ci    }
270518678f8Sopenharmony_ci
271518678f8Sopenharmony_ci    ssize_t nBytes = write(nFd, sendPacket, sizeof(struct DhcpPacket));
272518678f8Sopenharmony_ci    if (nBytes <= 0) {
273518678f8Sopenharmony_ci        DHCP_LOGE("SendDhcpPacket fd:%{public}d failed, write error:%{public}d.", nFd, errno);
274518678f8Sopenharmony_ci    } else {
275518678f8Sopenharmony_ci        DHCP_LOGI("SendDhcpPacket fd:%{public}d, bytes:%{public}d.", nFd, static_cast<int>(nBytes));
276518678f8Sopenharmony_ci    }
277518678f8Sopenharmony_ci    close(nFd);
278518678f8Sopenharmony_ci    return (nBytes <= 0) ? SOCKET_OPT_FAILED : SOCKET_OPT_SUCCESS;
279518678f8Sopenharmony_ci}
280518678f8Sopenharmony_ci
281518678f8Sopenharmony_ciint CheckReadBytes(const int count, const int totLen)
282518678f8Sopenharmony_ci{
283518678f8Sopenharmony_ci    if (count < 0) {
284518678f8Sopenharmony_ci        DHCP_LOGE("CheckReadBytes() couldn't read on raw listening socket, count:%{public}d, error:%{public}d!",
285518678f8Sopenharmony_ci            count, errno);
286518678f8Sopenharmony_ci        return SOCKET_OPT_ERROR;
287518678f8Sopenharmony_ci    }
288518678f8Sopenharmony_ci
289518678f8Sopenharmony_ci    int nCommonSize = sizeof(struct iphdr) + sizeof(struct udphdr);
290518678f8Sopenharmony_ci    if (count < nCommonSize) {
291518678f8Sopenharmony_ci        DHCP_LOGE("CheckReadBytes() read size:%{public}d less than common size:%{public}d!", count, nCommonSize);
292518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
293518678f8Sopenharmony_ci    }
294518678f8Sopenharmony_ci
295518678f8Sopenharmony_ci    if (count < totLen) {
296518678f8Sopenharmony_ci        DHCP_LOGE("CheckReadBytes() count:%{public}d less than totLen:%{public}d, packet is Truncated!", count, totLen);
297518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
298518678f8Sopenharmony_ci    }
299518678f8Sopenharmony_ci
300518678f8Sopenharmony_ci    DHCP_LOGI("CheckReadBytes() count:%{public}d, tot:%{public}d, common:%{public}d.", count, totLen, nCommonSize);
301518678f8Sopenharmony_ci    return SOCKET_OPT_SUCCESS;
302518678f8Sopenharmony_ci}
303518678f8Sopenharmony_ci
304518678f8Sopenharmony_ciint CheckUdpPacket(struct UdpDhcpPacket *pPacket, const int totLen)
305518678f8Sopenharmony_ci{
306518678f8Sopenharmony_ci    if (pPacket == NULL) {
307518678f8Sopenharmony_ci        DHCP_LOGE("CheckUdpPacket() failed, pPacket == NULL!");
308518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
309518678f8Sopenharmony_ci    }
310518678f8Sopenharmony_ci
311518678f8Sopenharmony_ci    if (totLen > (int)sizeof(struct UdpDhcpPacket)) {
312518678f8Sopenharmony_ci        DHCP_LOGE("CheckUdpPacket() totLen:%{public}d more than %{public}d!", totLen,
313518678f8Sopenharmony_ci            (int)sizeof(struct UdpDhcpPacket));
314518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
315518678f8Sopenharmony_ci    }
316518678f8Sopenharmony_ci
317518678f8Sopenharmony_ci    if ((pPacket->ip.protocol != IPPROTO_UDP) || (pPacket->ip.version != IPVERSION)) {
318518678f8Sopenharmony_ci        DHCP_LOGE("CheckUdpPacket() failed, pPacket->ip.protocol:%{public}d or version:%{public}u error!",
319518678f8Sopenharmony_ci            pPacket->ip.protocol, pPacket->ip.version);
320518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
321518678f8Sopenharmony_ci    }
322518678f8Sopenharmony_ci
323518678f8Sopenharmony_ci    uint32_t uIhl = (uint32_t)(sizeof(pPacket->ip) >> DHCP_UINT16_BYTES);
324518678f8Sopenharmony_ci    if (pPacket->ip.ihl != uIhl) {
325518678f8Sopenharmony_ci        DHCP_LOGE("CheckUdpPacket() failed, pPacket->ip.ihl:%{public}u error, uIhl:%{public}u!", pPacket->ip.ihl, uIhl);
326518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
327518678f8Sopenharmony_ci    }
328518678f8Sopenharmony_ci
329518678f8Sopenharmony_ci    if (pPacket->udp.dest != htons(BOOTP_CLIENT)) {
330518678f8Sopenharmony_ci        DHCP_LOGE("CheckUdpPacket() failed, pPacket->udp.dest:%{public}d error, htons:%{public}d!",
331518678f8Sopenharmony_ci            pPacket->udp.dest, htons(BOOTP_CLIENT));
332518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
333518678f8Sopenharmony_ci    }
334518678f8Sopenharmony_ci
335518678f8Sopenharmony_ci    uint16_t uLen = (uint16_t)(totLen - (int)sizeof(pPacket->ip));
336518678f8Sopenharmony_ci    if (ntohs(pPacket->udp.len) != uLen) {
337518678f8Sopenharmony_ci        DHCP_LOGE("CheckUdpPacket() failed, pPacket->udp.len:%{public}d error, uLen:%{public}d!",
338518678f8Sopenharmony_ci            pPacket->udp.len, uLen);
339518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
340518678f8Sopenharmony_ci    }
341518678f8Sopenharmony_ci    DHCP_LOGI("CheckUdpPacket() success, totLen:%{public}d.", totLen);
342518678f8Sopenharmony_ci    return SOCKET_OPT_SUCCESS;
343518678f8Sopenharmony_ci}
344518678f8Sopenharmony_ci
345518678f8Sopenharmony_ciint CheckPacketIpSum(struct UdpDhcpPacket *pPacket, const int bytes)
346518678f8Sopenharmony_ci{
347518678f8Sopenharmony_ci    if (pPacket == NULL) {
348518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
349518678f8Sopenharmony_ci    }
350518678f8Sopenharmony_ci
351518678f8Sopenharmony_ci    if (CheckUdpPacket(pPacket, bytes) != SOCKET_OPT_SUCCESS) {
352518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
353518678f8Sopenharmony_ci    }
354518678f8Sopenharmony_ci
355518678f8Sopenharmony_ci    /* Check packet ip sum. */
356518678f8Sopenharmony_ci    uint16_t uCheck = pPacket->ip.check;
357518678f8Sopenharmony_ci    pPacket->ip.check = 0;
358518678f8Sopenharmony_ci    uint16_t uCheckSum = GetCheckSum((uint16_t *)&(pPacket->ip), sizeof(pPacket->ip));
359518678f8Sopenharmony_ci    if (uCheck != uCheckSum) {
360518678f8Sopenharmony_ci        DHCP_LOGE("CheckPacketIpSum() failed, ip.check:%{public}d, uCheckSum:%{public}d!", uCheck, uCheckSum);
361518678f8Sopenharmony_ci        return SOCKET_OPT_ERROR;
362518678f8Sopenharmony_ci    }
363518678f8Sopenharmony_ci    DHCP_LOGI("CheckPacketIpSum() success, bytes:%{public}d.", bytes);
364518678f8Sopenharmony_ci    return SOCKET_OPT_SUCCESS;
365518678f8Sopenharmony_ci}
366518678f8Sopenharmony_ci
367518678f8Sopenharmony_ciint CheckPacketUdpSum(struct UdpDhcpPacket *pPacket, const int bytes)
368518678f8Sopenharmony_ci{
369518678f8Sopenharmony_ci    if (pPacket == NULL) {
370518678f8Sopenharmony_ci        DHCP_LOGE("CheckPacketUdpSum() failed, pPacket == NULL!");
371518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
372518678f8Sopenharmony_ci    }
373518678f8Sopenharmony_ci
374518678f8Sopenharmony_ci    /* Check packet udp sum. */
375518678f8Sopenharmony_ci    uint16_t uCheck = pPacket->udp.check;
376518678f8Sopenharmony_ci    pPacket->udp.check = 0;
377518678f8Sopenharmony_ci    u_int32_t source = pPacket->ip.saddr;
378518678f8Sopenharmony_ci    u_int32_t dest = pPacket->ip.daddr;
379518678f8Sopenharmony_ci    if (memset_s(&pPacket->ip, sizeof(pPacket->ip), 0, sizeof(pPacket->ip)) != EOK) {
380518678f8Sopenharmony_ci        DHCP_LOGE("CheckPacketUdpSum() failed, memset_s ERROR!");
381518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
382518678f8Sopenharmony_ci    }
383518678f8Sopenharmony_ci    pPacket->ip.protocol = IPPROTO_UDP;
384518678f8Sopenharmony_ci    pPacket->ip.saddr = source;
385518678f8Sopenharmony_ci    pPacket->ip.daddr = dest;
386518678f8Sopenharmony_ci    pPacket->ip.tot_len = pPacket->udp.len;
387518678f8Sopenharmony_ci    uint16_t uCheckSum = GetCheckSum((uint16_t *)pPacket, bytes);
388518678f8Sopenharmony_ci    if (uCheck && (uCheck != uCheckSum)) {
389518678f8Sopenharmony_ci        DHCP_LOGE("CheckPacketUdpSum() failed, udp.check:%{public}d, uCheckSum:%{public}d!", uCheck, uCheckSum);
390518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
391518678f8Sopenharmony_ci    }
392518678f8Sopenharmony_ci    DHCP_LOGI("CheckPacketUdpSum() success, bytes:%{public}d.", bytes);
393518678f8Sopenharmony_ci    return SOCKET_OPT_SUCCESS;
394518678f8Sopenharmony_ci}
395518678f8Sopenharmony_ci
396518678f8Sopenharmony_ciint GetDhcpRawPacket(struct DhcpPacket *getPacket, int rawFd)
397518678f8Sopenharmony_ci{
398518678f8Sopenharmony_ci    if (getPacket == NULL) {
399518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
400518678f8Sopenharmony_ci    }
401518678f8Sopenharmony_ci
402518678f8Sopenharmony_ci    /* Get and check udp dhcp packet bytes. */
403518678f8Sopenharmony_ci    struct UdpDhcpPacket udpPackets;
404518678f8Sopenharmony_ci    if (memset_s(&udpPackets, sizeof(struct UdpDhcpPacket), 0, sizeof(struct UdpDhcpPacket)) != EOK) {
405518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
406518678f8Sopenharmony_ci    }
407518678f8Sopenharmony_ci    int nBytes = read(rawFd, &udpPackets, sizeof(struct UdpDhcpPacket));
408518678f8Sopenharmony_ci    int nRet = CheckReadBytes(nBytes, (int)ntohs(udpPackets.ip.tot_len));
409518678f8Sopenharmony_ci    if (nRet != SOCKET_OPT_SUCCESS) {
410518678f8Sopenharmony_ci        usleep(SLEEP_TIME_200_MS);
411518678f8Sopenharmony_ci        return nRet;
412518678f8Sopenharmony_ci    }
413518678f8Sopenharmony_ci
414518678f8Sopenharmony_ci    /* Check udp dhcp packet sum. */
415518678f8Sopenharmony_ci    nBytes = (int)ntohs(udpPackets.ip.tot_len);
416518678f8Sopenharmony_ci    nRet = CheckPacketIpSum(&udpPackets, nBytes);
417518678f8Sopenharmony_ci    if (nRet != SOCKET_OPT_SUCCESS) {
418518678f8Sopenharmony_ci        return nRet;
419518678f8Sopenharmony_ci    }
420518678f8Sopenharmony_ci    nRet = CheckPacketUdpSum(&udpPackets, nBytes);
421518678f8Sopenharmony_ci    if (nRet != SOCKET_OPT_SUCCESS) {
422518678f8Sopenharmony_ci        return nRet;
423518678f8Sopenharmony_ci    }
424518678f8Sopenharmony_ci
425518678f8Sopenharmony_ci    int nDhcpPacket = nBytes - (int)(sizeof(udpPackets.ip) + sizeof(udpPackets.udp));
426518678f8Sopenharmony_ci    if (memcpy_s(getPacket, sizeof(struct DhcpPacket), &(udpPackets.data), nDhcpPacket) != EOK) {
427518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpRawPacket() memcpy_s packet.data failed!");
428518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
429518678f8Sopenharmony_ci    }
430518678f8Sopenharmony_ci    if (ntohl(getPacket->cookie) != MAGIC_COOKIE) {
431518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpRawPacket() cook:%{public}x error, COOK:%{public}x!", ntohl(getPacket->cookie), MAGIC_COOKIE);
432518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
433518678f8Sopenharmony_ci    }
434518678f8Sopenharmony_ci    return nDhcpPacket;
435518678f8Sopenharmony_ci}
436518678f8Sopenharmony_ci
437518678f8Sopenharmony_ciint GetDhcpKernelPacket(struct DhcpPacket *getPacket, int sockFd)
438518678f8Sopenharmony_ci{
439518678f8Sopenharmony_ci    if (getPacket == NULL) {
440518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
441518678f8Sopenharmony_ci    }
442518678f8Sopenharmony_ci
443518678f8Sopenharmony_ci    int nBytes = -1;
444518678f8Sopenharmony_ci    if ((nBytes = read(sockFd, getPacket, sizeof(struct DhcpPacket))) == -1) {
445518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpKernelPacket() couldn't read on kernel listening socket, error:%{public}d!", errno);
446518678f8Sopenharmony_ci        return SOCKET_OPT_ERROR;
447518678f8Sopenharmony_ci    }
448518678f8Sopenharmony_ci
449518678f8Sopenharmony_ci    if (ntohl(getPacket->cookie) != MAGIC_COOKIE) {
450518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpKernelPacket() cook:%{public}x error, COOK:%{public}x!", ntohl(getPacket->cookie),
451518678f8Sopenharmony_ci            MAGIC_COOKIE);
452518678f8Sopenharmony_ci        return SOCKET_OPT_FAILED;
453518678f8Sopenharmony_ci    }
454518678f8Sopenharmony_ci    return nBytes;
455518678f8Sopenharmony_ci}
456