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