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