/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6ha_pmipv6_dhcpv4.c,v $ $Revision: 1.7 $ * $Source: /home/interpeak/CVSRoot/ipmip6ha/config/ipmip6ha_pmipv6_dhcpv4.c,v $ * $Author: jhorteli $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6ha_config.h" #if defined(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 #include "ipmip6ha_h.h" #include "ipmip6ha_attr_h.h" #include "ipmip6ha_if.h" #include "ipmip6ha_node.h" #include "ipmip6ha_pktbuf.h" #include "ipmip6ha_nemo.h" #include "ipmip6ha_nemo_dsmipv6.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPMIP6HA_PMIPV6_DHCPV4_SERVER "DHCPV4-SERVER" /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipmip6ha_pmipv6_dhcpv4_config { Ip_bool enabled; } Ipmip6ha_pmipv6_dhcpv4_config_t; typedef struct Ipmip6ha_pmipv6_dhcpv4_config_global { Ip_bool enabled; } Ipmip6ha_pmipv6_dhcpv4_config_global_t; typedef struct Ipmip6ha_pmipv6_dhcpv4_node { Ipmip_dhcp_node_t dhcp; Ip_bool installed; } Ipmip6ha_pmipv6_dhcpv4_node_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC int ipmip6ha_pmipv6_dhcpv4_server(int event, Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc, Ipmip6ha_pmipv6_dhcpv4_node_t *dnode, Ipmip6ha_pktbuf_t *pbuf) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmip6ha_node_t *node = dnode->dhcp.opaque; Ipmip_dhcp_hdr_t *pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet); if (pkt->op == IPMIP_DHCP_OP_BOOTREQUEST) { Ip_u8 *opt; /**/ if ((opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_MESSAGE_TYPE)) == IP_NULL) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "No MESSAGE TYPE in DHCP Request Received by %s", ipmip6ha_node_describe(proc, node))); goto done_out; } else { Ipmip6ha_pktbuf_t *rpkt = (Ipmip6ha_pktbuf_t*)ipmip_pktbuf_alloc(&ctx->ipmip6.ipmip, proc, 512); Ipmip_buffer_t *buf = &rpkt->ipmip6.ipmip.packet; Ip_u8 type; Ip_u8 *ra_opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO); Ip_u8 *req_opt = ipmip_dhcp_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_PARAMETER_REQUEST_LIST); Ip_u32 tmp32; Ip_u32 override = 0; /* Do we have a override option? */ if (ra_opt) { Ip_u8 *oopt = ipmip_dhcp_option_find(&ra_opt[IPMIP_DHCP_OPT_DATA], ra_opt[IPMIP_DHCP_OPT_LEN], IPMIP_DHCP_SUBOPTCODE_RA_SERVER_OVERRIDE); if (oopt) override = IP_GET_32ON8(&oopt[IPMIP_DHCP_OPT_DATA]); } /* Add the packet */ ipmip_buffer_append(buf, pkt, sizeof(*pkt)); switch(opt[IPMIP_DHCP_OPT_DATA]) { case IPMIP_DHCP_MSG_DISCOVER: IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Discover Received by %s", ipmip6ha_node_describe(proc, node))); type = IPMIP_DHCP_MSG_OFFER; break; case IPMIP_DHCP_MSG_REQUEST: { Ip_u32 sid = 0; Ip_u32 req_addr = 0; IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Request Received by %s", ipmip6ha_node_describe(proc, node))); sid = ipmip_dhcp_option_buffer_find_ip(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_SERVER_IDENTIFIER); req_addr = ipmip_dhcp_option_buffer_find_ip(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP_OPTCODE_DHCP_REQUESTED_ADDRESS); if (req_addr == 0) req_addr = IP_GET_32ON8(&pkt->ciaddr); if (sid != 0 && sid != node->ifp_home->ifaddr_v4) { if (override == 0 || sid != override) goto done_out; } if (req_addr != 0 && req_addr == dnode->dhcp.remote_id) type = IPMIP_DHCP_MSG_ACK; else type = IPMIP_DHCP_MSG_NAK; } break; case IPMIP_DHCP_MSG_DECLINE: /* Do what? */ IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Decline Received by %s", ipmip6ha_node_describe(proc, node))); goto done_out; case IPMIP_DHCP_MSG_RELEASE: /* Do what? */ IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Release Received by %s", ipmip6ha_node_describe(proc, node))); goto done_out; case IPMIP_DHCP_MSG_INFORM: /* Do what? */ IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Inform Received by %s", ipmip6ha_node_describe(proc, node))); if (IP_GET_32ON8(&pkt->ciaddr) == dnode->dhcp.remote_id) type = IPMIP_DHCP_MSG_INFORM_ACK; else type = IPMIP_DHCP_MSG_NAK; break; default: IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP unknown Received by %s", ipmip6ha_node_describe(proc, node))); goto done_out; } /* Add TYPE */ ipmip_dhcp_option_buffer_append_u8(buf, IPMIP_DHCP_OPTCODE_DHCP_MESSAGE_TYPE, type); ipmip_dhcp_option_buffer_append_ip(buf, IPMIP_DHCP_OPTCODE_DHCP_SERVER_IDENTIFIER, override? override : node->ifp_home->ifaddr_v4); /**/ if (type != IPMIP_DHCP_MSG_NAK) { /* ACK or INFORM_ACK */ if (type != IPMIP_DHCP_MSG_INFORM_ACK) { #ifndef IPTESTENGINE ipmip_dhcp_option_buffer_append_u32(buf, IPMIP_DHCP_OPTCODE_DHCP_LEASE_TIME, node->mip6BindingCacheEntry.mip6BindingTimeRemaining); #else ipmip_dhcp_option_buffer_append_u32(buf, IPMIP_DHCP_OPTCODE_DHCP_LEASE_TIME, 5); #endif } /* Add the basic options */ { Ipmip6ha_nemo_dsmipv6_config_t *cfg = ipmip6ha_nemo_dsmipv6_subnet_config_get(ctx, proc, node->ifp_home->nemo->nemo_dsmipv6, dnode->dhcp.remote_id); if (cfg != IP_NULL) { Ipmip6ha_nemo_dsmipv6_config_t *ncfg; Ipmip_dhcp_option_t *dopt; if (req_opt != IP_NULL) { for (tmp32 = 0; tmp32 < req_opt[IPMIP_DHCP_OPT_LEN]; tmp32++) { for (ncfg = cfg; ncfg != IP_NULL; ncfg = ncfg->parent) { dopt = ipmip_dhcp_option_entry_find(&ncfg->opts, req_opt[IPMIP_DHCP_OPT_DATA + tmp32]); if (dopt != IP_NULL) { ipmip_dhcp_buffer_append_option_entry(buf, dopt); break; } } } } for (ncfg = cfg; ncfg != IP_NULL; ncfg = ncfg->parent) { for (dopt = IPCOM_LIST_FIRST(&ncfg->opts); dopt != IP_NULL; dopt = IPCOM_LIST_NEXT(&dopt->next)) ipmip_dhcp_buffer_append_option_entry(buf, dopt); } } } } else { /* NAK */ } /* Restore the RA_OPT */ if (ra_opt) ipmip_dhcp_option_buffer_append(buf, IPMIP_DHCP_OPTCODE_RELAY_AGENT_INFO, ra_opt[IPMIP_DHCP_OPT_LEN], &ra_opt[IPMIP_DHCP_OPT_DATA]); ipmip_dhcp_option_buffer_close(buf); pkt = (Ipmip_dhcp_hdr_t *)IPMIP_BUFFER_PTR(buf); pkt->op = IPMIP_DHCP_OP_BOOTREPLY; pkt->hops = 0; if (type != IPMIP_DHCP_MSG_NAK && type != IPMIP_DHCP_MSG_INFORM_ACK) IP_SET_32ON8(&pkt->yiaddr, dnode->dhcp.remote_id); /* Send */ tmp32 = IP_GET_32ON8(&pkt->giaddr); if (tmp32 == 0) tmp32 = dnode->dhcp.remote_id; /* Always assume unicast; unicast renew will be tunneled */ ipmip_dhcp_server_reply(&ctx->ipmip6.ipmip, proc, &rpkt->ipmip6.ipmip, node->ifp_home->ifaddr_v4, IP_NULL, IP_FALSE); } } else { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "DHCP Reply Received for %s", ipmip6ha_node_describe(proc, node))); } } done_out: /* Free the DHCP packet */ ipmip_pktbuf_release(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC void ipmip6ha_pmipv6_dhcpv4_config(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, int action, struct Ipmip6ha_if *ifp, Ipmip6ha_pmipv6_dhcpv4_config_global_t *gcfg, Ipmip6ha_pmipv6_dhcpv4_config_t *cfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(ifp); if (action == IPMIP_CALLBACK_CONFIG_READ) { cfg->enabled = ipmip_sysvar_bool(gcfg->enabled, "ipmip6ha.interface.%s.LMA.inet.dhcp.server", ifp->ipmip6.iff.ifname); if (cfg->enabled) ipmip_dhcp_context_create(&ctx->ipmip6.ipmip, proc); } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { /**/ } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { ipmip_cli_config_printf(&request->message, "ipmip6ha.interface.%s.LMA.inet.dhcp.server=%s", ifp->ipmip6.iff.ifname, cfg->enabled? "enabled" : "disabled"); } } IP_STATIC void ipmip6ha_pmipv6_dhcpv4_config_global(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, int action, Ipmip6ha_pmipv6_dhcpv4_config_global_t *gcfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); if (action == IPMIP_CALLBACK_CONFIG_READ) { gcfg->enabled = ipmip_sysvar_bool(IP_FALSE, "ipmip6ha.LMA.inet.dhcp.server"); } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { ipmip_cli_config_printf(&request->message, "ipmip6ha.LMA.inet.dhcp.server=%s", gcfg->enabled? "enabled" : "disabled"); } } IP_STATIC int ipmip6ha_pmipv6_dhcpv4_provide(struct Ipmip6ha_context *ctx, struct Ipmip_proc *proc, int action, void *gcfg, Ipmip6ha_pmipv6_dhcpv4_config_t *cfg, Ipmip6ha_pmipv6_dhcpv4_node_t *handle, struct Ipmip6ha_node_P *node, struct Ipmip_timer *service) { Ipmip6ha_nemo_dsmipv6_t *nemo; IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(service); IPMIP_UNUSED_PARAMETER(gcfg); if (cfg->enabled) { if (action == IPMIP_CALLBACK_ENABLE) { nemo = IPCOM_LIST_FIRST(&node->node.nemo_hoa_v4); if (nemo != IP_NULL) { handle->dhcp.remote_id = nemo->prefix; handle->dhcp.lock = node->node.lock; handle->dhcp.opaque = node; handle->dhcp.process_func = (Ipmip_timer_func_t)ipmip6ha_pmipv6_dhcpv4_server; ipmip_dhcp_register(&ctx->ipmip6.ipmip, proc, &handle->dhcp); handle->installed = IP_TRUE; } } else if (action == IPMIP_CALLBACK_DISABLE || action == IPMIP_CALLBACK_UPDATE) { if (handle->installed) { ipmip_dhcp_unregister(&ctx->ipmip6.ipmip, proc, &handle->dhcp); handle->installed = IP_FALSE; } if (action == IPMIP_CALLBACK_UPDATE) return IPMIP_CALLBACK_RET_FAILED; } } /* Don't delay */ return IPMIP_CALLBACK_RET_SUCCESS; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmip6ha_pmipv6_dhcpv4_install(struct Ipmip6ha_context *ctx); IP_GLOBAL void ipmip6ha_pmipv6_dhcpv4_install(struct Ipmip6ha_context *ctx) { static Ipmip6ha_extension_t srv; ipcom_memset(&srv, 0, sizeof(srv)); srv.name = IPMIP6HA_PMIPV6_DHCPV4_SERVER; srv.ifp_data_size = sizeof(Ipmip6ha_pmipv6_dhcpv4_config_t); srv.global_data_size= sizeof(Ipmip6ha_pmipv6_dhcpv4_config_global_t); srv.node_data_size = sizeof(Ipmip6ha_pmipv6_dhcpv4_node_t); srv.config_global = (Ipmip6ha_extension_config_global_t)ipmip6ha_pmipv6_dhcpv4_config_global; srv.config_ifp = (Ipmip6ha_extension_config_ifp_t)ipmip6ha_pmipv6_dhcpv4_config; srv.provide = (Ipmip6ha_extension_provide_t)ipmip6ha_pmipv6_dhcpv4_provide; /* This is a PMIP only feature */ ipmip6ha_context_register_extension(ctx, &srv, IP_FALSE, IP_TRUE); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ #else IP_GLOBAL void ipmip6ha_pmipv6_dhcpv4_install(struct Ipmip6ha_context *ctx); IP_GLOBAL void ipmip6ha_pmipv6_dhcpv4_install(struct Ipmip6ha_context *ctx) { IPMIP_UNUSED_PARAMETER(ctx); } #endif /* **************************************************************************** * END OF FILE **************************************************************************** */