Files
m241Neelima/components/ip_net2-6.9/ipmcp/src/ipmcp.c
T
2026-07-30 11:19:44 +05:30

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
****************************************************************************
*/