1518678f8Sopenharmony_ci/* 2518678f8Sopenharmony_ci * Copyright (C) 2021-2022 Huawei Device Co., Ltd. 3518678f8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4518678f8Sopenharmony_ci * you may not use this file except in compliance with the License. 5518678f8Sopenharmony_ci * You may obtain a copy of the License at 6518678f8Sopenharmony_ci * 7518678f8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8518678f8Sopenharmony_ci * 9518678f8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10518678f8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11518678f8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12518678f8Sopenharmony_ci * See the License for the specific language governing permissions and 13518678f8Sopenharmony_ci * limitations under the License. 14518678f8Sopenharmony_ci */ 15518678f8Sopenharmony_ci 16518678f8Sopenharmony_ci#include "dhcp_option.h" 17518678f8Sopenharmony_ci#include <stdint.h> 18518678f8Sopenharmony_ci#include <stdlib.h> 19518678f8Sopenharmony_ci#include "dhcp_s_define.h" 20518678f8Sopenharmony_ci#include "dhcp_logger.h" 21518678f8Sopenharmony_ci#include "securec.h" 22518678f8Sopenharmony_ci 23518678f8Sopenharmony_ciDEFINE_DHCPLOG_DHCP_LABEL("DhcpServerOption"); 24518678f8Sopenharmony_ci 25518678f8Sopenharmony_ciPDhcpOptionNode CreateOptionNode(PDhcpOption opt) 26518678f8Sopenharmony_ci{ 27518678f8Sopenharmony_ci if (!opt) { 28518678f8Sopenharmony_ci DHCP_LOGE("input parameter is null."); 29518678f8Sopenharmony_ci return nullptr; 30518678f8Sopenharmony_ci } 31518678f8Sopenharmony_ci DhcpOptionNode *pNode = (DhcpOptionNode *)calloc(1, sizeof(DhcpOptionNode)); 32518678f8Sopenharmony_ci if (pNode == nullptr) { 33518678f8Sopenharmony_ci DHCP_LOGE("failed to create dhcp option node!"); 34518678f8Sopenharmony_ci return nullptr; 35518678f8Sopenharmony_ci } 36518678f8Sopenharmony_ci pNode->option.code = opt->code; 37518678f8Sopenharmony_ci pNode->option.length = opt->length; 38518678f8Sopenharmony_ci if (memcpy_s(pNode->option.data, sizeof(pNode->option.data), opt->data, opt->length) != EOK) { 39518678f8Sopenharmony_ci DHCP_LOGE("create option node failed when memcpy opt data!"); 40518678f8Sopenharmony_ci free(pNode); 41518678f8Sopenharmony_ci pNode = nullptr; 42518678f8Sopenharmony_ci return nullptr; 43518678f8Sopenharmony_ci } 44518678f8Sopenharmony_ci pNode->previous = pNode->next = 0; 45518678f8Sopenharmony_ci return pNode; 46518678f8Sopenharmony_ci} 47518678f8Sopenharmony_ci 48518678f8Sopenharmony_ciint HasInitialized(PDhcpOptionList pOptions) 49518678f8Sopenharmony_ci{ 50518678f8Sopenharmony_ci if (!pOptions) { 51518678f8Sopenharmony_ci DHCP_LOGE("option list pointer is null."); 52518678f8Sopenharmony_ci return 0; 53518678f8Sopenharmony_ci } 54518678f8Sopenharmony_ci if (pOptions->first != nullptr) { 55518678f8Sopenharmony_ci return 1; 56518678f8Sopenharmony_ci } 57518678f8Sopenharmony_ci return 0; 58518678f8Sopenharmony_ci} 59518678f8Sopenharmony_ci 60518678f8Sopenharmony_ciint InitOptionList(PDhcpOptionList pOptions) 61518678f8Sopenharmony_ci{ 62518678f8Sopenharmony_ci DHCP_LOGI("start %{public}s %{public}d ", __func__, __LINE__); 63518678f8Sopenharmony_ci if (!pOptions) { 64518678f8Sopenharmony_ci return RET_ERROR; 65518678f8Sopenharmony_ci } 66518678f8Sopenharmony_ci if (pOptions->first != nullptr && pOptions->first == pOptions->last) { 67518678f8Sopenharmony_ci DHCP_LOGE(" start %{public}s %{public}d over return success", __func__, __LINE__); 68518678f8Sopenharmony_ci return RET_SUCCESS; 69518678f8Sopenharmony_ci } 70518678f8Sopenharmony_ci 71518678f8Sopenharmony_ci DhcpOptionNode *pNode = (DhcpOptionNode *)calloc(1, sizeof(DhcpOptionNode)); 72518678f8Sopenharmony_ci if (!pNode) { 73518678f8Sopenharmony_ci DHCP_LOGE("failed to create dhcp option node!"); 74518678f8Sopenharmony_ci return 1; 75518678f8Sopenharmony_ci } 76518678f8Sopenharmony_ci 77518678f8Sopenharmony_ci pOptions->size = 0; 78518678f8Sopenharmony_ci pOptions->first = pOptions->last = pNode; 79518678f8Sopenharmony_ci pOptions->first->previous = nullptr; 80518678f8Sopenharmony_ci pOptions->last->next = nullptr; 81518678f8Sopenharmony_ci DHCP_LOGI("start %{public}s %{public}d success ", __func__, __LINE__); 82518678f8Sopenharmony_ci return RET_SUCCESS; 83518678f8Sopenharmony_ci} 84518678f8Sopenharmony_ci 85518678f8Sopenharmony_ciint PushBackOption(PDhcpOptionList pOptions, PDhcpOption pOption) 86518678f8Sopenharmony_ci{ 87518678f8Sopenharmony_ci if (!pOptions) { 88518678f8Sopenharmony_ci DHCP_LOGE("option list pointer is null."); 89518678f8Sopenharmony_ci return RET_ERROR; 90518678f8Sopenharmony_ci } 91518678f8Sopenharmony_ci if (!pOption) { 92518678f8Sopenharmony_ci DHCP_LOGE("option pointer is null."); 93518678f8Sopenharmony_ci return RET_ERROR; 94518678f8Sopenharmony_ci } 95518678f8Sopenharmony_ci if (pOptions->first == nullptr) { 96518678f8Sopenharmony_ci DHCP_LOGE("option list not initialized"); 97518678f8Sopenharmony_ci return RET_SUCCESS; 98518678f8Sopenharmony_ci } 99518678f8Sopenharmony_ci DhcpOptionNode *pNode = CreateOptionNode(pOption); 100518678f8Sopenharmony_ci if (!pNode) { 101518678f8Sopenharmony_ci DHCP_LOGE("failed to create option node."); 102518678f8Sopenharmony_ci return 1; 103518678f8Sopenharmony_ci } 104518678f8Sopenharmony_ci pNode->previous = pOptions->last; 105518678f8Sopenharmony_ci pOptions->last->next = pNode; 106518678f8Sopenharmony_ci pOptions->last = pNode; 107518678f8Sopenharmony_ci pOptions->size++; 108518678f8Sopenharmony_ci 109518678f8Sopenharmony_ci return RET_SUCCESS; 110518678f8Sopenharmony_ci} 111518678f8Sopenharmony_ci 112518678f8Sopenharmony_ciint PushFrontOption(PDhcpOptionList pOptions, PDhcpOption pOption) 113518678f8Sopenharmony_ci{ 114518678f8Sopenharmony_ci if (!pOptions) { 115518678f8Sopenharmony_ci DHCP_LOGE("option list pointer is null."); 116518678f8Sopenharmony_ci return RET_ERROR; 117518678f8Sopenharmony_ci } 118518678f8Sopenharmony_ci if (!pOption) { 119518678f8Sopenharmony_ci DHCP_LOGE("option pointer is null."); 120518678f8Sopenharmony_ci return RET_ERROR; 121518678f8Sopenharmony_ci } 122518678f8Sopenharmony_ci PDhcpOptionNode pNode = CreateOptionNode(pOption); 123518678f8Sopenharmony_ci if (!pNode) { 124518678f8Sopenharmony_ci return RET_FAILED; 125518678f8Sopenharmony_ci } 126518678f8Sopenharmony_ci 127518678f8Sopenharmony_ci if (pOptions->first == pOptions->last) { 128518678f8Sopenharmony_ci pNode->previous = pOptions->first; 129518678f8Sopenharmony_ci pOptions->first->next = pNode; 130518678f8Sopenharmony_ci pOptions->last = pNode; 131518678f8Sopenharmony_ci } else { 132518678f8Sopenharmony_ci pNode->next = pOptions->first->next; 133518678f8Sopenharmony_ci pNode->next->previous = pNode; 134518678f8Sopenharmony_ci pNode->previous = pOptions->first; 135518678f8Sopenharmony_ci pOptions->first->next = pNode; 136518678f8Sopenharmony_ci } 137518678f8Sopenharmony_ci pOptions->size++; 138518678f8Sopenharmony_ci 139518678f8Sopenharmony_ci return RET_SUCCESS; 140518678f8Sopenharmony_ci} 141518678f8Sopenharmony_ci 142518678f8Sopenharmony_ciint RemoveOption(PDhcpOptionList pOptions, uint8_t code) 143518678f8Sopenharmony_ci{ 144518678f8Sopenharmony_ci if (pOptions == nullptr) { 145518678f8Sopenharmony_ci return RET_ERROR; 146518678f8Sopenharmony_ci } 147518678f8Sopenharmony_ci if (pOptions->size == 0) { 148518678f8Sopenharmony_ci return RET_FAILED; 149518678f8Sopenharmony_ci } 150518678f8Sopenharmony_ci DhcpOptionNode *pNode = GetOptionNode(pOptions, code); 151518678f8Sopenharmony_ci if (pNode == nullptr) { 152518678f8Sopenharmony_ci return RET_FAILED; 153518678f8Sopenharmony_ci } 154518678f8Sopenharmony_ci if (pNode == pOptions->last) { 155518678f8Sopenharmony_ci pOptions->last = pNode->previous; 156518678f8Sopenharmony_ci pOptions->last->next = nullptr; 157518678f8Sopenharmony_ci } else { 158518678f8Sopenharmony_ci pNode->next->previous = pNode->previous; 159518678f8Sopenharmony_ci pNode->previous->next = pNode->next; 160518678f8Sopenharmony_ci } 161518678f8Sopenharmony_ci pOptions->size--; 162518678f8Sopenharmony_ci free(pNode); 163518678f8Sopenharmony_ci pNode = nullptr; 164518678f8Sopenharmony_ci return RET_SUCCESS; 165518678f8Sopenharmony_ci} 166518678f8Sopenharmony_ci 167518678f8Sopenharmony_ciPDhcpOptionNode GetOptionNode(PDhcpOptionList pOptions, uint8_t code) 168518678f8Sopenharmony_ci{ 169518678f8Sopenharmony_ci if (pOptions->first == nullptr) { 170518678f8Sopenharmony_ci return nullptr; 171518678f8Sopenharmony_ci } 172518678f8Sopenharmony_ci PDhcpOptionNode pNode = pOptions->first->next; 173518678f8Sopenharmony_ci while (pNode != nullptr && pNode->option.code != code) { 174518678f8Sopenharmony_ci pNode = pNode->next; 175518678f8Sopenharmony_ci } 176518678f8Sopenharmony_ci return pNode; 177518678f8Sopenharmony_ci} 178518678f8Sopenharmony_ci 179518678f8Sopenharmony_ciPDhcpOption GetOption(PDhcpOptionList pOptions, uint8_t code) 180518678f8Sopenharmony_ci{ 181518678f8Sopenharmony_ci PDhcpOptionNode pNode = GetOptionNode(pOptions, code); 182518678f8Sopenharmony_ci if (pNode) { 183518678f8Sopenharmony_ci return &pNode->option; 184518678f8Sopenharmony_ci } 185518678f8Sopenharmony_ci return nullptr; 186518678f8Sopenharmony_ci} 187518678f8Sopenharmony_ci 188518678f8Sopenharmony_civoid ClearOptions(PDhcpOptionList pOptions) 189518678f8Sopenharmony_ci{ 190518678f8Sopenharmony_ci if (pOptions == nullptr || pOptions->size == 0) { 191518678f8Sopenharmony_ci return; 192518678f8Sopenharmony_ci } 193518678f8Sopenharmony_ci DhcpOptionNode *pNode = pOptions->first->next; 194518678f8Sopenharmony_ci while (pNode != nullptr) { 195518678f8Sopenharmony_ci if (pNode == pOptions->last) { 196518678f8Sopenharmony_ci pOptions->last = pOptions->first; 197518678f8Sopenharmony_ci pOptions->last->next = nullptr; 198518678f8Sopenharmony_ci } else { 199518678f8Sopenharmony_ci pNode->next->previous = pNode->previous; 200518678f8Sopenharmony_ci pNode->previous->next = pNode->next; 201518678f8Sopenharmony_ci } 202518678f8Sopenharmony_ci free(pNode); 203518678f8Sopenharmony_ci pNode = pOptions->first->next; 204518678f8Sopenharmony_ci } 205518678f8Sopenharmony_ci pNode = pOptions->first; 206518678f8Sopenharmony_ci pOptions->size = 0; 207518678f8Sopenharmony_ci pOptions->first = pOptions->last = pNode; 208518678f8Sopenharmony_ci pOptions->first->previous = nullptr; 209518678f8Sopenharmony_ci pOptions->last->next = nullptr; 210518678f8Sopenharmony_ci} 211518678f8Sopenharmony_ci 212518678f8Sopenharmony_civoid FreeOptionList(PDhcpOptionList pOptions) 213518678f8Sopenharmony_ci{ 214518678f8Sopenharmony_ci if (pOptions == nullptr) { 215518678f8Sopenharmony_ci return; 216518678f8Sopenharmony_ci } 217518678f8Sopenharmony_ci if (pOptions->first == nullptr) { 218518678f8Sopenharmony_ci return; 219518678f8Sopenharmony_ci } 220518678f8Sopenharmony_ci DhcpOptionNode *pNode = pOptions->first->next; 221518678f8Sopenharmony_ci while (pNode != nullptr) { 222518678f8Sopenharmony_ci if (pNode == pOptions->last) { 223518678f8Sopenharmony_ci pOptions->last = pOptions->first; 224518678f8Sopenharmony_ci pOptions->last->next = nullptr; 225518678f8Sopenharmony_ci } else { 226518678f8Sopenharmony_ci pNode->next->previous = pNode->previous; 227518678f8Sopenharmony_ci pNode->previous->next = pNode->next; 228518678f8Sopenharmony_ci } 229518678f8Sopenharmony_ci free(pNode); 230518678f8Sopenharmony_ci pNode = pOptions->first->next; 231518678f8Sopenharmony_ci } 232518678f8Sopenharmony_ci pOptions->size = 0; 233518678f8Sopenharmony_ci free(pOptions->first); 234518678f8Sopenharmony_ci pOptions->first = pOptions->last = nullptr; 235518678f8Sopenharmony_ci return; 236518678f8Sopenharmony_ci} 237518678f8Sopenharmony_ci 238518678f8Sopenharmony_ciint FillOption(PDhcpOption pOption, const char *data, size_t len) 239518678f8Sopenharmony_ci{ 240518678f8Sopenharmony_ci if (!pOption) { 241518678f8Sopenharmony_ci return RET_ERROR; 242518678f8Sopenharmony_ci } 243518678f8Sopenharmony_ci if (!data) { 244518678f8Sopenharmony_ci return RET_FAILED; 245518678f8Sopenharmony_ci } 246518678f8Sopenharmony_ci size_t flen = len; 247518678f8Sopenharmony_ci if (flen > (DHCP_OPTION_SIZE - 1)) { 248518678f8Sopenharmony_ci flen = DHCP_OPTION_SIZE - 1; 249518678f8Sopenharmony_ci } 250518678f8Sopenharmony_ci if (memcpy_s(pOption->data, sizeof(pOption->data) - 1, data, flen) != EOK) { 251518678f8Sopenharmony_ci return RET_ERROR; 252518678f8Sopenharmony_ci } 253518678f8Sopenharmony_ci pOption->length = flen; 254518678f8Sopenharmony_ci return RET_SUCCESS; 255518678f8Sopenharmony_ci} 256518678f8Sopenharmony_ci 257518678f8Sopenharmony_ciint FillU32Option(PDhcpOption pOption, uint32_t u32) 258518678f8Sopenharmony_ci{ 259518678f8Sopenharmony_ci if (!pOption) { 260518678f8Sopenharmony_ci return RET_ERROR; 261518678f8Sopenharmony_ci } 262518678f8Sopenharmony_ci if (memcpy_s(pOption->data, sizeof(pOption->data), &u32, sizeof(uint32_t)) != EOK) { 263518678f8Sopenharmony_ci return RET_ERROR; 264518678f8Sopenharmony_ci } 265518678f8Sopenharmony_ci pOption->length = sizeof(uint32_t); 266518678f8Sopenharmony_ci return RET_SUCCESS; 267518678f8Sopenharmony_ci} 268518678f8Sopenharmony_ci 269518678f8Sopenharmony_ciint FillOptionData(PDhcpOption pOption, const uint8_t *data, size_t len) 270518678f8Sopenharmony_ci{ 271518678f8Sopenharmony_ci size_t flen = len; 272518678f8Sopenharmony_ci if (!pOption) { 273518678f8Sopenharmony_ci return RET_ERROR; 274518678f8Sopenharmony_ci } 275518678f8Sopenharmony_ci if (!data) { 276518678f8Sopenharmony_ci return RET_FAILED; 277518678f8Sopenharmony_ci } 278518678f8Sopenharmony_ci if (flen > (DHCP_OPTION_SIZE)) { 279518678f8Sopenharmony_ci flen = DHCP_OPTION_SIZE; 280518678f8Sopenharmony_ci } 281518678f8Sopenharmony_ci if (memcpy_s(pOption->data, sizeof(pOption->data), data, flen) != EOK) { 282518678f8Sopenharmony_ci return RET_ERROR; 283518678f8Sopenharmony_ci } 284518678f8Sopenharmony_ci pOption->length = flen; 285518678f8Sopenharmony_ci return RET_SUCCESS; 286518678f8Sopenharmony_ci} 287518678f8Sopenharmony_ci 288518678f8Sopenharmony_ciint AppendAddressOption(PDhcpOption pOption, uint32_t address) 289518678f8Sopenharmony_ci{ 290518678f8Sopenharmony_ci if (!pOption) { 291518678f8Sopenharmony_ci return RET_ERROR; 292518678f8Sopenharmony_ci } 293518678f8Sopenharmony_ci uint8_t addrLen = pOption->length; 294518678f8Sopenharmony_ci uint8_t *pData = pOption->data; 295518678f8Sopenharmony_ci int spaceSize = sizeof(pOption->data) - addrLen; 296518678f8Sopenharmony_ci if (spaceSize < DHCP_ADDRESS_LENGTH) { 297518678f8Sopenharmony_ci DHCP_LOGE("failed to append address, not enough space for option data."); 298518678f8Sopenharmony_ci return RET_ERROR; 299518678f8Sopenharmony_ci } 300518678f8Sopenharmony_ci if ((int)addrLen > 0) { 301518678f8Sopenharmony_ci pData += addrLen; 302518678f8Sopenharmony_ci } 303518678f8Sopenharmony_ci if (memcpy_s(pData, spaceSize, &address, DHCP_ADDRESS_LENGTH) != EOK) { 304518678f8Sopenharmony_ci return RET_ERROR; 305518678f8Sopenharmony_ci } 306518678f8Sopenharmony_ci pOption->length += DHCP_ADDRESS_LENGTH; 307518678f8Sopenharmony_ci return RET_SUCCESS; 308518678f8Sopenharmony_ci} 309