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

972 lines
28 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_RCPL8_2024030303 $ $RCSfile: ipnet_rtnetlink_neigh.c,v $ $Revision: 1.16.10.6 $
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_rtnetlink_neigh.c,v $
* $Author: lwang7 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation Jonas Rendel <Jonas.Rendel@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
* Contains netlink handlers for managing Ipv4 and Ipv6 addresses.
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#ifndef IPCOM_KERNEL
#define IPCOM_KERNEL
#endif
#include "ipnet_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#ifdef IPNET_USE_NETLINK
#define IPCOM_USE_CLIB_PROTO
#include <ipcom.h>
#include <ipcom_type.h>
#include <ipcom_clib.h>
#include <ipcom_cstyle.h>
#include <ipcom_sock.h>
#include <ipcom_sock6.h>
#include <ipcom_sock2.h>
#include <ipcom_route.h>
#include <ipcom_errno.h>
#include "ipnet_h.h"
#include "ipnet_ctrl.h"
#include "ipnet_route.h"
#include "ipnet_netlink_h.h"
#include "ipnet_rtnetlink_h.h"
#include "ipcom_sock.h"
#ifdef IPCOM_USE_INET6
#include "ipcom_sock6.h"
#include "ipnet_ip6.h"
#endif
#ifdef IP_PORT_LKM
#include "ipcom_lkm.h" /* Needed for Linux PPP interface config */
#endif /* IP_PORT_LKM */
#include "ipnet_eth.h"
#ifdef IPCOM_FORWARDER_NAE
#include "ipcom_forwarder.h"
#endif
#ifdef IPNET_USE_VRRP
#include "ipnet_vrrp.h"
#endif
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef struct Ipnet_rtnetlink_neigh_family
{
struct
{
Ip_ptrdiff_t *vr;
Ip_ptrdiff_t *neigh;
Ip_ptrdiff_t *done;
Ip_ptrdiff_t aborted;
Ip_ptrdiff_t cont;
} state;
/* Requested */
struct Ip_nlmsghdr *nlmsg;
int family;
/* Buffering */
Ipnet_netlink_mem_t *mem;
}
Ipnet_rtnetlink_neigh_family_t;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
#ifdef IPNET_USE_VRRP
/*
*===========================================================================
* ipnet_eth_vrrp_dtor
*===========================================================================
* Description: Destructor for VRRP neighbors.
* Parameters: neigh - neighbor entry that is used to respond to ARP
* requests for the VRRP MAC.
* Returns:
*
*/
IP_STATIC void
ipnet_eth_vrrp_dtor(const Ipnet_neigh *neigh)
{
Ipnet_netif *netif = neigh->netif;
switch(neigh->domain)
{
case IP_AF_INET:
#ifdef IPCOM_USE_INET
if (ipnet_ip4_get_addr_type2(neigh->addr.in.s_addr, netif)
== IPNET_ADDR_TYPE_UNICAST)
/*
* Owner address, inform link local nodes about the MAC
* change
*/
ipnet_arp_request(netif,
0,
neigh->addr.in.s_addr,
IP_TRUE,
IP_NULL,
IP_NULL);
return;
#endif
default:
return;
}
}
/*
*===========================================================================
* ipnet_eth_vrrp_add_addr
*===========================================================================
* Description: Checks if the neighbor should be used for VRRP and
* adds the VRRP address in that case.
* Parameters: neigh - a neighbor entry.
* Returns: 0 = success
* <0 = error code
*
*/
IP_STATIC int
ipnet_eth_vrrp_add_addr(Ipnet_neigh *neigh)
{
Ip_u8 vrid = neigh->lladdr[5];
if ((ipnet_eth_get_vrrp_mac_addr_type(neigh->lladdr) == IPNET_NOT_VRRP_MAC_ADDRESS)
|| vrid == 0
|| ipnet_neigh_is_blackhole(neigh))
/*
* Should not be added as a VRRP address.
*/
return 0;
/* set VRRP address to be publish */
ipnet_neigh_set_publ(neigh, IP_TRUE);
return ipnet_vrrp_add_addr(neigh, vrid);
}
/*
*===========================================================================
* ipnet_eth_vrrp_del_addr
*===========================================================================
* Description: Removes a VRRP address
* Parameters: neigh - neighbor used to respond to ARP/ND request on the
* VRRP address.
* Returns:
*
*/
IP_STATIC int
ipnet_eth_vrrp_del_addr(Ipnet_neigh *neigh)
{
if (ipnet_eth_get_vrrp_mac_addr_type(neigh->lladdr) == IPNET_NOT_VRRP_MAC_ADDRESS)
return -IP_ERRNO_EINVAL;
return ipnet_vrrp_del_addr(neigh, neigh->lladdr[5], ipnet_eth_vrrp_dtor);
}
#endif
/*
*===========================================================================
* ipnet_rtnetlink_neigh_foreach
*===========================================================================
* Description: Called for each neighbor entry during dumping of
* neighbors via netlink.
* Parameters: neigh - a neighbor entry
* user_arg - pointer the the netlink dump parameters.
* Returns:
*
*/
IP_STATIC void
ipnet_rtnetlink_neigh_foreach(Ipnet_neigh *neigh, void *user_arg)
{
Ipnet_rtnetlink_neigh_family_t *param = user_arg;
Ip_u16 vr = neigh->netif->vr_index;
int ret = 0;
/*
* This traversal is already aborted
*/
if (param->state.aborted)
return;
/*
* Is this the right domain? AF_UNSPEC means we should dump all
* domain
*/
if (param->family != IP_AF_UNSPEC
&& neigh->key_domain != param->family)
return;
/*
* Check if specific VR shall be dumped.
*/
if (IP_BIT_ISFALSE(param->nlmsg->nlmsg_flags, IP_NLM_F_VR_UNSPEC)
&& (param->mem->vr != IPCOM_VR_ANY)
&& (param->mem->vr != vr))
return;
#ifdef IPCOM_USE_INET6
if (neigh->domain == IP_AF_INET6
&& ipnet_rtnetlink_ip6_neigh_not_local(neigh) == IP_FALSE)
return;
#endif
/*
* If this is a trailer message buffer, make sure it
* starts dumping where the last message ended
*/
if (param->state.cont)
{
Ipnet_neigh *prev_neigh = (Ipnet_neigh*)(*param->state.neigh);
/*
* Verify current state
*/
if (*param->state.vr != vr)
return;
if (prev_neigh != neigh)
/*
* Skip all entries until we get back to the entry we
* should continue from.
*/
return;
}
/*
* Reset the continue variable; we're on the move again
*/
param->state.cont = 0;
/*
* Verify this particular NC entry
*/
#ifdef IPCOM_USE_INET
if (neigh->domain == IP_AF_INET)
ret = ipnet_rtnetlink_ip4_neigh_fill_info(param->mem,
neigh,
param->nlmsg->nlmsg_seq,
IP_RTM_NEWNEIGH,
IP_NLM_F_MULTI);
#endif
#ifdef IPCOM_USE_INET6
if (neigh->domain == IP_AF_INET6)
ret = ipnet_rtnetlink_ip6_neigh_fill_info(param->mem,
neigh,
param->nlmsg->nlmsg_seq,
IP_RTM_NEWNEIGH,
IP_NLM_F_MULTI);
#endif
if (ret < 0)
goto aborted;
return;
aborted:
param->state.aborted = 1;
*param->state.neigh = (Ip_ptrdiff_t)neigh;
*param->state.vr = (Ip_ptrdiff_t)vr;
}
/*
*===========================================================================
* ipnet_rtnetlink_neigh_event
*===========================================================================
* Description: Status of a neighbor has changed create a netlink
* event to inform any listeners about it
* Parameters: neigh - neighbor entry that generated the event
* event - RTM_NEWNEIGH or RTM_DELNEIGH
* Returns: -
*
*/
IP_STATIC void
ipnet_rtnetlink_neigh_event(Ipnet_neigh *neigh, int event)
{
Ipcom_pkt *pkt = IP_NULL;
Ipnet_netlink_mem_t mem;
int ret = -1;
if (!ipnet_netlink_pkt_alloc(&pkt, IP_NULL, IP_TRUE, &mem, 512))
return;
/*
* Set the VR-index
*/
pkt->vr_index = mem.vr = neigh->netif->vr_index;
#ifdef IPCOM_USE_INET
if (neigh->domain == IP_AF_INET)
{
ret = ipnet_rtnetlink_ip4_neigh_fill_info (&mem,
neigh,
0,
event,
0);
}
#endif
#ifdef IPCOM_USE_INET6
if (neigh->domain == IP_AF_INET6)
{
if (ipnet_rtnetlink_ip6_neigh_not_local(neigh))
ret = ipnet_rtnetlink_ip6_neigh_fill_info (&mem,
neigh,
0,
event,
0);
}
#endif
if (ret < 0)
ipcom_pkt_free(pkt);
else
{
pkt->end += ret;
/*
* We're done; do report this pkt
*/
ipnet_rtnetlink_broadcast(pkt, IP_RTNLGRP_NEIGH);
}
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*==========================================================================
* ipnet_rtnetlink_getroute_family
*===========================================================================
* Description: Get interface info via NETLINK
* Parameters: data - Message payload.
* len - Length of message.
* cb - NETLINK callback entry
*
* Returns: 0 - Success
* <0 - Failure
*
*/
IP_GLOBAL int
ipnet_rtnetlink_neigh_get_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlh,
struct Ip_rtattr **rta,
int family)
{
struct Ip_ndmsg *ndm = IP_NLMSG_DATA(nlh);
int ret = -IP_ERRNO_EAFNOSUPPORT;
Ip_u16 vr;
Ipnet_netif *netif;
Ipnet_neigh *neigh;
/*
* Destination address required
*/
if (rta[IP_NDA_DST-1] == IP_NULL)
return -IP_ERRNO_EINVAL;
if (mem->vr == IPCOM_VR_ANY)
return -IP_ERRNO_EINVAL;
vr = ipnet_rtnetlink_vr(rta[IP_NDA_VR - 1], mem->vr);
netif = ipnet_if_indextonetif(vr, (Ip_u32) ndm->ndm_ifindex);
if (netif == IP_NULL)
/*
* No network interface with the specified index
*/
return -IP_ERRNO_ENXIO;
neigh = ipnet_neigh_get(family,
IP_RTA_DATA(rta[IP_NDA_DST-1]),
netif,
IPNET_NEIGH_NO_CREATE);
if (IP_NULL == neigh)
return -IP_ERRNO_ENOENT;
switch (family)
{
#ifdef IPCOM_USE_INET
case IP_AF_INET:
ret = ipnet_rtnetlink_ip4_neigh_fill_info(mem,
neigh,
nlh->nlmsg_seq,
IP_RTM_NEWNEIGH,
0);
break;
#endif
#ifdef IPCOM_USE_INET6
case IP_AF_INET6:
ret = ipnet_rtnetlink_ip6_neigh_fill_info(mem,
neigh,
nlh->nlmsg_seq,
IP_RTM_NEWNEIGH,
0);
break;
#endif
}
ipnet_neigh_release(neigh);
return ret;
}
/*
*==========================================================================
* ipnet_rtnetlink_neigh_dump_family
*===========================================================================
* Description: Get interface info via NETLINK
* Parameters: data - Message payload.
* len - Length of message.
* cb - NETLINK callback entry
*
* Returns: 0 - Success
* <0 - Failure
*
*/
IP_GLOBAL int
ipnet_rtnetlink_neigh_dump_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
int family,
Ip_ptrdiff_t *args)
{
Ipnet_rtnetlink_neigh_family_t param;
Ip_ptrdiff_t *done = &args[0];
Ip_ptrdiff_t *s_vr = &args[1];
Ip_ptrdiff_t *s_neigh = &args[2];
Ip_ptrdiff_t *s_continue = &args[3];
param.nlmsg = nlmsg;
param.family = family;
param.mem = mem;
if (*done)
goto exit_out;
param.state.aborted = 0;
param.state.done = done;
param.state.neigh = s_neigh;
param.state.vr = s_vr;
param.state.cont = *s_continue;
ipnet_neigh_foreach(ipnet_rtnetlink_neigh_foreach,
&param);
/*
* Are we aborted?
*/
*s_continue = param.state.aborted;
/*
* If not aborted; we're done
*/
if (!param.state.aborted)
*done = 1;
exit_out:
return (int) param.mem->used;
}
/*
*===========================================================================
* ipnet_rtnetlink_neigh_delneigh_family
*===========================================================================
* Description: Marks a specific neighbor as dead. Dead neighbors will
* be deleted as soon as their reference count reaches zero.
* Parameters:
* Returns:
*
*/
IP_GLOBAL int
ipnet_rtnetlink_neigh_delneigh_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
Ip_u16 vr;
Ipnet_netif *netif;
struct Ip_ndmsg *ndm = IP_NLMSG_DATA(nlmsg);
Ipnet_neigh *neigh;
/*
* Destination address required
*/
if (rta[IP_NDA_DST-1] == IP_NULL)
return -IP_ERRNO_EINVAL;
if (mem->vr == IPCOM_VR_ANY)
return -IP_ERRNO_EINVAL;
vr = ipnet_rtnetlink_vr(rta[IP_NDA_VR - 1], mem->vr);
netif = ipnet_if_indextonetif(vr, (Ip_u32) ndm->ndm_ifindex);
if (netif == IP_NULL)
/*
* No network interface with the specified index
*/
return -IP_ERRNO_ENXIO;
if (netif->vr_index != vr)
/*
* Wrong VR
*/
return -IP_ERRNO_EINVAL;
/*
* Get the matching neighbor entry, create it if necessary.
*/
neigh = ipnet_neigh_get(family,
IP_RTA_DATA(rta[IP_NDA_DST-1]),
netif,
IPNET_NEIGH_NO_CREATE);
if (neigh == IP_NULL)
/*
* No matching neighbor present
*/
return -IP_ERRNO_ESRCH;
#ifdef IPNET_USE_VRRP
(void)ipnet_eth_vrrp_del_addr(neigh);
#endif
#ifdef IPCOM_FORWARDER_NAE
if (neigh->state == IPNET_ND_REACHABLE && ipnet_neigh_is_external(neigh) && ipcom_nae_is_control())
{
/*
* Go STALE; were deleting an external REACHABLE neighbour on the mgmt plane.
*/
ipnet_neigh_set_external(neigh, IP_FALSE);
if (!ipnet_neigh_nae_verify_use(neigh, IPNET_ND_DEAD))
{
#ifdef IPCOM_FORWARDER_NAE
ipcom_forwarder_fw_neigh_external_delete++;
#endif
ipnet_neigh_set_state(neigh, IPNET_ND_DEAD);
}
}
else
{
#ifdef IPCOM_FORWARDER_NAE
ipcom_forwarder_fw_neigh_external_delete++;
#endif
ipnet_neigh_set_state(neigh, IPNET_ND_DEAD);
}
#else
ipnet_neigh_set_state(neigh, IPNET_ND_DEAD);
#endif
ipnet_neigh_release(neigh);
return 0;
}
/*
*===========================================================================
* ipnet_rtnetlink_neigh_newneigh_family
*===========================================================================
* Description: Creates a new neighbor entry as a response to a
* netlink RTM_NEWNEIGH message
*
* Parameters:
* Returns:
*
*/
IP_GLOBAL int
ipnet_rtnetlink_neigh_newneigh_family(Ipnet_netlink_mem_t *mem,
struct Ip_nlmsghdr *nlmsg,
struct Ip_rtattr **rta,
int family)
{
Ipnet_netif *netif;
Ipnet_neigh *neigh;
int nd_state;
int ret = 0;
Ip_u16 vr;
struct Ip_ndmsg *ndm = IP_NLMSG_DATA(nlmsg);
void *link_addr = IP_NULL;
/*
* Destination address required
*/
if (rta[IP_NDA_DST-1] == IP_NULL)
return -IP_ERRNO_EINVAL;
if (mem->vr == IPCOM_VR_ANY)
return -IP_ERRNO_EINVAL;
vr = ipnet_rtnetlink_vr(rta[IP_NDA_VR - 1], mem->vr);
netif = ipnet_if_indextonetif(vr, (Ip_u32) ndm->ndm_ifindex);
if (netif == IP_NULL)
/*
* No network interface with the specified index
*/
return -IP_ERRNO_ENXIO;
#ifndef IPCOM_FORWARDER_NAE
neigh = ipnet_neigh_get(family,
IP_RTA_DATA(rta[IP_NDA_DST-1]),
netif,
IPNET_NEIGH_NO_CREATE);
if (IP_NULL == neigh)
{
if (IP_BIT_ISFALSE(nlmsg->nlmsg_flags, IP_NLM_F_CREATE))
return -IP_ERRNO_ENOENT;
}
else
{
if (IP_BIT_ISSET(nlmsg->nlmsg_flags, IP_NLM_F_EXCL))
{
ipnet_neigh_release(neigh);
return -IP_ERRNO_EEXIST;
}
if (IP_BIT_ISSET(nlmsg->nlmsg_flags, IP_NLM_F_REPLACE) && IP_BIT_ISFALSE(ndm->ndm_flags, IP_NTF_USE))
{
ipnet_neigh_set_state(neigh, IPNET_ND_DEAD);
ipnet_neigh_release(neigh);
neigh = IP_NULL;
}
}
/*
* Get the matching neighbor entry, create it if necessary.
*/
if (IP_NULL == neigh)
neigh = ipnet_neigh_get(family,
IP_RTA_DATA(rta[IP_NDA_DST-1]),
netif,
IPNET_NEIGH_CAN_CREATE);
#else
neigh = ipnet_neigh_get(family,
IP_RTA_DATA(rta[IP_NDA_DST-1]),
netif,
IPNET_NEIGH_CAN_CREATE);
#endif
if (neigh == IP_NULL)
return -IP_ERRNO_ENOMEM;
if (IP_BIT_ISFALSE(ndm->ndm_flags, IP_NTF_USE))
{
if (rta[IP_NDA_LLADDR-1])
/*
* Neighbors link layer address
*/
link_addr = IP_RTA_DATA(rta[IP_NDA_LLADDR-1]);
else if (IP_BIT_ISSET(ndm->ndm_flags, IP_NTF_PROXY))
{
/*
* Proxy ARP entry. Use Link layer address of local netif
*/
link_addr = netif->ipcom.link_addr;
ipnet_neigh_set_publ(neigh, IP_TRUE);
}
nd_state = ipnet_rtnetlink_neigh_nud2nc(ndm->ndm_state);
if (nd_state == IPNET_ND_INCOMPLETE && ipnet_neigh_is_complete(neigh))
{
#ifdef IPCOM_FORWARDER_NAE
if (!ipcom_nae_is_control() || ipnet_neigh_is_external(neigh))
{
/*
* This state will end up being incomplete - which is
* allowed under NAE, since we do not drive our own
* states
*/
ipcom_forwarder_fw_invalid_incomplete++;
ipnet_neigh_invalidate(neigh);
}
else
#endif
{
/*
* Don't allow the entry to be pushed back to invalid
* state.
*/
ret = -IP_ERRNO_EINVAL;
goto done;
}
}
if (link_addr && ipcom_memcmp(neigh->lladdr, link_addr, neigh->netif->ipcom.link_addr_size) != 0)
{
#ifdef IPCOM_FORWARDER_NAE
if (ipnet_neigh_is_complete(neigh))
{
ipcom_forwarder_fw_invalid_lladdr++;
ipnet_neigh_invalidate(neigh);
}
#endif
/* Must update */
ipnet_neigh_set_lladdr(neigh, link_addr);
}
/*
* No link layer address specified, the neighbour is incomplete,
* and we're setting it to something that indicates reachability
*/
if (IP_NULL == link_addr && !ipnet_neigh_is_complete(neigh) && nd_state != IPNET_ND_INCOMPLETE)
{
ret = -IP_ERRNO_EINVAL;
goto done;
}
if (IP_BIT_ISSET(ndm->ndm_flags, IP_NTF_EXTERNAL))
ipnet_neigh_set_external(neigh, IP_TRUE);
if (IP_BIT_ISTRUE(ndm->ndm_state, IP_NUD_PERMANENT))
{
ipnet_neigh_set_report(neigh);
ipnet_neigh_set_perm(neigh, IP_TRUE);
ipnet_neigh_set_state(neigh, IPNET_ND_REACHABLE);
}
else
{
ipnet_neigh_set_perm(neigh, IP_FALSE);
/* Change State */
#ifdef IPCOM_FORWARDER_NAE
if (ipcom_nae_is_control() && ipnet_neigh_is_external(neigh) && nd_state == IPNET_ND_STALE && neigh->state == IPNET_ND_REACHABLE)
{
if (!ipnet_neigh_nae_verify_use(neigh, IPNET_ND_STALE))
ipnet_neigh_set_state(neigh, IPNET_ND_STALE);
}
else
#endif
{
if (nd_state != (int) neigh->state)
{
ipnet_neigh_set_report(neigh);
ipnet_neigh_set_state(neigh, nd_state);
}
}
}
#ifndef IPCOM_FORWARDER_NAE
if (link_addr != IP_NULL
&& IP_BIT_ISSET(ndm->ndm_flags, IP_NTF_GRAT))
/*
* Gratuitous ARP/NDP was requested
*/
ipnet_neigh_dad(neigh);
#endif
#ifdef IPNET_USE_VRRP
(void)ipnet_eth_vrrp_add_addr(neigh);
#endif
}
else
{
/* Have this entry be 'updated' */
switch (neigh->state)
{
default:
case IPNET_ND_REACHABLE:
case IPNET_ND_PROBE:
case IPNET_ND_INCOMPLETE:
case IPNET_ND_DELAY:
break;
case IPNET_ND_STALE:
ipnet_neigh_set_state(neigh, IPNET_ND_PROBE);
break;
case IPNET_ND_PENDING:
ipnet_neigh_set_state(neigh, IPNET_ND_INCOMPLETE);
break;
}
}
done:
ipnet_neigh_release(neigh);
return ret;
}
/*
*===========================================================================
* ipnet_rtnetlink_neigh_nc2nud
*===========================================================================
* Description: Converts neighbor states from IPNET to NETLINK standard.
* Parameters: neigh - a IPNET neighbor entry.
* Returns: NETLINK neighbor state
*
*/
IP_GLOBAL Ip_u16
ipnet_rtnetlink_neigh_nc2nud(Ipnet_neigh *neigh)
{
Ip_u16 flags = 0;
if (ipnet_neigh_is_perm(neigh))
{
flags |= IP_NUD_PERMANENT;
return flags;
}
switch (neigh->state)
{
case IPNET_ND_PENDING:
case IPNET_ND_INCOMPLETE:
if (neigh->remaining_ucast_probes == 0
&& neigh->remaining_mcast_probes == 0)
flags |= IP_NUD_FAILED;
else
flags |= IP_NUD_INCOMPLETE;
break;
case IPNET_ND_REACHABLE:
flags |= IP_NUD_REACHABLE;
break;
case IPNET_ND_STALE:
flags |= IP_NUD_STALE;
break;
case IPNET_ND_DELAY:
flags |= IP_NUD_DELAY;
break;
case IPNET_ND_PROBE:
flags |= IP_NUD_PROBE;
break;
default:
/*
* Set all other states to the NUD_NONE dummy state.
*/
flags = IP_NUD_NONE;
break;
}
return flags;
}
/*
*===========================================================================
* ipnet_rtnetlink_neigh_nud2nc
*===========================================================================
* Description: Converts neighbor states from NETLINK standard to IPNET
* Parameters: ndm_state - NETLINK neighbor state
* Returns: IPNET neighbor state.
*
*/
IP_GLOBAL int
ipnet_rtnetlink_neigh_nud2nc(Ip_u16 ndm_state)
{
if (IP_BIT_ISSET(ndm_state, IP_NUD_PERMANENT|IP_NUD_REACHABLE))
return IPNET_ND_REACHABLE;
if (IP_BIT_ISSET(ndm_state, IP_NUD_STALE))
return IPNET_ND_STALE;
if (IP_BIT_ISSET(ndm_state, IP_NUD_PROBE))
return IPNET_ND_PROBE;
if (IP_BIT_ISSET(ndm_state, IP_NUD_DELAY))
return IPNET_ND_DELAY;
return IPNET_ND_INCOMPLETE;
}
/*
*===========================================================================
* ipnet_rtnetlink_neigh_change
*===========================================================================
* Description: Called for any kind of change in the neighbor state machine.
* There is no need for a specific neigh_add() function
* anymore. This function is called at creation time with
* state set to INCOMPLETE
* Parameters: neigh - a neighbor entry
* Returns:
*
*/
IP_GLOBAL void
ipnet_rtnetlink_neigh_change(Ipnet_neigh *neigh)
{
ipnet_rtnetlink_neigh_event(neigh, IP_RTM_NEWNEIGH);
}
/*
*===========================================================================
* ipnet_rtnetlink_neigh_del
*===========================================================================
* Description: Called when a neighbor is about to be removed from the stack.
* Parameters: neigh - neighbor entry that is about to be deleted.
* Returns:
*
*/
IP_GLOBAL void
ipnet_rtnetlink_neigh_del(Ipnet_neigh *neigh)
{
ipnet_rtnetlink_neigh_event(neigh, IP_RTM_DELNEIGH);
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
#endif /* IPNET_USE_NETLINK */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/