2710 lines
82 KiB
C
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);
|
|
}
|