Files
2026-07-30 11:19:44 +05:30

751 lines
23 KiB
C

/*
*******************************************************************************
* 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 <n@interpeak.se>
******************************************************************************
*/
/*
*******************************************************************************
* 1 DESCRIPTION
*******************************************************************************
*
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipmipfa_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_drv_eth_filter.h>
#include <ipcom_err.h>
#include <ipcom_hash.h>
#include <ipcom_inet.h>
#include <ipcom_ipd.h>
#include <ipcom_list.h>
#include <ipcom_os.h>
#include <ipcom_sock.h>
#include <ipcom_sock2.h>
#include <ipcom_sysctl.h>
#include <ipcom_syslog.h>
#include <ipcom_netif.h>
#include <ipcom_sysvar.h>
#include <ipmip.h>
#include <private/ipmip_cli.h>
#include <private/ipmip_sysvar.h>
#include <private/ipmip_dhcp.h>
#include <ipmip4.h>
#include <private/ipmip4_sysext.h>
#include <private/ipmip4_util.h>
#include <private/ipmip4_pkt.h>
#include <private/ipmip4_radius.h>
#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
****************************************************************************
*/