/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6ha_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 **************************************************************************** */