/* ******************************************************************************* * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmipfa_main.c,v $ $Revision: 1.8.16.1 $ * $Source: /home/interpeak/CVSRoot/ipmipfa/src/ipmipfa_main.c,v $ * $Author: jsheng $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Niklas Lundberg ****************************************************************************** */ /* ******************************************************************************* * 1 DESCRIPTION ******************************************************************************* * */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmipfa_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 "ipmipfa.h" #include "ipmipfa_h.h" #include "ipmipfa_reg.h" #include "ipmipfa_node.h" #include "ipmipfa_agent.h" #include "ipmipfa_attr_h.h" #include "ipmipfa_route.h" #include "ipmipfa_pktbuf.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* *=========================================================================== * Application datatypes *=========================================================================== */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ IP_PUBLIC Ip_err ipmipfa_configure(void); IP_PUBLIC Ip_err ipmipfa_init(void); IP_PUBLIC Ip_err ipmipfa_exit(void); #ifdef IPSNMP IP_EXTERN Ip_err ipmipfa_mip_mib_init(void); IP_EXTERN Ip_err ipmip4_mip_mib_init(void); #endif /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_PUBLIC Ip_err ipmipfa_start(void); IP_PUBLIC const char *ipmipfa_version(void); /* **************************************************************************** * 8 DATA **************************************************************************** */ static int ipmipfa_instances = 0; static Ipcom_once_t ipmipfa_extensions_once = IPCOM_ONCE_INIT; static Ipmipfa_function_context_t ipmipfa_extensions[IPMIPFA_FUNCTION_MAX]; static Ip_u32 ipmipfa_extensions_node_data = 0; static Ipcom_list ipmipfa_msgext_vendor_extensions; static Ipmip_pktbuf_pktaux_t ipmipfa_pktaux; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC Ip_err ipmipfa_main_once_init(void *unused) { int f; IPMIP_UNUSED_PARAMETER(unused); /* Clear */ ipcom_memset(&ipmipfa_extensions[0], 0, sizeof(ipmipfa_extensions)); ipcom_memset(&ipmipfa_pktaux, 0, sizeof(ipmipfa_pktaux)); ipcom_list_init(&ipmipfa_msgext_vendor_extensions); /* Do service init */ for (f = 0; ipmipfa_function_registrations[f] != IP_NULL; f++) (*ipmipfa_function_registrations[f]) (); return IPCOM_SUCCESS; } /* *=========================================================================== * ipmipfa_exit_agent *=========================================================================== * Description: Cleanup the resources allocated by this FA entity. * Parameters: data - The FA entity structure. * proc - Current process * Returns: * */ IP_STATIC void ipmipfa_exit_agent(Ipmipfa_data_t *data, Ipmip_proc_t *proc) { /* Sanity */ if (data == IP_NULL) return; IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "IPMIPFA ending")); /* Stop the context */ ipmip4_context_stop(&data->ipmip4, proc); /* Destroy route context */ ipmipfa_route_context_destroy(data, proc); /**/ ipmip_timer_lock_destroy(&data->ipmip4.ipmip, proc, data->llh_lock); /* Exit the IPD */ if (data->fd_ipd == IP_INVALID_SOCKET) (void)ipcom_ipd_init("ipmipfa", IPCOM_ERR_FAILED, &data->fd_ipd); (void)ipcom_ipd_exit("ipmipfa", data->fd_ipd); /**/ ipcom_mutex_delete(&data->mibLock); /**/ ipmip_context_id_destroy(data->idents); /* Free the context */ ipmip4_context_destroy(&data->ipmip4, proc); } /* *=========================================================================== * ipmipfa_init_agent *=========================================================================== * Description: Allocate and initialize a FA entity structure. * Parameters: proc - Current process * Returns: The new FA entity structure if successful. * */ IP_STATIC Ipmipfa_data_t * ipmipfa_init_agent(Ipmip_proc_t *proc) { Ipmipfa_data_t *data; (void)IPMIP_ONCE(&ipmipfa_extensions_once, ipmipfa_main_once_init, IP_NULL); data = (Ipmipfa_data_t *) ipmip_context_alloc(proc, sizeof(*data), "ipmipfa", IPMIP4_SYSTEM_PRIORITY, IPMIPFA_EVENT_BACKLOG); if (data == IP_NULL) return IP_NULL; /* Setup the extension structure */ data->extensions = &ipmipfa_extensions[0]; data->extensions_node_data = &ipmipfa_extensions_node_data; data->ipmip4.vendor_extensions = &ipmipfa_msgext_vendor_extensions; data->ipmip4.ipmip.pktaux = &ipmipfa_pktaux; ipmip4_context_init(&data->ipmip4, proc); /* Initialize file descriptors */ data->fd_ipd = IP_INVALID_SOCKET; IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "IPMIPFA starting [VR %d]", data->ipmip4.ipmip.vr)); data->llh_lock = ipmip_timer_lock_alloc(&data->ipmip4.ipmip, proc, IP_NULL, IP_NULL); if(IP_NULL == data->llh_lock) goto fail; (void)ipcom_mutex_create(&data->mibLock); /* IPD init. */ if (ipcom_ipd_init("ipmipfa", IPCOM_SUCCESS, &data->fd_ipd) != IPCOM_SUCCESS) goto fail; data->idents = ipmip_context_id_create(ip_offsetof(Ipmipfa_node_t, faVisitorIdentity), 0xFFFFFFFF); /* Initialize the parse structure */ ipmip_cli_context_create(&data->ipmip4.ipmip, proc, "ipmipfa", IPCOM_IPD_ID_IPMIPFA, (Ipmip_cli_callback_t)ipmipfa_attr_command); /* Create the packet buffer context */ ipmip_pktbuf_context_create(&data->ipmip4.ipmip, proc, (Ipmip_pkt_buf_alloc_t)ipmipfa_pktbuf_alloc, (Ipmip_pkt_buf_free_t)ipmipfa_pktbuf_free); ipmip4_pkt_context_create(&data->ipmip4, proc, IPMIP4_PKT_UDP_IN_434|IPMIP4_PKT_UDP_IN_OUT|IPMIP4_PKT_PKT_OUT|IPMIP4_PKT_ICMP_IN, (Ipmip4_pkt_udp_cb_t)ipmipfa_reg_recv, (Ipmip4_pkt_icmp_cb_t)ipmipfa_adv_recv, IP_NULL); ipmipfa_route_context_alloc(data, proc); return data; fail: ipmipfa_exit_agent(data, proc); return IP_NULL; } IP_STATIC void ipmipfa_services_clear(Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_conf_t *conf) { unsigned si, f; for (f = 0; f < IPMIPFA_FUNCTION_MAX; f++) { for (si = 0; si < ctx->extensions[f].num; si++) { if (ctx->extensions[f].functions[si]->config_global != IP_NULL && conf->extdata[f][si]) { (*ctx->extensions[f].functions[si]->config_global) (ctx, proc, IPMIP_CALLBACK_CONFIG_FREE, conf->extdata[f][si], IP_NULL); ipcom_free(conf->extdata[f][si]); } } } } IP_STATIC void ipmipfa_services_read(Ipmipfa_data_t *ctx, Ipmip_proc_t *proc, Ipmipfa_conf_t *conf) { unsigned si, f; for (f = 0; f < IPMIPFA_FUNCTION_MAX; f++) { for (si = 0; si < ctx->extensions[f].num; si++) { if (ctx->extensions[f].functions[si]->config_global != IP_NULL && ctx->extensions[f].functions[si]->global_data_size) { conf->extdata[f][si] = ipcom_calloc(1, ctx->extensions[f].functions[si]->global_data_size);; (*ctx->extensions[f].functions[si]->config_global) (ctx, proc, IPMIP_CALLBACK_CONFIG_READ, conf->extdata[f][si], IP_NULL); } } } } /* *=========================================================================== * ipmipfa_config_exit *=========================================================================== * Description: Clear out a configuration structure, free any resources * associated with it. * Parameters: data - The FA entity it belongs to * proc - The process * conf - The configuration structure. * Returns: */ IP_STATIC void ipmipfa_config_free(Ipmipfa_data_t *data, Ipmip_proc_t *proc, Ipmipfa_conf_t *conf) { /* free interface list */ ipmipfa_if_stop(data, proc, conf); ipmipfa_services_clear(data, proc, conf); ipcom_free(conf); } /* *=========================================================================== * ipmipfa_config_exit *=========================================================================== * Description: Clear out a configuration structure, free any resources * associated with it. * Parameters: data - The FA entity it belongs to * proc - The process * conf - The configuration structure. * Returns: */ IP_STATIC void ipmipfa_config_exit(Ipmipfa_data_t *data, Ipmip_proc_t *proc) { Ipmipfa_iff_t *iff; if (data->conf == IP_NULL) return; /* Stop the current context */ ipmip4_pkt_context_stop(&data->ipmip4, proc); data->shutdown = IPMIPFA_SHUTDOWN_ALL; ipmip4_pkt_context_start(&data->ipmip4, proc); /* Free all mobile nodes */ ipmipfa_node_clear(data, proc); /**/ ipmip4_context_stop(&data->ipmip4, proc); /* free interface list */ for (iff = IPCOM_LIST_FIRST(&data->conf->if_head); iff != IP_NULL; iff = IPCOM_LIST_NEXT(&iff->iff.ipmip.next)) { if (iff->adv_interval > 0 && iff->iff.ifaddr != 0) { /* Reduce lifetime to 0 */ iff->lifetime = 0; iff->adv_lifetime = 0; ipmipfa_agent_advert_output(data, proc, iff, IP_NULL, IP_NULL, IP_NULL, IP_FALSE); } } /* Free the configuration */ ipmipfa_config_free(data, proc, data->conf); ipmip_dhcp_context_destroy(&data->ipmip4.ipmip, proc); data->conf = IP_NULL; } /* *=========================================================================== * ipmipfa_config_read *=========================================================================== * Description: Read IPMIPFA config. * used in ipmipfa_config_init * Parameters: data - The FA entity. * proc - Process * Returns: The new configuration entity. * */ IP_STATIC Ipmipfa_conf_t * ipmipfa_config_read(Ipmipfa_data_t *data, Ipmip_proc_t *proc) { Ipmipfa_conf_t *conf; char **arr = IP_NULL; conf = ipcom_calloc(1, sizeof(Ipmipfa_conf_t)); if (conf == IP_NULL) return IP_NULL; /* Init */ ipcom_list_init(&conf->if_head); ipmipfa_services_read(data, proc, conf); /* Find all interfaces */ arr = ipmip_sysvar_strarr("ipmipfa.interfaces"); if (arr == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Bad configuration. Invalid/missing \"ipmipfa.interfaces\"")); goto fail; } else { int i; for (i = 0; arr[i] != IP_NULL; i++) { /* If I can't create the interface, exit */ if (ipmipfa_if_create(data, proc, conf, arr[i]) == IP_FALSE) goto fail; } } /* */ ipcom_free(arr); return conf; /* success */ fail: if (arr != IP_NULL) ipcom_free(arr); ipmipfa_config_free(data, proc, conf); return IP_NULL; } /* *=========================================================================== * ipmipfa_config_init *=========================================================================== * Description: Setup MIP ha after config has been read. * Parameters: data - The FA data entity. * proc - The process * Returns: -1 on error; 0 otherwise. * */ IP_STATIC int ipmipfa_config_init(Ipmipfa_data_t *data, Ipmip_proc_t *proc) { Ipmipfa_conf_t *conf; #ifndef IP_PORT_LAS int name[4]; Ip_size_t oldlenp; #endif Ipmipfa_iff_t *iff; /* Reconfigure (existing config was in place) */ if (data->conf) ipmipfa_config_exit(data, proc); /* Read configuration. */ conf = ipmipfa_config_read(data, proc); if (conf == IP_NULL) { ipmip_context_start(&data->ipmip4.ipmip, proc); return -1; } #ifndef IP_PORT_LAS /* Check if we are a router */ name[0] = IP_CTL_NET; name[1] = IP_AF_INET; name[2] = IP_IPPROTO_IP; name[3] = IP_IPCTL_FORWARDING; oldlenp = sizeof(data->ipnet_is_router); if (ipcom_sysctl(name, 4, &data->ipnet_is_router, &oldlenp, IP_NULL, IP_NULL) < 0) data->ipnet_is_router = 0; #endif data->conf = conf; data->shutdown = 0; ipmip4_context_start(&data->ipmip4, proc); ipmipfa_if_start(data, proc); /* Send instant RtAdv on all active interfaces */ for (iff = IPCOM_LIST_FIRST(&data->conf->if_head); iff; iff = IPCOM_LIST_NEXT(&iff->iff.ipmip.next)) { /* Should I send a multicast PrRtAdv? */ if (iff->adv_interval > 0) ipmipfa_agent_advert_output(data, proc, iff, IP_NULL, IP_NULL, IP_NULL, IP_FALSE); } return 0; } /* *=========================================================================== * ipmipfa_data_process *=========================================================================== * Description: Process any file descriptors set by the platform. * Parameters: data - The data structure * rset - The read set. * Returns: IP_FALSE if we should exit the process. * */ IP_STATIC Ip_bool ipmipfa_ipd_process(Ipmipfa_data_t *data, Ipmip_proc_t *proc) { /* IPD input. */ int event; Ip_ssize_t len; Ipmipfa_pktbuf_t *pbuf = (Ipmipfa_pktbuf_t *)ipmip_pktbuf_alloc(&data->ipmip4.ipmip, proc, 512); if (pbuf == IP_NULL) return IP_TRUE; len = ipcom_ipd_read(data->fd_ipd, IPMIP_BUFFER_PTR(&pbuf->ipmip4.ipmip.packet), 512, &event); if (len < 0) ipmip_util_sock_clear(data->fd_ipd); else { /* Advance past */ ipmip_buffer_append(&pbuf->ipmip4.ipmip.packet, IP_NULL, len); switch (event) { case IPCOM_IPD_EVENT_RECONFIGURE: IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Received IPD reconfigure message")); if (ipmipfa_config_init(data, proc) != 0) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Invalid new configuration - reconfigure failed and process suspended. Please correct configuration")); } break; case IPCOM_IPD_EVENT_KILL: IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Received IPD kill message")); ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); return IP_FALSE; default: /* Ignore all other IPD messages */ break; } } ipmip_pktbuf_release(&data->ipmip4.ipmip, proc, &pbuf->ipmip4.ipmip); return IP_TRUE; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmipfad *=========================================================================== * Description: The main process. * Parameters: * Returns: * */ IP_GLOBAL void ipmipfa_main(void) { char icmp_redirect[8]; Ip_size_t size = sizeof(icmp_redirect); Ipmipfa_data_t *data = IP_NULL; Ipmip_proc_t *proc; ipcom_proc_init(); /* Get me a process context for this thread */ proc = ipmip_proc_alloc(); if(IP_NULL == proc) return; /* Init IPMIPFA */ if (ipmipfa_instances++ == 0) (void)ipmipfa_init(); ipcom_sysvar_get("ipnet.inet.IcmpRedirectSend", icmp_redirect, &size); if (ipcom_sysvar_set("ipnet.inet.IcmpRedirectSend", "0", IPCOM_SYSVAR_FLAG_OVERWRITE) != IPCOM_SUCCESS) goto end; /* Configure IPMIPFA. */ if (ipmipfa_configure() != IPCOM_SUCCESS) goto end; /* Init IPMIPFA data. */ if ((data = ipmipfa_init_agent(proc)) == IP_NULL) goto end; /* Init FA from configuration. */ if (ipmipfa_config_init(data, proc) != 0) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Invalid configuration - configure failed and process suspended. Please correct configuration")); } for (;;) { int num; int max_fd; Ip_fd_set read_set; IP_FD_ZERO(&read_set); /* Set the IPD */ max_fd = data->fd_ipd; IP_FD_SET(data->fd_ipd, &read_set); /* Select */ num = ipcom_socketselect(max_fd + 1, &read_set, IP_NULL, IP_NULL, IP_NULL); switch(num) { case -1: /* socket error. */ (void)ipcom_sleep(1); break; case 0: /* timeout, not used. triggered by bug in linux glibc if compiled with nptl */ (void)ipcom_millisleep(1); break; default: /* Process IPD */ if (IP_FD_ISSET(data->fd_ipd, &read_set)) { if (ipmipfa_ipd_process(data, proc) == IP_FALSE) goto end; } } } end: /* If we've gotten the data, clear it */ if (data != IP_NULL) { ipmipfa_config_exit(data, proc); ipmipfa_exit_agent(data, proc); } (void)ipcom_sysvar_set("ipnet.inet.IcmpRedirectSend", icmp_redirect, IPCOM_SYSVAR_FLAG_OVERWRITE); /* Exit IPMIPFA */ if (--ipmipfa_instances == 0) (void)ipmipfa_exit(); /* Free the context process */ ipmip_proc_destroy(proc); ipcom_proc_exit(); } /* INIT FUNCTIONS */ IP_GLOBAL Ip_u32 ipmipfa_context_register_extension(Ipmipfa_extension_t *srv, int function) { Ipmipfa_function_context_t *func = &ipmipfa_extensions[function]; Ip_u32 type = func->num++; /* Store values */ srv->type = type; srv->func = function; /* Create the unique identifier */ srv->unique = type; srv->unique |= function << 16; func->mask |= (1 << type); ipmipfa_extensions_node_data += srv->node_data_size; ipmipfa_extensions_node_data += sizeof(void *); func->functions[type] = srv; func->node_data += srv->node_data_size; /* Register payload, if requested */ if (srv->pktaux.pktbuf_data_size != 0) ipmip_pktbuf_pktaux_add(&ipmipfa_pktaux, &srv->pktaux); return srv->unique; } IP_GLOBAL void ipmipfa_msgext_vendor_parse_ext_register(struct Ipmip4_msgext_vendor_parse_ext *pext) { /**/ ipmip4_msgext_vendor_parse_ext_register(&ipmipfa_msgext_vendor_extensions, &ipmipfa_pktaux, pext); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */