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