1 /*
2 * Copyright (C) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dhcp_option.h"
17 #include <stdint.h>
18 #include <cstdlib>
19 #include "dhcp_s_define.h"
20 #include "dhcp_logger.h"
21 #include "securec.h"
22
23 DEFINE_DHCPLOG_DHCP_LABEL("DhcpServerOption");
24
CreateOptionNode(PDhcpOption opt)25 PDhcpOptionNode CreateOptionNode(PDhcpOption opt)
26 {
27 if (!opt) {
28 DHCP_LOGE("input parameter is null.");
29 return nullptr;
30 }
31 DhcpOptionNode *pNode = (DhcpOptionNode *)calloc(1, sizeof(DhcpOptionNode));
32 if (pNode == nullptr) {
33 DHCP_LOGE("failed to create dhcp option node!");
34 return nullptr;
35 }
36 pNode->option.code = opt->code;
37 pNode->option.length = opt->length;
38 if (opt == nullptr || opt->length == 0) {
39 free(pNode);
40 return nullptr;
41 }
42 if (memcpy_s(pNode->option.data, sizeof(pNode->option.data), opt->data, opt->length) != EOK) {
43 DHCP_LOGE("create option node failed when memcpy opt data!");
44 free(pNode);
45 pNode = nullptr;
46 return nullptr;
47 }
48 pNode->previous = pNode->next = 0;
49 return pNode;
50 }
51
HasInitialized(PDhcpOptionList pOptions)52 int HasInitialized(PDhcpOptionList pOptions)
53 {
54 if (!pOptions) {
55 DHCP_LOGE("option list pointer is null.");
56 return 0;
57 }
58 if (pOptions->first != nullptr) {
59 return 1;
60 }
61 return 0;
62 }
63
InitOptionList(PDhcpOptionList pOptions)64 int InitOptionList(PDhcpOptionList pOptions)
65 {
66 DHCP_LOGI("start %{public}s %{public}d ", __func__, __LINE__);
67 if (!pOptions) {
68 return RET_ERROR;
69 }
70 if (pOptions->first != nullptr && pOptions->first == pOptions->last) {
71 DHCP_LOGE(" start %{public}s %{public}d over return success", __func__, __LINE__);
72 return RET_SUCCESS;
73 }
74
75 DhcpOptionNode *pNode = (DhcpOptionNode *)calloc(1, sizeof(DhcpOptionNode));
76 if (!pNode) {
77 DHCP_LOGE("failed to create dhcp option node!");
78 return 1;
79 }
80
81 pOptions->size = 0;
82 pOptions->first = pOptions->last = pNode;
83 pOptions->first->previous = nullptr;
84 pOptions->last->next = nullptr;
85 DHCP_LOGI("start %{public}s %{public}d success ", __func__, __LINE__);
86 return RET_SUCCESS;
87 }
88
PushBackOption(PDhcpOptionList pOptions,PDhcpOption pOption)89 int PushBackOption(PDhcpOptionList pOptions, PDhcpOption pOption)
90 {
91 if (!pOptions) {
92 DHCP_LOGE("option list pointer is null.");
93 return RET_ERROR;
94 }
95 if (!pOption) {
96 DHCP_LOGE("option pointer is null.");
97 return RET_ERROR;
98 }
99 if (pOptions->first == nullptr) {
100 DHCP_LOGE("option list not initialized");
101 return RET_SUCCESS;
102 }
103 DhcpOptionNode *pNode = CreateOptionNode(pOption);
104 if (!pNode) {
105 DHCP_LOGE("failed to create option node.");
106 return 1;
107 }
108 pNode->previous = pOptions->last;
109 pOptions->last->next = pNode;
110 pOptions->last = pNode;
111 pOptions->size++;
112
113 return RET_SUCCESS;
114 }
115
PushFrontOption(PDhcpOptionList pOptions,PDhcpOption pOption)116 int PushFrontOption(PDhcpOptionList pOptions, PDhcpOption pOption)
117 {
118 if (!pOptions) {
119 DHCP_LOGE("option list pointer is null.");
120 return RET_ERROR;
121 }
122 if (!pOption) {
123 DHCP_LOGE("option pointer is null.");
124 return RET_ERROR;
125 }
126 PDhcpOptionNode pNode = CreateOptionNode(pOption);
127 if (!pNode) {
128 return RET_FAILED;
129 }
130
131 if (pOptions->first == pOptions->last) {
132 pNode->previous = pOptions->first;
133 pOptions->first->next = pNode;
134 pOptions->last = pNode;
135 } else {
136 pNode->next = pOptions->first->next;
137 pNode->next->previous = pNode;
138 pNode->previous = pOptions->first;
139 pOptions->first->next = pNode;
140 }
141 pOptions->size++;
142
143 return RET_SUCCESS;
144 }
145
RemoveOption(PDhcpOptionList pOptions,uint8_t code)146 int RemoveOption(PDhcpOptionList pOptions, uint8_t code)
147 {
148 if (pOptions == nullptr) {
149 return RET_ERROR;
150 }
151 if (pOptions->size == 0) {
152 return RET_FAILED;
153 }
154 DhcpOptionNode *pNode = GetOptionNode(pOptions, code);
155 if (pNode == nullptr) {
156 return RET_FAILED;
157 }
158 if (pNode == pOptions->last) {
159 pOptions->last = pNode->previous;
160 pOptions->last->next = nullptr;
161 } else {
162 pNode->next->previous = pNode->previous;
163 pNode->previous->next = pNode->next;
164 }
165 pOptions->size--;
166 free(pNode);
167 pNode = nullptr;
168 return RET_SUCCESS;
169 }
170
GetOptionNode(PDhcpOptionList pOptions,uint8_t code)171 PDhcpOptionNode GetOptionNode(PDhcpOptionList pOptions, uint8_t code)
172 {
173 if (pOptions->first == nullptr) {
174 return nullptr;
175 }
176 PDhcpOptionNode pNode = pOptions->first->next;
177 while (pNode != nullptr && pNode->option.code != code) {
178 pNode = pNode->next;
179 }
180 return pNode;
181 }
182
GetOption(PDhcpOptionList pOptions,uint8_t code)183 PDhcpOption GetOption(PDhcpOptionList pOptions, uint8_t code)
184 {
185 PDhcpOptionNode pNode = GetOptionNode(pOptions, code);
186 if (pNode) {
187 return &pNode->option;
188 }
189 return nullptr;
190 }
191
ClearOptions(PDhcpOptionList pOptions)192 void ClearOptions(PDhcpOptionList pOptions)
193 {
194 if (pOptions == nullptr || pOptions->size == 0) {
195 return;
196 }
197 DhcpOptionNode *pNode = pOptions->first->next;
198 while (pNode != nullptr) {
199 if (pNode == pOptions->last) {
200 pOptions->last = pOptions->first;
201 pOptions->last->next = nullptr;
202 } else {
203 pNode->next->previous = pNode->previous;
204 pNode->previous->next = pNode->next;
205 }
206 free(pNode);
207 pNode = pOptions->first->next;
208 }
209 pNode = pOptions->first;
210 pOptions->size = 0;
211 pOptions->first = pOptions->last = pNode;
212 pOptions->first->previous = nullptr;
213 pOptions->last->next = nullptr;
214 }
215
FreeOptionList(PDhcpOptionList pOptions)216 void FreeOptionList(PDhcpOptionList pOptions)
217 {
218 if (pOptions == nullptr) {
219 return;
220 }
221 if (pOptions->first == nullptr) {
222 return;
223 }
224 DhcpOptionNode *pNode = pOptions->first->next;
225 while (pNode != nullptr) {
226 if (pNode == pOptions->last) {
227 pOptions->last = pOptions->first;
228 pOptions->last->next = nullptr;
229 } else {
230 pNode->next->previous = pNode->previous;
231 pNode->previous->next = pNode->next;
232 }
233 free(pNode);
234 pNode = pOptions->first->next;
235 }
236 pOptions->size = 0;
237 free(pOptions->first);
238 pOptions->first = pOptions->last = nullptr;
239 return;
240 }
241
FillOption(PDhcpOption pOption,const char * data,size_t len)242 int FillOption(PDhcpOption pOption, const char *data, size_t len)
243 {
244 if (!pOption) {
245 return RET_ERROR;
246 }
247 if (!data) {
248 return RET_FAILED;
249 }
250 size_t flen = len;
251 if (flen > (DHCP_OPTION_SIZE - 1)) {
252 flen = DHCP_OPTION_SIZE - 1;
253 }
254 if (memcpy_s(pOption->data, sizeof(pOption->data) - 1, data, flen) != EOK) {
255 return RET_ERROR;
256 }
257 pOption->length = static_cast<uint8_t>(flen);
258 return RET_SUCCESS;
259 }
260
FillU32Option(PDhcpOption pOption,uint32_t u32)261 int FillU32Option(PDhcpOption pOption, uint32_t u32)
262 {
263 if (!pOption) {
264 return RET_ERROR;
265 }
266 if (memcpy_s(pOption->data, sizeof(pOption->data), &u32, sizeof(uint32_t)) != EOK) {
267 return RET_ERROR;
268 }
269 pOption->length = sizeof(uint32_t);
270 return RET_SUCCESS;
271 }
272
FillOptionData(PDhcpOption pOption,const uint8_t * data,size_t len)273 int FillOptionData(PDhcpOption pOption, const uint8_t *data, size_t len)
274 {
275 size_t flen = len;
276 if (!pOption) {
277 return RET_ERROR;
278 }
279 if (!data) {
280 return RET_FAILED;
281 }
282 if (flen > (DHCP_OPTION_SIZE)) {
283 flen = DHCP_OPTION_SIZE;
284 }
285 if (memcpy_s(pOption->data, sizeof(pOption->data), data, flen) != EOK) {
286 return RET_ERROR;
287 }
288 pOption->length = flen;
289 return RET_SUCCESS;
290 }
291
AppendAddressOption(PDhcpOption pOption,uint32_t address)292 int AppendAddressOption(PDhcpOption pOption, uint32_t address)
293 {
294 if (!pOption) {
295 return RET_ERROR;
296 }
297 uint8_t addrLen = pOption->length;
298 uint8_t *pData = pOption->data;
299 int spaceSize = sizeof(pOption->data) - addrLen;
300 if (spaceSize < DHCP_ADDRESS_LENGTH) {
301 DHCP_LOGE("failed to append address, not enough space for option data.");
302 return RET_ERROR;
303 }
304 if ((int)addrLen > 0) {
305 pData += addrLen;
306 }
307 if (memcpy_s(pData, spaceSize, &address, DHCP_ADDRESS_LENGTH) != EOK) {
308 return RET_ERROR;
309 }
310 pOption->length += DHCP_ADDRESS_LENGTH;
311 return RET_SUCCESS;
312 }
313