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

1099 lines
48 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6ha_route.c,v $ $Revision: 1.23.10.2 $
* $Source: /home/interpeak/CVSRoot/ipmip6ha/src/ipmip6ha_route.c,v $
* $Author: svc-cmnet $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Joel Hortelius <joel.hortelis@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipmip6ha_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom_clib.h>
#include <ipcom_os.h>
#include <ipcom_sock.h>
#include <ipcom_sock6.h>
#include <ipcom_inet.h>
#include <ipcom_list.h>
#include <ipcom_hash.h>
#include <ipcom_syslog.h>
#include <ipcom_ipd.h>
#include <ipnet.h>
#include <ipmip.h>
#include <private/ipmip_util.h>
#include <private/ipmip_inet.h>
#include <ipmip6.h>
#include <private/ipmip6_context.h>
#include <private/ipmip6_mh.h>
#include <private/ipmip6_mh_pkt.h>
#include <private/ipmip6_netlink.h>
#include <private/ipmip6_if.h>
#include <private/ipmip6_util.h>
#include "ipmip6ha_h.h"
#include "ipmip6ha_pktbuf.h"
#include "ipmip6ha_mh.h"
#include "ipmip6ha_if.h"
#include "ipmip6ha_node.h"
#include "ipmip6ha_attr_h.h"
#include "ipmip6ha_route.h"
#include "ipmip6ha_nemo.h"
#include "ipmip6ha_nemo_dsmipv6.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
enum
{
IPMIP6HA_ROUTE_STATE_DO_ADD,
IPMIP6HA_ROUTE_STATE_DO_DEL,
};
#define IPMIP6HA_ROUTE_COA_SIZE(x) ((x) == IPMIP6_MIB_InetAddressType_ipv6? sizeof(struct Ip_in6_addr) : sizeof(Ip_u32))
#define IPMIP6HA_ROUTE_GRE(x) ((x)->registered.mip6BindingTunnelType == IPMIP_TUNNELTYPE_GRE || (x)->registered.mip6BindingTunnelType == IPMIP_TUNNELTYPE_GRE6)
#define IPMIP6HA_ROUTE_GRE_KEYS(x) (IPMIP6HA_ROUTE_GRE(x) && (x)->gre_keys[IPMIP_LINK_DOWN] && (x)->gre_keys[IPMIP_LINK_UP])
#define IPMIP6HA_ROUTE_GRE_DOWNLINK(x) (IPMIP6HA_ROUTE_GRE_KEYS(x)? (x)->gre_keys[IPMIP_LINK_DOWN] : IP_NULL)
#define IPMIP6HA_ROUTE_GRE_UPLINK(x) (IPMIP6HA_ROUTE_GRE_KEYS(x)? (x)->gre_keys[IPMIP_LINK_UP] : IP_NULL)
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
typedef void (*Ipmip6ha_route_state_do_t) (struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd);
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC void ipmip6ha_route_state_ipv6(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd);
IP_STATIC void ipmip6ha_route_state_tunnel_ipv6(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd);
IP_STATIC void ipmip6ha_route_state_ipv6_nemo(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd);
IP_STATIC void ipmip6ha_route_state_ipv4_nemo(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd);
IP_STATIC void ipmip6ha_route_state_ipv4(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
static Ipmip6ha_route_state_do_t ipmip6ha_route_states[IPMIP6HA_ROUTE_BIT_MAX] =
{
ipmip6ha_route_state_ipv6,
ipmip6ha_route_state_tunnel_ipv6,
ipmip6ha_route_state_ipv6_nemo,
ipmip6ha_route_state_ipv4_nemo,
ipmip6ha_route_state_ipv4
};
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
IP_STATIC int
ipmip6ha_netlink_route_ro_rthdr(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ip_u8 flags,
Ip_u32 table,
Ip_u32 ifindex,
const struct Ip_in6_addr *hoa,
const struct Ip_in6_addr *coa,
const void *prefix,
Ip_size_t psize,
Ip_u32 prefix_len,
Ip_u32 rtf_flags,
Ip_u32 identity,
Ipmip_netlink_kern_compare_t *srccmp)
{
Ipmip_buffer_t rbuf;
Ip_size_t hdr_off;
struct Ip_mipmsg *msg;
int ret;
Ipmip_netlink_kern_handle_t handle;
ipmip_buffer_init(&rbuf);
/* Create NLMSG HDR */
ipmip_netlink_nlmsghdr_request(&rbuf, 0, 0, IP_RTM_NEWMIP, 0);
msg = ipmip_buffer_offset(&rbuf, ipmip_netlink_nlmsghdr_put(&rbuf, IP_NULL, sizeof(*msg)));
msg->mip_family = IP_AF_INET6;
msg->mip_type = IP_WRMOB6_NEW_ROUTE_RO_RTHDR;
msg->mip_flags = flags;
/* Create the nested HoA attribute */
hdr_off = ipmip_netlink_nlmsghdr_rta_begin(&rbuf, IP_MIP_ENCAP);
ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_IFINDEX, ifindex);
ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_DST, psize, prefix);
ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_DST_LEN, prefix_len);
ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_TABLE, table);
ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_FLAGS, rtf_flags);
if (srccmp)
ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_SRCMAC, sizeof(*srccmp), srccmp);
if (identity)
{
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
handle.mip_ident = identity;
ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_HANDLE, sizeof(handle), &handle);
}
if (hoa)
ipmip_netlink_nlmsghdr_rta_put_in6(&rbuf, IP_WRMOB6_ROUTE_HOA, hoa);
if (coa)
ipmip_netlink_nlmsghdr_rta_put_in6(&rbuf, IP_WRMOB6_ROUTE_COA, coa);
ipmip_netlink_nlmsghdr_rta_end(&rbuf, hdr_off);
/* Complete the buffer */
ipmip_netlink_nlmsghdr_done(&rbuf, 0);
/* NETLINK request */
ret = ipmip_netlink_request(&ctx->ipmip6.ipmip,
proc,
ctx->ipmip6.ipmip.nl_req,
0,
0,
(struct Ip_nlmsghdr *)IPMIP_BUFFER_PTR(&rbuf),
IP_NULL);
/**/
ipmip_buffer_release(&rbuf);
if (ret < 0)
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Unable to perform MIP6 command NEW/RTHDR = %d", -ret));
}
return ret;
}
IP_STATIC Ipmip_netlink_kern_compare_t *
ipmip6ha_route_state_cmp_tunnel_end(Ipmip_netlink_kern_compare_t *scmp,
Ipmip6ha_node_t *node)
{
Ip_u32 *gre_key = IPMIP6HA_ROUTE_GRE_UPLINK(node);
Ipmip_netlink_kern_compare_t *scmpp = IP_NULL;
if (gre_key || node->ifp_home->AlwaysVerifyTunnelSrc)
{
if (node->registered.mip6BindingCOAType == IPMIP6_MIB_InetAddressType_ipv6)
scmpp = ipmip_netlink_route_src_tunnel_in6(scmp, &node->registered.mip6BindingCOA.ipv6, gre_key);
#ifdef IPMIP_USE_INET
else
scmpp = ipmip_netlink_route_src_tunnel_in(scmp, node->registered.mip6BindingCOA.ipv4.s_addr, gre_key);
#endif
}
return scmpp;
}
IP_STATIC void
ipmip6ha_route_state_ipv6(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd)
{
switch (docmd)
{
case IPMIP6HA_ROUTE_STATE_DO_ADD:
/* Add the R/O route to the home agent */
ipmip6ha_netlink_route_ro_rthdr(ctx,
proc,
0,
node->ifp_transport->iftables.route_optimize,
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
&node->registered.mip6BindingCOA.ipv6,
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
sizeof(node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6),
128,
IPNET_RTF_MBINDING|IPNET_RTF_BLACKHOLE,
node->identity,
IP_NULL);
break;
case IPMIP6HA_ROUTE_STATE_DO_DEL:
/* Delete the R/O route to the home agent */
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET6,
IP_RTM_DELROUTE,
node->ifp_transport->iftables.route_optimize,
0,
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
128,
IP_NULL,
IP_RTN_UNICAST);
break;
}
}
IP_STATIC void
ipmip6ha_route_state_ipv6_nemo(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd)
{
Ipmip6ha_nemo_t *nemo, *nnemo;
Ipmip_netlink_kern_compare_t scmp;
Ipmip_netlink_kern_handle_t handle;
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
handle.mip_ident = node->identity;
switch (docmd)
{
case IPMIP6HA_ROUTE_STATE_DO_ADD:
for (nemo = IPCOM_LIST_FIRST(&node->nemo_v6); nemo != IP_NULL; nemo = nnemo)
{
nnemo = IPCOM_LIST_NEXT(&nemo->next);
/* Create inbound tunnel route */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
0,
node->ifp_home->iftables.tunnel,
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
&nemo->prefix,
sizeof(nemo->prefix),
nemo->len,
&node->registered.mip6BindingCOA,
IPMIP6HA_ROUTE_COA_SIZE(node->registered.mip6BindingCOAType),
node->registered.mip6BindingUDPEncapType,
IP_NULL,
&handle,
IPMIP_LINK_RECV,
IPMIP6HA_ROUTE_GRE_DOWNLINK(node),
IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND);
/* Create outbound statistics route */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_RX,
0,
ctx->iftables.forward,
node->ifp_home->ipmip6.iff.ifindex,
&nemo->prefix,
sizeof(nemo->prefix),
nemo->len,
IP_NULL,
0,
0,
ipmip6ha_route_state_cmp_tunnel_end(&scmp, node),
&handle,
IPMIP_LINK_SEND,
IP_NULL,
IPNET_RTF_SKIP); /* */
nemo->flags = (Ip_u8)(nemo->flags & ~IPMIP6HA_NEMO_ACL_ADDED);
}
break;
case IPMIP6HA_ROUTE_STATE_DO_DEL:
for (nemo = IPCOM_LIST_FIRST(&node->nemo_v6); nemo != IP_NULL; nemo = nnemo)
{
nnemo = IPCOM_LIST_NEXT(&nemo->next);
if (IP_BIT_ISFALSE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
{
/* Delete the tunneling route */
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET6,
IP_RTM_DELROUTE,
node->ifp_home->iftables.tunnel,
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
&nemo->prefix,
nemo->len,
IP_NULL,
IP_RTN_UNICAST);
/* Delete the STATS route */
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET6,
IP_RTM_DELROUTE,
ctx->iftables.forward,
node->ifp_home->ipmip6.iff.ifindex,
&nemo->prefix,
nemo->len,
IP_NULL,
IP_RTN_UNICAST);
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_DELETED))
ipmip6ha_nemo_free(ctx, proc, node, nemo);
}
}
break;
}
}
IP_STATIC void
ipmip6ha_route_state_tunnel_ipv6(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd)
{
Ipmip_netlink_kern_compare_t scmp;
Ipmip_netlink_kern_handle_t handle;
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
handle.mip_ident = node->identity;
switch (docmd)
{
case IPMIP6HA_ROUTE_STATE_DO_ADD:
/* Create inbound tunnel route */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
0,
node->ifp_home->iftables.tunnel,
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
sizeof(node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6),
128,
&node->registered.mip6BindingCOA,
IPMIP6HA_ROUTE_COA_SIZE(node->registered.mip6BindingCOAType),
node->registered.mip6BindingUDPEncapType,
IP_NULL,
&handle,
IPMIP_LINK_RECV,
IPMIP6HA_ROUTE_GRE_DOWNLINK(node),
IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND);
/* Create outbound statistics route */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_RX,
0,
ctx->iftables.forward,
node->ifp_home->ipmip6.iff.ifindex,
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
sizeof(node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6),
128,
IP_NULL,
0,
0,
ipmip6ha_route_state_cmp_tunnel_end(&scmp, node),
&handle,
IPMIP_LINK_SEND,
IP_NULL,
IPNET_RTF_SKIP); /* */
break;
case IPMIP6HA_ROUTE_STATE_DO_DEL:
/* Delete the tunneling route */
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET6,
IP_RTM_DELROUTE,
node->ifp_home->iftables.tunnel,
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
128,
IP_NULL,
IP_RTN_UNICAST);
/* Delete the STATS route */
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET6,
IP_RTM_DELROUTE,
ctx->iftables.forward,
node->ifp_home->ipmip6.iff.ifindex,
&node->mip6BindingCacheEntry.mip6BindingHomeAddress.ipv6,
128,
IP_NULL,
IP_RTN_UNICAST);
break;
}
}
IP_STATIC void
ipmip6ha_route_state_ipv4_nemo(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd)
{
#ifdef IPMIP_USE_INET
Ipmip6ha_nemo_dsmipv6_t *nemo, *nnemo;
Ipmip_netlink_kern_compare_t scmp;
Ipmip_netlink_kern_handle_t handle;
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
handle.mip_ident = node->identity;
switch (docmd)
{
case IPMIP6HA_ROUTE_STATE_DO_ADD:
for (nemo = IPCOM_LIST_FIRST(&node->nemo_prefix_v4); nemo != IP_NULL; nemo = nnemo)
{
nnemo = IPCOM_LIST_NEXT(&nemo->next);
/* Create inbound tunnel route */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
0,
node->ifp_home->iftables.tunnel,
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
&nemo->prefix,
sizeof(nemo->prefix),
(Ip_u8)nemo->len,
&node->registered.mip6BindingCOA,
IPMIP6HA_ROUTE_COA_SIZE(node->registered.mip6BindingCOAType),
node->registered.mip6BindingUDPEncapType,
IP_NULL,
&handle,
IPMIP_LINK_RECV,
IPMIP6HA_ROUTE_GRE_DOWNLINK(node),
IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND);
/* Create outbound statistics route */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_RX,
0,
ctx->iftables.forward,
node->ifp_home->ipmip6.iff.ifindex,
&nemo->prefix,
sizeof(nemo->prefix),
(Ip_u8)nemo->len,
IP_NULL,
0,
0,
ipmip6ha_route_state_cmp_tunnel_end(&scmp, node),
&handle,
IPMIP_LINK_SEND,
IP_NULL,
IPNET_RTF_SKIP); /* */
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
nemo->flags = (Ip_u8)(nemo->flags & ~IPMIP6HA_NEMO_ACL_ADDED);
}
break;
case IPMIP6HA_ROUTE_STATE_DO_DEL:
for (nemo = IPCOM_LIST_FIRST(&node->nemo_prefix_v4); nemo != IP_NULL; nemo = nnemo)
{
nnemo = IPCOM_LIST_NEXT(&nemo->next);
if (IP_BIT_ISFALSE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
{
/* Delete the tunneling route */
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET,
IP_RTM_DELROUTE,
node->ifp_home->iftables.tunnel,
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
&nemo->prefix,
(Ip_u8)nemo->len,
IP_NULL,
IP_RTN_UNICAST);
/* Delete the STATS route */
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET,
IP_RTM_DELROUTE,
ctx->iftables.forward,
node->ifp_home->ipmip6.iff.ifindex,
&nemo->prefix,
(Ip_u8)nemo->len,
IP_NULL,
IP_RTN_UNICAST);
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_DELETED))
{
/* Free this NEMO entry */
ipmip6ha_nemo_dsmipv6_free(ctx, proc, node, nemo);
}
}
}
break;
}
#else
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(node);
IPMIP_UNUSED_PARAMETER(docmd);
#endif
}
IP_STATIC void
ipmip6ha_route_state_ipv4(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
int docmd)
{
#ifdef IPMIP_USE_INET
Ipmip6ha_nemo_dsmipv6_t *nemo, *nnemo;
Ipmip_netlink_kern_compare_t scmp;
Ipmip_netlink_kern_handle_t handle;
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
handle.mip_ident = node->identity;
switch (docmd)
{
case IPMIP6HA_ROUTE_STATE_DO_ADD:
for (nemo = IPCOM_LIST_FIRST(&node->nemo_hoa_v4); nemo != IP_NULL; nemo = nnemo)
{
nnemo = IPCOM_LIST_NEXT(&nemo->next);
/* Create inbound tunnel route */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
0,
node->ifp_home->iftables.tunnel,
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
&nemo->prefix,
sizeof(nemo->prefix),
(Ip_u8)nemo->len,
&node->registered.mip6BindingCOA,
IPMIP6HA_ROUTE_COA_SIZE(node->registered.mip6BindingCOAType),
node->registered.mip6BindingUDPEncapType,
IP_NULL,
&handle,
IPMIP_LINK_RECV,
IPMIP6HA_ROUTE_GRE_DOWNLINK(node),
IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND);
/* Create outbound statistics route */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
0,
ctx->iftables.forward,
node->ifp_home->ipmip6.iff.ifindex,
&nemo->prefix,
sizeof(nemo->prefix),
(Ip_u8)nemo->len,
IP_NULL,
0,
0,
ipmip6ha_route_state_cmp_tunnel_end(&scmp, node),
&handle,
IPMIP_LINK_SEND,
IP_NULL,
IPNET_RTF_SKIP); /* */
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
{
if (IP_BIT_ISFALSE(nemo->flags, IPMIP6HA_NEMO_ACL_HOA_PROXY))
{
ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff_lock);
if (!ipmip_inet_arp_proxy(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff.ifindex, nemo->prefix, IP_TRUE))
{
IPMIP6_EVENT_IF(ERR, proc,
ipmip_log_event_add(&ctx->ipmip6.ipmip,
proc,
"Unable to install proxy ARP handler for %s (%s) = %x",
ipmip6ha_node_describe(proc, node),
ipmip_ntop_inet(proc, nemo->prefix),
ipcom_errno));
}
IP_BIT_SET(nemo->flags, IPMIP6HA_NEMO_ACL_HOA_PROXY);
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff_lock);
}
nemo->flags = (Ip_u8)(nemo->flags & ~IPMIP6HA_NEMO_ACL_ADDED);
}
}
break;
case IPMIP6HA_ROUTE_STATE_DO_DEL:
for (nemo = IPCOM_LIST_FIRST(&node->nemo_hoa_v4); nemo != IP_NULL; nemo = nnemo)
{
nnemo = IPCOM_LIST_NEXT(&nemo->next);
if (IP_BIT_ISFALSE(nemo->flags, IPMIP6HA_NEMO_ACL_ADDED))
{
/* Delete the tunneling route */
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET,
IP_RTM_DELROUTE,
node->ifp_home->iftables.tunnel,
node->ifp_transport->iftunnels[node->registered.mip6BindingTunnelType]->ipmip6.iff.ifindex,
&nemo->prefix,
(Ip_u8)nemo->len,
IP_NULL,
IP_RTN_UNICAST);
/* Delete the STATS route */
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET,
IP_RTM_DELROUTE,
ctx->iftables.forward,
node->ifp_home->ipmip6.iff.ifindex,
&nemo->prefix,
(Ip_u8)nemo->len,
IP_NULL,
IP_RTN_UNICAST);
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_DELETED))
{
if (IP_BIT_ISTRUE(nemo->flags, IPMIP6HA_NEMO_ACL_HOA_PROXY))
{
ipmip_timer_lock_acquire(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff_lock);
ipmip_inet_arp_proxy(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff.ifindex, nemo->prefix, IP_FALSE);
nemo->flags = (Ip_u8)(nemo->flags & ~IPMIP6HA_NEMO_ACL_HOA_PROXY);
ipmip_timer_lock_release(&ctx->ipmip6.ipmip, proc, node->ifp_home->ipmip6.iff_lock);
}
/* Free this NEMO entry */
ipmip6ha_nemo_dsmipv6_free(ctx, proc, node, nemo);
}
}
}
break;
}
#else
IPMIP_UNUSED_PARAMETER(ctx);
IPMIP_UNUSED_PARAMETER(proc);
IPMIP_UNUSED_PARAMETER(node);
IPMIP_UNUSED_PARAMETER(docmd);
#endif
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipmip6ha_route_state_add
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip6ha_route_state_add(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
Ip_u32 states)
{
unsigned int i;
for (i = 0; i < IPMIP6HA_ROUTE_BIT_MAX; i++)
{
if (IPMIP6HA_ROUTE_STATE_CHECK(states,i) != 0)
{
if (IPMIP6HA_ROUTE_STATE_CHECK(node->route_state,i) == 0)
{
/* Time to enable this state */
(*ipmip6ha_route_states[i]) (ctx, proc, node, IPMIP6HA_ROUTE_STATE_DO_ADD);
node->route_state |= IPMIP6HA_ROUTE_STATE_BIT(i);
}
}
}
}
/*
*===========================================================================
* ipmip6ha_route_state_add
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL void
ipmip6ha_route_state_del(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node,
Ip_u32 states)
{
unsigned int i;
for (i = 0; i < IPMIP6HA_ROUTE_BIT_MAX; i++)
{
if (IPMIP6HA_ROUTE_STATE_CHECK(states,i) != 0)
{
if (IPMIP6HA_ROUTE_STATE_CHECK(node->route_state,i) != 0)
{
/* Time to enable this state */
(*ipmip6ha_route_states[i]) (ctx, proc, node, IPMIP6HA_ROUTE_STATE_DO_DEL);
node->route_state &= ~IPMIP6HA_ROUTE_STATE_BIT(i);
}
}
}
}
IP_GLOBAL void
ipmip6ha_route_add_outbound(struct Ipmip6ha_context *ctx,
struct Ipmip6ha_node *node,
Ip_u64 octets,
Ip_u64 pkts)
{
IPMIP_UNUSED_PARAMETER(ctx);
IP_U64_ADD(node->mip6NodeTrafficEntry.mip6HCNodeOutOctets, octets);
node->mip6NodeTrafficEntry.mip6NodeOutOctets = IP_U64_GETLO(node->mip6NodeTrafficEntry.mip6HCNodeOutOctets);
IP_U64_ADD(node->mip6NodeTrafficEntry.mip6HCNodeOutPkts, pkts);
node->mip6NodeTrafficEntry.mip6NodeOutPkts = IP_U64_GETLO(node->mip6NodeTrafficEntry.mip6HCNodeOutPkts);
}
IP_GLOBAL void
ipmip6ha_route_add_inbound(struct Ipmip6ha_context *ctx,
struct Ipmip6ha_node *node,
Ip_u64 octets,
Ip_u64 pkts)
{
IPMIP_UNUSED_PARAMETER(ctx);
IP_U64_ADD(node->mip6NodeTrafficEntry.mip6HCNodeInOctets, octets);
node->mip6NodeTrafficEntry.mip6NodeInOctets = IP_U64_GETLO(node->mip6NodeTrafficEntry.mip6HCNodeInOctets);
IP_U64_ADD(node->mip6NodeTrafficEntry.mip6HCNodeInPkts, pkts);
node->mip6NodeTrafficEntry.mip6NodeInPkts = IP_U64_GETLO(node->mip6NodeTrafficEntry.mip6HCNodeInPkts);
}
IP_GLOBAL void
ipmip6ha_route_direct_temporary(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_if_t *ifp,
struct Ip_in6_addr *endpoint,
union Ipmip6_mib_InetAddress *tunnel_endpoint,
Ip_u32 tunnel_endpoint_type,
Ip_u16 port)
{
Ipmip_netlink_kern_compare_t scmp;
#ifdef IPMIP_USE_INET
if (tunnel_endpoint_type == IPMIP6_MIB_InetAddressType_ipv4)
{
/* Need the temporary tunneling rule if we're doing inet */
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
IP_WRMOB6_NEW_TYPE_TEMPORARY,
ifp->iftables.pending,
ifp->iftunnels[IPMIP_TUNNELTYPE_IPIP]->ipmip6.iff.ifindex,
endpoint,
sizeof(struct Ip_in6_addr),
128,
&tunnel_endpoint->ipv4,
sizeof(struct Ip_in_addr),
port,
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH),
IP_NULL,
IPMIP_LINK_RECV,
IP_NULL,
IPNET_RTF_TUNNELEND);
}
else
#endif
if (port)
{
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
IP_WRMOB6_NEW_TYPE_TEMPORARY,
ifp->iftables.pending,
ifp->iftunnels[IPMIP_TUNNELTYPE_IP6IP6]->ipmip6.iff.ifindex,
endpoint,
sizeof(struct Ip_in6_addr),
128,
&tunnel_endpoint->ipv6,
sizeof(struct Ip_in6_addr),
port,
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH),
IP_NULL,
IPMIP_LINK_RECV,
IP_NULL,
IPNET_RTF_TUNNELEND);
}
}
IP_GLOBAL void
ipmip6ha_route_rthdr_temporary(Ipmip6ha_context_t *ctx,
Ipmip_proc_t *proc,
Ipmip6ha_if_t *ifp,
struct Ip_in6_addr *hoa,
union Ipmip6_mib_InetAddress *coa,
Ip_u32 coa_type,
Ip_u16 port)
{
Ipmip_netlink_kern_compare_t scmp;
IPMIP_UNUSED_PARAMETER(coa_type);
#ifdef IPMIP_USE_INET
if (coa_type == IPMIP6_MIB_InetAddressType_ipv4)
{
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
IP_WRMOB6_NEW_TYPE_TEMPORARY,
ifp->iftables.pending,
ifp->iftunnels[IPMIP_TUNNELTYPE_IPIP]->ipmip6.iff.ifindex,
hoa,
sizeof(struct Ip_in6_addr),
128,
&coa->ipv4.s_addr,
sizeof(struct Ip_in_addr),
port,
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH),
IP_NULL,
IPMIP_LINK_RECV,
IP_NULL,
IPNET_RTF_TUNNELEND);
}
else
#endif
if (port)
{
ipmip6_netlink_route_mip_do(&ctx->ipmip6,
proc,
IP_RTM_NEWMIP,
IP_WRMOB6_NEW_LINK_TX,
IP_WRMOB6_NEW_TYPE_TEMPORARY,
ifp->iftables.pending,
ifp->iftunnels[IPMIP_TUNNELTYPE_IP6IP6]->ipmip6.iff.ifindex,
hoa,
sizeof(struct Ip_in6_addr),
128,
&coa->ipv6,
sizeof(struct Ip_in6_addr),
port,
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH),
IP_NULL,
IPMIP_LINK_RECV,
IP_NULL,
IPNET_RTF_TUNNELEND);
}
else
{
/* Add the R/O route to the mobile node */
ipmip6ha_netlink_route_ro_rthdr(ctx,
proc,
IP_WRMOB6_NEW_TYPE_TEMPORARY,
ifp->iftables.pending,
ifp->ipmip6.iff.ifindex,
hoa,
&coa->ipv6,
hoa,
sizeof(struct Ip_in6_addr),
128,
IPNET_RTF_BLACKHOLE,
0,
ipmip_netlink_route_src_protocol(&scmp, IP_IPPROTO_MH));
}
}
IP_GLOBAL Ip_bool
ipmip6ha_route_update_temporary(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_pktbuf *pbuf,
Ip_bool route_direct)
{
/* Restore route states; we're done */
if (route_direct)
{
ipmip6ha_route_direct_temporary(ctx,
proc,
pbuf->iff_transport.priv,
&pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr,
&pbuf->pktinfo.mip6BindingCOA,
pbuf->pktinfo.mip6BindingCOAType,
pbuf->pktinfo.mip6BindingUDPEncapPort);
}
else
{
if (pbuf->pktinfo.haMobilityDeregistration && ipmip6_util_InetAddress_cmp(pbuf->pktinfo.mip6BindingCOAType, &pbuf->pktinfo.mip6BindingCOA, pbuf->pktinfo.mip6BindingHomeAddressType, &pbuf->pktinfo.mip6BindingHomeAddress))
{
ipmip_netlink_inX_route(&ctx->ipmip6.ipmip,
proc,
IP_AF_INET6,
IP_RTM_DELROUTE,
pbuf->iff_transport.priv->iftables.pending,
0,
&pbuf->ipmip6.ipmip.srcinfo.src->sin6.sin6_addr,
128,
IP_NULL,
IP_RTN_UNICAST);
return IP_TRUE;
}
else
{
ipmip6ha_route_rthdr_temporary(ctx,
proc,
pbuf->iff_transport.priv,
&pbuf->pktinfo.mip6BindingHomeAddress.ipv6,
&pbuf->pktinfo.mip6BindingCOA,
pbuf->pktinfo.mip6BindingCOAType,
pbuf->pktinfo.mip6BindingUDPEncapPort);
}
}
return IP_FALSE;
}
IP_GLOBAL void
ipmip6ha_route_context_init(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc)
{
ctx->iftables.forward = ipmip_util_route_table_alloc(&ctx->ipmip6.ipmip, proc);
}
IP_GLOBAL void
ipmip6ha_route_context_destroy(struct Ipmip6ha_context *ctx,
struct Ipmip_proc *proc)
{
if (ctx->iftables.forward != IPCOM_ROUTE_TABLE_UNSPEC)
ipmip_util_route_table_free(&ctx->ipmip6.ipmip, proc, ctx->iftables.forward);
}
IP_GLOBAL int
ipmip6ha_netlink_new_handle(Ipmip6ha_context_t *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node)
{
/**/
return ipmip6_netlink_new_handle(&ctx->ipmip6, proc, IPCOM_IPD_ID_IPMIP6HA, node->identity);
}
IP_GLOBAL int
ipmip6ha_netlink_del_handle(Ipmip6ha_context_t *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node)
{
/**/
return ipmip6_netlink_del_handle(&ctx->ipmip6, proc, IPCOM_IPD_ID_IPMIP6HA, node->identity);
}
IP_GLOBAL Ip_bool
ipmip6ha_netlink_get_handle_stat(Ipmip6ha_context_t *ctx,
struct Ipmip_proc *proc,
struct Ipmip6ha_node *node)
{
Ipmip6_netlink_kern_statistics_t link_recv, link_send;
Ipmip_netlink_kern_handle_t handle;
/* Identity */
handle.mip_facility = IPCOM_IPD_ID_IPMIP6HA;
handle.mip_ident = node->identity;
/* Retrieve the statistics; the SEND/RECV from the MIP4 point of view is
* 'send tunnel' / 'receive tunnel', while from the node point of view
* (statistics) is 'send from node' / 'send to node'. So, we have to
* reverse the send/recv variables to get it right.
*/
if (ipmip6_netlink_get_handle_stat(&ctx->ipmip6, proc, &handle, &link_recv, &link_send))
{
/* Update stats */
ipmip6_context_add_outbound(&ctx->ipmip6, link_send.mip_s_octets, link_send.mip_s_pkts);
ipmip6ha_route_add_outbound(ctx, node, link_send.mip_s_octets, link_send.mip_s_pkts);
ipmip6_context_add_inbound(&ctx->ipmip6, link_recv.mip_s_octets, link_recv.mip_s_pkts);
ipmip6ha_route_add_inbound(ctx, node, link_recv.mip_s_octets, link_recv.mip_s_pkts);
return IP_TRUE;
}
return IP_FALSE;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/