/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip_netlink_kern.c,v $ $Revision: 1.7.10.1 $ * $Source: /home/interpeak/CVSRoot/ipmip/src/ipmip_netlink_kern.c,v $ * $Author: jsheng $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "ipnet_config.h" #if defined(IPNET) /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include "ipnet_h.h" #include "ipnet.h" #ifdef IPTCP #include "iptcp.h" #endif #include #ifdef IPMIP6 #include #endif #ifdef IPMIP4 #include #endif /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IPMIP_PKT_HAS_INFO(pkt) (pkt->next_extra_data != 0) /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipmip_netlink_kern { Ipcom_hash *handles[IPCOM_VR_MAX]; } Ipmip_netlink_kern_t; /**/ IP_STATIC Ipmip_netlink_kern_t *ipmip_netlink_kern = IP_NULL; IP_STATIC unsigned ipmip_netlink_kern_handle_obj_hash(Ipmip_netlink_kern_handle_t *hdr) { return ipcom_hash_update(hdr, sizeof(*hdr), 0); } IP_STATIC Ip_bool ipmip_netlink_kern_handle_cmp_hash(Ipmip_netlink_kern_handle_t *obj1, Ipmip_netlink_kern_handle_t *obj2) { /**/ return obj1->mip_facility == obj2->mip_facility && obj1->mip_ident == obj2->mip_ident; } IP_STATIC Ip_bool ipmip_netlink_kern_rt_flow_cmp(struct Ipnet_route_entry_struct *rtentry, struct Ipnet_dst_cache_struct *dst) { struct Ipnet_route_func_info *rtinfo = rtentry->rt_func_info; Ipmip_netlink_route_flow_info_t *rtflow = (Ipmip_netlink_route_flow_info_t *)(rtinfo + 1); if (IP_BIT_ISSET(rtflow->type, IPMIP_NETLINK_KERN_INGRESS_IFINDEX)) { if (dst->flow_spec.ingress_ifindex == 0) { IPCOM_LOG0(DEBUG2, "FLOW compare missed on INGRESS"); return IP_FALSE; } else if (rtflow->ifindex != 0 && rtflow->ifindex != dst->flow_spec.ingress_ifindex) { IPCOM_LOG0(DEBUG2, "FLOW compare missed on INGRESS IFINDEX"); return IP_FALSE; } } if (IP_BIT_ISSET(rtflow->type, IPMIP_NETLINK_KERN_EGRESS_IFINDEX)) { if (dst->flow_spec.ingress_ifindex != 0) { IPCOM_LOG0(DEBUG2, "FLOW compare missed on EGRESS"); return IP_FALSE; } else if (rtflow->ifindex != 0 && rtflow->ifindex != dst->flow_spec.egress_ifindex) { IPCOM_LOG0(DEBUG2, "FLOW compare missed on EGRESS IFINDEX"); return IP_FALSE; } } if ((rtflow->flow.key.u64[0] != (dst->flow_spec.mip.key.u64[0] & rtflow->flow.mask.u64[0])) || (rtflow->flow.key.u64[1] != (dst->flow_spec.mip.key.u64[1] & rtflow->flow.mask.u64[1])) || (rtflow->flow.key.u64[2] != (dst->flow_spec.mip.key.u64[2] & rtflow->flow.mask.u64[2]))) { IPCOM_LOG0(DEBUG2, "FLOW compare missed on FLOW"); return IP_FALSE; } /* Clear the flow spec values from this dst cache that arent used, just to speed up the cmps a bit */ dst->flow_spec.mip.key.u64[0] = dst->flow_spec.mip.key.u64[0] & rtflow->flow.mask.u64[0]; dst->flow_spec.mip.key.u64[1] = dst->flow_spec.mip.key.u64[1] & rtflow->flow.mask.u64[1]; dst->flow_spec.mip.key.u64[2] = dst->flow_spec.mip.key.u64[2] & rtflow->flow.mask.u64[2]; /* Store the mask */ ipcom_memcpy(&dst->flow_spec.mip.mask, &rtflow->flow.mask, sizeof(rtflow->flow.mask)); /* Setup the MIP DST cache init routine based on the Route's callbacks */ if (rtflow->flow_handle != IP_NULL) { dst->mip.flow_handle = rtflow->flow_handle; dst->mip.flow_aux = ipcom_malloc(rtinfo->rt_info_size); if(IP_NULL == dst->mip.flow_aux) return IP_FALSE; ipcom_memcpy(dst->mip.flow_aux, rtinfo, rtinfo->rt_info_size); } /**/ return IP_TRUE; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ IP_GLOBAL Ip_bool ipmip_netlink_kern_rt_flow_set(struct Ipnet_route_func_info *rtinfo, Ipmip_netlink_kern_compare_t *srccmp, Ipnet_dst_cache_mip_handle flow_handle) { Ipmip_netlink_route_flow_info_t *rtflow = (Ipmip_netlink_route_flow_info_t *)(rtinfo + 1); /* Set compare function */ rtinfo->rt_flow_cmp = (Ipnet_route_flow_spec_cmp_t)ipmip_netlink_kern_rt_flow_cmp; /* Set init function */ rtflow->flow_handle = flow_handle; if (IP_LIKELY(srccmp != IP_NULL)) { if (IP_BIT_ISSET(srccmp->srcmac_type, IPMIP_NETLINK_KERN_PROTO)) { rtflow->flow.mask.u8[1] = 0xFF; rtflow->flow.key.u8[1] = srccmp->srcmac.proto; } /* Create the flow MASK */ if (IP_BIT_ISSET(srccmp->srcmac_type, IPMIP_NETLINK_KERN_TUNNEL|IPMIP_NETLINK_KERN_SRCMAC)) { /* First field is ENCAP size */ rtflow->flow.mask.u8[0] = 0xFF; rtflow->flow.key.u8[0] = srccmp->srcmac.srcmac_len; ipcom_memcpy(&rtflow->flow.key.u32[1], &srccmp->srcmac.hdr.opaque[0], srccmp->srcmac.srcmac_len); ipcom_memset(&rtflow->flow.mask.u32[1], 0xFF, srccmp->srcmac.srcmac_len); } if (IP_BIT_ISSET(srccmp->srcmac_type, IPMIP_NETLINK_KERN_INGRESS_IFINDEX|IPMIP_NETLINK_KERN_EGRESS_IFINDEX)) rtflow->ifindex = srccmp->srcmac.ifindex; if (IP_BIT_ISSET(srccmp->srcmac_type, IPMIP_NETLINK_KERN_GREKEY)) { rtflow->flow.key.u32[5] = srccmp->srcmac.gre_key; rtflow->flow.mask.u32[5] = 0xFFFFFFFF; } rtflow->type = srccmp->srcmac_type; } return IP_TRUE; } IP_GLOBAL Ipmip_netlink_kern_handle_t * ipmip_netlink_kern_handle_get(Ip_u32 vr, Ipmip_netlink_kern_handle_t *handle) { /**/ return (Ipmip_netlink_kern_handle_t *)ipcom_hash_get(ipmip_netlink_kern->handles[vr], handle); } IP_GLOBAL void ipmip_netlink_kern_handle_add(Ip_u32 vr, Ipmip_netlink_kern_handle_t *handle) { ipcom_hash_add(ipmip_netlink_kern->handles[vr], handle); } IP_GLOBAL Ipmip_netlink_kern_handle_t * ipmip_netlink_kern_handle_del(Ip_u32 vr, Ipmip_netlink_kern_handle_t *handle) { Ipmip_netlink_kern_handle_t *rhandle = ipmip_netlink_kern_handle_get(vr, handle); if (rhandle) ipcom_hash_remove(ipmip_netlink_kern->handles[vr], rhandle); /**/ return rhandle; } IP_GLOBAL void ipmip_netlink_kern_handle_free(Ip_u32 vr, Ipmip_netlink_kern_handle_t *handle) { handle = ipmip_netlink_kern_handle_del(vr, handle); if (handle) ipcom_free(handle); } IP_GLOBAL void ipmip_netlink_kern_if_include(Ipnet_netif *netif) { IP_BIT_CLR(netif->flags2, IPNET_IFF2_NO_GLOBAL_SRC); } IP_GLOBAL void ipmip_netlink_kern_if_exclude(Ipnet_netif *netif) { IP_BIT_SET(netif->flags2, IPNET_IFF2_NO_GLOBAL_SRC); } IP_GLOBAL void ipmip_netlink_kern_hoa_activate(Ipnet_netif *netif, struct Ip_rtattr *rta) { Ipnet_socket *sock = IP_NULL; Ipnet_socket *next_sock; #ifdef IPCOM_USE_INET6 if (IP_RTA_PAYLOAD(rta) == sizeof(struct Ip_in6_addr)) { Ipnet_ip6_addr_entry *entry = ipnet_ip6_get_addr_entry(IP_RTA_DATA(rta), netif->vr_index, netif); /* Loop through all addresses */ if (entry != IP_NULL && IP_BIT_ISTRUE(entry->flags, IPNET_IP6_ADDR_FLAG_HOMEADDRESS)) { /* Kickstart list */ #ifdef IPTCP sock = entry->socket_list; #endif } } #endif #ifdef IPCOM_USE_INET if (IP_RTA_PAYLOAD(rta) == sizeof(struct Ip_in_addr)) { Ipnet_ip4_addr_entry *entry = ipnet_ip4_get_addr_entry(IP_GET_32ON8(IP_RTA_DATA(rta)), netif->vr_index, netif); /* Loop through all addresses */ if (entry != IP_NULL && IP_BIT_ISTRUE(entry->flags, IPNET_IP4_ADDR_FLAG_HOMEADDRESS)) { #ifdef IPTCP sock = entry->socket_list; #endif IP_BIT_SET(entry->flags, IPNET_IP4_ADDR_FLAG_PREFERRED); } } #endif #ifdef IPTCP while (sock != IP_NULL) { /* Locate next socket with the same address */ next_sock = sock->addr_next; /* Do we have a notify CB */ if (sock->notify_cb != IP_NULL) { /* Kickstart it */ (*sock->notify_cb) (sock, IPTCP_SOCKET_EVENT_KICKSTART); } /* Do next socket */ sock = next_sock; } #endif } IP_GLOBAL void ipmip_netlink_kern_hoa_deactivate(Ipnet_netif *netif, struct Ip_rtattr *rta) { #ifdef IPCOM_USE_INET6 if (IP_RTA_PAYLOAD(rta) == sizeof(struct Ip_in6_addr)) { Ipnet_ip6_addr_entry *entry = ipnet_ip6_get_addr_entry(IP_RTA_DATA(rta), netif->vr_index, netif); /* Loop through all addresses */ if (entry != IP_NULL && IP_BIT_ISTRUE(entry->flags, IPNET_IP6_ADDR_FLAG_HOMEADDRESS)) { /* Kickstart list */ } } #endif #ifdef IPCOM_USE_INET if (IP_RTA_PAYLOAD(rta) == sizeof(struct Ip_in_addr)) { Ipnet_ip4_addr_entry *entry = ipnet_ip4_get_addr_entry(IP_GET_32ON8(IP_RTA_DATA(rta)), netif->vr_index, netif); /* Loop through all addresses */ if (entry != IP_NULL && IP_BIT_ISTRUE(entry->flags, IPNET_IP4_ADDR_FLAG_HOMEADDRESS)) { IP_BIT_CLR(entry->flags, IPNET_IP4_ADDR_FLAG_PREFERRED); } } #endif } IP_GLOBAL void ipmip_rtnetlink_init(void) { int i; /* Create the handles */ ipmip_netlink_kern = ipcom_calloc(1, sizeof(*ipmip_netlink_kern)); for (i = 0; i < IPCOM_VR_MAX; i++) { ipmip_netlink_kern->handles[i] = ipcom_hash_new((Ipcom_hash_obj_func) ipmip_netlink_kern_handle_obj_hash, (Ipcom_hash_key_func) ipmip_netlink_kern_handle_obj_hash, (Ipcom_hash_cmp_func) ipmip_netlink_kern_handle_cmp_hash); } #ifdef IPMIP6 ipmip6_rtnetlink_init(); #endif #ifdef IPMIP4 ipmip4_rtnetlink_init(); #endif } #else int ipmip_netlink_kern_empty_file = 0; #endif /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */