1171 lines
33 KiB
C
1171 lines
33 KiB
C
/* oldRouteLib.c - Maintain backward compatibility with obsolete API */
|
|
|
|
/* Copyright 2004 - 2005, 2008 Wind River Systems, Inc. */
|
|
#include "copyright_wrs.h"
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
01q,25apr12,ggz Fix for WIND00346438. mRouteAdd() should add a static route
|
|
01p,19dec11,h_x Back port to 6.9.2.1 for WIND00310113
|
|
01o,29sep10,h_x Fix build and coverity warnings
|
|
01n,21jun10,h_x Fix WIND00217113
|
|
01m,02dec08,spw Fix WIND00143199
|
|
01l,03oct08,spw Fix WIND00135680
|
|
01k,31may08,spw Resolve warnings
|
|
01j,18jan08,brk ported to ipnet, moved in ifRoute* from ifLib
|
|
01i,24feb05,spm removed unneeded route format values and macros (SPR #100995)
|
|
01h,24feb05,spm performance updates and code cleanup (SPR #100995)
|
|
01g,12jan05,vvv osdep.h cleanup
|
|
01f,04oct04,niq translate unspecified protocol to the default. Fix
|
|
documentation.
|
|
01e,17sep04,niq Scale out routing sockets
|
|
01d,23aug04,rp merged from COMP_WN_IPV6_BASE6_ITER5_TO_UNIFIED_PRE_MERGE
|
|
01c,12aug04,spm fixed default route creation (SPR #99683)
|
|
01b,28may04,niq Merging from base6 label POST_ITER5_FRZ16_REBASE
|
|
01a,18feb04,rae Written
|
|
*/
|
|
|
|
/*
|
|
DESCRIPTION
|
|
This library implements a set of APIs, some of which are obsolete. This
|
|
library should only be included when necessary. All new code should use the
|
|
Routing Sockets interface.
|
|
|
|
This library contains routines for inspecting the routing table,
|
|
as well as routines for adding and deleting routes from that table.
|
|
If you do not configure VxWorks to include a routing protocol, such
|
|
as RIP or OSPF, you can use these routines to maintain the routing
|
|
tables manually.
|
|
|
|
To use this feature, include the following component:
|
|
INCLUDE_OLDROUTE
|
|
|
|
INCLUDE FILES: routeLib.h
|
|
|
|
SEE ALSO: hostLib
|
|
*/
|
|
|
|
#include <vxWorks.h>
|
|
#include <logLib.h>
|
|
#include <net/mbuf.h>
|
|
#include <sys/socket.h>
|
|
#include <sockLib.h>
|
|
#include <unistd.h>
|
|
#include <net/if.h>
|
|
#include <net/route.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/ioctl.h>
|
|
#include <inetLib.h>
|
|
#include <errno.h>
|
|
#include <errnoLib.h>
|
|
#include <hostLib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ioLib.h>
|
|
#include "routeLib.h"
|
|
#include <m2Lib.h>
|
|
#include <taskLib.h>
|
|
|
|
#include <version.h>
|
|
|
|
|
|
#include <ipcom_sock.h>
|
|
#include <ipnet_routesock.h>
|
|
#include <ipcom_sysctl.h>
|
|
#include <ipcom_clib.h>
|
|
extern void
|
|
ipnet_cmd_init_addrs(void *msg, Ip_u32 addrs, struct Ip_sockaddr **sas);
|
|
|
|
LOCAL BOOL routeExistsOnIf(Ip_u32 addr, char *buf, BOOL exactMatch);
|
|
LOCAL BOOL routeExistsInTable(Ip_u32 addr);
|
|
|
|
/*
|
|
* The gateway address may be a struct Ip_sockaddr_dl, which we assume
|
|
* is no larger than 64 bytes.
|
|
*/
|
|
#define MAX_GW_LEN 64
|
|
#define RTM_BUFSIZE \
|
|
(sizeof(struct Ipnet_rt_msghdr) + 2 * sizeof(struct Ip_sockaddr) + MAX_GW_LEN)
|
|
|
|
#ifndef TOS_SET
|
|
#define TOS_SET(pSockaddr, tosVal) \
|
|
(((struct Ipnet_sockaddr_rt *)(pSockaddr))->srt_tos = tosVal)
|
|
#endif
|
|
|
|
#ifndef RT_PROTO_SET
|
|
#define RT_PROTO_SET(pSockaddr, proto) \
|
|
(((struct Ipnet_sockaddr_rt *)(pSockaddr))->srt_proto = proto)
|
|
#endif
|
|
|
|
#undef SAI
|
|
#define SAI(x) ((struct Ip_sockaddr_in *)(x))
|
|
|
|
#undef SA
|
|
#define SA(x) ((struct Ip_sockaddr *)(x))
|
|
|
|
/* LOCAL function */
|
|
|
|
LOCAL STATUS routeCmdExecute(int cmd, Ip_u32 dstAddr, Ip_u32 netmask,
|
|
Ip_u32 gateway, int tos, int flags, int proto,
|
|
int if_index);
|
|
|
|
/* subnet unaware version (sigh!) */
|
|
LOCAL u_long in_netof
|
|
(
|
|
struct in_addr in
|
|
)
|
|
{
|
|
|
|
register u_long net;
|
|
register u_long i = ntohl(in.s_addr);
|
|
|
|
if (IN_CLASSA(i))
|
|
net = i & IN_CLASSA_NET;
|
|
else if (IN_CLASSB(i))
|
|
net = i & IN_CLASSB_NET;
|
|
else if (IN_CLASSC(i))
|
|
net = i & IN_CLASSC_NET;
|
|
else if (IN_CLASSD(i))
|
|
net = i & IN_CLASSD_NET;
|
|
else
|
|
return (0);
|
|
|
|
return (net);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* oldRouteLibInit - do nothing, but ensure linkage
|
|
*
|
|
* This routine does nothing, but if called will link in this library.
|
|
*
|
|
* NOMANUAL
|
|
*
|
|
* RETURNS: nothing
|
|
*/
|
|
|
|
void oldRouteLibInit (void)
|
|
{
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* routeAdd - add a route
|
|
*
|
|
* This routine adds gateways to the network routing tables.
|
|
* It is called from a VxWorks machine that needs
|
|
* to establish a gateway to a destination network (or machine).
|
|
*
|
|
* You can specify both <destination> and <gateway> in standard Internet
|
|
* address format (for example, 90.0.0.2), or you can specify them using
|
|
* their host names, as specified with hostAdd().
|
|
*
|
|
* This routine can be used to add multiple routes to the same destination
|
|
* differing by the gateway.
|
|
*
|
|
* EXAMPLE
|
|
* Consider the following example:
|
|
* .CS
|
|
* -> routeAdd "90.0.0.0", "gate"
|
|
* .CE
|
|
* This call tells VxWorks that the machine with the host name "gate" is
|
|
* the gateway to network 90.0.0.0. The host "gate" must already have
|
|
* been created by hostAdd().
|
|
*
|
|
* Consider the following example:
|
|
* .CS
|
|
* -> routeAdd "90.0.0.0", "91.0.0.3"
|
|
* .CE
|
|
* This call tells VxWorks that the machine with the Internet
|
|
* address 91.0.0.3 is the gateway to network 90.0.0.0.
|
|
*
|
|
* Consider the following example:
|
|
* .CS
|
|
* -> routeAdd "destination", "gate"
|
|
* .CE
|
|
* This call tells VxWorks that the machine with the host name "gate" is
|
|
* the gateway to the machine named "destination". The host names "gate" and
|
|
* "destination" must already have been created by hostAdd().
|
|
*
|
|
* Consider the following example:
|
|
* .CS
|
|
* -> routeAdd "0", "gate"
|
|
* .CE
|
|
* This call tells VxWorks that the machine with the host name "gate" is
|
|
* the default gateway. The host "gate" must already have been created
|
|
* by hostAdd(). A default gateway is where Internet Protocol (IP)
|
|
* datagrams are routed when there is no specific routing table entry
|
|
* available for the destination IP network or host.
|
|
*
|
|
* DEPRECATED
|
|
* This routine uses the old class-based addresses and does not support
|
|
* CIDR. Use mRouteAdd() or routec() instead.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
STATUS routeAdd
|
|
(
|
|
char *destination, /* inet addr or name of route destination */
|
|
char *gateway /* inet addr or name of gateway to destination */
|
|
)
|
|
{
|
|
return (routeNetAdd (destination, gateway));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* routeNetAdd - add a route to a destination that is a network
|
|
*
|
|
* This routine is equivalent to routeAdd(), except that the destination
|
|
* address is assumed to be a network. This is useful for adding a route
|
|
* to a sub-network that is not on the same overall network as the
|
|
* local network.
|
|
*
|
|
* This routine can be used to add multiple routes to the same destination
|
|
* differing by the gateway.
|
|
*
|
|
* DEPRECATED
|
|
* This routine uses the old class-based addresses and does not support
|
|
* CIDR. Use mRouteAdd() or routec() instead.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*/
|
|
|
|
STATUS routeNetAdd
|
|
(
|
|
char *destination, /* inet addr or name of network destination */
|
|
char *gateway /* inet addr or name of gateway to destination */
|
|
)
|
|
{
|
|
struct in_addr dst; /* destnation address */
|
|
struct in_addr gate; /* gateway address */
|
|
Ip_u32 dstSubnet; /* destination subnet */
|
|
Ip_u32 gateSubnet; /* gateway subnet */
|
|
Ip_u32 netmask;
|
|
Ip_u32 dstAddr;
|
|
int flags;
|
|
int tos;
|
|
int proto;
|
|
int ifIndex;
|
|
char ifName[IP_IFNAMSIZ];
|
|
int sock;
|
|
struct Ip_sockaddr_in *addrp;
|
|
Ip_u32 ifSubnet;
|
|
Ip_u32 ifAddr;
|
|
Ip_u32 ifMask;
|
|
struct Ip_ifreq ifreq;
|
|
|
|
flags = RTF_STATIC;
|
|
tos = 0;
|
|
proto = M2_ipRouteProto_other;
|
|
ifIndex = 0;
|
|
|
|
if (destination == NULL || gateway == NULL)
|
|
return (ERROR);
|
|
|
|
if (inet_aton (destination, &dst) == ERROR)
|
|
return (ERROR);
|
|
|
|
if (inet_aton (gateway, &gate) == ERROR)
|
|
return (ERROR);
|
|
|
|
/* dstSubnet and gateSubnet are in host byte order */
|
|
|
|
dstSubnet = (int)in_netof (dst);
|
|
gateSubnet = (int)in_netof (gate);
|
|
dstAddr = (int)ntohl (dst.s_addr);
|
|
|
|
/*
|
|
* If the destination is a host in the same subnet then reject the
|
|
* route. A destination is a host in the same subnet if it has the
|
|
* same subnet number as the gateway and if the destination is not
|
|
* the subnet itself (route to the subnet).
|
|
*/
|
|
|
|
if ((dstSubnet == gateSubnet) && (dstSubnet != dstAddr))
|
|
{
|
|
logMsg ("Destination %s and gateway %s are both in same subnet\n",
|
|
(_Vx_usr_arg_t)destination,
|
|
(_Vx_usr_arg_t)gateway,
|
|
(_Vx_usr_arg_t)0,
|
|
(_Vx_usr_arg_t)0,
|
|
(_Vx_usr_arg_t)0,
|
|
(_Vx_usr_arg_t)0);
|
|
return (ERROR);
|
|
}
|
|
|
|
if (inet_lnaof ((int)(dst.s_addr)) == 0) /* host portion is zero */
|
|
{
|
|
if (dstAddr == 0) /* Default route */
|
|
netmask = 0;
|
|
else if (IN_CLASSA (dstAddr))
|
|
netmask = IN_CLASSA_NET;
|
|
else if (IN_CLASSB (dstAddr))
|
|
netmask = IN_CLASSB_NET;
|
|
else if (IN_CLASSC (dstAddr))
|
|
netmask = IN_CLASSC_NET;
|
|
else if (IN_CLASSD (dstAddr))
|
|
netmask = IN_CLASSD_NET; /* XXX ??? */
|
|
else
|
|
return ERROR;
|
|
}
|
|
else /* Host route */
|
|
netmask = 0;
|
|
|
|
/* If we can reach the gateway address through one of the interfaces,
|
|
* it's possible that we'll have to do some work to add specific routes
|
|
* to the table for the interface address / subnet. Normally this
|
|
* would not be the case, as these routes are added automatically
|
|
* when and interface is brought up. However, it's possible that
|
|
* these routes can be deleted via APIs such as ifAllRoutesDelete.
|
|
* If this is the case, we need to add them back in for compatibility
|
|
* with the coreip stack.
|
|
*/
|
|
|
|
if (routeExistsOnIf(gate.s_addr, ifName, FALSE) == TRUE)
|
|
{
|
|
if ((sock = ipcom_socket (AF_INET, SOCK_RAW, 0)) < 0)
|
|
return ERROR;
|
|
|
|
strcpy(ifreq.ifr_name, ifName);
|
|
|
|
if (ipcom_socketioctl(sock, IP_SIOCGIFADDR,(char *)&ifreq) < 0)
|
|
{
|
|
ipcom_socketclose(sock);
|
|
return ERROR;
|
|
}
|
|
|
|
addrp = (struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr;
|
|
ifAddr = addrp->sin_addr.s_addr;
|
|
|
|
/* Grab the netmask for this interface */
|
|
|
|
if (ipcom_socketioctl(sock, IP_SIOCGIFNETMASK,(char *)&ifreq) < 0)
|
|
{
|
|
ipcom_socketclose(sock);
|
|
return ERROR;
|
|
}
|
|
|
|
addrp = (struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr;
|
|
ifMask = addrp->sin_addr.s_addr;
|
|
|
|
/* Get the subnet of this interface */
|
|
|
|
ifSubnet = gate.s_addr & ifMask;
|
|
|
|
ipcom_socketclose(sock);
|
|
|
|
/* If the interface address is not in the route table,
|
|
* add it in, passing through the loopback interface
|
|
*/
|
|
|
|
if (routeExistsInTable(ifAddr) == FALSE)
|
|
{
|
|
ifIndex = (int)ipcom_if_nametoindex("lo0");
|
|
if (ifIndex == 0)
|
|
{
|
|
ipcom_socketclose(sock);
|
|
return ERROR;
|
|
}
|
|
|
|
if (routeCmdExecute (RTM_ADD, ifAddr, 0, 0, 0,
|
|
IPNET_RTF_HOST,
|
|
M2_ipRouteProto_other, ifIndex) != OK)
|
|
{
|
|
logMsg ("Couldn't add host route through ifIndex %d.\n",
|
|
ifIndex, 0, 0, 0, 0, 0);
|
|
ipcom_socketclose(sock);
|
|
return ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ifIndex = (int)ipcom_if_nametoindex(ifName);
|
|
}
|
|
|
|
if (ifSubnet == htonl(dstSubnet))
|
|
{
|
|
ifIndex = (int)ipcom_if_nametoindex(ifName);
|
|
if (ifIndex == 0)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
gate.s_addr = 0;
|
|
dst.s_addr = (in_addr_t)ifSubnet;
|
|
flags = (IPNET_RTF_CLONING | IPNET_RTF_MASK);
|
|
netmask = ntohl(ifMask);
|
|
}
|
|
}
|
|
|
|
return (routeCmdExecute (RTM_ADD, dst.s_addr, htonl (netmask),
|
|
gate.s_addr, tos, flags, M2_ipRouteProto_other, ifIndex));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* routeDelete - delete a route
|
|
*
|
|
* This routine deletes a specified route from the network routing tables.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* DEPRECATED
|
|
* This routine uses the old class-based addresses and does not support
|
|
* CIDR. Use mRouteDelete() or routec() instead.
|
|
*
|
|
* SEE ALSO: routeAdd()
|
|
*/
|
|
|
|
STATUS routeDelete
|
|
(
|
|
char *destination, /* inet addr or name of route destination */
|
|
char *gateway /* inet addr or name of gateway to destination */
|
|
)
|
|
{
|
|
Ip_u32 destIp;
|
|
Ip_u32 gateIp;
|
|
Ip_u32 netmask;
|
|
Ip_u32 dstAddr;
|
|
int flags;
|
|
|
|
if (((destIp = (Ip_u32)inet_addr (destination)) == (Ip_u32)ERROR) ||
|
|
((gateIp = (Ip_u32)inet_addr (gateway)) == (Ip_u32)ERROR))
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
dstAddr = (Ip_u32)ntohl (destIp);
|
|
|
|
if (inet_lnaof (destIp) == 0) /* host portion is zero */
|
|
{
|
|
if (dstAddr == 0) /* Default route */
|
|
netmask = 0;
|
|
else if (IN_CLASSA (dstAddr))
|
|
netmask = IN_CLASSA_NET;
|
|
else if (IN_CLASSB (dstAddr))
|
|
netmask = IN_CLASSB_NET;
|
|
else if (IN_CLASSC (dstAddr))
|
|
netmask = IN_CLASSC_NET;
|
|
else if (IN_CLASSD (dstAddr))
|
|
netmask = IN_CLASSD_NET; /* XXX ??? */
|
|
else
|
|
return ERROR;
|
|
|
|
flags = 0;
|
|
}
|
|
else
|
|
{
|
|
netmask = 0;
|
|
flags = RTF_HOST;
|
|
}
|
|
|
|
flags |= RTF_STATIC;
|
|
return (routeCmdExecute (RTM_DELETE, destIp, htonl (netmask),
|
|
gateIp, 0, flags, M2_ipRouteProto_other, 0));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* mRouteAdd - add multiple routes to the same destination
|
|
*
|
|
* This routine is similar to routeAdd(), except that you can use multiple
|
|
* mRouteAdd() calls to add multiple routes to the same location. Use
|
|
* <pDest> to specify the destination, <pGate> to specify the gateway to
|
|
* that destination, <mask> to specify destination mask, and <tos> to specify
|
|
* the type of service. For <tos>, netinet/ip.h defines the following
|
|
* constants as valid values:
|
|
*
|
|
* IPTOS_LOWDELAY
|
|
* IPTOS_THROUGHPUT
|
|
* IPTOS_RELIABILITY
|
|
* IPTOS_MINCOST
|
|
*
|
|
* Use <flags> to specify flags you want to associate with this entry.
|
|
* Valid values for <flags> are 0, RTF_HOST and RTF_CLONING (defined in
|
|
* net/route.h).
|
|
*
|
|
* To add a host route you should specify a <mask> value of 0. <flags> can
|
|
* be set to RTF_HOST or left as zero.
|
|
*
|
|
* EXAMPLE
|
|
* To add a default route through 91.0.0.3:
|
|
* .CS
|
|
* -> mRouteAdd ("0.0.0.0", "91.0.0.3", 0, 0, 0);
|
|
* .CE
|
|
*
|
|
* To add a host route through 91.0.0.3:
|
|
* .CS
|
|
* -> mRouteAdd ("20.0.0.1", "91.0.0.3", 0, 0, 0);
|
|
* .CE
|
|
*
|
|
* To add a route to the 90.0.0.0 network through 91.0.0.3:
|
|
* .CS
|
|
* -> mRouteAdd ("90.0.0.0", "91.0.0.3", 0xffffff00, 0, 0);
|
|
* .CE
|
|
*
|
|
* Using mRouteAdd(), you could create multiple routes to the same destination.
|
|
* VxWorks would distinguish among these routes based on factors such as the
|
|
* netmask or the type of service. Thus, it is perfectly legal to say:
|
|
* .CS
|
|
* -> mRouteAdd ("90.0.0.0", "91.0.0.3", 0xffffff00, 0, 0);
|
|
*
|
|
* -> mRouteAdd ("90.0.0.0", "91.0.0.254", 0xffff0000, 0, 0);
|
|
* .CE
|
|
* This adds two routes to the same network, "90.0.0.0", that go by two
|
|
* different gateways. The differentiating factor is the netmask.
|
|
*
|
|
* This routine adds a route of type `M2_ipRouteProto_other', which is a
|
|
* static route. This route will not be modified or deleted until a
|
|
* call to mRouteDelete() removes it.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* SEE ALSO: mRouteEntryAdd(), mRouteDelete(), routeAdd()
|
|
*/
|
|
|
|
STATUS mRouteAdd
|
|
(
|
|
char * pDest, /* destination addr in internet dot notation */
|
|
char * pGate, /* gateway address in internet dot notation */
|
|
Ip_u32 mask, /* mask for destination */
|
|
int tos, /* type of service */
|
|
int flags /* route flags */
|
|
)
|
|
{
|
|
Ip_u32 destIp;
|
|
Ip_u32 gateIp;
|
|
|
|
if (((destIp = (Ip_u32)inet_addr (pDest)) == (Ip_u32)ERROR) ||
|
|
((gateIp = (Ip_u32)inet_addr (pGate)) == (Ip_u32)ERROR))
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
mask = htonl (mask);
|
|
flags |= RTF_STATIC;
|
|
|
|
return (mRouteEntryAdd (destIp, gateIp, mask, tos, flags,
|
|
M2_ipRouteProto_other));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* mRouteEntryAdd - add a protocol-specific route to the routing table
|
|
*
|
|
* For a single destination <destIp>, this routine can add additional
|
|
* routes <gateIp> to the routing table. The different routes are
|
|
* distinguished by the gateway, a destination mask <mask>,
|
|
* the type of service <tos> and associated flag values <flags>.
|
|
* Valid values for <flags> are 0, RTF_HOST, RTF_CLONING (defined in net/route.h).
|
|
* To add a host route you should specify a <mask> value of 0. <flags> can
|
|
* be set to RTF_HOST or left as zero.
|
|
*
|
|
* The <proto> parameter identifies the protocol that generated this route.
|
|
* Values for <proto> may be found in m2Lib.h. The <tos> parameter takes one of
|
|
* following values (defined in netinet/ip.h):
|
|
*
|
|
* IPTOS_LOWDELAY
|
|
* IPTOS_THROUGHPUT
|
|
* IPTOS_RELIABILITY
|
|
* IPTOS_MINCOST
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* SEE ALSO: m2Lib.h, mRouteAdd(), mRouteDelete()
|
|
*/
|
|
|
|
STATUS mRouteEntryAdd
|
|
(
|
|
Ip_u32 destIp, /* destination address, network order */
|
|
Ip_u32 gateIp, /* gateway address, network order */
|
|
Ip_u32 mask, /* mask for destination, network order */
|
|
int tos, /* type of service */
|
|
int flags, /* route flags */
|
|
int proto /* routing protocol */
|
|
)
|
|
{
|
|
int rtflags;
|
|
int sock;
|
|
Ip_u32 ifIndex;
|
|
int netmask;
|
|
char ifName[IP_IFNAMSIZ];
|
|
struct Ip_sockaddr_in *addrp;
|
|
Ip_u32 ifAddr;
|
|
Ip_u32 ifSubnet;
|
|
Ip_u32 ifMask;
|
|
struct Ip_ifreq ifreq;
|
|
|
|
rtflags = flags;
|
|
netmask = (int)mask;
|
|
ifIndex = 0;
|
|
|
|
if (mask != 0)
|
|
{
|
|
/* For a host route, require a 0 mask */
|
|
|
|
if (flags & RTF_HOST)
|
|
return (ERROR);
|
|
|
|
/* Mask the destination address with the netmask */
|
|
|
|
destIp &= mask;
|
|
}
|
|
|
|
if (gateIp)
|
|
{
|
|
/* If we can reach the gateway address through one of the interfaces,
|
|
* it's possible that we'll have to do some work to add specific routes
|
|
* to the table for the interface address / subnet. Normally this
|
|
* would not be the case, as these routes are added automatically
|
|
* when and interface is brought up. However, it's possible that
|
|
* these routes can be deleted via APIs such as ifAllRoutesDelete.
|
|
* If this is the case, we need to add them back in for compatibility
|
|
* with the coreip stack.
|
|
*/
|
|
|
|
if (routeExistsOnIf(gateIp, ifName, FALSE) == TRUE)
|
|
{
|
|
|
|
if ((sock = ipcom_socket (AF_INET, SOCK_RAW, 0)) < 0)
|
|
return ERROR;
|
|
|
|
strcpy(ifreq.ifr_name, ifName);
|
|
|
|
if (ipcom_socketioctl(sock, IP_SIOCGIFADDR,(char *)&ifreq) < 0)
|
|
{
|
|
ipcom_socketclose(sock);
|
|
return ERROR;
|
|
}
|
|
|
|
addrp = (struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr;
|
|
ifAddr = addrp->sin_addr.s_addr;
|
|
|
|
/* Grab the netmask for this interface */
|
|
|
|
if (ipcom_socketioctl(sock, IP_SIOCGIFNETMASK,(char *)&ifreq) < 0)
|
|
{
|
|
ipcom_socketclose(sock);
|
|
return ERROR;
|
|
}
|
|
|
|
addrp = (struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr;
|
|
ifMask = addrp->sin_addr.s_addr;
|
|
|
|
/* Get the subnet of this interface */
|
|
|
|
ifSubnet = gateIp & ifMask;
|
|
|
|
ipcom_socketclose(sock);
|
|
|
|
/* If the interface address is not in the route table,
|
|
* add it in, passing through the loopback interface
|
|
*/
|
|
|
|
if (routeExistsInTable((int)ifAddr) == FALSE)
|
|
{
|
|
ifIndex = ipcom_if_nametoindex("lo0");
|
|
if (ifIndex == 0)
|
|
{
|
|
ipcom_socketclose(sock);
|
|
return ERROR;
|
|
}
|
|
|
|
if (routeCmdExecute (RTM_ADD, ifAddr, 0, 0, 0,
|
|
IPNET_RTF_HOST,
|
|
M2_ipRouteProto_other, (int)ifIndex) != OK)
|
|
{
|
|
logMsg ("Couldn't add host route through ifIndex %d.\n",
|
|
(_Vx_usr_arg_t)ifIndex,
|
|
(_Vx_usr_arg_t)0,
|
|
(_Vx_usr_arg_t)0,
|
|
(_Vx_usr_arg_t)0,
|
|
(_Vx_usr_arg_t)0,
|
|
(_Vx_usr_arg_t)0);
|
|
ipcom_socketclose(sock);
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
if (ifSubnet == destIp)
|
|
{
|
|
ifIndex = ipcom_if_nametoindex(ifName);
|
|
if (ifIndex == 0)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
gateIp = 0;
|
|
destIp = ifSubnet;
|
|
rtflags = (IPNET_RTF_CLONING | IPNET_RTF_MASK);
|
|
netmask = ifMask;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* A protocol value of 0 is not valid for route creation.
|
|
* If we do get this value, convert it to the default protocol.
|
|
* This helps support non-proto aware applications without any change.
|
|
* Note that a 0 value is valid for route deletion and specifies any
|
|
* matching route.
|
|
*/
|
|
|
|
if (proto == 0)
|
|
proto = M2_ipRouteProto_other;
|
|
|
|
return (routeCmdExecute (RTM_ADD, destIp, netmask, gateIp, tos, rtflags,
|
|
proto, ifIndex));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* mRouteDelete - delete a route from the routing table
|
|
*
|
|
* This routine deletes a routing table entry as specified by the
|
|
* destination, <pDest>, the destination mask, <mask>, and type of service,
|
|
* <tos>. The <tos> values are as defined in the reference entry for
|
|
* mRouteAdd().
|
|
*
|
|
* EXAMPLE
|
|
* Consider the case of a route added in the following manner:
|
|
* .CS
|
|
* -> mRouteAdd ("90.0.0.0", "91.0.0.3", 0xffffff00, 0, 0);
|
|
* .CE
|
|
* To delete a route that was added in the above manner, call mRouteDelete()
|
|
* as follows:
|
|
* .CS
|
|
* -> mRouteDelete("90.0.0.0", 0xffffff00, 0);
|
|
* .CE
|
|
*
|
|
* If the netmask and or type of service do not match, the route
|
|
* is not deleted.
|
|
*
|
|
* The valid value for <flags> is RTF_HOST for host routes or 0.
|
|
*
|
|
* To delete a host route you should specify a <mask> value of 0. <flags> can
|
|
* be set to RTF_HOST or left as zero.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* SEE ALSO: mRouteAdd()
|
|
*/
|
|
|
|
STATUS mRouteDelete
|
|
(
|
|
char * pDest, /* destination address */
|
|
Ip_u32 mask, /* mask for destination */
|
|
int tos, /* type of service */
|
|
int flags /* either 0 or RTF_HOST */
|
|
)
|
|
{
|
|
Ip_u32 destIp;
|
|
|
|
if ((destIp = (Ip_u32)inet_addr (pDest)) == (Ip_u32)ERROR)
|
|
{
|
|
return (ERROR);
|
|
}
|
|
|
|
mask = htonl (mask);
|
|
return (mRouteEntryDelete (destIp, 0, mask, tos, flags, 0));
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* mRouteEntryDelete - delete route from the routing table
|
|
*
|
|
* This routine deletes a protocol-specific route from the routing
|
|
* table. Specify the route using a destination <pDest>, a gateway <pGate>,
|
|
* a destination mask <mask>, the type of service <tos>, a <flags> value,
|
|
* and a <proto> value that identifies the routing protocol that added the
|
|
* route. The valid values for <flags> are 0 and RTF_HOST (defined
|
|
* in net/route.h). Values for <proto> may be found in m2Lib.h and <tos>
|
|
* is one of the following values defined in netinet/ip.h:
|
|
*
|
|
* IPTOS_LOWDELAY
|
|
* IPTOS_THROUGHPUT
|
|
* IPTOS_RELIABILITY
|
|
* IPTOS_MINCOST
|
|
*
|
|
* An existing route is deleted only if it is owned by the protocol specified
|
|
* by <proto>.
|
|
*
|
|
* To delete a host route you should specify a <mask> value of 0. <flags> can
|
|
* be set to RTF_HOST or left as zero.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
*/
|
|
|
|
STATUS mRouteEntryDelete
|
|
(
|
|
Ip_u32 destIp, /* destination address, network order */
|
|
Ip_u32 gateIp, /* gateway address, network order */
|
|
Ip_u32 mask, /* mask for destination, network order */
|
|
int tos, /* type of service */
|
|
int flags, /* route flags */
|
|
int proto /* routing protocol */
|
|
)
|
|
{
|
|
if (mask != 0)
|
|
{
|
|
/* For a host route, require a 0 mask */
|
|
|
|
if (flags & RTF_HOST)
|
|
return (ERROR);
|
|
|
|
/* Mask the destination address with the netmask */
|
|
|
|
destIp &= mask;
|
|
}
|
|
|
|
return (routeCmdExecute (RTM_DELETE, destIp, mask, gateIp,
|
|
tos, flags, proto, 0));
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* routeRtmSendReply - send a routing command and wait for reply
|
|
*
|
|
* ipnet adaptation support routine
|
|
*
|
|
* RETURNS: N/A
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
LOCAL STATUS routeRtmSendReply
|
|
(
|
|
int sock,
|
|
int index,
|
|
char type,
|
|
struct Ipnet_rt_msghdr * rtm,
|
|
Ip_u32 dstAddr, /* destination address (IPv4 only) */
|
|
Ip_u32 netmask, /* IPv4 prefix length */
|
|
struct Ip_sockaddr * gw, /* gateway address */
|
|
int flags /* route flags */
|
|
)
|
|
{
|
|
int seq;
|
|
struct Ip_sockaddr_in *net;
|
|
struct Ip_sockaddr_in *mask;
|
|
struct Ip_sockaddr_in *gate;
|
|
struct Ip_sockaddr_in *gwp;
|
|
int sa_len;
|
|
|
|
int err;
|
|
ssize_t size = sizeof(struct Ipnet_rt_msghdr);
|
|
IP_TASK_ID pid = taskIdSelf();
|
|
seq = (int)ipcom_random();
|
|
ipcom_memset (rtm, 0, RTM_BUFSIZE);
|
|
rtm->rtm_version = (Ip_u16)IPNET_RTM_VERSION;
|
|
rtm->rtm_msglen = (Ip_u16)size;
|
|
rtm->rtm_type = type;
|
|
rtm->rtm_pid = (Ip_pid_t)pid;
|
|
rtm->rtm_seq = seq;
|
|
rtm->rtm_index = index;
|
|
rtm->rtm_flags = flags;
|
|
|
|
net = (struct Ip_sockaddr_in *) (rtm + 1);
|
|
|
|
net->sin_len = sizeof (struct sockaddr_in);
|
|
rtm->rtm_msglen = (Ip_u16)(rtm->rtm_msglen + (net->sin_len));
|
|
net->sin_family = AF_INET;
|
|
net->sin_addr.s_addr = dstAddr;
|
|
rtm->rtm_addrs |= IPNET_RTA_DST;
|
|
|
|
gate = (struct Ip_sockaddr_in *) (net + 1);
|
|
gwp = (struct Ip_sockaddr_in *)gw;
|
|
|
|
if (gwp != NULL && gwp->sin_addr.s_addr)
|
|
{
|
|
sa_len = (int)(gw->sa_len ? IP_ROUNDUP(gw->sa_len, sizeof(Ip_u32))
|
|
: sizeof(Ip_u32));
|
|
|
|
if (sa_len > MAX_GW_LEN)
|
|
{
|
|
errnoSet (EINVAL);
|
|
return ERROR;
|
|
}
|
|
|
|
ipcom_memcpy(gate, gw, (size_t)sa_len);
|
|
|
|
rtm->rtm_msglen = (Ip_u16)(rtm->rtm_msglen + sa_len);
|
|
rtm->rtm_addrs |= IPNET_RTA_GATEWAY;
|
|
|
|
mask = (struct Ip_sockaddr_in *) ((char *)gate + sa_len);
|
|
}
|
|
else
|
|
mask = gate;
|
|
|
|
if (type == RTM_ADD)
|
|
{
|
|
rtm->rtm_flags |= IPNET_RTF_UP | IPNET_RTF_DONE;
|
|
rtm->rtm_rmx.rmx_expire = IPCOM_ADDR_INFINITE;
|
|
|
|
if ( dstAddr && netmask == 0)
|
|
{
|
|
rtm->rtm_flags |= RTF_HOST;
|
|
}
|
|
else if (gwp != NULL && gwp->sin_addr.s_addr)
|
|
{
|
|
rtm->rtm_flags |= IPNET_RTF_GATEWAY;
|
|
}
|
|
}
|
|
|
|
if ( ! (rtm->rtm_flags & RTF_HOST))
|
|
{
|
|
mask->sin_len = sizeof (struct sockaddr_in);
|
|
rtm->rtm_msglen = (Ip_u16)(rtm->rtm_msglen + mask->sin_len);
|
|
mask->sin_family = AF_INET;
|
|
mask->sin_addr.s_addr = netmask;
|
|
rtm->rtm_addrs |= IPNET_RTA_NETMASK;
|
|
}
|
|
|
|
err = (int)ipcom_send(sock, (const char *)rtm, rtm->rtm_msglen, 0);
|
|
if (err < 0)
|
|
{
|
|
return ERROR;
|
|
}
|
|
do
|
|
{
|
|
size = ipcom_recv(sock, (char *)rtm, (Ip_size_t)(RTM_BUFSIZE), MSG_DONTWAIT);
|
|
if (size < 0)
|
|
{
|
|
return ERROR;
|
|
}
|
|
}
|
|
while (rtm->rtm_type != type || rtm->rtm_seq != seq || rtm->rtm_pid != (Ip_pid_t)pid);
|
|
|
|
if (rtm->rtm_errno != 0)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* routeCmdExecute - execute the specified routing command
|
|
*
|
|
* The <msgtype> parameter corresponds to the routing operation to
|
|
* perform. The value of RTM_ADD (1) creates a route, and RTM_DELETE (2)
|
|
* deletes an existing route. The <dstAddr> parameter specifies the
|
|
* IPv4 destination address for the route.
|
|
*
|
|
* The <gateway> parameter usually must specify a valid gateway address
|
|
* directly reachable through a network interface.
|
|
*
|
|
* The <netmask> parameter contains the netmask for the new (or
|
|
* existing) route's netmask. A netmask value of 0 signifies a host route
|
|
* unless <dstAddr> is also zero, which specifies a default route.
|
|
*
|
|
* All the addresses are specified in network byte order
|
|
*
|
|
* The routeCmdExecute() routine calls the underlying routing API to
|
|
* perform the specified operation.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
|
|
LOCAL STATUS routeCmdExecute
|
|
(
|
|
int cmd, /* routing operation */
|
|
Ip_u32 dstAddr, /* destination address (IPv4 only) */
|
|
Ip_u32 netmask, /* IPv4 prefix length */
|
|
Ip_u32 gateway, /* gateway address (IPv4 only) */
|
|
int tos, /* type of service * ignored * */
|
|
int flags, /* route flags */
|
|
int proto, /* routing protocol * ignored * */
|
|
int if_index
|
|
)
|
|
{
|
|
int sock, status;
|
|
struct Ipnet_rt_msghdr * rtm;
|
|
struct Ip_sockaddr_in gw;
|
|
|
|
if ((sock = ipcom_socket(AF_ROUTE, SOCK_RAW, 0)) < 0)
|
|
return (ERROR);
|
|
|
|
rtm = (struct Ipnet_rt_msghdr *)ipcom_malloc(RTM_BUFSIZE);
|
|
|
|
if (rtm == IP_NULL)
|
|
{
|
|
ipcom_socketclose (sock);
|
|
return ERROR;
|
|
}
|
|
|
|
ipcom_memset (&gw, 0, sizeof (gw));
|
|
gw.sin_family = AF_INET;
|
|
gw.sin_len = sizeof (gw);
|
|
gw.sin_addr.s_addr = (Ip_u32)gateway;
|
|
|
|
status = routeRtmSendReply(sock, if_index, (char)cmd, rtm, dstAddr,
|
|
netmask, SA(&gw), flags);
|
|
ipcom_socketclose(sock);
|
|
ipcom_free(rtm);
|
|
return status;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* routeExistsOnIf- Determine whether the address exists on an enabled interface
|
|
*
|
|
* The <addr> parameter corresponds to an address to check.
|
|
* The <buf> parameter corresponds to a pointer to a pre-allocated buffer of
|
|
* minimum size IP_IFNAMSIZ
|
|
* The <exactMatch> parameter determines whether the <addr> is a host route
|
|
* through the interface. That is, <exactMatch> is TRUE, whetherthe addr
|
|
* exists as a primary address on one of the interfaces.
|
|
*
|
|
* If the address exists on an 'UP' interface, TRUE is returned and the
|
|
* interface name is copied into the supplied buffer. Otherwise, FALSE
|
|
* is returned.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
LOCAL BOOL routeExistsOnIf(Ip_u32 addr, char *ifNameBuffer, BOOL exactMatch)
|
|
{
|
|
struct Ip_if_nameindex *oifrs, *ifrs;
|
|
struct Ip_ifreq ifreq;
|
|
struct Ip_sockaddr_in *addrp;
|
|
int sock;
|
|
int ret = FALSE;
|
|
Ip_u32 ifAddr;
|
|
Ip_u32 ifMask;
|
|
Ip_u32 ifSubnet;
|
|
Ip_u32 addrSubnet;
|
|
|
|
/* Socket to use with interface ioctl */
|
|
|
|
if ((sock = ipcom_socket (AF_INET, SOCK_RAW, 0)) < 0)
|
|
return FALSE;
|
|
|
|
/* Search through all of the interfaces */
|
|
|
|
ifrs = ipcom_if_nameindex();
|
|
if (ifrs == IP_NULL || strlen(ifrs->if_name) >= IP_IFNAMSIZ)
|
|
{
|
|
ipcom_if_freenameindex(ifrs);
|
|
ipcom_socketclose(sock);
|
|
return FALSE;
|
|
}
|
|
|
|
for (oifrs = ifrs; ifrs && ifrs->if_name != IP_NULL; ifrs++)
|
|
{
|
|
/* Check if interface is up. */
|
|
|
|
strcpy(ifreq.ifr_name, ifrs->if_name);
|
|
if (ipcom_socketioctl(sock, IP_SIOCGIFFLAGS,(char *)&ifreq) < 0)
|
|
{
|
|
continue;
|
|
}
|
|
if (IP_BIT_ISFALSE(ifreq.ifr_ifru.ifru_flags, IP_IFF_UP))
|
|
continue;
|
|
|
|
/* Grab the primary address on this interface */
|
|
|
|
if (ipcom_socketioctl(sock, IP_SIOCGIFADDR,(char *)&ifreq) < 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
addrp = (struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr;
|
|
ifAddr = addrp->sin_addr.s_addr;
|
|
|
|
/* Grab the netmask for this interface */
|
|
|
|
if (ipcom_socketioctl(sock, IP_SIOCGIFNETMASK,(char *)&ifreq) < 0)
|
|
{
|
|
ipcom_socketclose(sock);
|
|
return ERROR;
|
|
}
|
|
|
|
addrp = (struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr;
|
|
ifMask = addrp->sin_addr.s_addr;
|
|
|
|
ifSubnet = ifAddr & ifMask;
|
|
addrSubnet = addr & ifMask;
|
|
|
|
/* Check the match */
|
|
|
|
if (exactMatch == TRUE)
|
|
{
|
|
if (addr == ifAddr)
|
|
{
|
|
ret = TRUE;
|
|
strncpy(ifNameBuffer, ifrs->if_name, IP_IFNAMSIZ);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ifSubnet == addrSubnet)
|
|
{
|
|
ret = TRUE;
|
|
strncpy(ifNameBuffer, ifrs->if_name, IP_IFNAMSIZ);
|
|
}
|
|
}
|
|
}
|
|
|
|
ipcom_if_freenameindex(oifrs);
|
|
ipcom_socketclose(sock);
|
|
return ret;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* routeExistsInTable - Determine whether the address exists in the routing
|
|
* table
|
|
*
|
|
* The <addr> parameter corresponds to an route to check. If the address
|
|
* exists in the routing table, TRUE is returned. Otherwise, FALSE is returned.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
LOCAL BOOL routeExistsInTable(Ip_u32 addr)
|
|
{
|
|
int sock;
|
|
int status;
|
|
int flags;
|
|
int ret;
|
|
struct Ipnet_rt_msghdr * rtm;
|
|
|
|
flags = RTF_STATIC | RTF_UP | RTF_HOST | RTF_GATEWAY;
|
|
ret = FALSE;
|
|
|
|
if ((sock = ipcom_socket(AF_ROUTE, SOCK_RAW, 0)) < 0)
|
|
return (ERROR);
|
|
|
|
rtm = (struct Ipnet_rt_msghdr *)ipcom_malloc(RTM_BUFSIZE);
|
|
|
|
if (rtm == IP_NULL)
|
|
{
|
|
ipcom_socketclose (sock);
|
|
return ERROR;
|
|
}
|
|
|
|
status = routeRtmSendReply(sock, 0, RTM_GET, rtm, (ULONG)addr, 0, 0, flags);
|
|
|
|
if (status != ERROR && rtm->rtm_errno == 0)
|
|
{
|
|
ret = TRUE;
|
|
}
|
|
|
|
ipcom_socketclose (sock);
|
|
ipcom_free(rtm);
|
|
return ret;
|
|
}
|
|
|