903 lines
24 KiB
C
903 lines
24 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmcp.c,v $ $Revision: 1.30.10.4 $
|
|
* $Source: /home/interpeak/CVSRoot/ipmcp/src/ipmcp.c,v $
|
|
* $Author: jren $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Kenneth Jonsson <kenneth@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipmcp_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_ipd.h>
|
|
#include <ipcom_os.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_syslog.h>
|
|
#include <ipcom_sysvar.h>
|
|
#include <ipcom_type.h>
|
|
|
|
#include <ipnet_routesock.h>
|
|
|
|
#include "ipmcp.h"
|
|
#include "ipmcp_h.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
IPCOM_PROCESS(ipmcp_daemon);
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
Ipmcp_data_t ipmcp;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_if_destroy
|
|
*===========================================================================
|
|
* Description: Frees all resources held by the interface structure.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmcp_if_destroy(Ipmcp_netif_t *netif)
|
|
{
|
|
if (netif == IP_NULL)
|
|
return;
|
|
|
|
#ifdef IPMCP_USE_IGMP
|
|
ipmcp_igmp_if_destroy(netif);
|
|
#endif
|
|
#ifdef IPMCP_USE_MLD
|
|
ipmcp_mld_if_destroy(netif);
|
|
#endif
|
|
|
|
ipcom_list_remove(&netif->list);
|
|
ipcom_free(netif);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_if_create
|
|
*===========================================================================
|
|
* Description: Create interface descriptors for IPMCP
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmcp_if_create(Ip_u32 ifindex)
|
|
{
|
|
Ipmcp_netif_t *netif;
|
|
int ret;
|
|
char ifname[IP_IFNAMSIZ];
|
|
char *downstream_if;
|
|
char *p = IP_NULL;
|
|
char *sep = ", ";
|
|
char *ds;
|
|
|
|
netif = ipmcp_if_find(ifindex);
|
|
if (netif)
|
|
/* Duplicate */
|
|
return -1;
|
|
|
|
if (ipcom_if_indextoname(ifindex, ifname) == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipmcp_if_create: could not get the name of the interface with index %d", ifindex);
|
|
return -1;
|
|
}
|
|
|
|
ds = ipcom_strdup(ipmcp.config.downstream_ifs);
|
|
if (ds == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipmcp_if_create: failed to duplicate string", ifindex);
|
|
return -1;
|
|
}
|
|
|
|
for (downstream_if = ipcom_strtok_r(ds, sep, &p);
|
|
downstream_if != IP_NULL;
|
|
downstream_if = ipcom_strtok_r(IP_NULL, sep, &p))
|
|
{
|
|
if (ipcom_strcmp(ifname, downstream_if) == 0)
|
|
break;
|
|
}
|
|
ipcom_free(ds);
|
|
|
|
if (downstream_if == IP_NULL)
|
|
{
|
|
IPCOM_LOG1(DEBUG, "ipmcp_if_create: interface %s is not a downstream interface, ignoring",
|
|
ifname);
|
|
return 0;
|
|
}
|
|
|
|
netif = ipcom_calloc(1, sizeof(Ipmcp_netif_t));
|
|
if (netif == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipmcp_if_create: failed to allocate memory");
|
|
return -1;
|
|
}
|
|
|
|
netif->ifindex = ifindex;
|
|
ipcom_strcpy(netif->ifname, ifname);
|
|
ipcom_list_insert_last(&ipmcp.downstream_ifs_head, &netif->list);
|
|
|
|
#ifdef IPMCP_USE_IGMP
|
|
ret = ipmcp_igmp_if_create(netif);
|
|
if (ret < 0)
|
|
goto cleanup;
|
|
#endif
|
|
#ifdef IPMCP_USE_MLD
|
|
ret = ipmcp_mld_if_create(netif);
|
|
if (ret < 0)
|
|
goto cleanup;
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
cleanup:
|
|
ipmcp_if_destroy(netif);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_add_downstream_ifs
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmcp_add_downstream_ifs(void)
|
|
{
|
|
struct Ip_if_nameindex *ifrs, *i;
|
|
struct Ip_ifreq ifreq;
|
|
int ret = -1;
|
|
|
|
ifrs = ipcom_if_nameindex();
|
|
|
|
for (i = ifrs; i && (i->if_name != IP_NULL); i++)
|
|
{
|
|
/* coverity[fixed_size_dest] : FALSE */
|
|
ipcom_strcpy(ifreq.ifr_name, i->if_name);
|
|
#ifdef IP_PORT_LAS
|
|
if (ipcom_socketioctl(ipmcp.cfg_fd, IP_SIOCGIFFLAGS, (char*)&ifreq) < 0)
|
|
#else
|
|
if (ipcom_socketioctl(ipmcp.ipd_fd, IP_SIOCGIFFLAGS, (char*)&ifreq) < 0)
|
|
#endif
|
|
{
|
|
IPCOM_LOG1(ERR, "ipcom_ioctl(SIOCGIFFLAGS) failed, errno = %d", ipcom_errno);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Skip loopback */
|
|
if (IP_BIT_ISSET(ifreq.ifr_ifru.ifru_flags, IP_IFF_LOOPBACK))
|
|
continue;
|
|
|
|
/* Skip if not multicast capable */
|
|
if (IP_BIT_ISFALSE(ifreq.ifr_ifru.ifru_flags, IP_IFF_MULTICAST))
|
|
continue;
|
|
|
|
/* Skip if DOWN */
|
|
if (IP_BIT_ISFALSE(ifreq.ifr_ifru.ifru_flags, IP_IFF_UP))
|
|
continue;
|
|
|
|
if (ipmcp_if_create(i->if_index) < 0)
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = 0;
|
|
cleanup:
|
|
ipcom_if_freenameindex(ifrs);
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_upstream_if_add
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmcp_upstream_if_add(void)
|
|
{
|
|
struct Ip_ifreq ifreq;
|
|
Ip_size_t namsiz = sizeof(ifreq.ifr_name);
|
|
int ret;
|
|
|
|
if (ipcom_sysvar_get("ipmcp.UpstreamIf", ifreq.ifr_name, &namsiz) == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "missing 'ipmcp.UpstreamIf'");
|
|
IP_PANIC2();
|
|
return -1;
|
|
}
|
|
|
|
ipcom_strcpy(ipmcp.upstream_if.ifname, ifreq.ifr_name);
|
|
|
|
ipmcp.upstream_if.ifindex = ipcom_if_nametoindex(ifreq.ifr_name);
|
|
if (ipmcp.upstream_if.ifindex == 0)
|
|
{
|
|
IPCOM_LOG1(ERR, "upstream interface %s is not attached to the stack", ifreq.ifr_name);
|
|
IP_PANIC2();
|
|
return -1;
|
|
}
|
|
#ifdef IP_PORT_LAS
|
|
if (ipcom_socketioctl(ipmcp.cfg_fd, IP_SIOCGIFFLAGS, (char*)&ifreq) < 0)
|
|
#else
|
|
if (ipcom_socketioctl(ipmcp.ipd_fd, IP_SIOCGIFFLAGS, (char*)&ifreq) < 0)
|
|
#endif
|
|
{
|
|
IPCOM_LOG1(ERR, "ipcom_ioctl(SIOCGIFFLAGS) failed: %s", ipcom_strerror(ipcom_errno));
|
|
IP_PANIC();
|
|
return -1;
|
|
}
|
|
|
|
if (IP_BIT_ISSET(ifreq.ifr_ifru.ifru_flags, IP_IFF_LOOPBACK)
|
|
|| IP_BIT_ISFALSE(ifreq.ifr_ifru.ifru_flags, IP_IFF_MULTICAST))
|
|
{
|
|
IPCOM_LOG1(ERR,
|
|
"%s cannot be used as uplink interface, must not be loopback and must be multicast capable",
|
|
ifreq.ifr_name);
|
|
IP_PANIC2();
|
|
return -1;
|
|
}
|
|
|
|
if (IP_BIT_ISSET(ifreq.ifr_ifru.ifru_flags, IP_IFF_UP))
|
|
ipmcp.state = IPMCP_STATE_RUNNING;
|
|
else
|
|
{
|
|
IPCOM_LOG1(NOTICE,
|
|
"%s was found, but is currently not UP, enter WAITING state",
|
|
ifreq.ifr_name);
|
|
ipmcp.state = IPMCP_STATE_WAITING;
|
|
}
|
|
|
|
#ifdef IPMCP_USE_IGMP
|
|
ret = ipmcp_igmp_upstream_if_create(&ipmcp.upstream_if);
|
|
if (ret < 0)
|
|
return ret;
|
|
#endif
|
|
#ifdef IPMCP_USE_MLD
|
|
ret = ipmcp_mld_upstream_if_create(&ipmcp.upstream_if);
|
|
if (ret < 0)
|
|
return ret;
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_upstream_if_destroy
|
|
*===========================================================================
|
|
* Description: Removes the upstream interface.
|
|
* Parameters:
|
|
* Returns: 0 = success, <0 = error.
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmcp_upstream_if_destroy(void)
|
|
{
|
|
#ifdef IPMCP_USE_IGMP
|
|
ipmcp_igmp_upstream_if_destroy(&ipmcp.upstream_if);
|
|
#endif
|
|
#ifdef IPMCP_USE_MLD
|
|
ipmcp_mld_upstream_if_destroy(&ipmcp.upstream_if);
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_apply_configuration
|
|
*===========================================================================
|
|
* Description: Setup the system according to the configuration.
|
|
* Parameters:
|
|
* Returns: 0 = success, <0 = error.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmcp_setup_configuration(void)
|
|
{
|
|
Ipmcp_conf_t *conf = &ipmcp.config;
|
|
|
|
if (ipmcp_upstream_if_add() < 0)
|
|
return -1;
|
|
|
|
/* Read sysvar configuration. */
|
|
conf->robustness_variable = (Ip_u32)ipcom_sysvar_get_as_int("ipmcp.RobustnessVariable", 2);
|
|
if (conf->robustness_variable == 0 || conf->robustness_variable == 0xffffffff)
|
|
{
|
|
IPCOM_LOG0(ERR, "invalid 'ipmcp.RobustnessVariable'");
|
|
return -1;
|
|
}
|
|
|
|
conf->query_interval = (Ip_u32)ipcom_sysvar_get_as_int("ipmcp.QueryInterval", 125);
|
|
if (conf->query_interval > 0xffffffff / 1000)
|
|
{
|
|
IPCOM_LOG1(ERR, "No support for query intervals > %u 'ipmcp.QueryInterval'", 0xffffffff / 1000);
|
|
return -1;
|
|
}
|
|
conf->query_interval *= 1000; /* milliseconds */
|
|
|
|
conf->query_response_interval =
|
|
(Ip_u16)ipcom_sysvar_get_as_int("ipmcp.QueryResponseInterval", 10000);
|
|
conf->last_member_query_interval =
|
|
(Ip_u32)ipcom_sysvar_get_as_int("ipmcp.LastMemberQueryInterval", 1000);
|
|
conf->last_member_query_count =
|
|
(Ip_u32)ipcom_sysvar_get_as_int("ipmcp.LastMemberQueryCount", conf->robustness_variable);
|
|
|
|
/* Calculate some parameters */
|
|
conf->startup_query_interval =
|
|
(Ip_u32)ipcom_sysvar_get_as_int("ipmcp.StartupQueryInterval", 0) * 1000;
|
|
if (conf->startup_query_interval == 0)
|
|
conf->startup_query_interval = conf->query_interval / 4;
|
|
conf->startup_query_count = conf->robustness_variable;
|
|
|
|
ipmcp.config.downstream_ifs = ipcom_sysvar_get("ipmcp.DownstreamIfs", IP_NULL, IP_NULL);
|
|
if (ipmcp.config.downstream_ifs == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "missing 'ipmcp.DownstreamIfs'");
|
|
return -1;
|
|
}
|
|
|
|
return ipmcp_add_downstream_ifs();
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_teardown_configuration
|
|
*===========================================================================
|
|
* Description: Frees all resouces that is tied to the current configuration.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmcp_teardown_configuration(void)
|
|
{
|
|
Ipmcp_netif_t *i;
|
|
|
|
ipmcp.state = IPMCP_STATE_HALTED;
|
|
|
|
for (i = IPCOM_LIST_FIRST(&ipmcp.downstream_ifs_head);
|
|
i != IP_NULL;
|
|
i = IPCOM_LIST_FIRST(&ipmcp.downstream_ifs_head))
|
|
{
|
|
ipmcp_if_destroy(i);
|
|
}
|
|
|
|
ipmcp_upstream_if_destroy();
|
|
ipcom_free(ipmcp.config.downstream_ifs);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_init
|
|
*===========================================================================
|
|
* Description: Initializes the multicast proxy.
|
|
* Parameters:
|
|
* Returns: 0 = success, <0 = error.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmcp_init(void)
|
|
{
|
|
int ret;
|
|
Ip_err err = IPCOM_ERR_FAILED;;
|
|
|
|
ipcom_list_init(&ipmcp.downstream_ifs_head);
|
|
|
|
ipmcp.tmo_head = ipcom_tmo2_new();
|
|
if (ipmcp.tmo_head == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "Failed to create timeout head");
|
|
goto done;
|
|
}
|
|
|
|
ipmcp.rt_fd = ipcom_socket(IP_AF_ROUTE, IP_SOCK_RAW, 0);
|
|
if (ipmcp.rt_fd == IP_INVALID_SOCKET)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipcom_socket(ROUTE,RAW) failed: %s", ipcom_strerror(ipcom_errno));
|
|
goto done;
|
|
}
|
|
|
|
#ifdef IP_PORT_LAS
|
|
ipmcp.cfg_fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, 0);
|
|
if (ipmcp.cfg_fd == IP_INVALID_SOCKET)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipcom_socket(INET,DGRAM) failed: %s", ipcom_strerror(ipcom_errno));
|
|
goto done;
|
|
}
|
|
#endif
|
|
|
|
#ifdef IPMCP_USE_IGMP
|
|
if (0 > (ret = ipmcp_igmp_init()))
|
|
return ret;
|
|
#endif
|
|
|
|
#ifdef IPMCP_USE_MLD
|
|
if (0 > (ret = ipmcp_mld_init()))
|
|
return ret;
|
|
#endif
|
|
|
|
err = IPCOM_SUCCESS;;
|
|
done:
|
|
if (ipcom_ipd_init(IPMCP_IPD_NAME, err, &ipmcp.ipd_fd) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG1(ERR, "Failed to initialize IPD: %s", ipcom_strerror(ipcom_errno));
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_exit
|
|
*===========================================================================
|
|
* Description: Frees all resources held by the daemon.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipmcp_exit(void)
|
|
{
|
|
(void)ipcom_ipd_exit("ipmcp", ipmcp.ipd_fd);
|
|
(void)ipcom_socketclose(ipmcp.rt_fd);
|
|
#ifdef IP_PORT_LAS
|
|
(void)ipcom_socketclose(ipmcp.cfg_fd);
|
|
#endif
|
|
#ifdef IPMCP_USE_IGMP
|
|
ipmcp_igmp_exit();
|
|
#endif
|
|
|
|
#ifdef IPMCP_USE_MLD
|
|
ipmcp_mld_exit();
|
|
#endif
|
|
|
|
ipcom_tmo2_delete(ipmcp.tmo_head);
|
|
ipmcp_is_enabled = IP_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_ipd_input
|
|
*===========================================================================
|
|
* Description: Processes IPD messages,
|
|
* Parameters: fd - The IPD socket
|
|
* done - Will be set to true if the daemon should shutdown.
|
|
* Returns: 0 = Daemon will continue and process other messages.
|
|
* 1 = The daemon must reconfigure itsef.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmcp_ipd_input(int fd, Ip_bool *done)
|
|
{
|
|
switch (ipcom_ipd_input(fd))
|
|
{
|
|
case IPCOM_IPD_EVENT_RECONFIGURE:
|
|
IPCOM_LOG0(INFO, "received IPD reconfigure message");
|
|
*done = IP_FALSE;
|
|
return 1;
|
|
|
|
case IPCOM_IPD_EVENT_KILL:
|
|
IPCOM_LOG0(INFO, "received IPD kill message");
|
|
*done = IP_TRUE;
|
|
return 1;
|
|
|
|
case IPMCP_IPD_EVENT_WAIT_FOR_SHELL_CMD:
|
|
/* Notify the shell command that the MCP daemon now waiting
|
|
here */
|
|
(void)ipcom_sem_post(ipmcp.cmd_sem);
|
|
|
|
/* This will block this task until the shell command has
|
|
finished reading the state of the MCP daemon */
|
|
(void)ipcom_mutex_lock(ipmcp.daemon_mutex);
|
|
(void)ipcom_mutex_unlock(ipmcp.daemon_mutex);
|
|
return 0;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_route_input
|
|
*===========================================================================
|
|
* Description: Processes route socket messages.
|
|
* Parameters: fd - The route socket
|
|
* Returns: 0 = success
|
|
* <0 = error
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipmcp_route_input(int fd)
|
|
{
|
|
Ipmcp_netif_t *netif;
|
|
int length;
|
|
union rtmsg_union
|
|
{
|
|
struct Ipnet_rt_msghdr rtmsg;
|
|
struct Ipnet_if_msghdr ifmsg;
|
|
struct Ipnet_ifa_msghdr ifamsg;
|
|
} buf;
|
|
|
|
/* Read routing message headers only (truncated read). */
|
|
length = ipcom_recv(fd, &buf, sizeof(buf), 0);
|
|
if (length == IP_SOCKERR)
|
|
{
|
|
IP_PANIC2();
|
|
IPCOM_LOG1(ERR, "ipmcp_route_input: ipcom_recv() failed, errno = %d", ipcom_errno);
|
|
return -1;
|
|
}
|
|
|
|
if (length < (int) sizeof(struct Ipnet_rs_msghdr))
|
|
{
|
|
IP_PANIC2();
|
|
IPCOM_LOG2(ERR, "ipmcp_route_input: ipcom_recv() failed, truncated rtsock message %ld/%d", length,
|
|
(int)sizeof(struct Ipnet_rs_msghdr));
|
|
return -1;
|
|
}
|
|
|
|
switch (buf.rtmsg.rtm_type)
|
|
{
|
|
case IPNET_RTM_DELADDR:
|
|
case IPNET_RTM_NEWADDR:
|
|
netif = ipmcp_if_find(buf.ifamsg.ifam_index);
|
|
if (netif)
|
|
{
|
|
#ifdef IPMCP_USE_IGMP
|
|
ipmcp_igmp_addr_change(netif, buf.rtmsg.rtm_type == IPNET_RTM_NEWADDR);
|
|
#endif
|
|
#ifdef IPMCP_USE_MLD
|
|
ipmcp_mld_addr_change(netif, buf.rtmsg.rtm_type == IPNET_RTM_NEWADDR);
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case IPNET_RTM_IFINFO:
|
|
if (IP_BIT_ISSET(buf.ifmsg.ifm_flags, IP_IFF_UP))
|
|
(void) ipmcp_if_create(buf.ifmsg.ifm_index);
|
|
else
|
|
ipmcp_if_destroy(ipmcp_if_find(buf.ifmsg.ifm_index));
|
|
break;
|
|
|
|
default:
|
|
/* ignore all other routing messages. */
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_daemon
|
|
*===========================================================================
|
|
* Description: Multicast proxy daemon.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IPCOM_PROCESS(ipmcp_daemon)
|
|
{
|
|
int max_fd;
|
|
int num;
|
|
int ret = 0;
|
|
Ip_fd_set read_set;
|
|
int retries;
|
|
Ip_bool done = IP_FALSE;
|
|
|
|
ipcom_proc_init();
|
|
|
|
IPCOM_LOG0(INFO, "Multicast proxy daemon starting");
|
|
|
|
ret = ipmcp_init();
|
|
if (0 > ret)
|
|
done = IP_TRUE;
|
|
|
|
while (!done)
|
|
{
|
|
ret = ipmcp_setup_configuration();
|
|
if (ret != 0)
|
|
break;
|
|
|
|
ipmcp_is_enabled = IP_TRUE;
|
|
|
|
for (;;)
|
|
{
|
|
IP_FD_ZERO(&read_set);
|
|
IP_FD_SET(ipmcp.ipd_fd, &read_set);
|
|
IP_FD_SET(ipmcp.rt_fd, &read_set);
|
|
max_fd = IP_MAX(ipmcp.rt_fd, ipmcp.ipd_fd);
|
|
#ifdef IPMCP_USE_IGMP
|
|
IP_FD_SET(ipmcp.igmp.fd, &read_set);
|
|
max_fd = IP_MAX(ipmcp.igmp.fd, max_fd);
|
|
#endif
|
|
#ifdef IPMCP_USE_MLD
|
|
IP_FD_SET(ipmcp.mld.mld_fd, &read_set);
|
|
max_fd = IP_MAX(ipmcp.mld.mld_fd, max_fd);
|
|
IP_FD_SET(ipmcp.mld.mrt_fd, &read_set);
|
|
max_fd = IP_MAX(ipmcp.mld.mrt_fd, max_fd);
|
|
#endif
|
|
|
|
done = IP_TRUE;
|
|
|
|
for (retries = 0, num = 0; num <= 0 && retries < 3; retries++)
|
|
{
|
|
num = ipcom_tmo2_select(ipmcp.tmo_head, max_fd + 1, &read_set, IP_NULL, IP_NULL, IP_NULL);
|
|
if (num < 0)
|
|
IPCOM_LOG1(WARNING, "socket select returned %s", ipcom_strerror(ipcom_errno));
|
|
}
|
|
|
|
if (num < 0)
|
|
{
|
|
IPCOM_LOG1(ERR, "socket select returned %s, shutting down", ipcom_strerror(ipcom_errno));
|
|
break;
|
|
}
|
|
|
|
if (IP_FD_ISSET(ipmcp.ipd_fd, &read_set) && ipmcp_ipd_input(ipmcp.ipd_fd, &done) != 0)
|
|
break;
|
|
|
|
if (IP_FD_ISSET(ipmcp.rt_fd, &read_set) && ipmcp_route_input(ipmcp.rt_fd) < 0)
|
|
break;
|
|
|
|
|
|
#ifdef IPMCP_USE_IGMP
|
|
if (IP_FD_ISSET(ipmcp.igmp.fd, &read_set)
|
|
&& ipmcp_igmp_input(ipmcp.igmp.fd) < 0)
|
|
break;
|
|
#endif
|
|
|
|
#ifdef IPMCP_USE_MLD
|
|
if (IP_FD_ISSET(ipmcp.mld.mld_fd, &read_set)
|
|
&& ipmcp_mld_input(ipmcp.mld.mld_fd) < 0)
|
|
break;
|
|
|
|
if (IP_FD_ISSET(ipmcp.mld.mrt_fd, &read_set)
|
|
&& ipmcp_mld_mroute_input(ipmcp.mld.mrt_fd) < 0)
|
|
break;
|
|
#endif
|
|
|
|
done = IP_FALSE;
|
|
}
|
|
|
|
ipmcp_teardown_configuration();
|
|
}
|
|
|
|
ipmcp_exit();
|
|
|
|
IPCOM_LOG0(INFO, "Multicast proxy daemon ending");
|
|
ipcom_proc_exit();
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_if_find
|
|
*===========================================================================
|
|
* Description: Finds the interface that matches the index.
|
|
* Parameters:
|
|
* Returns: The interface structure or IP_NULL if it does not exists.
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipmcp_netif_t *
|
|
ipmcp_if_find(Ip_u32 ifindex)
|
|
{
|
|
Ipmcp_netif_t *i;
|
|
|
|
for (i = IPCOM_LIST_FIRST(&ipmcp.downstream_ifs_head);
|
|
i != IP_NULL;
|
|
i = IPCOM_LIST_NEXT(&i->list))
|
|
{
|
|
if (ifindex == i->ifindex)
|
|
return i;
|
|
}
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_route_init_addrs
|
|
*===========================================================================
|
|
* Description: Sets the address pointer to point to the correct entry
|
|
* in the 'rt' buffer.
|
|
* Parameters: msg - The first socket address in the route socket message.
|
|
* addrs - The IPNET_RTA_xxx from the message.
|
|
* sas - Will contain the route pointer.
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipmcp_route_init_addrs(void *msg, Ip_u32 addrs, struct Ip_sockaddr **sas)
|
|
{
|
|
int i;
|
|
Ip_size_t offset = 0;
|
|
|
|
for (i = 0; i < IPNET_RTAX_MAX; i++)
|
|
{
|
|
if (IP_BIT_ISSET(addrs, 1 << i))
|
|
{
|
|
sas[i] = (struct Ip_sockaddr *) &((Ip_u8 *) msg)[offset];
|
|
offset += IPCOM_SA_LEN_GET(sas[i]);
|
|
}
|
|
else
|
|
sas[i] = IP_NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_create
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipmcp_create(void)
|
|
{
|
|
Ip_err ret;
|
|
|
|
ipcom_memset(&ipmcp, 0, sizeof(Ipmcp_data_t));
|
|
|
|
if ((ret = ipcom_mutex_create(&ipmcp.daemon_mutex)) != IPCOM_SUCCESS)
|
|
return ret;
|
|
|
|
if ((ret = ipcom_sem_create(&ipmcp.cmd_sem, 0)) != IPCOM_SUCCESS)
|
|
return ret;
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_start
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipmcp_start(void)
|
|
{
|
|
Ip_err ret;
|
|
Ipcom_proc_attr attr;
|
|
|
|
ipcom_proc_attr_init(&attr);
|
|
|
|
ipmcp.ipd_fd = IP_INVALID_SOCKET;
|
|
ipmcp.rt_fd = IP_INVALID_SOCKET;
|
|
#ifdef IPMCP_USE_IGMP
|
|
ipmcp.igmp.fd = IP_INVALID_SOCKET;
|
|
#endif
|
|
#ifdef IPMCP_USE_MLD
|
|
ipmcp.mld.mld_fd = IP_INVALID_SOCKET;
|
|
ipmcp.mld.mrt_fd = IP_INVALID_SOCKET;
|
|
#endif
|
|
|
|
ret = ipcom_proc_acreate("ipmcp", ipmcp_daemon, &attr, IP_NULL);
|
|
ip_assert(ret == IPCOM_SUCCESS);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipmcp_version
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC const char *
|
|
ipmcp_version(void)
|
|
{
|
|
return "@(#) IPMCP $Name: VXWORKS_ITER40_2019102207 $ - INTERPEAK_COPYRIGHT_STRING";
|
|
}
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|