10d163575Sopenharmony_ci/*
20d163575Sopenharmony_ci * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
30d163575Sopenharmony_ci * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
40d163575Sopenharmony_ci *
50d163575Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
60d163575Sopenharmony_ci * are permitted provided that the following conditions are met:
70d163575Sopenharmony_ci *
80d163575Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of
90d163575Sopenharmony_ci *    conditions and the following disclaimer.
100d163575Sopenharmony_ci *
110d163575Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list
120d163575Sopenharmony_ci *    of conditions and the following disclaimer in the documentation and/or other materials
130d163575Sopenharmony_ci *    provided with the distribution.
140d163575Sopenharmony_ci *
150d163575Sopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used
160d163575Sopenharmony_ci *    to endorse or promote products derived from this software without specific prior written
170d163575Sopenharmony_ci *    permission.
180d163575Sopenharmony_ci *
190d163575Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
200d163575Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
210d163575Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
220d163575Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
230d163575Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
240d163575Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
250d163575Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
260d163575Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
270d163575Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
280d163575Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
290d163575Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
300d163575Sopenharmony_ci */
310d163575Sopenharmony_ci
320d163575Sopenharmony_ci/**
330d163575Sopenharmony_ci * @file
340d163575Sopenharmony_ci * Dynamic Host Configuration Protocol Server
350d163575Sopenharmony_ci *
360d163575Sopenharmony_ci */
370d163575Sopenharmony_ci
380d163575Sopenharmony_ci#include "../core/ipv4/dhcp.c"  /* for enum dhcp_option_idx/dhcp_option_xx/dhcp_parse_reply etc. */
390d163575Sopenharmony_ci
400d163575Sopenharmony_ci#include "lwip/opt.h"
410d163575Sopenharmony_ci
420d163575Sopenharmony_ci#if (LWIP_DHCP) && (LWIP_DHCPS) /* don't build if not configured for use in lwipopts.h */
430d163575Sopenharmony_ci#include <string.h>
440d163575Sopenharmony_ci
450d163575Sopenharmony_ci#include "lwip/stats.h"
460d163575Sopenharmony_ci#include "lwip/mem.h"
470d163575Sopenharmony_ci#include "lwip/udp.h"
480d163575Sopenharmony_ci#include "lwip/ip_addr.h"
490d163575Sopenharmony_ci#include "lwip/netif.h"
500d163575Sopenharmony_ci#include "lwip/def.h"
510d163575Sopenharmony_ci#include "lwip/prot/dhcp.h"
520d163575Sopenharmony_ci#include "lwip/dhcp.h"
530d163575Sopenharmony_ci#include "lwip/dhcps.h"
540d163575Sopenharmony_ci#include "lwip/sys.h"
550d163575Sopenharmony_ci#include "netif/etharp.h"
560d163575Sopenharmony_ci
570d163575Sopenharmony_ci#define DHCPS_ADDRESS_FREE 0x0
580d163575Sopenharmony_ci#define DHCPS_ADDRESS_OFFERRED 0x1
590d163575Sopenharmony_ci#define DHCPS_ADDRESS_BOUND 0x2
600d163575Sopenharmony_ci#define DHCPS_ADDRESS_DECLINED 0x3
610d163575Sopenharmony_ci
620d163575Sopenharmony_ci#define LWIP_STATIC static
630d163575Sopenharmony_ci#define DHCP_OPTION_ROUTER_SIZE     4
640d163575Sopenharmony_ci#define DHCP_OPTION_SUBNET_MASK_SIZE 4
650d163575Sopenharmony_ci#define DHCP_OPTION_LEASE_TIME_SIZE 4
660d163575Sopenharmony_ci#define DHCP_OPTION_SERVER_ID_LEN   4
670d163575Sopenharmony_ci#define DHCP_OPTION_T1_LEN          4
680d163575Sopenharmony_ci#define DHCP_OPTION_T2_LEN          4
690d163575Sopenharmony_ci
700d163575Sopenharmony_ci#define DHCP_CLIENT_PORT  68
710d163575Sopenharmony_ci#define DHCP_SERVER_PORT  67
720d163575Sopenharmony_ci
730d163575Sopenharmony_ci#define DHCP_BROADCAST_FLAG             0x8000
740d163575Sopenharmony_ci
750d163575Sopenharmony_cistruct dyn_lease_addr {
760d163575Sopenharmony_ci    u8_t cli_hwaddr[DHCP_CHADDR_LEN];
770d163575Sopenharmony_ci    u32_t flags;
780d163575Sopenharmony_ci    u32_t leasetime;
790d163575Sopenharmony_ci    u32_t proposed_leasetime;
800d163575Sopenharmony_ci    ip4_addr_t cli_addr;
810d163575Sopenharmony_ci};
820d163575Sopenharmony_ci
830d163575Sopenharmony_cistruct dhcps {
840d163575Sopenharmony_ci    struct dhcp dhcp;
850d163575Sopenharmony_ci    struct udp_pcb *pcb;
860d163575Sopenharmony_ci    struct dyn_lease_addr leasearr[LWIP_DHCPS_MAX_LEASE];
870d163575Sopenharmony_ci    u8_t pcb_allocated;
880d163575Sopenharmony_ci    u8_t lease_num;
890d163575Sopenharmony_ci    struct netif *netif;
900d163575Sopenharmony_ci    ip4_addr_t start_addr;
910d163575Sopenharmony_ci    ip4_addr_t end_addr;
920d163575Sopenharmony_ci};
930d163575Sopenharmony_ci
940d163575Sopenharmony_ci#define dhcps_option_given(dhcps, idx)          dhcp_option_given(&(dhcps)->dhcp, idx)
950d163575Sopenharmony_ci#define dhcps_got_option(dhcps, idx)            dhcp_got_option(&(dhcps)->dhcp, idx)
960d163575Sopenharmony_ci#define dhcps_clear_option(dhcps, idx)          dhcp_clear_option(&(dhcps)->dhcp, idx)
970d163575Sopenharmony_ci#define dhcps_clear_all_options(dhcps)          dhcp_clear_all_options(&(dhcps)->dhcp)
980d163575Sopenharmony_ci#define dhcps_get_option_value(dhcps, idx)      dhcp_get_option_value(&(dhcps)->dhcp, idx)
990d163575Sopenharmony_ci#define dhcps_set_option_value(dhcps, idx, val) dhcp_set_option_value(&(dhcps)->dhcp, idx, val)
1000d163575Sopenharmony_ci
1010d163575Sopenharmony_ci#define netif_get_dhcps(netif) ((struct dhcps*)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCPS))
1020d163575Sopenharmony_ci#define netif_set_dhcps(netif, dhcps) netif_set_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_DHCPS, dhcps)
1030d163575Sopenharmony_ci
1040d163575Sopenharmony_ciLWIP_STATIC void dhcp_common_option(struct dhcp_msg *msg_out, u8_t option_type, u8_t option_len, u16_t *options_out_len);
1050d163575Sopenharmony_ciLWIP_STATIC void dhcp_common_option_byte(struct dhcp_msg *msg_out, u8_t value, u16_t *options_out_len);
1060d163575Sopenharmony_ciLWIP_STATIC void dhcp_common_option_long(struct dhcp_msg *msg_out, u32_t value, u16_t *options_out_len);
1070d163575Sopenharmony_ciLWIP_STATIC void dhcp_common_option_trailer(struct dhcp_msg *msg_out, u16_t options_out_len, struct pbuf *p_out);
1080d163575Sopenharmony_ciLWIP_STATIC err_t dhcps_parse_options(struct pbuf *p, struct dhcps *dhcps);
1090d163575Sopenharmony_ci
1100d163575Sopenharmony_ciLWIP_STATIC struct pbuf *dhcps_create_base_msg(struct dhcp_msg *client_msg);
1110d163575Sopenharmony_ciLWIP_STATIC void remove_stale_entries(struct dhcps *dhcps);
1120d163575Sopenharmony_ciLWIP_STATIC void add_client_entry(struct dhcps *dhcps, unsigned int idx, struct dhcp_msg *client_msg);
1130d163575Sopenharmony_ciLWIP_STATIC int find_free_slot(struct dhcps *dhcps);
1140d163575Sopenharmony_ciLWIP_STATIC struct dyn_lease_addr *find_client_lease(struct dhcps *dhcps, struct dhcp_msg *client_msg);
1150d163575Sopenharmony_ciLWIP_STATIC ip4_addr_t validate_discover(struct dhcps *dhcps, struct dhcp_msg *client_msg,
1160d163575Sopenharmony_ci                                         struct dyn_lease_addr **client_lease);
1170d163575Sopenharmony_ciLWIP_STATIC void handle_discover(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
1180d163575Sopenharmony_ci                                 struct dyn_lease_addr *client_lease);
1190d163575Sopenharmony_ciLWIP_STATIC ip4_addr_t validate_request_message(struct netif *netif, struct dhcp_msg *client_msg,
1200d163575Sopenharmony_ci                                                struct dyn_lease_addr *client_lease, ip4_addr_t serverid);
1210d163575Sopenharmony_ciLWIP_STATIC void handle_request(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
1220d163575Sopenharmony_ci                                struct dyn_lease_addr *client_lease, ip4_addr_t serverid);
1230d163575Sopenharmony_ciLWIP_STATIC void handle_decline(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
1240d163575Sopenharmony_ci                                struct dyn_lease_addr *client_lease);
1250d163575Sopenharmony_ciLWIP_STATIC void handle_inform(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg);
1260d163575Sopenharmony_ciLWIP_STATIC void handle_client_messages(struct netif *netif, struct dhcps *dhcps,
1270d163575Sopenharmony_ci                                        struct dhcp_msg *client_msg, ip4_addr_t serverid, u8_t msg_type);
1280d163575Sopenharmony_ciLWIP_STATIC void dhcps_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p,
1290d163575Sopenharmony_ci                            const ip_addr_t *ip_addr, u16_t port);
1300d163575Sopenharmony_ci
1310d163575Sopenharmony_ciLWIP_STATIC struct pbuf *dhcps_create_base_msg(struct dhcp_msg *client_msg)
1320d163575Sopenharmony_ci{
1330d163575Sopenharmony_ci    struct pbuf *srvr_msg_pbuf = NULL;
1340d163575Sopenharmony_ci    struct dhcp_msg *srvr_msg = NULL;
1350d163575Sopenharmony_ci
1360d163575Sopenharmony_ci    srvr_msg_pbuf = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
1370d163575Sopenharmony_ci    if (srvr_msg_pbuf == NULL) {
1380d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
1390d163575Sopenharmony_ci                    ("dhcps_create_base_msg(): could not allocate pbuf\n"));
1400d163575Sopenharmony_ci        return NULL;
1410d163575Sopenharmony_ci    }
1420d163575Sopenharmony_ci
1430d163575Sopenharmony_ci    LWIP_ASSERT("dhcps_create_base_msg: check that first pbuf can hold struct dhcp_msg",
1440d163575Sopenharmony_ci                (srvr_msg_pbuf->len >= sizeof(struct dhcp_msg)));
1450d163575Sopenharmony_ci#if DRIVER_STATUS_CHECK
1460d163575Sopenharmony_ci    srvr_msg_pbuf->flags |= PBUF_FLAG_DHCP_BUF;
1470d163575Sopenharmony_ci#endif
1480d163575Sopenharmony_ci
1490d163575Sopenharmony_ci    srvr_msg = (struct dhcp_msg *)srvr_msg_pbuf->payload;
1500d163575Sopenharmony_ci    srvr_msg->op = DHCP_BOOTREPLY;
1510d163575Sopenharmony_ci    srvr_msg->htype = client_msg->htype;
1520d163575Sopenharmony_ci    srvr_msg->hlen = client_msg->hlen;
1530d163575Sopenharmony_ci    srvr_msg->hops = 0;
1540d163575Sopenharmony_ci    srvr_msg->xid = client_msg->xid;
1550d163575Sopenharmony_ci    srvr_msg->secs = 0;
1560d163575Sopenharmony_ci    srvr_msg->flags = client_msg->flags;
1570d163575Sopenharmony_ci    ip4_addr_set_zero(&srvr_msg->ciaddr);
1580d163575Sopenharmony_ci    ip4_addr_set_zero(&srvr_msg->yiaddr);
1590d163575Sopenharmony_ci    ip4_addr_set_zero(&srvr_msg->siaddr);
1600d163575Sopenharmony_ci    ip4_addr_copy(srvr_msg->giaddr, client_msg->giaddr);
1610d163575Sopenharmony_ci    if (memcpy_s(srvr_msg->chaddr, sizeof(srvr_msg->chaddr), client_msg->chaddr, DHCP_CHADDR_LEN) != EOK) {
1620d163575Sopenharmony_ci        (void)pbuf_free(srvr_msg_pbuf);
1630d163575Sopenharmony_ci        return NULL;
1640d163575Sopenharmony_ci    }
1650d163575Sopenharmony_ci    (void)memset_s(srvr_msg->sname, sizeof(srvr_msg->sname), 0, DHCP_SNAME_LEN);
1660d163575Sopenharmony_ci    (void)memset_s(srvr_msg->file, sizeof(srvr_msg->file), 0, DHCP_FILE_LEN);
1670d163575Sopenharmony_ci    srvr_msg->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
1680d163575Sopenharmony_ci
1690d163575Sopenharmony_ci    return srvr_msg_pbuf;
1700d163575Sopenharmony_ci}
1710d163575Sopenharmony_ci
1720d163575Sopenharmony_ciLWIP_STATIC void remove_stale_entries(struct dhcps *dhcps)
1730d163575Sopenharmony_ci{
1740d163575Sopenharmony_ci    int i = 0;
1750d163575Sopenharmony_ci    u32_t curr_time = sys_now();
1760d163575Sopenharmony_ci
1770d163575Sopenharmony_ci    for (i = 0; i < dhcps->lease_num; i++) {
1780d163575Sopenharmony_ci        /* Slot should not be free or have infinite lease time */
1790d163575Sopenharmony_ci        if ((dhcps->leasearr[i].flags != DHCPS_ADDRESS_FREE) && (dhcps->leasearr[i].leasetime != (u32_t)~0)) {
1800d163575Sopenharmony_ci            if (dhcps->leasearr[i].leasetime < curr_time) {
1810d163575Sopenharmony_ci                LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
1820d163575Sopenharmony_ci                            ("remove_stale_entries: Removing Client Entry at Index = %"U32_F"\n", i));
1830d163575Sopenharmony_ci                (void)memset_s(&(dhcps->leasearr[i]), sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
1840d163575Sopenharmony_ci                dhcps->leasearr[i].flags = DHCPS_ADDRESS_FREE;
1850d163575Sopenharmony_ci            }
1860d163575Sopenharmony_ci        }
1870d163575Sopenharmony_ci    }
1880d163575Sopenharmony_ci}
1890d163575Sopenharmony_ci
1900d163575Sopenharmony_ciLWIP_STATIC void add_client_entry(struct dhcps *dhcps, unsigned int idx, struct dhcp_msg *client_msg)
1910d163575Sopenharmony_ci{
1920d163575Sopenharmony_ci    u32_t client_lease_time = (u32_t)(LWIP_DHCPS_LEASE_TIME);
1930d163575Sopenharmony_ci
1940d163575Sopenharmony_ci    if ((dhcps_option_given(dhcps, DHCP_OPTION_IDX_LEASE_TIME))
1950d163575Sopenharmony_ci#if (LWIP_DHCPS_LEASE_TIME != ~0)
1960d163575Sopenharmony_ci        && (dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_LEASE_TIME) < LWIP_DHCPS_LEASE_TIME)
1970d163575Sopenharmony_ci#endif
1980d163575Sopenharmony_ci        ) {
1990d163575Sopenharmony_ci        client_lease_time = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_LEASE_TIME);
2000d163575Sopenharmony_ci    }
2010d163575Sopenharmony_ci
2020d163575Sopenharmony_ci    (void)memset_s(&(dhcps->leasearr[idx]), sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
2030d163575Sopenharmony_ci    if (memcpy_s(dhcps->leasearr[idx].cli_hwaddr, DHCP_CHADDR_LEN,
2040d163575Sopenharmony_ci                 client_msg->chaddr, sizeof(client_msg->chaddr)) != EOK) {
2050d163575Sopenharmony_ci        return;
2060d163575Sopenharmony_ci    }
2070d163575Sopenharmony_ci    /* This is called only during offer message, so adding offer time.
2080d163575Sopenharmony_ci      This is later updated to lease time when request message is handled */
2090d163575Sopenharmony_ci    dhcps->leasearr[idx].leasetime = sys_now() + (LWIP_DHCPS_OFFER_TIME * 1000);
2100d163575Sopenharmony_ci    dhcps->leasearr[idx].cli_addr.addr = dhcps->start_addr.addr + idx;
2110d163575Sopenharmony_ci    dhcps->leasearr[idx].flags = DHCPS_ADDRESS_OFFERRED;
2120d163575Sopenharmony_ci    dhcps->leasearr[idx].proposed_leasetime = client_lease_time;
2130d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("add_client_entry: Adding Client Entry at Index = %"U32_F"\n", idx));
2140d163575Sopenharmony_ci}
2150d163575Sopenharmony_ci
2160d163575Sopenharmony_ciLWIP_STATIC int find_free_slot(struct dhcps *dhcps)
2170d163575Sopenharmony_ci{
2180d163575Sopenharmony_ci    int i;
2190d163575Sopenharmony_ci    for (i = 0; i < dhcps->lease_num; i++) {
2200d163575Sopenharmony_ci        if ((dhcps->leasearr[i].flags == DHCPS_ADDRESS_FREE) &&
2210d163575Sopenharmony_ci            (htonl(dhcps->start_addr.addr + (u32_t)i) != ip_2_ip4(&dhcps->netif->ip_addr)->addr)) {
2220d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("find_free_slot: Found Free Slot at Index = %"U32_F"\n", i));
2230d163575Sopenharmony_ci            return i;
2240d163575Sopenharmony_ci        }
2250d163575Sopenharmony_ci    }
2260d163575Sopenharmony_ci
2270d163575Sopenharmony_ci    return -1;
2280d163575Sopenharmony_ci}
2290d163575Sopenharmony_ci
2300d163575Sopenharmony_ciLWIP_STATIC struct dyn_lease_addr *find_client_lease(struct dhcps *dhcps, struct dhcp_msg *client_msg)
2310d163575Sopenharmony_ci{
2320d163575Sopenharmony_ci    int i;
2330d163575Sopenharmony_ci    for (i = 0; i < dhcps->lease_num; i++) {
2340d163575Sopenharmony_ci        if (dhcps->leasearr[i].flags != DHCPS_ADDRESS_FREE) {
2350d163575Sopenharmony_ci            if (memcmp(dhcps->leasearr[i].cli_hwaddr, client_msg->chaddr, client_msg->hlen) == 0) {
2360d163575Sopenharmony_ci                LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
2370d163575Sopenharmony_ci                            ("find_client_lease: Found Client Lease at Index = %"U32_F"\n", i));
2380d163575Sopenharmony_ci                return &(dhcps->leasearr[i]);
2390d163575Sopenharmony_ci            }
2400d163575Sopenharmony_ci        }
2410d163575Sopenharmony_ci    }
2420d163575Sopenharmony_ci
2430d163575Sopenharmony_ci    return NULL;
2440d163575Sopenharmony_ci}
2450d163575Sopenharmony_ci
2460d163575Sopenharmony_ciLWIP_STATIC ip4_addr_t validate_discover(struct dhcps *dhcps, struct dhcp_msg *client_msg,
2470d163575Sopenharmony_ci                                         struct dyn_lease_addr **client_lease)
2480d163575Sopenharmony_ci{
2490d163575Sopenharmony_ci    ip4_addr_t client_ip;
2500d163575Sopenharmony_ci    int idx = -1;
2510d163575Sopenharmony_ci
2520d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_discover: Validating Discover Message\n"));
2530d163575Sopenharmony_ci
2540d163575Sopenharmony_ci    client_ip.addr = 0;
2550d163575Sopenharmony_ci    if (*client_lease == NULL) {
2560d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_discover: Existing Client Lease not Found\n"));
2570d163575Sopenharmony_ci        if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) {
2580d163575Sopenharmony_ci            client_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
2590d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
2600d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
2610d163575Sopenharmony_ci                        ("validate_discover function: Requested IP from client = %"U32_F"\n", client_ip.addr));
2620d163575Sopenharmony_ci#endif
2630d163575Sopenharmony_ci
2640d163575Sopenharmony_ci            if ((client_ip.addr >= dhcps->start_addr.addr) && (client_ip.addr <= dhcps->end_addr.addr)) {
2650d163575Sopenharmony_ci                idx = (int)(client_ip.addr - dhcps->start_addr.addr);
2660d163575Sopenharmony_ci                if ((dhcps->leasearr[idx].flags != DHCPS_ADDRESS_FREE) ||
2670d163575Sopenharmony_ci                    (ntohl(client_ip.addr) == ip_2_ip4(&dhcps->netif->ip_addr)->addr)) {
2680d163575Sopenharmony_ci                    /* Requested IP is not available */
2690d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
2700d163575Sopenharmony_ci                    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
2710d163575Sopenharmony_ci                      ("validate_discover function: Requested IP from client = %"U32_F" Not available \n", client_ip.addr));
2720d163575Sopenharmony_ci#endif
2730d163575Sopenharmony_ci                    idx = -1;
2740d163575Sopenharmony_ci                }
2750d163575Sopenharmony_ci            }
2760d163575Sopenharmony_ci        }
2770d163575Sopenharmony_ci
2780d163575Sopenharmony_ci        if (idx == -1) {
2790d163575Sopenharmony_ci            idx = find_free_slot(dhcps);
2800d163575Sopenharmony_ci            if (idx == -1) {
2810d163575Sopenharmony_ci                LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
2820d163575Sopenharmony_ci                            ("validate_discover function: No Free Slot available for Storing addresses\n"));
2830d163575Sopenharmony_ci                client_ip.addr = 0;
2840d163575Sopenharmony_ci                return client_ip;
2850d163575Sopenharmony_ci            }
2860d163575Sopenharmony_ci            client_ip.addr = dhcps->start_addr.addr + (u32_t)idx;
2870d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
2880d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
2890d163575Sopenharmony_ci                        ("validate_discover function: New IP = %"U32_F" is being assigned\n", client_ip.addr));
2900d163575Sopenharmony_ci#endif
2910d163575Sopenharmony_ci        }
2920d163575Sopenharmony_ci
2930d163575Sopenharmony_ci        add_client_entry(dhcps, (unsigned int)idx, client_msg);
2940d163575Sopenharmony_ci        (*client_lease) = &(dhcps->leasearr[idx]);
2950d163575Sopenharmony_ci    } else {
2960d163575Sopenharmony_ci        client_ip.addr = (*client_lease)->cli_addr.addr;
2970d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
2980d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
2990d163575Sopenharmony_ci                    ("validate_discover: Existing Client Lease Found. Existing IP =%"U32_F"\n", client_ip.addr));
3000d163575Sopenharmony_ci#endif
3010d163575Sopenharmony_ci
3020d163575Sopenharmony_ci        if ((dhcps_option_given(dhcps, DHCP_OPTION_IDX_LEASE_TIME))
3030d163575Sopenharmony_ci#if (~0 != LWIP_DHCPS_LEASE_TIME)
3040d163575Sopenharmony_ci            && (dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_LEASE_TIME) < LWIP_DHCPS_LEASE_TIME)
3050d163575Sopenharmony_ci#endif
3060d163575Sopenharmony_ci            ) {
3070d163575Sopenharmony_ci            /* Assign the newly requested time or else use the existing lease time as-is */
3080d163575Sopenharmony_ci            (*client_lease)->proposed_leasetime = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_LEASE_TIME);
3090d163575Sopenharmony_ci        }
3100d163575Sopenharmony_ci    }
3110d163575Sopenharmony_ci
3120d163575Sopenharmony_ci    return client_ip;
3130d163575Sopenharmony_ci}
3140d163575Sopenharmony_ci
3150d163575Sopenharmony_civoid dhcp_common_option(struct dhcp_msg *msg_out, u8_t option_type, u8_t option_len, u16_t *options_out_len)
3160d163575Sopenharmony_ci{
3170d163575Sopenharmony_ci    *options_out_len = dhcp_option(*options_out_len, msg_out->options, option_type, option_len);
3180d163575Sopenharmony_ci}
3190d163575Sopenharmony_ci
3200d163575Sopenharmony_civoid dhcp_common_option_byte(struct dhcp_msg *msg_out, u8_t value, u16_t *options_out_len)
3210d163575Sopenharmony_ci{
3220d163575Sopenharmony_ci    *options_out_len = dhcp_option_byte(*options_out_len, msg_out->options, value);
3230d163575Sopenharmony_ci}
3240d163575Sopenharmony_ci
3250d163575Sopenharmony_civoid dhcp_common_option_long(struct dhcp_msg *msg_out, u32_t value, u16_t *options_out_len)
3260d163575Sopenharmony_ci{
3270d163575Sopenharmony_ci    *options_out_len = dhcp_option_long(*options_out_len, msg_out->options, value);
3280d163575Sopenharmony_ci}
3290d163575Sopenharmony_ci
3300d163575Sopenharmony_civoid dhcp_common_option_trailer(struct dhcp_msg *msg_out, u16_t options_out_len, struct pbuf *p_out)
3310d163575Sopenharmony_ci{
3320d163575Sopenharmony_ci    dhcp_option_trailer(options_out_len, msg_out->options, p_out);
3330d163575Sopenharmony_ci}
3340d163575Sopenharmony_ci
3350d163575Sopenharmony_ciLWIP_STATIC void handle_discover(struct netif *netif, struct dhcps *dhcps,
3360d163575Sopenharmony_ci                                 struct dhcp_msg *client_msg, struct dyn_lease_addr *client_lease)
3370d163575Sopenharmony_ci{
3380d163575Sopenharmony_ci#if !LWIP_DHCPS_DISCOVER_BROADCAST
3390d163575Sopenharmony_ci    ip_addr_t client_ipaddr;
3400d163575Sopenharmony_ci#endif
3410d163575Sopenharmony_ci
3420d163575Sopenharmony_ci    ip4_addr_t client_ip;
3430d163575Sopenharmony_ci    ip_addr_t dst_addr;
3440d163575Sopenharmony_ci    struct pbuf *out_msg = NULL;
3450d163575Sopenharmony_ci    struct dhcp_msg *srvr_msg = NULL;
3460d163575Sopenharmony_ci    u16_t options_len = 0;
3470d163575Sopenharmony_ci#if !LWIP_DHCPS_DISCOVER_BROADCAST
3480d163575Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
3490d163575Sopenharmony_ci    struct eth_addr ethaddr;
3500d163575Sopenharmony_ci#endif
3510d163575Sopenharmony_ci#endif
3520d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Processing Discover Message\n"));
3530d163575Sopenharmony_ci
3540d163575Sopenharmony_ci    client_ip = validate_discover(dhcps, client_msg, &client_lease);
3550d163575Sopenharmony_ci    if (client_ip.addr == 0) {
3560d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
3570d163575Sopenharmony_ci                    ("handle_discover: Returning as unable to get a proper address for client\n"));
3580d163575Sopenharmony_ci        return;
3590d163575Sopenharmony_ci    }
3600d163575Sopenharmony_ci
3610d163575Sopenharmony_ci    out_msg = dhcps_create_base_msg(client_msg);
3620d163575Sopenharmony_ci    if (out_msg == NULL) {
3630d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
3640d163575Sopenharmony_ci                    ("handle_discover function: Memory allocation for base message failed\n"));
3650d163575Sopenharmony_ci        return;
3660d163575Sopenharmony_ci    }
3670d163575Sopenharmony_ci
3680d163575Sopenharmony_ci    srvr_msg = (struct dhcp_msg *)out_msg->payload;
3690d163575Sopenharmony_ci    // no need check msg pointer from payload here
3700d163575Sopenharmony_ci    srvr_msg->yiaddr.addr = htonl(client_ip.addr);
3710d163575Sopenharmony_ci
3720d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
3730d163575Sopenharmony_ci    dhcp_common_option_byte(srvr_msg, DHCP_OFFER, &options_len);
3740d163575Sopenharmony_ci
3750d163575Sopenharmony_ci    /* hilink need this router option */
3760d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_ROUTER, DHCP_OPTION_ROUTER_SIZE, &options_len);
3770d163575Sopenharmony_ci    dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
3780d163575Sopenharmony_ci
3790d163575Sopenharmony_ci    /* netif already holds the Server ID in network order. so, no need to convert it again */
3800d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_SERVER_ID, DHCP_OPTION_SERVER_ID_LEN, &options_len);
3810d163575Sopenharmony_ci    dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
3820d163575Sopenharmony_ci
3830d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_LEASE_TIME, DHCP_OPTION_LEASE_TIME_SIZE, &options_len);
3840d163575Sopenharmony_ci    dhcp_common_option_long(srvr_msg, client_lease->proposed_leasetime, &options_len);
3850d163575Sopenharmony_ci
3860d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_T1, DHCP_OPTION_T1_LEN, &options_len);
3870d163575Sopenharmony_ci    dhcp_common_option_long(srvr_msg, (client_lease->proposed_leasetime / 2), &options_len);
3880d163575Sopenharmony_ci
3890d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_T2, DHCP_OPTION_T2_LEN, &options_len);
3900d163575Sopenharmony_ci    /* calculate safe periods for lease (proposed_leasetime * 0.875 -> 87.5%) */
3910d163575Sopenharmony_ci    dhcp_common_option_long(srvr_msg, ((client_lease->proposed_leasetime * 7) / 8), &options_len);
3920d163575Sopenharmony_ci
3930d163575Sopenharmony_ci    /* No need to convert netmask into network order as it is already stored in network order */
3940d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_SUBNET_MASK_SIZE, &options_len);
3950d163575Sopenharmony_ci    dhcp_common_option_long(srvr_msg, ntohl(ip4_addr_get_u32(ip_2_ip4(&netif->netmask))), &options_len);
3960d163575Sopenharmony_ci
3970d163575Sopenharmony_ci    dhcp_common_option_trailer(srvr_msg, options_len, out_msg);
3980d163575Sopenharmony_ci
3990d163575Sopenharmony_ci    if (client_msg->ciaddr.addr != 0) {
4000d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: sendto(OFFER, ciaddr, DHCP_CLIENT_PORT)\n"));
4010d163575Sopenharmony_ci        ip_addr_set_ip4_u32_val(dst_addr, (u32_t)(client_msg->ciaddr.addr));
4020d163575Sopenharmony_ci        (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
4030d163575Sopenharmony_ci    }
4040d163575Sopenharmony_ci#if !LWIP_DHCPS_DISCOVER_BROADCAST
4050d163575Sopenharmony_ci    else if (ntohs(client_msg->flags) & DHCP_BROADCAST_FLAG) {
4060d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
4070d163575Sopenharmony_ci                    ("handle_discover: sendto(OFFER, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT)\n"));
4080d163575Sopenharmony_ci        (void)udp_sendto_if_src(dhcps->pcb, out_msg, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
4090d163575Sopenharmony_ci    } else {
4100d163575Sopenharmony_ci        client_ip.addr = htonl(client_ip.addr);
4110d163575Sopenharmony_ci
4120d163575Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
4130d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Updating ARP Static Entry for unicast reply\n"));
4140d163575Sopenharmony_ci        if (memcpy_s(ethaddr.addr, ETHARP_HWADDR_LEN, client_msg->chaddr, client_msg->hlen) != EOK) {
4150d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("memcpy_s failed\n"));
4160d163575Sopenharmony_ci            (void)pbuf_free(out_msg);
4170d163575Sopenharmony_ci            return;
4180d163575Sopenharmony_ci        }
4190d163575Sopenharmony_ci        if (etharp_add_static_entry(&client_ip, &ethaddr) != ERR_OK) {
4200d163575Sopenharmony_ci            (void)pbuf_free(out_msg);
4210d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Adding static entry to arp cache failed\n"));
4220d163575Sopenharmony_ci            return;
4230d163575Sopenharmony_ci        }
4240d163575Sopenharmony_ci#endif
4250d163575Sopenharmony_ci
4260d163575Sopenharmony_ci        /* Need to check and add an arp entry to make this pass through smoothly */
4270d163575Sopenharmony_ci        ip_addr_copy_from_ip4(client_ipaddr, client_ip);
4280d163575Sopenharmony_ci        (void)udp_sendto_if_src(dhcps->pcb, out_msg, &client_ipaddr, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
4290d163575Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
4300d163575Sopenharmony_ci        /* We just added the entry above and checked for it's success too. so, the below function call cannot fail */
4310d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
4320d163575Sopenharmony_ci                    ("handle_discover: Removing ARP Static Entry added for unicast reply\n"));
4330d163575Sopenharmony_ci        (void)etharp_remove_static_entry(&client_ip);
4340d163575Sopenharmony_ci#endif
4350d163575Sopenharmony_ci    }
4360d163575Sopenharmony_ci#else
4370d163575Sopenharmony_ci    else {
4380d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
4390d163575Sopenharmony_ci                    ("handle_discover: sendto(OFFER, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT)\n"));
4400d163575Sopenharmony_ci        (void)udp_sendto_if_src(dhcps->pcb, out_msg, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
4410d163575Sopenharmony_ci    }
4420d163575Sopenharmony_ci#endif
4430d163575Sopenharmony_ci
4440d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: deleting()ing\n"));
4450d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_discover: Sending Reply has been successful\n"));
4460d163575Sopenharmony_ci
4470d163575Sopenharmony_ci    (void)pbuf_free(out_msg);
4480d163575Sopenharmony_ci    return;
4490d163575Sopenharmony_ci}
4500d163575Sopenharmony_ci
4510d163575Sopenharmony_ciLWIP_STATIC ip4_addr_t validate_request_message(struct netif *netif, struct dhcp_msg *client_msg,
4520d163575Sopenharmony_ci                                                struct dyn_lease_addr *client_lease, ip4_addr_t serverid)
4530d163575Sopenharmony_ci{
4540d163575Sopenharmony_ci    struct dhcps *dhcps = netif_get_dhcps(netif);
4550d163575Sopenharmony_ci    ip4_addr_t requested_ip;
4560d163575Sopenharmony_ci    requested_ip.addr = 0;
4570d163575Sopenharmony_ci
4580d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: Processing Request Message\n"));
4590d163575Sopenharmony_ci
4600d163575Sopenharmony_ci    if ((client_lease != NULL) && (client_lease->flags == DHCPS_ADDRESS_OFFERRED)) {
4610d163575Sopenharmony_ci        /* Now, we are in selecting state */
4620d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: In Selecting State\n"));
4630d163575Sopenharmony_ci
4640d163575Sopenharmony_ci        if ((serverid.addr == 0) || (client_msg->ciaddr.addr != 0) ||
4650d163575Sopenharmony_ci            (!dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP))) {
4660d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
4670d163575Sopenharmony_ci                        ("Server ID or ciaddr or requested ip option is not present\n"));
4680d163575Sopenharmony_ci            return requested_ip;
4690d163575Sopenharmony_ci        }
4700d163575Sopenharmony_ci
4710d163575Sopenharmony_ci        if (serverid.addr != ip_2_ip4(&netif->ip_addr)->addr) {
4720d163575Sopenharmony_ci            /* This message is not meant for us. The client intends to talk to some other server */
4730d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
4740d163575Sopenharmony_ci                        ("validate_request_message: Server id doesn't match with ours. Message not for us\n"));
4750d163575Sopenharmony_ci            requested_ip.addr = 1;
4760d163575Sopenharmony_ci            return requested_ip;
4770d163575Sopenharmony_ci        }
4780d163575Sopenharmony_ci
4790d163575Sopenharmony_ci        requested_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
4800d163575Sopenharmony_ci    } else {
4810d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
4820d163575Sopenharmony_ci                    ("validate_request_message: In Init-Reboot, Renew or Rebinding State\n"));
4830d163575Sopenharmony_ci
4840d163575Sopenharmony_ci        /* Now, we can be either in Init-reboot state or renew state or rebinding state */
4850d163575Sopenharmony_ci        if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) {
4860d163575Sopenharmony_ci            /* Requested IP option is filled in. Indicates we are mostly in Init-Reboot State */
4870d163575Sopenharmony_ci            if (client_lease == NULL) {
4880d163575Sopenharmony_ci                LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
4890d163575Sopenharmony_ci                            ("validate_request_message: No Configuration found corresponding to request message\n"));
4900d163575Sopenharmony_ci                return requested_ip;
4910d163575Sopenharmony_ci            }
4920d163575Sopenharmony_ci
4930d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
4940d163575Sopenharmony_ci                        ("validate_request_message: Requested IP Option is present. So, considering as Init-Reboot State\n"));
4950d163575Sopenharmony_ci
4960d163575Sopenharmony_ci            if (client_msg->ciaddr.addr != 0) {
4970d163575Sopenharmony_ci                LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
4980d163575Sopenharmony_ci                            ("validate_request_message: Error: ciaddr is filled in the Init-Reboot state. \n"));
4990d163575Sopenharmony_ci                return requested_ip;
5000d163575Sopenharmony_ci            }
5010d163575Sopenharmony_ci
5020d163575Sopenharmony_ci            requested_ip.addr = (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP);
5030d163575Sopenharmony_ci        } else {
5040d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: \
5050d163575Sopenharmony_ci                  Requested IP Option is not present. So, considering as Renewing or Rebinding State\n"));
5060d163575Sopenharmony_ci
5070d163575Sopenharmony_ci            if (client_msg->ciaddr.addr == 0) {
5080d163575Sopenharmony_ci                LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
5090d163575Sopenharmony_ci                            ("validate_request_message: Error: ciaddr is not filled in the Renewing or Rebinding state. \n"));
5100d163575Sopenharmony_ci                return requested_ip;
5110d163575Sopenharmony_ci            }
5120d163575Sopenharmony_ci
5130d163575Sopenharmony_ci            requested_ip.addr = ntohl(client_msg->ciaddr.addr);
5140d163575Sopenharmony_ci        }
5150d163575Sopenharmony_ci    }
5160d163575Sopenharmony_ci
5170d163575Sopenharmony_ci    /* requested_ip is in host order and DHCP Server IP is in network order,
5180d163575Sopenharmony_ci      so converting the former to network order for check */
5190d163575Sopenharmony_ci    if (htonl(requested_ip.addr) == ip_2_ip4(&netif->ip_addr)->addr) {
5200d163575Sopenharmony_ci        /* This requested_ip is the dhcp server is using, it is invalid */
5210d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("validate_request_message: Requested IP addr is invalid\n"));
5220d163575Sopenharmony_ci        requested_ip.addr = 1;
5230d163575Sopenharmony_ci    }
5240d163575Sopenharmony_ci
5250d163575Sopenharmony_ci    return requested_ip;
5260d163575Sopenharmony_ci}
5270d163575Sopenharmony_ci
5280d163575Sopenharmony_ciLWIP_STATIC void handle_request(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
5290d163575Sopenharmony_ci                                struct dyn_lease_addr *client_lease, ip4_addr_t serverid)
5300d163575Sopenharmony_ci{
5310d163575Sopenharmony_ci    ip4_addr_t requested_ip;
5320d163575Sopenharmony_ci    struct pbuf *out_msg = NULL;
5330d163575Sopenharmony_ci    struct dhcp_msg *srvr_msg = NULL;
5340d163575Sopenharmony_ci    u16_t options_len = 0;
5350d163575Sopenharmony_ci    ip_addr_t dst_addr;
5360d163575Sopenharmony_ci    ip_addr_t ip_send;
5370d163575Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
5380d163575Sopenharmony_ci    struct eth_addr ethaddr;
5390d163575Sopenharmony_ci#endif
5400d163575Sopenharmony_ci
5410d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Processing Request Message\n"));
5420d163575Sopenharmony_ci
5430d163575Sopenharmony_ci    requested_ip = validate_request_message(netif, client_msg, client_lease, serverid);
5440d163575Sopenharmony_ci    if (requested_ip.addr == 1) {
5450d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
5460d163575Sopenharmony_ci                    ("handle_request: Validation of request message failed. Dropping the packet.\n"));
5470d163575Sopenharmony_ci        return;
5480d163575Sopenharmony_ci    }
5490d163575Sopenharmony_ci
5500d163575Sopenharmony_ci    out_msg = dhcps_create_base_msg(client_msg);
5510d163575Sopenharmony_ci    if (out_msg == NULL) {
5520d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Creating base message failed\n"));
5530d163575Sopenharmony_ci        return;
5540d163575Sopenharmony_ci    }
5550d163575Sopenharmony_ci
5560d163575Sopenharmony_ci    srvr_msg = (struct dhcp_msg *)out_msg->payload;
5570d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_SERVER_ID, DHCP_OPTION_SERVER_ID_LEN, &options_len);
5580d163575Sopenharmony_ci    dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
5590d163575Sopenharmony_ci
5600d163575Sopenharmony_ci    /* hilink need this router option */
5610d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_ROUTER, DHCP_OPTION_ROUTER_SIZE, &options_len);
5620d163575Sopenharmony_ci    dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->ip_addr)->addr), &options_len);
5630d163575Sopenharmony_ci
5640d163575Sopenharmony_ci    if ((client_lease != NULL) && (client_lease->cli_addr.addr == requested_ip.addr)) {
5650d163575Sopenharmony_ci        if (client_lease->proposed_leasetime != (u32_t)(~0)) {
5660d163575Sopenharmony_ci            if (client_lease->flags == DHCPS_ADDRESS_OFFERRED) {
5670d163575Sopenharmony_ci                client_lease->leasetime = sys_now() + (client_lease->proposed_leasetime * 1000);
5680d163575Sopenharmony_ci            } else {
5690d163575Sopenharmony_ci                client_lease->leasetime += (client_lease->proposed_leasetime * 1000);
5700d163575Sopenharmony_ci            }
5710d163575Sopenharmony_ci        } else {
5720d163575Sopenharmony_ci            client_lease->leasetime = client_lease->proposed_leasetime;
5730d163575Sopenharmony_ci        }
5740d163575Sopenharmony_ci
5750d163575Sopenharmony_ci        client_lease->flags = DHCPS_ADDRESS_BOUND;
5760d163575Sopenharmony_ci        srvr_msg->yiaddr.addr = htonl(client_lease->cli_addr.addr);
5770d163575Sopenharmony_ci
5780d163575Sopenharmony_ci        dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
5790d163575Sopenharmony_ci        dhcp_common_option_byte(srvr_msg, DHCP_ACK, &options_len);
5800d163575Sopenharmony_ci
5810d163575Sopenharmony_ci        dhcp_common_option(srvr_msg, DHCP_OPTION_LEASE_TIME, DHCP_OPTION_LEASE_TIME_SIZE, &options_len);
5820d163575Sopenharmony_ci        dhcp_common_option_long(srvr_msg, client_lease->proposed_leasetime, &options_len);
5830d163575Sopenharmony_ci
5840d163575Sopenharmony_ci        dhcp_common_option(srvr_msg, DHCP_OPTION_T1, DHCP_OPTION_T1_LEN, &options_len);
5850d163575Sopenharmony_ci        dhcp_common_option_long(srvr_msg, (client_lease->proposed_leasetime / 2), &options_len);
5860d163575Sopenharmony_ci
5870d163575Sopenharmony_ci        dhcp_common_option(srvr_msg, DHCP_OPTION_T2, DHCP_OPTION_T2_LEN, &options_len);
5880d163575Sopenharmony_ci        /* calculate safe periods for lease (proposed_leasetime * 0.875 -> 87.5%) */
5890d163575Sopenharmony_ci        dhcp_common_option_long(srvr_msg, ((client_lease->proposed_leasetime * 7) / 8), &options_len);
5900d163575Sopenharmony_ci
5910d163575Sopenharmony_ci        dhcp_common_option(srvr_msg, DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_SUBNET_MASK_SIZE, &options_len);
5920d163575Sopenharmony_ci        dhcp_common_option_long(srvr_msg, ntohl(ip_2_ip4(&netif->netmask)->addr), &options_len);
5930d163575Sopenharmony_ci
5940d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
5950d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
5960d163575Sopenharmony_ci                    ("handle_request: Send ACK. to=%"U32_F" lease time=%"U32_F"\n",
5970d163575Sopenharmony_ci                    requested_ip.addr, client_lease->proposed_leasetime));
5980d163575Sopenharmony_ci#endif
5990d163575Sopenharmony_ci    } else {
6000d163575Sopenharmony_ci        dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
6010d163575Sopenharmony_ci        dhcp_common_option_byte(srvr_msg, DHCP_NAK, &options_len);
6020d163575Sopenharmony_ci
6030d163575Sopenharmony_ci        /* Just set this here, so that the NAK message is brcasted.
6040d163575Sopenharmony_ci        The correct flags has already been added in the response message during base message creation */
6050d163575Sopenharmony_ci        client_msg->flags |= htons(DHCP_BROADCAST_FLAG);
6060d163575Sopenharmony_ci        client_msg->ciaddr.addr = 0; /* This is done so that NAK Gets brcasted */
6070d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
6080d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
6090d163575Sopenharmony_ci                    ("handle_request: Send NAK. Requested from=%"U32_F"\n", requested_ip.addr));
6100d163575Sopenharmony_ci#endif
6110d163575Sopenharmony_ci    }
6120d163575Sopenharmony_ci
6130d163575Sopenharmony_ci    requested_ip.addr = htonl(requested_ip.addr);
6140d163575Sopenharmony_ci    dhcp_common_option_trailer(srvr_msg, options_len, out_msg);
6150d163575Sopenharmony_ci
6160d163575Sopenharmony_ci    if (client_msg->ciaddr.addr != 0) {
6170d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: sendto(ACK, ciaddr, DHCP_CLIENT_PORT)\n"));
6180d163575Sopenharmony_ci        ip_addr_set_ip4_u32_val(dst_addr, (u32_t)(client_msg->ciaddr.addr));
6190d163575Sopenharmony_ci        (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
6200d163575Sopenharmony_ci    } else if (ntohs(client_msg->flags) & DHCP_BROADCAST_FLAG) {
6210d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: sending reply using brdcast \n"));
6220d163575Sopenharmony_ci        (void)udp_sendto_if_src(dhcps->pcb, out_msg, IP_ADDR_BROADCAST, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
6230d163575Sopenharmony_ci    } else {
6240d163575Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
6250d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Updating ARP Static Entry for unicast reply\n"));
6260d163575Sopenharmony_ci        if (memcpy_s(ethaddr.addr, ETHARP_HWADDR_LEN, client_msg->chaddr, client_msg->hlen) != EOK) {
6270d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Copy chaddr failed\n"));
6280d163575Sopenharmony_ci            (void)pbuf_free(out_msg);
6290d163575Sopenharmony_ci            return;
6300d163575Sopenharmony_ci        }
6310d163575Sopenharmony_ci        if (ERR_OK != etharp_add_static_entry(&requested_ip, &ethaddr)) {
6320d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: Adding static entry to arp cache failed\n"));
6330d163575Sopenharmony_ci            (void)pbuf_free(out_msg);
6340d163575Sopenharmony_ci            return;
6350d163575Sopenharmony_ci        }
6360d163575Sopenharmony_ci#endif
6370d163575Sopenharmony_ci        /* Need to check and add an arp entry to make this pass through smoothly */
6380d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
6390d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
6400d163575Sopenharmony_ci                    ("handle_request: sending reply using unicast Client IP =%"U32_F"\n", requested_ip.addr));
6410d163575Sopenharmony_ci#endif
6420d163575Sopenharmony_ci        ip_send.u_addr.ip4.addr = requested_ip.addr;
6430d163575Sopenharmony_ci        ip_send.type = IPADDR_TYPE_V4;
6440d163575Sopenharmony_ci        (void)udp_sendto_if_src(dhcps->pcb, out_msg, &ip_send, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
6450d163575Sopenharmony_ci
6460d163575Sopenharmony_ci#if ETHARP_SUPPORT_STATIC_ENTRIES
6470d163575Sopenharmony_ci        /* We just added the entry above and checked for it's success too. so, the below function call cannot fail */
6480d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
6490d163575Sopenharmony_ci                    ("handle_request: Removing ARP Static Entry added for unicast reply\n"));
6500d163575Sopenharmony_ci        (void)etharp_remove_static_entry(&requested_ip);
6510d163575Sopenharmony_ci#endif
6520d163575Sopenharmony_ci    }
6530d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_request: deleting\n"));
6540d163575Sopenharmony_ci
6550d163575Sopenharmony_ci    (void)pbuf_free(out_msg);
6560d163575Sopenharmony_ci    return;
6570d163575Sopenharmony_ci}
6580d163575Sopenharmony_ci
6590d163575Sopenharmony_ciLWIP_STATIC void handle_decline(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg,
6600d163575Sopenharmony_ci                                struct dyn_lease_addr *client_lease)
6610d163575Sopenharmony_ci{
6620d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_decline: Processing Decline Message\n"));
6630d163575Sopenharmony_ci
6640d163575Sopenharmony_ci    if ((client_lease != NULL) && (dhcps_option_given(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) &&
6650d163575Sopenharmony_ci        (client_msg->ciaddr.addr == 0)) {
6660d163575Sopenharmony_ci        if (client_lease->cli_addr.addr == (u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_REQUESTED_IP)) {
6670d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
6680d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
6690d163575Sopenharmony_ci                        ("handle_decline: Marking Client Entry as declined. Client IP =%"U32_F"\n",
6700d163575Sopenharmony_ci                        client_lease->cli_addr.addr));
6710d163575Sopenharmony_ci#endif
6720d163575Sopenharmony_ci            (void)memset_s(client_lease->cli_hwaddr, sizeof(client_lease->cli_hwaddr), 0, DHCP_CHADDR_LEN);
6730d163575Sopenharmony_ci            client_lease->proposed_leasetime = 0;
6740d163575Sopenharmony_ci            client_lease->leasetime = sys_now() + (LWIP_DHCPS_DECLINE_TIME * 1000);
6750d163575Sopenharmony_ci            client_lease->flags = DHCPS_ADDRESS_DECLINED;
6760d163575Sopenharmony_ci        }
6770d163575Sopenharmony_ci    }
6780d163575Sopenharmony_ci}
6790d163575Sopenharmony_ci
6800d163575Sopenharmony_ciLWIP_STATIC void handle_inform(struct netif *netif, struct dhcps *dhcps, struct dhcp_msg *client_msg)
6810d163575Sopenharmony_ci{
6820d163575Sopenharmony_ci    struct pbuf *out_msg = NULL;
6830d163575Sopenharmony_ci    struct dhcp_msg *srvr_msg = NULL;
6840d163575Sopenharmony_ci    u16_t options_len = 0;
6850d163575Sopenharmony_ci    ip_addr_t dst_addr;
6860d163575Sopenharmony_ci
6870d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: Processing Inform Message\n"));
6880d163575Sopenharmony_ci
6890d163575Sopenharmony_ci    if (client_msg->ciaddr.addr == 0) {
6900d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: ciaddr is empty. Can't send back a response\n"));
6910d163575Sopenharmony_ci        return;
6920d163575Sopenharmony_ci    }
6930d163575Sopenharmony_ci
6940d163575Sopenharmony_ci    out_msg = dhcps_create_base_msg(client_msg);
6950d163575Sopenharmony_ci    if (out_msg == NULL) {
6960d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: Creating base message failed\n"));
6970d163575Sopenharmony_ci        return;
6980d163575Sopenharmony_ci    }
6990d163575Sopenharmony_ci
7000d163575Sopenharmony_ci    srvr_msg = (struct dhcp_msg *)out_msg->payload;
7010d163575Sopenharmony_ci    dhcp_common_option(srvr_msg, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, &options_len);
7020d163575Sopenharmony_ci    dhcp_common_option_byte(srvr_msg, DHCP_ACK, &options_len);
7030d163575Sopenharmony_ci
7040d163575Sopenharmony_ci    dhcp_common_option_trailer(srvr_msg, options_len, out_msg);
7050d163575Sopenharmony_ci
7060d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
7070d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
7080d163575Sopenharmony_ci               ("handle_inform: Send ACK to Client. Client is=%"U32_F"\n", client_msg->ciaddr.addr));
7090d163575Sopenharmony_ci#endif
7100d163575Sopenharmony_ci    ip_addr_set_ip4_u32_val(dst_addr, client_msg->ciaddr.addr);
7110d163575Sopenharmony_ci    (void)udp_sendto_if_src(dhcps->pcb, out_msg, &dst_addr, DHCP_CLIENT_PORT, netif, &(netif->ip_addr));
7120d163575Sopenharmony_ci
7130d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("handle_inform: deleting pbuf\n"));
7140d163575Sopenharmony_ci    (void)pbuf_free(out_msg);
7150d163575Sopenharmony_ci
7160d163575Sopenharmony_ci    return;
7170d163575Sopenharmony_ci}
7180d163575Sopenharmony_ci
7190d163575Sopenharmony_ciLWIP_STATIC void handle_client_messages(struct netif *netif, struct dhcps *dhcps,
7200d163575Sopenharmony_ci                                        struct dhcp_msg *client_msg, ip4_addr_t serverid, u8_t msg_type)
7210d163575Sopenharmony_ci{
7220d163575Sopenharmony_ci    struct dyn_lease_addr *client_lease = NULL;
7230d163575Sopenharmony_ci
7240d163575Sopenharmony_ci    client_lease = find_client_lease(dhcps, client_msg);
7250d163575Sopenharmony_ci    switch (msg_type) {
7260d163575Sopenharmony_ci        case DHCP_DISCOVER:
7270d163575Sopenharmony_ci            handle_discover(netif, dhcps, client_msg, client_lease);
7280d163575Sopenharmony_ci            break;
7290d163575Sopenharmony_ci        case DHCP_REQUEST:
7300d163575Sopenharmony_ci            handle_request(netif, dhcps, client_msg, client_lease, serverid);
7310d163575Sopenharmony_ci            break;
7320d163575Sopenharmony_ci        case DHCP_DECLINE:
7330d163575Sopenharmony_ci            handle_decline(netif, dhcps, client_msg, client_lease);
7340d163575Sopenharmony_ci            break;
7350d163575Sopenharmony_ci        case DHCP_RELEASE:
7360d163575Sopenharmony_ci            if ((client_lease != NULL) && (client_lease->cli_addr.addr == ntohl(client_msg->ciaddr.addr))) {
7370d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
7380d163575Sopenharmony_ci                LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP Release: Client IPAdd =%"U32_F"\n", client_msg->ciaddr.addr));
7390d163575Sopenharmony_ci#endif
7400d163575Sopenharmony_ci                (void)memset_s(client_lease, sizeof(struct dyn_lease_addr), 0, sizeof(struct dyn_lease_addr));
7410d163575Sopenharmony_ci                client_lease->flags = DHCPS_ADDRESS_FREE;
7420d163575Sopenharmony_ci            }
7430d163575Sopenharmony_ci            break;
7440d163575Sopenharmony_ci        case DHCP_INFORM:
7450d163575Sopenharmony_ci            handle_inform(netif, dhcps, client_msg);
7460d163575Sopenharmony_ci            break;
7470d163575Sopenharmony_ci        default:
7480d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
7490d163575Sopenharmony_ci                        ("DHCP Server. Invalid message type received %d\n", msg_type));
7500d163575Sopenharmony_ci    }
7510d163575Sopenharmony_ci}
7520d163575Sopenharmony_ci
7530d163575Sopenharmony_cierr_t dhcps_parse_options(struct pbuf *p, struct dhcps *dhcps)
7540d163575Sopenharmony_ci{
7550d163575Sopenharmony_ci    return dhcp_parse_reply(p, &dhcps->dhcp);
7560d163575Sopenharmony_ci}
7570d163575Sopenharmony_ci
7580d163575Sopenharmony_ciLWIP_STATIC void dhcps_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *ip_addr, u16_t port)
7590d163575Sopenharmony_ci{
7600d163575Sopenharmony_ci    struct netif *netif = (struct netif *)arg;
7610d163575Sopenharmony_ci    struct dhcps *dhcps = netif_get_dhcps(netif);
7620d163575Sopenharmony_ci    struct dhcp_msg *client_msg = (struct dhcp_msg *)p->payload;
7630d163575Sopenharmony_ci    u8_t msg_type;
7640d163575Sopenharmony_ci    ip4_addr_t serverid;
7650d163575Sopenharmony_ci    ip4_addr_t addr;
7660d163575Sopenharmony_ci
7670d163575Sopenharmony_ci    if (client_msg == NULL) {
7680d163575Sopenharmony_ci        return;
7690d163575Sopenharmony_ci    }
7700d163575Sopenharmony_ci    addr.addr = ip_addr->u_addr.ip4.addr;
7710d163575Sopenharmony_ci    serverid.addr = 0;
7720d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
7730d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
7740d163575Sopenharmony_ci                ("dhcps_recv(pbuf = %p) from DHCP Client %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
7750d163575Sopenharmony_ci                ip4_addr1_16(&addr), ip4_addr2_16(&addr), ip4_addr3_16(&addr), ip4_addr4_16(&addr), port));
7760d163575Sopenharmony_ci#endif
7770d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
7780d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
7790d163575Sopenharmony_ci    /* prevent warnings about unused arguments */
7800d163575Sopenharmony_ci    LWIP_UNUSED_ARG(pcb);
7810d163575Sopenharmony_ci    LWIP_UNUSED_ARG(addr);
7820d163575Sopenharmony_ci    LWIP_UNUSED_ARG(port);
7830d163575Sopenharmony_ci
7840d163575Sopenharmony_ci    dhcps_clear_all_options(dhcps);
7850d163575Sopenharmony_ci
7860d163575Sopenharmony_ci    /* Check and remove old entries on each call to dhcp_recv. This way, we don't need to maintain timers */
7870d163575Sopenharmony_ci    remove_stale_entries(dhcps);
7880d163575Sopenharmony_ci
7890d163575Sopenharmony_ci    if (p->len < DHCP_OPTIONS_OFS) {
7900d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
7910d163575Sopenharmony_ci                    ("DHCP client message or pbuf too short. pbuf len =%"U16_F" DHCP MIN Reply Len = %"U32_F"\n",
7920d163575Sopenharmony_ci                        p->len, DHCP_MIN_REPLY_LEN));
7930d163575Sopenharmony_ci        goto free_pbuf_and_return;
7940d163575Sopenharmony_ci    }
7950d163575Sopenharmony_ci
7960d163575Sopenharmony_ci    if (client_msg->op != DHCP_BOOTREQUEST) {
7970d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
7980d163575Sopenharmony_ci                    ("Not a DHCP reply message, Type %"U16_F"\n", (u16_t)client_msg->op));
7990d163575Sopenharmony_ci        goto free_pbuf_and_return;
8000d163575Sopenharmony_ci    }
8010d163575Sopenharmony_ci
8020d163575Sopenharmony_ci    if (client_msg->cookie != PP_HTONL(DHCP_MAGIC_COOKIE)) {
8030d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
8040d163575Sopenharmony_ci                    ("DHCP Server. Cookie Value is incorrect. %"U32_F"\n", (u32_t)client_msg->cookie));
8050d163575Sopenharmony_ci        goto free_pbuf_and_return;
8060d163575Sopenharmony_ci    }
8070d163575Sopenharmony_ci
8080d163575Sopenharmony_ci    if (client_msg->hlen != ETHARP_HWADDR_LEN) {
8090d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
8100d163575Sopenharmony_ci                    ("DHCP Server. Invalid hardware address length %"U16_F"\n", (u16_t)client_msg->hlen));
8110d163575Sopenharmony_ci        goto free_pbuf_and_return;
8120d163575Sopenharmony_ci    }
8130d163575Sopenharmony_ci
8140d163575Sopenharmony_ci    if (dhcps_parse_options(p, dhcps) != ERR_OK) {
8150d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
8160d163575Sopenharmony_ci                    ("Parsing of Options failed in DHCP Client Message\n"));
8170d163575Sopenharmony_ci        goto free_pbuf_and_return;
8180d163575Sopenharmony_ci    }
8190d163575Sopenharmony_ci
8200d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("Searching DHCP_OPTION_MESSAGE_TYPE\n"));
8210d163575Sopenharmony_ci    /* obtain pointer to DHCP message type */
8220d163575Sopenharmony_ci    if (!dhcps_option_given(dhcps, DHCP_OPTION_IDX_MSG_TYPE)) {
8230d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
8240d163575Sopenharmony_ci                    ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
8250d163575Sopenharmony_ci        goto free_pbuf_and_return;
8260d163575Sopenharmony_ci    }
8270d163575Sopenharmony_ci
8280d163575Sopenharmony_ci    /* read DHCP message type */
8290d163575Sopenharmony_ci    msg_type = (u8_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_MSG_TYPE);
8300d163575Sopenharmony_ci
8310d163575Sopenharmony_ci    if (dhcps_option_given(dhcps, DHCP_OPTION_IDX_SERVER_ID)) {
8320d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
8330d163575Sopenharmony_ci                    ("DHCP_OPTION_SERVER_ID option found\n"));
8340d163575Sopenharmony_ci        /* Parse options would have changed it to host order. But, we have our IP stored in netif in network order */
8350d163575Sopenharmony_ci        serverid.addr = htonl((u32_t)dhcps_get_option_value(dhcps, DHCP_OPTION_IDX_SERVER_ID));
8360d163575Sopenharmony_ci    }
8370d163575Sopenharmony_ci
8380d163575Sopenharmony_ci    if ((serverid.addr != 0) && ((msg_type == DHCP_DISCOVER) || (msg_type == DHCP_INFORM))) {
8390d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
8400d163575Sopenharmony_ci                    ("Serverid present in DHCP_DISCOVER and DHCP_INFORM messages\n"));
8410d163575Sopenharmony_ci        goto free_pbuf_and_return;
8420d163575Sopenharmony_ci    }
8430d163575Sopenharmony_ci
8440d163575Sopenharmony_ci    if ((!ip4_addr_cmp(&serverid, ip_2_ip4(&netif->ip_addr))) &&
8450d163575Sopenharmony_ci        ((msg_type == DHCP_DECLINE) || (msg_type == DHCP_RELEASE))) {
8460d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
8470d163575Sopenharmony_ci                    ("Serverid not present in DHCP_RELEASE and DHCP_DECLINE messages\n"));
8480d163575Sopenharmony_ci        goto free_pbuf_and_return;
8490d163575Sopenharmony_ci    }
8500d163575Sopenharmony_ci
8510d163575Sopenharmony_ci    handle_client_messages(netif, dhcps, client_msg, serverid, msg_type);
8520d163575Sopenharmony_ci
8530d163575Sopenharmony_cifree_pbuf_and_return:
8540d163575Sopenharmony_ci    (void)pbuf_free(p);
8550d163575Sopenharmony_ci}
8560d163575Sopenharmony_ci
8570d163575Sopenharmony_cierr_t dhcps_start(struct netif *netif, const char *start_ip, u16_t ip_num)
8580d163575Sopenharmony_ci{
8590d163575Sopenharmony_ci    struct dhcps *dhcps = NULL;
8600d163575Sopenharmony_ci    ip4_addr_t address_in_hton;
8610d163575Sopenharmony_ci    int err;
8620d163575Sopenharmony_ci
8630d163575Sopenharmony_ci    LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG);
8640d163575Sopenharmony_ci    dhcps = netif_get_dhcps(netif);
8650d163575Sopenharmony_ci
8660d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
8670d163575Sopenharmony_ci                ("dhcps_start(netif=%p) %s\n", (void *)netif, netif_get_name(netif)));
8680d163575Sopenharmony_ci
8690d163575Sopenharmony_ci    if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
8700d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
8710d163575Sopenharmony_ci                    ("MTU =%"U16_F",DHCP Msg Len Required =%"U32_F"\n", netif->mtu, DHCP_MAX_MSG_LEN_MIN_REQUIRED));
8720d163575Sopenharmony_ci        return ERR_MEM;
8730d163575Sopenharmony_ci    }
8740d163575Sopenharmony_ci
8750d163575Sopenharmony_ci    if (dhcps != NULL) {
8760d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): DHCP Server is already started\n"));
8770d163575Sopenharmony_ci        return ERR_MEM;
8780d163575Sopenharmony_ci    }
8790d163575Sopenharmony_ci
8800d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): starting new DHCP Server\n"));
8810d163575Sopenharmony_ci    dhcps = (struct dhcps *)mem_malloc(sizeof(struct dhcps));
8820d163575Sopenharmony_ci    if (dhcps == NULL) {
8830d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): could not allocate dhcp\n"));
8840d163575Sopenharmony_ci        return ERR_MEM;
8850d163575Sopenharmony_ci    }
8860d163575Sopenharmony_ci
8870d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): allocated dhcp"));
8880d163575Sopenharmony_ci
8890d163575Sopenharmony_ci    (void)memset_s(dhcps, sizeof(struct dhcps), 0, sizeof(struct dhcps));
8900d163575Sopenharmony_ci
8910d163575Sopenharmony_ci    dhcps->pcb = udp_new();
8920d163575Sopenharmony_ci    if (dhcps->pcb == NULL) {
8930d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate pcb\n"));
8940d163575Sopenharmony_ci        mem_free((void *)dhcps);
8950d163575Sopenharmony_ci        return ERR_MEM;
8960d163575Sopenharmony_ci    }
8970d163575Sopenharmony_ci
8980d163575Sopenharmony_ci#if LWIP_SO_BINDTODEVICE
8990d163575Sopenharmony_ci    /* bind dhcp udp_pcb to specific netif, this could make dhcp server start on multiple netif */
9000d163575Sopenharmony_ci    dhcps->pcb->ifindex = netif->ifindex;
9010d163575Sopenharmony_ci#endif
9020d163575Sopenharmony_ci    if ((start_ip == NULL) || (ip_num == 0)) {
9030d163575Sopenharmony_ci        /* use default ip lease configuration. */
9040d163575Sopenharmony_ci        dhcps->start_addr.addr = ntohl(ip_2_ip4(&netif->ip_addr)->addr & ip_2_ip4(&netif->netmask)->addr) + 1;
9050d163575Sopenharmony_ci        dhcps->end_addr.addr = ntohl(ip_2_ip4(&netif->ip_addr)->addr | (~ip_2_ip4(&netif->netmask)->addr)) - 1;
9060d163575Sopenharmony_ci        dhcps->lease_num = (u8_t)(dhcps->end_addr.addr - dhcps->start_addr.addr + 1);
9070d163575Sopenharmony_ci        if (dhcps->lease_num > LWIP_DHCPS_MAX_LEASE) {
9080d163575Sopenharmony_ci            dhcps->lease_num = LWIP_DHCPS_MAX_LEASE;
9090d163575Sopenharmony_ci            dhcps->end_addr.addr = dhcps->start_addr.addr + LWIP_DHCPS_MAX_LEASE - 1;
9100d163575Sopenharmony_ci        }
9110d163575Sopenharmony_ci    } else {
9120d163575Sopenharmony_ci        dhcps->start_addr.addr = ntohl(ipaddr_addr(start_ip));
9130d163575Sopenharmony_ci        dhcps->end_addr.addr = (u32_t)(dhcps->start_addr.addr +
9140d163575Sopenharmony_ci                                       (u32_t)(LWIP_MIN(ip_num - 1, LWIP_DHCPS_MAX_LEASE - 1)));
9150d163575Sopenharmony_ci
9160d163575Sopenharmony_ci        ip4_addr_set_hton(&address_in_hton, &dhcps->start_addr);
9170d163575Sopenharmony_ci
9180d163575Sopenharmony_ci        if (!ip4_addr_netcmp((&address_in_hton), ip_2_ip4(&netif->ip_addr), ip_2_ip4(&netif->netmask)) ||
9190d163575Sopenharmony_ci            ip4_addr_isbroadcast((&address_in_hton), netif)) {
9200d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): %s in not a valid ip lease\n", start_ip));
9210d163575Sopenharmony_ci            udp_remove(dhcps->pcb);
9220d163575Sopenharmony_ci            mem_free((void *)dhcps);
9230d163575Sopenharmony_ci            return ERR_ARG;
9240d163575Sopenharmony_ci        }
9250d163575Sopenharmony_ci
9260d163575Sopenharmony_ci        ip4_addr_set_hton(&address_in_hton, &dhcps->end_addr);
9270d163575Sopenharmony_ci
9280d163575Sopenharmony_ci        if (!ip4_addr_netcmp((&address_in_hton), ip_2_ip4(&netif->ip_addr), ip_2_ip4(&netif->netmask)) ||
9290d163575Sopenharmony_ci            ip4_addr_isbroadcast((&address_in_hton), netif)) {
9300d163575Sopenharmony_ci            dhcps->end_addr.addr = ntohl(ip_2_ip4(&netif->ip_addr)->addr | (~ip_2_ip4(&netif->netmask)->addr)) - 1;
9310d163575Sopenharmony_ci        }
9320d163575Sopenharmony_ci        dhcps->lease_num = (u8_t)(dhcps->end_addr.addr - dhcps->start_addr.addr + 1);
9330d163575Sopenharmony_ci    }
9340d163575Sopenharmony_ci
9350d163575Sopenharmony_ci    dhcps->netif = netif;
9360d163575Sopenharmony_ci    dhcps->pcb->so_options |= SOF_BROADCAST;
9370d163575Sopenharmony_ci    err = udp_bind(dhcps->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
9380d163575Sopenharmony_ci    if (err != ERR_OK) {
9390d163575Sopenharmony_ci        udp_remove(dhcps->pcb);
9400d163575Sopenharmony_ci        mem_free((void *)dhcps);
9410d163575Sopenharmony_ci        return ERR_MEM;
9420d163575Sopenharmony_ci    }
9430d163575Sopenharmony_ci
9440d163575Sopenharmony_ci    err = udp_connect(dhcps->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
9450d163575Sopenharmony_ci    if (err != ERR_OK) {
9460d163575Sopenharmony_ci        udp_remove(dhcps->pcb);
9470d163575Sopenharmony_ci        mem_free((void *)dhcps);
9480d163575Sopenharmony_ci        return ERR_MEM;
9490d163575Sopenharmony_ci    }
9500d163575Sopenharmony_ci    udp_recv(dhcps->pcb, dhcps_recv, netif);
9510d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_start(): starting DHCPS Successfully\n"));
9520d163575Sopenharmony_ci#ifdef  LWIP_DEV_DEBUG
9530d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
9540d163575Sopenharmony_ci                ("dhcps_start(): DHCPS Conf:: netif addr = %"U32_F" dhcps start addr%"U32_F" dhcp end addr%"U32_F"\n",
9550d163575Sopenharmony_ci                ip_2_ip4(&netif->ip_addr)->addr, dhcps->start_addr.addr, dhcps->end_addr.addr));
9560d163575Sopenharmony_ci#endif
9570d163575Sopenharmony_ci    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE,
9580d163575Sopenharmony_ci                ("dhcps_start(): DHCPS Lease Conf:: Lease Time = %"U32_F" Offer Time = %"U32_F"\n",
9590d163575Sopenharmony_ci                    LWIP_DHCPS_LEASE_TIME, LWIP_DHCPS_OFFER_TIME));
9600d163575Sopenharmony_ci    netif_set_dhcps(netif, dhcps);
9610d163575Sopenharmony_ci    return ERR_OK;
9620d163575Sopenharmony_ci}
9630d163575Sopenharmony_ci
9640d163575Sopenharmony_civoid dhcps_stop(struct netif *netif)
9650d163575Sopenharmony_ci{
9660d163575Sopenharmony_ci    LWIP_ERROR("dhcps_stop: netif != NULL", (netif != NULL), return);
9670d163575Sopenharmony_ci    struct dhcps *dhcps = netif_get_dhcps(netif);
9680d163575Sopenharmony_ci    if (dhcps != NULL) {
9690d163575Sopenharmony_ci        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_stop(): Stopping DHCP Server\n"));
9700d163575Sopenharmony_ci        if (dhcps->pcb != NULL) {
9710d163575Sopenharmony_ci            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcps_stop(): Removing UDP PCB\n"));
9720d163575Sopenharmony_ci            udp_remove(dhcps->pcb);
9730d163575Sopenharmony_ci            dhcps->pcb = NULL;
9740d163575Sopenharmony_ci        }
9750d163575Sopenharmony_ci
9760d163575Sopenharmony_ci        mem_free(dhcps);
9770d163575Sopenharmony_ci        netif_set_dhcps(netif, NULL);
9780d163575Sopenharmony_ci    }
9790d163575Sopenharmony_ci}
9800d163575Sopenharmony_ci
9810d163575Sopenharmony_ci#endif
9820d163575Sopenharmony_ci
983