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

2710 lines
82 KiB
C

/* m2Ipv6IfLib.c - MIB-II IPv6 general-group API for SNMP agents */
/*
* Copyright (c) 2002-2005 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
02a,03may05,kch Renamed nd6_delay to _nd6_delay (SPR#108823).
01z,28apr05,kch Fixed virtual stack build.
01y,20apr05,kch Merged from comp_wn_ipv6_mld_interim-dev branch.
01x,24feb05,spm removed unneeded route format values and macros (SPR #100995)
01w,24feb05,spm fixed previous modification history entry
01v,24feb05,spm performance updates and code cleanup (SPR #100995)
01u,28jan05,vvv fixed bitfield definitions (SPR #92171)
01t,26jan05,vvv fixed build errors
01s,12jan05,vvv osdep.h cleanup
01r,19sep04,spm updated virtual stack startup: restored use of published
init routine and removed packing/unpacking parameters
01q,13aug04,kc Made m2Ipv6Initialized bool variable extern.
01p,12aug04,kc VS data structure reorganization. Also added m2Ipv6Initialized
bool variable.
01o,16jul04,niq Check whether data is present before copying it (SPR 99100)
01n,01jul04,vvv fixed warnings
01m,09jun04,spm fixed fastpath function pointers for virtual stacks
01l,19may04,niq RTM memory storage changes
01k,21apr04,niq Merge from base6_itn4_networking_perf-dev.al branch
01j,02feb04,pas changed for new avlLib without GENERIC_ARGUMENT.
01i,05dec03,xli change include path
01h,20nov03,niq osdep.h cleanup
01f,10nov03,rlm 2nd pass of include update for header re-org.
01e,06nov03,rlm Ran batch header update for header re-org.
01d,08sep03,vvv merged from ACCORDION_BASE6_MERGE_BASELINE
01c,10apr03,ijm fixed diab compiler warnings
01b,10jan03,ann moved some globals into m2IfLib.c
01b,01feb03,pas fixed sysctl calls in m2Ipv6IfGeneralSet
01a,25mar02,ant written
*/
/*
DESCRIPTION
This library provides MIB-II services for the IPv6 general group. It provides
routines to initialize the group, access the scalar variables, read the IPv6
interface group table, IPv6 address prefix table, IPv6 address table, IPv6
route and IPv6 address translation table. The IPv6 interface group, IPv6 route
and IPv6 address translation table can also be modified. For a broader
description of IPv6 MIB-II services, see the manual entry for m2Ipv6Lib.
To use this feature, include the following component:
INCLUDE_MIB2_IPV6
USING THIS LIBRARY
This library can be initialized and deleted by calling m2Ipv6IfInit() and
m2Ipv6IfDelete() respectively, if only the IPv6 general group's services are
needed. If full IPv6 MIB-II support is used, this group and all other groups
can be initialized and deleted by calling m2Ipv6Init() and m2Ipv6Delete().
The following example demonstrates how to access and change general-group
scalar variables:
.CS
M2_IPV6_GENERAL ipv6Gen;
IPV6_GENERAL_SETENTRY ipv6IfEntry;
if (m2Ipv6IfGeneralGet (&ipv6Gen) == OK)
/@ values in ipv6Gen are valid @/
/@ if IPv6 is forwarding packets (MIB-II value is 1) turn it off @/
if (ipv6Gen.ipv6Forwarding == M2_ipv6Forwarding_forwarding)
{
/@ Not forwarding (MIB-II value is 2) @/
ipv6IfEntry.ipv6Forwarding = M2_ipv6Forwarding_notForwarding;
ipv6IfEntry.varToSet |= M2_varId_ipv6Forwarding;
}
/@ change the IPv6 default hop limit parameter @/
ipv6IfEntry.ipv6DefaultHopLimit = 55;
ipv6IfEntry.varToSet |= M2_varId_ipv6DefaultHopLimit;
if (m2Ipv6IfGeneralSet (&ipv6IfEntry) == OK)
/@ values in ipv6IfEntry are valid @/
.CE
An IPv6 interface group table entry can be retrieved as follows:
.CS
struct in6_ifdata ipv6IfReqEntry;
/@ Specify the index to get the requested entry in the table @/
ipv6IfReqEntry.ifInfo.ipv6IfIndex = 2; /@ Get interface with index 2 @/
if (m2Ipv6IfTblEntryGet (M2_EXACT_VALUE, &ipv6IfReqEntry) == OK)
/@ values in ipv6IfReqEntry are valid @/
.CE
An IPv6 interface entry operational state can be changed as follows:
.CS
IPV6_IF_SETENTRY ipv6IfEntryToSet;
ipv6IfEntryToSet.ipv6IfIndex = 2; /@ Select interface with index 2 @/
/@ MIB-II value to set the interface @/
/@ to the down state. @/
ipv6IfEntryToSet.varToSet |= M2_varId_ipv6IfAdminStatus;
ipv6IfEntryToSet.ipv6IfAdminStatus = M2_ipv6IfAdminStatus_down;
if (m2Ipv6IfTblEntrySet (&ipv6IfEntryToSet) == OK)
/@ Interface is now in the down state @/
.CE
The IPv6 address prefix table is a read-only table. Entries to this table can
be retrieved as follows:
.CS
M2_IPV6ADDRPFXTBL ipv6AddrPfxTblEntry;
int index;
/@ Specify the index as zero to get the first entry in the table @/
index = 0; /@ Interface index @/
/@ Address prefix in host byte order @/
memset (ipv6AddrPfxTblEntry.ipv6AddrPrefixAddress, 0,
sizeof (struct in6_addr));
ipv6AddrPfxTblEntry.ipv6AddrPrefixLength = 0; /@ prefix length @/
/@ get the first entry in the table @/
if((m2Ipv6AddrPfxTblEntryGet (M2_NEXT_VALUE, &index,
&ipv6AddrPfxTblEntry) == OK)
/@ values in ipv6AddrPfxTblEntry in the first entry are valid @/
/@ Process first entry in the table @/
/@ get the second entry in the table @/
if((m2Ipv6AddrPfxTblEntryGet (M2_NEXT_VALUE, &index,
&ipv6AddrPfxTblEntry) == OK)
/@ values in ipv6AddrPfxTblEntry in the first entry are valid @/
.CE
The IPv6 address table is a read-only table. Entries to this table can be
retrieved as follows:
.CS
M2_IPV6ADDRTBL ipv6AddrTblEntry;
int index;
/@ Specify the index as zero to get the first entry in the table @/
index = 0; /@ Interface index @/
/@ Address in host byte order @/
memset (ipv6AddrTblEntry.ipv6AddrAddress, 0, sizeof (struct in6_addr));
/@ get the first entry in the table @/
if((m2Ipv6AddrTblEntryGet (M2_NEXT_VALUE, &index, &ipv6AddrTblEntry) == OK)
/@ values in ipv6AddrTblEntry in the first entry are valid @/
/@ Process first entry in the table @/
/@ get the second entry in the table @/
if((m2Ipv6AddrTblEntryGet (M2_NEXT_VALUE, &index, &ipv6AddrTblEntry) == OK)
/@ values in ipv6AddrTblEntry in the first entry are valid @/
.CE
The following example demonstrates how to access IPv6 routing scalar variables:
.CS
M2_IPV6ROUTE ipv6RouteInfo;
if (m2Ipv6RouteInfoGet (&ipv6RouteInfo) == OK)
/@ values in ipv6RouteInfo are valid @/
.CE
The IPv6 route table allows for entries to be read and deleted. This example
demonstrates how an existing route is deleted:
.CS
M2_IPV6ROUTETBL ipv6RouteTblEntry;
char destAddr[] = "3000::40";
char nextHopAddr[] = "4000::42";
/@ Specify the index for the connection to be deleted in the table @/
/@ Destination IPv6 address in host byte order @/
/@ convert a presentation format address to a network format address @/
inet_pton (AF_INET6, destAddr, ipv6RouteTblEntry.ipv6RouteDest);
NTOHL_IPV6ADDR (ipv6RouteTblEntry.ipv6RouteDest);
/@ destination address prefix length @/
ipv6RouteTblEntry.ipv6RoutePfxLength = 64;
/@ implementation specific index @/
ipv6RouteTblEntry.ipv6RouteIndex = 0x021bb250;
/@ Next hop IPv6 address in host byte order @/
/@ convert a presentation format address to a network format address @/
inet_pton (AF_INET6, nextHopAddr, ipv6RouteTblEntry.ipv6RouteNextHop);
NTOHL_IPV6ADDR (ipv6RouteTblEntry.ipv6RouteNextHop);
/@ mark entry as invalid @/
ipv6RouteTblEntry.ipv6RouteValid = M2_FALSE;
/@ set the entry in the table @/
if ((m2Ipv6RouteTblEntrySet (&ipv6RouteTblEntry) == OK)
/@ Entry deleted successfully @/
.CE
The IPv6 address translation table allows for entries to be read and
deleted. An entry is deleted (with a set operation) by setting the
`ipv6NetToMediaValid' field to the value "false(2)". The following
example shows how to delete an entry:
.CS
M2_IPV6ATRANSTBL reqIpv6AtEntry;
char destAddr[] = "3000::40";
int index;
/@ Specify the index for the connection to be deleted in the table @/
index = 2 /@ interface index @/
/@ destination IPv6 address in host byte order @/
/@ convert a presentation format address to a network format address @/
inet_pton (AF_INET6, destAddr, reqIpv6AtEntry.ipv6NetToMediaNetAddress);
NTOHL_IPV6ADDR (reqIpv6AtEntry.ipv6NetToMediaNetAddress);
/@ mark entry as invalid @/
reqIpv6AtEntry.ipv6NetToMediaValid = M2_FALSE;
/@ set the entry in the table @/
if ((m2Ipv6AtransTblEntrySet (index, &reqIpv6AtEntry) == OK)
/@ Entry deleted successfully @/
.CE
INCLUDE FILES: m2Ipv6Lib.h
SEE ALSO:
m2Ipv6Lib, m2Ipv6IfIcmpLib, m2Ipv6UdpLib, m2Ipv6TcpLib, m2Ipv6MldLib */
/* includes */
#include <vxWorks.h>
#include <stdlib.h>
#include <errnoLib.h>
#include <netconf.h>
#include "stdio.h"
#include "sysLib.h"
#include <float.h>
#include <ioLib.h>
#include <tickLib.h>
#include <sockLib.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet6/ip6.h>
#include <netinet6/ip6_var.h>
#include <sys/ioctl.h>
#include <ipProto.h>
#include <m2Lib.h>
#include <private/m2LibP.h>
#include <m2Ipv6Lib.h>
#include <net/radix.h>
#include <net/route.h>
#include <net/if_dl.h>
#include <netinet6/nd6.h>
#include <rip/defs.h>
#include <sys/ds_conf.h>
#include <sys/mem_stru.h>
#include <fastPath/fastPathLib.h>
#ifdef VIRTUAL_STACK
#include <netinet/vsM2.h>
#include <netinet/vsLib.h>
#include <netinet/vsData.h>
#include <netinet/vsRadix.h>
#include <vs/vsNd6.h>
#include <vs/vsIp6.h>
#include <vs/vsIf.h>
#endif /*VIRTUAL_STACK*/
/* defines */
#define M2IPV6_MAX_ROUTE_DEFAULT 40
/* globals */
/* imports */
#if 0 /* Not needed right now */
#ifndef VIRTUAL_STACK
IMPORT int ffIpv6State;
#endif /* VIRTUAL_STACK */
/* Fastpath hook */
IMPORT STATUS (*pFFL3ConfigChanged) (int af, int flags);
#endif /* 0 */
#ifndef VIRTUAL_STACK
extern SEM_ID m2InterfaceSem; /* defined in m2IfLib.c */
extern AVLU_TREE * pM2IfRootPtr; /* defined in m2IfLib.c */
extern int ifsInList; /* defined in m2IfLib.c */
IMPORT int ipMaxUnits;
extern struct llinfo_nd6 _llinfo_nd6;
extern struct nd_prhead _nd_prefix;
IMPORT int m2Ipv6Interfaces; /* no. of IPv6 interfaces */
IMPORT ULONG m2Ipv6IfTableLastChange;
IMPORT BOOL m2Ipv6Initialized; /* defined in m2IfLib.c */
/* locals */
LOCAL int priv_m2Ipv6RouteTableSaved;
LOCAL unsigned long priv_m2Ipv6RouteTableSize;
LOCAL unsigned long priv_m2Ipv6NumRouteEntries;
LOCAL unsigned long priv_m2Ipv6DiscardedRoutes;
LOCAL M2_IPV6ROUTETBL * priv_m2Ipv6RouteTable;
LOCAL SEM_ID priv_m2Ipv6RouteSem;
#else
#define priv_m2Ipv6RouteTableSaved VS_M2_IPV6_IF_DATA->priv_m2Ipv6RouteTableSaved
#define priv_m2Ipv6RouteTableSize VS_M2_IPV6_IF_DATA->priv_m2Ipv6RouteTableSize
#define priv_m2Ipv6NumRouteEntries VS_M2_IPV6_IF_DATA->priv_m2Ipv6NumRouteEntries
#define priv_m2Ipv6DiscardedRoutes VS_M2_IPV6_IF_DATA->priv_m2Ipv6DiscardedRoutes
#define priv_m2Ipv6RouteTable VS_M2_IPV6_IF_DATA->priv_m2Ipv6RouteTable
#define priv_m2Ipv6RouteSem VS_M2_IPV6_IF_DATA->priv_m2Ipv6RouteSem
#endif /* VIRTUAL_STACK */
/*
* The zero object id is used throught out the MIB-II library to fill OID
* requests when an object ID is not provided by a group variable.
*/
LOCAL M2_OBJECTID ipZeroObjectId = { 2, {0,0} };
/* forward declarations */
LOCAL int m2Ipv6RouteTableGet();
LOCAL void m2Ipv6RouteCacheInit (struct rtentry *rt, void * pRtArg);
LOCAL STATUS m2Ipv6SystemRouteAdd (struct in6_addr * pDstIp, struct in6_addr * pGateIp,
struct in6_addr * pMaskIp, int flags);
LOCAL STATUS m2Ipv6SystemRouteDelete (struct in6_addr * pDstIp, struct in6_addr * pGateIp,
struct in6_addr * pMaskIp, int flags);
extern int prefix (void *, int);
extern unsigned long m2IfCentiSecsGet (void);
/******************************************************************************
*
* m2Ipv6IfInit - initialize MIB-II IPv6 general-group access
*
* This routine allocates the resources needed to allow access to the MIB-II
* IPv6 general-group variables. This routine must be called before any IPv6
* general-group variables can be accessed. The 'maxRouteTableSize' argument
* is used to increase the default size of the MIB-II IPv6 route table cache.
*
* RETURNS:
* OK, or ERROR if the route table or the route semaphore cannot be allocated.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_CANT_CREATE_ROUTE_SEM
*
* SEE ALSO: m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(), m2Ipv6IfTblEntryGet(),
* m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(), m2Ipv6AddrTblEntryGet(),
* m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(), m2Ipv6RouteTblEntrySet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6IfInit
(
unsigned long maxRouteTableSize /* max size of routing table */
)
{
/* initialize the routing table stuff */
if (priv_m2Ipv6RouteTable == NULL)
{
/* only initialized the first time called */
priv_m2Ipv6RouteTableSaved = 0;
priv_m2Ipv6RouteTableSize = (maxRouteTableSize == 0) ?
M2IPV6_MAX_ROUTE_DEFAULT : maxRouteTableSize;
priv_m2Ipv6RouteTable = (M2_IPV6ROUTETBL *) KHEAP_ALLOC (priv_m2Ipv6RouteTableSize *
sizeof (M2_IPV6ROUTETBL));
if (priv_m2Ipv6RouteTable == NULL)
return (ERROR);
bzero ((char *) priv_m2Ipv6RouteTable, priv_m2Ipv6RouteTableSize * sizeof (M2_IPV6ROUTETBL));
}
if (priv_m2Ipv6RouteSem == NULL)
{
priv_m2Ipv6RouteSem = semMCreate (SEM_Q_PRIORITY | SEM_INVERSION_SAFE |
SEM_DELETE_SAFE);
if (priv_m2Ipv6RouteSem == NULL)
{
KHEAP_FREE ((char *) priv_m2Ipv6RouteTable);
priv_m2Ipv6RouteTable = NULL;
errnoSet (S_m2Lib_CANT_CREATE_ROUTE_SEM);
return (ERROR);
}
}
(void) m2Ipv6RouteTableGet (priv_m2Ipv6RouteTable, priv_m2Ipv6RouteTableSize);
m2Ipv6Interfaces = 0;
m2Ipv6IfTableLastChange = 0;
m2Ipv6Initialized = TRUE;
return (OK);
}
/*******************************************************************************
*
* m2Ipv6IfDestructor - Clean up the resources used by VS Portion of the code
*
* RETURNS: ERROR if it could not free the memory
* OK otherwise
*
* NOMANUAL
*/
#ifdef VIRTUAL_STACK
STATUS m2Ipv6IfDestructor
(
VSNUM vsnum
)
{
/* Free route semaphore */
if (priv_m2Ipv6RouteSem != NULL)
{
semDelete (priv_m2Ipv6RouteSem);
priv_m2Ipv6RouteSem = NULL;
}
/* Free route table */
if (priv_m2Ipv6RouteTable != NULL)
{
KHEAP_FREE ((char *) priv_m2Ipv6RouteTable);
priv_m2Ipv6RouteTable = NULL;
}
m2Ipv6Initialized = FALSE;
return (OK);
}
#endif /* VIRTUAL_STACK */
/******************************************************************************
*
* m2Ipv6AddrCmp - compare two ipv6 addresses
*/
LOCAL int m2Ipv6AddrCmp
(
struct in6_addr * addr1,
struct in6_addr * addr2
)
{
int ix;
for (ix = 0; ix < 4; ix++)
{
if (addr1->s6_addr32[ix] > addr2->s6_addr32[ix])
return (1);
else if (addr1->s6_addr32[ix] < addr2->s6_addr32[ix])
return (-1);
}
return (0);
}
/******************************************************************************
*
* m2Ipv6AvlSearch - search the node in avl tree and check if the mibStyle in the
* struct M2_IFINDEX is equal to IF_MIB_IPV6
*/
M2_IFINDEX * m2Ipv6AvlSearch
(
AVLU_TREE root,
UINT key
)
{
M2_IFINDEX * pIfIndexEntry = NULL;
pIfIndexEntry = (M2_IFINDEX *) avlUintSearch (root, key);
if (pIfIndexEntry && (pIfIndexEntry->mibStyle & IF_MIB_IPV6))
return (pIfIndexEntry);
else
return (NULL);
}
/******************************************************************************
*
* m2Ipv6AvlSuccessorGet - search the next node in avl tree and check if the
* mibStyle in the struct M2_IFINDEX is equal to
* IF_MIB_IPV6
*/
M2_IFINDEX * m2Ipv6AvlSuccessorGet
(
AVLU_TREE root,
UINT key
)
{
M2_IFINDEX * pIfIndexEntry = NULL;
pIfIndexEntry = (M2_IFINDEX *) avlUintSuccessorGet (root, key);
while (pIfIndexEntry)
{
if (pIfIndexEntry->mibStyle & IF_MIB_IPV6)
return (pIfIndexEntry);
else
{
pIfIndexEntry = (M2_IFINDEX *) avlUintSuccessorGet (root,
pIfIndexEntry->ifIndex);
}
}
return (NULL);
}
/******************************************************************************
*
* m2Ipv6IfGeneralGet - get the MIB-II IPv6 general-group scalar variables
*
* This routine fills in the structure at <pIpv6Gen> with the
* values of MIB-II IPv6 general-group global variables.
*
* RETURNS: OK, or ERROR if <pIpv6Gen> is not a valid pointer.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_GEN_ERR
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralSet(), m2Ipv6IfTblEntryGet(),
* m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(), m2Ipv6AddrTblEntryGet(),
* m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(), m2Ipv6RouteTblEntrySet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6IfGeneralGet
(
M2_IPV6_GENERAL * pIpv6Gen /* pointer to IPv6 general group structure */
)
{
int mib[] = {CTL_NET, PF_INET6, IPPROTO_IPV6, 0};
int value;
size_t size;
/* Validate the input parameter pointer */
if (pIpv6Gen == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR);
}
semTake (m2InterfaceSem, WAIT_FOREVER);
/* forwarding? */
mib[3] = IPV6CTL_FORWARDING;
size = sizeof(value);
if (sysctl (mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_GEN_ERR);
return (ERROR);
}
pIpv6Gen->ipv6Forwarding = (value) ?
M2_ipv6Forwarding_forwarding :
M2_ipv6Forwarding_notForwarding;
/* get default IPv6 hop limit */
mib[3] = IPV6CTL_DEFHLIM;
size = sizeof(value);
if (sysctl (mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_GEN_ERR);
return (ERROR);
}
pIpv6Gen->ipv6DefaultHopLimit = value;
pIpv6Gen->ipv6Interfaces = m2Ipv6Interfaces;
pIpv6Gen->ipv6IfTableLastChange = m2Ipv6IfTableLastChange;
semGive (m2InterfaceSem);
return OK;
}
/******************************************************************************
*
* m2Ipv6IfGeneralSet - set the MIB-II IPv6 general-group scalar variables
*
* This routine sets one or more variables in the IPv6 general-group, as
* specified in the input structure <pIpv6IfReqEntry>.
*
* RETURNS: OK, or ERROR if <pIpv6IfReqEntry> is not a valid pointer.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_GEN_ERR
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfTblEntryGet(),
* m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(), m2Ipv6AddrTblEntryGet(),
* m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(), m2Ipv6RouteTblEntrySet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6IfGeneralSet
(
void * pIpv6IfReqEntry /* pointer to requested entry to change */
)
{
int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
int value;
size_t size;
IPV6_GENERAL_SETENTRY * pIpv6IfEntry =
(IPV6_GENERAL_SETENTRY *)pIpv6IfReqEntry;
/* Validate pointer to requeste structure */
if (pIpv6IfReqEntry == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR);
}
semTake (m2InterfaceSem, WAIT_FOREVER);
/* Check variables to set */
if (pIpv6IfEntry->varToSet & M2_varId_ipv6Forwarding)
{
mib[3] = IPV6CTL_FORWARDING;
size = sizeof (value);
value = (pIpv6IfEntry->ipv6Forwarding == M2_ipv6Forwarding_forwarding)
? 1 : 0;
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, 0, &value, size) < 0)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_GEN_ERR);
return (ERROR);
}
#if 0
/*
* Sysctl already informs fastpath so we don't need to;
* but if we ever modify ip6_forwarding directly, we'll need to
* enable this code.
*
* The ffIpv6State flag test guarantees the function pointer is
* assigned correctly for a virtual or non-virtual stack.
*/
if ((ffIpv6State & FF_MODULE_INITIALIZED) != 0)
(*pFFL3ConfigChanged) (AF_INET6, ip6_forwarding);
#endif /* 0 */
}
if (pIpv6IfEntry->varToSet & M2_varId_ipv6DefaultHopLimit)
{
mib[3] = IPV6CTL_DEFHLIM;
size = sizeof (value);
value = pIpv6IfEntry->ipv6DefaultHopLimit;
if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), NULL, 0, &value, size) < 0)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_GEN_ERR);
return (ERROR);
}
}
semGive (m2InterfaceSem);
return (OK);
}
/******************************************************************************
*
* m2Ipv6IfTblEntryGet - get a MIB-II IPv6 interface group table entry
*
* This routine traverses the IPv6 interface group table and does an
* M2_EXACT_VALUE or a M2_NEXT_VALUE search based on the <search> parameter.
* The calling routine is responsible for supplying a valid MIB-II entry index
* in the input structure <pIpv6IfReqEntry>. The entry index is the interface
* index. The first entry in the table is retrieved by doing a NEXT search
* with the entry index set to zero.
*
* RETURNS:
* OK, ERROR if the input parameter is not specified, or a match is not found.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_ENTRY_NOT_FOUND
* S_m2Lib_GEN_ERR
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(), m2Ipv6AddrTblEntryGet(),
* m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(), m2Ipv6RouteTblEntrySet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6IfTblEntryGet
(
int search, /* M2_EXACT_VALUE or M2_NEXT_VALUE */
void * pIpv6IfReqEntry /* pointer to requested IPv6 interface entry */
)
{
M2_IFINDEX * pIfIndexEntry = NULL;
int index;
struct in6_ifdata * pIpv6IfEntry = (struct in6_ifdata *) pIpv6IfReqEntry;
struct ifnet * pIfNet;
struct in6_ifextra * pIfExtra;
struct ipdrvFields ipDrvFieldData;
IF_ID_T ifIdentifierInfo;
/* Validate pointer to requested structure */
if (pIpv6IfReqEntry == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR);
}
semTake (m2InterfaceSem, WAIT_FOREVER);
/*
* For a M2_EXACT_VALUE search, look up the index provided in the
* request and get the node from our internal tree. For a
* M2_NEXT_VALUE search, look up the successor of this node.
*/
/* First, Validate the bounds of the requested index */
index = pIpv6IfEntry->ifInfo.ipv6IfIndex;
if (index > ifsInList || index < 0)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
/* Check to see if it is a EXACT search or a next search */
if (search == M2_EXACT_VALUE)
{
pIfIndexEntry = m2Ipv6AvlSearch (pM2IfRoot, index);
}
else
{
pIfIndexEntry = m2Ipv6AvlSuccessorGet (pM2IfRoot, index);
}
if (!pIfIndexEntry)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
/* Get the value of mib objects that could have changed */
pIfNet = pIfIndexEntry->pIfStats;
pIfExtra = (struct in6_ifextra *)pIfNet->if_afdata[AF_INET6];
if ((pIfExtra == NULL) || (pIfExtra->in6_ifstat == NULL))
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
/* Copy the IPv6 MIB data, if it exists */
if (pIfIndexEntry->pIn6IfInfo != NULL)
{
memcpy ((char *)&pIpv6IfEntry->ifInfo,(char *)pIfIndexEntry->pIn6IfInfo,
sizeof (struct in6_ifinfo));
memcpy ((char *)&pIpv6IfEntry->ifStat, (char *)pIfExtra->in6_ifstat,
sizeof (struct in6_ifstat));
}
else
bzero ((char *)pIpv6IfEntry, sizeof (struct in6_ifdata));
/* ipv6IfEffectiveMtu */
pIpv6IfEntry->ifInfo.ipv6IfEffectiveMtu = pIfNet->if_mtu;
/* ipv6IfIdentifier */
bzero (pIpv6IfEntry->ifInfo.ipv6IfIdentifier, IF_IDENT_SIZE);
ipDrvFieldData.pBuf = &ifIdentifierInfo;
ipDrvFieldData.cmd = IPDRVCTRL_IFID;
if ((pIfNet->if_ioctl != NULL) &&
((*pIfNet->if_ioctl) (pIfNet, SIOCGMIPDRVCTRL,
(caddr_t)&ipDrvFieldData) != 0))
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_GEN_ERR);
return (ERROR);
}
bcopy ((char *) ifIdentifierInfo.interfaceId,
(char *) pIpv6IfEntry->ifInfo.ipv6IfIdentifier,
ifIdentifierInfo.interfaceIdLen);
pIpv6IfEntry->ifInfo.ipv6IfIdentifierLength =
(int) ifIdentifierInfo.interfaceIdLen;
/* ipv6IfAdminStatus */
if (!(pIfNet->if_adminstatus & ADMIN_DOWN))
pIpv6IfEntry->ifInfo.ipv6IfAdminStatus = M2_ipv6IfAdminStatus_up;
else
pIpv6IfEntry->ifInfo.ipv6IfAdminStatus = M2_ipv6IfAdminStatus_down;
/* ipv6IfOperStatus*/
if (pIfNet->if_flags & IFF_INET6_UP)
pIpv6IfEntry->ifInfo.ipv6IfOperStatus = M2_ipv6IfOperStatus_up;
else
pIpv6IfEntry->ifInfo.ipv6IfOperStatus = M2_ipv6IfOperStatus_down;
semGive (m2InterfaceSem);
return (OK);
}
/******************************************************************************
*
* m2Ipv6IfTblEntrySet - set a MIB-II IPv6 interface group table entry
*
* This routine traverses the interface group table for the entry specified in
* the parameter <pIpv6IfReqEntry>. A MIB-II entry index is specified by the
* interface index. An entry can be modified by specifying the MIB-II
* index and the field that is to be modified.
*
* RETURNS:
* OK, or ERROR if the input parameter is not specified.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_ENTRY_NOT_FOUND
* S_m2Lib_READ_ONLY
* S_m2Lib_BAD_VALUE
* S_m2Lib_GEN_ERR
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntryGet(), m2Ipv6AddrPfxTblEntryGet(), m2Ipv6AddrTblEntryGet(),
* m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(), m2Ipv6RouteTblEntrySet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6IfTblEntrySet
(
void * pIpv6IfReqEntry /* pointer to requested entry to change */
)
{
int index;
M2_IFINDEX * pIfIndexEntry = NULL;
IPV6_IF_SETENTRY * pIpv6IfEntry = (IPV6_IF_SETENTRY *) pIpv6IfReqEntry;
struct ifreq ifReqChange;
struct ifnet * pIfNet = NULL;
struct ipdrvFields ipDrvFieldData;
IF_ID_T ifIdentifierInfo;
/* Validate pointer to requeste structure */
if (pIpv6IfReqEntry == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR);
}
semTake (m2InterfaceSem, WAIT_FOREVER);
/* Validate the bounds of the requested index */
index = pIpv6IfEntry->ipv6IfIndex;
if (index < 0 || index > ifsInList)
{
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
semGive (m2InterfaceSem);
return (ERROR);
}
/* Get the node associated with the index */
pIfIndexEntry = m2Ipv6AvlSearch (pM2IfRoot, index);
if (!pIfIndexEntry)
{
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
semGive (m2InterfaceSem);
return (ERROR);
}
pIfNet = pIfIndexEntry->pIfStats;
/* Check variables to set */
if (pIpv6IfEntry->varToSet & M2_varId_ipv6IfDescr)
{
strcpy (pIfIndexEntry->pIn6IfInfo->ipv6IfDescr,
pIpv6IfEntry->ipv6IfDescr);
}
if (((pIpv6IfEntry->varToSet & M2_varId_ipv6IfIdentifierLength) &&
!(pIpv6IfEntry->varToSet & M2_varId_ipv6IfIdentifier)) ||
(!(pIpv6IfEntry->varToSet & M2_varId_ipv6IfIdentifierLength) &&
(pIpv6IfEntry->varToSet & M2_varId_ipv6IfIdentifier)))
{
/*
* Variables ipv6IfIdentifierLength and ipv6IfIdentifier must be
* both specified.
*/
errnoSet (S_m2Lib_INVALID_PARAMETER);
semGive (m2InterfaceSem);
return (ERROR);
}
if ((pIpv6IfEntry->varToSet & M2_varId_ipv6IfIdentifier) &&
(pIpv6IfEntry->varToSet & M2_varId_ipv6IfIdentifierLength))
{
/*
* XXX For now only set the if identifier for ethernet
* Its length must be 64 bits.
*/
if (pIpv6IfEntry->ipv6IfIdentifierLength != EUI_64_LEN)
{
errnoSet (S_m2Lib_BAD_VALUE);
semGive (m2InterfaceSem);
return (ERROR);
}
ipDrvFieldData.pBuf = &ifIdentifierInfo;
ipDrvFieldData.cmd = IPDRVCTRL_IFID;
ifIdentifierInfo.interfaceIdLen = pIpv6IfEntry->ipv6IfIdentifierLength;
bcopy ((char *) pIpv6IfEntry->ipv6IfIdentifier,
(char *) ifIdentifierInfo.interfaceId,
ifIdentifierInfo.interfaceIdLen);
if ((pIfNet->if_ioctl != NULL) &&
((*pIfNet->if_ioctl) (pIfNet, SIOCSMIPDRVCTRL,
(caddr_t)&ipDrvFieldData) != 0))
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_GEN_ERR);
return (ERROR);
}
}
if (pIpv6IfEntry->varToSet & M2_varId_ipv6IfAdminStatus)
{
if (pIpv6IfEntry->ipv6IfAdminStatus == M2_ipv6IfAdminStatus_up)
{
/*
* If the driver is in the UP state, there is no need to send the
* IOCTL command, otherwise format the IOCTL request.
*/
if (pIfNet->if_adminstatus & ADMIN_DOWN)
ifReqChange.ifr_flags = pIfNet->if_flags | IFF_INET6_UP;
else
pIpv6IfEntry->varToSet =
pIpv6IfEntry->varToSet & ~M2_varId_ipv6IfAdminStatus;
}
else
{
/*
* If the driver is in the DOWN state, there is no need to send the
* IOCTL command, otherwise format the IOCTL request.
*/
if (!(pIfNet->if_adminstatus & ADMIN_DOWN))
ifReqChange.ifr_flags = pIfNet->if_flags & ~IFF_INET6_UP;
else
pIpv6IfEntry->varToSet =
pIpv6IfEntry->varToSet & ~M2_varId_ipv6IfAdminStatus;
}
}
if (pIpv6IfEntry->varToSet & M2_varId_ipv6IfAdminStatus)
{
sprintf (ifReqChange.ifr_name,"%s%d", pIfNet->if_name,
pIfNet->if_unit);
if ((*pIfIndexEntry->ifIoctl) (0, SIOCSIFFLAGS, (char *) &ifReqChange) != 0)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_GEN_ERR);
return (ERROR);
}
/* Update time stamp */
pIfIndexEntry->pIn6IfInfo->ipv6IfLastChange = m2IfCentiSecsGet ();
}
semGive (m2InterfaceSem);
return (OK);
}
/******************************************************************************
*
* m2Ipv6PfxEntryCmp - compare two IPv6 address prefix table entries in
* lexicographical order
*
* This routine compares two Prefix Table Entries. It compares the
* value 1 with value 2. It returns equal, value 1 greater than
* value 2, or value 1 less than value 2. The comparison is done based
* on the lexicographical order specified by IPV6 MIB.
*
* RETURNS: 0 = equal, 1 > greater than, and -1 < less than.
*
* SEE ALSO: N/A
*/
LOCAL int m2Ipv6PfxEntryCmp
(
int index1,
int index2,
struct in6_addr * addr1,
struct in6_addr * addr2,
int length1,
int length2
)
{
int result;
/* Comparison of two signed values */
result = index1 - index2;
if (result != 0)
return (result); /* Value > 0 or < 0 */
/* Comparison of two IPv6 addresses */
result = m2Ipv6AddrCmp(addr1, addr2);
if (result > 0)
{
return 1; /* First Entry is Greater */
}
if (result < 0)
{
return -1; /* First Entry is Smaller */
}
/* Result will determine Equal, Less than or Greater than */
return (length1 - length2);
}
/******************************************************************************
*
* m2Ipv6AddrPfxTblEntryGet - get a MIB-II IPv6 address prefix table entry
*
* This routine traverses the IPv6 address prefix table and does an
* M2_EXACT_VALUE or a M2_NEXT_VALUE search based on the <search> parameter.
* The calling routine is responsible for supplying a valid MIB-II entry index
* in the input parameters <reqIndex> and <pIpv6AddrPfxTblEntry>. The MIB-II
* entry index is made up of the interface index, IPv6 address prefix and the
* prefix length. The first entry in the table is retrieved by doing a NEXT
* search with the MIB-II entry index set to zero.
*
* RETURNS:
* OK, ERROR if the input parameter is not specified, or a match is not found.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_ENTRY_NOT_FOUND
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntryGet(), m2Ipv6IfTblEntrySet(), m2Ipv6AddrTblEntryGet(),
* m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(), m2Ipv6RouteTblEntrySet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6AddrPfxTblEntryGet
(
int search, /* M2_EXACT_VALUE or M2_NEXT_VALUE */
int * reqIndex, /* requested interface index */
M2_IPV6ADDRPFXTBL * pIpv6AddrPfxTblEntry /* ptr to IPv6 addr prefix tbl entry */
)
{
M2_IPV6ADDRPFXTBL entrySaved; /* IPv6 address entry selected */
struct in6_addr reqIp6AddrPfx; /* Caller IPv6 address Table index req */
struct in6_addr currIp6AddrPfx; /* Current IPv6 address Table index req */
FAST struct nd_prefix * ifpr;
BOOL found = FALSE;
int reqPfxLength;
int savedIndex;
/* Validate the input pointer */
if (pIpv6AddrPfxTblEntry == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR);
}
/* First, Validate the bounds of the requested index */
if (*reqIndex > ifsInList || *reqIndex < 0)
{
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
/* Setup variables to be used in the table search */
/* Largest IP address */
memset (entrySaved.ipv6AddrPrefixAddress, 0xff, sizeof (struct in6_addr));
entrySaved.ipv6AddrPrefixLength = 128; /* Largest prefix length */
savedIndex = ifsInList; /* Largest ifIndex */
/* Requested IP address */
memcpy (&reqIp6AddrPfx, pIpv6AddrPfxTblEntry->ipv6AddrPrefixAddress,
sizeof (struct in6_addr));
reqPfxLength = pIpv6AddrPfxTblEntry->ipv6AddrPrefixLength;
/* search exact value */
if (search == M2_EXACT_VALUE)
{
for (ifpr = _nd_prefix.lh_first; ifpr; ifpr = ifpr->ndpr_next)
{
memcpy (&currIp6AddrPfx, &ifpr->ndpr_prefix.sin6_addr,
sizeof (struct in6_addr));
NTOHL_IPV6ADDR(&currIp6AddrPfx);
if ((ifpr->ndpr_ifp->if_index == *reqIndex) &&
(pIpv6AddrPfxTblEntry->ipv6AddrPrefixLength <= in6_matchlen (&reqIp6AddrPfx, &currIp6AddrPfx)) &&
(ifpr->ndpr_plen == reqPfxLength))
{
if ((ifpr->ndpr_raf & PRF_RA_ONLINK) != 0)
pIpv6AddrPfxTblEntry->ipv6AddrPrefixOnLinkFlag = M2_TRUE;
else
pIpv6AddrPfxTblEntry->ipv6AddrPrefixOnLinkFlag = M2_FALSE;
if ((ifpr->ndpr_raf & PRF_RA_AUTONOMOUS) != 0)
pIpv6AddrPfxTblEntry->ipv6AddrPrefixAutonomousFlag = M2_TRUE;
else
pIpv6AddrPfxTblEntry->ipv6AddrPrefixAutonomousFlag = M2_FALSE;
pIpv6AddrPfxTblEntry->ipv6AddrPrefixAdvPreferredLifetime =
ifpr->ndpr_pltime;
pIpv6AddrPfxTblEntry->ipv6AddrPrefixAdvValidLifetime =
ifpr->ndpr_vltime;
return (OK);
}
}
}
else /* M2_NEXT_VALUE */
{
for (ifpr = _nd_prefix.lh_first; ifpr; ifpr = ifpr->ndpr_next)
{
memcpy (&currIp6AddrPfx, &ifpr->ndpr_prefix.sin6_addr,
sizeof (struct in6_addr));
NTOHL_IPV6ADDR(&currIp6AddrPfx);
if ((m2Ipv6PfxEntryCmp (ifpr->ndpr_ifp->if_index, *reqIndex,
&currIp6AddrPfx, &reqIp6AddrPfx,
ifpr->ndpr_plen, reqPfxLength) > 0) &&
(m2Ipv6PfxEntryCmp (ifpr->ndpr_ifp->if_index, savedIndex,
&currIp6AddrPfx, (struct in6_addr *)entrySaved.ipv6AddrPrefixAddress,
ifpr->ndpr_plen, entrySaved.ipv6AddrPrefixLength) < 0)
)
{
savedIndex = ifpr->ndpr_ifp->if_index;
memcpy (entrySaved.ipv6AddrPrefixAddress, &currIp6AddrPfx,
sizeof (struct in6_addr));
entrySaved.ipv6AddrPrefixLength = ifpr->ndpr_plen;
if ((ifpr->ndpr_raf & PRF_RA_ONLINK) != 0)
entrySaved.ipv6AddrPrefixOnLinkFlag = M2_TRUE;
else
entrySaved.ipv6AddrPrefixOnLinkFlag = M2_FALSE;
if ((ifpr->ndpr_raf & PRF_RA_AUTONOMOUS) != 0)
entrySaved.ipv6AddrPrefixAutonomousFlag = M2_TRUE;
else
entrySaved.ipv6AddrPrefixAutonomousFlag = M2_FALSE;
entrySaved.ipv6AddrPrefixAdvPreferredLifetime =
ifpr->ndpr_pltime;
entrySaved.ipv6AddrPrefixAdvValidLifetime =
ifpr->ndpr_vltime;
found = TRUE;
}
}
}
if (found) /* there was bigger address prefix, otherwise try the next ifIndex */
{
*reqIndex = savedIndex;
memcpy (pIpv6AddrPfxTblEntry->ipv6AddrPrefixAddress, entrySaved.ipv6AddrPrefixAddress,
sizeof (struct in6_addr));
pIpv6AddrPfxTblEntry->ipv6AddrPrefixLength = entrySaved.ipv6AddrPrefixLength;
pIpv6AddrPfxTblEntry->ipv6AddrPrefixOnLinkFlag = entrySaved.ipv6AddrPrefixOnLinkFlag;
pIpv6AddrPfxTblEntry->ipv6AddrPrefixAutonomousFlag =
entrySaved.ipv6AddrPrefixAutonomousFlag;
pIpv6AddrPfxTblEntry->ipv6AddrPrefixAdvPreferredLifetime =
entrySaved.ipv6AddrPrefixAdvPreferredLifetime;
pIpv6AddrPfxTblEntry->ipv6AddrPrefixAdvValidLifetime =
entrySaved.ipv6AddrPrefixAdvValidLifetime;
return (OK);
}
else
{
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
}
/******************************************************************************
*
* m2Ipv6AddrTblEntryGet - get a MIB-II IPv6 address table entry
*
* This routine traverses the IPv6 address table and does an M2_EXACT_VALUE or
* a M2_NEXT_VALUE search based on the <search> parameter. The calling
* routine is responsible for supplying a valid MIB-II entry index in the
* input parameters <index> and <pIpv6AddrTblEntry>. The MIB-II entry index is
* made up of the interface index and IPv6 address. The first entry in the table
* is retrieved by doing a NEXT search with the MIB-II entry index set to zero.
*
* RETURNS:
* OK, ERROR if the input parameter is not specified, or a match is not found.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_ENTRY_NOT_FOUND
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntryGet(), m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(),
* m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(), m2Ipv6RouteTblEntrySet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6AddrTblEntryGet
(
int search, /* M2_EXACT_VALUE or M2_NEXT_VALUE */
int * index, /* requested interface index */
M2_IPV6ADDRTBL * pIpv6AddrTblEntry /* ptr to IPv6 address tbl entry */
)
{
M2_IPV6ADDRTBL entrySaved; /* IPv6 address selected */
struct in6_addr ip6Addr; /* Caller IPv6 address Table index req */
struct in6_addr currIp6Addr; /* Current IPv6 address Table index req */
M2_IFINDEX * pIfIndexEntry = NULL;
struct ifnet * pIfNetEntry = NULL;
FAST struct in6_ifaddr * ia = 0;
FAST struct ifaddr * ifa;
BOOL found = FALSE;
/* Validate the input pointer */
if (pIpv6AddrTblEntry == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR);
}
semTake (m2InterfaceSem, WAIT_FOREVER);
/* First, Validate the bounds of the requested index */
if (*index > ifsInList || *index < 0)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
/* Setup variables to be used in the table search */
/* Largest IP address */
memset (entrySaved.ipv6AddrAddress, 0xff, sizeof (struct in6_addr));
/* Requested IP address */
memcpy (&ip6Addr, pIpv6AddrTblEntry->ipv6AddrAddress,
sizeof (struct in6_addr));
if (search == M2_EXACT_VALUE)
{
pIfIndexEntry = m2Ipv6AvlSearch (pM2IfRoot, *index);
if (!pIfIndexEntry)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
/* Get the pointer to the ifnet struct for this ifIndex */
pIfNetEntry = (struct ifnet *) pIfIndexEntry->pIfStats;
HTONL_IPV6ADDR(&ip6Addr);
/* find the internet address corresponding to a given interface and address */
ia = in6ifa_ifpwithaddr(pIfNetEntry, &ip6Addr);
if (ia == NULL)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
found = TRUE;
pIpv6AddrTblEntry->ipv6AddrPfxLength =
prefix (IA6_MASKIN6(ia), sizeof(struct in6_addr));
/* stateful state not implemented yet */
if (ia->ia6_flags & IN6_IFF_AUTOCONF)
pIpv6AddrTblEntry->ipv6AddrType = M2_ipv6AddrType_stateless;
/* else if (ia->ia6_flags & IN6_IFF_xxxxxxx)
pIpv6AddrTblEntry->ipv6AddrType =
M2_ipv6AddrType_stateful;*/
else
pIpv6AddrTblEntry->ipv6AddrType =
M2_ipv6AddrType_unknown;
/* ****** */
if (ia->ia6_flags & IN6_IFF_ANYCAST)
pIpv6AddrTblEntry->ipv6AddrAnycastFlag = M2_TRUE;
else
pIpv6AddrTblEntry->ipv6AddrAnycastFlag = M2_FALSE;
if (ia->ia6_flags & IN6_IFF_DEPRECATED)
pIpv6AddrTblEntry->ipv6AddrStatus =
M2_ipv6AddrStatus_deprecated;
else if (ia->ia6_flags & (IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED))
pIpv6AddrTblEntry->ipv6AddrStatus =
M2_ipv6AddrStatus_invalid;
else if (ia->ia6_flags & IN6_IFF_DETACHED)
pIpv6AddrTblEntry->ipv6AddrStatus =
M2_ipv6AddrStatus_inaccessible;
else
pIpv6AddrTblEntry->ipv6AddrStatus =
M2_ipv6AddrStatus_preferred;
}
else /* M2_NEXT_VALUE */
{
pIfIndexEntry = m2Ipv6AvlSearch (pM2IfRoot, *index);
if (!pIfIndexEntry)
{
/* The required ifIndex doesn't contain IPV6 address. Move to the next
ifIndex if there is any.*/
pIfIndexEntry = m2Ipv6AvlSuccessorGet (pM2IfRoot, *index);
if (!pIfIndexEntry)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
}
do
{
*index = pIfIndexEntry->ifIndex;
/* Get the pointer to the ifnet struct for this ifIndex */
pIfNetEntry = (struct ifnet *) pIfIndexEntry->pIfStats;
/* go throught the list, pick up IPV6 addresses and remember
the firsh higher to the required one */
for(ifa = pIfNetEntry->if_addrhead.tqh_first;ifa != NULL; ifa = ifa->ifa_link.tqe_next)
{
if (ifa->ifa_addr->sa_family == AF_INET6)
{
memcpy (&currIp6Addr, IFA_IN6(ifa),
sizeof (struct in6_addr));
NTOHL_IPV6ADDR(&currIp6Addr);
if ((m2Ipv6AddrCmp(&currIp6Addr, &ip6Addr) > 0) &&
(m2Ipv6AddrCmp(&currIp6Addr, (struct in6_addr *)entrySaved.ipv6AddrAddress) < 0))
{
memcpy (entrySaved.ipv6AddrAddress, &currIp6Addr,
sizeof (struct in6_addr));
ia = (struct in6_ifaddr *)ifa;
entrySaved.ipv6AddrPfxLength =
prefix(IA6_MASKIN6(ia), sizeof(struct in6_addr));
ia = (struct in6_ifaddr *)ifa;
/* stateful state not implemented yet */
if (ia->ia6_flags & IN6_IFF_AUTOCONF)
entrySaved.ipv6AddrType =
M2_ipv6AddrType_stateless;
/* else if (ia->ia6_flags & IN6_IFF_xxxxxxx)
entrySaved.ipv6AddrType =
M2_ipv6AddrType_stateful;*/
else
entrySaved.ipv6AddrType =
M2_ipv6AddrType_unknown;
/* ****** */
if (ia->ia6_flags & IN6_IFF_DEPRECATED)
entrySaved.ipv6AddrStatus =
M2_ipv6AddrStatus_deprecated;
else if (ia->ia6_flags & (IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED))
entrySaved.ipv6AddrStatus =
M2_ipv6AddrStatus_invalid;
else if (ia->ia6_flags & IN6_IFF_DETACHED)
entrySaved.ipv6AddrStatus =
M2_ipv6AddrStatus_inaccessible;
else
entrySaved.ipv6AddrStatus =
M2_ipv6AddrStatus_preferred;
found = TRUE;
}
}
}
if (found) /* there was bigger address, otherwise try the next ifIndex */
{
memcpy (pIpv6AddrTblEntry->ipv6AddrAddress, entrySaved.ipv6AddrAddress,
sizeof (struct in6_addr));
pIpv6AddrTblEntry->ipv6AddrPfxLength = entrySaved.ipv6AddrPfxLength;
pIpv6AddrTblEntry->ipv6AddrType = entrySaved.ipv6AddrType;
pIpv6AddrTblEntry->ipv6AddrAnycastFlag = entrySaved.ipv6AddrAnycastFlag;
pIpv6AddrTblEntry->ipv6AddrStatus = entrySaved.ipv6AddrStatus;
break;
}
/* The required address was the biggest in the required ifIndex.
Move to the next ifIndex and choose the smallest one */
pIfIndexEntry = m2Ipv6AvlSuccessorGet (pM2IfRoot, *index);
/* set new limits for the next ifIndex */
/* largest IP address */
memset (entrySaved.ipv6AddrAddress, 0xff, sizeof (struct in6_addr));
/* smallest IP address */
memset (&ip6Addr, 0x00, sizeof (struct in6_addr));
} while (pIfIndexEntry);
}
if (!found)
{
semGive (m2InterfaceSem);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
semGive (m2InterfaceSem);
return (OK);
}
/******************************************************************************
*
* m2Ipv6RouteEntryCmp - compare two IPv6 route table entries in
* lexicographical order
*
* This routine compares two IPv6 route table entries. It compares the value 1
* with value 2. It returns equal, value 1 greater than value 2, or value 1
* less than value 2. The comparison is done based on the lexicographical
* order specified by IPv6 MIB.
*
* RETURNS: 0 = equal, 1 > greater than, and -1 < less than.
*
* SEE ALSO: N/A
*/
LOCAL int m2Ipv6RouteEntryCmp
(
struct in6_addr * addr1,
struct in6_addr * addr2,
int length1,
int length2,
unsigned long index1,
unsigned long index2
)
{
int result;
/* Comparison of two IPv6 addresses */
result = m2Ipv6AddrCmp(addr1, addr2);
if (result > 0)
{
return 1; /* First Entry is Greater */
}
if (result < 0)
{
return -1; /* First Entry is Smaller */
}
/* Comparison of two signed values */
result = length1 - length2;
if (result != 0)
return (result); /* Value > 0 or < 0 */
/* Result will determine Equal, Less than or Greater than */
return (index1 - index2);
}
/******************************************************************************
*
* m2Ipv6RouteInfoGet - get the MIB-II IPv6 routing scalar variables
*
* This routine fills in the structure at <pIpv6RouteInfo> with the values of
* IPv6 routing objects.
*
* RETURNS: OK if successful, otherwise ERROR.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_ENTRY_NOT_FOUND
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntryGet(),m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(),
* m2Ipv6AddrTblEntryGet(),m2Ipv6RouteTblEntryGet(), m2Ipv6RouteTblEntrySet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6RouteInfoGet
(
M2_IPV6ROUTE * pIpv6RouteInfo /* pointer to IPV6 routing objects structure */
)
{
/* Validate Pointer to the requested IPv6 routing objects structure */
if (pIpv6RouteInfo == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR);
}
semTake (priv_m2Ipv6RouteSem, WAIT_FOREVER); /* protect the cache */
/* Reread the route table if it has since been modified. */
if (m2Ipv6RouteTableGet (priv_m2Ipv6RouteTable, priv_m2Ipv6RouteTableSize) == ERROR)
{
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
semGive (priv_m2Ipv6RouteSem);
return (ERROR); /* no such entry */
}
pIpv6RouteInfo->ipv6RouteNumber = priv_m2Ipv6NumRouteEntries;
pIpv6RouteInfo->ipv6DiscardedRoutes = priv_m2Ipv6DiscardedRoutes;
semGive (priv_m2Ipv6RouteSem); /* release cache */
return (OK);
}
/******************************************************************************
*
* m2Ipv6RouteTblEntryGet - get a MIB-II IPv6 routing table entry
*
* This routine retrieves MIB-II information about an entry in the network
* IPv6 routing table and returns it in the caller-supplied structure
* <pIpv6RouteTblEntry>.
*
* The routine compares IPv6 routing table entries to the MIB-II entry index. The
* index is made up of the `ipv6RouteDest', 'ipv6RoutePfxLength' and
* 'ipv6RouteIndex', members of the <pIpv6RouteTblEntry> structure. The routine
* retrieves an entry chosen by the <search> type (M2_EXACT_VALUE or
* M2_NEXT_VALUE, as described in the manual entry for m2Lib).
*
* RETURNS: OK if successful, otherwise ERROR.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_ENTRY_NOT_FOUND
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntryGet(), m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(),
* m2Ipv6AddrTblEntryGet(), m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntrySet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6RouteTblEntryGet
(
int search, /* M2_EXACT_VALUE or M2_NEXT_VALUE */
M2_IPV6ROUTETBL * pIpv6RouteTblEntry /* IPv6 routing table entry */
)
{
unsigned long ix;
unsigned long index;
struct in6_addr savedDest;
int savedPfxLength;
unsigned long savedIndex;
struct in6_addr tableDest;
struct in6_addr dstIpAddr;
/* Validate the arguments */
if ((pIpv6RouteTblEntry == NULL) || ((search != M2_EXACT_VALUE) &&
(search != M2_NEXT_VALUE)))
{
errnoSet(S_m2Lib_INVALID_PARAMETER);
return (ERROR); /* invalid argument */
}
memcpy (&dstIpAddr, pIpv6RouteTblEntry->ipv6RouteDest,
sizeof (struct in6_addr));
semTake (priv_m2Ipv6RouteSem, WAIT_FOREVER); /* protect the cache */
/* Reread the route table if it has since been modified. */
if (m2Ipv6RouteTableGet (priv_m2Ipv6RouteTable, priv_m2Ipv6RouteTableSize) == ERROR)
{
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
semGive (priv_m2Ipv6RouteSem);
return (ERROR); /* no such entry */
}
/* Largest IP address */
memset (&savedDest, 0xff, sizeof (struct in6_addr));
savedPfxLength = 128; /* Largest prefix length */
savedIndex = -1; /* Largest index */
/* Find Match */
for (ix = 0, index = priv_m2Ipv6NumRouteEntries; ix < priv_m2Ipv6NumRouteEntries; ix++)
{
/* XXX */
memcpy (&tableDest, priv_m2Ipv6RouteTable [ix].ipv6RouteDest,
sizeof (struct in6_addr));
NTOHL_IPV6ADDR(&tableDest);
if (search == M2_EXACT_VALUE)
{
if (IN6_ARE_ADDR_EQUAL(&dstIpAddr, &tableDest) &&
pIpv6RouteTblEntry->ipv6RoutePfxLength == priv_m2Ipv6RouteTable [ix].ipv6RoutePfxLength &&
pIpv6RouteTblEntry->ipv6RouteIndex == priv_m2Ipv6RouteTable [ix].ipv6RouteIndex)
{
index = ix;
break; /* found exact match */
}
}
else /* (search == M2_NEXT_VALUE) */
{
/* Find the next dest value. The alternative to
* going through the entire array each time is to sort it.
* Which is more expensive is dependent on how often
* new routes get added to the table, how often this is used,
* and how long the list is.
*/
if ((m2Ipv6RouteEntryCmp(&tableDest, &dstIpAddr,
priv_m2Ipv6RouteTable [ix].ipv6RoutePfxLength, pIpv6RouteTblEntry->ipv6RoutePfxLength,
priv_m2Ipv6RouteTable [ix].ipv6RouteIndex, pIpv6RouteTblEntry->ipv6RouteIndex) > 0) &&
(m2Ipv6RouteEntryCmp(&tableDest, &savedDest,
priv_m2Ipv6RouteTable [ix].ipv6RoutePfxLength, savedPfxLength,
priv_m2Ipv6RouteTable [ix].ipv6RouteIndex, savedIndex) < 0))
{
memcpy (&savedDest, &tableDest, sizeof (struct in6_addr));
savedPfxLength = priv_m2Ipv6RouteTable [ix].ipv6RoutePfxLength;
savedIndex = priv_m2Ipv6RouteTable [ix].ipv6RouteIndex;
index = ix;
}
}
}
if (index >= priv_m2Ipv6NumRouteEntries)
{
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
semGive (priv_m2Ipv6RouteSem);
return (ERROR); /* no such entry */
}
/* fill in return structure */
bcopy ((char *) &priv_m2Ipv6RouteTable [index], (char *) pIpv6RouteTblEntry,
sizeof (M2_IPV6ROUTETBL));
pIpv6RouteTblEntry->ipv6RouteAge =
(tickGet () - pIpv6RouteTblEntry->ipv6RouteAge) / sysClkRateGet ();
semGive (priv_m2Ipv6RouteSem); /* release cache */
NTOHL_IPV6ADDR(pIpv6RouteTblEntry->ipv6RouteDest);
NTOHL_IPV6ADDR(pIpv6RouteTblEntry->ipv6RouteNextHop);
return (OK);
}
/******************************************************************************
*
* m2Ipv6RouteTblEntrySet - set a a MIB-II IPv6 routing table entry
*
* This routine deletes a network IPv6 routing table entry. The table entry to
* be deleted is specified by the `ipv6RouteDest', 'ipv6RoutePfxLength' and
* `ipv6RouteNextHop' members of the <pIpv6RouteTblEntry> structure. If
* `ipv6RouteValid' has the value of 'false(2)', then the the routing table
* entry is deleted.
*
* RETURNS: OK if successful, otherwise ERROR.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_BAD_VALUE
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntryGet(), m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(),
* m2Ipv6AddrTblEntryGet(), m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(),
* m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6RouteTblEntrySet
(
M2_IPV6ROUTETBL * pIpv6RouteTblEntry /* IPv6 route table entry */
)
{
struct in6_addr maskIp;
int flags = 0;
struct sockaddr_in6 gate;
if (pIpv6RouteTblEntry == NULL)
{
errnoSet(S_m2Lib_INVALID_PARAMETER);
return (ERROR); /* invalid argument */
}
/* it is not allowed to create new entry */
if (pIpv6RouteTblEntry->ipv6RouteValid != M2_FALSE)
{
errnoSet(S_m2Lib_BAD_VALUE);
return (ERROR);
}
/* delete the route */
if (pIpv6RouteTblEntry->ipv6RouteValid == M2_FALSE)
{
if (m2Ipv6RouteTblEntryGet (M2_EXACT_VALUE, pIpv6RouteTblEntry) != OK)
return (ERROR);
/* Convert from host order to network order */
HTONL_IPV6ADDR(pIpv6RouteTblEntry->ipv6RouteDest);
HTONL_IPV6ADDR(pIpv6RouteTblEntry->ipv6RouteNextHop);
in6_prefixlen2mask (&maskIp, pIpv6RouteTblEntry->ipv6RoutePfxLength);
flags |= RTF_MGMT;
/*
* Remove the matching route. Report the change using
* both routing socket messages and direct callbacks.
*/
return (m2Ipv6SystemRouteDelete ((struct in6_addr *) pIpv6RouteTblEntry->ipv6RouteDest,
(struct in6_addr *) pIpv6RouteTblEntry->ipv6RouteNextHop,
&maskIp, flags));
}
/* otherwise change it */
else
{
/* Convert from host order to network order */
HTONL_IPV6ADDR(pIpv6RouteTblEntry->ipv6RouteDest);
HTONL_IPV6ADDR(pIpv6RouteTblEntry->ipv6RouteNextHop);
in6_prefixlen2mask (&maskIp, pIpv6RouteTblEntry->ipv6RoutePfxLength);
flags |= RTF_MGMT;
gate.sin6_len = sizeof (struct sockaddr_in6);
gate.sin6_family = AF_INET6;
memcpy (&gate.sin6_addr, pIpv6RouteTblEntry->ipv6RouteNextHop, sizeof (struct in6_addr));
if (ifa_ifwithaddr ((struct sockaddr *)&gate) == NULL)
flags |= RTF_GATEWAY;
/*
* Add the requested route using the default weight value. Report
* the change using both routing socket messages and direct callbacks.
*/
if (m2Ipv6SystemRouteAdd ((struct in6_addr *) pIpv6RouteTblEntry->ipv6RouteDest,
(struct in6_addr *) pIpv6RouteTblEntry->ipv6RouteNextHop,
&maskIp, flags) != OK)
return (ERROR);
}
return (OK);
}
/******************************************************************************
*
* m2Ipv6SystemRouteAdd - add a IPv6 route to the system routing database
*
* This routine adds the IPv6 route to the system routing database using the
* method which the particular product supports.
*
* RETURNS: ERROR or OK (return value from selected add method)
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS m2Ipv6SystemRouteAdd
(
struct in6_addr * pDstIp, /* destination address, network order */
struct in6_addr * pGateIp, /* gateway address, network order */
struct in6_addr * pMaskIp, /* mask for destination, network order */
int flags /* route flags */
)
{
int rSockFd;
int msgLen;
int errStatus = 0;
struct rt_msghdr *pRtm;
struct sockaddr_in6 *pDest;
struct sockaddr_in6 *pGate;
struct sockaddr_in6 *pMask;
msgLen = sizeof (struct rt_msghdr) + 3 * sizeof (struct sockaddr_in6);
if ((pRtm = (struct rt_msghdr *) malloc (msgLen)) == NULL)
return (ERROR);
else
bzero ((char *) pRtm, msgLen);
/* Open a routing socket */
if ((rSockFd = socket (AF_ROUTE, SOCK_RAW, 0)) == ERROR)
{
free (pRtm);
return (ERROR);
}
pRtm->rtm_msglen = msgLen;
pRtm->rtm_version = RTM_VERSION;
pRtm->rtm_type = RTM_ADD;
pRtm->rtm_flags |= flags;
pRtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
pDest = (struct sockaddr_in6 *) (pRtm + 1);
pDest->sin6_len = sizeof (struct sockaddr_in6);
pDest->sin6_family = AF_INET6;
memcpy (&pDest->sin6_addr, pDstIp, sizeof (struct in6_addr));
pGate = pDest + 1;
pGate->sin6_len = sizeof (struct sockaddr_in6);
pGate->sin6_family = AF_INET6;
memcpy (&pGate->sin6_addr, pGateIp, sizeof (struct in6_addr));
pMask = pGate + 1;
pMask->sin6_len = sizeof (struct sockaddr_in6);
pMask->sin6_family = AF_INET6;
memcpy (&pMask->sin6_addr, pMaskIp, sizeof (struct in6_addr));
if (send (rSockFd, (char *) pRtm, msgLen, 0) == msgLen)
{
close (rSockFd);
free (pRtm);
return (OK);
}
else
{
close (rSockFd);
free (pRtm);
/* set errno again because it's cleared by close () */
errnoSet (errStatus);
return (ERROR);
}
}
/******************************************************************************
*
* m2Ipv6SystemRouteDelete - delete a IPv6 route from the system routing database
*
* This routine deletes a IPv6 route from the system routing database using the
* method which the particular product supports.
*
* RETURNS: ERROR or OK (return value from selected delete method)
*
* ERRNO: N/A
*
* NOMANUAL
*/
LOCAL STATUS m2Ipv6SystemRouteDelete
(
struct in6_addr * pDstIp, /* destination address, network order */
struct in6_addr * pGateIp, /* gateway address, network order */
struct in6_addr * pMaskIp, /* mask for destination, network order */
int flags /* route flags */
)
{
int rSockFd;
int msgLen;
int errStatus = 0;
struct rt_msghdr *pRtm;
struct sockaddr_in6 *pDest;
struct sockaddr_in6 *pGate;
struct sockaddr_in6 *pMask;
msgLen = sizeof (struct rt_msghdr) + 3 * sizeof (struct sockaddr_in6);
if ((pRtm = (struct rt_msghdr *) malloc (msgLen)) == NULL)
return (ERROR);
else
bzero ((char *) pRtm, msgLen);
/* Open a routing socket */
if ((rSockFd = socket (AF_ROUTE, SOCK_RAW, 0)) == ERROR)
{
free (pRtm);
return (ERROR);
}
pRtm->rtm_msglen = msgLen;
pRtm->rtm_version = RTM_VERSION;
pRtm->rtm_type = RTM_DELETE;
pRtm->rtm_flags |= flags;
pRtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
pDest = (struct sockaddr_in6 *) (pRtm + 1);
pDest->sin6_len = sizeof (struct sockaddr_in6);
pDest->sin6_family = AF_INET6;
memcpy (&pDest->sin6_addr, pDstIp, sizeof (struct in6_addr));
pGate = pDest + 1;
pGate->sin6_len = sizeof (struct sockaddr_in6);
pGate->sin6_family = AF_INET6;
memcpy (&pGate->sin6_addr, pGateIp, sizeof (struct in6_addr));
pMask = pGate + 1;
pMask->sin6_len = sizeof (struct sockaddr_in6);
pMask->sin6_family = AF_INET;
memcpy (&pMask->sin6_addr, pMaskIp, sizeof (struct in6_addr));
if (send (rSockFd, (char *) pRtm, msgLen, 0) == msgLen)
{
close (rSockFd);
free (pRtm);
return (OK);
}
else
{
close (rSockFd);
free (pRtm);
/* set errno again because it's cleared by close () */
errnoSet (errStatus);
return (ERROR);
}
}
/* generic structure for traversing the route table XXX move elsewhere */
typedef struct
{
ULONG arg1;
ULONG arg2;
ULONG arg3;
ULONG arg4;
} RT_IPV6TBL_ARGS;
/******************************************************************************
*
* m2Ipv6RouteCacheInit - fill the route cache with routing information
*
* Function to pass to ipRouteTableWalk().
*/
LOCAL void m2Ipv6RouteCacheInit
(
struct rtentry * pRoute,
void * pRtArg
)
{
M2_IPV6ROUTETBL * pRouteCache; /* the route table cache */
M2_IPV6ROUTETBL * pEntry; /* pointer to route cache */
unsigned long routeCacheSize; /* size of cache */
unsigned long * pRouteCacheIx;
unsigned long * pDiscardedRoutes;
struct sockaddr_in6 * pSin; /* address pointer */
pRouteCache =(M2_IPV6ROUTETBL *)((RT_IPV6TBL_ARGS *)pRtArg)->arg1;
routeCacheSize = (unsigned long )((RT_IPV6TBL_ARGS *)pRtArg)->arg2;
pRouteCacheIx = (unsigned long * )&((RT_IPV6TBL_ARGS *)pRtArg)->arg3;
pDiscardedRoutes = (unsigned long * )&((RT_IPV6TBL_ARGS *)pRtArg)->arg4;
if (*pRouteCacheIx >= routeCacheSize) /* terminate the table walk */
return;
/* implementation specific */
if ((pRoute->rt_flags & RTF_UP) == 0) /* go to the next entry */
return;
/* Get the next entry to add */
pEntry = &pRouteCache [*pRouteCacheIx];
/* implementation specific */
pEntry->ipv6RouteValid = M2_TRUE;
pEntry->ipv6RouteIndex = (unsigned long ) pRoute;
pSin = (struct sockaddr_in6 *) pRoute->rt_gateway;
/*
* Test whether the gateway is of type AF_LINK and if so
* test whether it is a real arp entry because interfaces
* initialized with RTF_CLONE flag have a dummy gateway of
* type AF_LINK. If it is a real arp entry then skip to next
* entry, we are only dealing with gateways of type AF_INET6.
*/
if (pRoute->rt_gateway->sa_family == AF_LINK)
{
if (((struct sockaddr_dl *)pSin)->sdl_alen)
pSin = NULL;
else
pSin = (struct sockaddr_in6 *)pRoute->rt_ifa->ifa_addr;
}
if (pSin == NULL)
return;
memcpy (pEntry->ipv6RouteNextHop, &pSin->sin6_addr,
sizeof (struct in6_addr));
pSin = (struct sockaddr_in6 *) rt_key(pRoute);
memcpy (pEntry->ipv6RouteDest, &pSin->sin6_addr,
sizeof (struct in6_addr));
pEntry->ipv6RouteIfIndex = pRoute->rt_ifp->if_index;
/* fill in the route mask */
if (rt_mask (pRoute) == NULL) /* implicit prefix length 128 */
pEntry->ipv6RoutePfxLength = 128;
else
pEntry->ipv6RoutePfxLength =
prefix(&((struct sockaddr_in6 *)rt_mask(pRoute))->sin6_addr,
sizeof(struct in6_addr));
pEntry->ipv6RouteAge = pRoute->rt_mod; /* initialize last modified */
/* is it a direct or indirect route ? */
if (pRoute->rt_flags & RTF_GATEWAY)
{
pEntry->ipv6RouteMetric = 1; /* 1 means non local */
pEntry->ipv6RouteType = M2_ipv6RouteType_remote;
}
else
pEntry->ipv6RouteType = M2_ipv6RouteType_local;
if (pRoute->rt_flags & RTF_MGMT)
pEntry->ipv6RouteProtocol = M2_ipv6RouteProtocol_netmgmt;
else if (pRoute->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))
pEntry->ipv6RouteProtocol = M2_ipv6RouteProtocol_ndisc;
else
{
/*
* Routes created using the routeLib API store the correct protocol
* value using the RT_PROTO_SET macro. The RT_PROTO_GET macro
* retrieves that information. All routing protocols must alter
* the kernel routing table using the routeLib API so that the
* IP group MIB variables can return the correct settings. Both RIP
* and OSPF comply with this requirement.
*/
pEntry->ipv6RouteProtocol = RT_PROTO_GET (pSin);
if (pEntry->ipv6RouteProtocol == M2_ipv6RouteProtocol_idrp)
{
/*
* The VxWorks RIP implementation stores the advertised metric
* in the (normally unused) rmx_hopcount field of the kernel's
* routing table. Use that value instead of the simple 0/1
* boolean for local or remote routes assigned earlier.
*/
pEntry->ipv6RouteMetric = pRoute->rt_rmx.rmx_hopcount;
}
else if (pEntry->ipv6RouteProtocol == 0)
{
/*
* Entries added through ioctl() calls on a routing socket or
* otherwise created directly without using the API have an
* undefined value of 0 in the protocol type field. Replace it
* with the correct setting.
*/
if (pRoute->rt_flags & RTF_LLINFO)
{
/*
* Sanity check: handle route entries for link-level
* protocols such as ARP in case they are not ignored
* as expected.
*/
pEntry->ipv6RouteProtocol = M2_ipv6RouteProtocol_other;
}
else
{
/* Handle protocol-independent locally generated entries. */
pEntry->ipv6RouteProtocol = M2_ipv6RouteProtocol_local;
}
}
}
if (pRoute->rt_flags & RTF_BLACKHOLE)
(*pDiscardedRoutes)++;
(*pRouteCacheIx)++; /* increment the index */
return;
}
/******************************************************************************
*
* m2Ipv6RouteTableGet - get a copy of the IPv6 network routing table.
*
* This routine gets a copy of the IPv6 network routing table and puts
* it into a pre-allocated route table cache. The route table cache is
* specified by <pRouteCache> and the size of the cache is <routeCacheSize>.
*
* RETURNS: OK if successful, otherwise ERROR.
*
* ERRNO
* S_m2Lib_INVALID_PARAMETER
*/
LOCAL STATUS m2Ipv6RouteTableGet
(
M2_IPV6ROUTETBL * pRouteCache, /* the route table cache */
unsigned long routeCacheSize /* size of cache */
)
{
M2_IPV6ROUTETBL * pEntry; /* pointer to route cache */
unsigned long routeCacheIx; /* route cache index */
int spl; /* for splnet */
RT_IPV6TBL_ARGS rtTblArgs;
/* Validate argument */
if (pRouteCache == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR); /* bad parameter passed */
}
/* If the network interface table has been changed, re-read it */
semTake (m2InterfaceSem, WAIT_FOREVER); /* protect interface */
/* Clear out the routing table and rebuild it */
bzero ((char *) pRouteCache, routeCacheSize * (sizeof (M2_IPV6ROUTETBL)));
for (routeCacheIx = 0; routeCacheIx < routeCacheSize; routeCacheIx++)
{
pEntry = &pRouteCache [routeCacheIx];
/* fill in defaults */
pEntry->ipv6RouteMetric = -1;
bcopy ((char *) &ipZeroObjectId, (char *) &pEntry->ipv6RouteInfo,
sizeof (ipZeroObjectId));
}
routeCacheIx = 0;
rtTblArgs.arg4 = 0;
rtTblArgs.arg1 = (ULONG) pRouteCache;
rtTblArgs.arg2 = (ULONG) routeCacheSize;
rtTblArgs.arg3 = (ULONG) routeCacheIx;
spl = splnet ();
ipRouteTableWalk (ROUTE_USAGE_IPV6,
m2Ipv6RouteCacheInit, (void *) &rtTblArgs);
/* Number of routes in the system */
priv_m2Ipv6NumRouteEntries = rtTblArgs.arg3;
/* Number of discarded routes in the system */
priv_m2Ipv6DiscardedRoutes = rtTblArgs.arg4;
splx (spl);
semGive (m2InterfaceSem);
return (OK); /* return the number of entries */
}
/******************************************************************************
*
* m2Ipv6AtransTblEntryGet - get a MIB-II IPv6 address translation table entry
*
* This routine traverses the ND table and does an M2_EXACT_VALUE or a
* M2_NEXT_VALUE search based on the <search> parameter. The calling
* routine is responsible for supplying a valid MIB-II entry index in the
* input parameters <index> and <pReqIpv6AtEntry>. The index is made up of the
* interface index and the IPv6 address corresponding to the physical address.
* The first entry in the table is retrieved by doing a NEXT search with the
* MIB-II entry index set to zero.
*
* RETURNS:
* OK, ERROR if the input parameter is not specified, or a match is not found.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_ENTRY_NOT_FOUND
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntryGet(), m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(),
* m2Ipv6AddrTblEntryGet(), m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(),
* m2Ipv6RouteTblEntrySet(), m2Ipv6AtransTblEntrySet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6AtransTblEntryGet
(
int search, /* M2_EXACT_VALUE or M2_NEXT_VALUE */
int * index, /* requested interface index */
M2_IPV6ATRANSTBL * pReqIpv6AtEntry /* ptr to the requested At tbl entry */
)
{
struct in6_addr ipv6AddrSaved; /* Used for a NEXT search */
struct in6_addr currIpv6Addr; /* Current IPv6 address Table index req */
struct in6_addr reqIpv6Addr; /* required IPv6 address */
int ix; /* All purpose loop Index */
int netLock; /* Use to secure the Network Code Access */
int indexSaved; /* used for a NEXT search */
int currIndex; /* current interface index required */
struct llinfo_nd6 * pLnkInfo;
struct rtentry * pRtEnt;
struct rtentry * pRtEntMatch;
struct llinfo_nd6 * pLnkInfoMatch;
/* Validate Pointer to AT request structure */
if (pReqIpv6AtEntry == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR);
}
/* Initialize all local variable before the Network Semaphore is taken */
ix = 0;
pLnkInfoMatch = NULL; /* initialized to NULL */
indexSaved = ipMaxUnits; /* largest possible value */
memset (&ipv6AddrSaved, 0xff, sizeof (struct in6_addr));
memcpy (&reqIpv6Addr, pReqIpv6AtEntry->ipv6NetToMediaNetAddress,
sizeof (struct in6_addr));
netLock = splnet (); /* Get exclusive access to Network Code */
/*
* Traverse the ND Table. The whole table is searched
*/
pLnkInfo = _llinfo_nd6.ln_next;
while (pLnkInfo && pLnkInfo != &_llinfo_nd6)
{
pRtEnt = pLnkInfo->ln_rt;
memcpy (&currIpv6Addr, ((struct sockaddr_in6 *)
rt_key(pRtEnt))->sin6_addr.s6_addr,
sizeof (struct in6_addr));
NTOHL_IPV6ADDR(&currIpv6Addr);
currIndex = pRtEnt->rt_ifp->if_index;
if (search == M2_NEXT_VALUE)
{
/*
* A NEXT search is satisfied by an IP address lexicographicaly
* greater than the input IPv6 address. Because IPv6
* addresses are not in order in the ND table, the list must
* be traverse completely before a selection is made.
*/
if (((currIndex > *index) ||
((currIndex == *index) &&
(m2Ipv6AddrCmp(&currIpv6Addr, &reqIpv6Addr) > 0))) &&
((currIndex < indexSaved) || ((currIndex == indexSaved) &&
(m2Ipv6AddrCmp(&currIpv6Addr, &ipv6AddrSaved) < 0))))
{
pLnkInfoMatch = pLnkInfo; /* Found Requested Entry */
memcpy (&ipv6AddrSaved, &currIpv6Addr,
sizeof (struct in6_addr));
indexSaved = currIndex;
}
}
else
{
/* Search for an EXACT match in the ND Table */
if ((currIndex == *index) &&
(m2Ipv6AddrCmp(&currIpv6Addr, &reqIpv6Addr) == 0))
{
pLnkInfoMatch = pLnkInfo; /* Found Requested Entry */
memcpy (&ipv6AddrSaved, &currIpv6Addr,
sizeof (struct in6_addr));
break;
}
}
pLnkInfo = pLnkInfo->ln_next;
}
/* pRtEntMatch is pointer to the route for the IP address found
* The interface pointer is obtained from pRtEntMatch. This pointer is
* used as a key to search the MIB-II interface table, once the key is
* matched the interface number is found.
*/
if (pLnkInfoMatch != NULL)
{
struct ifnet * ifp;
struct nd_ifinfo * pNdIfInfo;
ifp = ifindex2ifnet[*index];
if (ifp == NULL)
{
splx (netLock);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
pNdIfInfo =
((struct in6_ifextra *)(ifp->if_afdata[AF_INET6]))->nd_ifinfo;
if (pNdIfInfo == NULL)
{
splx (netLock);
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
/* Search for Interface number in the MIB-II interface table */
pRtEntMatch = pLnkInfoMatch->ln_rt;
*index = pRtEntMatch->rt_ifp->if_index;
/* Fill requested ND entry */
memcpy (pReqIpv6AtEntry->ipv6NetToMediaNetAddress, &ipv6AddrSaved,
sizeof (struct in6_addr));
pReqIpv6AtEntry->ipv6NetToMediaType =
(pLnkInfoMatch->ln_expire == 0) ?
M2_ipv6NetToMediaType_static :
M2_ipv6NetToMediaType_dynamic;
pReqIpv6AtEntry->ipv6NetToMediaState = (int) pLnkInfoMatch->ln_state;
bcopy (LLADDR((struct sockaddr_dl *) pRtEntMatch->rt_gateway),
(char *) pReqIpv6AtEntry->ipv6NetToMediaPhysAddress.phyAddress,
ETHERADDRLEN);
pReqIpv6AtEntry->ipv6NetToMediaLastUpdated = 0;
if (pLnkInfoMatch->ln_expire == 0)
pReqIpv6AtEntry->ipv6NetToMediaLastUpdated = 0;
else if (pLnkInfoMatch->ln_state == ND6_LLINFO_INCOMPLETE)
pReqIpv6AtEntry->ipv6NetToMediaLastUpdated =
pLnkInfoMatch->ln_expire - pNdIfInfo->retrans / 1000;
else if (pLnkInfoMatch->ln_state == ND6_LLINFO_REACHABLE)
pReqIpv6AtEntry->ipv6NetToMediaLastUpdated =
pLnkInfoMatch->ln_expire - pNdIfInfo->reachable;
else if (pLnkInfoMatch->ln_state == ND6_LLINFO_STALE)
pReqIpv6AtEntry->ipv6NetToMediaLastUpdated =
pLnkInfoMatch->ln_expire - nd6_gctimer;
else if (pLnkInfoMatch->ln_state == ND6_LLINFO_DELAY)
pReqIpv6AtEntry->ipv6NetToMediaLastUpdated =
pLnkInfoMatch->ln_expire - _nd6_delay;
else if (pLnkInfoMatch->ln_state == ND6_LLINFO_PROBE)
pReqIpv6AtEntry->ipv6NetToMediaLastUpdated =
pLnkInfoMatch->ln_expire - pNdIfInfo->retrans / 1000;
/* ipv6NetToMediaLastUpdated is of TimeStamp type = TimeTicks =>
in 100 of sec */
pReqIpv6AtEntry->ipv6NetToMediaLastUpdated =
pReqIpv6AtEntry->ipv6NetToMediaLastUpdated * 100;
pReqIpv6AtEntry->ipv6NetToMediaValid = M2_TRUE;
splx (netLock); /* Give up exclusive access to Network Code */
pReqIpv6AtEntry->ipv6NetToMediaPhysAddress.addrLength = ETHERADDRLEN;
return (OK);
}
splx (netLock); /* Give up exclusive access to Network Code */
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
/******************************************************************************
*
* m2Ipv6AtransTblEntrySet - set a MIB-II IPv6 address translation table entry
*
* This routine traverses the ND table for the entry specified in the parameters
* <index> and <pReqIpv6AtEntry>. An ND entry can be deleted. A MIB-II entry
* index is specified by the interface index and destination IPv6 address
* corresponding to the physical address. An entry is deleted by specifying the
* MIB-II entry index and setting the 'ipv6NetToMediaValid' in the input
* parameter <pReqIpv6AtEntry> to the MIB-II value "false(2)".
*
* RETURNS:
* OK, ERROR if the input parameter is not specified, or a match is not found.
*
* ERRNO:
* S_m2Lib_INVALID_PARAMETER
* S_m2Lib_ENTRY_NOT_FOUND
* S_m2Lib_INVALID_VAR_TO_SET
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntryGet(), m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(),
* m2Ipv6AddrTblEntryGet(), m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(),
* m2Ipv6RouteTblEntrySet(), m2Ipv6AtransTblEntryGet(), m2Ipv6IfDelete(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6AtransTblEntrySet
(
int index, /* requested index */
M2_IPV6ATRANSTBL * pReqIpv6AtEntry /* ptr to the requested At entry */
)
{
struct rtentry * pRtEnt;
M2_IFINDEX * pIfIndexEntry = NULL;
struct ifnet * pIfNet;
struct llinfo_nd6 * ln = NULL;
struct sockaddr_dl *sdl = NULL;
char * lladdr;
struct in6_addr reqIpv6Addr; /* required IPv6 address */
int s, rf;
ULONG flags;
/* Validate Pointer to AT request structure */
if (pReqIpv6AtEntry == NULL)
{
errnoSet (S_m2Lib_INVALID_PARAMETER);
return (ERROR);
}
/* it is not allowed to create new entry */
if (pReqIpv6AtEntry->ipv6NetToMediaValid != M2_FALSE)
{
errnoSet (S_m2Lib_BAD_VALUE);
return (ERROR);
}
memcpy (&reqIpv6Addr, pReqIpv6AtEntry->ipv6NetToMediaNetAddress,
sizeof (struct in6_addr));
HTONL_IPV6ADDR(&reqIpv6Addr);
lladdr = (char *) pReqIpv6AtEntry->ipv6NetToMediaPhysAddress.phyAddress;
pIfIndexEntry = m2Ipv6AvlSearch (pM2IfRoot, index);
if (!pIfIndexEntry)
{
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
pIfNet = (struct ifnet *) pIfIndexEntry->pIfStats;
pRtEnt = nd6_lookup (&reqIpv6Addr, 0, pIfNet); /* search nd cache entry */
if (pReqIpv6AtEntry->ipv6NetToMediaValid == M2_FALSE) /* delete entry */
{
if (!pRtEnt)
{
errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
return (ERROR);
}
(void)nd6_free(pRtEnt, 0); /* delete nd cache entry */
return (OK);
}
else /* add new entry */
{
if (pRtEnt)
{
errnoSet (S_m2Lib_INVALID_VAR_TO_SET);
return (ERROR);
}
/* create nd cache entry */
pRtEnt = nd6_lookup (&reqIpv6Addr, 1, pIfNet);
if (!pRtEnt)
return (ERROR);
if ((pRtEnt->rt_flags & (RTF_GATEWAY | RTF_LLINFO)) != RTF_LLINFO)
{
fail:
(void)nd6_free(pRtEnt, 0);
return (ERROR);
}
ln = (struct llinfo_nd6 *)pRtEnt->rt_llinfo;
if (!ln)
goto fail;
if (!pRtEnt->rt_gateway)
goto fail;
if (pRtEnt->rt_gateway->sa_family != AF_LINK)
goto fail;
sdl = (struct sockaddr_dl *)(pRtEnt->rt_gateway);
if (lladdr)
{
/*
* Record source link-layer address
* XXX is it dependent to ifp->if_type?
*/
sdl->sdl_alen = pIfNet->if_addrlen;
bcopy(lladdr, LLADDR(sdl), pIfNet->if_addrlen);
}
ln->ln_state = ND6_LLINFO_STALE;
ln->ln_expire = 0;
ln->ln_router = 0;
s = splnet ();
flags = pRtEnt->rt_flags & ~RTF_DYNAMIC;
if (pIfNet->if_flags & IFF_LOOPBACK) /* is necessary ? */
{
flags &= ~RTF_STATIC;
flags |= RTF_LOCAL;
}
else
{
flags &= ~RTF_LOCAL;
flags |= RTF_STATIC;
}
/*
* A separate data structure for cloned routes will save
* space, but is not implemented for performance reasons,
* so neighor discovery entries use the same storage as
* "normal" IPv6 routes.
*/
rf = ROUTE_USAGE_IPV6;
/*
* Now change the flags. We use the splnet to protect against
* any concurrent change
*/
ipRouteModify (rt_key (pRtEnt), rt_mask (pRtEnt),
pRtEnt->rt_gateway, 0, ROUTE_TOS (pRtEnt),
ROUTE_PROTO (pRtEnt), ROUTE_MIB, rf, NULL, NULL,
&flags, NULL, NULL);
splx (s);
return(OK);
}
}
/*******************************************************************************
*
* m2Ipv6IfDelete - delete all resources used to access the IPv6 general-group
*
* This routine frees all the resources allocated when the IPv6 general-group was
* initialized. The IPv6 general-group should not be accessed after this routine
* has been called.
*
* RETURNS: OK, always.
*
* SEE ALSO: m2Ipv6IfInit(), m2Ipv6IfGeneralGet(), m2Ipv6IfGeneralSet(),
* m2Ipv6IfTblEntryGet(), m2Ipv6IfTblEntrySet(), m2Ipv6AddrPfxTblEntryGet(),
* m2Ipv6AddrTblEntryGet(), m2Ipv6RouteInfoGet(), m2Ipv6RouteTblEntryGet(),
* m2Ipv6RouteTblEntrySet(), m2Ipv6AtransTblEntryGet(), m2Ipv6AtransTblEntrySet(),
* m2Ipv6IfLib
*/
STATUS m2Ipv6IfDelete (void)
{
/* Free route semaphore */
if (priv_m2Ipv6RouteSem != NULL)
{
semDelete (priv_m2Ipv6RouteSem);
priv_m2Ipv6RouteSem = NULL;
}
/* Free route table */
if (priv_m2Ipv6RouteTable != NULL)
{
KHEAP_FREE ((char *) priv_m2Ipv6RouteTable);
priv_m2Ipv6RouteTable = NULL;
}
return (OK);
}