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 <stdlib.h>
19 #include "dhcp_define.h"
20 #include "dhcp_logger.h"
21 #include "securec.h"
22
23 #undef LOG_TAG
24 #define LOG_TAG "DhcpServerOption"
25
CreateOptionNode(PDhcpOption opt)26 PDhcpOptionNode CreateOptionNode(PDhcpOption opt)
27 {
28 if (!opt) {
29 LOGE("input parameter is null.");
30 return NULL;
31 }
32 DhcpOptionNode *pNode = (DhcpOptionNode *)calloc(1, sizeof(DhcpOptionNode));
33 if (pNode == NULL) {
34 LOGE("failed to create dhcp option node!");
35 return NULL;
36 }
37 pNode->option.code = opt->code;
38 pNode->option.length = opt->length;
39 if (memcpy_s(pNode->option.data, sizeof(pNode->option.data), opt->data, opt->length) != EOK) {
40 LOGE("create option node failed when memcpy opt data!");
41 free(pNode);
42 pNode = NULL;
43 return NULL;
44 }
45 pNode->previous = pNode->next = 0;
46 return pNode;
47 }
48
HasInitialized(PDhcpOptionList pOptions)49 int HasInitialized(PDhcpOptionList pOptions)
50 {
51 if (!pOptions) {
52 LOGE("option list pointer is null.");
53 return 0;
54 }
55 if (pOptions->first != NULL) {
56 return 1;
57 }
58 return 0;
59 }
60
InitOptionList(PDhcpOptionList pOptions)61 int InitOptionList(PDhcpOptionList pOptions)
62 {
63 if (!pOptions) {
64 return RET_ERROR;
65 }
66 if (pOptions->first != NULL && pOptions->first == pOptions->last) {
67 return RET_SUCCESS;
68 }
69
70 DhcpOptionNode *pNode = (DhcpOptionNode *)calloc(1, sizeof(DhcpOptionNode));
71 if (!pNode) {
72 LOGE("failed to create dhcp option node!");
73 return 1;
74 }
75
76 pOptions->size = 0;
77 pOptions->first = pOptions->last = pNode;
78 pOptions->first->previous = NULL;
79 pOptions->last->next = NULL;
80 return RET_SUCCESS;
81 }
82
PushBackOption(PDhcpOptionList pOptions,PDhcpOption pOption)83 int PushBackOption(PDhcpOptionList pOptions, PDhcpOption pOption)
84 {
85 if (!pOptions) {
86 LOGE("option list pointer is null.");
87 return RET_ERROR;
88 }
89 if (!pOption) {
90 LOGE("option pointer is null.");
91 return RET_ERROR;
92 }
93 if (pOptions->first == NULL) {
94 LOGE("option list not initialized");
95 return RET_SUCCESS;
96 }
97 DhcpOptionNode *pNode = CreateOptionNode(pOption);
98 if (!pNode) {
99 LOGE("failed to create option node.");
100 return 1;
101 }
102 pNode->previous = pOptions->last;
103 pOptions->last->next = pNode;
104 pOptions->last = pNode;
105 pOptions->size++;
106
107 return RET_SUCCESS;
108 }
109
PushFrontOption(PDhcpOptionList pOptions,PDhcpOption pOption)110 int PushFrontOption(PDhcpOptionList pOptions, PDhcpOption pOption)
111 {
112 if (!pOptions) {
113 LOGE("option list pointer is null.");
114 return RET_ERROR;
115 }
116 if (!pOption) {
117 LOGE("option pointer is null.");
118 return RET_ERROR;
119 }
120 PDhcpOptionNode pNode = CreateOptionNode(pOption);
121 if (!pNode) {
122 return RET_FAILED;
123 }
124
125 if (pOptions->first == pOptions->last) {
126 pNode->previous = pOptions->first;
127 pOptions->first->next = pNode;
128 pOptions->last = pNode;
129 } else {
130 pNode->next = pOptions->first->next;
131 pNode->next->previous = pNode;
132 pNode->previous = pOptions->first;
133 pOptions->first->next = pNode;
134 }
135 pOptions->size++;
136
137 return RET_SUCCESS;
138 }
139
RemoveOption(PDhcpOptionList pOptions,uint8_t code)140 int RemoveOption(PDhcpOptionList pOptions, uint8_t code)
141 {
142 if (pOptions == NULL) {
143 return RET_ERROR;
144 }
145 if (pOptions->size == 0) {
146 return RET_FAILED;
147 }
148 DhcpOptionNode *pNode = GetOptionNode(pOptions, code);
149 if (pNode == NULL) {
150 return RET_FAILED;
151 }
152 if (pNode == pOptions->last) {
153 pOptions->last = pNode->previous;
154 pOptions->last->next = NULL;
155 } else {
156 pNode->next->previous = pNode->previous;
157 pNode->previous->next = pNode->next;
158 }
159 pOptions->size--;
160 free(pNode);
161 pNode = NULL;
162 return RET_SUCCESS;
163 }
164
GetOptionNode(PDhcpOptionList pOptions,uint8_t code)165 PDhcpOptionNode GetOptionNode(PDhcpOptionList pOptions, uint8_t code)
166 {
167 if (pOptions->first == NULL) {
168 return NULL;
169 }
170 PDhcpOptionNode pNode = pOptions->first->next;
171 while (pNode != NULL && pNode->option.code != code) {
172 pNode = pNode->next;
173 }
174 return pNode;
175 }
176
GetOption(PDhcpOptionList pOptions,uint8_t code)177 PDhcpOption GetOption(PDhcpOptionList pOptions, uint8_t code)
178 {
179 PDhcpOptionNode pNode = GetOptionNode(pOptions, code);
180 if (pNode) {
181 return &pNode->option;
182 }
183 return NULL;
184 }
185
ClearOptions(PDhcpOptionList pOptions)186 void ClearOptions(PDhcpOptionList pOptions)
187 {
188 if (pOptions == NULL || pOptions->size == 0) {
189 return;
190 }
191 DhcpOptionNode *pNode = pOptions->first->next;
192 while (pNode != NULL) {
193 if (pNode == pOptions->last) {
194 pOptions->last = pOptions->first;
195 pOptions->last->next = NULL;
196 } else {
197 pNode->next->previous = pNode->previous;
198 pNode->previous->next = pNode->next;
199 }
200 free(pNode);
201 pNode = pOptions->first->next;
202 }
203 pNode = pOptions->first;
204 pOptions->size = 0;
205 pOptions->first = pOptions->last = pNode;
206 pOptions->first->previous = NULL;
207 pOptions->last->next = NULL;
208 }
209
FreeOptionList(PDhcpOptionList pOptions)210 void FreeOptionList(PDhcpOptionList pOptions)
211 {
212 if (pOptions == NULL) {
213 return;
214 }
215 if (pOptions->first == NULL) {
216 return;
217 }
218 DhcpOptionNode *pNode = pOptions->first->next;
219 while (pNode != NULL) {
220 if (pNode == pOptions->last) {
221 pOptions->last = pOptions->first;
222 pOptions->last->next = NULL;
223 } else {
224 pNode->next->previous = pNode->previous;
225 pNode->previous->next = pNode->next;
226 }
227 free(pNode);
228 pNode = pOptions->first->next;
229 }
230 pOptions->size = 0;
231 free(pOptions->first);
232 pOptions->first = pOptions->last = NULL;
233 return;
234 }
235
FillOption(PDhcpOption pOption,const char * data,size_t len)236 int FillOption(PDhcpOption pOption, const char *data, size_t len)
237 {
238 if (!pOption) {
239 return RET_ERROR;
240 }
241 if (!data) {
242 return RET_FAILED;
243 }
244 size_t flen = len;
245 if (flen > (DHCP_OPTION_SIZE - 1)) {
246 flen = DHCP_OPTION_SIZE - 1;
247 }
248 if (memcpy_s(pOption->data, sizeof(pOption->data) - 1, data, flen) != EOK) {
249 return RET_ERROR;
250 }
251 pOption->length = flen;
252 return RET_SUCCESS;
253 }
254
FillU32Option(PDhcpOption pOption,uint32_t u32)255 int FillU32Option(PDhcpOption pOption, uint32_t u32)
256 {
257 if (!pOption) {
258 return RET_ERROR;
259 }
260 if (memcpy_s(pOption->data, sizeof(pOption->data), &u32, sizeof(uint32_t)) != EOK) {
261 return RET_ERROR;
262 }
263 pOption->length = sizeof(uint32_t);
264 return RET_SUCCESS;
265 }
266
FillOptionData(PDhcpOption pOption,const uint8_t * data,size_t len)267 int FillOptionData(PDhcpOption pOption, const uint8_t *data, size_t len)
268 {
269 int flen = len;
270 if (!pOption) {
271 return RET_ERROR;
272 }
273 if (!data) {
274 return RET_FAILED;
275 }
276 if (flen > (DHCP_OPTION_SIZE)) {
277 flen = DHCP_OPTION_SIZE;
278 }
279 if (memcpy_s(pOption->data, sizeof(pOption->data), data, flen) != EOK) {
280 return RET_ERROR;
281 }
282 pOption->length = flen;
283 return RET_SUCCESS;
284 }
285
AppendAddressOption(PDhcpOption pOption,uint32_t address)286 int AppendAddressOption(PDhcpOption pOption, uint32_t address)
287 {
288 if (!pOption) {
289 return RET_ERROR;
290 }
291 uint8_t addrLen = pOption->length;
292 uint8_t *pData = pOption->data;
293 int spaceSize = sizeof(pOption->data) - addrLen;
294 if (spaceSize < DHCP_ADDRESS_LENGTH) {
295 LOGE("failed to append address, not enough space for option data.");
296 return RET_ERROR;
297 }
298 if ((int)addrLen > 0) {
299 pData += addrLen;
300 }
301 if (memcpy_s(pData, spaceSize, &address, DHCP_ADDRESS_LENGTH) != EOK) {
302 return RET_ERROR;
303 }
304 pOption->length += DHCP_ADDRESS_LENGTH;
305 return RET_SUCCESS;
306 }
307