/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6ha_main.c,v $ $Revision: 1.8 $ * $Source: /home/interpeak/CVSRoot/ipmip6ha/src/ipmip6ha_main.c,v $ * $Author: jhorteli $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6ha_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #include #include #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 "ipmip6ha.h" #include "ipmip6ha_h.h" #include "ipmip6ha_node.h" #include "ipmip6ha_nemo.h" #include "ipmip6ha_attr_h.h" #include "ipmip6ha_cli.h" #include "ipmip6ha_ifevent.h" #include "ipmip6ha_mh.h" #include "ipmip6ha_icmp.h" #include "ipmip6ha_if.h" #include "ipmip6ha_route.h" #include "ipmip6ha_pktbuf.h" #include "ipmip6ha_mag.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ IP_PUBLIC Ip_err ipmip6ha_exit(void); IP_PUBLIC Ip_err ipmip6ha_init(void); IP_PUBLIC Ip_err ipmip6ha_start(void); IP_PUBLIC const char *ipmip6ha_version(void); /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ static int ipmip6ha_instances = 0; /* Dispatch function callbacks */ static Ipmip6_pkt_context_dispatch_t ipmip6ha_dispatch_table = { (Ipmip6_pkt_dispatch_t)ipmip6ha_mh_dispatch, (Ipmip6_pkt_dispatch_t)ipmip6ha_icmp_dispatch }; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC unsigned ipmip6ha_relay_nai_obj_hash(Ipmip6ha_relay_key_t *obj) { return ipcom_hash_update(obj->nai, (int)obj->nai_len, 0); } IP_STATIC Ip_bool ipmip6ha_relay_nai_key_cmp(Ipmip6ha_relay_key_t *obj, Ipmip6ha_relay_key_t *key) { /**/ return ipmip_util_strnncmp(obj->nai, obj->nai_len, key->nai, key->nai_len); } IP_STATIC void ipmip6ha_relay_map_sysvar_nai_foreach(struct Ipmip_proc *proc, char *name, char *subkey, const char *value, Ipmip6ha_context_t *ctx) { Ipmip6ha_relay_key_t *nkey; Ip_size_t slen = ipcom_strlen(subkey); Ipmip6ha_if_t *ifp = ipmip6ha_if_findbyname(ctx, proc, value); if (ifp == IP_NULL) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Unable to allocate to MAP %s to %s -- no such interface", subkey, value)); return; } IPMIP_UNUSED_PARAMETER(name); nkey = ipcom_calloc(1, sizeof(*nkey) + slen + 1); if (!nkey) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "Unable to allocate NAI entry")); return; } nkey->nai = (char *)(nkey + 1); ipcom_strcpy(nkey->nai, subkey); nkey->nai_len = slen; nkey->ifp = ifp; /* Overload? */ ipcom_hash_add(ctx->relay_map, nkey); } IP_STATIC void ipmip6ha_configure_relay_map(Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc) { ipmip_sysvar_foreach(proc, (Ipmip_sysvar_foreach_t) ipmip6ha_relay_map_sysvar_nai_foreach, ctx, "ipmip6ha.relay_map.*"); } IP_STATIC void ipmip6ha_unconfigure_relay_map_cb(Ipmip6ha_relay_key_t *obj, Ipcom_hash *htable) { ipcom_hash_remove(htable, obj); ipcom_free(obj); } IP_STATIC void ipmip6ha_unconfigure_relay_map(Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc) { IPMIP_UNUSED_PARAMETER(proc); ipcom_hash_for_each(ctx->relay_map, (Ipcom_hash_foreach_cb_func)ipmip6ha_unconfigure_relay_map_cb, ctx->relay_map); } IP_STATIC void ipmip6ha_dump_relay_map_cb(Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc, Ipmip6ha_relay_key_t *obj, Ipmip_buffer_t *buffer, void *unused) { IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(unused); ipmip_cli_config_printf(buffer, "ipmip6ha.relay_map.%s=%s", obj->nai, obj->ifp->ipmip6.iff.ifname); } IP_STATIC void ipmip6ha_services_clear(Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc) { unsigned si; for (si = 0; si < ctx->extensions_num; si++) { if (ctx->extensions[si]->config_global != IP_NULL && ctx->extdata[si] != IP_NULL) { (*ctx->extensions[si]->config_global) (ctx, proc, IPMIP_CALLBACK_CONFIG_FREE, ctx->extdata[si], IP_NULL); ipcom_free(ctx->extdata[si]); ctx->extdata[si] = IP_NULL; } } } IP_STATIC void ipmip6ha_services_read(Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc) { unsigned si; for (si = 0; si < ctx->extensions_num; si++) { if (ctx->extensions[si]->config_global != IP_NULL && ctx->extensions[si]->global_data_size) { ctx->extdata[si] = ipcom_calloc(1, ctx->extensions[si]->global_data_size); (*ctx->extensions[si]->config_global) (ctx, proc, IPMIP_CALLBACK_CONFIG_READ, ctx->extdata[si], 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 ipmip6ha_update_config(Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc) { ipmip6_pkt_context_stop(&ctx->ipmip6, proc); /* Free all mobile nodes */ ipmip6ha_node_clear(ctx, proc); /* Stop the current context */ ipmip6_context_stop(&ctx->ipmip6, proc); /* Clear global service config */ ipmip6ha_services_clear(ctx, proc); #ifdef IPMIP_USE_INET ipmip_dhcp_context_destroy(&ctx->ipmip6.ipmip, proc); #endif ipmip6ha_unconfigure_relay_map(ctx, proc); /* Unconfigure IF */ ipmip6ha_if_unconfigure(ctx, proc); /* Restart Counter */ ipmip6_context_restart_counter_update(&ctx->ipmip6, proc); /* Clear global service config */ ipmip6ha_services_read(ctx, proc); if (ctx->prefixes != IP_NULL) ipcom_route_free_table(ctx->prefixes); ctx->prefixes = ipcom_route_new_table(sizeof(struct Ip_in6_addr) * 8, (Ipcom_route_notify_func) ipmip_route_notify); /* Re-read them */ ipmip6ha_if_configure(ctx, proc); /* Configure relay map */ ipmip6ha_configure_relay_map(ctx, proc); /**/ ipmip6_context_start(&ctx->ipmip6, proc); return 0; } /* *=========================================================================== * ipmip6mn_destroy *=========================================================================== * Description: Shutdown the mobile node portion of the context. * Parameters: ctx - The MIP6 context. * Returns: * */ IP_STATIC void ipmip6ha_context_destroy(Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc) { /* Only if we actually got a context. */ if (ctx != IP_NULL) { /* Stop the packet context; for starters */ ipmip6_pkt_context_stop(&ctx->ipmip6, proc); /* Destroy the entries that has been removed */ ipmip6ha_node_clear(ctx, proc); /* Stop the rest */ ipmip6_context_stop(&ctx->ipmip6, proc); /**/ ipmip6ha_unconfigure_relay_map(ctx, proc); ipmip6ha_if_unconfigure(ctx, proc); ipmip6ha_nemo_unconfigure(ctx, proc, ctx->nemo); ipmip6ha_services_clear(ctx, proc); /* Close the IPD */ if (ctx->fd_ipd == IP_INVALID_SOCKET) (void)ipcom_ipd_init("ipmip6ha", IPCOM_ERR_FAILED, &ctx->fd_ipd); ipcom_hash_delete(ctx->relay_map); /**/ ipcom_ipd_exit("ipmip6ha", ctx->fd_ipd); /**/ ipmip_timer_lock_destroy(&ctx->ipmip6.ipmip, proc, ctx->ifs_lock); /* Free the lock */ ipmip6ha_nemo_context_destroy(ctx, proc); ipcom_mutex_delete(&ctx->prefixes_lock); ipmip6ha_route_context_destroy(ctx, proc); /* Free the identity contexts */ ipmip_context_id_destroy(ctx->idents); ipmip_context_id_destroy(ctx->bri); /* Shutdown the 'mip6' context */ ipmip6_context_destroy(&ctx->ipmip6, proc); } } /* *=========================================================================== * ipmip6ha_context_allocate *=========================================================================== * Description: Initialize the mobile node portion of the context. * Parameters: ctx - The MIP6 context. * Returns: * */ IP_STATIC Ipmip6ha_context_t * ipmip6ha_context_allocate(Ipmip_proc_t *proc) { Ipmip6ha_context_t *ctx = (Ipmip6ha_context_t *)ipmip_context_alloc(proc, sizeof(*ctx), "ipmip6ha", IPMIP6_SYSTEM_PRIORITY, IPMIP6HA_EVENT_BACKLOG); int i; /* */ if (ctx == IP_NULL) return IP_NULL; /* For LAS */ ipmip_dhcp6_embedded_server_init(&ctx->ipmip6.ipmip, proc); ipmip6ha_route_context_init(ctx, proc); /* Initialize */ ipmip6ha_nemo_context_init(ctx, proc); ipcom_list_init(&ctx->ifs); ipcom_mutex_create(&ctx->prefixes_lock); ctx->ifs_lock = ipmip_timer_lock_alloc(&ctx->ipmip6.ipmip, proc, IP_NULL, IP_NULL); ctx->idents = ipmip_context_id_create(ip_offsetof(Ipmip6ha_node_t, identity), 0xFFFFFFFF); ctx->bri = ipmip_context_id_create(ip_offsetof(Ipmip6ha_br_t, sequence), 0x0000FFFF); /* Initialize the global information */ if (ipmip6_context_initialize(&ctx->ipmip6, proc, &ipmip6ha_ifevent_table) == IP_FALSE) goto failure; /* Server side; don't do solicitations */ ctx->ipmip6.iff.no_solicitation = IP_TRUE; /**/ ctx->relay_map = ipcom_hash_new((Ipcom_hash_obj_func) ipmip6ha_relay_nai_obj_hash, (Ipcom_hash_key_func) ipmip6ha_relay_nai_obj_hash, (Ipcom_hash_cmp_func) ipmip6ha_relay_nai_key_cmp); if (ipmip6_pkt_context_create(&ctx->ipmip6, proc, &ipmip6ha_dispatch_table, IPMIP6_DSMIP_UDP_PORT, (Ipmip_pkt_buf_alloc_t)ipmip6ha_pktbuf_alloc, (Ipmip_pkt_buf_free_t)ipmip6ha_pktbuf_free) == IP_FALSE) { IPCOM_LOG0(ERR, "Unable to create IPMIP6HA Packet Context"); goto failure; } ipmip_cli_context_create(&ctx->ipmip6.ipmip, proc, "ipmip6ha", IPCOM_IPD_ID_IPMIP6HA, (Ipmip_cli_callback_t)ipmip6ha_attr_command); /* IPD init */ if (ipcom_ipd_init("ipmip6ha", IPCOM_SUCCESS, &ctx->fd_ipd) != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "Unable to create IPMIP6MN IPD pipe = %d", ipcom_errno); goto failure; } (void) ipcom_inet_pton(IP_AF_INET6, "FE80::", &ctx->link_local_prefix); for (i = 0; ipmip6ha_service_registrations[i] != IP_NULL; i++) (*ipmip6ha_service_registrations[i]) (ctx); /* Update configuration */ ipmip6ha_update_config(ctx, proc); /* Return the mobile node instance */ return ctx; failure: ipmip6ha_context_destroy(ctx, 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 ipmip6ha_ipd_process(Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc) { /* IPD input. */ int event; Ip_ssize_t len; Ipmip6ha_pktbuf_t *pbuf = (Ipmip6ha_pktbuf_t *)ipmip_pktbuf_alloc(&ctx->ipmip6.ipmip, proc, 512); if (pbuf == IP_NULL) return IP_TRUE; len = ipcom_ipd_read(ctx->fd_ipd, IPMIP_BUFFER_PTR(&pbuf->ipmip6.ipmip.packet), 512, &event); if (len < 0) { IPCOM_LOG2(ERR, "ipcom_socketread(IPD) failed : %s [%d]", ipcom_strerror(ipcom_errno), ipcom_errno); ipmip_util_sock_clear(ctx->fd_ipd); } else { /* Advance past */ ipmip_buffer_append(&pbuf->ipmip6.ipmip.packet, IP_NULL, (Ip_size_t)len); switch (event) { case IPCOM_IPD_EVENT_RECONFIGURE: IPCOM_LOG0(INFO, "Received IPD reconfigure message"); ipmip6ha_update_config(ctx, proc); break; case IPCOM_IPD_EVENT_KILL: IPCOM_LOG0(INFO, "Received IPD kill message"); ipmip_pktbuf_release(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip); return IP_FALSE; default: /* Ignore all other IPD messages */ break; } } ipmip_pktbuf_release(&ctx->ipmip6.ipmip, proc, &pbuf->ipmip6.ipmip); return IP_TRUE; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ IP_GLOBAL void ipmip6ha_main(void) { int num; int max_fd; Ipmip6ha_context_t *ctx = IP_NULL; Ipmip_proc_t *proc; ipcom_proc_init(); proc = ipmip_proc_alloc(); IPCOM_LOG0(INFO, "ipmip6ha: starting"); /* Init the configuration */ if (ipmip6ha_configure() != IPCOM_SUCCESS) goto done; /* Init IPMIP6MN */ if ((ctx = ipmip6ha_context_allocate(proc)) == IP_NULL) goto done; if (ipmip6ha_instances++ == 0) if (ipmip6ha_init() != IPCOM_SUCCESS) goto end; for (;;) { Ip_fd_set read_set; IP_FD_ZERO(&read_set); /* Set the IPD */ max_fd = ctx->fd_ipd; IP_FD_SET(ctx->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. */ IPCOM_LOG2(WARNING, "ipcom_socketselect() failed : %s [%d]", ipcom_strerror(ipcom_errno), ipcom_errno); (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(ctx->fd_ipd, &read_set)) { if (ipmip6ha_ipd_process(ctx, proc) == IP_FALSE) goto end; } } } end: ipmip6ha_context_destroy(ctx, proc); /**/ if (--ipmip6ha_instances == 0) ipmip6ha_exit(); done: /* Free the context process */ ipmip_proc_destroy(proc); IPCOM_LOG0(NOTICE, "ipmip6ha: ending"); ipcom_proc_exit(); } IP_GLOBAL Ip_u32 ipmip6ha_context_register_extension(Ipmip6ha_context_t *ctx, Ipmip6ha_extension_t *srv, Ip_bool reg_H, Ip_bool reg_P) { srv->type = ctx->extensions_num++; ctx->extensions[srv->type] = srv; if (reg_H) { ctx->extensions_H_mask |= (1 << srv->type); ctx->extensions_node_H_data += srv->node_data_size; } if (reg_P) { ctx->extensions_P_mask |= (1 << srv->type); ctx->extensions_node_P_data += srv->node_data_size; } return srv->type; } IP_GLOBAL void ipmip6ha_dump_relay_map(Ipmip6ha_context_t *ctx, Ipmip_proc_t *proc, Ipmip_buffer_t *buffer) { ipmip_util_hash_foreach(&ctx->ipmip6.ipmip, proc, ctx->relay_map, (Ipmip_util_hash_foreach_t)ipmip6ha_dump_relay_map_cb, buffer, IP_NULL); } /* **************************************************************************** * END OF FILE **************************************************************************** */