Files
m241Neelima/components/ip_net2-6.9/ipmip/src/ipmip_dhcp.c
T
2026-07-30 11:19:44 +05:30

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
****************************************************************************
*/