/* ******************************************************************************* * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmipha_main.c,v $ $Revision: 1.9.16.1 $ * $Source: /home/interpeak/CVSRoot/ipmipha/src/ipmipha_main.c,v $ * $Author: jsheng $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Niklas Lundberg ****************************************************************************** */ /* ******************************************************************************* * 1 DESCRIPTION ******************************************************************************* * * Legend: * HA = Home agent * MN = Mobile node * FA = Foreign agent * CN = Correspondent node (someone on the internet the mobile node talks to * via the HA) * COA = Care-of address * */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmipha_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 "ipmipha.h" #include "ipmipha_h.h" #include "ipmipha_attr_h.h" #include "ipmipha_if.h" #include "ipmipha_node.h" #include "ipmipha_reg.h" #include "ipmipha_agent.h" #include "ipmipha_route.h" #include "ipmipha_pktbuf.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* *=========================================================================== * Private Application datatypes *=========================================================================== */ /* *=========================================================================== * Registration request and reply *=========================================================================== */ /* *=========================================================================== * Ipmipha_rtmsg *=========================================================================== */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ IP_PUBLIC Ip_err ipmipha_create(void); IP_PUBLIC Ip_err ipmipha_start(void); IP_PUBLIC Ip_err ipmipha_init(void); IP_PUBLIC Ip_err ipmipha_exit(void); IP_PUBLIC Ip_err ipmipha_configure(void); IP_PUBLIC const char *ipmipha_version(void); #ifdef IPSNMP IP_EXTERN Ip_err ipmipha_mip_mib_init(void); IP_EXTERN Ip_err ipmip4_mip_mib_init(void); #endif /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_PUBLIC IPCOM_PROCESS(ipmipha_proc); /* **************************************************************************** * 8 DATA **************************************************************************** */ /* *=========================================================================== * Global IPMIPHA data *=========================================================================== * All global IPMIPHA data is located in this structure. */ static int ipmipha_instances = 0; static Ipcom_once_t ipmipha_extensions_once = IPCOM_ONCE_INIT; static Ipmipha_function_context_t ipmipha_extensions[IPMIPHA_FUNCTION_MAX]; static Ip_u32 ipmipha_extensions_node_data = 0; static Ipcom_list ipmipha_msgext_vendor_extensions; static Ipmip_pktbuf_pktaux_t ipmipha_pktaux; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC Ip_err ipmipha_main_once_init(void *unused) { int f; IPMIP_UNUSED_PARAMETER(unused); /* Clear */ ipcom_memset(&ipmipha_extensions[0], 0, sizeof(ipmipha_extensions)); ipcom_memset(&ipmipha_pktaux, 0, sizeof(ipmipha_pktaux)); ipcom_list_init(&ipmipha_msgext_vendor_extensions); /* Do service init */ for (f = 0; ipmipha_function_registrations[f] != IP_NULL; f++) (*ipmipha_function_registrations[f]) (); return IPCOM_SUCCESS; } /* *=========================================================================== * ipmipha_config_free *=========================================================================== * Description: Clear out a configuration structure, free any resources * associated with it. * Parameters: data - The HA entity it belongs to * proc - The process * conf - The configuration structure. * Returns: */ IP_STATIC void ipmipha_config_free(Ipmipha_data_t *data, Ipmip_proc_t *proc, Ipmipha_conf_t *conf) { ipmipha_if_stop(data, proc, conf); /**/ ipcom_free(conf); } /* *=========================================================================== * ipmipha_config_exit *=========================================================================== * Description: Clears the indicated configuration * Parameters: instance - The Home Agent instance we're currently working on. * conf - The configuration * Returns: */ IP_STATIC void ipmipha_config_exit(Ipmipha_data_t *data, Ipmip_proc_t *proc) { Ipmipha_iff_t *iff; if (data->conf == IP_NULL) return; /* Disallow any new regs */ ipmip4_pkt_context_stop(&data->ipmip4, proc); data->shutdown = IPMIPHA_SHUTDOWN_ALL; ipmip4_pkt_context_start(&data->ipmip4, proc); /* Free all mobile nodes */ ipmipha_node_clear(data, proc); /* Stop the current context */ 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->adv_lifetime = 0; iff->lifetime = 0; ipmipha_agent_advert_output(data, proc, iff, IP_NULL, IP_NULL); } } /* Free the configuration */ ipmipha_config_free(data, proc, data->conf); data->conf = IP_NULL; } /* *=========================================================================== * ipmipha_config_read *=========================================================================== * Description: Read IPMIPHA config. * used in ipmipha_config_init * Parameters: . * Returns: . * */ IP_STATIC Ipmipha_conf_t * ipmipha_config_read(Ipmipha_data_t *data, Ipmip_proc_t *proc) { Ipmipha_conf_t *conf; char **arr = IP_NULL; conf = ipcom_calloc(1, sizeof(Ipmipha_conf_t)); if (conf == IP_NULL) return IP_NULL; ipcom_list_init(&conf->if_head); /* Find all interfaces */ arr = ipmip_sysvar_strarr("ipmipha.interfaces"); if (arr == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Bad configuration. Invalid/missing \"ipmipha.interfaces\"")); goto fail; } else { int i; for (i = 0; arr[i] != IP_NULL; i++) { /* If I can't create the interface, exit */ if (ipmipha_if_create(data, proc, conf, arr[i]) == IP_FALSE) goto fail; } } /* Free the interface name buffer */ ipcom_free(arr); return conf; /* success */ fail: if (arr) ipcom_free(arr); ipmipha_config_free(data, proc, conf); return IP_NULL; } /* *=========================================================================== * ipmipha_config_init *=========================================================================== * Description: Initialize the configuration for the specified instance * Parameters: instance - The HA instance * Returns: 0 on success * */ IP_STATIC int ipmipha_config_init(Ipmipha_data_t *data, Ipmip_proc_t *proc) { Ipmipha_conf_t *conf; #ifndef IP_PORT_LAS int name[4]; Ip_size_t oldlenp; #endif /* No new nodes*/ IP_BIT_SET(data->shutdown, IPMIPHA_SHUTDOWN_NODE); if (data->conf) ipmipha_config_exit(data, proc); /* Read configuration */ conf = ipmipha_config_read(data, proc); if (conf == IP_NULL) { IPMIP4_EVENT_IF(ERR, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "Configuration Failed - Invalid Configuration")); IP_BIT_CLR(data->shutdown, IPMIPHA_SHUTDOWN_NODE); 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 /* Reconfigure (existing config was in place) */ data->conf = conf; data->shutdown = 0; ipmip4_context_start(&data->ipmip4, proc); ipmipha_if_start(data, proc); return 0; } /* *=========================================================================== * ipmipha_exit_agent *=========================================================================== * Description: Free the HA instance * Parameters: instance - The HA instance to free. * Returns: * */ IP_STATIC void ipmipha_exit_agent(Ipmipha_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, "IPMIPHA ending")); /* Stop the context */ ipmip4_context_stop(&data->ipmip4, proc); /* Destroy route context */ ipmipha_route_context_destroy(data, proc); /* Exit the IPD */ if (data->fd_ipd == IP_INVALID_SOCKET) (void)ipcom_ipd_init("ipmipha", IPCOM_ERR_FAILED, &data->fd_ipd); (void)ipcom_ipd_exit("ipmipha", data->fd_ipd); /* */ ipcom_mutex_delete(&data->mibLock); ipmip_context_id_destroy(data->idents); /* Free the context */ ipmip4_context_destroy(&data->ipmip4, proc); } /* *=========================================================================== * ipmipha_init_agent *=========================================================================== * Description: Initialize an agent instance * Parameters: * Returns: The pointer to the agent instance if successful * */ IP_STATIC Ipmipha_data_t * ipmipha_init_agent(Ipmip_proc_t *proc) { Ipmipha_data_t *data; (void)IPMIP_ONCE(&ipmipha_extensions_once, ipmipha_main_once_init, IP_NULL); data = (Ipmipha_data_t *)ipmip_context_alloc(proc, sizeof(*data), "ipmipha", IPMIP4_SYSTEM_PRIORITY, IPMIPHA_EVENT_BACKLOG); if (data == IP_NULL) return IP_NULL; /* Setup the extension structure */ data->extensions = &ipmipha_extensions[0]; data->extensions_node_data = &ipmipha_extensions_node_data; data->ipmip4.vendor_extensions = &ipmipha_msgext_vendor_extensions; data->ipmip4.ipmip.pktaux = &ipmipha_pktaux; ipmip4_context_init(&data->ipmip4, proc); data->fd_ipd = IP_INVALID_SOCKET; IPMIP4_EVENT_IF(INFO, proc, ipmip_log_event_add(&data->ipmip4.ipmip, proc, "IPMIPHA starting [VR %d]", data->ipmip4.ipmip.vr)); (void)ipcom_mutex_create(&data->mibLock); /* IPD init. */ if (ipcom_ipd_init("ipmipha", IPCOM_SUCCESS, &data->fd_ipd) != IPCOM_SUCCESS) goto fail; data->idents = ipmip_context_id_create(ip_offsetof(Ipmipha_node_t, haNodeIdentity), 0xFFFFFFFF); ipmip_cli_context_create(&data->ipmip4.ipmip, proc, "ipmipha", IPCOM_IPD_ID_IPMIPHA, (Ipmip_cli_callback_t)ipmipha_attr_command); /* Create the packet buffer context */ ipmip_pktbuf_context_create(&data->ipmip4.ipmip, proc, (Ipmip_pkt_buf_alloc_t)ipmipha_pktbuf_alloc, (Ipmip_pkt_buf_free_t)ipmipha_pktbuf_free); if (!ipmip4_pkt_context_create(&data->ipmip4, proc, IPMIP4_PKT_UDP_IN_434|IPMIP4_PKT_PKT_OUT|IPMIP4_PKT_ICMP_IN, (Ipmip4_pkt_udp_cb_t)ipmipha_reg_recv, (Ipmip4_pkt_icmp_cb_t)ipmipha_adv_recv, IP_NULL)) goto fail; ipmipha_route_context_alloc(data, proc); return data; fail: ipmipha_exit_agent(data, proc); return IP_NULL; } /* *=========================================================================== * ipmipha_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 ipmipha_ipd_process(Ipmipha_data_t *data, Ipmip_proc_t *proc) { /* IPD input. */ int event; Ip_ssize_t len; Ipmipha_pktbuf_t *pbuf = (Ipmipha_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 (ipmipha_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; } /* To remove the warning */ IP_PUBLIC IPCOM_PROCESS(ipmipha_proc); /* *=========================================================================== * ipmiphad *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL void ipmipha_main(void) { char icmp_redirect[8]; Ip_size_t size = sizeof(icmp_redirect); Ipmipha_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) goto end; /**/ ipmipha_configure(); /* First instance? */ if (ipmipha_instances++ == 0) ipmipha_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; /* Init IPMIPHA */ if ((data = ipmipha_init_agent(proc)) == IP_NULL) goto end; /* Init HA from configuration */ if (ipmipha_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 (ipmipha_ipd_process(data, proc) == IP_FALSE) goto end; } } } end: /* If we've gotten the data, clear it */ if (data != IP_NULL) { ipmipha_config_exit(data, proc); ipmipha_exit_agent(data, proc); } (void)ipcom_sysvar_set("ipnet.inet.IcmpRedirectSend", icmp_redirect, IPCOM_SYSVAR_FLAG_OVERWRITE); /* Last instance? */ if (--ipmipha_instances == 0) ipmipha_exit(); /* Free the context process */ ipmip_proc_destroy(proc); ipcom_proc_exit(); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* INIT FUNCTIONS */ IP_GLOBAL Ip_u32 ipmipha_context_register_extension(Ipmipha_extension_t *srv, int function) { Ipmipha_function_context_t *func = &ipmipha_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); ipmipha_extensions_node_data+= srv->node_data_size; ipmipha_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(&ipmipha_pktaux, &srv->pktaux); return srv->unique; } IP_GLOBAL void ipmipha_msgext_vendor_parse_ext_register(struct Ipmip4_msgext_vendor_parse_ext *pext) { /**/ ipmip4_msgext_vendor_parse_ext_register(&ipmipha_msgext_vendor_extensions, &ipmipha_pktaux, pext); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */