1333 lines
40 KiB
C
1333 lines
40 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_mpls.c,v $ $Revision: 1.73.10.5 $
|
|
* $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_mpls.c,v $
|
|
* $Author: hsun $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Jonas Rendel <Jonas Rendel@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifndef IPCOM_KERNEL
|
|
#define IPCOM_KERNEL
|
|
#endif
|
|
#include "ipnet_config.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPMPLS
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_hash.h>
|
|
#include <ipcom_type.h>
|
|
|
|
#include <ipcom_netif.h>
|
|
|
|
#include <ipmpls.h>
|
|
#include <ipmpls_ipstack.h>
|
|
#include <ipmpls_h.h>
|
|
|
|
#include "ipnet_h.h"
|
|
#include "ipnet_pkt_queue.h"
|
|
|
|
#include "ipnet_netif.h"
|
|
#include "ipnet_loopback.h"
|
|
#include "ipnet_eth.h"
|
|
|
|
#include "ipnet_mpls.h"
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/* Number of bits in the host part (EUI-64) when using the
|
|
* MPLS to create a IPv6 address (RFC 2464?)
|
|
*/
|
|
#define IPMPLS_IP6_ID_BITS 64
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC int ipnet_mpls_link_ioctl(struct Ipnet_netif_struct *netif, Ip_u32 command, void *data);
|
|
IP_STATIC int ipnet_mpls_ioevent(Ipcom_netif *netif, int command, void *data, int fcflags);
|
|
IP_STATIC int ipnet_mpls_tunnel_output(Ipnet_neigh *neigh, Ipcom_pkt *pkt);
|
|
IP_STATIC int ipnet_mpls_shortcut_route_output(Ipnet_neigh *neigh, Ipcom_pkt *pkt);
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC Ipcom_hash *ipnet_mpls_fibif = IP_NULL;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_for_each_rtab_cb
|
|
*===========================================================================
|
|
* Description: Callback that is called for each route table in the system.
|
|
* Parameters: rtab - One of the route tables in the system.
|
|
* data - User supplied data
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_mpls_for_each_rtab_cb(Ipcom_route *rtab, void *data)
|
|
{
|
|
Ipnet_route_entry *rt;
|
|
|
|
(void)data;
|
|
|
|
rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab),
|
|
IPNET_ROUTE_GET_VR(rtab),
|
|
IPNET_ROUTE_GET_TABLE(rtab));
|
|
while (rt != IP_NULL)
|
|
{
|
|
ipnet_mpls_shortcut_route_clear(rt);
|
|
rt = ipnet_route_next_entry(rt);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_ioctl
|
|
*===========================================================================
|
|
* Description: MPLS IO control.
|
|
* Parameters: netif - The interface on which the multicast address will
|
|
* be used.
|
|
* command - ioctl command.
|
|
* data - Depends on command.
|
|
* Returns: 0 = success, < 0 = error code
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_mpls_link_ioctl(Ipnet_netif *netif, Ip_u32 command, void *data)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
struct Ip_ifreq *ifreq = data;
|
|
struct Ip_sockaddr_in *in_addr;
|
|
Ipnet_ppp_peer *p = netif->private_data;
|
|
#endif
|
|
|
|
switch (command)
|
|
{
|
|
case IPMPLS_SIOCMPLSTUNNELDEL:
|
|
ipnet_if_clean_ppp_peer(netif->private_data);
|
|
ipcom_free(netif->private_data);
|
|
netif->private_data = IP_NULL;
|
|
/* Use break here since this ioctl must be propagated to the MPLS module */
|
|
break;
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_SIOCGIFDSTADDR:
|
|
in_addr = (struct Ip_sockaddr_in *) &ifreq->ip_ifr_dstaddr;
|
|
ipcom_memset(in_addr, 0, sizeof(struct Ip_sockaddr_in));
|
|
in_addr->sin_family = IP_AF_INET;
|
|
IPCOM_SA_LEN_SET(in_addr, sizeof(struct Ip_sockaddr_in));
|
|
in_addr->sin_addr.s_addr = p->peer4.s_addr;
|
|
return 0;
|
|
case IP_SIOCSIFDSTADDR:
|
|
in_addr = (struct Ip_sockaddr_in *) &ifreq->ip_ifr_dstaddr;
|
|
if (in_addr->sin_family != IP_AF_INET
|
|
|| IPCOM_SA_LEN_GET(in_addr) < sizeof(struct Ip_sockaddr_in))
|
|
return -IP_ERRNO_EINVAL;
|
|
return ipnet_if_set_ipv4_ppp_peer(p, &in_addr->sin_addr);
|
|
#endif /* IPCOM_USE_INET */
|
|
default:
|
|
break;
|
|
}
|
|
return ipmpls_tunnel_ioctl(&netif->ipcom, command, data);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_tunnel_output
|
|
*===========================================================================
|
|
* Description: Outputs a packet to a MPLS tunnel interface.
|
|
* Parameters:
|
|
* Returns: 0 = success, <0 = error code.
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_mpls_tunnel_output(Ipnet_neigh *neigh, Ipcom_pkt *pkt)
|
|
{
|
|
struct Ipnet_netif_struct *netif;
|
|
|
|
if (neigh == IP_NULL)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
netif = neigh->netif;
|
|
|
|
netif->obytes += pkt->end - pkt->start;
|
|
netif->opackets++;
|
|
|
|
return ipmpls_tunnel_output(&netif->ipcom, pkt);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_shortcut_route_output
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_mpls_shortcut_route_output(Ipnet_neigh *neigh, Ipcom_pkt *pkt)
|
|
{
|
|
Ip_u32 key;
|
|
|
|
if (neigh->netif->ipcom.type == IP_IFT_MPLS_FIBIF)
|
|
{
|
|
ipcom_memcpy(&key, neigh->lladdr, sizeof(Ip_u32));
|
|
|
|
return ipmpls_shortcut_route_output(key, pkt);
|
|
}
|
|
|
|
return -IP_ERRNO_EHOSTUNREACH;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_ioevent
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_mpls_ioevent(Ipcom_netif *netif, int command, void *data, int fcflags)
|
|
{
|
|
(void)netif;
|
|
(void)command;
|
|
(void)data;
|
|
(void)fcflags;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_get_proto
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_u16
|
|
ipnet_mpls_get_proto(Ipcom_pkt *pkt)
|
|
{
|
|
switch(pkt->data[pkt->ipstart] & 0xf0)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case 0x40:
|
|
return IPNET_ETHFRAME_IP;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case 0x60:
|
|
return IPNET_ETHFRAME_IPV6;
|
|
#endif
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_ifs_obj_hash
|
|
*===========================================================================
|
|
* Description: Creates a hash value from a network interface.
|
|
* Parameters: netif - A MPLS tunnel interface
|
|
* Returns: hash value
|
|
*
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipnet_mpls_ifs_obj_hash(Ipnet_netif *netif)
|
|
{
|
|
return (unsigned) netif->vr_index;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_ifs_key_hash
|
|
*===========================================================================
|
|
* Description: Creates a hash value from a virtual router index.
|
|
* Parameters: vr_index - A pointer to a virtual router index.
|
|
* Returns: hash value
|
|
*
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipnet_mpls_ifs_key_hash(Ip_u16 *vr_index)
|
|
{
|
|
return (unsigned) *vr_index;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_ifs_cmp
|
|
*===========================================================================
|
|
* Description: Checks if the MPLS tunnel interface is assigned to the
|
|
* specified virtual router.
|
|
* Parameters: netif - A MPLS tunnel interface
|
|
* vr_index - A pointer to a virtual router index.
|
|
* Returns: IP_TRUE if they matches.
|
|
*
|
|
*/
|
|
IP_STATIC unsigned
|
|
ipnet_mpls_ifs_cmp(Ipnet_netif *netif, Ip_u16 *vr_index)
|
|
{
|
|
return netif->vr_index == *vr_index;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_prepare_eth_hdr
|
|
*===========================================================================
|
|
* Description: Writes a temporary header with the correct frame type
|
|
* while neighbor discovery is performed.
|
|
* Parameters: netif - egress interface
|
|
* pkt - a MPLS packet
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipnet_mpls_prepare_eth_hdr(Ipnet_netif *netif, Ipcom_pkt *pkt)
|
|
{
|
|
Ip_u16 type;
|
|
|
|
if (pkt->force_frame_type == 0)
|
|
type = ipnet_mpls_get_proto(pkt);
|
|
else
|
|
type = pkt->force_frame_type;
|
|
|
|
/*
|
|
* The destination MAC isn't known at this time. The local MAC is
|
|
* just used since ipnet_eth_add_hdr() requires a pointer to a
|
|
* valid MAC..
|
|
*/
|
|
ipnet_eth_add_hdr(pkt,
|
|
netif,
|
|
netif->ipcom.link_addr,
|
|
netif->ipcom.link_addr,
|
|
type);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_neigh_probe
|
|
*===========================================================================
|
|
* Description:
|
|
*
|
|
* Parameters:
|
|
*
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC int
|
|
ipnet_mpls_neigh_probe(Ipnet_netif *netif,
|
|
Ipcom_pkt *pkt,
|
|
int domain,
|
|
union Ip_in_addr_union *addr,
|
|
Ipnet_mpls_probecb probecb)
|
|
{
|
|
Ipnet_neigh *neigh;
|
|
int ret;
|
|
|
|
if (probecb == IP_NULL)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
|
|
neigh = ipnet_neigh_get(domain,
|
|
addr,
|
|
netif,
|
|
IPNET_NEIGH_CAN_CREATE);
|
|
|
|
if (neigh == IP_NULL)
|
|
{
|
|
ret = -IP_ERRNO_EINVAL;
|
|
goto errout;
|
|
}
|
|
|
|
switch (neigh->state)
|
|
{
|
|
case IPNET_ND_STALE:
|
|
ipnet_neigh_set_state(neigh, IPNET_ND_DELAY);
|
|
/* Fall through */
|
|
case IPNET_ND_REACHABLE:
|
|
case IPNET_ND_DELAY:
|
|
case IPNET_ND_PROBE:
|
|
probecb(netif, pkt, neigh->lladdr); /*lint !e522 */
|
|
break;
|
|
|
|
case IPNET_ND_INCOMPLETE:
|
|
ipnet_mpls_prepare_eth_hdr(netif, pkt);
|
|
neigh->tx_action(neigh, pkt);
|
|
break;
|
|
|
|
default:
|
|
IP_PANIC();
|
|
ret = -IP_ERRNO_EINVAL;
|
|
goto errout;
|
|
}
|
|
|
|
ipnet_neigh_release(neigh);
|
|
|
|
return 0;
|
|
|
|
errout:
|
|
ipnet_neigh_release(neigh);
|
|
ip_assert(ret < 0);
|
|
ipcom_pkt_free(pkt);
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_arp_probe
|
|
*===========================================================================
|
|
* Description: Send an forced ARP request.
|
|
* Parameters: netif - The ethernet interface to send to ARP request from.
|
|
* pkt - The packet to send if the ARP finish successfully.
|
|
* sin - The IPv4 destination address for 'pkt'
|
|
* probecb - A function that will be called when/if the ARP
|
|
* request is successful.
|
|
* cookie - Caller data that will be passed to the 'probecb'
|
|
* Returns: 0 = success, <0 = error code.
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET
|
|
IP_GLOBAL int
|
|
ipnet_mpls_arp_probe(Ipnet_netif *netif,
|
|
Ipcom_pkt *pkt,
|
|
struct Ip_sockaddr_in *sin,
|
|
Ipnet_mpls_probecb probecb)
|
|
{
|
|
union Ip_in_addr_union addr;
|
|
|
|
if (sin == IP_NULL)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
ipcom_memcpy(&addr.in, &sin->sin_addr, sizeof(struct Ip_in_addr));
|
|
|
|
return ipnet_mpls_neigh_probe(netif,
|
|
pkt,
|
|
IP_AF_INET,
|
|
&addr,
|
|
probecb);
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_ip6_neighbor_cache_probe
|
|
*===========================================================================
|
|
* Description: Probes for a neighbor cache entry
|
|
* Parameters: netif - interface to send packet on
|
|
* pkt - packet to send
|
|
* probecb - Callback to be called when probe is completed
|
|
* Returns:
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET6
|
|
IP_GLOBAL int
|
|
ipnet_mpls_ip6_neighbor_cache_probe(Ipnet_netif *netif,
|
|
Ipcom_pkt *pkt,
|
|
struct Ip_sockaddr_in6 *sin6,
|
|
Ipnet_mpls_probecb probecb)
|
|
{
|
|
union Ip_in_addr_union addr;
|
|
|
|
if (sin6 == IP_NULL)
|
|
return -IP_ERRNO_EINVAL;
|
|
|
|
ipcom_memcpy(&addr.in6, &sin6->sin6_addr, sizeof(struct Ip_in6_addr));
|
|
|
|
return ipnet_mpls_neigh_probe(netif,
|
|
pkt,
|
|
IP_AF_INET6,
|
|
&addr,
|
|
probecb);
|
|
|
|
}
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_init
|
|
*===========================================================================
|
|
* Description: Initiates the IPNET_MPLS module.
|
|
* Parameters: -
|
|
* Returns: 0 = success, <0 error code
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipnet_mpls_init(void)
|
|
{
|
|
ipnet_mpls_fibif = ipcom_hash_new((Ipcom_hash_obj_func) ipnet_mpls_ifs_obj_hash,
|
|
(Ipcom_hash_key_func) ipnet_mpls_ifs_key_hash,
|
|
(Ipcom_hash_cmp_func) ipnet_mpls_ifs_cmp);
|
|
|
|
return ipnet_mpls_fibif != IP_NULL ? 0 : -1;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_input
|
|
*===========================================================================
|
|
* Description: Input handler for ethernet frames. pkt->start is the offset
|
|
* to the ethernet header.
|
|
* Parameters: pkt - The ethernet frame.
|
|
* Returns: 0 = success, <0 error code
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipnet_mpls_input(struct Ipnet_netif_struct *netif, Ipcom_pkt *pkt)
|
|
{
|
|
return ipmpls_input(&netif->ipcom, pkt, IP_FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_route_table_notify
|
|
*===========================================================================
|
|
* Description: Called when a route table is created or deleted in IPNET
|
|
* Parameters: vr_index - Route table index.
|
|
* is_added - Tells if table is added (or deleted)
|
|
* Returns: -
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipnet_mpls_route_table_notify(Ip_u16 vr_index, Ip_bool is_added)
|
|
{
|
|
Ipnet_netif *fibif;
|
|
|
|
fibif = ipcom_hash_get(ipnet_mpls_fibif, &vr_index);
|
|
|
|
if (!is_added && fibif != IP_NULL)
|
|
{
|
|
/* Removed table. Delete corresponding MPLS FIB interface */
|
|
(void)ipcom_hash_remove(ipnet_mpls_fibif, fibif);
|
|
ipmpls_if_free(&fibif->ipcom);
|
|
ipcom_free(fibif->private_data);
|
|
ipcom_free(fibif);
|
|
}
|
|
else if (is_added && fibif == IP_NULL)
|
|
{
|
|
/* New table. Create a new MPLS FIB interface to represent it */
|
|
fibif = ipcom_calloc(1, sizeof(Ipnet_netif));
|
|
|
|
if (fibif)
|
|
{
|
|
fibif->ipcom.metric = 1;
|
|
fibif->ipcom.type = IP_IFT_MPLS_FIBIF;
|
|
fibif->vr_index = (Ip_u16)vr_index;
|
|
|
|
ipcom_snprintf(fibif->ipcom.name,
|
|
IP_IFNAMSIZ,
|
|
"mplsfib%d",
|
|
vr_index);
|
|
|
|
|
|
(void)ipnet_mpls_if_init(fibif);
|
|
|
|
IP_BIT_SET(fibif->ipcom.flags, IP_IFF_UP | IP_IFF_RUNNING | IP_IFF_NOARP);
|
|
if (ipcom_hash_add(ipnet_mpls_fibif, fibif) != IPCOM_SUCCESS)
|
|
IP_PANIC();
|
|
|
|
ipnet_conf_update(fibif->ipcom.name, IP_NULL, IP_NULL);
|
|
}
|
|
}
|
|
#if IPMPLS_MULTIPLE_ROUTE_TABLES
|
|
ipmpls_route_table_notify(vr_index, is_added);
|
|
#endif /* IPMPLS_MULTIPLE_ROUTE_TABLES */
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_get_src_addr
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL IP_CONST void*
|
|
ipnet_mpls_get_src_addr(Ip_sa_family_t sa_family, Ipnet_netif *fibif, void* dst)
|
|
{
|
|
Ip_u32 i;
|
|
Ipnet_netif *this_netif;
|
|
void* src = IP_NULL;
|
|
|
|
#ifdef IPNET_ASSERT
|
|
ip_assert(fibif != IP_NULL);
|
|
#endif
|
|
|
|
switch(sa_family)
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IP_AF_INET:
|
|
{
|
|
IP_CONST struct Ip_in_addr *first_valid = IP_NULL;
|
|
IP_CONST struct Ip_in_addr *selected = IP_NULL;
|
|
Ipnet_ip4_addr_entry *addr;
|
|
Ip_u32 mask_n = 0;
|
|
Ip_u32 dst_n;
|
|
int longest_match_bits;
|
|
|
|
dst_n = IP_GET_32ON16((struct Ip_in_addr*)dst);
|
|
|
|
/*
|
|
* IPNET_NETIF_FOR_EACH sets netif to NULL after the for loop,
|
|
* this is a performance optimized defination
|
|
*/
|
|
/* coverity[result_independent_of_operands] */
|
|
IPNET_NETIF_FOR_EACH(this_netif, i)
|
|
{
|
|
if (this_netif->ipcom.type == IP_IFT_LOOP
|
|
|| this_netif->vr_index != fibif->vr_index)
|
|
continue;
|
|
|
|
for (addr = this_netif->inet4_addr_list; addr != IP_NULL; addr = addr->next)
|
|
{
|
|
if (addr->type != IPNET_ADDR_TYPE_UNICAST)
|
|
continue;
|
|
|
|
if (!first_valid)
|
|
first_valid = (struct Ip_in_addr *) &addr->ipaddr_n;
|
|
|
|
mask_n = 0;
|
|
longest_match_bits = IP_NETBITS(dst_n);
|
|
ipnet_route_create_mask(&mask_n, longest_match_bits);
|
|
|
|
while (longest_match_bits < 32 && ipcom_route_key_cmp(32, &addr->ipaddr_n, &dst_n, &mask_n))
|
|
{
|
|
ipnet_route_create_mask(&mask_n, ++longest_match_bits);
|
|
selected = (struct Ip_in_addr *) &addr->ipaddr_n;
|
|
}
|
|
}
|
|
|
|
if (selected)
|
|
{
|
|
src = (void*)selected;
|
|
goto finish;
|
|
}
|
|
}
|
|
|
|
src = (void*)first_valid;
|
|
}
|
|
break;
|
|
#endif /* IPCOM_USE_INET */
|
|
#ifdef IPCOM_USE_INET6
|
|
case IP_AF_INET6:
|
|
{
|
|
IP_CONST struct Ip_in6_addr *first_valid = IP_NULL;
|
|
IP_CONST struct Ip_in6_addr *selected = IP_NULL;
|
|
IP_CONST struct Ip_in6_addr *dst_addr;
|
|
Ipnet_ip6_addr_entry *addr;
|
|
int matched_16bits = -1;
|
|
|
|
dst_addr = (IP_CONST struct Ip_in6_addr *)dst;
|
|
|
|
/*
|
|
* IPNET_NETIF_FOR_EACH sets netif to NULL after the for loop,
|
|
* this is a performance optimized defination
|
|
*/
|
|
/* coverity[result_independent_of_operands] */
|
|
IPNET_NETIF_FOR_EACH(this_netif, i)
|
|
{
|
|
if (this_netif->ipcom.type == IP_IFT_LOOP
|
|
|| this_netif->vr_index != fibif->vr_index)
|
|
continue;
|
|
|
|
for (addr = this_netif->inet6_addr_list; addr != IP_NULL; addr = addr->next)
|
|
{
|
|
if (IP_IN6_IS_ADDR_MULTICAST(&addr->addr)
|
|
|| IP_IN6_IS_ADDR_LINK_LOCAL(&addr->addr)
|
|
|| IP_IN6_IS_ADDR_SITE_LOCAL(&addr->addr)
|
|
|| IP_BIT_ISSET(addr->flags, IPNET_IP6_ADDR_FLAG_DEPRECATED))
|
|
continue;
|
|
|
|
if (!first_valid)
|
|
src = &addr->addr;
|
|
|
|
if (IP_BIT_ISFALSE(addr->flags, IPNET_IP6_ADDR_FLAG_TENTATIVE))
|
|
{
|
|
unsigned b;
|
|
|
|
for (b = 0; b < (int) (sizeof(struct Ip_in6_addr) / sizeof(Ip_u16)); b++)
|
|
if (dst_addr->in6.addr16[b] != addr->addr.in6.addr16[b])
|
|
break;
|
|
|
|
if (matched_16bits < (int) b)
|
|
{
|
|
if ((b << 4) >= addr->prefixlen)
|
|
{
|
|
/* All of the prefix matched, use this address */
|
|
src = &addr->addr;
|
|
goto finish;
|
|
}
|
|
|
|
/* Use the address with the longest match */
|
|
matched_16bits = b;
|
|
selected = &addr->addr;
|
|
}
|
|
}
|
|
}
|
|
if (selected)
|
|
{
|
|
src = (void*)selected;
|
|
goto finish;
|
|
}
|
|
}
|
|
|
|
src = (void*)first_valid;
|
|
}
|
|
break;
|
|
#endif /* IPCOM_USE_INET6 */
|
|
}
|
|
|
|
finish:
|
|
|
|
return src;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_shortcut_route_setup
|
|
*===========================================================================
|
|
* Description: Called when a new shortcut route is setup in IPNET.
|
|
* Parameters: vr - Virtual router to use.
|
|
* rt - Pointer to pseudo-wire route entry.
|
|
* pnetif - Location where the outgoing interface should be stored.
|
|
* Returns: 0 = success, <0 error code
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipnet_mpls_shortcut_route_setup(Ip_u16 vr, Ipnet_route_entry *rt, Ipnet_netif **pnetif)
|
|
{
|
|
rt->netif = ipcom_hash_get(ipnet_mpls_fibif, &vr);
|
|
if (pnetif != IP_NULL)
|
|
*pnetif = rt->netif;
|
|
IP_BIT_SET(rt->hdr.flags, IPNET_RTF_LLINFO);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_get_fibif
|
|
*===========================================================================
|
|
* Description: get the fibif interface.
|
|
* Parameters: vr - Virtual router to use.
|
|
* Returns: 0 = success, <0 error code
|
|
*
|
|
*/
|
|
IP_GLOBAL Ipnet_netif *
|
|
ipnet_mpls_get_fibif(Ip_u16 vr)
|
|
{
|
|
return ipcom_hash_get(ipnet_mpls_fibif, &vr);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_shortcut_route_setup
|
|
*===========================================================================
|
|
* Description: Called when a new shortcut route is removed in IPNET.
|
|
* Parameters: rt - Pointer to pseudo-wire route entry.
|
|
*
|
|
* Returns: -
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipnet_mpls_shortcut_route_clear(Ipnet_route_entry *rt)
|
|
{
|
|
(void)rt;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_default_ip4_neigh_probe
|
|
*===========================================================================
|
|
* Description: Sets the status of the neighbor to IPNET_ND_REACHABLE.
|
|
* This behavior can be used by links that do not need to
|
|
* resolve the peer link address (ex. loopback, PPP) or
|
|
* by interfaces that do their own IP4-to-link-addr
|
|
* mapping (IFF_NOARP flag set).
|
|
* Parameters: neigh - a neighbor entry.
|
|
* Returns:
|
|
*
|
|
*/
|
|
#ifdef IPCOM_USE_INET
|
|
IP_STATIC void
|
|
ipnet_mpls_default_ip4_neigh_probe(Ipnet_neigh *neigh, Ip_bool unicast_probe)
|
|
{
|
|
IPCOM_UNUSED_ARG(unicast_probe);
|
|
ipnet_neigh_set_state(neigh, IPNET_ND_REACHABLE);
|
|
/*
|
|
* The neigh->laddr is set to zero when the neighbor entry is
|
|
* created.
|
|
*/
|
|
}
|
|
#endif /* IPCOM_USE_INET */
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipnet_mpls_if_init
|
|
*===========================================================================
|
|
* Description: MPLS interface setup routine.
|
|
* Parameters: netif - pointer to interface descriptor.
|
|
* Returns: 0 = success, <0 error code
|
|
*
|
|
*/
|
|
IP_GLOBAL int
|
|
ipnet_mpls_if_init(Ipnet_netif *netif)
|
|
{
|
|
/* Setup link functions for MPLS use. */
|
|
netif->link_input = ipnet_mpls_input;
|
|
netif->link_ioctl = ipnet_mpls_link_ioctl;
|
|
netif->ipcom.link_ioevent = ipnet_mpls_ioevent;
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
netif->inet4_neigh_probe = ipnet_mpls_default_ip4_neigh_probe;
|
|
#endif
|
|
|
|
switch (netif->ipcom.type)
|
|
{
|
|
case IP_IFT_MPLS_TUNNEL:
|
|
netif->link_output = ipnet_mpls_tunnel_output;
|
|
break;
|
|
case IP_IFT_MPLS_FIBIF:
|
|
netif->link_output = ipnet_mpls_shortcut_route_output;
|
|
break;
|
|
default:
|
|
return -IP_ERRNO_EINVAL;
|
|
}
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
netif->inet6_if_id_bits = IPMPLS_IP6_ID_BITS;
|
|
#endif
|
|
netif->neigh_create = ipnet_netif_neigh_create;
|
|
|
|
netif->private_data = ipcom_malloc(sizeof(Ipnet_ppp_peer));
|
|
if (netif->private_data == IP_NULL)
|
|
return -IP_ERRNO_ENOMEM;
|
|
ipnet_if_init_ppp_peer(netif, netif->private_data);
|
|
|
|
return ipmpls_if_init(&netif->ipcom);
|
|
}
|
|
|
|
|
|
IP_GLOBAL void
|
|
ipnet_mpls_probe_reply(Ipnet_netif *netif,
|
|
Ipcom_pkt *pkt,
|
|
Ip_u8 *dst)
|
|
{
|
|
/* Get frame type from PDU */
|
|
Ip_u16 type;
|
|
|
|
if (pkt->force_frame_type == 0)
|
|
type = ipnet_mpls_get_proto(pkt);
|
|
else
|
|
type = pkt->force_frame_type;
|
|
|
|
ipnet_eth_add_hdr(pkt,
|
|
netif,
|
|
dst,
|
|
netif->ipcom.link_addr,
|
|
type);
|
|
|
|
/* The interface is now known, what we should do is set the packet's
|
|
* interface index so that it matches the output interface
|
|
*/
|
|
pkt->ifindex = netif->ipcom.ifindex;
|
|
(void) ipnet_if_output(netif, pkt);
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipcom_mpls_ioevent
|
|
*===========================================================================
|
|
* Description: IPNET Protocol stack portation layer handler for the IPMPLS
|
|
* module.
|
|
* Parameters: netif - Pointer to IPCOM interface descriptor.
|
|
* command - IPMPLS EIOX command.
|
|
* data - Used for various purposes.
|
|
* more - Used for various purposes.
|
|
* Returns: 0 = success, <0 error code
|
|
*
|
|
*/
|
|
IP_PUBLIC int
|
|
ipcom_mpls_ioevent(Ipcom_netif *netif, int command, void *data, void *more, void *cookie)
|
|
{
|
|
Ipnet_netif *ipnet_netif = (Ipnet_netif *)netif;
|
|
Ipnet_netif **pnetif = (Ipnet_netif **)more;
|
|
int ret = 0;
|
|
Ipcom_pkt *pkt = (Ipcom_pkt*)data;
|
|
Ip_bool *penultimate = (Ip_bool*)cookie;
|
|
|
|
|
|
switch(command)
|
|
{
|
|
case IPMPLS_EIOXBLOCKOK:
|
|
if (ipnet_is_stack_task() == IP_FALSE)
|
|
ret = 1; /* user process -> block is ok. */
|
|
break;
|
|
|
|
case IPMPLS_EIOXDRVIOCTL:
|
|
{
|
|
Ipmpls_eio_ioctl *eio_ioctl = data;
|
|
|
|
ip_assert(netif);
|
|
ret = netif->drv_ioctl(netif, eio_ioctl->command, eio_ioctl->data);
|
|
break;
|
|
}
|
|
|
|
case IPMPLS_EIOXGET_TTL:
|
|
{
|
|
Ip_u8 ttl;
|
|
switch (ipnet_mpls_get_proto(pkt))
|
|
{
|
|
#ifdef IPCOM_USE_INET
|
|
case IPNET_ETHFRAME_IP:
|
|
ttl = ((Ipnet_pkt_ip*)&pkt->data[pkt->ipstart])->ttl;
|
|
break;
|
|
#endif
|
|
#ifdef IPCOM_USE_INET6
|
|
case IPNET_ETHFRAME_IPV6:
|
|
ttl = ((Ipnet_pkt_ip6*)&pkt->data[pkt->ipstart])->hlim;
|
|
break;
|
|
#endif
|
|
default:
|
|
ttl = 255;
|
|
break;
|
|
}
|
|
|
|
ret = (int)ttl;
|
|
}
|
|
break;
|
|
|
|
case IPMPLS_EIOXGET_USER_VR:
|
|
{
|
|
Ip_u16 *vr = (Ip_u16*)data;
|
|
|
|
if (vr == IP_NULL)
|
|
return -IP_ERRNO_EINVAL;
|
|
#if IPCOM_VR_MAX > 1
|
|
*vr = ipnet_get_effective_vr();
|
|
#else
|
|
*vr = 0;
|
|
#endif
|
|
}
|
|
break;
|
|
|
|
case IPMPLS_EIOXOUTPUT_IF:
|
|
ip_assert(ipnet_netif);
|
|
ret = ipnet_if_output(ipnet_netif, pkt);
|
|
break;
|
|
|
|
case IPMPLS_EIOXRTABTONETIF:
|
|
{
|
|
Ip_u16 vr = *(Ip_u16*)data;
|
|
|
|
*pnetif = ipnet_loopback_get_netif(vr);
|
|
|
|
if (*pnetif == IP_NULL)
|
|
ret = 1;
|
|
|
|
break;
|
|
}
|
|
|
|
case IPMPLS_EIOXINDEXTONETIF:
|
|
{
|
|
Ip_u32 ifindex = *(Ip_u32*)data;
|
|
|
|
*pnetif = ipnet_if_indextonetif(IPCOM_VR_ANY, ifindex);
|
|
|
|
if (*pnetif == IP_NULL)
|
|
ret = 1;
|
|
break;
|
|
}
|
|
case IPMPLS_EIOXNAMETONETIF:
|
|
{
|
|
Ip_u16 vr = *(Ip_u16*)cookie;
|
|
char *name = (char*)data;
|
|
|
|
*pnetif = ipnet_if_nametonetif(vr, name);
|
|
|
|
if (*pnetif == IP_NULL)
|
|
ret = 1;
|
|
break;
|
|
}
|
|
case IPMPLS_EIOXFOREACHNETIF:
|
|
{
|
|
Ipmpls_netif_foreach_cb cb = (Ipmpls_netif_foreach_cb)data;
|
|
Ip_u32 i;
|
|
|
|
if (cb)
|
|
{
|
|
#if IPMPLS_RELEASE >= 60101
|
|
/*
|
|
* IPNET_NETIF_FOR_EACH sets netif to NULL after the for loop,
|
|
* this is a performance optimized defination
|
|
*/
|
|
/* coverity[result_independent_of_operands] */
|
|
IPNET_NETIF_FOR_EACH(ipnet_netif, i)
|
|
cb(&ipnet_netif->ipcom, ipnet_netif->vr_index, more);
|
|
#else
|
|
/*
|
|
* IPNET_NETIF_FOR_EACH sets netif to NULL after the for loop,
|
|
* this is a performance optimized defination
|
|
*/
|
|
/* coverity[result_independent_of_operands] */
|
|
IPNET_NETIF_FOR_EACH(ipnet_netif, i)
|
|
cb(&ipnet_netif->ipcom, more);
|
|
#endif
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IPMPLS_EIOXIF_LOCK:
|
|
ip_assert(netif);
|
|
IPNET_IF_LOCK(ipnet_netif);
|
|
break;
|
|
|
|
case IPMPLS_EIOXIF_UNLOCK:
|
|
ip_assert(netif);
|
|
IPNET_IF_UNLOCK(ipnet_netif);
|
|
break;
|
|
case IPMPLS_EIOXIF_OPEN:
|
|
ip_assert(netif);
|
|
ipnet_kioevent(ipnet_netif, IP_EIOXUP, IP_NULL, IP_FLAG_FC_STACKCONTEXT);
|
|
break;
|
|
case IPMPLS_EIOXIF_RUNNING:
|
|
ip_assert(netif);
|
|
ipnet_kioevent(ipnet_netif, IP_EIOXRUNNING, IP_NULL, IP_FLAG_FC_STACKCONTEXT);
|
|
break;
|
|
case IPMPLS_EIOXIF_CLOSE:
|
|
ip_assert(netif);
|
|
ipnet_kioevent(ipnet_netif, IP_EIOXDOWN, IP_NULL, IP_FLAG_FC_STACKCONTEXT);
|
|
break;
|
|
case IPMPLS_EIOXIF_STOP:
|
|
ip_assert(netif);
|
|
ipnet_kioevent(ipnet_netif, IP_EIOXSTOP, IP_NULL, IP_FLAG_FC_STACKCONTEXT);
|
|
break;
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
case IPMPLS_EIOXINPUT_IN:
|
|
ip_assert(ipnet_netif);
|
|
|
|
ipnet_netif->ibytes += pkt->end - pkt->start;
|
|
ipnet_netif->ipackets++;
|
|
|
|
if (!more)
|
|
ret = ipnet_ip4_input(ipnet_netif, pkt);
|
|
else
|
|
{
|
|
/* Forward IPv4 packet via IPNET */
|
|
Ipnet_pkt_ip *ip_pkt;
|
|
|
|
pkt->ipstart = pkt->start;
|
|
ip_pkt = ipcom_pkt_get_iphdr(pkt);
|
|
|
|
--ip_pkt->ttl;
|
|
ip_pkt->sum = 0;
|
|
ip_pkt->sum = ipcom_in_checksum(ip_pkt, (ip_pkt->v_hl & 0x0F) << 2);
|
|
IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_HAS_IP_HDR | IPCOM_PKT_FLAG_FORWARDED);
|
|
|
|
IPCOM_MIB2(ipForwDatagrams++);
|
|
IPCOM_MIB2_SYSWI_U64_ADD(v4, ipSystemStatsHCInForwDatagrams, 1);
|
|
IPCOM_MIB2_PERIF_U64_ADD(v4, ipIfStatsHCInForwDatagrams, 1, ipnet_netif);
|
|
|
|
ret = ipnet_ip4_pkt_with_iphdr_tx(pkt, IP_NULL);
|
|
}
|
|
break;
|
|
|
|
case IPMPLS_EIOXUP_IN:
|
|
{
|
|
|
|
}
|
|
break;
|
|
|
|
case IPMPLS_EIOXDOWN_IN:
|
|
ip_assert(ipnet_netif);
|
|
ipnet_if_clean(ipnet_netif, IP_TRUE, IP_FALSE);
|
|
break;
|
|
|
|
case IPMPLS_EIOXDSTADDR_IN:
|
|
{
|
|
Ip_u32 dstaddr = ((struct Ip_in_addr *)data)->s_addr;
|
|
Ip_u32 i;
|
|
Ipnet_netif *tmpif;
|
|
struct Ip_ifreq ifreq;
|
|
struct Ip_sockaddr_in *inaddr = (struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr;
|
|
|
|
dstaddr = ip_htonl(dstaddr);
|
|
/*
|
|
* IPNET_NETIF_FOR_EACH sets netif to NULL after the for loop,
|
|
* this is a performance optimized defination
|
|
*/
|
|
/* coverity[result_independent_of_operands] */
|
|
IPNET_NETIF_FOR_EACH(tmpif, i)
|
|
{
|
|
if (IP_BIT_ISFALSE(tmpif->ipcom.flags, IP_IFF_POINTOPOINT))
|
|
continue;
|
|
(void)ipnet_if_link_ioctl(tmpif, IP_SIOCGIFDSTADDR, &ifreq);
|
|
if (inaddr->sin_addr.s_addr == dstaddr)
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
#endif /* ifdef IPCOM_USE_INET */
|
|
|
|
#ifdef IPCOM_USE_INET6
|
|
case IPMPLS_EIOXINPUT_IN6:
|
|
ip_assert(ipnet_netif);
|
|
|
|
ipnet_netif->ibytes += pkt->end - pkt->start;
|
|
ipnet_netif->ipackets++;
|
|
|
|
if (!more)
|
|
{
|
|
ret = ipnet_ip6_input(ipnet_netif, data);
|
|
}
|
|
else
|
|
{
|
|
Ipnet_pkt_ip6 *ip6_hdr;
|
|
|
|
pkt->ipstart = pkt->start;
|
|
ip6_hdr = (Ipnet_pkt_ip6*) &pkt->data[pkt->ipstart];
|
|
|
|
--ip6_hdr->hlim;
|
|
|
|
|
|
IP_BIT_SET(pkt->flags, IPCOM_PKT_FLAG_HAS_IP_HDR | IPCOM_PKT_FLAG_FORWARDED);
|
|
|
|
IPCOM_MIB2_SYSWI_U64_ADD(v6, ipSystemStatsHCInForwDatagrams, 1);
|
|
IPCOM_MIB2_PERIF_U64_ADD(v6, ipIfStatsHCInForwDatagrams, 1, ipnet_netif);
|
|
|
|
ret = ipnet_ip6_tx(IPNET_IP6_GET_CLASS(ip6_hdr),
|
|
--ip6_hdr->hlim,
|
|
ip6_hdr->nxt,
|
|
IPNET_IP6_GET_FLOW(ip6_hdr),
|
|
(struct Ip_in6_addr*)&ip6_hdr->src,
|
|
&((struct Ip_sockaddr_in6*)more)->sin6_addr,
|
|
0,
|
|
ipnet_netif->ipcom.ifindex,
|
|
pkt);
|
|
}
|
|
break;
|
|
|
|
case IPMPLS_EIOXUP_IN6:
|
|
{
|
|
struct Ipnet_ipv6_key rt6[2];
|
|
struct Ipnet_rt_metrics metrics;
|
|
struct Ipnet_route_add_param param;
|
|
Ipmpls_eio_in6 *eio_in6 = data;
|
|
|
|
ip_assert(netif);
|
|
|
|
/* Add IPv6 address. */
|
|
ret = ipnet_ip6_add_addr(ipnet_netif, &eio_in6->local_addr, 0,
|
|
IPCOM_ADDR_INFINITE, IPCOM_ADDR_INFINITE, 0);
|
|
if (ret < 0)
|
|
{
|
|
IP_PANIC2();
|
|
return ret;
|
|
}
|
|
|
|
/* Add cloning route for link local net. */
|
|
ipcom_memset(¶m, 0, sizeof(struct Ipnet_route_add_param));
|
|
ipcom_memset(&metrics, 0, sizeof(struct Ipnet_rt_metrics));
|
|
ipcom_memset(rt6, 0, sizeof(struct Ipnet_ipv6_key) * 2);
|
|
rt6[0].scope_id = netif->ifindex;
|
|
rt6[0].addr.in6.addr8[0] = 0xfe;
|
|
rt6[0].addr.in6.addr8[1] = 0x80;
|
|
rt6[1].scope_id = 0xffffffff;
|
|
rt6[1].addr.in6.addr32[0] = 0xffffffff;
|
|
rt6[1].addr.in6.addr32[1] = 0xffffffff;
|
|
param.domain = IP_AF_INET6;
|
|
param.vr = ipnet_netif->vr_index;
|
|
param.table = IPCOM_ROUTE_TABLE_DEFAULT;
|
|
param.netif = ipnet_netif;
|
|
param.key = &rt6[0];
|
|
param.netmask = &rt6[1];
|
|
param.flags = IPNET_RTF_UP | IPNET_RTF_MASK | IPNET_RTF_CLONING | IPNET_RTF_DONE;
|
|
param.metrics = &metrics;
|
|
metrics.rmx_hopcount = netif->metric;
|
|
metrics.rmx_expire = IPCOM_ADDR_INFINITE;
|
|
ret = ipnet_route_add(¶m);
|
|
if (ret < 0)
|
|
{
|
|
IP_PANIC2();
|
|
return ret;
|
|
}
|
|
|
|
/* Add link local multicast route. */
|
|
rt6[0].addr.in6.addr8[0] = 0xff;
|
|
rt6[0].addr.in6.addr8[1] = 0x02;
|
|
param.flags = IPNET_RTF_UP | IPNET_RTF_MASK | IPNET_RTF_DONE;
|
|
ret = ipnet_route_add(¶m);
|
|
if (ret < 0)
|
|
{
|
|
IP_PANIC2();
|
|
return ret;
|
|
}
|
|
|
|
/* Add IPv6 host route to peer. */
|
|
ipcom_memcpy(&rt6[0].addr, &eio_in6->peer_addr, sizeof(struct Ip_in6_addr));
|
|
param.netmask = IP_NULL;
|
|
param.flags = IPNET_RTF_UP | IPNET_RTF_HOST | IPNET_RTF_DONE;
|
|
ret = ipnet_route_add(¶m);
|
|
if (ret < 0)
|
|
{
|
|
IP_PANIC2();
|
|
return ret;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IPMPLS_EIOXDOWN_IN6:
|
|
ip_assert(ipnet_netif);
|
|
ipnet_if_clean(ipnet_netif, IP_FALSE, IP_TRUE);
|
|
break;
|
|
#endif /* ifdef IPCOM_USE_INET6 */
|
|
|
|
case IPMPLS_EIOXADDETHHDR:
|
|
ipnet_eth_add_hdr((Ipcom_pkt*) data,
|
|
ipnet_netif,
|
|
(const Ip_u8*)more,
|
|
ipnet_netif->ipcom.link_addr,
|
|
IPNET_ETHFRAME_MPLS_UNICAST);
|
|
ret = 0;
|
|
break;
|
|
|
|
|
|
case IPMPLS_EIOXFLUSHSHORTCUTROUTES:
|
|
ipcom_hash_for_each(ipnet->rtabs,
|
|
(Ipcom_hash_foreach_cb_func) ipnet_mpls_for_each_rtab_cb,
|
|
data);
|
|
break;
|
|
|
|
#ifdef IPCOM_USE_INET
|
|
case IPMPLS_EIOXARPPROBE:
|
|
|
|
if (penultimate == IP_NULL || *penultimate == IP_FALSE)
|
|
pkt->force_frame_type = IPNET_ETHFRAME_MPLS_UNICAST;
|
|
|
|
ret = ipnet_mpls_arp_probe((Ipnet_netif *) netif,
|
|
pkt,
|
|
(struct Ip_sockaddr_in *) more,
|
|
ipnet_mpls_probe_reply);
|
|
|
|
break;
|
|
#endif /* IPCOM_USE_INET */
|
|
#ifdef IPCOM_USE_INET6
|
|
case IPMPLS_EIOXNDPROBE:
|
|
|
|
|
|
if (penultimate == IP_NULL || *penultimate == IP_FALSE)
|
|
pkt->force_frame_type = IPNET_ETHFRAME_MPLS_UNICAST;
|
|
|
|
ipnet_mpls_ip6_neighbor_cache_probe((Ipnet_netif *) netif,
|
|
pkt,
|
|
(struct Ip_sockaddr_in6 *) more,
|
|
ipnet_mpls_probe_reply);
|
|
break;
|
|
#endif /* IPCOM_USE_INET6 */
|
|
|
|
default:
|
|
ip_assert(ipnet_netif);
|
|
ipnet_kioevent(ipnet_netif, command, data, IP_FLAG_FC_STACKCONTEXT);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* IPMPLS */
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|