/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include #ifdef IPMIP_USE_INET /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* **************************************************************************** * 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 **************************************************************************** */