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

1025 lines
26 KiB
C

/* wrnad_mon.c - Wind River network acceleration daemon (NAD) */
/*
* Copyright (c) 2010 Wind River Systems, Inc.
*
* The right to copy, distribute or otherwise make use of this software
* may be licensed only pursuant to the terms of an applicable Wind River
* license agreement.
*/
/* includes */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include "wrnad.h"
/* for VLAN stacking */
#include "wrnad_svconfig.h"
/* defines */
/*
* FIXME: The stdlib.h at ipxinc/include/stdlib.h doesn't define
* EXIT_FAILURE or EXIT_SUCCESS.
*/
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#endif
#ifndef EXIT_SUCCESS
#define EXIT_SUCCESS 0
#endif
/* typedefs */
/* imports */
/* globals */
Wrnad_proxy_interface wrnad_proxy_ifs[WRNAD_MAX_IF];
int wrnad_rtfd = -1; /* for clean-up */
int wrnad_mipcfd = -1;
int wrnad_pfkeyfd = -1;
/* locals */
static int wrnad_seq = 0;
static int request_done = 0;
static char recvbuf[WRNAD_RECVBUF_SIZE];
int wrnad_mon_running = 0;
/*
* Table to translate Linux address family values
* to IPNET/VxWorks (NAE) address family values.
* Gotta love them family values!
*/
#if !defined IPWRNAD
/* In IPWRNAD case, we use ipxinc/include/sys/socket.h ... */
#define IP_AF_UNSPEC 0 /* Unspecified domain */
#define IP_AF_INET 2 /* IPv4 */
#define IP_AF_IPX 4 /* IPX */
#define IP_AF_NETLINK 16 /* Linux Netlink, RFC 3549 */
#define IP_AF_ROUTE 17 /* Internal routing Protocol */
#define IP_AF_LINK 18 /* Link layer address (used in route entries and ancillary data) */
#define IP_AF_PACKET 19 /* Linux packet family */
/* for VxWorks (NAE) case: */
#define IP_AF_INET6 28 /* Default family value of IP version 6 */
#define IP_AF_KEY 27 /* PFKEYv2 key-management socket API */
#define IP_AF_TIPC 33 /* Transparent Inter-Process Communic. */
#define IP_AF_MAX 35
static unsigned char af_xlat[AF_MAX] =
{
IP_AF_UNSPEC, /* 0, AF_UNSPEC */
255, /* 1, AF_LOCAL/AF_UNIX/AF_FILE */
IP_AF_INET, /* 2, AF_INET */
255, /* 3, AF_AX25 */
IP_AF_IPX, /* 4, AF_IPX */
255, /* 5, AF_APPLETALK */
255, /* 6, AF_NETROM */
255, /* 7, AF_BRIDGE */
255, /* 8, AF_ATMPVC */
255, /* 9, AF_X25 */
IP_AF_INET6, /* 10, AF_INET6 */
255, /* 11, AF_ROSE */
255, /* 12, AF_DECnet */
255, /* 13, AF_NETBEUI */
255, /* 14, AF_SECURITY */
IP_AF_KEY, /* 15, AF_KEY */
IP_AF_NETLINK, /* 16, AF_NETLINK (AF_ROUTE is an alias in linux) */
IP_AF_PACKET, /* 17, AF_PACKET */
255, /* 18, AF_ASH */
255, /* 19, AF_ECONET */
255, /* 20, AF_ATMSVC */
255, /* 21, AF_RDS */
255, /* 22, AF_SNA */
255, /* 23, AF_IRDA */
255, /* 24, AF_PPPOX */
255, /* 25, AF_WANPIPE */
255, /* 26, AF_LLC */
255, /* 27, unused */
255, /* 28, unused */
255, /* 29, AF_CAN */
IP_AF_TIPC, /* 30, AF_TIPC */
255, /* 31, AF_BLUETOOTH */
255, /* 32, AF_IUCV */
255, /* 33, AF_RXRPC */
255, /* 34, AF_ISDN */
255, /* 35, AF_PHONET */
255 /* 36, AF_IEEE802154 */
/* 37 --> AF_MAX */
};
#endif /* !defined(IPWRNAD) */
/*******************************************************************************
*
* wrnad_rtnl_init - initialize wrnad monitoring
*
* This routine initializes wrnad monitoring
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
static void
wrnad_rtnl_init(void)
{
memset(&wrnad_proxy_ifs, 0, sizeof(wrnad_proxy_ifs));
}
/*******************************************************************************
*
* wrnad_rtnl_control_handler - rtnetlink handler for control messages
*
* This routine handles rtnetlink control messages.
*
* RETURNS: -1 = failed
* 0 = skip
* 1 = action
*
* ERRNO: N/A
*/
static int
wrnad_rtnl_control_handler(struct nlmsghdr *nlh)
{
int len;
struct nlmsgerr *err;
if (nlh->nlmsg_type == NLMSG_ERROR)
{
err = NLMSG_DATA(nlh);
len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(struct nlmsgerr));
if (len < 0)
{
wrnad_log(LOG_WARNING, "Rtnetlink message type %s has wrong nlmsg length %d!",
wrnad_rtnl_typestr(nlh->nlmsg_type), nlh->nlmsg_len);
return -1;
}
#ifndef IPWRNAD
/* Neighbour updates */
if (err->msg.nlmsg_type != RTM_NEWNEIGH)
#endif
wrnad_log(LOG_ERR, "Rtnetlink control message ERROR: error=%s (%d)", strerror(-err->error), -err->error);
}
else if (nlh->nlmsg_type == NLMSG_NOOP)
wrnad_log(LOG_DEBUG, "Rtnetlink control message NOOP:");
else if (nlh->nlmsg_type == NLMSG_DONE)
{
request_done = 1;
wrnad_log(LOG_DEBUG, "Rtnetlink control message DONE:");
}
else
wrnad_log(LOG_WARNING, "Rtnetlink control message %d:", nlh->nlmsg_type);
return 0;
}
/*******************************************************************************
*
* wrnad_rtnl_handler - find rtnetlink handler
*
* This routine returns a handler form the rtnetlink message type.
*
* RETURNS: handler or NULL if not found
*
* ERRNO: N/A
*/
static wrnad_rtnl_handler
wrnad_rtnl_find_handler(struct nlmsghdr *nlh)
{
switch (nlh->nlmsg_type)
{
case NLMSG_ERROR:
case NLMSG_NOOP:
case NLMSG_DONE:
return wrnad_rtnl_control_handler;
case RTM_NEWNEIGH:
case RTM_DELNEIGH:
return wrnad_rtnl_neigh_handler;
case RTM_NEWLINK:
case RTM_DELLINK:
return wrnad_rtnl_link_handler;
case RTM_NEWADDR:
case RTM_DELADDR:
return wrnad_rtnl_addr_handler;
case RTM_NEWROUTE:
case RTM_DELROUTE:
return wrnad_rtnl_route_handler;
/* for VLAN stacking */
case RTM_SET_SVLAN:
case RTM_DEL_SVLAN:
return wrnad_rtnl_svlan_handler;
default:
return NULL;
}
}
/*******************************************************************************
*
* wrnad_rtnl_close - close rtnetlink socket
*
* This routine closes a rtnetlink socket
*
* RETURNS: N/A
*
* ERRNO: N/A
*/
static void
wrnad_rtnl_close(int fd)
{
if (fd >= 0)
close(fd);
}
/*******************************************************************************
*
* wrnad_rtnl_open - open and bind rtnetlink socket
*
* This routine opens a rtnetlink socket and binds it.
*
* RETURNS: socket descriptor if exited normally, else -1.
*
* ERRNO: N/A
*/
static int
wrnad_rtnl_open(int proto, unsigned int groups, struct sockaddr_nl *laddr)
{
int fd;
socklen_t addr_len;
int bufsize;
socklen_t slen;
fd = socket(AF_NETLINK, SOCK_RAW, proto);
if (fd < 0)
{
wrnad_log(LOG_ERR, "Failed to open rtnetlink socket!");
return -1;
}
wrnad_log(LOG_DEBUG, "Rtnetlink socket %d created.", fd);
memset(laddr, 0, sizeof(laddr));
laddr->nl_family = AF_NETLINK;
laddr->nl_groups = groups;
/* associate the process's pid with netlink sock address */
laddr->nl_pid = getpid();
if (bind(fd, (struct sockaddr *)laddr, sizeof(struct sockaddr_nl)) < 0)
{
wrnad_log(LOG_ERR, "Failed to bind rtnetlink socket! errno=%s", strerror(errno));
close(fd);
return -1;
}
addr_len = sizeof(struct sockaddr_nl);
if (getsockname(fd, (struct sockaddr *)laddr, &addr_len) < 0)
{
wrnad_log(LOG_ERR, "Failed to getsockname!");
close(fd);
return -1;
}
bufsize = 0;
slen = (socklen_t)sizeof (bufsize);
if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, &slen) < 0)
wrnad_log(LOG_ERR, "Failed to get default netlink socket RCVBUF\n");
else
wrnad_log(LOG_INFO, "Default netlink socket RCVBUF is %u\n", bufsize);
bufsize = 64 * 1024 * 1024;
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) < 0)
{
wrnad_log(LOG_ERR, "Failed to set netlink socket RCVBUF to %u.\n", bufsize);
close(fd);
return -1;
}
wrnad_log(LOG_DEBUG, "Rtnetlink socket %d bound to pid %u.", fd, laddr->nl_pid);
return fd;
}
/*******************************************************************************
*
* wrnad_rtnl_parse - parse message received on rtnetlink socket
*
* This routine parses indivudual messages received on a rtnetlink socket
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
static int
wrnad_rtnl_parse(int fd, struct nlmsghdr *nlh)
{
wrnad_rtnl_handler f;
int ret;
/* Find handler */
if ((f = wrnad_rtnl_find_handler(nlh)))
{
ret = f(nlh);
if (ret == 1)
{
/* Send rtnetlink message over MIPC */
nlh->nlmsg_seq = 0;
nlh->nlmsg_pid = 0;
ret = wrnad_mipc_send_netlink(fd, nlh);
}
return ret;
}
else
{
wrnad_log(LOG_INFO, "No handler found for rtnetlink type %d (%s)!",
nlh->nlmsg_type, wrnad_rtnl_typestr(nlh->nlmsg_type));
return -1;
}
}
/*******************************************************************************
*
* wrnad_rtnl_scan - scan message received on rtnetlink socket
*
* This routine scans messages received on a rtnetlink socket
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
static int
wrnad_rtnl_scan(char *buf, int buflen, int fd)
{
struct nlmsghdr *nlh;
nlh = (struct nlmsghdr *)buf;
while (NLMSG_OK(nlh, (size_t)buflen))
{
wrnad_log(LOG_DEBUG, "Rtnetlink message header: length=%d, type=%s, flags=%d, seq=%d, pid=%u.",
nlh->nlmsg_len,
wrnad_rtnl_typestr(nlh->nlmsg_type),
nlh->nlmsg_flags,
nlh->nlmsg_seq,
nlh->nlmsg_pid);
if (wrnad_rtnl_parse(fd, nlh) >= 0)
{
wrnad_log(LOG_DEBUG, "Rtnetlink message type %s handled ok.",
wrnad_rtnl_typestr(nlh->nlmsg_type));
}
nlh = NLMSG_NEXT(nlh, buflen);
}
if (buflen)
{
wrnad_log(LOG_WARNING, "Rtnetlink message truncated! Found %d trailing bytes.", buflen);
return -1;
}
return 0;
}
/*******************************************************************************
*
* wrnad_rtnl_recvfrom - recv on rtnetlink socket
*
* This routine receives messages on a rtnetlink socket
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
static int
wrnad_rtnl_recvfrom(int rtfd, int mipc_fd)
{
int len;
struct sockaddr_nl raddr;
socklen_t addrlen;
memset(&raddr, 0, sizeof(raddr));
raddr.nl_family = AF_NETLINK;
raddr.nl_pid = 0;
raddr.nl_groups = 0;
addrlen = 0;
len = recvfrom(rtfd, recvbuf, sizeof(recvbuf), 0, (struct sockaddr *)&raddr, &addrlen);
if (len < 0)
{
wrnad_log(LOG_ERR, "Recvfrom on rtnetlink socket %d interrupted by error %s -> exit.", rtfd, strerror(errno));
return -1;
}
else if (len == 0)
{
wrnad_log(LOG_ERR, "Recvfrom on rtnetlink socket %d interrupted by EOF.", rtfd);
return -1;
}
wrnad_log(LOG_DEBUG, "Recvfrom on rtnetlink socket %d returned %d bytes of data.", rtfd, len);
/* Verify that the message was received from the kernel.
Note: A message may also arrive from svconfig for VLAN stacking configuration (via the kernel).
*/
if (raddr.nl_pid)
{
wrnad_log(LOG_WARNING, "Skipped rtnetlink message received from pid %d!", raddr.nl_pid);
return 0;
}
/* Scan receive message */
if (wrnad_rtnl_scan(recvbuf, len, mipc_fd) < 0)
wrnad_log(LOG_WARNING, "Rtnetlink message failed scan!\n");
else
wrnad_log(LOG_DEBUG, "Rtnetlink message scanned ok.\n");
return 0;
}
/*******************************************************************************
*
* wrnad_rtnl_get_request - set get rtnetlink get request
*
* This routine sends a request to retrieve all entries of a rtnetlink type.
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
static int
wrnad_rtnl_send_request(int fd, int family, int type)
{
struct sockaddr_nl raddr;
struct {
struct nlmsghdr nlh;
unsigned char family;
} req;
memset(&raddr, 0, sizeof(raddr));
raddr.nl_family = AF_NETLINK;
memset(&req, 0, sizeof(req));
req.nlh.nlmsg_len = sizeof(req);
req.nlh.nlmsg_type = type;
req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
req.nlh.nlmsg_seq = ++wrnad_seq;
req.family = family;
/* Send the request */
wrnad_log(LOG_DEBUG, "Sending rtnetlink %s request on socket %d", wrnad_rtnl_typestr(type), fd);
if (sendto(fd, (void *)&req, sizeof(req), 0, (struct sockaddr *)&raddr, sizeof(struct sockaddr_nl)) < 0)
{
wrnad_log(LOG_ERR, "send failed! errno=%s (%d)\n", strerror(errno), errno);
return -1;
}
request_done = 0;
return 0;
}
/*******************************************************************************
*
* wrnad_rtnl_proxyifstr - find proxy interfaces
*
* This routine returns the current proxy interfaces as a string
*
* RETURNS: string representation of procy interfaces.
*
* ERRNO: N/A
*/
static char *
wrnad_rtnl_proxyifstr(char *ifstr)
{
int i, j;
ifstr[0] = '\0';
j = 0;
for (i = 0; i<WRNAD_MAX_IF; i++)
{
if (wrnad_proxy_ifs[i].ifname[0] != '\0')
{
if (j == 0)
j += sprintf(&ifstr[j], "%s (%d)", wrnad_proxy_ifs[i].ifname, wrnad_proxy_ifs[i].ifindex);
else
j += sprintf(&ifstr[j], ", %s (%d)", wrnad_proxy_ifs[i].ifname, wrnad_proxy_ifs[i].ifindex);
}
}
return ifstr;
}
/*******************************************************************************
*
* wrnad_rtnl_check_proxy_interface - check proxy interface
*
* This routine checks if an interface is a proxy inteface
*
* RETURNS: proxy interface name if found else NULL;
*
* ERRNO: N/A
*/
Wrnad_proxy_interface *
wrnad_rtnl_check_proxy_interface(int ifindex)
{
int i;
for (i = 0; i<WRNAD_MAX_IF; i++)
{
if (wrnad_proxy_ifs[i].ifindex == ifindex)
{
return &wrnad_proxy_ifs[i];
}
}
/* Not found */
return NULL;
}
/*******************************************************************************
*
* wrnad_rtnl_add_proxy_interface - add proxy interface
*
* This routine adds a proxy interface to the internal list
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
int
wrnad_rtnl_add_proxy_interface(int ifindex, char *ifname)
{
int i;
char proxyifs[512];
if (wrnad_rtnl_check_proxy_interface(ifindex))
{
wrnad_log(LOG_INFO, "Found proxy interface %s with index %d", ifname, ifindex);
return 0;
}
for (i = 0; i<WRNAD_MAX_IF; i++)
{
if (wrnad_proxy_ifs[i].ifname[0] == '\0')
{
wrnad_proxy_ifs[i].ifindex = ifindex;
strcpy(wrnad_proxy_ifs[i].ifname, ifname);
#ifdef WRNAD_IDENTIFY_ROUTERS
if (hash_v4_init(&wrnad_proxy_ifs[i].v4_routers) != 0 ||
hash_v6_init(&wrnad_proxy_ifs[i].v6_routers) != 0)
{
wrnad_log(LOG_ERR,
"Failed allocating router hash table for "
"proxy interface %s\n", ifname);
wrnad_terminate(EXIT_FAILURE);
}
#endif
wrnad_log(LOG_INFO, "Added proxy interface %s with index %d at position %d",
ifname, ifindex, i);
wrnad_log(LOG_INFO, "Current proxy interfaces are: %s.", wrnad_rtnl_proxyifstr(proxyifs));
return 0;
}
}
/* Reached maximum number of proxy interfaces */
return -1;
}
/*******************************************************************************
*
* wrnad_rtnl_del_proxy_interface - del proxy interface
*
* This routine deletes a proxy interface from the internal list
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
int
wrnad_rtnl_del_proxy_interface(int ifindex, char *ifname)
{
int i;
char proxyifs[512];
for (i = 0; i<WRNAD_MAX_IF; i++)
{
if (wrnad_proxy_ifs[i].ifindex == ifindex
&& strcmp(wrnad_proxy_ifs[i].ifname, ifname) == 0)
{
wrnad_proxy_ifs[i].ifindex = 0;
wrnad_proxy_ifs[i].ifname[0] = '\0';
wrnad_log(LOG_INFO, "Removed proxy interface %s with index %d from position %d",
ifname, ifindex, i);
wrnad_log(LOG_INFO, "Current proxy interfaces are: %s.", wrnad_rtnl_proxyifstr(proxyifs));
return 0;
}
}
/* Not found */
return -1;
}
/*******************************************************************************
*
* wrnad_rtnl_familystr - find rtnetlink family in string format
*
* This routine returns the rtnetlink family as a string
*
* RETURNS: string representation of rtnetlink family.
*
* ERRNO: N/A
*/
const char *
wrnad_rtnl_familystr(int family)
{
static char familystr[32];
switch (family)
{
case AF_UNSPEC:
return "AF_UNSPEC";
case AF_INET:
return "AF_INET";
case AF_INET6:
return "AF_INET6";
default:
sprintf(familystr, "%d", family);
return familystr;
}
}
/*******************************************************************************
*
* wrnad_rtnl_typestr - find rtnetlink type in string format
*
* This routine returns the rtnetlink message type as a string
*
* RETURNS: string representation of rtnetlink type.
*
* ERRNO: N/A
*/
const char *
wrnad_rtnl_typestr(int type)
{
switch (type)
{
case NLMSG_ERROR:
return "NLMSG_ERROR";
case NLMSG_NOOP:
return "NLMSG_NOOP";
case NLMSG_DONE:
return "NLMSG_DONE";
case RTM_NEWLINK:
return "RTM_NEWLINK";
case RTM_DELLINK:
return "RTM_DELLINK";
case RTM_GETLINK:
return "RTM_GETLINK";
case RTM_SETLINK:
return "RTM_SETLINK";
case RTM_NEWADDR:
return "RTM_NEWADDR";
case RTM_DELADDR:
return "RTM_DELADDR";
case RTM_GETADDR:
return "RTM_GETADDR";
case RTM_NEWROUTE:
return "RTM_NEWROUTE";
case RTM_DELROUTE:
return "RTM_DELROUTE";
case RTM_GETROUTE:
return "RTM_GETROUTE";
#ifdef RTM_NEWNEIGH
case RTM_NEWNEIGH:
return "RTM_NEWNEIGH";
case RTM_DELNEIGH:
return "RTM_DELNEIGH";
case RTM_GETNEIGH:
return "RTM_GETNEIGH";
#endif
case RTM_NEWRULE:
return "RTM_NEWRULE";
case RTM_DELRULE:
return "RTM_DELRULE";
case RTM_GETRULE:
return "RTM_GETRULE";
case RTM_NEWQDISC:
return "RTM_NEWQDISC";
case RTM_DELQDISC:
return "RTM_DELQDISC";
case RTM_GETQDISC:
return "RTM_GETQDISC";
case RTM_NEWTCLASS:
return "RTM_NEWTCLASS";
case RTM_DELTCLASS:
return "RTM_NEWTCLASS";
case RTM_GETTCLASS:
return "RTM_NEWTCLASS";
case RTM_NEWTFILTER:
return "RTM_NEWTFILTER";
case RTM_DELTFILTER:
return "RTM_DELTFILTER";
case RTM_GETTFILTER:
return "RTM_GETTFILTER";
case RTM_NEWACTION:
return "RTM_NEWACTION";
case RTM_DELACTION:
return "RTM_DELACTION";
case RTM_GETACTION:
return "RTM_GETACTION";
case RTM_NEWPREFIX:
return "RTM_NEWPREFIX";
case RTM_GETMULTICAST:
return "RTM_GETMULTICAST";
case RTM_GETANYCAST:
return "RTM_GETANYCAST";
#ifdef RTM_NEWNEIGHTBL
case RTM_NEWNEIGHTBL:
return "RTM_NEWNEIGHTBL";
case RTM_GETNEIGHTBL:
return "RTM_GETNEIGHTBL";
case RTM_SETNEIGHTBL:
return "RTM_SETNEIGHTBL";
#endif
case RTM_SET_SVLAN:
return "RTM_SET_SVLAN";
case RTM_DEL_SVLAN:
return "RTM_DEL_SVLAN";
#if 0
case RTM_NEWNDUSEROPT:
return "RTM_NEWNDUSEROPT";
case RTM_NEWADDRLABEL:
return "RTM_NEWADDRLABEL";
case RTM_DELADDRLABEL:
return "RTM_DELADDRLABEL";
case RTM_GETADDRLABEL:
return "RTM_GETADDRLABEL";
case RTM_GETDCB:
return "RTM_GETDCB";
case RTM_SETDCB:
return "RTM_SETDCB";
#endif
default:
return "RTM_UNKNOWN";
}
}
/*******************************************************************************
*
* wrnad_rtnl_eth_ntop - ethernet mac address in string format
*
* This routine returns the ethernet mac address as a string
*
* RETURNS: string representation of the ethernet mac address.
*
* ERRNO: N/A
*/
void
wrnad_rtnl_eth_ntop(unsigned char *mac, char *buf)
{
sprintf(&buf[0], "%02x", mac[0]);
sprintf(&buf[2], ":%02x", mac[1]);
sprintf(&buf[5], ":%02x", mac[2]);
sprintf(&buf[8], ":%02x", mac[3]);
sprintf(&buf[11], ":%02x", mac[4]);
sprintf(&buf[14], ":%02x", mac[5]);
}
/*******************************************************************************
*
* wrnad_monitor - wrnad monitor main loop
*
* This routine is the wrnad monitor main loop. It subscribes and listens to
* rtnetlink messages and acts upon them. Normally it never returns.
*
* RETURNS: 0 if exited normally, else -1.
*
* ERRNO: N/A
*/
int
wrnad_rtnl_monitor(int bus, int node, int port)
{
int rtfd, mipcfd, nfds, ret = 0;
unsigned int groups;
struct sockaddr_nl laddr;
fd_set rfds;
#if !defined(IPWRNAD) || defined(IPIPSEC2)
int pfkeyfd;
#endif /* !IPWRNAD || IPIPSEC2 */
#if !defined(IPWRNAD)
int ndp = -1;
#endif
/* Initialize */
wrnad_rtnl_init();
rtfd = mipcfd = -1;
#if !defined(IPWRNAD) || defined(IPIPSEC2)
/* Create the pfkey socket and set promiscuous mode */
pfkeyfd = wrnad_pfkey_open();
wrnad_pfkeyfd = pfkeyfd;
#ifdef IPIPSEC2
if (pfkeyfd < 0)
return -1;
#endif
#endif /* !IPWRNAD || IPIPSEC2 */
#if !defined(IPWRNAD)
ndp = wrnad_neigh_ndp_open();
#endif
/* Create the mipc socket and connect to peer */
mipcfd = wrnad_mipc_open(bus, node, port);
wrnad_mipcfd = mipcfd;
if (mipcfd < 0)
{
ret = -1;
goto exit;
}
/* Create the rtnetlink socket and bind to multicast groups */
groups = (RTMGRP_LINK
| RTMGRP_NEIGH
| RTMGRP_IPV4_IFADDR
| RTMGRP_IPV4_ROUTE
| RTMGRP_IPV6_IFADDR
| RTMGRP_IPV6_ROUTE);
rtfd = wrnad_rtnl_open(NETLINK_ROUTE, groups, &laddr);
wrnad_rtfd = rtfd;
if (rtfd < 0)
{
ret = -1;
goto exit;
}
/* Send a request to list all network interfaces */
wrnad_rtnl_send_request(rtfd, AF_UNSPEC, RTM_GETLINK);
while (!request_done)
wrnad_rtnl_recvfrom(rtfd, mipcfd);
/* Send a request to list all ip addresses */
wrnad_rtnl_send_request(rtfd, AF_UNSPEC, RTM_GETADDR);
while (!request_done)
wrnad_rtnl_recvfrom(rtfd, mipcfd);
/* Send a request to list all routes */
wrnad_rtnl_send_request(rtfd, AF_UNSPEC, RTM_GETROUTE);
while (!request_done)
wrnad_rtnl_recvfrom(rtfd, mipcfd);
/* Send a request to list all routes */
wrnad_rtnl_send_request(rtfd, AF_UNSPEC, RTM_GETNEIGH);
while (!request_done)
wrnad_rtnl_recvfrom(rtfd, mipcfd);
/* Enter main loop */
wrnad_log(LOG_INFO, "Entering monitoring loop.");
wrnad_mon_running = 1;
for (;;)
{
FD_ZERO(&rfds);
FD_SET(rtfd, &rfds);
#if !defined(IPWRNAD) || defined(IPIPSEC2)
if (pfkeyfd > 0)
FD_SET(pfkeyfd, &rfds);
#endif /* !IPWRNAD || IPIPSEC2 */
nfds = rtfd;
#if !defined(IPWRNAD) || defined(IPIPSEC2)
if (pfkeyfd > nfds)
nfds = pfkeyfd;
#endif
#if !defined(IPWRNAD)
if (-1 != ndp)
{
FD_SET(ndp, &rfds);
if (ndp > nfds)
nfds = ndp;
}
#endif
ret = select(nfds + 1, &rfds, NULL, NULL, NULL);
if (ret < 0)
{
wrnad_log(LOG_ERR, "select interrupted by error %s.", strerror(errno));
if (errno == EINTR || errno == EAGAIN)
continue;
ret = 0;
break;
}
else if (ret == 0)
{
wrnad_log(LOG_ERR, "select returned unexpected timeout", strerror(errno));
ret = -1;
goto exit;
}
if (FD_ISSET(rtfd, &rfds))
{
/* Receive messages on the rtnetlink socket */
if (wrnad_rtnl_recvfrom(rtfd, mipcfd) < 0)
{
ret = -1;
goto exit;
}
}
#if !defined(IPWRNAD)
if (-1 != ndp && FD_ISSET(ndp, &rfds))
wrnad_neigh_ndp_read(ndp, rtfd, recvbuf, sizeof(recvbuf));
#endif
#if !defined(IPWRNAD) || defined(IPIPSEC2)
if (FD_ISSET(pfkeyfd, &rfds))
{
/* Receive messages on the pfkey socket */
if (wrnad_pfkey_recv(pfkeyfd, mipcfd) < 0)
{
ret = -1;
goto exit;
}
}
#endif /* !IPWRNAD || IPIPSEC2 */
}
exit:
wrnad_mon_running = 0;
return ret;
}
void
wrnad_cleanup(void)
{
int i;
wrnad_mipc_close(wrnad_mipcfd);
wrnad_mipcfd = -1;
wrnad_rtnl_close(wrnad_rtfd);
wrnad_rtfd = -1;
#if !defined(IPWRNAD) || defined(IPIPSEC2)
wrnad_pfkey_close(wrnad_pfkeyfd);
wrnad_pfkeyfd = -1;
#endif /* !IPWRNAD || IPIPSEC2 */
#ifdef WRNAD_IDENTIFY_ROUTERS
for (i = 0; i<WRNAD_MAX_IF; i++)
{
if (wrnad_proxy_ifs[i].ifname[0] == '\0')
continue;
hash_table_destroy(&wrnad_proxy_ifs[i].v4_routers);
hash_table_destroy(&wrnad_proxy_ifs[i].v6_routers);
}
hash_item_pools_destroy();
#endif
}
#if !defined IPWRNAD
unsigned char
wrnad_af_xlat(unsigned int linux_af)
{
if (linux_af >= AF_MAX)
return (unsigned char)255;
return af_xlat[linux_af];
}
#endif /* !defined WRNAD */