/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip6mn_route.c,v $ $Revision: 1.36.2.1 $ * $Source: /home/interpeak/CVSRoot/ipmip6mn/src/ipmip6mn_route.c,v $ * $Author: svc-cmnet $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include "ipmip6mn_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 "ipmip6mn_h.h" #include "ipmip6mn_route.h" #include "ipmip6mn_attr_h.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ enum { IPMIP6MN_ROUTE_DO_ADD, IPMIP6MN_ROUTE_DO_DEL, }; #ifdef IPMIP_USE_INET #define IPMIP6MN_ROUTE_LOCAL(ifp) ((ifp)->tun.family == IP_AF_INET6? (void *)&(ifp)->tun.local.in6 : (void *)&(ifp)->tun.local.in.s_addr) #define IPMIP6MN_ROUTE_ENDPOINT(ifp) ((ifp)->tun.family == IP_AF_INET6? (void *)&(ifp)->tun.remote_inet6 : (void *)&(ifp)->tun.remote_inet) #define IPMIP6MN_ROUTE_ENDPOINT_SIZE(ifp) (Ip_size_t)((ifp)->tun.family == IP_AF_INET6? sizeof(struct Ip_in6_addr) : sizeof(struct Ip_in_addr)) #define IPMIP6MN_ROUTE_SIZE(ifp) (Ip_size_t)((ifp)->tun.family == IP_AF_INET6? sizeof(struct Ip_in6_addr) : sizeof(struct Ip_in_addr)) #define IPMIP6MN_ROUTE_ENDPOINT_PORT(ifp,encap) (Ip_u32) ((encap)? ip_htons(IPMIP6_DSMIP_UDP_PORT) : 0) #define IPMIP6MN_ROUTE_ENDPOINT_PORT_CHECK(ifp) IPMIP6MN_ROUTE_ENDPOINT_PORT(ifp, (ifp)->tun.remote_transport_udp_encapsulate) #else #define IPMIP6MN_ROUTE_LOCAL(ifp) ((void *)&(ifp)->tun.local.in6) #define IPMIP6MN_ROUTE_ENDPOINT(ifp) (&(ifp)->tun.remote_inet6) #define IPMIP6MN_ROUTE_SIZE(ifp) (sizeof(struct Ip_in6_addr)) #define IPMIP6MN_ROUTE_ENDPOINT_PORT(ifp, nat) (0) #define IPMIP6MN_ROUTE_ENDPOINT_PORT_CHECK(ifp) (0) #endif /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipmip6mn_route_tunnel { Ipmip6_if_t iff6; int route_type; /* Current state */ int route_state; /* Current state */ Ip_u32 rtable; Ip_u32 btable; Ip_u32 htable; /* Home agent routing table */ Ip_u32 nemo_table; /* NEMO routing table */ Ip_u32 nemo_stats; /* NEMO routing table */ struct Ip_in6_addr inet6; /* Home Address */ #ifdef IPMIP_USE_INET Ip_u32 inet; Ip_u32 inet_plen; #endif /**/ struct Ipmip6mn_node *node; /* Current home agent policy route */ struct { Ip_u8 family; union Ip_in_addr_union local; struct Ip_in6_addr remote_inet6; Ip_u32 remote_inet; Ip_bool remote_transport_udp_encapsulate; Ip_bool remote_mh_udp_encapsulate; struct Ip_in6_addr nexthop; Ip_u32 ifindex; } tun; struct Ipmip6_mib_mip6NodeTrafficEntry mip6NodeTrafficEntry; struct { struct Ip_timeval basetick; struct Ip_timeval basetime; struct Ip_timeval current; } stats; } Ipmip6mn_route_tunnel_t; typedef void (*Ipmip6mn_route_func_t) (struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_STATIC void ipmip6mn_route_address(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_address_inet(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_blackhole_ipv6(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_blackhole_ipv4(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_transport_ha_ipv6_using_ipv6(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_transport_ha_MH_using_udp_encap(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_transport_ha_MH_home(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_transport_ipv6_using_ipvX(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_transport_ipv4_using_ipvX(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_transport_nemov6_using_ipvX(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); IP_STATIC void ipmip6mn_route_transport_nemov4_using_ipvX(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp); /* **************************************************************************** * 8 DATA **************************************************************************** */ static const char *route_types[IPMIP6MN_ROUTE_TYPE_MAX] = { "none", "blackhole", "home agent", "tunnel", "home", "home pending" }; static Ipmip6mn_route_func_t ipmip6mn_route_funcs[IPMIP6MN_ROUTE_BIT_MAX] = { ipmip6mn_route_address, ipmip6mn_route_address_inet, ipmip6mn_route_blackhole_ipv6, ipmip6mn_route_blackhole_ipv4, ipmip6mn_route_transport_ha_ipv6_using_ipv6, ipmip6mn_route_transport_ha_MH_using_udp_encap, ipmip6mn_route_transport_ha_MH_home, ipmip6mn_route_transport_ipv6_using_ipvX, ipmip6mn_route_transport_ipv4_using_ipvX, ipmip6mn_route_transport_nemov6_using_ipvX, ipmip6mn_route_transport_nemov4_using_ipvX }; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC int ipmip6mn_route_policy(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ip_u8 family, Ip_u32 prio, int cmd, Ip_u32 ifindex, const void *saddr, Ip_u32 saddr_len, const void *daddr, Ip_u32 daddr_len, Ip_u32 table, Ip_u32 extact) { IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "ip rule %s from %s/%d to %s/%d%s%s prio %u table %d", cmd == IP_RTM_NEWRULE? "add" : "delete", ipmip_ntop(proc, family, saddr? saddr : &ip_in6addr_any, IP_NULL), saddr_len, ipmip_ntop(proc, family, daddr? daddr : &ip_in6addr_any, IP_NULL), daddr_len, ifindex? " dev " : "", ifindex? ipcom_if_indextoname(ifindex, proc->ntop.ntop_name) : "", prio, table)); return ipmip_netlink_inX_rule(&ctx->ipmip6.ipmip, proc, family, cmd, table, prio, ifindex, saddr? saddr : &ip_in6addr_any, (Ip_u8)(saddr? saddr_len : 0), daddr? daddr : &ip_in6addr_any, (Ip_u8)(daddr? daddr_len : 0), 0, extact); } IP_STATIC void ipmip6mn_route_tunnel_cleanup(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_route_tunnel_t *ife) { /* Move routing state to NONE */ ipmip6mn_route_change(ctx, proc, &ife->iff6, IPMIP6MN_ROUTE_TYPE_NONE); /* Delete the route tables */ ipmip_util_route_table_free(&ctx->ipmip6.ipmip, proc, ife->rtable); ipmip_util_route_table_free(&ctx->ipmip6.ipmip, proc, ife->btable); ipmip_util_route_table_free(&ctx->ipmip6.ipmip, proc, ife->htable); ipmip_util_route_table_free(&ctx->ipmip6.ipmip, proc, ife->nemo_table); ipmip_util_route_table_free(&ctx->ipmip6.ipmip, proc, ife->nemo_stats); } IP_STATIC void ipmip6mn_route_address(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { Ipmip_netlink_kern_handle_t handle; /* Setup the inbound statistics route */ handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = rtifp->node->identifier; switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: /* Time to create a route for this prefix. */ ipmip6_netlink_route_mip_do(&ctx->ipmip6, proc, IP_RTM_NEWMIP, IP_WRMOB6_NEW_LINK_RX, 0, rtifp->nemo_stats, rtifp->iff6.iff.ifindex, &rtifp->inet6, sizeof(rtifp->inet6), 128, IP_NULL, 0, 0, IP_NULL, &handle, IPMIP_LINK_RECV, IP_NULL, IPNET_RTF_SKIP); ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_NEWRULE, rtifp->iff6.iff.ifindex, IP_NULL, 0, IP_NULL, 0, rtifp->nemo_stats, 0); break; case IPMIP6MN_ROUTE_DO_DEL: ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->nemo_stats, rtifp->iff6.iff.ifindex, &rtifp->inet6, 128, IP_NULL, IP_RTN_THROW); ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_DELRULE, rtifp->iff6.iff.ifindex, IP_NULL, 0, IP_NULL, 0, rtifp->nemo_stats, 0); break; } } IP_STATIC void ipmip6mn_route_address_inet(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { #ifdef IPMIP_USE_INET Ipmip_netlink_kern_handle_t handle; /* Setup the inbound statistics route */ handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = rtifp->node->identifier; switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: if (rtifp->inet != 0) { /* Time to create a route for this prefix. */ ipmip6_netlink_route_mip_do(&ctx->ipmip6, proc, IP_RTM_NEWMIP, IP_WRMOB6_NEW_LINK_RX, 0, rtifp->nemo_stats, rtifp->iff6.iff.ifindex, &rtifp->inet, sizeof(rtifp->inet), 32, IP_NULL, 0, 0, IP_NULL, &handle, IPMIP_LINK_RECV, IP_NULL, IPNET_RTF_SKIP); ipmip6mn_route_policy(ctx, proc, IP_AF_INET, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_NEWRULE, rtifp->iff6.iff.ifindex, IP_NULL, 0, IP_NULL, 0, rtifp->nemo_stats, 0); } break; case IPMIP6MN_ROUTE_DO_DEL: if (rtifp->inet != 0) { ipmip6mn_route_policy(ctx, proc, IP_AF_INET, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_DELRULE, rtifp->iff6.iff.ifindex, IP_NULL, 0, IP_NULL, 0, rtifp->nemo_stats, 0); ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->nemo_stats, rtifp->iff6.iff.ifindex, &rtifp->inet6, 128, IP_NULL, IP_RTN_THROW); } break; } #else IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(cmd); IPMIP_UNUSED_PARAMETER(rtifp); #endif } IP_STATIC void ipmip6mn_route_blackhole_ipv6(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: case IPMIP6MN_ROUTE_DO_DEL: ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_BLACKHOLE, cmd == IPMIP6MN_ROUTE_DO_ADD? IP_RTM_NEWRULE : IP_RTM_DELRULE, 0, &rtifp->inet6, 128, IP_NULL, 0, rtifp->btable, 0); break; } } IP_STATIC void ipmip6mn_route_blackhole_ipv4(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { #ifdef IPMIP_USE_INET switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: case IPMIP6MN_ROUTE_DO_DEL: { ipmip6mn_route_policy(ctx, proc, IP_AF_INET, IPMIP6MN_ROUTE_BLACKHOLE, cmd == IPMIP6MN_ROUTE_DO_ADD? IP_RTM_NEWRULE : IP_RTM_DELRULE, 0, &rtifp->inet, 32, IP_NULL, 0, rtifp->btable, 0); } break; } #else IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(cmd); IPMIP_UNUSED_PARAMETER(rtifp); #endif } IP_STATIC void ipmip6mn_route_transport_ha_ipv6_using_ipv6(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: { Ipmip_buffer_t rbuf; Ip_size_t hdr_off; struct Ip_mipmsg *msg; int ret; Ipmip_netlink_kern_handle_t handle; handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = rtifp->node->identifier; 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_DSTOPT; msg->mip_flags = 0; /* 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, rtifp->tun.ifindex); ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_DST, sizeof(struct Ip_in6_addr), &rtifp->tun.remote_inet6); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_DST_LEN, 128); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_TABLE, rtifp->rtable); ipmip_netlink_nlmsghdr_rta_put_u32(&rbuf, IP_WRMOB6_ROUTE_FLAGS, IPNET_RTF_GATEWAY); ipmip_netlink_nlmsghdr_rta_put_in6(&rbuf, IP_WRMOB6_ROUTE_HOA, &rtifp->inet6); ipmip_netlink_nlmsghdr_rta_put_in6(&rbuf, IP_WRMOB6_ROUTE_COA, &rtifp->tun.local.in6); ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_GW, sizeof(rtifp->tun.nexthop), &rtifp->tun.nexthop); ipmip_netlink_nlmsghdr_rta_put(&rbuf, IP_WRMOB6_ROUTE_HANDLE, sizeof(handle), &handle); 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 NEWMIP/DSTOPT = %d", -ret)); } } /* Nexthop routing */ ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_COA, IP_RTM_NEWRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->htable, 0); ipmip6mn_route_policy(ctx, proc, rtifp->tun.family, IPMIP6MN_ROUTE_BLACKHOLE, IP_RTM_NEWRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->btable, 0); ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_NEWROUTE, rtifp->htable, rtifp->tun.ifindex, &rtifp->tun.remote_inet6, 128, &rtifp->tun.nexthop, IP_RTN_UNICAST); break; case IPMIP6MN_ROUTE_DO_DEL: ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->rtable, rtifp->tun.ifindex, &rtifp->tun.remote_inet6, 128, &rtifp->tun.nexthop, IP_RTN_UNICAST); ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_COA, IP_RTM_DELRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->htable, 0); ipmip6mn_route_policy(ctx, proc, rtifp->tun.family, IPMIP6MN_ROUTE_BLACKHOLE, IP_RTM_DELRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->btable, 0); ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->htable, rtifp->tun.ifindex, &rtifp->tun.remote_inet6, 128, &rtifp->tun.nexthop, IP_RTN_UNICAST); break; } } IP_STATIC void ipmip6mn_route_transport_ha_MH_using_udp_encap(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { Ipmip_netlink_kern_handle_t handle; handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = rtifp->node->identifier; switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: ipmip6_netlink_route_mip_do(&ctx->ipmip6, proc, IP_RTM_NEWMIP, IP_WRMOB6_NEW_LINK_TX, 0, rtifp->rtable, rtifp->iff6.iff.ifindex, &rtifp->tun.remote_inet6, sizeof(struct Ip_in6_addr), 128, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp), IPMIP6MN_ROUTE_ENDPOINT_PORT(rtifp, IP_TRUE), IP_NULL, &handle, IPMIP_LINK_SEND, IP_NULL, IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND); if (rtifp->tun.family != IP_AF_INET6) { ipmip6mn_route_policy(ctx, proc, rtifp->tun.family, IPMIP6MN_ROUTE_COA, IP_RTM_NEWRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPCOM_ROUTE_TABLE_DEFAULT, 0); } else { ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_NEWROUTE, rtifp->htable, rtifp->tun.ifindex, &rtifp->tun.remote_inet6, 128, &rtifp->tun.nexthop, IP_RTN_UNICAST); ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_COA, IP_RTM_NEWRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->htable, 0); } ipmip6mn_route_policy(ctx, proc, rtifp->tun.family, IPMIP6MN_ROUTE_BLACKHOLE, IP_RTM_NEWRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->btable, 0); break; case IPMIP6MN_ROUTE_DO_DEL: if (rtifp->tun.family != IP_AF_INET6) { ipmip6mn_route_policy(ctx, proc, rtifp->tun.family, IPMIP6MN_ROUTE_COA, IP_RTM_DELRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPCOM_ROUTE_TABLE_DEFAULT, 0); } else { ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->htable, rtifp->tun.ifindex, &rtifp->tun.remote_inet6, 128, &rtifp->tun.nexthop, IP_RTN_UNICAST); ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_COA, IP_RTM_DELRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->htable, 0); } ipmip6mn_route_policy(ctx, proc, rtifp->tun.family, IPMIP6MN_ROUTE_BLACKHOLE, IP_RTM_DELRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->btable, 0); ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->rtable, rtifp->iff6.iff.ifindex, &rtifp->tun.remote_inet6, 128, IP_NULL, IP_RTN_UNICAST); break; } } IP_STATIC void ipmip6mn_route_transport_ha_MH_home(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { Ipmip_netlink_kern_handle_t handle; handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = rtifp->node->identifier; switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_NEWROUTE, rtifp->htable, rtifp->tun.ifindex, &rtifp->tun.remote_inet6, 128, &rtifp->tun.nexthop, IP_RTN_UNICAST); ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_COA, IP_RTM_NEWRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->htable, 0); break; case IPMIP6MN_ROUTE_DO_DEL: ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->htable, rtifp->tun.ifindex, &rtifp->tun.remote_inet6, 128, &rtifp->tun.nexthop, IP_RTN_UNICAST); ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_COA, IP_RTM_DELRULE, 0, IPMIP6MN_ROUTE_LOCAL(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp) * 8, rtifp->htable, 0); break; } } /* *=========================================================================== * ipmipmn_route_blackhole *=========================================================================== * Description: Add/delete blackhole route "0.0.0.0/0 -> 127.0.0.1" * Parameters: * Returns: * */ IP_STATIC void ipmip6mn_route_transport_nemov6_using_ipvX(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { Ipmip6mn_entry_nemo_t *nemo; Ipmip_netlink_kern_handle_t handle; handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = rtifp->node->identifier; switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: /* Go through the NEMO tables */ for (nemo = IPCOM_LIST_FIRST(&rtifp->node->config->nemo); nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->nemo_next)) { if ((nemo->nemo_ifindex = ipcom_if_nametoindex(nemo->nemo_ingress)) != 0) { unsigned i; nemo->nemo_installed = IP_TRUE; ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_NEWRULE, nemo->nemo_ifindex, IP_NULL, 0, IP_NULL, 0, rtifp->nemo_table, IP_FIB_RULE_FIND_SADDR); for (i = 0; i < nemo->nemo_prefixes.numelem; i++) { Ipmip6_mh_mo_mobile_prefix_t *mo = (Ipmip6_mh_mo_mobile_prefix_t *)nemo->nemo_prefixes.hdrs[i]; /* Time to create a route for this prefix. */ ipmip6_netlink_route_mip_do(&ctx->ipmip6, proc, IP_RTM_NEWMIP, IP_WRMOB6_NEW_LINK_TX, 0, rtifp->nemo_table, rtifp->iff6.iff.ifindex, &mo->prefix, sizeof(mo->prefix), mo->prefix_length, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp), IPMIP6MN_ROUTE_ENDPOINT_PORT_CHECK(rtifp), IP_NULL, &handle, IPMIP_LINK_SEND, IP_NULL, IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND); /* Time to create a route for this prefix. */ ipmip6_netlink_route_mip_do(&ctx->ipmip6, proc, IP_RTM_NEWMIP, IP_WRMOB6_NEW_LINK_TX, 0, rtifp->nemo_stats, nemo->nemo_ifindex, &mo->prefix, sizeof(mo->prefix), mo->prefix_length, IP_NULL, 0, 0, IP_NULL, &handle, IPMIP_LINK_RECV, IP_NULL, IPNET_RTF_SKIP); } } } break; case IPMIP6MN_ROUTE_DO_DEL: /* Go through the NEMO tables */ for (nemo = IPCOM_LIST_FIRST(&rtifp->node->config->nemo); nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->nemo_next)) { if (nemo->nemo_installed) { unsigned i; ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_DELRULE, nemo->nemo_ifindex, IP_NULL, 0, IP_NULL, 0, rtifp->nemo_table, IP_FIB_RULE_FIND_SADDR); for (i = 0; i < nemo->nemo_prefixes.numelem; i++) { Ipmip6_mh_mo_mobile_prefix_t *mo = (Ipmip6_mh_mo_mobile_prefix_t *)nemo->nemo_prefixes.hdrs[i]; ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->nemo_table, rtifp->iff6.iff.ifindex, &mo->prefix, mo->prefix_length, IP_NULL, IP_RTN_UNICAST); ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->nemo_stats, nemo->nemo_ifindex, &mo->prefix, mo->prefix_length, IP_NULL, IP_RTN_UNICAST); } nemo->nemo_installed = IP_FALSE; } } break; } } /* *=========================================================================== * ipmipmn_route_blackhole *=========================================================================== * Description: Add/delete blackhole route "0.0.0.0/0 -> 127.0.0.1" * Parameters: * Returns: * */ IP_STATIC void ipmip6mn_route_transport_nemov4_using_ipvX(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { #ifdef IPMIP_USE_INET Ipmip6mn_dsmipv6_nemo_t *nemo; Ipmip6mn_dsmipv6_nemo_prefix_t *nw; Ipmip_netlink_kern_handle_t handle; handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = rtifp->node->identifier; switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: /* Go through the NEMO tables */ for (nemo = IPCOM_LIST_FIRST(&rtifp->node->config->dsmipv6.nemo); nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->nemo_next)) { if ((nemo->nemo_if.ifindex = ipcom_if_nametoindex(nemo->nemo_if.ifname)) != 0) { ipmip_if_resolve_lla(&ctx->ipmip6.ipmip, proc, &nemo->nemo_if); ipmip6mn_route_policy(ctx, proc, IP_AF_INET, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_NEWRULE, nemo->nemo_if.ifindex, IP_NULL, 0, IP_NULL, 0, rtifp->nemo_table, IP_FIB_RULE_FIND_SADDR); for (nw = nemo->nemo_dsmipv6; nw != IP_NULL; nw = nw->next_nemo_prefix) { if (nw->request_prefix && nw->updated == IP_TRUE && nw->status == IPMIP6_MH_BU_DSMIPV6_HOA_ACK_SUCCESS) { ipmip6_netlink_route_mip_do(&ctx->ipmip6, proc, IP_RTM_NEWMIP, IP_WRMOB6_NEW_LINK_TX, 0, rtifp->nemo_table, rtifp->iff6.iff.ifindex, &nw->runtime_prefix, sizeof(nw->runtime_prefix), nw->runtime_prefix_length, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp), IPMIP6MN_ROUTE_ENDPOINT_PORT_CHECK(rtifp), IP_NULL, &handle, IPMIP_LINK_SEND, IP_NULL, IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND); /* Time to create a route for this prefix. */ ipmip6_netlink_route_mip_do(&ctx->ipmip6, proc, IP_RTM_NEWMIP, IP_WRMOB6_NEW_LINK_TX, 0, rtifp->nemo_stats, nemo->nemo_if.ifindex, &nw->runtime_prefix, sizeof(nw->runtime_prefix), nw->runtime_prefix_length, IP_NULL, 0, 0, IP_NULL, &handle, IPMIP_LINK_RECV, IP_NULL, IPNET_RTF_SKIP); } } } } break; case IPMIP6MN_ROUTE_DO_DEL: /* Go through the NEMO tables */ for (nemo = IPCOM_LIST_FIRST(&rtifp->node->config->dsmipv6.nemo); nemo != IP_NULL; nemo = IPCOM_LIST_NEXT(&nemo->nemo_next)) { if (nemo->nemo_if.ifindex != 0) { ipmip6mn_route_policy(ctx, proc, IP_AF_INET, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_DELRULE, nemo->nemo_if.ifindex, IP_NULL, 0, IP_NULL, 0, rtifp->nemo_table, IP_FIB_RULE_FIND_SADDR); for (nw = nemo->nemo_dsmipv6; nw != IP_NULL; nw = nw->next_nemo_prefix) { if (nw->request_prefix && nw->updated == IP_TRUE && nw->status == IPMIP6_MH_BU_DSMIPV6_HOA_ACK_SUCCESS) { ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_DELROUTE, rtifp->nemo_table, rtifp->iff6.iff.ifindex, &nw->runtime_prefix, nw->runtime_prefix_length, IP_NULL, IP_RTN_UNICAST); ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_DELROUTE, rtifp->nemo_stats, nemo->nemo_if.ifindex, &nw->runtime_prefix, nw->runtime_prefix_length, IP_NULL, IP_RTN_UNICAST); } } } } break; } #else IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(cmd); IPMIP_UNUSED_PARAMETER(rtifp); #endif } /* *=========================================================================== * ipmip6mn_route_tunnel *=========================================================================== * Description: Add/delete blackhole route "0.0.0.0/0 -> 127.0.0.1" * Parameters: * Returns: * */ IP_STATIC void ipmip6mn_route_transport_ipv6_using_ipvX(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { Ipmip_netlink_kern_handle_t handle; handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = rtifp->node->identifier; switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: ipmip6_netlink_route_mip_do(&ctx->ipmip6, proc, IP_RTM_NEWMIP, IP_WRMOB6_NEW_LINK_TX, IP_WRMOB6_NEW_TYPE_SILENT, rtifp->rtable, rtifp->iff6.iff.ifindex, &ip_in6addr_any, sizeof(ip_in6addr_any), 0, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp), IPMIP6MN_ROUTE_ENDPOINT_PORT_CHECK(rtifp), IP_NULL, &handle, IPMIP_LINK_SEND, IP_NULL, IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND); break; case IPMIP6MN_ROUTE_DO_DEL: /* Delete the tunneling route */ ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELROUTE, rtifp->rtable, rtifp->iff6.iff.ifindex, IP_NULL, 0, IP_NULL, IP_RTN_UNICAST); break; } } /* *=========================================================================== * ipmip6mn_route_tunnel *=========================================================================== * Description: Add/delete blackhole route "0.0.0.0/0 -> 127.0.0.1" * Parameters: * Returns: * */ IP_STATIC void ipmip6mn_route_transport_ipv4_using_ipvX(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, int cmd, Ipmip6mn_route_tunnel_t *rtifp) { #ifdef IPMIP_USE_INET Ipmip_netlink_kern_handle_t handle; handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = rtifp->node->identifier; switch (cmd) { case IPMIP6MN_ROUTE_DO_ADD: ipmip6_netlink_route_mip_do(&ctx->ipmip6, proc, IP_RTM_NEWMIP, IP_WRMOB6_NEW_LINK_TX, IP_WRMOB6_NEW_TYPE_SILENT, rtifp->rtable, rtifp->iff6.iff.ifindex, &ip_inaddr_any, sizeof(ip_inaddr_any), 0, IPMIP6MN_ROUTE_ENDPOINT(rtifp), IPMIP6MN_ROUTE_SIZE(rtifp), IPMIP6MN_ROUTE_ENDPOINT_PORT_CHECK(rtifp), IP_NULL, &handle, IPMIP_LINK_SEND, IP_NULL, IPNET_RTF_MBINDING|IPNET_RTF_TUNNELEND); break; case IPMIP6MN_ROUTE_DO_DEL: ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_DELROUTE, rtifp->rtable, rtifp->iff6.iff.ifindex, IP_NULL, 0, IP_NULL, IP_RTN_UNICAST); break; } #else IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(cmd); IPMIP_UNUSED_PARAMETER(rtifp); #endif } /* *=========================================================================== * ipmip6mn_route_tunnel *=========================================================================== * Description: Add/delete blackhole route "0.0.0.0/0 -> 127.0.0.1" * Parameters: * Returns: * */ IP_STATIC void ipmip6mn_route_statistics_get(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_route_tunnel_t *rtifp) { ipmip6mn_netlink_get_handle_stat(ctx, proc, rtifp->node); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmip6_port_tunnel_configure *=========================================================================== * Description: Configure end-points in a tunneling interface. * Parameters: ifp - The tunneling interface. * local - Local end-point. * remote - Remote end-point. * router - Route by. * Returns: IP_TRUE if successful * */ IP_GLOBAL Ip_bool ipmip6mn_route_remote_setup(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_node_t *node, struct Ip_in6_addr *remote, Ip_u32 inet) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)node->persistent.tunnel; /**/ if (inet) { #ifdef IPMIP_USE_INET IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s %s remote INET endpoint %s assigned", rtifp->node->name, rtifp->iff6.iff.ifname, ipmip_ntop_inet(proc, inet))); #endif rtifp->tun.remote_inet = inet; } /**/ IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s %s remote INET6 endpoint %s assigned", rtifp->node->name, rtifp->iff6.iff.ifname, ipmip_ntop_inet6(proc, remote, IP_NULL))); ipcom_memcpy(&rtifp->tun.remote_inet6, remote, sizeof(struct Ip_in6_addr)); return ipmip6mn_route_tunnel_configure(ctx, proc, node); } IP_GLOBAL void ipmip6mn_route_remote_transport_udp_encapsulation(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_node_t *node, Ip_bool enable) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)node->persistent.tunnel; IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s %s remote TRANSPORT UDP ENCAPSULATION %s", rtifp->node->name, rtifp->iff6.iff.ifname, enable? "enabled" : "disabled")); rtifp->tun.remote_transport_udp_encapsulate = enable; #if 0 return ipmip6mn_route_tunnel_configure(ctx, proc, node); #endif } IP_GLOBAL void ipmip6mn_route_remote_mh_transport_udp_encapsulation(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_node_t *node, Ip_bool enable) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)node->persistent.tunnel; IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s %s remote UDP ENCAPSULATION %s", rtifp->node->name, rtifp->iff6.iff.ifname, enable? "enabled" : "disabled")); rtifp->tun.remote_mh_udp_encapsulate = enable; rtifp->tun.remote_transport_udp_encapsulate = enable; #if 0 return ipmip6mn_route_tunnel_configure(ctx, proc, node); #endif } /* *=========================================================================== * ipmip6mn_route_tunnel_local_setup *=========================================================================== * Description: Configure end-points in a tunneling interface. * Parameters: ifp - The tunneling interface. * local - Local end-point. * remote - Remote end-point. * router - Route by. * Returns: IP_TRUE if successful * */ IP_GLOBAL Ip_bool ipmip6mn_route_tunnel_local_setup(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_node_t *node, Ip_u8 family, const void *local, const struct Ip_in6_addr *nexthop, Ip_u32 ifindex) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)node->persistent.tunnel; /**/ IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); if (rtifp->tun.family == IP_AF_INET6) { if (!IP_IN6_IS_ADDR_UNSPECIFIED(&rtifp->tun.local.in6) && !IP_IN6_ARE_ADDR_EQUAL(&rtifp->tun.local.in6, &rtifp->inet6)) { ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELADDR, rtifp->iff6.iff.ifindex, &rtifp->tun.local.in6, 128, 0, 0); } } #ifdef IPMIP_USE_INET else if (rtifp->tun.family == IP_AF_INET) { if (rtifp->tun.local.in.s_addr != 0 && rtifp->tun.local.in.s_addr != rtifp->inet) { ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_DELADDR, rtifp->iff6.iff.ifindex, &rtifp->tun.local.in.s_addr, 32, 0, 0); } } #endif if (family == IP_AF_INET6) { IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s %s local INET6 endpoint %s set", rtifp->node->name, rtifp->iff6.iff.ifname, ipmip_ntop_inet6(proc, (void *)local, IP_NULL))); ipcom_memcpy(&rtifp->tun.local, local, sizeof(struct Ip_in6_addr)); ipcom_memcpy(&rtifp->tun.nexthop, nexthop, sizeof(*nexthop)); if (!IP_IN6_IS_ADDR_UNSPECIFIED(&rtifp->tun.local.in6) && !IP_IN6_ARE_ADDR_EQUAL(&rtifp->tun.local.in6, &rtifp->inet6)) { ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_NEWADDR, rtifp->iff6.iff.ifindex, &rtifp->tun.local.in6, 128, 0, 0); } } #ifdef IPMIP_USE_INET else if (family == IP_AF_INET) { IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s %s local INET endpoint %s set", rtifp->node->name, rtifp->iff6.iff.ifname, ipmip_ntop_inet(proc, IP_GET_32ON8(local)))); ipcom_memcpy(&rtifp->tun.local, local, sizeof(struct Ip_in_addr)); if (rtifp->tun.local.in.s_addr != 0 && rtifp->tun.local.in.s_addr != rtifp->inet) { ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_NEWADDR, rtifp->iff6.iff.ifindex, &rtifp->tun.local.in.s_addr, 32, 0, 0); } } #endif rtifp->tun.family = family; rtifp->tun.ifindex = ifindex; return ipmip6mn_route_tunnel_configure(ctx, proc, node); } /* *=========================================================================== * ipmip6_port_tunnel_configure *=========================================================================== * Description: Configure end-points in a tunneling interface. * Parameters: ifp - The tunneling interface. * local - Local end-point. * remote - Remote end-point. * router - Route by. * Returns: IP_TRUE if successful * */ IP_GLOBAL Ip_bool ipmip6mn_route_tunnel_configure(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_node_t *node) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)node->persistent.tunnel; struct Ip_ip_tunnel_param tun; /* Change tunnel */ ipcom_memset(&tun, 0, sizeof(tun)); ipcom_strncpy(tun.ifr_name, rtifp->iff6.iff.ifname, sizeof(tun.ifr_name)); /* Set values */ if (rtifp->tun.family == IP_AF_INET6) { IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s %s configured with INET6 endpoints", rtifp->node->name, rtifp->iff6.iff.ifname)); tun.local_addr.sin6.sin6_family = IP_AF_INET6; ipcom_memcpy(&tun.local_addr.sin6.sin6_addr, &rtifp->tun.local.in6, sizeof(struct Ip_in6_addr)); IPCOM_SA_LEN_SET(&tun.local_addr.sin6, sizeof(struct Ip_sockaddr_in6)); tun.local_addr.sin6.sin6_port = ctx->ipmip6.pkt->s_udp_nat.sin6_port; tun.remote_addr.sin6.sin6_family = IP_AF_INET6; } #ifdef IPMIP_USE_INET else if (rtifp->tun.family == IP_AF_INET) { IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s %s configured with INET endpoints", rtifp->node->name, rtifp->iff6.iff.ifname)); tun.local_addr.sin.sin_family = IP_AF_INET; ipcom_memcpy(&tun.local_addr.sin.sin_addr, &rtifp->tun.local.in, sizeof(struct Ip_in_addr)); IPCOM_SA_LEN_SET(&tun.local_addr.sin, sizeof(struct Ip_sockaddr_in)) /* Prepare UDP NAT-T */; tun.local_addr.sin.sin_port = ctx->ipmip6.pkt->s_udp_nat.sin6_port; tun.remote_addr.sin.sin_family = IP_AF_INET; } #endif tun.ttl = 64; /* Try set the tunnel values */ if (ipmip_util_ioctl(&ctx->ipmip6.ipmip, proc, IP_SIOCCHGTUNNEL, &tun) < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s ipcom_socketioctl(%s, IP_SIOCCHGTUNNEL) failed: errno = %d)", rtifp->node->name, rtifp->iff6.iff.ifname, ipcom_errno)); return IP_FALSE; } /* OK */ return IP_TRUE; } /* *=========================================================================== * ipmip6mn_route_tunnel_create *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL Ipmip6_if_t * ipmip6mn_route_tunnel_create(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, Ipmip6mn_node_t *node) { Ipmip6mn_route_tunnel_t *ifp = IP_NULL; char gifname[IP_IFNAMSIZ]; struct Ip_ip_tunnel_param tun; int ret; #ifdef IPMIP_USE_INET Ip_u32 loopback = ip_htonl(IP_INADDR_LOOPBACK); #endif ipcom_snprintf(gifname, sizeof(gifname), "gif%s0", node->name); if (ipcom_if_nametoindex(gifname) != 0) return IP_NULL; ifp = (Ipmip6mn_route_tunnel_t *)ipmip6_if_alloc_tunnel(&ctx->ipmip6, proc, sizeof(*ifp), gifname, 0, IPMIP_TUNNELTYPE_IP6IP6, IP_FALSE, (Ipmip_if_cleanup_t)ipmip6mn_route_tunnel_cleanup); if (ifp == IP_NULL) return IP_NULL; /**/ ipcom_memcpy(&ifp->inet6, &node->config->inet6.prefix, sizeof(struct Ip_in6_addr)); /**/ IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s %s created", node->name, gifname)); /* Assign the home address */ if (ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_NEWADDR, ifp->iff6.iff.ifindex, &ifp->inet6, 128, IP_IFA_F_HOMEADDRESS, 0) < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s ipcom_socketioctl(IP_SIOCADDROUTETAB) failed, errno = %d", node->name, ipcom_errno)); goto fail; } /* Create the MIPv6 policy routing table */ ifp->rtable = ipmip_util_route_table_alloc(&ctx->ipmip6.ipmip, proc); ifp->btable = ipmip_util_route_table_alloc(&ctx->ipmip6.ipmip, proc); ifp->htable = ipmip_util_route_table_alloc(&ctx->ipmip6.ipmip, proc); ifp->nemo_table = ipmip_util_route_table_alloc(&ctx->ipmip6.ipmip, proc); ifp->nemo_stats = ipmip_util_route_table_alloc(&ctx->ipmip6.ipmip, proc); IPMIP6_EVENT_IF(DEBUG2, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s TABLES: %d %d %d", node->name, ifp->rtable, ifp->btable, ifp->htable)); ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_NEWROUTE, ifp->btable, 0, IP_NULL, 0, &ip_in6addr_loopback, IP_RTN_BLACKHOLE); #ifdef IPMIP_USE_INET ipmip_netlink_inX_route(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_NEWROUTE, ifp->btable, 0, IP_NULL, 0, &loopback, IP_RTN_BLACKHOLE); #endif if ((ret = ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_NEWRULE, 0, &ifp->inet6, 128, IP_NULL, 0, ifp->rtable, 0)) < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s POLICY: %d", node->name, -ret)); } /* Change tunnel */ ipcom_memset(&tun, 0, sizeof(tun)); ipcom_strncpy(tun.ifr_name, ifp->iff6.iff.ifname, sizeof(tun.ifr_name)); /* Set values */ tun.local_addr.sin6.sin6_family = IP_AF_INET6; tun.local_addr.sin6.sin6_addr = ip_in6addr_any; IPCOM_SA_LEN_SET(&tun.local_addr.sin6, sizeof(struct Ip_sockaddr_in6)); tun.remote_addr.sin6.sin6_family = IP_AF_INET6; tun.remote_addr.sin6.sin6_addr = ip_in6addr_any; IPCOM_SA_LEN_SET(&tun.remote_addr.sin6, sizeof(struct Ip_sockaddr_in6)); tun.remote_addr.sin6.sin6_scope_id = 3; tun.ttl = 64; /* Try set the tunnel values */ if (ipmip_util_ioctl(&ctx->ipmip6.ipmip, proc, IP_SIOCCHGTUNNEL, &tun) < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s ipcom_socketioctl(%s, IP_SIOCCHGTUNNEL) failed: errno = %d", node->name, gifname, ipcom_errno)); goto fail; } ifp->node = node; /**/ return &ifp->iff6; fail: ipmip_if_free(&ctx->ipmip6.ipmip, proc, &ifp->iff6.iff); return IP_NULL; } /* *=========================================================================== * ipmip6mn_route_change *=========================================================================== * Description: Upgrade the route to a more explicit route type. * Parameters: data - The context * proc - The process * rtn - Route information * type - Type of route. * Returns: * */ IP_GLOBAL int ipmip6mn_route_change(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, struct Ipmip6_if *ifp, int type) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)ifp; int otype = rtifp->route_type; int ostate = rtifp->route_state; int state = 0; int dstate = 0; int i; int rs_home_agent = IPMIP6MN_ROUTE_STATE_HOME_AGENT|IPMIP6MN_ROUTE_STATE_ADDRESS; int rs_home_pending= IPMIP6MN_ROUTE_STATE_HOME_AGENT_HOME; int rs_blackhole = IPMIP6MN_ROUTE_STATE_BLACKHOLE; int rs_tunnel = IPMIP6MN_ROUTE_STATE_TUNNEL|IPMIP6MN_ROUTE_STATE_ADDRESS; int rs_address = IPMIP6MN_ROUTE_STATE_TUNNEL; int rs_nemo = IPMIP6MN_ROUTE_STATE_NEMO; #ifdef IPMIP_USE_INET if (rtifp->inet) { /* We have an inet state; do update with dsmipv6 */ rs_home_agent |= IPMIP6MN_ROUTE_STATE_ADDRESS_INET; rs_blackhole |= IPMIP6MN_ROUTE_STATE_BLACKHOLE_INET; rs_tunnel |= IPMIP6MN_ROUTE_STATE_TUNNEL_INET|IPMIP6MN_ROUTE_STATE_ADDRESS_INET; rs_nemo |= IPMIP6MN_ROUTE_STATE_NEMO_INET; } #endif if (rtifp->tun.family != IP_AF_INET6 || rtifp->tun.remote_transport_udp_encapsulate) { /* Switch home agent route state */ rs_home_agent = IPMIP6MN_ROUTE_STATE_HOME_AGENT_UDP; } switch (type) { case IPMIP6MN_ROUTE_TYPE_NONE: break; case IPMIP6MN_ROUTE_TYPE_BLACKHOLE: state = rs_blackhole; break; case IPMIP6MN_ROUTE_TYPE_HOME_AGENT: state = rs_blackhole|rs_home_agent; break; case IPMIP6MN_ROUTE_TYPE_TUNNEL: state = rs_tunnel|rs_home_agent|rs_nemo|rs_address; break; case IPMIP6MN_ROUTE_TYPE_HOME_PENDING: state = rs_home_pending|rs_blackhole; break; case IPMIP6MN_ROUTE_TYPE_HOME: break; } if (state == ostate) { if (type != otype) { IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s Routing type changed %s(%x) -> %s(%x)", rtifp->node->name, route_types[otype], ostate, route_types[type], state)); rtifp->route_type = type; } return otype; } ipmip6mn_route_statistics_get(ctx, proc, rtifp); dstate = state ^ rtifp->route_state; /* Add any new states */ while ((i = ipcom_ffs((Ip_u32)dstate)) != 0) { int bitmask = (1 << (i - 1)); dstate &= ~bitmask; if ((state & bitmask) != 0) { /* The bit's set in the new route state */ (*ipmip6mn_route_funcs[i - 1])(ctx, proc, IPMIP6MN_ROUTE_DO_ADD, rtifp); } } dstate = state ^ rtifp->route_state; /* Remove any old states no longer set */ while ((i = ipcom_ffs((Ip_u32)dstate)) != 0) { int bitmask = (1 << (i - 1)); dstate &= ~bitmask; if ((rtifp->route_state & bitmask) != 0) { /* The bit's set in the current route state */ (*ipmip6mn_route_funcs[i - 1])(ctx, proc, IPMIP6MN_ROUTE_DO_DEL, rtifp); } } IPMIP6_EVENT_IF(INFO, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s Routing state changed %s(%x) -> %s(%x)", rtifp->node->name, route_types[otype], ostate, route_types[type], state)); rtifp->route_type = type; rtifp->route_state = state; return otype; } /* *=========================================================================== * ipmip6mn_route_statistics *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL void ipmip6mn_route_statistics(Ipmip6mn_context_t *ctx, Ipmip_proc_t *proc, struct Ipmip6_if *ifp) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)ifp; ipmip6mn_route_statistics_get(ctx, proc, rtifp); } IP_GLOBAL void ipmip6mn_route_add_outbound(struct Ipmip6mn_context *ctx, struct Ipmip6_if *ifp, Ip_u64 octets, Ip_u64 pkts) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)ifp; IPMIP_UNUSED_PARAMETER(ctx); IP_U64_ADD(rtifp->mip6NodeTrafficEntry.mip6HCNodeOutOctets, octets); rtifp->mip6NodeTrafficEntry.mip6NodeOutOctets = IP_U64_GETLO(rtifp->mip6NodeTrafficEntry.mip6HCNodeOutOctets); IP_U64_ADD(rtifp->mip6NodeTrafficEntry.mip6HCNodeOutPkts, pkts); rtifp->mip6NodeTrafficEntry.mip6NodeOutPkts = IP_U64_GETLO(rtifp->mip6NodeTrafficEntry.mip6HCNodeOutPkts); } IP_GLOBAL void ipmip6mn_route_add_inbound(struct Ipmip6mn_context *ctx, struct Ipmip6_if *ifp, Ip_u64 octets, Ip_u64 pkts) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)ifp; IPMIP_UNUSED_PARAMETER(ctx); IP_U64_ADD(rtifp->mip6NodeTrafficEntry.mip6HCNodeInOctets, octets); rtifp->mip6NodeTrafficEntry.mip6NodeInOctets = IP_U64_GETLO(rtifp->mip6NodeTrafficEntry.mip6HCNodeInOctets); IP_U64_ADD(rtifp->mip6NodeTrafficEntry.mip6HCNodeInPkts, pkts); rtifp->mip6NodeTrafficEntry.mip6NodeInPkts = IP_U64_GETLO(rtifp->mip6NodeTrafficEntry.mip6HCNodeInPkts); } IP_GLOBAL void ipmip6mn_route_attr_put(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, struct Ipmip6_if *ifp, Ipmip_buffer_t *msg) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)ifp; IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); /* Put tunnel name */ ipmip_attr_put_str(msg, IPMIP6MN_CLI_NETWORK_ATTR_TUNNEL_IFNAME, ifp->iff.ifname); /* Put the registration counter entry */ ipmip_attr_put(msg, IPMIP6MN_CLI_NETWORK_ATTR_MIB_mip6NodeTrafficEntry, sizeof(rtifp->mip6NodeTrafficEntry), &rtifp->mip6NodeTrafficEntry); } IP_GLOBAL void ipmip6mn_route_binding_attr_put(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, struct Ipmip6_if *ifp, struct Ipmip6_bc *bc, Ipmip_buffer_t *msg) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)ifp; Ip_u32 encap = IPMIP6MN_CLI_NETWORK_ATTR_ENCAP_IP6IP6; const char *ifname; IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); IPMIP_UNUSED_PARAMETER(bc); #ifdef IPMIP_USE_INET if (rtifp->tun.family == IP_AF_INET) { if (rtifp->tun.remote_transport_udp_encapsulate) encap = IPMIP6MN_CLI_NETWORK_ATTR_ENCAP_IPIP_UDP; else encap = IPMIP6MN_CLI_NETWORK_ATTR_ENCAP_IPIP; } else #endif { if (rtifp->tun.remote_transport_udp_encapsulate) encap = IPMIP6MN_CLI_NETWORK_ATTR_ENCAP_IP6IP6_UDP; else encap = IPMIP6MN_CLI_NETWORK_ATTR_ENCAP_IP6IP6; } ifname = ipcom_if_indextoname(rtifp->tun.ifindex, proc->ntop.ntop_name); if (ifname) ipmip_attr_put_str(msg, IPMIP6MN_CLI_NETWORK_ATTR_BINDING_ITEM_IFNAME, ifname); ipmip_attr_put_u32(msg, IPMIP6MN_CLI_NETWORK_ATTR_BINDING_ITEM_ENCAP, encap); } #ifdef IPMIP_USE_INET IP_GLOBAL void ipmip6mn_route_dsmipv6_set(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, struct Ipmip6_if *ifp, Ip_u32 addr, Ip_u8 plen) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)ifp; if (rtifp->inet != 0 && (addr == 0 || rtifp->inet != addr)) { ipmip6mn_route_policy(ctx, proc, IP_AF_INET, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_DELRULE, 0, &rtifp->inet, 32, IP_NULL, 0, rtifp->rtable, 0); ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_DELADDR, rtifp->iff6.iff.ifindex, &rtifp->inet, 32, IP_IFA_F_HOMEADDRESS, 0); } if (addr != 0 && addr != rtifp->inet) { ipmip6mn_route_policy(ctx, proc, IP_AF_INET, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_NEWRULE, 0, &addr, 32, IP_NULL, 0, rtifp->rtable, 0); ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET, IP_RTM_NEWADDR, rtifp->iff6.iff.ifindex, &addr, 32, IP_IFA_F_HOMEADDRESS, IP_IFA_F_X_PREFERRED); } rtifp->inet = addr; rtifp->inet_plen = plen; } #endif IP_GLOBAL void ipmip6mn_route_tunnel_reassign(struct Ipmip6mn_context *ctx, struct Ipmip_proc *proc, struct Ipmip6mn_node *node, struct Ip_in6_addr *hoa) { Ipmip6mn_route_tunnel_t *rtifp = (Ipmip6mn_route_tunnel_t *)node->persistent.tunnel; int rs = ipmip6mn_route_change(ctx, proc, &rtifp->iff6, IPMIP6MN_ROUTE_TYPE_NONE); ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_DELRULE, 0, &rtifp->inet6, 128, IP_NULL, 0, rtifp->rtable, 0); /* Assign the home address */ if (ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_DELADDR, rtifp->iff6.iff.ifindex, &rtifp->inet6, 128, IP_IFA_F_HOMEADDRESS, 0) < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s unable to delete Home Address from %s, errno = %d", rtifp->node->name, rtifp->iff6.iff.ifname, ipcom_errno)); } ipcom_memcpy(&rtifp->inet6, hoa, sizeof(struct Ip_in6_addr)); /* Assign the home address */ if (ipmip_netlink_inX_addr(&ctx->ipmip6.ipmip, proc, IP_AF_INET6, IP_RTM_NEWADDR, rtifp->iff6.iff.ifindex, &rtifp->inet6, 128, IP_IFA_F_HOMEADDRESS, 0) < 0) { IPMIP6_EVENT_IF(ERR, proc, ipmip_log_event_add(&ctx->ipmip6.ipmip, proc, "%s unable to add Home Address to %s, errno = %d", rtifp->node->name, rtifp->iff6.iff.ifname, ipcom_errno)); } ipmip6mn_route_policy(ctx, proc, IP_AF_INET6, IPMIP6MN_ROUTE_PRIORITY, IP_RTM_NEWRULE, 0, &rtifp->inet6, 128, IP_NULL, 0, rtifp->rtable, 0); ipmip6mn_route_change(ctx, proc, &rtifp->iff6, rs); } IP_GLOBAL int ipmip6mn_netlink_new_handle(Ipmip6mn_context_t *ctx, struct Ipmip_proc *proc, struct Ipmip6mn_node *node) { /**/ return ipmip6_netlink_new_handle(&ctx->ipmip6, proc, IPCOM_IPD_ID_IPMIP6MN, node->identifier); } IP_GLOBAL int ipmip6mn_netlink_del_handle(Ipmip6mn_context_t *ctx, struct Ipmip_proc *proc, struct Ipmip6mn_node *node) { /**/ return ipmip6_netlink_del_handle(&ctx->ipmip6, proc, IPCOM_IPD_ID_IPMIP6MN, node->identifier); } IP_GLOBAL Ip_bool ipmip6mn_netlink_get_handle_stat(Ipmip6mn_context_t *ctx, struct Ipmip_proc *proc, struct Ipmip6mn_node *node) { Ipmip6_netlink_kern_statistics_t link_recv, link_send; Ipmip_netlink_kern_handle_t handle; /* Identity */ handle.mip_facility = IPCOM_IPD_ID_IPMIP6MN; handle.mip_ident = node->identifier; /* 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); ipmip6mn_route_add_outbound(ctx, node->persistent.tunnel, 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); ipmip6mn_route_add_inbound(ctx, node->persistent.tunnel, link_recv.mip_s_octets, link_recv.mip_s_pkts); return IP_TRUE; } return IP_FALSE; } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */