1491 lines
54 KiB
C
1491 lines
54 KiB
C
|
|
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip_dhcp.c,v $ $Revision: 1.7.10.1 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmip/src/ipmip_dhcp.c,v $
|
|
* $Author: jsheng $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include <ipmip_config.h>
|
|
|
|
#ifdef IPMIP_USE_INET
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_hash.h>
|
|
#include <ipcom_inet.h>
|
|
#include <ipcom_list.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock2.h>
|
|
#include <ipcom_sysctl.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_sysvar.h>
|
|
|
|
|
|
#include <ipmip.h>
|
|
#include <private/ipmip_context.h>
|
|
#include <private/ipmip_timer.h>
|
|
#include <private/ipmip_buffer.h>
|
|
#include <private/ipmip_dhcp.h>
|
|
#include <private/ipmip_pktbuf.h>
|
|
#include <private/ipmip_sysvar.h>
|
|
#include <private/ipmip_lladdr.h>
|
|
#include <private/ipmip_if.h>
|
|
#include <private/ipmip_util.h>
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
#define IPMIP_PKT_CLEN 128
|
|
|
|
#define IPCOM_SYSLOG_PRIORITY IPCOM_LOG_DEBUG2
|
|
#define IPCOM_SYSLOG_FACILITY IPCOM_LOG_IPMIP
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
const char *ipmip_dhcp_type_name[IPMIP_DHCP_TYPE_MAX] =
|
|
{
|
|
"bool",
|
|
"u32",
|
|
"u16",
|
|
"u8",
|
|
"string",
|
|
"ip",
|
|
"ip_pair"
|
|
};
|
|
|
|
|
|
const Ipmip_dhcp_option_def_t ipmip_dhcp_options[] =
|
|
{
|
|
{ "subnet_mask", IPMIP_DHCP_OPTCODE_SUBNET_MASK, IPMIP_DHCP_TYPE_IP },
|
|
{ "time_offset", IPMIP_DHCP_OPTCODE_TIME_OFFSET, IPMIP_DHCP_TYPE_U32 },
|
|
{ "router", IPMIP_DHCP_OPTCODE_ROUTERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "time_server", IPMIP_DHCP_OPTCODE_TIME_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "name_server", IPMIP_DHCP_OPTCODE_NAME_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "ns", IPMIP_DHCP_OPTCODE_NAME_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "domain_name_server", IPMIP_DHCP_OPTCODE_DOMAIN_NAME_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "dns", IPMIP_DHCP_OPTCODE_DOMAIN_NAME_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "log_server", IPMIP_DHCP_OPTCODE_LOG_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "cookie_server", IPMIP_DHCP_OPTCODE_COOKIE_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "lpr_server", IPMIP_DHCP_OPTCODE_LPR_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "impress_server", IPMIP_DHCP_OPTCODE_IMPRESS_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "resource_location_server", IPMIP_DHCP_OPTCODE_RESOURCE_LOCATION_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "host_name", IPMIP_DHCP_OPTCODE_HOST_NAME, IPMIP_DHCP_TYPE_STRING },
|
|
{ "boot_file_size", IPMIP_DHCP_OPTCODE_BOOT_SIZE, IPMIP_DHCP_TYPE_U16 },
|
|
{ "merit_dump", IPMIP_DHCP_OPTCODE_MERIT_DUMP, IPMIP_DHCP_TYPE_STRING },
|
|
{ "domain_name", IPMIP_DHCP_OPTCODE_DOMAIN_NAME, IPMIP_DHCP_TYPE_STRING },
|
|
{ "swap_server", IPMIP_DHCP_OPTCODE_SWAP_SERVER, IPMIP_DHCP_TYPE_IP },
|
|
{ "root_path", IPMIP_DHCP_OPTCODE_ROOT_PATH, IPMIP_DHCP_TYPE_STRING },
|
|
{ "extension_path", IPMIP_DHCP_OPTCODE_EXTENSIONS_PATH, IPMIP_DHCP_TYPE_STRING },
|
|
{ "ip_forwarding", IPMIP_DHCP_OPTCODE_IP_FORWARDING, IPMIP_DHCP_TYPE_BOOL },
|
|
{ "non_local_source_routing", IPMIP_DHCP_OPTCODE_NON_LOCAL_SOURCE_ROUTING, IPMIP_DHCP_TYPE_BOOL },
|
|
{ "policy_filter", IPMIP_DHCP_OPTCODE_POLICY_FILTER, IPMIP_DHCP_TYPE_IP_PAIR },
|
|
{ "maximum_datagram_reassembly_size", IPMIP_DHCP_OPTCODE_MAX_DGRAM_REASSEMBLY, IPMIP_DHCP_TYPE_U16 },
|
|
{ "default_ip_time_to_live", IPMIP_DHCP_OPTCODE_DEFAULT_IP_TTL, IPMIP_DHCP_TYPE_U8 },
|
|
{ "default_ip_ttl", IPMIP_DHCP_OPTCODE_DEFAULT_IP_TTL, IPMIP_DHCP_TYPE_U8 },
|
|
{ "path_mtu_aging_timeout", IPMIP_DHCP_OPTCODE_PATH_MTU_AGING_TIMEOUT, IPMIP_DHCP_TYPE_U32 },
|
|
{ "path_mtu_plateau_table", IPMIP_DHCP_OPTCODE_PATH_MTU_PLATEAU_TABLE, IPMIP_DHCP_TYPE_U16 },
|
|
{ "interface_mtu", IPMIP_DHCP_OPTCODE_INTERFACE_MTU, IPMIP_DHCP_TYPE_U16 },
|
|
{ "mtu", IPMIP_DHCP_OPTCODE_INTERFACE_MTU, IPMIP_DHCP_TYPE_U16 },
|
|
{ "all_subnets_are_local", IPMIP_DHCP_OPTCODE_ALL_SUBNETS_LOCAL, IPMIP_DHCP_TYPE_BOOL },
|
|
{ "broadcast_address", IPMIP_DHCP_OPTCODE_BROADCAST_ADDRESS, IPMIP_DHCP_TYPE_IP },
|
|
{ "perform_mask_discovery", IPMIP_DHCP_OPTCODE_PERFORM_MASK_DISCOVERY, IPMIP_DHCP_TYPE_BOOL },
|
|
{ "mask_supplier", IPMIP_DHCP_OPTCODE_MASK_SUPPLIER, IPMIP_DHCP_TYPE_BOOL },
|
|
{ "router_discovery", IPMIP_DHCP_OPTCODE_ROUTER_DISCOVERY, IPMIP_DHCP_TYPE_BOOL },
|
|
{ "router_solicitation_address", IPMIP_DHCP_OPTCODE_ROUTER_SOLICITATION_ADDRESS, IPMIP_DHCP_TYPE_IP },
|
|
{ "static_route", IPMIP_DHCP_OPTCODE_STATIC_ROUTES, IPMIP_DHCP_TYPE_IP_PAIR },
|
|
{ "trailer_encapsulation", IPMIP_DHCP_OPTCODE_TRAILER_ENCAPSULATION, IPMIP_DHCP_TYPE_BOOL },
|
|
{ "arp_cache_timeout", IPMIP_DHCP_OPTCODE_TRAILER_ENCAPSULATION, IPMIP_DHCP_TYPE_U32 },
|
|
{ "ethernet_encapsulation", IPMIP_DHCP_OPTCODE_IEEE802_3_ENCAPSULATION, IPMIP_DHCP_TYPE_BOOL },
|
|
{ "tcp_default_ttl", IPMIP_DHCP_OPTCODE_DEFAULT_TCP_TTL, IPMIP_DHCP_TYPE_U8 },
|
|
{ "tcp_keepalive_interval", IPMIP_DHCP_OPTCODE_TCP_KEEPALIVE_INTERVAL, IPMIP_DHCP_TYPE_U32 },
|
|
{ "tcp_keepalive_garbage", IPMIP_DHCP_OPTCODE_TCP_KEEPALIVE_GARBAGE, IPMIP_DHCP_TYPE_BOOL },
|
|
{ "network_information_service_domain", IPMIP_DHCP_OPTCODE_NIS_DOMAIN, IPMIP_DHCP_TYPE_STRING },
|
|
{ "NIS_domain", IPMIP_DHCP_OPTCODE_NIS_DOMAIN, IPMIP_DHCP_TYPE_STRING },
|
|
{ "network_information_servers", IPMIP_DHCP_OPTCODE_NIS_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "NIS_servers", IPMIP_DHCP_OPTCODE_NIS_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "network_time_protocol_servers", IPMIP_DHCP_OPTCODE_NTP_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "NTP_servers", IPMIP_DHCP_OPTCODE_NTP_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "vendor_specific_information", IPMIP_DHCP_OPTCODE_VENDOR_ENCAPSULATED_OPTIONS, IPMIP_DHCP_TYPE_U8 },
|
|
{ "netbios_over_tcp/ip_name_server", IPMIP_DHCP_OPTCODE_NETBIOS_NAME_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "netbios_name_server", IPMIP_DHCP_OPTCODE_NETBIOS_NAME_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "netbios_over_tcp/ip_datagram_distribution_server", IPMIP_DHCP_OPTCODE_NETBIOS_NAME_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "netbios_datagram_distribution_server", IPMIP_DHCP_OPTCODE_NETBIOS_NAME_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "netbios_over_tcp/ip_node_type", IPMIP_DHCP_OPTCODE_NETBIOS_NODE_TYPE, IPMIP_DHCP_TYPE_U8 },
|
|
{ "netbios_node_type", IPMIP_DHCP_OPTCODE_NETBIOS_NODE_TYPE, IPMIP_DHCP_TYPE_U8 },
|
|
{ "netbios_over_tcp/ip_scope", IPMIP_DHCP_OPTCODE_NETBIOS_SCOPE, IPMIP_DHCP_TYPE_STRING },
|
|
{ "netbios_scope", IPMIP_DHCP_OPTCODE_NETBIOS_SCOPE, IPMIP_DHCP_TYPE_STRING },
|
|
{ "X_window_system_font_server", IPMIP_DHCP_OPTCODE_FONT_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "X_window_system_display_manager", IPMIP_DHCP_OPTCODE_X_DISPLAY_MANAGER, IPMIP_DHCP_TYPE_IP },
|
|
{ "network_information_service+_domain", IPMIP_DHCP_OPTCODE_NISPLUS_DOMAIN, IPMIP_DHCP_TYPE_STRING },
|
|
{ "NIS+_domain", IPMIP_DHCP_OPTCODE_NISPLUS_DOMAIN, IPMIP_DHCP_TYPE_STRING },
|
|
{ "network_information_service+_servers", IPMIP_DHCP_OPTCODE_NISPLUS_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "NIS+_servers", IPMIP_DHCP_OPTCODE_NISPLUS_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "NIS+_servers", IPMIP_DHCP_OPTCODE_NISPLUS_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "mobile_ip_home_agent", IPMIP_DHCP_OPTCODE_HOME_AGENTS, IPMIP_DHCP_TYPE_IP },
|
|
{ "simple_mail_transport_protocol_server", IPMIP_DHCP_OPTCODE_SMTP_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "SMTP_server", IPMIP_DHCP_OPTCODE_SMTP_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "post_office_protocol_server", IPMIP_DHCP_OPTCODE_POP3_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "POP3_server", IPMIP_DHCP_OPTCODE_POP3_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "network_news_transport_protocol_server", IPMIP_DHCP_OPTCODE_NNTP_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "NNTP_server", IPMIP_DHCP_OPTCODE_NNTP_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "default_world_wide_web_server", IPMIP_DHCP_OPTCODE_WWW_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "default_WWW_server", IPMIP_DHCP_OPTCODE_WWW_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "default_finger_server", IPMIP_DHCP_OPTCODE_FINGER_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "default_internet_relay_chat_server", IPMIP_DHCP_OPTCODE_IRC_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "default_IRC_server", IPMIP_DHCP_OPTCODE_IRC_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "streettalk_server", IPMIP_DHCP_OPTCODE_STREETTALK_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "streettalk_directory_assistance_server", IPMIP_DHCP_OPTCODE_STDA_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ "STDA_server", IPMIP_DHCP_OPTCODE_STDA_SERVERS, IPMIP_DHCP_TYPE_IP },
|
|
{ IP_NULL, 0 }
|
|
};
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip_dhcp_route_walk(Ipmip_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
Ipmip_rtab_t *rtab,
|
|
Ipmip_dhcp_lease_t *lease,
|
|
Ipmip_dhcp_pool_t *pool)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
IPMIP_UNUSED_PARAMETER(rtab);
|
|
|
|
return lease->pool == pool;
|
|
}
|
|
|
|
IP_STATIC void
|
|
ipmip_dhcp_route_notify(Ipcom_route *rtab,
|
|
Ipmip_dhcp_lease_t *lease,
|
|
int code)
|
|
{
|
|
if (code == IPCOM_ROUTE_CODE_REMOVE || code == IPCOM_ROUTE_CODE_DUPLICATE)
|
|
{
|
|
if (lease->rtab != IP_NULL && lease->rtab->rtab_free != IP_NULL)
|
|
(*lease->rtab->rtab_free) (lease->rtab->rtab_ctx, lease->rtab->rtab_proc, lease);
|
|
}
|
|
|
|
ipmip_route_notify(rtab, &lease->ipmip, code);
|
|
}
|
|
|
|
|
|
IP_STATIC unsigned
|
|
ipmip_dhcp_key_ifindex(Ip_u32 *ifindex)
|
|
{
|
|
return ipcom_hash_update(ifindex, sizeof(*ifindex), 0);
|
|
}
|
|
|
|
|
|
IP_STATIC unsigned
|
|
ipmip_dhcp_obj_ifindex(Ipmip_dhcp_node_t *node)
|
|
{
|
|
return ipmip_dhcp_key_ifindex(&node->ifindex);
|
|
}
|
|
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip_dhcp_cmp_ifindex(Ipmip_dhcp_node_t *node, Ip_u32 *ifindex)
|
|
{
|
|
/* Compare */
|
|
return node->ifindex == *ifindex;
|
|
}
|
|
|
|
IP_STATIC unsigned
|
|
ipmip_dhcp_key_clientid(struct Ip_iovec *vec)
|
|
{
|
|
return ipcom_hash_update(vec->iov_base, vec->iov_len, 0);
|
|
}
|
|
|
|
|
|
IP_STATIC unsigned
|
|
ipmip_dhcp_obj_clientid(Ipmip_dhcp_node_t *node)
|
|
{
|
|
return ipmip_dhcp_key_clientid(&node->clientid);
|
|
}
|
|
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip_dhcp_cmp_clientid(Ipmip_dhcp_node_t *node, struct Ip_iovec *vec)
|
|
{
|
|
/* Compare */
|
|
return node->clientid.iov_len == vec->iov_len && ipcom_memcmp(vec->iov_base, node->clientid.iov_base, vec->iov_len) == 0;
|
|
}
|
|
|
|
IP_STATIC unsigned
|
|
ipmip_dhcp_key_remote_id(Ip_u32 *rid)
|
|
{
|
|
return ipcom_hash_update(rid, sizeof(*rid), 0);
|
|
}
|
|
|
|
|
|
IP_STATIC unsigned
|
|
ipmip_dhcp_obj_remote_id(Ipmip_dhcp_node_t *node)
|
|
{
|
|
return ipmip_dhcp_key_ifindex(&node->remote_id);
|
|
}
|
|
|
|
|
|
IP_STATIC Ip_bool
|
|
ipmip_dhcp_cmp_remote_id(Ipmip_dhcp_node_t *node, Ip_u32 *rid)
|
|
{
|
|
/* Compare */
|
|
return node->remote_id == *rid;
|
|
}
|
|
|
|
IP_STATIC Ip_fd
|
|
ipmip_dhcp_socket_server_alloc(Ipmip_context_t *ctx,
|
|
Ipmip_proc_t *proc,
|
|
struct Ip_sockaddr_in *sin4)
|
|
{
|
|
Ip_fd fd;
|
|
int i;
|
|
Ip_socklen_t slen;
|
|
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
/* Create raw IP socket for all IPv4 input on this interface */
|
|
if ((fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, IP_IPPROTO_UDP)) == IP_INVALID_SOCKET)
|
|
goto fail;
|
|
|
|
/* Allow reusage of address */
|
|
i = 1;
|
|
if (ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_REUSEADDR, &i, sizeof(i)))
|
|
goto fail;
|
|
|
|
/* Allow reusage of ports */
|
|
i = 1;
|
|
if (ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_REUSEPORT, &i, sizeof(i)))
|
|
goto fail;
|
|
|
|
/* */
|
|
if (ipcom_bind(fd, (struct Ip_sockaddr *) sin4, sizeof(*sin4)) < 0)
|
|
goto fail;
|
|
|
|
/* I want to receive PACKET INFO as ancillary data */
|
|
i = 1;
|
|
if (ipcom_setsockopt(fd, IP_IPPROTO_IP, IP_IP_PKTINFO, &i, sizeof(i)) < 0)
|
|
goto fail;
|
|
|
|
i = 1;
|
|
if (ipcom_setsockopt(fd, IP_IPPROTO_IP, IP_IP_RECVTTL, &i, sizeof(i)))
|
|
goto fail;
|
|
|
|
/* Enable IP_X_SENDERLINKADDR to get source link address */
|
|
i= 1;
|
|
if (ipcom_setsockopt(fd, IP_IPPROTO_IP, IP_IP_X_SENDERLINKADDR, &i, sizeof(i)) < 0)
|
|
goto fail;
|
|
|
|
slen = sizeof(*sin4);
|
|
if (ipcom_getsockname(fd, (struct Ip_sockaddr *) sin4, &slen) < 0)
|
|
goto fail;
|
|
|
|
return fd;
|
|
|
|
fail:
|
|
IPCOM_LOG1(ERR, "Error while creating DHCPR context, errcode = %x", ipcom_errno);
|
|
ipcom_socketclose(fd);
|
|
return IP_INVALID_SOCKET;
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_context_create(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc)
|
|
{
|
|
int i = 1;
|
|
struct Ip_sockaddr_in sin4;
|
|
|
|
if (ctx->dhcp != IP_NULL)
|
|
return;
|
|
|
|
ctx->dhcp = ipcom_calloc(1, sizeof(*ctx->dhcp));
|
|
if (ctx->dhcp == IP_NULL)
|
|
return;
|
|
|
|
(void)ipcom_mutex_create(&ctx->dhcp->mutex);
|
|
|
|
ipcom_memset(&sin4, 0, sizeof(sin4));
|
|
sin4.sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(&sin4, sizeof(sin4));
|
|
sin4.sin_port = ip_htons(67);
|
|
sin4.sin_addr.s_addr = 0;
|
|
ctx->dhcp->fd_udp = ipmip_dhcp_socket_server_alloc(ctx, proc, &sin4);
|
|
|
|
/**/
|
|
ctx->dhcp->fd_raw = ipcom_socket(IP_AF_INET, IP_SOCK_RAW, 0);
|
|
i = 1;
|
|
(void)ipcom_setsockopt(ctx->dhcp->fd_raw, IP_IPPROTO_IP, IP_IP_HDRINCL, &i, sizeof(i));
|
|
ipcom_shutdown(ctx->dhcp->fd_raw, IP_SHUT_RD);
|
|
|
|
ctx->dhcp->fd_pkt = ipcom_socket(IP_AF_PACKET, IP_SOCK_DGRAM, ip_htons(0x0800));
|
|
ipcom_shutdown(ctx->dhcp->fd_pkt, IP_SHUT_RD);
|
|
|
|
ctx->dhcp->ifindex_table = ipcom_hash_new((Ipcom_hash_obj_func) ipmip_dhcp_obj_ifindex,
|
|
(Ipcom_hash_key_func) ipmip_dhcp_key_ifindex,
|
|
(Ipcom_hash_cmp_func) ipmip_dhcp_cmp_ifindex);
|
|
ctx->dhcp->clientid_table = ipcom_hash_new((Ipcom_hash_obj_func) ipmip_dhcp_obj_clientid,
|
|
(Ipcom_hash_key_func) ipmip_dhcp_key_clientid,
|
|
(Ipcom_hash_cmp_func) ipmip_dhcp_cmp_clientid);
|
|
ctx->dhcp->remote_id_table = ipcom_hash_new((Ipcom_hash_obj_func) ipmip_dhcp_obj_remote_id,
|
|
(Ipcom_hash_key_func) ipmip_dhcp_key_remote_id,
|
|
(Ipcom_hash_cmp_func) ipmip_dhcp_cmp_remote_id);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_context_destroy(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
if (ctx->dhcp != IP_NULL)
|
|
{
|
|
ipcom_mutex_delete(&ctx->dhcp->mutex);
|
|
if (ctx->dhcp->fd_udp != IP_INVALID_SOCKET)
|
|
ipcom_socketclose(ctx->dhcp->fd_udp);
|
|
if (ctx->dhcp->fd_pkt != IP_INVALID_SOCKET)
|
|
ipcom_socketclose(ctx->dhcp->fd_pkt);
|
|
if (ctx->dhcp->fd_raw != IP_INVALID_SOCKET)
|
|
ipcom_socketclose(ctx->dhcp->fd_raw);
|
|
if (ctx->dhcp->ifindex_table)
|
|
ipcom_hash_delete(ctx->dhcp->ifindex_table);
|
|
if (ctx->dhcp->clientid_table)
|
|
ipcom_hash_delete(ctx->dhcp->clientid_table);
|
|
if (ctx->dhcp->remote_id_table)
|
|
ipcom_hash_delete(ctx->dhcp->remote_id_table);
|
|
ipcom_free(ctx->dhcp);
|
|
ctx->dhcp = IP_NULL;
|
|
}
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipmip_dhcp_retrieve_client_id(struct Ipmip_buffer *pbuf,
|
|
struct Ip_iovec *vec)
|
|
{
|
|
Ip_u8 *clid = ipmip_dhcp_option_buffer_find(pbuf, IPMIP_DHCP_OPTCODE_CLIENT_IDENTIFIER);;
|
|
|
|
if (clid != IP_NULL)
|
|
{
|
|
/**/
|
|
vec->iov_len = clid[IPMIP_DHCP_OPT_LEN];
|
|
vec->iov_base = &clid[IPMIP_DHCP_OPT_DATA];
|
|
return IP_TRUE;
|
|
}
|
|
else
|
|
{
|
|
Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(pbuf);
|
|
|
|
/**/
|
|
vec->iov_len = pkt->hlen;
|
|
vec->iov_base = &pkt->chaddr[0];
|
|
return IP_FALSE;
|
|
}
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_process(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc)
|
|
{
|
|
Ipmip_pktbuf_t *pbuf = ipmip_inet_udp_recvmsg(ctx, proc, 1024, ctx->dhcp->fd_udp);
|
|
|
|
/* Invoke callback */
|
|
if (pbuf)
|
|
{
|
|
Ipmip_dhcp_node_t *node = IP_NULL;
|
|
Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->packet);
|
|
Ip_u8 *ra_opt;
|
|
Ip_u8 *cid = IP_NULL;
|
|
Ip_u8 *rid = IP_NULL;
|
|
|
|
/* Sanity process */
|
|
if (IPMIP_BUFFER_SIZE(&pbuf->packet) >= sizeof(*pkt))
|
|
{
|
|
if ((ra_opt = ipmip_dhcp_option_buffer_find(&pbuf->packet, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO)) != IP_NULL)
|
|
{
|
|
cid = ipmip_dhcp_option_find(&ra_opt[IPMIP_DHCP_OPT_DATA], ra_opt[IPMIP_DHCP_OPT_LEN], IPMIP_DHCP_SUBOPTCODE_RA_CIRCUIT_ID);
|
|
rid = ipmip_dhcp_option_find(&ra_opt[IPMIP_DHCP_OPT_DATA], ra_opt[IPMIP_DHCP_OPT_LEN], IPMIP_DHCP_SUBOPTCODE_RA_REMOTE_ID);
|
|
}
|
|
|
|
ipcom_mutex_lock(ctx->dhcp->mutex);
|
|
if (pkt->op == IPMIP_DHCP_OP_BOOTREQUEST)
|
|
{
|
|
Ip_u32 ciaddr;
|
|
struct Ip_iovec v;
|
|
|
|
ipmip_dhcp_retrieve_client_id(&pbuf->packet, &v);
|
|
node = ipcom_hash_get(ctx->dhcp->clientid_table, &v);
|
|
if (node == IP_NULL)
|
|
node = ipcom_hash_get(ctx->dhcp->ifindex_table, &pbuf->srcinfo.dst->ifindex);
|
|
if (node == IP_NULL && rid != IP_NULL)
|
|
node = ipcom_hash_get(ctx->dhcp->remote_id_table, &rid[IPMIP_DHCP_OPT_DATA]);
|
|
if (node == IP_NULL && (ciaddr = IP_GET_32ON8(&pkt->ciaddr)))
|
|
node = ipcom_hash_get(ctx->dhcp->remote_id_table, &ciaddr);
|
|
}
|
|
else
|
|
{
|
|
/* Reply - how do I locate this node? */
|
|
if (cid != IP_NULL && cid[IPMIP_DHCP_OPT_LEN] == sizeof(Ip_u32))
|
|
node = ipcom_hash_get(ctx->dhcp->ifindex_table, &cid[IPMIP_DHCP_OPT_DATA]);
|
|
else if (rid != IP_NULL && rid[IPMIP_DHCP_OPT_LEN] == sizeof(Ip_u32))
|
|
node = ipcom_hash_get(ctx->dhcp->remote_id_table, &rid[IPMIP_DHCP_OPT_DATA]);
|
|
}
|
|
|
|
/* Time to invoke function */
|
|
if (node != IP_NULL)
|
|
ipmip_timer_request(ctx, proc, &pbuf->timeout, node->lock, node->process_func, node, pbuf, 0);
|
|
|
|
ipcom_mutex_unlock(ctx->dhcp->mutex);
|
|
}
|
|
|
|
if (node == IP_NULL)
|
|
ipmip_pktbuf_release(ctx, proc, pbuf);
|
|
}
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ip_u8 *
|
|
ipmip_dhcp_option_find(Ip_u8 *options,
|
|
int optsize,
|
|
Ip_u8 code)
|
|
{
|
|
Ip_u8 *oend = options + optsize;
|
|
|
|
if (optsize <= 0)
|
|
return IP_NULL;
|
|
|
|
for ( ; options != IP_NULL; options = ipmip_dhcp_option_get_next (options, (int) (oend - options)))
|
|
if (code == options[IPMIP_DHCP_OPT_CODE])
|
|
break;
|
|
|
|
return options;
|
|
}
|
|
|
|
IP_GLOBAL Ip_u8 *
|
|
ipmip_dhcp_option_buffer_find(Ipmip_buffer_t *buf,
|
|
Ip_u8 code)
|
|
{
|
|
/**/
|
|
return ipmip_dhcp_option_find(((Ip_u8 *)IPMIP_BUFFER_DATA(buf)) + sizeof(Ipmip_dhcp_hdr_t), IPMIP_BUFFER_SIZE(buf) - sizeof(Ipmip_dhcp_hdr_t), code);
|
|
}
|
|
|
|
IP_GLOBAL Ip_u32
|
|
ipmip_dhcp_option_buffer_find_ip(Ipmip_buffer_t *buf,
|
|
Ip_u8 code)
|
|
{
|
|
/**/
|
|
Ip_u8 *opt = ipmip_dhcp_option_find(((Ip_u8 *)IPMIP_BUFFER_DATA(buf)) + sizeof(Ipmip_dhcp_hdr_t), IPMIP_BUFFER_SIZE(buf) - sizeof(Ipmip_dhcp_hdr_t), code);
|
|
|
|
if (opt)
|
|
{
|
|
if (opt[IPMIP_DHCP_OPT_LEN] < 4)
|
|
return 0;
|
|
|
|
return IP_GET_32ON8(&opt[IPMIP_DHCP_OPT_DATA]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
IP_GLOBAL Ip_u32
|
|
ipmip_dhcp_option_buffer_find_u32(Ipmip_buffer_t *buf,
|
|
Ip_u8 code)
|
|
{
|
|
/**/
|
|
Ip_u8 *opt = ipmip_dhcp_option_find(((Ip_u8 *)IPMIP_BUFFER_DATA(buf)) + sizeof(Ipmip_dhcp_hdr_t), IPMIP_BUFFER_SIZE(buf) - sizeof(Ipmip_dhcp_hdr_t), code);
|
|
|
|
if (opt)
|
|
{
|
|
if (opt[IPMIP_DHCP_OPT_LEN] < 4)
|
|
return 0;
|
|
|
|
return IP_GET_NTOHL(&opt[IPMIP_DHCP_OPT_DATA]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
IP_GLOBAL Ip_u8 *
|
|
ipmip_dhcp_option_get_next (Ip_u8 *options,
|
|
int optsize)
|
|
{
|
|
Ip_u8 optlen;
|
|
|
|
if (optsize-- < 1)
|
|
return IP_NULL;
|
|
|
|
if (*options++ == IPMIP_DHCP_OPTCODE_END)
|
|
return IP_NULL;
|
|
|
|
if (optsize-- < 1)
|
|
return IP_NULL;
|
|
|
|
optlen = *options++;
|
|
|
|
options += optlen;
|
|
optsize -= optlen;
|
|
|
|
while (optsize > 0 && *options == IPMIP_DHCP_OPTCODE_PAD)
|
|
{
|
|
options++;
|
|
optsize--;
|
|
}
|
|
|
|
if (optsize <= 0)
|
|
return IP_NULL;
|
|
|
|
return options;
|
|
}
|
|
|
|
IP_GLOBAL Ip_bool
|
|
ipmip_dhcp_option_buffer_open(Ipmip_buffer_t *buf,
|
|
Ip_u8 code)
|
|
{
|
|
Ip_u8 *opt = ipmip_dhcp_option_buffer_find(buf, code);
|
|
|
|
/* */
|
|
if (opt != IP_NULL)
|
|
{
|
|
Ip_u8 *pkt = (Ip_u8 *)IPMIP_BUFFER_DATA(buf);
|
|
ipmip_buffer_shrink(buf, (Ip_size_t) (opt - pkt));
|
|
return IP_TRUE;
|
|
}
|
|
|
|
return IP_FALSE;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_option_buffer_close(Ipmip_buffer_t *buf)
|
|
{
|
|
Ip_u8 topt = 255;
|
|
|
|
/* Add the END option */
|
|
ipmip_buffer_append(buf, &topt, 1);
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipmip_dhcp_option_buffer_init(Ipmip_buffer_t *buf,
|
|
Ip_u8 opt)
|
|
{
|
|
Ip_u8 val[2];
|
|
|
|
val[IPMIP_DHCP_OPT_CODE] = opt;
|
|
|
|
/* Add the END option */
|
|
return ipmip_buffer_append(buf, val, 2);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_option_buffer_end(Ipmip_buffer_t *buf,
|
|
int opt_start)
|
|
{
|
|
Ip_u8 *val = ipmip_buffer_offset(buf, opt_start);
|
|
|
|
/* Add the END option */
|
|
val[IPMIP_DHCP_OPT_LEN] = IPMIP_BUFFER_SIZE(buf) - opt_start - 2;
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipmip_dhcp_option_buffer_append(Ipmip_buffer_t *buf,
|
|
Ip_u8 opt,
|
|
Ip_u8 opt_size,
|
|
void *opt_data)
|
|
{
|
|
int sz = ipmip_buffer_append(buf, IP_NULL, opt_size + 2);
|
|
Ip_u8 *val = ipmip_buffer_offset(buf, sz);
|
|
|
|
/* Add the END option */
|
|
val[IPMIP_DHCP_OPT_CODE] = opt;
|
|
val[IPMIP_DHCP_OPT_LEN] = opt_size;
|
|
|
|
if (opt_data)
|
|
ipcom_memcpy(&val[IPMIP_DHCP_OPT_DATA], opt_data, opt_size);
|
|
|
|
return sz;
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipmip_dhcp_option_buffer_append_u8(Ipmip_buffer_t *buf,
|
|
Ip_u8 opt,
|
|
Ip_u8 opt_data)
|
|
{
|
|
return ipmip_dhcp_option_buffer_append(buf, opt, 1, &opt_data);
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipmip_dhcp_option_buffer_append_u32(Ipmip_buffer_t *buf,
|
|
Ip_u8 opt,
|
|
Ip_u32 opt_data)
|
|
{
|
|
int sz = ipmip_buffer_append(buf, IP_NULL, 6);
|
|
Ip_u8 *val = ipmip_buffer_offset(buf, sz);
|
|
|
|
/* Add the END option */
|
|
val[IPMIP_DHCP_OPT_CODE] = opt;
|
|
val[IPMIP_DHCP_OPT_LEN] = 4;
|
|
|
|
IP_SET_HTONL(&val[IPMIP_DHCP_OPT_DATA], opt_data);
|
|
|
|
return sz;
|
|
}
|
|
|
|
|
|
IP_GLOBAL int
|
|
ipmip_dhcp_option_buffer_append_ip(Ipmip_buffer_t *buf,
|
|
Ip_u8 opt,
|
|
Ip_u32 opt_data)
|
|
{
|
|
int sz = ipmip_buffer_append(buf, IP_NULL, 6);
|
|
Ip_u8 *val = ipmip_buffer_offset(buf, sz);
|
|
|
|
/* Add the END option */
|
|
val[IPMIP_DHCP_OPT_CODE] = opt;
|
|
val[IPMIP_DHCP_OPT_LEN] = 4;
|
|
|
|
IP_SET_32ON8(&val[IPMIP_DHCP_OPT_DATA], opt_data);
|
|
|
|
return sz;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_register(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_dhcp_node_t *node)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
/* We're going to relay */
|
|
ipcom_mutex_lock(ctx->dhcp->mutex);
|
|
|
|
if (node->clientid.iov_len)
|
|
ipcom_hash_add(ctx->dhcp->clientid_table, node);
|
|
if (node->ifindex)
|
|
ipcom_hash_add(ctx->dhcp->ifindex_table, node);
|
|
|
|
if (node->remote_id)
|
|
ipcom_hash_add(ctx->dhcp->remote_id_table, node);
|
|
|
|
ipcom_mutex_unlock(ctx->dhcp->mutex);
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_unregister(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_dhcp_node_t *node)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
/* We're going to relay */
|
|
ipcom_mutex_lock(ctx->dhcp->mutex);
|
|
|
|
if (node->ifindex)
|
|
ipcom_hash_remove(ctx->dhcp->ifindex_table, node);
|
|
if (node->remote_id)
|
|
ipcom_hash_remove(ctx->dhcp->remote_id_table, node);
|
|
if (node->clientid.iov_len)
|
|
ipcom_hash_remove(ctx->dhcp->clientid_table, node);
|
|
|
|
ipcom_mutex_unlock(ctx->dhcp->mutex);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_relay_to_server(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_pktbuf_t *pbuf,
|
|
Ip_u32 src,
|
|
Ip_u32 server)
|
|
{
|
|
/**/
|
|
ipmip_inet_udp_sendmsg(ctx, proc, ctx->dhcp->fd_raw, &pbuf->packet, src, ip_htons(67), server, ip_htons(67), IP_NULL);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_server_reply(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_pktbuf_t *pbuf,
|
|
Ip_u32 ifinet,
|
|
struct Ipmip_if *iff,
|
|
Ip_bool broadcast)
|
|
{
|
|
Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->packet);
|
|
Ip_u16 endport = ip_htons(67);
|
|
Ip_u32 endpoint = IP_GET_32ON8(&pkt->giaddr);
|
|
|
|
if (endpoint == 0)
|
|
{
|
|
endpoint = IP_GET_32ON8(&pkt->ciaddr);
|
|
endport = ip_htons(68);
|
|
}
|
|
|
|
if (endpoint == 0)
|
|
{
|
|
ipmip_dhcp_write_to_client(ctx, proc, pbuf, ifinet, iff, broadcast);
|
|
}
|
|
else
|
|
{
|
|
ipmip_inet_udp_sendmsg(ctx, proc, ctx->dhcp->fd_raw, &pbuf->packet, ifinet, ip_htons(67), endpoint, endport, IP_NULL);
|
|
}
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_write_to_client(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_pktbuf_t *pbuf,
|
|
Ip_u32 ifinet,
|
|
struct Ipmip_if *iff,
|
|
Ip_bool broadcast)
|
|
{
|
|
Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->packet);
|
|
Ip_u32 to;
|
|
Ipmip_lladdr_t *lla = IP_NULL;
|
|
|
|
if (broadcast || ((IP_GET_HTONS(&pkt->flags) & IPMIP_DHCP_BROADCAST_FLAG)) != 0)
|
|
to = IP_INADDR_BROADCAST;
|
|
else if ((to = IP_GET_32ON8(&pkt->ciaddr)) == 0)
|
|
to = IP_GET_32ON8(&pkt->yiaddr);
|
|
|
|
if (to == 0)
|
|
to = IP_INADDR_BROADCAST;
|
|
|
|
if (iff != IP_NULL && iff->lladdr != IP_NULL)
|
|
{
|
|
if (to != IP_INADDR_BROADCAST)
|
|
lla = ipmip_lladdr_build((Ipmip_lladdr_t *)proc->ntop.ntop_pbuf, iff->lladdr->type, iff->lladdr->subtype, &pkt->chaddr[0], IPMIP_LLADDR_LEN_LLA(iff->lladdr));
|
|
}
|
|
|
|
|
|
/* Remove the agent info */
|
|
if (ipmip_dhcp_option_buffer_open(&pbuf->packet, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO))
|
|
ipmip_dhcp_option_buffer_close(&pbuf->packet);
|
|
|
|
ipmip_inet_udp_write(ctx, proc, ctx->dhcp->fd_pkt, ctx->dhcp->fd_raw, &pbuf->packet, ifinet, ip_htons(67), to, ip_htons(68), iff, lla);
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ipmip_dhcp_option_t *
|
|
ipmip_dhcp_option_parse_type(Ip_u8 code,
|
|
const char *value,
|
|
int type)
|
|
{
|
|
Ipmip_dhcp_option_t *dopt = IP_NULL;
|
|
Ip_size_t opt_len = 0;
|
|
Ip_u8 *args = ipmip_util_explode(value);
|
|
Ip_u8 *aptr = args;
|
|
|
|
if (args != IP_NULL && *args != 0)
|
|
{
|
|
Ip_size_t slen = ipcom_strlen(value);
|
|
int i;
|
|
|
|
aptr = args + 1;
|
|
switch (type)
|
|
{
|
|
case IPMIP_DHCP_TYPE_BOOL:
|
|
opt_len += 1;
|
|
break;
|
|
case IPMIP_DHCP_TYPE_IP_PAIR:
|
|
if (((*args) & 1) != 0)
|
|
goto error_out;
|
|
case IPMIP_DHCP_TYPE_IP:
|
|
case IPMIP_DHCP_TYPE_U32:
|
|
opt_len += sizeof(Ip_u32) * *args;
|
|
break;
|
|
case IPMIP_DHCP_TYPE_U16:
|
|
opt_len += sizeof(Ip_u16) * *args;
|
|
break;
|
|
case IPMIP_DHCP_TYPE_U8:
|
|
opt_len += IP_MAX(sizeof(Ip_u8), slen);
|
|
break;
|
|
case IPMIP_DHCP_TYPE_STRING:
|
|
opt_len += slen + 1;;
|
|
break;
|
|
}
|
|
|
|
dopt = ipcom_calloc(1, sizeof(*dopt) - 1 + opt_len + 3);
|
|
if (dopt != IP_NULL)
|
|
{
|
|
opt_len = 0;
|
|
switch (type)
|
|
{
|
|
case IPMIP_DHCP_TYPE_BOOL:
|
|
i = ipmip_sysvar_cmd_str_to_key(ipmip_sysvar_bool_ops, (char *)aptr + 1);
|
|
if (i == -1)
|
|
goto error_out;
|
|
|
|
dopt->option[IPMIP_DHCP_OPT_DATA] = (Ip_u8)i;
|
|
opt_len = 1;
|
|
break;
|
|
case IPMIP_DHCP_TYPE_IP_PAIR:
|
|
case IPMIP_DHCP_TYPE_IP:
|
|
while (*aptr != 0)
|
|
{
|
|
Ip_u32 ip;
|
|
if (ipcom_strncasecmp("0x", (char *)aptr + 1, 2) == 0)
|
|
{
|
|
ip = (Ip_u32)ipcom_strtoul((char *)aptr + 1, IP_NULL, 0);
|
|
ip = ip_htonl(ip);
|
|
}
|
|
else
|
|
{
|
|
if (ipmip_util_inet((char *)aptr + 1, &ip, IP_NULL) == IP_FALSE)
|
|
goto error_out;
|
|
}
|
|
|
|
IP_SET_32ON8(&dopt->option[IPMIP_DHCP_OPT_DATA + opt_len], ip);
|
|
opt_len += sizeof(ip);
|
|
aptr += *aptr;
|
|
}
|
|
break;
|
|
case IPMIP_DHCP_TYPE_U32:
|
|
while (*aptr != 0)
|
|
{
|
|
Ip_u32 val = (Ip_u32)ipcom_strtoul((char *)aptr + 1, IP_NULL, 0);
|
|
IP_SET_HTONL(&dopt->option[IPMIP_DHCP_OPT_DATA + opt_len], val);
|
|
opt_len += sizeof(val);
|
|
aptr += *aptr;
|
|
}
|
|
break;
|
|
case IPMIP_DHCP_TYPE_U16:
|
|
while (*aptr != 0)
|
|
{
|
|
Ip_u16 val = (Ip_u16)ipcom_strtoul((char *)aptr + 1, IP_NULL, 0);
|
|
IP_SET_HTONS(&dopt->option[IPMIP_DHCP_OPT_DATA + opt_len], val);
|
|
opt_len += sizeof(val);
|
|
aptr += *aptr;
|
|
}
|
|
break;
|
|
case IPMIP_DHCP_TYPE_U8:
|
|
while (*aptr != 0)
|
|
{
|
|
Ip_u8 val;
|
|
if (ipcom_strncasecmp("0x", (char *)aptr + 1, 2) == 0)
|
|
{
|
|
int nv = (int) (*aptr - 2 - 1 - 1);
|
|
Ip_u8 *vals = aptr + 3;
|
|
char vbuf[3];
|
|
|
|
vbuf[2] = '\0';
|
|
nv >>= 1;
|
|
for (i = 0; i < nv; i++)
|
|
{
|
|
vbuf[0] = vals[0];
|
|
vbuf[1] = vals[1];
|
|
vals += 2;
|
|
|
|
val = (Ip_u8)ipcom_strtoul(vbuf, IP_NULL, 16);
|
|
dopt->option[IPMIP_DHCP_OPT_DATA + opt_len] = val;
|
|
opt_len += sizeof(val);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
val = (Ip_u8)ipcom_strtoul((char *)aptr + 1, IP_NULL, 0);
|
|
dopt->option[IPMIP_DHCP_OPT_DATA + opt_len] = val;
|
|
opt_len += sizeof(val);
|
|
}
|
|
|
|
aptr += *aptr;
|
|
}
|
|
break;
|
|
case IPMIP_DHCP_TYPE_STRING:
|
|
ipcom_memcpy(&dopt->option[IPMIP_DHCP_OPT_DATA], value, slen);
|
|
dopt->option[IPMIP_DHCP_OPT_DATA + slen] = '\0';
|
|
opt_len += slen;
|
|
break;
|
|
}
|
|
|
|
dopt->option[IPMIP_DHCP_OPT_CODE] = code;
|
|
dopt->option[IPMIP_DHCP_OPT_LEN] = opt_len;
|
|
dopt->type = type;
|
|
}
|
|
}
|
|
|
|
done_out:
|
|
if (args)
|
|
ipcom_free(args);
|
|
return dopt;
|
|
|
|
error_out:
|
|
ipcom_free(dopt);
|
|
dopt = IP_NULL;
|
|
goto done_out;
|
|
}
|
|
|
|
IP_GLOBAL const Ipmip_dhcp_option_def_t *
|
|
ipmip_dhcp_option_def_name_get(const char *name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; ipmip_dhcp_options[i].name != IP_NULL; i++)
|
|
{
|
|
if (ipcom_strcasecmp(name, ipmip_dhcp_options[i].name) == 0)
|
|
return &ipmip_dhcp_options[i];
|
|
}
|
|
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
IP_GLOBAL const Ipmip_dhcp_option_def_t *
|
|
ipmip_dhcp_option_def_code_get(Ip_u8 code)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; ipmip_dhcp_options[i].name != IP_NULL; i++)
|
|
{
|
|
if (ipmip_dhcp_options[i].code == code)
|
|
return &ipmip_dhcp_options[i];
|
|
}
|
|
|
|
return IP_NULL;
|
|
}
|
|
|
|
IP_GLOBAL const char *
|
|
ipmip_dhcp_option_print(struct Ipmip_proc *proc,
|
|
Ip_u8 *opt,
|
|
int type)
|
|
{
|
|
Ip_size_t off = 0;
|
|
Ip_size_t tsize = sizeof(proc->ntop.ntop_name);
|
|
Ip_size_t opt_len = opt[IPMIP_DHCP_OPT_LEN];
|
|
Ip_u8 *opt_data = &opt[IPMIP_DHCP_OPT_DATA];
|
|
unsigned i;
|
|
|
|
switch (type)
|
|
{
|
|
case IPMIP_DHCP_TYPE_STRING:
|
|
ipcom_memcpy(proc->ntop.ntop_name, opt_data, opt_len);
|
|
proc->ntop.ntop_name[off] = '\0';
|
|
break;
|
|
case IPMIP_DHCP_TYPE_BOOL:
|
|
ipcom_sprintf(proc->ntop.ntop_name, "%s", opt_data[0]? "enabled" : "disabled");
|
|
break;
|
|
case IPMIP_DHCP_TYPE_U32:
|
|
for (i = 0; i < opt_len / 4; i++)
|
|
off = ipcom_snprintf(&proc->ntop.ntop_name[off], tsize - off, "%s%s", i? " " : "", IP_GET_NTOHL(&opt_data[i * 4]));
|
|
break;
|
|
case IPMIP_DHCP_TYPE_U16:
|
|
for (i = 0; i < opt_len / 2; i++)
|
|
off = ipcom_snprintf(&proc->ntop.ntop_name[off], tsize - off, "%s%s", i? " " : "", IP_GET_NTOHS(&opt_data[i * 2]));
|
|
break;
|
|
case IPMIP_DHCP_TYPE_IP:
|
|
case IPMIP_DHCP_TYPE_IP_PAIR:
|
|
for (i = 0; i < opt_len / 4; i++)
|
|
off = ipcom_snprintf(&proc->ntop.ntop_name[off], tsize - off, "%s%s", i? " " : "", ipmip_ntop_inet(proc, IP_GET_32ON8(&opt_data[i * 4])));
|
|
break;
|
|
case IPMIP_DHCP_TYPE_U8:
|
|
off = ipcom_snprintf(&proc->ntop.ntop_name[off], tsize - off, "0x");
|
|
for (i = 0; i < opt_len; i++)
|
|
off = ipcom_snprintf(&proc->ntop.ntop_name[off], tsize - off, "%02x", opt_data[i]);
|
|
break;
|
|
}
|
|
|
|
return proc->ntop.ntop_name;
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ipmip_dhcp_option_t *
|
|
ipmip_dhcp_option_parse_name(Ipmip_proc_t *proc,
|
|
const char *name,
|
|
const char *value,
|
|
char **endptr)
|
|
{
|
|
int type;
|
|
Ip_u32 code;
|
|
Ip_u8 off;
|
|
|
|
if (endptr)
|
|
*endptr = IP_NULL;
|
|
|
|
for (type = 0; type < IPMIP_DHCP_TYPE_MAX; type++)
|
|
{
|
|
off = ipcom_strlen(ipmip_dhcp_type_name[type]);
|
|
if (ipcom_strncasecmp(ipmip_dhcp_type_name[type], name, off) == 0)
|
|
{
|
|
if (name[off] == '.')
|
|
{
|
|
off++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (type == IPMIP_DHCP_TYPE_MAX)
|
|
{
|
|
const Ipmip_dhcp_option_def_t *dopt;
|
|
const char *delim = ipcom_strchr(name, '.');
|
|
|
|
if (delim != IP_NULL)
|
|
{
|
|
Ip_size_t sz = IP_MIN((Ip_size_t)(delim - name), (sizeof(proc->ntop.ntop_pbuf) - 1));
|
|
if (endptr && delim[1] != '\0')
|
|
*endptr = (char *) (delim + 1);
|
|
|
|
ipcom_strncpy(proc->ntop.ntop_pbuf, name, sz);
|
|
proc->ntop.ntop_pbuf[sz] = '\0';
|
|
name = proc->ntop.ntop_pbuf;
|
|
}
|
|
|
|
dopt = ipmip_dhcp_option_def_name_get(name);
|
|
if (dopt == IP_NULL)
|
|
{
|
|
code = (Ip_u32)ipcom_strtoul((char *)name, IP_NULL, 0);
|
|
if (code > 0 && code < 255)
|
|
dopt = ipmip_dhcp_option_def_code_get((Ip_u8)code);
|
|
}
|
|
|
|
if (dopt)
|
|
return ipmip_dhcp_option_parse_type(dopt->code, value, dopt->type);
|
|
return IP_NULL;
|
|
}
|
|
|
|
/* Do parse */
|
|
code = (Ip_u32)ipcom_strtoul((char *)&name[off], endptr, 0);
|
|
if (endptr && (*endptr)[0] == '.')
|
|
*endptr = ((*endptr) + 1);
|
|
if (code < 255)
|
|
return ipmip_dhcp_option_parse_type((Ip_u8)code, value, type);
|
|
|
|
return IP_NULL;
|
|
}
|
|
|
|
IP_GLOBAL Ipmip_dhcp_option_t *
|
|
ipmip_dhcp_option_entry_find(Ipcom_list *options,
|
|
Ip_u8 code)
|
|
{
|
|
Ipmip_dhcp_option_t *opts;
|
|
for (opts = IPCOM_LIST_FIRST(options); opts != IP_NULL; opts = IPCOM_LIST_NEXT(&opts->next))
|
|
if (opts->option[IPMIP_DHCP_OPT_CODE] == code)
|
|
return opts;
|
|
|
|
return IP_NULL;
|
|
}
|
|
|
|
IP_GLOBAL int
|
|
ipmip_dhcp_buffer_append_option_entry(struct Ipmip_buffer *buf,
|
|
Ipmip_dhcp_option_t *opt)
|
|
{
|
|
if (ipmip_dhcp_option_buffer_find(buf, opt->option[IPMIP_DHCP_OPT_CODE]) == IP_NULL)
|
|
return ipmip_dhcp_option_buffer_append(buf, opt->option[IPMIP_DHCP_OPT_CODE], opt->option[IPMIP_DHCP_OPT_LEN], &opt->option[IPMIP_DHCP_OPT_DATA]);
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
IP_GLOBAL Ipmip_dhcp_pool_t *
|
|
ipmip_dhcp_pool_create(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
const char *name,
|
|
Ipmip_dhcp_rtab_t *rtab)
|
|
|
|
{
|
|
Ipmip_dhcp_pool_t *pool = ipcom_calloc(1, sizeof(*pool));
|
|
if(IP_NULL == pool)
|
|
return IP_NULL;
|
|
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
/**/
|
|
pool->name = ipcom_strdup(name);
|
|
pool->rtab = rtab;
|
|
ipcom_list_init(&pool->slices);
|
|
|
|
return pool;
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_pool_destroy(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_dhcp_pool_t *pool)
|
|
|
|
{
|
|
Ipmip_dhcp_slice_t *slice;
|
|
|
|
ipmip_route_walk(ctx, proc, pool->rtab->rtab, pool, (Ipmip_route_walk_t) ipmip_dhcp_route_walk);
|
|
|
|
ipcom_free(pool->name);
|
|
while ((slice = IPCOM_LIST_FIRST(&pool->slices)) != IP_NULL)
|
|
{
|
|
ipcom_list_remove(&slice->next);
|
|
ipcom_free(slice);
|
|
}
|
|
|
|
ipcom_free(pool);
|
|
}
|
|
|
|
IP_GLOBAL Ipmip_dhcp_rtab_t *
|
|
ipmip_dhcp_rtab_create(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_dhcp_lease_free_t rtab_free)
|
|
{
|
|
Ipmip_dhcp_rtab_t *rtab = ipcom_calloc(1, sizeof(*rtab));
|
|
if(IP_NULL == rtab)
|
|
return IP_NULL;
|
|
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
(void)ipcom_mutex_create(&rtab->rtab_lock);
|
|
rtab->rtab_free = rtab_free;
|
|
rtab->rtab = ipcom_route_new_table(sizeof(Ip_u32) * 8,
|
|
(Ipcom_route_notify_func) ipmip_dhcp_route_notify);
|
|
rtab->rtab_ctx = ctx;
|
|
rtab->rtab_proc = ipmip_proc_alloc();
|
|
|
|
return rtab;
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_rtab_destroy(Ipmip_dhcp_rtab_t *rtab)
|
|
{
|
|
ipcom_route_free_table(rtab->rtab);
|
|
ipcom_mutex_delete(&rtab->rtab_lock);
|
|
ipmip_proc_destroy(rtab->rtab_proc);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmip6ha_nemo_dsmipv6_alloc
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipmip_dhcp_lease_t *
|
|
ipmip_dhcp_pool_lease_alloc(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_dhcp_pool_t *pool,
|
|
Ip_u32 addr,
|
|
Ip_u8 prefix_len,
|
|
int alloc_rule,
|
|
void *opaque)
|
|
{
|
|
Ipmip_dhcp_slice_t *nslice = IPCOM_LIST_FIRST(&pool->slices);
|
|
Ipmip_dhcp_slice_t *oslice = nslice;
|
|
Ip_u32 chunk = 0;
|
|
Ip_u32 start = 0;
|
|
Ip_u32 size = 0;
|
|
Ipmip_dhcp_lease_t *lease = IP_NULL;
|
|
|
|
if (!nslice)
|
|
return IP_NULL;
|
|
|
|
if (addr != 0 && alloc_rule != IPMIP_DHCP_ALLOC_NETWORK)
|
|
{
|
|
Ipmip_dhcp_slice_t *rslice;
|
|
Ip_u8 rplen;
|
|
Ip_u32 raddr;
|
|
|
|
for (rslice = IPCOM_LIST_FIRST(&pool->slices); rslice != IP_NULL; rslice = IPCOM_LIST_NEXT(&rslice->next))
|
|
{
|
|
Ip_u32 mask;
|
|
if ((prefix_len == 32 && nslice->slice_size == 32) ||
|
|
(prefix_len != 32 && nslice->slice_size != 32))
|
|
{
|
|
rplen = nslice->slice_size;
|
|
|
|
mask = 0;
|
|
ipmip_util_create_mask((Ip_u8 *)&mask, rplen);
|
|
raddr = ip_ntohl(addr);
|
|
raddr &= mask;
|
|
|
|
/**/
|
|
if (raddr >= rslice->start && (raddr + ~mask) <= rslice->end)
|
|
{
|
|
if ((lease = ipmip_dhcp_lease_alloc(ctx, proc, pool, pool->rtab, addr, rplen, rslice->netmask_bits, opaque)) != IP_NULL)
|
|
return lease;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (alloc_rule == IPMIP_DHCP_ALLOC_EXACT)
|
|
return IP_NULL;
|
|
}
|
|
|
|
do
|
|
{
|
|
/* Find available entry in this pool */
|
|
Ip_u32 mask = 0;
|
|
|
|
if ((alloc_rule == IPMIP_DHCP_ALLOC_NETWORK && (addr & ipcom_htonl(nslice->mask)) == nslice->network) ||
|
|
(alloc_rule != IPMIP_DHCP_ALLOC_NETWORK && ((prefix_len == 32 && nslice->slice_size == 32) || (prefix_len != 32 && nslice->slice_size != 32))))
|
|
{
|
|
Ip_u32 stop_search = nslice->end;
|
|
|
|
prefix_len = nslice->slice_size;
|
|
|
|
ipmip_util_create_mask((Ip_u8 *)&mask, prefix_len);
|
|
size = ~ip_ntohl(mask);
|
|
|
|
/* Apparently we have it; find a nice chunk */
|
|
restart:
|
|
start = nslice->last & ip_ntohl(mask);
|
|
while (start < nslice->start)
|
|
start += size? size : 1;
|
|
|
|
while (start <= stop_search && (nslice->end - start) >= size)
|
|
{
|
|
Ipmip_route_t *prt;
|
|
|
|
chunk = ip_htonl(start);
|
|
|
|
/* Found, already in the table */
|
|
if (ipmip_route_lookup(pool->rtab->rtab, &chunk, &prt) == IPMIP_ROUTE_LOOKUP_MISS)
|
|
{
|
|
/* No match; try insert and see if it covers anything */
|
|
if ((lease = ipmip_dhcp_lease_alloc(ctx, proc, pool, pool->rtab, chunk, prefix_len, nslice->netmask_bits, opaque)) != IP_NULL)
|
|
{
|
|
/* Fix the last */
|
|
nslice->last = start + (size? size : 1);
|
|
if (nslice->last >= nslice->end)
|
|
nslice->last = nslice->start;
|
|
return lease;
|
|
}
|
|
}
|
|
|
|
/* Go next mask */
|
|
start += size? size : 1;
|
|
}
|
|
|
|
/* Do the init part as well */
|
|
if (nslice->last != nslice->start)
|
|
{
|
|
stop_search = nslice->last;
|
|
nslice->last = nslice->start;
|
|
goto restart;
|
|
}
|
|
|
|
ipcom_list_remove(&nslice->next);
|
|
ipcom_list_insert_last(&pool->slices, &nslice->next);
|
|
nslice = IPCOM_LIST_FIRST(&pool->slices);
|
|
continue;
|
|
}
|
|
|
|
/* Unusable slice; go to next */
|
|
nslice = IPCOM_LIST_NEXT(&nslice->next);
|
|
} while (nslice != IP_NULL && oslice != nslice);
|
|
|
|
return IP_NULL;
|
|
|
|
}
|
|
|
|
|
|
IP_GLOBAL Ipmip_dhcp_lease_t *
|
|
ipmip_dhcp_lease_alloc(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_dhcp_pool_t *pool,
|
|
Ipmip_dhcp_rtab_t *rtab,
|
|
Ip_u32 addr,
|
|
Ip_u8 prefix_len,
|
|
Ip_u8 netmask_bits,
|
|
void *opaque)
|
|
{
|
|
Ip_u32 subnet;
|
|
Ip_u32 mask = 0;
|
|
Ipmip_dhcp_lease_t *se;
|
|
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
ipmip_util_create_mask((Ip_u8 *)&mask, prefix_len);
|
|
subnet = addr & mask;
|
|
|
|
/* Found, already in the table */
|
|
if (ipmip_route_lookup(rtab->rtab, &subnet, (Ipmip_route_t **)&se) != IPMIP_ROUTE_LOOKUP_MISS)
|
|
return IP_NULL;
|
|
|
|
se = ipcom_calloc(1, sizeof(*se));
|
|
if (se == IP_NULL)
|
|
return IP_NULL;
|
|
|
|
se->mask = mask;
|
|
se->prefix = subnet;
|
|
se->prefix_len = prefix_len;
|
|
se->netmask_bits = netmask_bits;
|
|
|
|
/* Create the entry */
|
|
se->ipmip.hdr.key = &se->prefix;
|
|
se->ipmip.hdr.mask = &se->mask;
|
|
/**/
|
|
|
|
if (ipmip_route_add(rtab->rtab, &se->ipmip) != IPCOM_SUCCESS)
|
|
{
|
|
ipcom_free(se);
|
|
return IP_NULL;
|
|
}
|
|
|
|
/* We've added it; make certain it doesn't cover anyone */
|
|
if (ipmip_route_lookup_child(rtab->rtab, &se->ipmip) != IP_NULL)
|
|
{
|
|
ipmip_route_delete(rtab->rtab, &se->ipmip);
|
|
ipcom_free(se);
|
|
return IP_NULL;
|
|
}
|
|
|
|
se->pool = pool;
|
|
se->rtab = rtab;
|
|
se->opaque = opaque;
|
|
|
|
/* */
|
|
return se;
|
|
}
|
|
|
|
IP_GLOBAL Ipmip_dhcp_lease_t *
|
|
ipmip_dhcp_lease_lookup(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_dhcp_rtab_t *rtab,
|
|
Ip_u32 addr,
|
|
Ip_u8 prefix_len)
|
|
{
|
|
Ip_u32 subnet;
|
|
Ip_u32 mask = 0;
|
|
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
|
|
ipmip_util_create_mask((Ip_u8 *)&mask, prefix_len);
|
|
subnet = addr & mask;
|
|
|
|
/* Found, already in the table */
|
|
return (Ipmip_dhcp_lease_t *)ipmip_route_lookup_exact(rtab->rtab, &subnet, prefix_len);
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_lease_delete(struct Ipmip_context *ctx,
|
|
struct Ipmip_proc *proc,
|
|
Ipmip_dhcp_lease_t *lease)
|
|
{
|
|
IPMIP_UNUSED_PARAMETER(ctx);
|
|
IPMIP_UNUSED_PARAMETER(proc);
|
|
ipmip_route_delete(lease->rtab->rtab, &lease->ipmip);
|
|
}
|
|
|
|
IP_GLOBAL void
|
|
ipmip_dhcp_pool_add_slice(Ipmip_dhcp_pool_t *pool,
|
|
Ip_u32 start_addr,
|
|
Ip_u32 end_addr,
|
|
Ip_u8 plen,
|
|
Ip_u8 slice_size)
|
|
{
|
|
Ipmip_dhcp_slice_t *nslice = ipcom_calloc(1, sizeof(*nslice));
|
|
if (nslice)
|
|
{
|
|
ipmip_util_create_mask((Ip_u8 *)&nslice->mask, plen);
|
|
nslice->network = start_addr & nslice->mask;
|
|
nslice->mask = ip_ntohl(nslice->mask);
|
|
nslice->start = ip_ntohl(start_addr);
|
|
if (end_addr)
|
|
nslice->end = ip_ntohl(end_addr);
|
|
else
|
|
{
|
|
if (plen != 32)
|
|
{
|
|
Ip_u32 network = (nslice->start & nslice->mask);
|
|
if (slice_size == 32)
|
|
{
|
|
/* Skip the broadcast */
|
|
nslice->end = (network + ~nslice->mask) - 1;
|
|
/* Skip network address */
|
|
if (nslice->start == network)
|
|
nslice->start++;
|
|
}
|
|
else
|
|
nslice->end = (network + ~nslice->mask);
|
|
}
|
|
else
|
|
nslice->end = nslice->start;
|
|
}
|
|
nslice->remain = nslice->end - nslice->start;
|
|
nslice->last = nslice->start;
|
|
nslice->slice_size = slice_size;
|
|
nslice->netmask_bits = plen;
|
|
ipcom_list_insert_last(&pool->slices, &nslice->next);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
#else /* IPMIP_USE_INET */
|
|
int ipmip_dhcp_empty_file = 0;
|
|
#endif /* IPMIP_USE_INET */
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|