/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6pm_service_dhcpv6_relay.c,v $ $Revision: 1.7 $ * $Source: /home/interpeak/CVSRoot/ipmip6pm/config/ipmip6pm_service_dhcpv6_relay.c,v $ * $Author: jhorteli $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6pm_config.h" /* **************************************************************************** * 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 #include #include #include #include "ipmip6pm_h.h" #include "ipmip6pm_attr_h.h" #include "ipmip6pm_if.h" #include "ipmip6pm_node.h" #include "ipmip6pm_pktbuf.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPMIP6PM_SERVICE_DHCPV6_RELAY_NAME "DHCPV6_RELAY" /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipmip6pm_service_dhcpv6_relay_fwd { Ip_u32 ifindex; struct Ip_in6_addr srv; } Ipmip6pm_service_dhcpv6_relay_fwd_t; typedef struct Ipmip6pm_service_dhcpv6_relay_config { int mode; Ip_u32 ifscope; struct Ip_in6_addr *srv; } Ipmip6pm_service_dhcpv6_relay_config_t; typedef struct Ipmip6pm_service_dhcpv6_relay_handle { Ipmip_dhcp6_node_t relay; Ip_u32 ifscope; struct Ip_in6_addr *srv; Ipmip6_address_t link_address; Ip_bool enabled; Ip_bool registered; } Ipmip6pm_service_dhcpv6_relay_handle_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC int ipmip6pm_service_dhcpv6_relay(int event, Ipmip6pm_context_t *ctx, Ipmip_proc_t *proc, Ipmip6pm_service_dhcpv6_relay_handle_t *dnode, Ipmip6pm_pktbuf_t *pbuf) { if (event == IPMIP_TIMER_EVENT_RUN) { Ipmip_dhcp6_hdr_t *pkt = (Ipmip_dhcp6_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet); Ipmip_dhcp6_relay_hdr_t *rpkt = (Ipmip_dhcp6_relay_hdr_t *)IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet); Ip_u8 hc = 0; /* Sanity process */ switch (pkt->msg_type) { /**/ case IPMIP_DHCP6_MSG_RELAY_REPLY: /* Must forward to client */ { Ipmip_dhcp6_option_hdr_t *rmsg = ipmip_dhcp6_option_buffer_find(&pbuf->ipmip6.ipmip.packet, IPMIP_DHCP6_OPTION_RELAY_MSG); if (rmsg == IP_NULL) goto done_out; /* Do forward */ ipmip_dhcp6_send_msg(&ctx->ipmip6.ipmip, proc, rmsg + 1, IP_GET_NTOHS(&rmsg->length), &rpkt->peer_addr, dnode->relay.ifindex); } break; case IPMIP_DHCP6_MSG_RELAY_FORWARD: hc = rpkt->hop_count; /* Fall Through */ default: { Ipmip_pktbuf_t *rpbuf = (Ipmip_pktbuf_t *)ipmip_dhcp6_relay_msg(&ctx->ipmip6.ipmip, proc, &dnode->link_address.prefix, hc, &pbuf->ipmip6.ipmip); if (rpbuf) { ipmip_dhcp6_send_msg(&ctx->ipmip6.ipmip, proc, IPMIP_BUFFER_DATA(&rpbuf->packet), IPMIP_BUFFER_SIZE(&rpbuf->packet), dnode->srv, dnode->ifscope); ipmip_pktbuf_release(&ctx->ipmip6.ipmip, proc, rpbuf); } } break; } } /* Free the DHCP packet */ done_out: ipmip_pktbuf_release(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip); return IPMIP_TIMER_RET_DONE; } IP_STATIC void ipmip6pm_service_dhcpv6_relay_parse(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, struct Ip_in6_addr **addr, Ip_u32 *ifscope, const char *value) { /* Scope? */ if (((*ifscope) = ipcom_if_nametoindex(value)) == 0) { *addr = ipcom_malloc(sizeof(struct Ip_in6_addr)); if (!ipmip_util_inet6(value, *addr, IP_NULL)) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Unable to properly parse DHCPv6 Relay Destination %s", value)); ipcom_free(*addr); *addr = IP_NULL; } } } IP_STATIC void ipmip6pm_service_dhcpv6_relay_config_global(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, int action, Ipmip6pm_service_dhcpv6_relay_config_t *gcfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); if (action == IPMIP_CALLBACK_CONFIG_READ) { char *fwd = ipmip_sysvar("ipmip6pm.dhcpv6_relay.server"); gcfg->mode = ipmip_sysvar_mode(IPMIP_SYSVAR_MODE_OPTIONAL, "ipmip6pm.dhcpv6_relay.mode"); if (fwd) { ipmip6pm_service_dhcpv6_relay_parse(ctx, proc, &gcfg->srv, &gcfg->ifscope, fwd); ipcom_free(fwd); } } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { /* Do nothing */ if (gcfg->srv) ipcom_free(gcfg->srv); } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { ipmip_cli_config_printf(&request->message, "ipmip6pm.dhcpv6_relay.mode=%s", ipmip_sysvar_mode_desc[gcfg->mode]); if (gcfg->ifscope) { ipmip_cli_config_printf(&request->message, "ipmip6pm.dhcpv6_relay.server=%s", ipcom_if_indextoname(gcfg->ifscope, proc->ntop.ntop_name)); } else if (gcfg->srv != IP_NULL) { ipmip_cli_config_printf(&request->message, "ipmip6pm.dhcpv6_relay.server=%s", ipmip_ntop_inet6(proc, gcfg->srv, IP_NULL)); } } } IP_STATIC void ipmip6pm_service_dhcpv6_relay_config(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, int action, struct Ipmip6pm_if *ifp, Ipmip6pm_service_dhcpv6_relay_config_t *gcfg, Ipmip6pm_service_dhcpv6_relay_config_t *cfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); if (action == IPMIP_CALLBACK_CONFIG_READ) { char *fwd = ipmip_sysvar("ipmip6pm.interface.%s.dhcpv6_relay.server", ifp->ipmip6.iff.ifname); cfg->mode = ipmip_sysvar_mode(gcfg->mode, "ipmip6pm.interface.%s.dhcpv6_relay.mode", ifp->ipmip6.iff.ifname); if (fwd) { ipmip6pm_service_dhcpv6_relay_parse(ctx, proc, &cfg->srv, &cfg->ifscope, fwd); ipcom_free(fwd); } if (cfg->srv == IP_NULL && cfg->ifscope == 0) { cfg->srv = gcfg->srv; cfg->ifscope = gcfg->ifscope; } if (cfg->mode != IPMIP_SYSVAR_MODE_DISABLED) { /* We need the DHCP context */ ipmip_dhcp6_context_create(&ctx->ipmip6.ipmip, proc); } } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { /* Do nothing */ if (cfg->srv != IP_NULL && cfg->srv != gcfg->srv) { ipcom_free(cfg->srv); cfg->srv = IP_NULL; } } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.dhcpv6_relay.mode=%s", ifp->ipmip6.iff.ifname, ipmip_sysvar_mode_desc[cfg->mode]); if (cfg->ifscope) { ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.dhcpv6_relay.server=%s", ifp->ipmip6.iff.ifname, ipcom_if_indextoname(cfg->ifscope, proc->ntop.ntop_name)); } else if (cfg->srv) { ipmip_cli_config_printf(&request->message, "ipmip6pm.interface.%s.dhcpv6_relay.server=%s", ifp->ipmip6.iff.ifname, ipmip_ntop_inet6(proc, cfg->srv, IP_NULL)); } } } IP_STATIC int ipmip6pm_service_dhcpv6_relay_provide(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, int action, Ipmip6pm_service_dhcpv6_relay_config_t *gcfg, Ipmip6pm_service_dhcpv6_relay_config_t *cfg, Ipmip6pm_service_dhcpv6_relay_handle_t *handle, struct Ipmip6pm_node *node, struct Ipmip_timer *service) { IPMIP_UNUSED_PARAMETER(service); IPMIP_UNUSED_PARAMETER(cfg); IPMIP_UNUSED_PARAMETER(gcfg); if (action == IPMIP_CALLBACK_ENABLE) { if (handle->enabled) { unsigned i; /* OK - MUST ASSIGN ADDRESS BASED ON ALLOCATED PREFIX */ /* Do the prefixes */ for (i = 0; i < node->mo_home_prefix_size; i++) { if (ipmip6_netlink_prefix_generate(&ctx->ipmip6, proc, node->ifp_private.ipmip6.ifp->iff.ifindex, &node->mo_home_prefix[i].prefix, node->mo_home_prefix[i].prefix_length, &handle->link_address)) break; } /**/ if (i < node->mo_home_prefix_size) ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_NEWADDR, node->ifp_private.ipmip6.ifp->iff.ifindex, &handle->link_address.prefix, handle->link_address.len, 0, 0); handle->relay.ifindex = node->ifp_private.ipmip6.ifp->iff.ifindex; handle->relay.lock = node->lock; handle->relay.process_func = (Ipmip_timer_func_t)ipmip6pm_service_dhcpv6_relay; handle->registered = IP_TRUE; ipmip_dhcp6_register(&ctx->ipmip6.ipmip, proc, &handle->relay); } } else if (action == IPMIP_CALLBACK_DISABLE) { if (handle->registered) { ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELADDR, node->ifp_private.ipmip6.ifp->iff.ifindex, &handle->link_address.prefix, handle->link_address.len, 0, 0); handle->registered = IP_FALSE; ipmip_dhcp6_unregister(&ctx->ipmip6.ipmip, proc, &handle->relay); } } /* Don't delay */ return IPMIP_CALLBACK_RET_SUCCESS; } IP_STATIC Ip_bool ipmip6pm_service_dhcpv6_relay_setup(struct Ipmip6pm_context *ctx, struct Ipmip_proc *proc, int action, Ipmip6pm_service_dhcpv6_relay_config_t *gcfg, Ipmip6pm_service_dhcpv6_relay_config_t *cfg, Ipmip6pm_service_dhcpv6_relay_handle_t *handle, struct Ipmip6pm_node *node, const char *value, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(gcfg); if (action == IPMIP_CALLBACK_CONFIG_READ) { /* Turned off in configuration */ if (cfg->mode == IPMIP_SYSVAR_MODE_DISABLED) return IP_FALSE; /* Turned on by node */ if (value == IP_NULL && cfg->mode == IPMIP_SYSVAR_MODE_OPTIONAL) return IP_FALSE; handle->enabled = IP_TRUE; if (value && ipcom_strlen(value)) ipmip6pm_service_dhcpv6_relay_parse(ctx, proc, &handle->srv, &handle->ifscope, value); if (handle->srv == IP_NULL && handle->ifscope == 0) { handle->srv = cfg->srv; handle->ifscope = cfg->ifscope; } /* Rever to home agent */ if (handle->srv == IP_NULL && handle->ifscope == 0) handle->srv = &node->homeagent; return IP_TRUE; } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { handle->enabled = IP_FALSE; if (handle->srv != IP_NULL && handle->srv != cfg->srv && handle->srv != &node->homeagent) { ipcom_free(handle->srv); handle->srv = IP_NULL; } } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { if (handle->enabled) { Ip_size_t rta = ipmip_attr_begin(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SERVICE); ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SRV_MODULE, IPMIP6PM_SERVICE_DHCPV6_RELAY_NAME); if (handle->ifscope) { ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SRV_VALUE, ipcom_if_indextoname(handle->ifscope, proc->ntop.ntop_name)); } else { ipmip_attr_put_str(&request->message, IPMIP6PM_CLI_ATTR_BC_P_SRV_VALUE, ipmip_ntop_inet6(proc, handle->srv, IP_NULL)); } ipmip_attr_end(&request->message, rta); } } return IP_FALSE; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmip6pm_service_dhcpv6_relay_install(struct Ipmip6pm_context *ctx); IP_GLOBAL void ipmip6pm_service_dhcpv6_relay_install(struct Ipmip6pm_context *ctx) { static Ipmip6pm_extension_t srv; srv.name = IPMIP6PM_SERVICE_DHCPV6_RELAY_NAME; srv.syntax = ""; srv.node_data_size = sizeof(Ipmip6pm_service_dhcpv6_relay_handle_t); srv.ifp_data_size = sizeof(Ipmip6pm_service_dhcpv6_relay_config_t); srv.global_data_size= sizeof(Ipmip6pm_service_dhcpv6_relay_config_t); srv.config_global = (Ipmip6pm_extension_config_global_t)ipmip6pm_service_dhcpv6_relay_config_global; srv.config_ifp = (Ipmip6pm_extension_config_ifp_t)ipmip6pm_service_dhcpv6_relay_config; srv.provide = (Ipmip6pm_extension_provide_t)ipmip6pm_service_dhcpv6_relay_provide; srv.setup = (Ipmip6pm_extension_setup_t)ipmip6pm_service_dhcpv6_relay_setup; ipmip6pm_context_register_extension(ctx, &srv, IPMIP6PM_FUNCTION_SERVICE); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */