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_address_pool.h"
17518678f8Sopenharmony_ci#include <map>
18518678f8Sopenharmony_ci#include <mutex>
19518678f8Sopenharmony_ci#include <securec.h>
20518678f8Sopenharmony_ci#include <stdint.h>
21518678f8Sopenharmony_ci#include <stdio.h>
22518678f8Sopenharmony_ci#include <string.h>
23518678f8Sopenharmony_ci#include "address_utils.h"
24518678f8Sopenharmony_ci#include "common_util.h"
25518678f8Sopenharmony_ci#include "dhcp_logger.h"
26518678f8Sopenharmony_ci
27518678f8Sopenharmony_ciDEFINE_DHCPLOG_DHCP_LABEL("DhcpServerAddressPool");
28518678f8Sopenharmony_ci
29518678f8Sopenharmony_ci#define DHCP_POOL_INIT_SIZE 10
30518678f8Sopenharmony_ci#define DHCP_RELEASE_REMOVE_MODE 0
31518678f8Sopenharmony_ci
32518678f8Sopenharmony_cistatic int g_releaseRemoveMode = DHCP_RELEASE_REMOVE_MODE;
33518678f8Sopenharmony_cistatic std::map<std::size_t, AddressBinding> g_bindingRecoders;
34518678f8Sopenharmony_cistatic std::mutex g_bindingMapMutex;
35518678f8Sopenharmony_cistatic int g_distributeMode = 0;
36518678f8Sopenharmony_ci
37518678f8Sopenharmony_ci#define HASH_DEFAULT_VALUE 5381
38518678f8Sopenharmony_ci#define HASH_CAL_CODE_CAL 5
39518678f8Sopenharmony_ci//Write a HASH FUNCTION FOR uint8_t macAddr[DHCP_HWADDR_LENGTH]
40518678f8Sopenharmony_cistd::size_t macAddrHash(uint8_t macAddr[DHCP_HWADDR_LENGTH])
41518678f8Sopenharmony_ci{
42518678f8Sopenharmony_ci    std::size_t hash = HASH_DEFAULT_VALUE;
43518678f8Sopenharmony_ci    for (std::size_t i = 0; i < DHCP_HWADDR_LENGTH; ++i) {
44518678f8Sopenharmony_ci        hash = ((hash << HASH_CAL_CODE_CAL) + hash) ^ static_cast<std::size_t>(macAddr[i]);
45518678f8Sopenharmony_ci    }
46518678f8Sopenharmony_ci    return hash;
47518678f8Sopenharmony_ci}
48518678f8Sopenharmony_ci
49518678f8Sopenharmony_ci
50518678f8Sopenharmony_ciAddressBinding *GetBindingByMac(uint8_t macAddr[DHCP_HWADDR_LENGTH])
51518678f8Sopenharmony_ci{
52518678f8Sopenharmony_ci    std::size_t hash = macAddrHash(macAddr);
53518678f8Sopenharmony_ci    std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
54518678f8Sopenharmony_ci    if (g_bindingRecoders.count(hash) > 0) {
55518678f8Sopenharmony_ci        return &g_bindingRecoders[hash];
56518678f8Sopenharmony_ci    }
57518678f8Sopenharmony_ci    return nullptr;
58518678f8Sopenharmony_ci}
59518678f8Sopenharmony_ci
60518678f8Sopenharmony_ciAddressBinding *QueryBinding(uint8_t macAddr[DHCP_HWADDR_LENGTH], PDhcpOptionList cliOptins)
61518678f8Sopenharmony_ci{
62518678f8Sopenharmony_ci    return GetBindingByMac(macAddr);
63518678f8Sopenharmony_ci}
64518678f8Sopenharmony_ci
65518678f8Sopenharmony_ciAddressBinding *AddNewBinding(uint8_t macAddr[DHCP_HWADDR_LENGTH], PDhcpOptionList cliOptins)
66518678f8Sopenharmony_ci{
67518678f8Sopenharmony_ci    AddressBinding newBind = {0};
68518678f8Sopenharmony_ci    newBind.bindingMode = BIND_MODE_DYNAMIC;
69518678f8Sopenharmony_ci    newBind.bindingStatus = BIND_PENDING;
70518678f8Sopenharmony_ci    if (memcpy_s(newBind.chaddr, DHCP_HWADDR_LENGTH, macAddr, DHCP_HWADDR_LENGTH) != EOK) {
71518678f8Sopenharmony_ci        DHCP_LOGE("newBind chaddr memcpy_s failed!");
72518678f8Sopenharmony_ci        return nullptr;
73518678f8Sopenharmony_ci    }
74518678f8Sopenharmony_ci    newBind.bindingTime = Tmspsec();
75518678f8Sopenharmony_ci    newBind.pendingTime = Tmspsec();
76518678f8Sopenharmony_ci    newBind.expireIn = newBind.bindingTime + DHCP_LEASE_TIME;
77518678f8Sopenharmony_ci    newBind.leaseTime = DHCP_LEASE_TIME;
78518678f8Sopenharmony_ci    {
79518678f8Sopenharmony_ci        std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
80518678f8Sopenharmony_ci        g_bindingRecoders[macAddrHash(macAddr)] = newBind;
81518678f8Sopenharmony_ci    }
82518678f8Sopenharmony_ci    return GetBindingByMac(macAddr);
83518678f8Sopenharmony_ci}
84518678f8Sopenharmony_ci
85518678f8Sopenharmony_ciint CheckIpAvailability(DhcpAddressPool *pool, uint8_t macAddr[DHCP_HWADDR_LENGTH], uint32_t distIp)
86518678f8Sopenharmony_ci{
87518678f8Sopenharmony_ci    if (!pool) {
88518678f8Sopenharmony_ci        DHCP_LOGE("pool pointer is null.");
89518678f8Sopenharmony_ci        return DHCP_FALSE;
90518678f8Sopenharmony_ci    }
91518678f8Sopenharmony_ci    if (IsReserved(macAddr)) {
92518678f8Sopenharmony_ci        DHCP_LOGW("client address(%s) is reserved address.", ParseLogMac(macAddr));
93518678f8Sopenharmony_ci        return DHCP_FALSE;
94518678f8Sopenharmony_ci    }
95518678f8Sopenharmony_ci    AddressBinding *lease = GetLease(pool, distIp);
96518678f8Sopenharmony_ci    if (lease) {
97518678f8Sopenharmony_ci        int same = AddrEquels(lease->chaddr, macAddr, MAC_ADDR_LENGTH);
98518678f8Sopenharmony_ci        if (distIp == pool->serverId || distIp == pool->gateway) {
99518678f8Sopenharmony_ci            return DHCP_FALSE;
100518678f8Sopenharmony_ci        }
101518678f8Sopenharmony_ci        if (lease->bindingMode == BIND_MODE_STATIC && !same) {
102518678f8Sopenharmony_ci            return DHCP_FALSE;
103518678f8Sopenharmony_ci        }
104518678f8Sopenharmony_ci        if (IsReservedIp(pool, distIp) && !same) {
105518678f8Sopenharmony_ci            return DHCP_FALSE;
106518678f8Sopenharmony_ci        }
107518678f8Sopenharmony_ci        if (same) {
108518678f8Sopenharmony_ci            lease->pendingTime = Tmspsec();
109518678f8Sopenharmony_ci            lease->bindingTime = lease->pendingTime;
110518678f8Sopenharmony_ci            return DHCP_TRUE;
111518678f8Sopenharmony_ci        }
112518678f8Sopenharmony_ci        if (IsExpire(lease)) {
113518678f8Sopenharmony_ci            DHCP_LOGD("the binding recoder has expired.");
114518678f8Sopenharmony_ci            lease->pendingTime = Tmspsec();
115518678f8Sopenharmony_ci            lease->bindingTime = lease->pendingTime;
116518678f8Sopenharmony_ci            RemoveBinding(lease->chaddr);
117518678f8Sopenharmony_ci            if (memcpy_s(lease->chaddr, DHCP_HWADDR_LENGTH, macAddr, MAC_ADDR_LENGTH) != EOK) {
118518678f8Sopenharmony_ci                DHCP_LOGD("failed to rewrite client address.");
119518678f8Sopenharmony_ci            }
120518678f8Sopenharmony_ci            return DHCP_TRUE;
121518678f8Sopenharmony_ci        }
122518678f8Sopenharmony_ci        return DHCP_FALSE;
123518678f8Sopenharmony_ci    }
124518678f8Sopenharmony_ci    return DHCP_TRUE;
125518678f8Sopenharmony_ci}
126518678f8Sopenharmony_ci
127518678f8Sopenharmony_ciint CheckRangeAvailability(
128518678f8Sopenharmony_ci    DhcpAddressPool *pool, uint8_t macAddr[DHCP_HWADDR_LENGTH], uint32_t distIp, int *outOfRange)
129518678f8Sopenharmony_ci{
130518678f8Sopenharmony_ci    if (!pool || !pool->addressRange.beginAddress || !pool->addressRange.endAddress) {
131518678f8Sopenharmony_ci        DHCP_LOGE("pool beginAddress or endAddress pointer is null.");
132518678f8Sopenharmony_ci        return RET_ERROR;
133518678f8Sopenharmony_ci    }
134518678f8Sopenharmony_ci    if (!pool->netmask || IsEmptyHWAddr(macAddr)) {
135518678f8Sopenharmony_ci        DHCP_LOGE("pool netmask empty hwaddr pointer is null.");
136518678f8Sopenharmony_ci        return RET_ERROR;
137518678f8Sopenharmony_ci    }
138518678f8Sopenharmony_ci    uint32_t beginIp = pool->addressRange.beginAddress;
139518678f8Sopenharmony_ci    uint32_t endIp = pool->addressRange.endAddress;
140518678f8Sopenharmony_ci    if (IpInRange(distIp, beginIp, endIp, pool->netmask)) {
141518678f8Sopenharmony_ci        DHCP_LOGD("distribution IP address");
142518678f8Sopenharmony_ci        AddressBinding lease = {0};
143518678f8Sopenharmony_ci        lease.pendingTime = Tmspsec();
144518678f8Sopenharmony_ci        lease.bindingMode = BIND_PENDING;
145518678f8Sopenharmony_ci        lease.ipAddress = distIp;
146518678f8Sopenharmony_ci        lease.bindingTime = lease.pendingTime;
147518678f8Sopenharmony_ci        lease.leaseTime = pool->leaseTime;
148518678f8Sopenharmony_ci        if (memcpy_s(lease.chaddr, sizeof(lease.chaddr), macAddr, MAC_ADDR_LENGTH) != EOK) {
149518678f8Sopenharmony_ci            DHCP_LOGE("failed to set lease chaddr fields");
150518678f8Sopenharmony_ci            return RET_ERROR;
151518678f8Sopenharmony_ci        }
152518678f8Sopenharmony_ci        if (AddLease(pool, &lease) != RET_SUCCESS) {
153518678f8Sopenharmony_ci            DHCP_LOGE("failed to add lease.");
154518678f8Sopenharmony_ci            return RET_ERROR;
155518678f8Sopenharmony_ci        }
156518678f8Sopenharmony_ci        return RET_SUCCESS;
157518678f8Sopenharmony_ci    }
158518678f8Sopenharmony_ci    if (*outOfRange) {
159518678f8Sopenharmony_ci        DHCP_LOGD("address is out of range");
160518678f8Sopenharmony_ci        return RET_FAILED;
161518678f8Sopenharmony_ci    } else {
162518678f8Sopenharmony_ci        *outOfRange = 1;
163518678f8Sopenharmony_ci    }
164518678f8Sopenharmony_ci    return RET_FAILED;
165518678f8Sopenharmony_ci}
166518678f8Sopenharmony_ci
167518678f8Sopenharmony_ciuint32_t NextIpOffset(uint32_t netmask)
168518678f8Sopenharmony_ci{
169518678f8Sopenharmony_ci    uint32_t offset = 0;
170518678f8Sopenharmony_ci    if (g_distributeMode && netmask) {
171518678f8Sopenharmony_ci        uint32_t total = HostTotal(netmask);
172518678f8Sopenharmony_ci        if (total) {
173518678f8Sopenharmony_ci            offset = Tmspusec() % total;
174518678f8Sopenharmony_ci        }
175518678f8Sopenharmony_ci        DHCP_LOGD("next ip offset is: %u", offset);
176518678f8Sopenharmony_ci    }
177518678f8Sopenharmony_ci    return offset;
178518678f8Sopenharmony_ci}
179518678f8Sopenharmony_ci
180518678f8Sopenharmony_ciuint32_t AddressDistribute(DhcpAddressPool *pool, uint8_t macAddr[DHCP_HWADDR_LENGTH])
181518678f8Sopenharmony_ci{
182518678f8Sopenharmony_ci    if (!pool || !pool->addressRange.beginAddress || !pool->addressRange.endAddress) {
183518678f8Sopenharmony_ci        return 0;
184518678f8Sopenharmony_ci    }
185518678f8Sopenharmony_ci    if (!pool->netmask || IsEmptyHWAddr(macAddr)) {
186518678f8Sopenharmony_ci        return 0;
187518678f8Sopenharmony_ci    }
188518678f8Sopenharmony_ci    if (pool->distribution == 0) {
189518678f8Sopenharmony_ci        pool->distribution = pool->addressRange.beginAddress;
190518678f8Sopenharmony_ci    }
191518678f8Sopenharmony_ci    uint32_t total = HostTotal(pool->netmask);
192518678f8Sopenharmony_ci    uint32_t distIp = pool->distribution;
193518678f8Sopenharmony_ci    if (!distIp || distIp < pool->addressRange.beginAddress) {
194518678f8Sopenharmony_ci        distIp = pool->addressRange.beginAddress;
195518678f8Sopenharmony_ci    }
196518678f8Sopenharmony_ci    int distSucess = 0;
197518678f8Sopenharmony_ci    int outOfRange = 0;
198518678f8Sopenharmony_ci    for (uint32_t i = 0; i < total; i++) {
199518678f8Sopenharmony_ci        uint32_t offset = 0;
200518678f8Sopenharmony_ci        if (i == 0) {
201518678f8Sopenharmony_ci            offset = NextIpOffset(pool->netmask);
202518678f8Sopenharmony_ci        }
203518678f8Sopenharmony_ci        distIp = NextIpAddress(distIp, pool->netmask, offset);
204518678f8Sopenharmony_ci        if (!CheckIpAvailability(pool, macAddr, distIp)) {
205518678f8Sopenharmony_ci            continue;
206518678f8Sopenharmony_ci        }
207518678f8Sopenharmony_ci        int ret = CheckRangeAvailability(pool, macAddr, distIp, &outOfRange);
208518678f8Sopenharmony_ci        if (ret == RET_ERROR) {
209518678f8Sopenharmony_ci            break;
210518678f8Sopenharmony_ci        }
211518678f8Sopenharmony_ci        if (ret == RET_SUCCESS) {
212518678f8Sopenharmony_ci            distSucess = 1;
213518678f8Sopenharmony_ci            break;
214518678f8Sopenharmony_ci        }
215518678f8Sopenharmony_ci    }
216518678f8Sopenharmony_ci    if (!distSucess || !distIp) {
217518678f8Sopenharmony_ci        return 0;
218518678f8Sopenharmony_ci    }
219518678f8Sopenharmony_ci    pool->distribution = distIp;
220518678f8Sopenharmony_ci    return pool->distribution;
221518678f8Sopenharmony_ci}
222518678f8Sopenharmony_ci
223518678f8Sopenharmony_ciint InitAddressPool(DhcpAddressPool *pool, const char *ifname, PDhcpOptionList options)
224518678f8Sopenharmony_ci{
225518678f8Sopenharmony_ci    if (!pool) {
226518678f8Sopenharmony_ci        DHCP_LOGD("address pool pointer is null.");
227518678f8Sopenharmony_ci        return RET_ERROR;
228518678f8Sopenharmony_ci    }
229518678f8Sopenharmony_ci    if (memset_s(pool, sizeof(DhcpAddressPool), 0, sizeof(DhcpAddressPool)) != EOK) {
230518678f8Sopenharmony_ci        DHCP_LOGD("failed to init dhcp pool.");
231518678f8Sopenharmony_ci        return RET_ERROR;
232518678f8Sopenharmony_ci    }
233518678f8Sopenharmony_ci    if (memset_s(pool->ifname, IFACE_NAME_SIZE, '\0', IFACE_NAME_SIZE) != EOK) {
234518678f8Sopenharmony_ci        DHCP_LOGD("failed to reset interface name.");
235518678f8Sopenharmony_ci        return RET_ERROR;
236518678f8Sopenharmony_ci    }
237518678f8Sopenharmony_ci    if (strncpy_s(pool->ifname, IFACE_NAME_SIZE, ifname, strlen(ifname)) != EOK) {
238518678f8Sopenharmony_ci        DHCP_LOGD("failed to set interface name.");
239518678f8Sopenharmony_ci        return RET_ERROR;
240518678f8Sopenharmony_ci    }
241518678f8Sopenharmony_ci    if (InitOptionList(&pool->fixedOptions) != RET_SUCCESS) {
242518678f8Sopenharmony_ci        DHCP_LOGD("failed to init options field for dhcp pool.");
243518678f8Sopenharmony_ci        return RET_FAILED;
244518678f8Sopenharmony_ci    }
245518678f8Sopenharmony_ci    std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
246518678f8Sopenharmony_ci    g_bindingRecoders.clear();
247518678f8Sopenharmony_ci
248518678f8Sopenharmony_ci    pool->distribue = AddressDistribute;
249518678f8Sopenharmony_ci    pool->binding = QueryBinding;
250518678f8Sopenharmony_ci    pool->newBinding = AddNewBinding;
251518678f8Sopenharmony_ci    pool->leaseTable.clear();
252518678f8Sopenharmony_ci    return RET_SUCCESS;
253518678f8Sopenharmony_ci}
254518678f8Sopenharmony_ci
255518678f8Sopenharmony_civoid FreeAddressPool(DhcpAddressPool *pool)
256518678f8Sopenharmony_ci{
257518678f8Sopenharmony_ci    if (!pool) {
258518678f8Sopenharmony_ci        return;
259518678f8Sopenharmony_ci    }
260518678f8Sopenharmony_ci
261518678f8Sopenharmony_ci    if (pool->fixedOptions.size > 0) {
262518678f8Sopenharmony_ci        ClearOptions(&pool->fixedOptions);
263518678f8Sopenharmony_ci    }
264518678f8Sopenharmony_ci
265518678f8Sopenharmony_ci    if (pool) {
266518678f8Sopenharmony_ci        pool->leaseTable.clear();
267518678f8Sopenharmony_ci    }
268518678f8Sopenharmony_ci
269518678f8Sopenharmony_ci    if (pool && HasInitialized(&pool->fixedOptions)) {
270518678f8Sopenharmony_ci        FreeOptionList(&pool->fixedOptions);
271518678f8Sopenharmony_ci    }
272518678f8Sopenharmony_ci}
273518678f8Sopenharmony_ci
274518678f8Sopenharmony_ciAddressBinding *FindBindingByIp(uint32_t ipAddress)
275518678f8Sopenharmony_ci{
276518678f8Sopenharmony_ci    std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
277518678f8Sopenharmony_ci    if (g_bindingRecoders.empty()) {
278518678f8Sopenharmony_ci        return nullptr;
279518678f8Sopenharmony_ci    }
280518678f8Sopenharmony_ci    for (auto current: g_bindingRecoders) {
281518678f8Sopenharmony_ci        AddressBinding *binding = &current.second;
282518678f8Sopenharmony_ci        if (binding && ipAddress == binding->ipAddress) {
283518678f8Sopenharmony_ci            return binding;
284518678f8Sopenharmony_ci        }
285518678f8Sopenharmony_ci    }
286518678f8Sopenharmony_ci    return nullptr;
287518678f8Sopenharmony_ci}
288518678f8Sopenharmony_ci
289518678f8Sopenharmony_ciint IsReserved(uint8_t macAddr[DHCP_HWADDR_LENGTH])
290518678f8Sopenharmony_ci{
291518678f8Sopenharmony_ci    std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
292518678f8Sopenharmony_ci    if (g_bindingRecoders.count(macAddrHash(macAddr)) > 0) {
293518678f8Sopenharmony_ci        AddressBinding *binding = &g_bindingRecoders[macAddrHash(macAddr)];
294518678f8Sopenharmony_ci        if (binding && binding->bindingMode == BIND_MODE_RESERVED) {
295518678f8Sopenharmony_ci            return DHCP_TRUE;
296518678f8Sopenharmony_ci        }
297518678f8Sopenharmony_ci    }
298518678f8Sopenharmony_ci    return DHCP_FALSE;
299518678f8Sopenharmony_ci}
300518678f8Sopenharmony_ci
301518678f8Sopenharmony_ciint IsReservedIp(DhcpAddressPool *pool, uint32_t ipAddress)
302518678f8Sopenharmony_ci{
303518678f8Sopenharmony_ci    if (!pool) {
304518678f8Sopenharmony_ci        return DHCP_FALSE;
305518678f8Sopenharmony_ci    }
306518678f8Sopenharmony_ci    if (!ipAddress) {
307518678f8Sopenharmony_ci        return DHCP_FALSE;
308518678f8Sopenharmony_ci    }
309518678f8Sopenharmony_ci    if (pool->leaseTable.count(ipAddress) >0) {
310518678f8Sopenharmony_ci        AddressBinding *lease = &pool->leaseTable[ipAddress];
311518678f8Sopenharmony_ci        if (lease && lease->bindingMode == BIND_MODE_RESERVED) {
312518678f8Sopenharmony_ci            return DHCP_TRUE;
313518678f8Sopenharmony_ci        }
314518678f8Sopenharmony_ci    }
315518678f8Sopenharmony_ci    return DHCP_FALSE;
316518678f8Sopenharmony_ci}
317518678f8Sopenharmony_ci
318518678f8Sopenharmony_ciint AddBinding(AddressBinding *binding)
319518678f8Sopenharmony_ci{
320518678f8Sopenharmony_ci    if (!binding) {
321518678f8Sopenharmony_ci        DHCP_LOGE("binding pointer is null.");
322518678f8Sopenharmony_ci        return RET_ERROR;
323518678f8Sopenharmony_ci    }
324518678f8Sopenharmony_ci    if (IsEmptyHWAddr(binding->chaddr)) {
325518678f8Sopenharmony_ci        DHCP_LOGE("binding address is empty.");
326518678f8Sopenharmony_ci        return RET_ERROR;
327518678f8Sopenharmony_ci    }
328518678f8Sopenharmony_ci    if (!binding->ipAddress) {
329518678f8Sopenharmony_ci        DHCP_LOGE("binding ip is empty.");
330518678f8Sopenharmony_ci        return RET_ERROR;
331518678f8Sopenharmony_ci    }
332518678f8Sopenharmony_ci    std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
333518678f8Sopenharmony_ci    if (g_bindingRecoders.count(macAddrHash(binding->chaddr)) > 0) {
334518678f8Sopenharmony_ci        DHCP_LOGW("binding recoder exist.");
335518678f8Sopenharmony_ci        return RET_FAILED;
336518678f8Sopenharmony_ci    }
337518678f8Sopenharmony_ci    g_bindingRecoders[macAddrHash(binding->chaddr)] = *binding;
338518678f8Sopenharmony_ci    return RET_SUCCESS;
339518678f8Sopenharmony_ci}
340518678f8Sopenharmony_ci
341518678f8Sopenharmony_ciint AddReservedBinding(uint8_t macAddr[DHCP_HWADDR_LENGTH])
342518678f8Sopenharmony_ci{
343518678f8Sopenharmony_ci    AddressBinding *binding = GetBindingByMac(macAddr);
344518678f8Sopenharmony_ci    if (binding) {
345518678f8Sopenharmony_ci        binding->bindingMode = BIND_MODE_RESERVED;
346518678f8Sopenharmony_ci    } else {
347518678f8Sopenharmony_ci        AddressBinding bind = {0};
348518678f8Sopenharmony_ci        bind.bindingMode = BIND_MODE_RESERVED;
349518678f8Sopenharmony_ci        bind.bindingTime = Tmspsec();
350518678f8Sopenharmony_ci        bind.pendingTime = bind.bindingTime;
351518678f8Sopenharmony_ci        std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
352518678f8Sopenharmony_ci        g_bindingRecoders[macAddrHash(macAddr)] = bind;
353518678f8Sopenharmony_ci    }
354518678f8Sopenharmony_ci    return RET_SUCCESS;
355518678f8Sopenharmony_ci}
356518678f8Sopenharmony_ci
357518678f8Sopenharmony_ciint RemoveBinding(uint8_t macAddr[DHCP_HWADDR_LENGTH])
358518678f8Sopenharmony_ci{
359518678f8Sopenharmony_ci    std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
360518678f8Sopenharmony_ci    if (g_bindingRecoders.count(macAddrHash(macAddr)) > 0) {
361518678f8Sopenharmony_ci        g_bindingRecoders.erase(macAddrHash(macAddr));
362518678f8Sopenharmony_ci        return RET_SUCCESS;
363518678f8Sopenharmony_ci    }
364518678f8Sopenharmony_ci    return RET_FAILED;
365518678f8Sopenharmony_ci}
366518678f8Sopenharmony_ci
367518678f8Sopenharmony_ciint RemoveReservedBinding(uint8_t macAddr[DHCP_HWADDR_LENGTH])
368518678f8Sopenharmony_ci{
369518678f8Sopenharmony_ci    std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
370518678f8Sopenharmony_ci    if (g_bindingRecoders.count(macAddrHash(macAddr)) > 0) {
371518678f8Sopenharmony_ci        AddressBinding *binding = &g_bindingRecoders[macAddrHash(macAddr)];
372518678f8Sopenharmony_ci        if (binding && binding->bindingMode == BIND_MODE_RESERVED) {
373518678f8Sopenharmony_ci            g_bindingRecoders.erase(macAddrHash(macAddr));
374518678f8Sopenharmony_ci            return RET_SUCCESS;
375518678f8Sopenharmony_ci        }
376518678f8Sopenharmony_ci    }
377518678f8Sopenharmony_ci    DHCP_LOGW("binding mode is not 'BIND_MODE_RESERVED'.");
378518678f8Sopenharmony_ci    return RET_FAILED;
379518678f8Sopenharmony_ci}
380518678f8Sopenharmony_ci
381518678f8Sopenharmony_ciint ReleaseBinding(uint8_t macAddr[DHCP_HWADDR_LENGTH])
382518678f8Sopenharmony_ci{
383518678f8Sopenharmony_ci    std::lock_guard<std::mutex> autoLock(g_bindingMapMutex);
384518678f8Sopenharmony_ci    if (g_bindingRecoders.count(macAddrHash(macAddr)) > 0) {
385518678f8Sopenharmony_ci        if (g_releaseRemoveMode) {
386518678f8Sopenharmony_ci            g_bindingRecoders.erase(macAddrHash(macAddr));
387518678f8Sopenharmony_ci            return RET_SUCCESS;
388518678f8Sopenharmony_ci        }
389518678f8Sopenharmony_ci        AddressBinding *binding = &g_bindingRecoders[macAddrHash(macAddr)];
390518678f8Sopenharmony_ci        if (binding) {
391518678f8Sopenharmony_ci            binding->bindingStatus = BIND_RELEASED;
392518678f8Sopenharmony_ci            return RET_SUCCESS;
393518678f8Sopenharmony_ci        }
394518678f8Sopenharmony_ci    }
395518678f8Sopenharmony_ci    return RET_FAILED;
396518678f8Sopenharmony_ci}
397518678f8Sopenharmony_ci
398518678f8Sopenharmony_ciint AddLease(DhcpAddressPool *pool, AddressBinding *lease)
399518678f8Sopenharmony_ci{
400518678f8Sopenharmony_ci    if (!pool) {
401518678f8Sopenharmony_ci        DHCP_LOGE("add lease pool pointer is null.");
402518678f8Sopenharmony_ci        return RET_ERROR;
403518678f8Sopenharmony_ci    }
404518678f8Sopenharmony_ci
405518678f8Sopenharmony_ci    if (!lease || !lease->ipAddress || IsEmptyHWAddr(lease->chaddr)) {
406518678f8Sopenharmony_ci        DHCP_LOGE("add lease pool ipAddress or chaddr pointer is null.");
407518678f8Sopenharmony_ci        return RET_ERROR;
408518678f8Sopenharmony_ci    }
409518678f8Sopenharmony_ci
410518678f8Sopenharmony_ci    if (pool->leaseTable.count(lease->ipAddress) > 0) {
411518678f8Sopenharmony_ci        DHCP_LOGI("update lease info.");
412518678f8Sopenharmony_ci        pool->leaseTable[lease->ipAddress] = *lease;
413518678f8Sopenharmony_ci        return RET_SUCCESS;
414518678f8Sopenharmony_ci    } else {
415518678f8Sopenharmony_ci        DHCP_LOGI("insert lease info.");
416518678f8Sopenharmony_ci        pool->leaseTable[lease->ipAddress] = *lease;
417518678f8Sopenharmony_ci        return RET_SUCCESS;
418518678f8Sopenharmony_ci    }
419518678f8Sopenharmony_ci}
420518678f8Sopenharmony_ci
421518678f8Sopenharmony_ciAddressBinding *GetLease(DhcpAddressPool *pool, uint32_t ipAddress)
422518678f8Sopenharmony_ci{
423518678f8Sopenharmony_ci    if (!ipAddress) {
424518678f8Sopenharmony_ci        DHCP_LOGE("get lease ipAddress pointer is null.");
425518678f8Sopenharmony_ci        return nullptr;
426518678f8Sopenharmony_ci    }
427518678f8Sopenharmony_ci    if (!pool) {
428518678f8Sopenharmony_ci        DHCP_LOGE("get lease pool pointer is null.");
429518678f8Sopenharmony_ci        return nullptr;
430518678f8Sopenharmony_ci    }
431518678f8Sopenharmony_ci    uint32_t ipAddr = ipAddress;
432518678f8Sopenharmony_ci    if (pool->leaseTable.count(ipAddr) > 0) {
433518678f8Sopenharmony_ci        return &pool->leaseTable[ipAddr];
434518678f8Sopenharmony_ci    }
435518678f8Sopenharmony_ci    DHCP_LOGE("get lease address binding pointer is null.");
436518678f8Sopenharmony_ci    return nullptr;
437518678f8Sopenharmony_ci}
438518678f8Sopenharmony_ci
439518678f8Sopenharmony_ciint UpdateLease(DhcpAddressPool *pool, AddressBinding *lease)
440518678f8Sopenharmony_ci{
441518678f8Sopenharmony_ci    if (!pool) {
442518678f8Sopenharmony_ci        DHCP_LOGE("update lease pool pointer is null.");
443518678f8Sopenharmony_ci        return RET_ERROR;
444518678f8Sopenharmony_ci    }
445518678f8Sopenharmony_ci
446518678f8Sopenharmony_ci    if (!lease || !lease->ipAddress || IsEmptyHWAddr(lease->chaddr)) {
447518678f8Sopenharmony_ci        DHCP_LOGE("update lease pool ipAddress or chaddr pointer is null.");
448518678f8Sopenharmony_ci        return RET_ERROR;
449518678f8Sopenharmony_ci    }
450518678f8Sopenharmony_ci    if (pool->leaseTable.count(lease->ipAddress) > 0) {
451518678f8Sopenharmony_ci        pool->leaseTable[lease->ipAddress] = *lease;
452518678f8Sopenharmony_ci        return RET_SUCCESS;
453518678f8Sopenharmony_ci    }
454518678f8Sopenharmony_ci    DHCP_LOGE("update lease address binding pointer is null.");
455518678f8Sopenharmony_ci    return RET_FAILED;
456518678f8Sopenharmony_ci}
457518678f8Sopenharmony_ci
458518678f8Sopenharmony_ciint RemoveLease(DhcpAddressPool *pool, AddressBinding *lease)
459518678f8Sopenharmony_ci{
460518678f8Sopenharmony_ci    if (!pool) {
461518678f8Sopenharmony_ci        DHCP_LOGE("remove lease pool pointer is null.");
462518678f8Sopenharmony_ci        return RET_ERROR;
463518678f8Sopenharmony_ci    }
464518678f8Sopenharmony_ci
465518678f8Sopenharmony_ci    if (!lease || !lease->ipAddress || IsEmptyHWAddr(lease->chaddr)) {
466518678f8Sopenharmony_ci        DHCP_LOGE("remove lease pool ipAddress or chaddr pointer is null.");
467518678f8Sopenharmony_ci        return RET_ERROR;
468518678f8Sopenharmony_ci    }
469518678f8Sopenharmony_ci
470518678f8Sopenharmony_ci    if (pool->leaseTable.count(lease->ipAddress) > 0) {
471518678f8Sopenharmony_ci        pool->leaseTable.erase(lease->ipAddress);
472518678f8Sopenharmony_ci        return RET_SUCCESS;
473518678f8Sopenharmony_ci    }
474518678f8Sopenharmony_ci    DHCP_LOGE("remove lease address binding pointer is null.");
475518678f8Sopenharmony_ci    return RET_FAILED;
476518678f8Sopenharmony_ci}
477518678f8Sopenharmony_ci
478518678f8Sopenharmony_ciint LoadBindingRecoders(DhcpAddressPool *pool)
479518678f8Sopenharmony_ci{
480518678f8Sopenharmony_ci    if (pool == nullptr) {
481518678f8Sopenharmony_ci        DHCP_LOGE("loadbinding recorder pool pointer is null.");
482518678f8Sopenharmony_ci        return RET_FAILED;
483518678f8Sopenharmony_ci    }
484518678f8Sopenharmony_ci    char filePath[DHCP_LEASE_FILE_LENGTH] = {0};
485518678f8Sopenharmony_ci    if (snprintf_s(filePath, sizeof(filePath), sizeof(filePath) - 1, "%s.%s", DHCPD_LEASE_FILE, pool->ifname) < 0) {
486518678f8Sopenharmony_ci        DHCP_LOGE("Failed to get dhcp lease file path!");
487518678f8Sopenharmony_ci        return RET_FAILED;
488518678f8Sopenharmony_ci    }
489518678f8Sopenharmony_ci    FILE *fp = fopen(filePath, "r");
490518678f8Sopenharmony_ci    if (fp == nullptr) {
491518678f8Sopenharmony_ci        return RET_FAILED;
492518678f8Sopenharmony_ci    }
493518678f8Sopenharmony_ci    uint32_t beginIp = pool->addressRange.beginAddress;
494518678f8Sopenharmony_ci    uint32_t endIp = pool->addressRange.endAddress;
495518678f8Sopenharmony_ci    uint32_t netmask = pool->netmask;
496518678f8Sopenharmony_ci    char line[DHCP_FILE_LINE_LENGTH] = {0};
497518678f8Sopenharmony_ci    while (fgets(line, DHCP_FILE_LINE_LENGTH, fp) != nullptr) {
498518678f8Sopenharmony_ci        TrimString(line);
499518678f8Sopenharmony_ci        if (line[0] == '\0') { /* skip empty line */
500518678f8Sopenharmony_ci            continue;
501518678f8Sopenharmony_ci        }
502518678f8Sopenharmony_ci        AddressBinding bind = {0};
503518678f8Sopenharmony_ci        if (ParseAddressBinding(&bind, line) != 0) {
504518678f8Sopenharmony_ci            continue;
505518678f8Sopenharmony_ci        }
506518678f8Sopenharmony_ci        if (IpInRange(bind.ipAddress, beginIp, endIp, netmask)) {
507518678f8Sopenharmony_ci            pool->leaseTable[bind.ipAddress] = bind;
508518678f8Sopenharmony_ci        }
509518678f8Sopenharmony_ci    }
510518678f8Sopenharmony_ci
511518678f8Sopenharmony_ci    if (fclose(fp) != 0) {
512518678f8Sopenharmony_ci        DHCP_LOGE("LoadBindingRecoders fclose fp failed!");
513518678f8Sopenharmony_ci    }
514518678f8Sopenharmony_ci    return RET_SUCCESS;
515518678f8Sopenharmony_ci}
516518678f8Sopenharmony_ci
517518678f8Sopenharmony_ciint SaveBindingRecoders(const DhcpAddressPool *pool, int force)
518518678f8Sopenharmony_ci{
519518678f8Sopenharmony_ci    if (pool == nullptr) {
520518678f8Sopenharmony_ci        DHCP_LOGE("Save binding record, pool is null");
521518678f8Sopenharmony_ci        return RET_FAILED;
522518678f8Sopenharmony_ci    }
523518678f8Sopenharmony_ci    static uint64_t lastTime = 0;
524518678f8Sopenharmony_ci    uint64_t currTime = Tmspsec();
525518678f8Sopenharmony_ci    if (force == 0 && currTime < lastTime + DHCP_REFRESH_LEASE_FILE_INTERVAL) {
526518678f8Sopenharmony_ci        DHCP_LOGE("Save binding record, time interval is not satisfied.");
527518678f8Sopenharmony_ci        return RET_WAIT_SAVE;
528518678f8Sopenharmony_ci    }
529518678f8Sopenharmony_ci    char filePath[DHCP_LEASE_FILE_LENGTH] = {0};
530518678f8Sopenharmony_ci    if (snprintf_s(filePath, sizeof(filePath), sizeof(filePath) - 1, "%s.%s", DHCPD_LEASE_FILE, pool->ifname) < 0) {
531518678f8Sopenharmony_ci        DHCP_LOGE("Failed to set dhcp lease file path!");
532518678f8Sopenharmony_ci        return RET_FAILED;
533518678f8Sopenharmony_ci    }
534518678f8Sopenharmony_ci    char line[DHCP_FILE_LINE_LENGTH] = {0};
535518678f8Sopenharmony_ci    FILE *fp = fopen(filePath, "w");
536518678f8Sopenharmony_ci    if (fp == nullptr) {
537518678f8Sopenharmony_ci        DHCP_LOGE("Save binding records %{private}s failed: %{public}d", filePath, errno);
538518678f8Sopenharmony_ci        return RET_FAILED;
539518678f8Sopenharmony_ci    }
540518678f8Sopenharmony_ci    for (auto index: pool->leaseTable) {
541518678f8Sopenharmony_ci        AddressBinding *binding = &index.second;
542518678f8Sopenharmony_ci        if (binding && WriteAddressBinding(binding, line, sizeof(line)) != RET_SUCCESS) {
543518678f8Sopenharmony_ci            DHCP_LOGE("Failed to convert binding info to string");
544518678f8Sopenharmony_ci        } else {
545518678f8Sopenharmony_ci            fprintf(fp, "%s\n", line);
546518678f8Sopenharmony_ci        }
547518678f8Sopenharmony_ci    }
548518678f8Sopenharmony_ci
549518678f8Sopenharmony_ci    if (fclose(fp) != 0) {
550518678f8Sopenharmony_ci        DHCP_LOGE("SaveBindingRecoders fclose fp failed!");
551518678f8Sopenharmony_ci    }
552518678f8Sopenharmony_ci    lastTime = currTime;
553518678f8Sopenharmony_ci    return RET_SUCCESS;
554518678f8Sopenharmony_ci}
555518678f8Sopenharmony_ci
556518678f8Sopenharmony_civoid SetDistributeMode(int mode)
557518678f8Sopenharmony_ci{
558518678f8Sopenharmony_ci    g_distributeMode = mode;
559518678f8Sopenharmony_ci}
560518678f8Sopenharmony_ciint GetDistributeMode(void)
561518678f8Sopenharmony_ci{
562518678f8Sopenharmony_ci    return g_distributeMode;
563518678f8Sopenharmony_ci}
564518678f8Sopenharmony_ci
565518678f8Sopenharmony_ciint DeleteMacInLease(DhcpAddressPool *pool, AddressBinding *lease)
566518678f8Sopenharmony_ci{
567518678f8Sopenharmony_ci    if ((pool == nullptr) || (lease == nullptr)) {
568518678f8Sopenharmony_ci        DHCP_LOGE("DeleteMacInLease pointer is null.");
569518678f8Sopenharmony_ci        return RET_ERROR;
570518678f8Sopenharmony_ci    }
571518678f8Sopenharmony_ci    for (auto it = pool->leaseTable.begin(); it != pool->leaseTable.end();) {
572518678f8Sopenharmony_ci        AddressBinding *binding = &(it->second);
573518678f8Sopenharmony_ci        if (binding && AddrEquels(binding->chaddr, lease->chaddr, MAC_ADDR_LENGTH)) {
574518678f8Sopenharmony_ci            it = pool->leaseTable.erase(it);
575518678f8Sopenharmony_ci        } else {
576518678f8Sopenharmony_ci            ++it;
577518678f8Sopenharmony_ci        }
578518678f8Sopenharmony_ci    }
579518678f8Sopenharmony_ci    return RET_SUCCESS;
580518678f8Sopenharmony_ci}
581