/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6mn_service_mpdisc.c,v $ $Revision: 1.6 $ * $Source: /home/interpeak/CVSRoot/ipmip6mn/config/ipmip6mn_service_mpdisc.c,v $ * $Author: jhorteli $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6mn_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 "ipmip6mn_h.h" #include "ipmip6mn_pktbuf.h" #include "ipmip6mn_coa.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipmip6mn_service_mpdisc_config { Ip_bool save_config; Ip_bool derive_from_config; Ip_u32 derive_from_ifindex; Ip_bool derive_from_interface; } Ipmip6mn_service_mpdisc_config_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC Ip_bool ipmip6mn_mpdisc_prefix_renumber_if(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, struct Ipmip6mn_node *node, Ip_u32 ifindex, struct Ip_in6_addr *prefix, Ip_u8 *prefix_len) { Ipmip6_address_t reply; IPMIP_UNUSED_PARAMETER(node); if (ifindex == 0) return IP_FALSE; if (ipmip6_netlink_prefix_generate(&ctx->ipmip6, proc, ifindex, prefix, *prefix_len, &reply)) { ipcom_memcpy(prefix, &reply.prefix, sizeof(*prefix)); *prefix_len = reply.len; return IP_TRUE; } return IP_FALSE; } IP_STATIC Ip_bool ipmip6mn_mpdisc_prefix_renumber_resolve(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, struct Ipmip6mn_node *node, Ipmip6mn_service_mpdisc_config_t *rcfg, struct Ip_in6_addr *new_addr, Ip_u8 *new_addr_len) { unsigned int i; if (rcfg->derive_from_config) { for (i = 0; i < node->mobile_prefix.mobile_prefix_size; i++) { Ipmip6_pkt_nd_opt_prefix_info_t *pinfo = &node->mobile_prefix.mobile_prefix[i]; if (IP_BIT_ISSET(pinfo->nd_opt_pi_flags_reserved, IPMIP6_ND_OPT_PI_FLAG_AUTO)) { *new_addr_len = pinfo->nd_opt_pi_prefix_len; if (*new_addr_len == node->config->inet6.len) { ipcom_memcpy(new_addr, &node->config->inet6.prefix, sizeof(*new_addr)); ipmip6_address_apply_prefix(new_addr, &pinfo->nd_opt_pi_prefix, *new_addr_len); return IP_TRUE; } } } } if (rcfg->derive_from_interface) { Ipmip6mn_coa_notify_t *ifn; /* Try form a CoA based on explicitly specified interface */ if (rcfg->derive_from_ifindex != 0) { for (i = 0; i < node->mobile_prefix.mobile_prefix_size; i++) { Ipmip6_pkt_nd_opt_prefix_info_t *pinfo = &node->mobile_prefix.mobile_prefix[i]; if (IP_BIT_ISSET(pinfo->nd_opt_pi_flags_reserved, IPMIP6_ND_OPT_PI_FLAG_AUTO)) { *new_addr_len = pinfo->nd_opt_pi_prefix_len; ipcom_memcpy(new_addr, &pinfo->nd_opt_pi_prefix, sizeof(*new_addr)); if (ipmip6mn_mpdisc_prefix_renumber_if(ctx, proc, node, rcfg->derive_from_ifindex, new_addr, new_addr_len)) return IP_TRUE; } } } /* Try form an address based on current CoA interface */ for (i = 0; i < node->mobile_prefix.mobile_prefix_size; i++) { Ipmip6_pkt_nd_opt_prefix_info_t *pinfo = &node->mobile_prefix.mobile_prefix[i]; if (IP_BIT_ISSET(pinfo->nd_opt_pi_flags_reserved, IPMIP6_ND_OPT_PI_FLAG_AUTO)) { *new_addr_len = pinfo->nd_opt_pi_prefix_len; ipcom_memcpy(new_addr, &pinfo->nd_opt_pi_prefix, sizeof(*new_addr)); if (ipmip6mn_mpdisc_prefix_renumber_if(ctx, proc, node, node->ha.coa->ifn->ipmip6.ifp->iff.ifindex, new_addr, new_addr_len)) return IP_TRUE; } } /* Go through the interfaces; select the best we'll get */ for (ifn = IPCOM_LIST_FIRST(&node->config->ifs); ifn != IP_NULL; ifn = IPCOM_LIST_NEXT(&ifn->next)) { if (ifn != node->ha.coa->ifn && ifn->ipmip6.ifp->iff_down == IP_FALSE) { /* Try form an address based on current CoA interface */ for (i = 0; i < node->mobile_prefix.mobile_prefix_size; i++) { Ipmip6_pkt_nd_opt_prefix_info_t *pinfo = &node->mobile_prefix.mobile_prefix[i]; if (IP_BIT_ISSET(pinfo->nd_opt_pi_flags_reserved, IPMIP6_ND_OPT_PI_FLAG_AUTO)) { *new_addr_len = pinfo->nd_opt_pi_prefix_len; ipcom_memcpy(new_addr, &pinfo->nd_opt_pi_prefix, sizeof(*new_addr)); if (ipmip6mn_mpdisc_prefix_renumber_if(ctx, proc, node, ifn->ipmip6.ifp->iff.ifindex, new_addr, new_addr_len)) return IP_TRUE; } } } } } return IP_FALSE; } IP_STATIC int ipmip6mn_service_mpdisc_provide(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, int action, struct Ipmip6mn_node *node, struct Ipmip6mn_node_config *cfg, Ipmip6mn_service_mpdisc_config_t *priv_cfg, void *node_data, struct Ipmip_timer *service) { IPMIP_UNUSED_PARAMETER(node_data); IPMIP_UNUSED_PARAMETER(cfg); IPMIP_UNUSED_PARAMETER(service); if (action == IPMIP_CALLBACK_ENABLE) { struct Ip_in6_addr new_addr; Ip_u8 new_addr_len; if (ipmip6mn_mpdisc_prefix_renumber_resolve(ctx, proc, node, priv_cfg, &new_addr, &new_addr_len)) { if (priv_cfg->save_config) { ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf), "%s/%d", ipmip_ntop_inet6(proc, &new_addr, IP_NULL), new_addr_len); ipmip_sysvar_set(proc->ntop.ntop_pbuf, "ipmip6mn.%s.homeaddress", node->name); } /* Do renumber */ ipmip6mn_node_renumber(ctx, proc, node, &new_addr, new_addr_len); } } else if (action == IPMIP_CALLBACK_DISABLE) { /* Currently no action */ } return IPMIP_CALLBACK_RET_SUCCESS; } IP_STATIC void ipmip6mn_service_mpdisc_config(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, int action, struct Ipmip6mn_node *node, struct Ipmip6mn_node_config *cfg, Ipmip6mn_service_mpdisc_config_t *priv_cfg, Ipmip_cli_message_t *request) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(cfg); if (action == IPMIP_CALLBACK_CONFIG_READ) { char *ifname = ipmip_sysvar("ipmip6mn.%s.mobile_prefix.renumber.derive_from_interface", node->name); priv_cfg->derive_from_config = ipmip_sysvar_bool(IP_FALSE, "ipmip6mn.%s.mobile_prefix.renumber.derive_from_configured", node->name); if (ifname) { priv_cfg->derive_from_ifindex = ipcom_if_nametoindex(ifname); if (priv_cfg->derive_from_ifindex == 0) { int op_val = ipmip_sysvar_cmd_str_to_key(ipmip_sysvar_bool_ops, ifname); if (op_val != -1) priv_cfg->derive_from_interface = IP_TRUE; } else priv_cfg->derive_from_interface = IP_TRUE; ipcom_free(ifname); } priv_cfg->save_config = ipmip_sysvar_bool(IP_FALSE, "ipmip6mn.%s.mobile_prefix.renumber.save", node->name); } else if (action == IPMIP_CALLBACK_CONFIG_FREE) { /* Do nothing */ } else if (action == IPMIP_CALLBACK_CONFIG_DUMP) { if (priv_cfg->derive_from_ifindex) { ipmip_cli_config_printf(&request->message, "ipmip6mn.%s.mobile_prefix.renumber.derive_from_interface=%s", node->name, ipcom_if_indextoname(priv_cfg->derive_from_ifindex, proc->ntop.ntop_name)); } else { ipmip_cli_config_printf(&request->message, "ipmip6mn.%s.mobile_prefix.renumber.derive_from_interface=%s", node->name, priv_cfg->derive_from_interface? "true" : "false"); } ipmip_cli_config_printf(&request->message, "ipmip6mn.%s.mobile_prefix.renumber.derive_from_configured=%s", node->name, priv_cfg->derive_from_config? "true" : "false"); ipmip_cli_config_printf(&request->message, "ipmip6mn.%s.mobile_prefix.renumber.save=%s", node->name, priv_cfg->save_config? "true" : "false"); } } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmip6mn_service_mpdisc_install(struct Ipmip6mn_context *ctx); IP_GLOBAL void ipmip6mn_service_mpdisc_install(struct Ipmip6mn_context *ctx) { static Ipmip6mn_extension_t srv; srv.name = IPMIP6MN_SERVICE_NAME_MPDISC; srv.node_data_size = 0; srv.node_config_size = sizeof(Ipmip6mn_service_mpdisc_config_t); srv.config = (Ipmip6mn_extension_config_t)ipmip6mn_service_mpdisc_config; srv.provide = (Ipmip6mn_extension_provide_t)ipmip6mn_service_mpdisc_provide; /* This is a PMIP only feature */ ipmip6mn_context_register_function_mpdisc(ctx, &srv); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */