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_options.h"
16518678f8Sopenharmony_ci
17518678f8Sopenharmony_ci#include <stdio.h>
18518678f8Sopenharmony_ci#include <stdlib.h>
19518678f8Sopenharmony_ci#include <string.h>
20518678f8Sopenharmony_ci
21518678f8Sopenharmony_ci#include "securec.h"
22518678f8Sopenharmony_ci#include "dhcp_logger.h"
23518678f8Sopenharmony_ci
24518678f8Sopenharmony_ciDEFINE_DHCPLOG_DHCP_LABEL("DhcpOptions");
25518678f8Sopenharmony_ci
26518678f8Sopenharmony_ci/* Check packet option OPTION_OVERLOAD_OPTION. */
27518678f8Sopenharmony_cistatic bool CheckOptSoverloaded(const struct DhcpPacket *packet, int code, int maxLen, int *over, int *index)
28518678f8Sopenharmony_ci{
29518678f8Sopenharmony_ci    if (packet == nullptr) {
30518678f8Sopenharmony_ci        DHCP_LOGE("CheckOptSoverloaded failed, packet == nullptr!");
31518678f8Sopenharmony_ci        return false;
32518678f8Sopenharmony_ci    }
33518678f8Sopenharmony_ci
34518678f8Sopenharmony_ci    const uint8_t *pOption = packet->options;
35518678f8Sopenharmony_ci    if (*index + DHCP_OPT_LEN_INDEX + pOption[*index + DHCP_OPT_LEN_INDEX] >= maxLen) {
36518678f8Sopenharmony_ci        DHCP_LOGW("CheckOptSoverloaded code:%{public}d,*index:%{public}d more than max bytes:%{public}d!",
37518678f8Sopenharmony_ci            code, *index, maxLen);
38518678f8Sopenharmony_ci        return false;
39518678f8Sopenharmony_ci    }
40518678f8Sopenharmony_ci    *over = pOption[*index + DHCP_OPT_DATA_INDEX + DHCP_OPT_CODE_INDEX];
41518678f8Sopenharmony_ci    *index += pOption[DHCP_OPT_LEN_INDEX] + DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES;
42518678f8Sopenharmony_ci    return true;
43518678f8Sopenharmony_ci}
44518678f8Sopenharmony_ci
45518678f8Sopenharmony_ci/* Check packet options based on the code and index. */
46518678f8Sopenharmony_cistatic int CheckOptionsData(const struct DhcpPacket *packet, int code, int index, int maxLen)
47518678f8Sopenharmony_ci{
48518678f8Sopenharmony_ci    if (packet == nullptr) {
49518678f8Sopenharmony_ci        DHCP_LOGE("CheckOptionsData failed, packet == nullptr!");
50518678f8Sopenharmony_ci        return DHCP_OPT_FAILED;
51518678f8Sopenharmony_ci    }
52518678f8Sopenharmony_ci
53518678f8Sopenharmony_ci    if (index >= maxLen - DHCP_OPT_DATA_INDEX) {
54518678f8Sopenharmony_ci        DHCP_LOGW("CheckOptionsData code:%{public}d,index:%{public}d more than max bytes:%{public}d!",
55518678f8Sopenharmony_ci            code, index, maxLen);
56518678f8Sopenharmony_ci        return DHCP_OPT_FAILED;
57518678f8Sopenharmony_ci    }
58518678f8Sopenharmony_ci
59518678f8Sopenharmony_ci    const uint8_t *pOption = packet->options;
60518678f8Sopenharmony_ci    if (pOption[index + DHCP_OPT_CODE_INDEX] != code) {
61518678f8Sopenharmony_ci        return DHCP_OPT_NONE;
62518678f8Sopenharmony_ci    }
63518678f8Sopenharmony_ci
64518678f8Sopenharmony_ci    if (index + DHCP_OPT_LEN_INDEX + pOption[index + DHCP_OPT_LEN_INDEX] >= maxLen) {
65518678f8Sopenharmony_ci        DHCP_LOGW("CheckOptionsData failed, options data too long, code:%{public}d,index:%{public}d!", code, index);
66518678f8Sopenharmony_ci        return DHCP_OPT_FAILED;
67518678f8Sopenharmony_ci    }
68518678f8Sopenharmony_ci
69518678f8Sopenharmony_ci    return DHCP_OPT_SUCCESS;
70518678f8Sopenharmony_ci}
71518678f8Sopenharmony_ci
72518678f8Sopenharmony_ci/* Obtains the data type based on the code. */
73518678f8Sopenharmony_cistatic uint8_t GetDhcpOptionCodeType(const uint8_t code)
74518678f8Sopenharmony_ci{
75518678f8Sopenharmony_ci    if ((code <= PAD_OPTION) || (code >= END_OPTION)) {
76518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpOptionCodeType error, code:%{public}d is error!", code);
77518678f8Sopenharmony_ci        return DHCP_OPTION_DATA_INVALID;
78518678f8Sopenharmony_ci    }
79518678f8Sopenharmony_ci
80518678f8Sopenharmony_ci    uint8_t nDataType = DHCP_OPTION_DATA_INVALID;
81518678f8Sopenharmony_ci    switch (code) {
82518678f8Sopenharmony_ci        case DHCP_MESSAGE_TYPE_OPTION:
83518678f8Sopenharmony_ci        case FORCERENEW_NONCE_OPTION:
84518678f8Sopenharmony_ci            nDataType = DHCP_OPTION_DATA_U8;
85518678f8Sopenharmony_ci            break;
86518678f8Sopenharmony_ci        case INTERFACE_MTU_OPTION:
87518678f8Sopenharmony_ci        case MAXIMUM_DHCP_MESSAGE_SIZE_OPTION:
88518678f8Sopenharmony_ci            nDataType = DHCP_OPTION_DATA_U16;
89518678f8Sopenharmony_ci            break;
90518678f8Sopenharmony_ci        case IP_ADDRESS_LEASE_TIME_OPTION:
91518678f8Sopenharmony_ci            nDataType = DHCP_OPTION_DATA_U32;
92518678f8Sopenharmony_ci            break;
93518678f8Sopenharmony_ci        case SUBNET_MASK_OPTION:
94518678f8Sopenharmony_ci        case BROADCAST_ADDRESS_OPTION:
95518678f8Sopenharmony_ci        case REQUESTED_IP_ADDRESS_OPTION:
96518678f8Sopenharmony_ci        case SERVER_IDENTIFIER_OPTION:
97518678f8Sopenharmony_ci            nDataType = DHCP_OPTION_DATA_IP;
98518678f8Sopenharmony_ci            break;
99518678f8Sopenharmony_ci        case ROUTER_OPTION:
100518678f8Sopenharmony_ci        case DOMAIN_NAME_SERVER_OPTION:
101518678f8Sopenharmony_ci        case NETWORK_TIME_PROTOCOL_SERVERS_OPTION:
102518678f8Sopenharmony_ci            nDataType = DHCP_OPTION_DATA_IP_LIST;
103518678f8Sopenharmony_ci            break;
104518678f8Sopenharmony_ci        case HOST_NAME_OPTION:
105518678f8Sopenharmony_ci        case DOMAIN_NAME_OPTION:
106518678f8Sopenharmony_ci        case MESSAGE_OPTION:
107518678f8Sopenharmony_ci            nDataType = DHCP_OPTION_DATA_IP_STRING;
108518678f8Sopenharmony_ci            break;
109518678f8Sopenharmony_ci        default:
110518678f8Sopenharmony_ci            DHCP_LOGE("GetDhcpOptionCodeType failed, code:%{public}d is invalid!", code);
111518678f8Sopenharmony_ci            break;
112518678f8Sopenharmony_ci    }
113518678f8Sopenharmony_ci
114518678f8Sopenharmony_ci    return nDataType;
115518678f8Sopenharmony_ci}
116518678f8Sopenharmony_ci
117518678f8Sopenharmony_ci/* Obtains the data length based on the code. */
118518678f8Sopenharmony_ciuint8_t GetDhcpOptionDataLen(const uint8_t code)
119518678f8Sopenharmony_ci{
120518678f8Sopenharmony_ci    uint8_t nDataType = GetDhcpOptionCodeType(code);
121518678f8Sopenharmony_ci    if (nDataType == DHCP_OPTION_DATA_INVALID) {
122518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpOptionDataLen code:%{public}d error, GetDhcpOptionCodeType invalid!", code);
123518678f8Sopenharmony_ci        return 0;
124518678f8Sopenharmony_ci    }
125518678f8Sopenharmony_ci
126518678f8Sopenharmony_ci    uint8_t nDataLen = 0;
127518678f8Sopenharmony_ci    switch (nDataType) {
128518678f8Sopenharmony_ci        case DHCP_OPTION_DATA_U8:
129518678f8Sopenharmony_ci            nDataLen = DHCP_UINT8_BYTES;
130518678f8Sopenharmony_ci            break;
131518678f8Sopenharmony_ci        case DHCP_OPTION_DATA_U16:
132518678f8Sopenharmony_ci            nDataLen = DHCP_UINT16_BYTES;
133518678f8Sopenharmony_ci            break;
134518678f8Sopenharmony_ci        case DHCP_OPTION_DATA_U32:
135518678f8Sopenharmony_ci            nDataLen = DHCP_UINT32_BYTES;
136518678f8Sopenharmony_ci            break;
137518678f8Sopenharmony_ci        case DHCP_OPTION_DATA_IP:
138518678f8Sopenharmony_ci            nDataLen = DHCP_UINT32_BYTES;
139518678f8Sopenharmony_ci            break;
140518678f8Sopenharmony_ci        case DHCP_OPTION_DATA_IP_PAIR:
141518678f8Sopenharmony_ci            nDataLen = DHCP_UINT32_DOUBLE_BYTES;
142518678f8Sopenharmony_ci            break;
143518678f8Sopenharmony_ci        default:
144518678f8Sopenharmony_ci            DHCP_LOGE("GetDhcpOptionDataLen code:%{public}d failed, nDataType:%{public}d is invalid!",
145518678f8Sopenharmony_ci                code, nDataType);
146518678f8Sopenharmony_ci            break;
147518678f8Sopenharmony_ci    }
148518678f8Sopenharmony_ci
149518678f8Sopenharmony_ci    return nDataLen;
150518678f8Sopenharmony_ci}
151518678f8Sopenharmony_ci
152518678f8Sopenharmony_ci/* Obtains the data pointer and length from the packet based on the code. */
153518678f8Sopenharmony_ciconst uint8_t *GetDhcpOption(const struct DhcpPacket *packet, int code, size_t *length)
154518678f8Sopenharmony_ci{
155518678f8Sopenharmony_ci    *length = 0;
156518678f8Sopenharmony_ci    if (packet == nullptr) {
157518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpOption failed, packet == nullptr!");
158518678f8Sopenharmony_ci        return nullptr;
159518678f8Sopenharmony_ci    }
160518678f8Sopenharmony_ci
161518678f8Sopenharmony_ci    const uint8_t *pOption = packet->options;
162518678f8Sopenharmony_ci    int nIndex = 0, maxLen = DHCP_OPT_SIZE, nOver = 0, nFinished = 0, nFlag = OPTION_FIELD;
163518678f8Sopenharmony_ci    while (nFinished == 0) {
164518678f8Sopenharmony_ci        int nRet = CheckOptionsData(packet, code, nIndex, maxLen);
165518678f8Sopenharmony_ci        if (nRet == DHCP_OPT_SUCCESS) {
166518678f8Sopenharmony_ci            *length = pOption[nIndex + DHCP_OPT_LEN_INDEX];
167518678f8Sopenharmony_ci            return pOption + nIndex + DHCP_OPT_DATA_INDEX;
168518678f8Sopenharmony_ci        } else if (nRet == DHCP_OPT_FAILED) {
169518678f8Sopenharmony_ci            return nullptr;
170518678f8Sopenharmony_ci        }
171518678f8Sopenharmony_ci
172518678f8Sopenharmony_ci        switch (pOption[nIndex + DHCP_OPT_CODE_INDEX]) {
173518678f8Sopenharmony_ci            case PAD_OPTION:
174518678f8Sopenharmony_ci                nIndex++;
175518678f8Sopenharmony_ci                break;
176518678f8Sopenharmony_ci            case OPTION_OVERLOAD_OPTION:
177518678f8Sopenharmony_ci                if (!CheckOptSoverloaded(packet, code, maxLen, &nOver, &nIndex)) {
178518678f8Sopenharmony_ci                    return nullptr;
179518678f8Sopenharmony_ci                }
180518678f8Sopenharmony_ci                break;
181518678f8Sopenharmony_ci            case END_OPTION:
182518678f8Sopenharmony_ci                if ((nFlag == OPTION_FIELD) && (nOver & FILE_FIELD)) {
183518678f8Sopenharmony_ci                    pOption = packet->file;
184518678f8Sopenharmony_ci                    nIndex = 0;
185518678f8Sopenharmony_ci                    maxLen = DHCP_BOOT_FILE_LENGTH;
186518678f8Sopenharmony_ci                    nFlag = FILE_FIELD;
187518678f8Sopenharmony_ci                } else if ((nFlag == FILE_FIELD) && (nOver & SNAME_FIELD)) {
188518678f8Sopenharmony_ci                    pOption = packet->sname;
189518678f8Sopenharmony_ci                    nIndex = 0;
190518678f8Sopenharmony_ci                    maxLen = DHCP_HOST_NAME_LENGTH;
191518678f8Sopenharmony_ci                    nFlag = SNAME_FIELD;
192518678f8Sopenharmony_ci                } else {
193518678f8Sopenharmony_ci                    nFinished = 1;
194518678f8Sopenharmony_ci                }
195518678f8Sopenharmony_ci                break;
196518678f8Sopenharmony_ci            default:
197518678f8Sopenharmony_ci                nIndex += DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES + pOption[nIndex + DHCP_OPT_LEN_INDEX];
198518678f8Sopenharmony_ci                break;
199518678f8Sopenharmony_ci        }
200518678f8Sopenharmony_ci    }
201518678f8Sopenharmony_ci    DHCP_LOGW("GetDhcpOption options no find code:%{public}d, nIndex:%{public}d!", code, nIndex);
202518678f8Sopenharmony_ci    return nullptr;
203518678f8Sopenharmony_ci}
204518678f8Sopenharmony_ci
205518678f8Sopenharmony_ci/* Obtains the uint8 data from the packet based on the code. */
206518678f8Sopenharmony_cibool GetDhcpOptionUint8(const struct DhcpPacket *packet, int code, uint8_t *data)
207518678f8Sopenharmony_ci{
208518678f8Sopenharmony_ci    size_t len = 0;
209518678f8Sopenharmony_ci    const uint8_t *p = GetDhcpOption(packet, code, &len);
210518678f8Sopenharmony_ci    if (p == nullptr) {
211518678f8Sopenharmony_ci        DHCP_LOGW("GetDhcpOptionUint8 GetDhcpOption nullptr, code:%{public}d!", code);
212518678f8Sopenharmony_ci        return false;
213518678f8Sopenharmony_ci    }
214518678f8Sopenharmony_ci    if (len < static_cast<size_t>(sizeof(uint8_t))) {
215518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpOptionUint8 failed, len:%{public}zu less data:%{public}zu, code:%{public}d!",
216518678f8Sopenharmony_ci            len, sizeof(uint8_t), code);
217518678f8Sopenharmony_ci        return false;
218518678f8Sopenharmony_ci    }
219518678f8Sopenharmony_ci    if (memcpy_s(data, sizeof(uint8_t), p, sizeof(uint8_t)) != EOK) {
220518678f8Sopenharmony_ci        return false;
221518678f8Sopenharmony_ci    }
222518678f8Sopenharmony_ci    return true;
223518678f8Sopenharmony_ci}
224518678f8Sopenharmony_ci
225518678f8Sopenharmony_ci/* Obtains the uint32 data from the packet based on the code. */
226518678f8Sopenharmony_cibool GetDhcpOptionUint32(const struct DhcpPacket *packet, int code, uint32_t *data)
227518678f8Sopenharmony_ci{
228518678f8Sopenharmony_ci    size_t len = 0;
229518678f8Sopenharmony_ci    const uint8_t *p = GetDhcpOption(packet, code, &len);
230518678f8Sopenharmony_ci    if (p == nullptr) {
231518678f8Sopenharmony_ci        DHCP_LOGW("GetDhcpOptionUint32 GetDhcpOption nullptr, code:%{public}d!", code);
232518678f8Sopenharmony_ci        return false;
233518678f8Sopenharmony_ci    }
234518678f8Sopenharmony_ci    uint32_t uData = 0;
235518678f8Sopenharmony_ci    if (len < static_cast<size_t>(sizeof(uData))) {
236518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpOptionUint32 failed, len:%{public}zu less uData:%{public}zu, code:%{public}d!",
237518678f8Sopenharmony_ci            len, sizeof(uData), code);
238518678f8Sopenharmony_ci        return false;
239518678f8Sopenharmony_ci    }
240518678f8Sopenharmony_ci    if (memcpy_s(&uData, sizeof(uData), p, sizeof(uData)) != EOK) {
241518678f8Sopenharmony_ci        return false;
242518678f8Sopenharmony_ci    }
243518678f8Sopenharmony_ci    if (uData > 0) {
244518678f8Sopenharmony_ci        *data = ntohl(uData);
245518678f8Sopenharmony_ci    }
246518678f8Sopenharmony_ci    return true;
247518678f8Sopenharmony_ci}
248518678f8Sopenharmony_ci
249518678f8Sopenharmony_ci/* Obtains the uint32n data from the packet based on the code. */
250518678f8Sopenharmony_cibool GetDhcpOptionUint32n(const struct DhcpPacket *packet, int code, uint32_t *data1, uint32_t *data2)
251518678f8Sopenharmony_ci{
252518678f8Sopenharmony_ci    size_t len = 0;
253518678f8Sopenharmony_ci    const uint8_t *p = GetDhcpOption(packet, code, &len);
254518678f8Sopenharmony_ci    if (p == nullptr) {
255518678f8Sopenharmony_ci        DHCP_LOGW("GetDhcpOptionUint32n GetDhcpOption nullptr, code:%{public}d!", code);
256518678f8Sopenharmony_ci        return false;
257518678f8Sopenharmony_ci    }
258518678f8Sopenharmony_ci    uint32_t uData = 0;
259518678f8Sopenharmony_ci    if ((len < static_cast<size_t>(sizeof(uData))) || (len % static_cast<size_t>(sizeof(uData)) != 0)) {
260518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpOptionUint32n failed, len:%{public}zu is not %{public}zu * n, code:%{public}d!",
261518678f8Sopenharmony_ci            len, sizeof(uData), code);
262518678f8Sopenharmony_ci        return false;
263518678f8Sopenharmony_ci    }
264518678f8Sopenharmony_ci    if (memcpy_s(&uData, sizeof(uData), p, sizeof(uData)) != EOK) {
265518678f8Sopenharmony_ci        return false;
266518678f8Sopenharmony_ci    }
267518678f8Sopenharmony_ci    if (uData > 0) {
268518678f8Sopenharmony_ci        *data1 = ntohl(uData);
269518678f8Sopenharmony_ci    }
270518678f8Sopenharmony_ci    if (len > static_cast<size_t>(sizeof(uData))) {
271518678f8Sopenharmony_ci        p += sizeof(uData);
272518678f8Sopenharmony_ci        uData = 0;
273518678f8Sopenharmony_ci        if (memcpy_s(&uData, sizeof(uData), p, sizeof(uData)) != EOK) {
274518678f8Sopenharmony_ci            return false;
275518678f8Sopenharmony_ci        }
276518678f8Sopenharmony_ci        if (uData > 0) {
277518678f8Sopenharmony_ci            *data2 = ntohl(uData);
278518678f8Sopenharmony_ci        }
279518678f8Sopenharmony_ci    }
280518678f8Sopenharmony_ci    return true;
281518678f8Sopenharmony_ci}
282518678f8Sopenharmony_ci
283518678f8Sopenharmony_ci/* Obtains the string data from the packet based on the code. */
284518678f8Sopenharmony_cichar *GetDhcpOptionString(const struct DhcpPacket *packet, int code)
285518678f8Sopenharmony_ci{
286518678f8Sopenharmony_ci    size_t len;
287518678f8Sopenharmony_ci    const uint8_t *p = GetDhcpOption(packet, code, &len);
288518678f8Sopenharmony_ci    if ((p == nullptr) || (*p == '\0')) {
289518678f8Sopenharmony_ci        DHCP_LOGW("GetDhcpOptionString GetDhcpOption nullptr, code:%{public}d!", code);
290518678f8Sopenharmony_ci        return nullptr;
291518678f8Sopenharmony_ci    }
292518678f8Sopenharmony_ci    if (len < static_cast<size_t>(sizeof(uint8_t))) {
293518678f8Sopenharmony_ci        DHCP_LOGE("GetDhcpOptionString failed, len:%{public}zu less data:%{public}zu, code:%{public}d!",
294518678f8Sopenharmony_ci            len, sizeof(uint8_t), code);
295518678f8Sopenharmony_ci        return nullptr;
296518678f8Sopenharmony_ci    }
297518678f8Sopenharmony_ci
298518678f8Sopenharmony_ci    char *s = (char *)malloc(sizeof(char) * (len + 1));
299518678f8Sopenharmony_ci    if (s) {
300518678f8Sopenharmony_ci        if (memcpy_s(s, len + 1, p, len) != EOK) {
301518678f8Sopenharmony_ci            free(s);
302518678f8Sopenharmony_ci            s = nullptr;
303518678f8Sopenharmony_ci            return nullptr;
304518678f8Sopenharmony_ci        }
305518678f8Sopenharmony_ci        s[len] = '\0';
306518678f8Sopenharmony_ci    }
307518678f8Sopenharmony_ci    return s;
308518678f8Sopenharmony_ci}
309518678f8Sopenharmony_ci
310518678f8Sopenharmony_ci/* Obtain the end index from options. */
311518678f8Sopenharmony_ciint GetEndOptionIndex(const uint8_t *pOpts)
312518678f8Sopenharmony_ci{
313518678f8Sopenharmony_ci    int nIndex = 0;
314518678f8Sopenharmony_ci    while (pOpts[nIndex] != END_OPTION) {
315518678f8Sopenharmony_ci        if (pOpts[nIndex] != PAD_OPTION) {
316518678f8Sopenharmony_ci            nIndex += pOpts[nIndex + DHCP_OPT_LEN_INDEX] + DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES;
317518678f8Sopenharmony_ci            continue;
318518678f8Sopenharmony_ci        }
319518678f8Sopenharmony_ci        nIndex++;
320518678f8Sopenharmony_ci    }
321518678f8Sopenharmony_ci    return nIndex;
322518678f8Sopenharmony_ci}
323518678f8Sopenharmony_ci
324518678f8Sopenharmony_ci/* Adds a single option string to options. */
325518678f8Sopenharmony_ciint AddOptStrToOpts(uint8_t *pOpts, uint8_t *pOpt, int nOptLen)
326518678f8Sopenharmony_ci{
327518678f8Sopenharmony_ci    int optStrLen = DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES + pOpt[DHCP_OPT_LEN_INDEX];
328518678f8Sopenharmony_ci    if (nOptLen != optStrLen) {
329518678f8Sopenharmony_ci        DHCP_LOGE("AddOptStrToOpts() code:%{public}u nOptLen:%{public}d no equal optStrLen:%{public}d!",
330518678f8Sopenharmony_ci            pOpt[DHCP_OPT_CODE_INDEX], nOptLen, optStrLen);
331518678f8Sopenharmony_ci        return 0;
332518678f8Sopenharmony_ci    }
333518678f8Sopenharmony_ci
334518678f8Sopenharmony_ci    int nEndIndex = GetEndOptionIndex(pOpts);
335518678f8Sopenharmony_ci    if ((nEndIndex + nOptLen + 1) >= DHCP_OPT_SIZE) {
336518678f8Sopenharmony_ci        DHCP_LOGE("AddOptStrToOpts() code:%{public}u did not fit into the packet!", pOpt[DHCP_OPT_CODE_INDEX]);
337518678f8Sopenharmony_ci        return 0;
338518678f8Sopenharmony_ci    }
339518678f8Sopenharmony_ci
340518678f8Sopenharmony_ci    DHCP_LOGD("AddOptStrToOpts() adding option code %{public}u.", pOpt[DHCP_OPT_CODE_INDEX]);
341518678f8Sopenharmony_ci    if (memcpy_s(pOpts + nEndIndex, nOptLen + 1, pOpt, nOptLen) != EOK) {
342518678f8Sopenharmony_ci        return 0;
343518678f8Sopenharmony_ci    }
344518678f8Sopenharmony_ci    pOpts[nEndIndex + nOptLen] = END_OPTION;
345518678f8Sopenharmony_ci    return nOptLen;
346518678f8Sopenharmony_ci}
347518678f8Sopenharmony_ci
348518678f8Sopenharmony_ci/* Adds a single option value to options. */
349518678f8Sopenharmony_ciint AddOptValueToOpts(uint8_t *pOpts, uint8_t code, uint32_t value)
350518678f8Sopenharmony_ci{
351518678f8Sopenharmony_ci    uint8_t uLen = GetDhcpOptionDataLen(code);
352518678f8Sopenharmony_ci    if (uLen == 0) {
353518678f8Sopenharmony_ci        DHCP_LOGE("AddOptValueToOpts() code:%{public}d failed, GetDhcpOptionDataLen uLen:0!", code);
354518678f8Sopenharmony_ci        return 0;
355518678f8Sopenharmony_ci    }
356518678f8Sopenharmony_ci
357518678f8Sopenharmony_ci    uint32_t uValue = 0;
358518678f8Sopenharmony_ci    uint8_t *pUint8 = (uint8_t *)&uValue;
359518678f8Sopenharmony_ci    uint16_t *pUint16 = (uint16_t *)&uValue;
360518678f8Sopenharmony_ci    uint32_t *pUint32 = &uValue;
361518678f8Sopenharmony_ci    switch (uLen) {
362518678f8Sopenharmony_ci        case DHCP_UINT8_BYTES:
363518678f8Sopenharmony_ci            *pUint8 =  value;
364518678f8Sopenharmony_ci            break;
365518678f8Sopenharmony_ci        case DHCP_UINT16_BYTES:
366518678f8Sopenharmony_ci            *pUint16 = htons(static_cast<uint16_t>(value));
367518678f8Sopenharmony_ci            break;
368518678f8Sopenharmony_ci        case DHCP_UINT32_BYTES:
369518678f8Sopenharmony_ci            *pUint32 = value;
370518678f8Sopenharmony_ci            break;
371518678f8Sopenharmony_ci        default:
372518678f8Sopenharmony_ci            DHCP_LOGE("AddOptValueToOpts() uLen:%{public}d error, break!", uLen);
373518678f8Sopenharmony_ci            break;
374518678f8Sopenharmony_ci    }
375518678f8Sopenharmony_ci
376518678f8Sopenharmony_ci    uint8_t uOption[DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES + DHCP_UINT32_BYTES];
377518678f8Sopenharmony_ci    uOption[DHCP_OPT_CODE_INDEX] = code;
378518678f8Sopenharmony_ci    uOption[DHCP_OPT_LEN_INDEX] = uLen;
379518678f8Sopenharmony_ci    if (memcpy_s(uOption + DHCP_OPT_DATA_INDEX, sizeof(uint32_t), &uValue, uLen) != EOK) {
380518678f8Sopenharmony_ci        return 0;
381518678f8Sopenharmony_ci    }
382518678f8Sopenharmony_ci
383518678f8Sopenharmony_ci    int nLen = DHCP_OPT_CODE_BYTES + DHCP_OPT_LEN_BYTES + uOption[DHCP_OPT_LEN_INDEX];
384518678f8Sopenharmony_ci    return AddOptStrToOpts(pOpts, uOption, nLen);
385518678f8Sopenharmony_ci}
386