/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_rtnetlink_route.c,v $ $Revision: 1.11.10.2 $ * $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_rtnetlink_route.c,v $ * $Author: svc-cmnet $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation Jonas Rendel ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** * Contains netlink handlers for managing Ipv4 and Ipv6 routes as well as * MPLS shortcut routes. */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPNET_USE_NETLINK #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include "ipnet_h.h" #include "ipnet_ctrl.h" #include "ipnet_route.h" #include "ipnet_netlink_h.h" #include "ipnet_rtnetlink_h.h" #include "ipcom_sock.h" #include "ipnet_loopback.h" #ifdef IP_PORT_LKM #include "ipcom_lkm.h" /* Needed for Linux PPP interface config */ #endif /* IP_PORT_LKM */ #include "ipnet_eth.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #define IP_IN4_IS_ADDR_MULTICAST(x) (((x) & ip_htonl(0xf0000000)) == ip_ntohl (0xe0000000)) /* **************************************************************************** * 5 TYPES **************************************************************************** */ typedef struct Ipnet_rtnetlink_route_family { struct { Ip_ptrdiff_t *vr; Ip_ptrdiff_t *table; Ip_ptrdiff_t *rt; Ip_ptrdiff_t *done; Ip_ptrdiff_t aborted; Ip_ptrdiff_t cont; } state; /* Requested */ struct Ip_nlmsghdr *nlmsg; int table; /* Caller specified table */ Ip_u8 family; /* Buffering */ Ipnet_netlink_mem_t *mem; } Ipnet_rtnetlink_route_family_t; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_rtnetlink_route_foreach_vr *=========================================================================== * Description: Hash table foreach callback. Called once for each virtual * router that exists in the system. * Parameters: rtab - route table * param - callback parameters. * Returns: - * */ IP_STATIC void ipnet_rtnetlink_route_foreach_vr_family(Ipcom_route *rtab, Ipnet_rtnetlink_route_family_t *param) { int new_offs = 0; Ip_ptrdiff_t table = IPNET_ROUTE_GET_TABLE(rtab); Ip_u16 vr = IPNET_ROUTE_GET_VR(rtab); Ipnet_route_entry *rt = IP_NULL; /* This traversal is already aborted */ if (param->state.aborted) return; /* Only handle rtabs of selected address family */ if (IPNET_ROUTE_GET_FAMILY(rtab) != param->family) return; /* Check if specific VR shall be dumped */ if (IP_BIT_ISFALSE(param->nlmsg->nlmsg_flags, IP_NLM_F_VR_UNSPEC) && (param->mem->vr != IPCOM_VR_ANY) && (param->mem->vr != vr)) return; /* * If this is a trailer message buffer, make sure it * starts dumping where the last message ended */ if (param->state.cont) { Ipnet_route_entry *rtt = (Ipnet_route_entry*)(*param->state.rt); /* Verify current state */ if (*param->state.vr != vr || *param->state.table != table) return; if (rtt != IP_NULL) { rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab), vr, (Ip_u32) table); while (rt != IP_NULL) { if (rt == rtt) break; rt = ipnet_route_next_entry(rt); } } } /* Reset the continue variable; we're on the move again */ param->state.cont = 0; /* Get first unless we've found one to continue from */ if (rt == IP_NULL) rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab), vr, (Ip_u32) table); /* */ while (rt) { /* Do not dump the 255.255.255.255, 224.0.0.0/4 or IPv6 multicast routes. */ /* Do not dump routes that are part of multipath routes either */ if (IP_BIT_ISFALSE(rt->hdr.flags, IPNET_RTF_X_MCAST_RO | IPNET_RTF_X_BCAST_RO | IPNET_RTF_X_HIDDEN) && (rt->prev == IP_NULL)) { #ifdef IPCOM_USE_INET if (param->family == IP_AF_INET) { new_offs = ipnet_rtnetlink_ip4_route_fill_info (param->mem, rt, param->nlmsg->nlmsg_seq, IP_RTM_NEWROUTE, IP_NLM_F_MULTI); } else #endif #ifdef IPCOM_USE_INET6 if (param->family == IP_AF_INET6) { new_offs = ipnet_rtnetlink_ip6_route_fill_info (param->mem, rt, param->nlmsg->nlmsg_seq, IP_RTM_NEWROUTE, IP_NLM_F_MULTI); } else #endif { IP_PANIC(); } if (new_offs < 0) goto aborted; } rt = ipnet_route_next_entry(rt); /* */ if (rt && new_offs) goto aborted; } return; aborted: param->state.aborted = 1; *param->state.rt = (Ip_ptrdiff_t)rt; *param->state.table = (Ip_ptrdiff_t)table; *param->state.vr = (Ip_ptrdiff_t)vr; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_rtnetlink_route_newroute_family *=========================================================================== * Description: Add a new rotue via NETLINK. * Parameters: data - Message payload * len - Length of message. * nlh - NETLINK message header * arg - Reference to route attributes. * * Returns: 0 - Success * <0 - Failure * */ IP_GLOBAL int ipnet_rtnetlink_route_newroute_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlh, struct Ip_rtattr **rta, int family) { Ipnet_netif *netif = IP_NULL; Ipnet_ppp_peer *p = IP_NULL; int ret = -1; Ip_u16 vr; Ip_u32 table; Ip_bool is_multipath_route = IP_FALSE; Ip_ssize_t mpa_size = 0; struct Ip_rtnexthop *nh = IP_NULL; struct Ipnet_rt_metrics metrics; struct Ip_sockaddr *gw = IP_NULL; void *mask = IP_NULL; struct Ip_sockaddr_dl gw_dl; struct Ipnet_route_add_param param; struct Ip_rtmsg *rtm = IP_NLMSG_DATA(nlh); union Ip_sockaddr_union ugw; Ipnet_rtnetlink_key_t ukey; #ifdef IPMPLS struct Ip_sockaddr_mpls gw_mpls; #endif /* IPMPLS */ #ifdef IPNET_USE_ROUTE_COOKIES Ipnet_rt_cookie cookie; #endif /* IPNET_USE_ROUTE_COOKIES */ table = (Ip_u32) IPCOM_ROUTE_TABLE_GET(rtm->rtm_table); /* Prepare route parameters */ ipcom_memset(¶m, 0, sizeof(param)); ipcom_memset(&metrics,0,sizeof(metrics)); param.flags = IPNET_RTF_STATIC | IPNET_RTF_UP | IPNET_RTF_DONE; #ifdef IPNET_USE_ROUTE_TABLE_NAMES if (rta[IP_RTA_TABLE_NAME -1]) { if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_RTA_TABLE_NAME - 1]), &vr, &table) < 0) return -IP_ERRNO_ESRCH; } else #endif { if (mem->vr == IPCOM_VR_ANY) return -IP_ERRNO_EINVAL; vr = ipnet_rtnetlink_vr(rta[IP_RTA_VR - 1], mem->vr); if (rta[IP_RTA_TABLE - 1]) table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_TABLE - 1])); } if (rta[IP_RTA_OIF -1]) { Ip_u32 ifindex = 0; if (rta[IP_RTA_OIF-1]->rta_len != IP_RTA_LENGTH(sizeof(int))) return -IP_ERRNO_EINVAL; ifindex = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_OIF-1])); netif = ipnet_if_indextonetif(vr, ifindex); if (netif) p = netif->private_data; } if (rta[IP_RTA_MULTIPATH -1]) { is_multipath_route = IP_TRUE; nh = IP_RTA_DATA(rta[IP_RTA_MULTIPATH-1]); mpa_size = (Ip_ssize_t) IP_RTA_PAYLOAD(rta[IP_RTA_MULTIPATH-1]); if ((nh == IP_NULL) || (mpa_size == 0)) return -IP_ERRNO_EINVAL; } if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, netif? netif->ipcom.ifindex : 0, &mask, rtm->rtm_dst_len, rta[IP_RTA_DST-1])) < 0) return ret; if ((ret = ipnet_rtnetlink_route_gw_setup(family, netif? netif->ipcom.ifindex : 0, &ugw, &gw, rta[IP_RTA_GATEWAY-1])) < 0) return ret; #ifdef IPCOM_USE_INET if (family == IP_AF_INET) { if (gw != IP_NULL) { /* Check if it is a pure gateway or not */ if (p == IP_NULL || p->peer4.s_addr != ugw.sin.sin_addr.s_addr) { /* Support for NBMA tunnel routes */ if (netif != IP_NULL && IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_POINTOPOINT)) param.flags |= IPNET_RTF_TUNNELEND; else param.flags |= IPNET_RTF_GATEWAY; } } } else #endif #ifdef IPCOM_USE_INET6 if (family == IP_AF_INET6) { if (gw != IP_NULL) { /* Check if it is a pure gateway or not */ if (p == IP_NULL || !IP_IN6_ARE_ADDR_EQUAL(&ugw.sin6.sin6_addr, &p->peer6)) { if (netif != IP_NULL && IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_POINTOPOINT)) param.flags |= IPNET_RTF_TUNNELEND; else param.flags |= IPNET_RTF_GATEWAY; } } } else #endif { return -IP_ERRNO_EAFNOSUPPORT; } if (!mask) param.flags |= IPNET_RTF_HOST; if (rtm->rtm_type == IP_RTN_PROXY) { /* This is a proxy arp network route */ IP_BIT_CLR(param.flags, IPNET_RTF_CLONING); IP_BIT_SET(param.flags, IPNET_RTF_PROTO2); if (rta[IP_RTA_PROXY_ARP_LLADDR - 1]) { /* This is a network proxy arp with specific lladdr */ if (netif == IP_NULL) return -IP_ERRNO_EINVAL; ipcom_memset(&gw_dl, 0, sizeof(struct Ip_sockaddr_dl)); IPCOM_SA_LEN_SET(&gw_dl, sizeof(struct Ip_sockaddr_dl)); gw_dl.sdl_family = IP_AF_LINK; gw_dl.sdl_index = (Ip_u16)netif->ipcom.ifindex; gw_dl.sdl_alen = (Ip_u8) netif->ipcom.link_addr_size; gw_dl.sdl_type = (Ip_u8) netif->ipcom.type; ipcom_memcpy(IP_SOCKADDR_DL_LLADDR(&gw_dl), IP_RTA_DATA(rta[IP_RTA_PROXY_ARP_LLADDR - 1]), IPNET_ETH_ADDR_SIZE); gw = (struct Ip_sockaddr *) &gw_dl; IP_BIT_SET(param.flags, IPNET_RTF_LLINFO); } } else if (rtm->rtm_type == IP_RTN_PROHIBIT) IP_BIT_SET(param.flags, IPNET_RTF_REJECT); else if (rtm->rtm_type == IP_RTN_THROW) IP_BIT_SET(param.flags, IPNET_RTF_SKIP); else if (rtm->rtm_type == IP_RTN_UNREACHABLE) { if (netif == IP_NULL) netif = ipnet_loopback_get_netif(vr); IP_BIT_CLR(param.flags, IPNET_RTF_UP); } else if (rtm->rtm_type == IP_RTN_CLONE) IP_BIT_SET(param.flags, IPNET_RTF_CLONING); else if (rtm->rtm_type == IP_RTN_BLACKHOLE) IP_BIT_SET(param.flags, IPNET_RTF_BLACKHOLE); #ifdef IPMPLS /* Check for IPNET MPLS pseudo-wire route */ if (rta[IP_RTA_NH_PROTO-1]) { Ip_u32 nh_type; if (rta[IP_RTA_NH_PROTO-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; if (rta[IP_RTA_NH_PROTO_DATA-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; ipcom_memcpy(&nh_type, IP_RTA_DATA(rta[IP_RTA_NH_PROTO-1]), sizeof(Ip_u32)); if (nh_type != IPNET_ETH_P_MPLS_UNICAST) return -IP_ERRNO_EINVAL; ipcom_memset(&gw_mpls, 0, sizeof(gw_mpls)); gw_mpls.smpls_family = IP_AF_MPLS; IPCOM_SA_LEN_SET(&gw_mpls, sizeof (struct Ip_sockaddr_mpls)); ipcom_memcpy(&gw_mpls.smpls_key, IP_RTA_DATA(rta[IP_RTA_NH_PROTO_DATA-1]), sizeof(Ip_u32)); IP_BIT_CLR(param.flags,IPNET_RTF_GATEWAY); gw = (struct Ip_sockaddr *)&gw_mpls; } else { /* Check if cloning flag shall be set */ if (IP_BIT_ISFALSE(param.flags, IPNET_RTF_HOST | IPNET_RTF_GATEWAY | IPNET_RTF_REJECT | IPNET_RTF_BLACKHOLE)) IP_BIT_SET(param.flags, IPNET_RTF_CLONING); } #endif if (rta[IP_RTA_METRICS-1]) { Ip_size_t rlen = IP_RTA_PAYLOAD(rta[IP_RTA_METRICS-1]); struct Ip_rtattr *rtax = (struct Ip_rtattr*)IP_RTA_DATA(rta[IP_RTA_METRICS-1]); metrics.rmx_expire = IPCOM_ADDR_INFINITE; param.metrics = &metrics; while (IP_RTA_OK(rtax, rlen)) { switch (rtax->rta_type) { case IP_RTAX_MTU: ipcom_memcpy(&metrics.rmx_mtu, IP_RTA_DATA(rtax), sizeof(Ip_u32)); break; case IP_RTAX_RTT: ipcom_memcpy(&metrics.rmx_rtt, IP_RTA_DATA(rtax), sizeof(Ip_u32)); break; case IP_RTAX_RTTVAR: ipcom_memcpy(&metrics.rmx_rttvar, IP_RTA_DATA(rtax), sizeof(Ip_u32)); break; } rtax = IP_RTA_NEXT(rtax, rlen); } } #ifdef IPNET_USE_ROUTE_COOKIES if (rta[IP_RTA_COOKIE-1]) { if (IP_RTA_PAYLOAD(rta[IP_RTA_COOKIE-1]) > sizeof(cookie)) return -IP_ERRNO_EINVAL; ipcom_memset(&cookie, 0, sizeof(cookie)); ipcom_memcpy(&cookie, IP_RTA_DATA(rta[IP_RTA_COOKIE-1]), IP_RTA_PAYLOAD(rta[IP_RTA_COOKIE-1])); param.cookie = &cookie; } #endif /* IPNET_USE_ROUTE_COOKIES */ while (1) { if (is_multipath_route && (gw == IP_NULL)) { netif = ipnet_if_indextonetif(vr, (Ip_u32) nh->rtnh_ifindex); metrics.rmx_hopcount = nh->rtnh_hops; metrics.rmx_expire = IPCOM_ADDR_INFINITE; param.metrics = &metrics; if (nh->rtnh_len > sizeof(struct Ip_rtnexthop)) { /* Multihop route has gateway */ IP_BIT_CLR(param.flags, IPNET_RTF_CLONING); IP_BIT_SET(param.flags, IPNET_RTF_GATEWAY); if ((ret = ipnet_rtnetlink_route_gw_setup(family, netif? netif->ipcom.ifindex : 0, &ugw, &gw, IP_RTNH_DATA(nh))) < 0) return ret; } mpa_size -= (Ip_ssize_t)IP_RTNH_ALIGN(nh->rtnh_len); if (mpa_size > 0) nh = IP_RTNH_NEXT(nh); } param.domain = family; param.vr = vr; param.table = table; param.netif = netif; param.key = &ukey; param.netmask = mask; param.gateway = gw; param.pid = mem->pid; param.seq = nlh->nlmsg_seq; param.no_ref_count = IP_TRUE; /* Try to add the route */ if (netif) IPNET_IF_LOCK(netif); ret = ipnet_route_add(¶m); if (netif != IP_NULL) IPNET_IF_UNLOCK(netif); if (is_multipath_route) { gw = IP_NULL; if (ret < 0 && ret != -IP_ERRNO_EEXIST) goto rollback; if (mpa_size == 0) { ret = 0; break; } else if (mpa_size < 0) { /* Malformed packet */ ret = -IP_ERRNO_EINVAL; goto rollback; } } else break; } return ret; rollback: (void)ipnet_rtnetlink_route_delroute_family(mem, nlh, rta, family); return ret; } /* *=========================================================================== * ipnet_rtnetlink_route_delroute_family *=========================================================================== * Description: Delete a route via NETLINK. * Parameters: data - Message payload * len - Length of message. * nlh - NETLINK message header * arg - Reference to route attributes. * * Returns: 0 - Success * <0 - Failure * */ IP_GLOBAL int ipnet_rtnetlink_route_delroute_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlh, struct Ip_rtattr **rta, int family) { int ret = -1; Ip_u16 vr; Ip_u32 table; Ip_u32 ifindex = 0; Ip_bool is_multipath_route = IP_FALSE; Ip_size_t mpa_size = 0; struct Ip_rtnexthop *nh = IP_NULL; struct Ip_sockaddr *gw = IP_NULL; void *mask = IP_NULL; struct Ip_rtmsg *rtm = IP_NLMSG_DATA(nlh); union Ip_sockaddr_union ugw; Ipnet_rtnetlink_key_t ukey; #ifdef IPMPLS struct Ip_sockaddr_mpls gw_mpls; #endif /* IPMPLS */ table = (Ip_u32) IPCOM_ROUTE_TABLE_GET(rtm->rtm_table); #ifdef IPNET_USE_ROUTE_TABLE_NAMES if (rta[IP_RTA_TABLE_NAME -1]) { if (ipnet_route_vr_and_table_from_name(IP_RTA_DATA(rta[IP_RTA_TABLE_NAME - 1]), &vr, &table) < 0) return -IP_ERRNO_ESRCH; } else #endif { if (mem->vr == IPCOM_VR_ANY) return -IP_ERRNO_EINVAL; vr = ipnet_rtnetlink_vr(rta[IP_RTA_VR - 1], mem->vr); if (rta[IP_RTA_TABLE - 1]) table = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_TABLE - 1])); } if (rta[IP_RTA_OIF -1]) { if (rta[IP_RTA_OIF-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; ifindex = IP_GET_32ON8(IP_RTA_DATA(rta[IP_RTA_OIF-1])); } if (rta[IP_RTA_MULTIPATH -1]) { is_multipath_route = IP_TRUE; nh = IP_RTA_DATA(rta[IP_RTA_MULTIPATH-1]); mpa_size = IP_RTA_PAYLOAD(rta[IP_RTA_MULTIPATH-1]); if ((nh == IP_NULL) || (mpa_size == 0)) return -IP_ERRNO_EINVAL; } if ((ret = ipnet_rtnetlink_route_key_setup(family, &ukey, ifindex, &mask, rtm->rtm_dst_len, rta[IP_RTA_DST-1])) < 0) return ret; if ((ret = ipnet_rtnetlink_route_gw_setup(family, ifindex, &ugw, &gw, rta[IP_RTA_GATEWAY-1])) < 0) return ret; if (rta[IP_RTA_GATEWAY-1]) gw = &ugw.sa; #ifdef IPMPLS if (rta[IP_RTA_NH_PROTO-1]) { Ip_u32 nh_type; /* IPNET MPLS pseudo-wire route */ if (rta[IP_RTA_NH_PROTO-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; if (rta[IP_RTA_NH_PROTO_DATA-1]->rta_len != IP_RTA_LENGTH(sizeof(Ip_u32))) return -IP_ERRNO_EINVAL; ipcom_memcpy(&nh_type, IP_RTA_DATA(rta[IP_RTA_NH_PROTO-1]), sizeof(Ip_u32)); if (nh_type != IPNET_ETH_P_MPLS_UNICAST) return -IP_ERRNO_EINVAL; ipcom_memset(&gw_mpls, 0, sizeof(gw_mpls)); gw_mpls.smpls_family = IP_AF_MPLS; IPCOM_SA_LEN_SET(&gw_mpls, sizeof (struct Ip_sockaddr_mpls)); ipcom_memcpy(&gw_mpls.smpls_key, IP_RTA_DATA(rta[IP_RTA_NH_PROTO_DATA-1]), sizeof(Ip_u32)); gw = (struct Ip_sockaddr *)&gw_mpls; } #endif while(1) { if (is_multipath_route) { ifindex = (Ip_u32) nh->rtnh_ifindex; if (nh->rtnh_len > sizeof(struct Ip_rtnexthop)) { /* Multihop route has gateway */ if ((ret = ipnet_rtnetlink_route_gw_setup(family, ifindex, &ugw, &gw, IP_RTNH_DATA(nh))) < 0) return ret; } } /* Delete the route */ ret = ipnet_route_delete2(family, vr, table, &ukey, mask, gw, ifindex, 0, 0, 0); if (is_multipath_route) { mpa_size -= IP_RTNH_ALIGN(nh->rtnh_len); gw = IP_NULL; if (mpa_size > 0) nh = IP_RTNH_NEXT(nh); else break; } else break; } return is_multipath_route ? 0 : ret; } /* *=========================================================================== * ipnet_rtnetlink_route_sz_fill_metrics *=========================================================================== * Description: Fill route metrics as attributes in a NETLINK route message. * Parameters: data - Message buffer * metrics - Pointer to IPNET metrics pointer. * Returns: Length of added attributes * */ IP_GLOBAL int ipnet_rtnetlink_route_sz_fill_metrics(Ipnet_netlink_mem_t *mem, struct Ipnet_rt_metrics *metrics, Ip_u32 mtu) { struct Ip_rtattr *rta; rta = ipnet_rtnetlink_rta_sz_nested_begin(mem, IP_RTA_METRICS); if (!rta) return -1; if (metrics->rmx_mtu > 0) mtu = metrics->rmx_mtu; if (!ipnet_rtnetlink_rta_sz_put(mem, IP_RTAX_MTU, sizeof(Ip_u32), &mtu)) return -1; /* Add Round Trip Time */ if (metrics->rmx_rtt > 0) if (!ipnet_rtnetlink_rta_sz_put(mem, IP_RTAX_RTT, sizeof(Ip_u32), &metrics->rmx_rtt)) return -1; /* Add RTT Variance */ if (metrics->rmx_rttvar > 0) if (!ipnet_rtnetlink_rta_sz_put(mem, IP_RTAX_RTTVAR, sizeof(Ip_u32), &metrics->rmx_rttvar)) return -1; /* Terminate the nested RTA */ ipnet_rtnetlink_rta_sz_nested_end(mem, rta); return 0; } /* *========================================================================== * ipnet_rtnetlink_route_dump_family *=========================================================================== * Description: Get interface info via NETLINK * Parameters: data - Message payload. * len - Length of message. * cb - NETLINK callback entry * * Returns: 0 - Success * <0 - Failure * */ IP_GLOBAL int ipnet_rtnetlink_route_dump_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlmsg, int family, Ip_ptrdiff_t *args) { Ipnet_rtnetlink_route_family_t param; Ip_ptrdiff_t *done = &args[0]; Ip_ptrdiff_t *s_vr = &args[1]; Ip_ptrdiff_t *s_table = &args[2]; Ip_ptrdiff_t *s_rtm = &args[3]; Ip_ptrdiff_t *s_continue = &args[4]; param.nlmsg = nlmsg; param.table = 0; param.family = (Ip_u8) family; param.mem = mem; if (*done) goto exit_out; param.state.aborted = 0; param.state.done = done; param.state.rt = s_rtm; param.state.table = s_table; param.state.vr = s_vr; param.state.cont = *s_continue; /* */ ipcom_hash_for_each(ipnet->rtabs, (Ipcom_hash_foreach_cb_func)ipnet_rtnetlink_route_foreach_vr_family, ¶m); /* Are we aborted? */ *s_continue = param.state.aborted; /* If not aborted; we're done */ if (!param.state.aborted) *done = 1; exit_out: return (int) param.mem->used; } /* *========================================================================== * ipnet_rtnetlink_getroute_family *=========================================================================== * Description: Get interface info via NETLINK * Parameters: data - Message payload. * len - Length of message. * cb - NETLINK callback entry * * Returns: 0 - Success * <0 - Failure * */ IP_GLOBAL int ipnet_rtnetlink_route_getroute_family(Ipnet_netlink_mem_t *mem, struct Ip_nlmsghdr *nlh, struct Ip_rtattr **rta, int family) { switch (family) { #ifdef IPCOM_USE_INET case IP_AF_INET: return ipnet_rtnetlink_ip4_getroute(mem, nlh, rta); #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: return ipnet_rtnetlink_ip6_getroute(mem, nlh, rta); #endif default: return -IP_ERRNO_EAFNOSUPPORT;; } } /* *=========================================================================== * ipnet_rtnetlink_route_key_setup *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL int ipnet_rtnetlink_route_key_setup(int family, Ipnet_rtnetlink_key_t *ukey, Ip_u32 ifindex, void **maskp, unsigned mask_len, struct Ip_rtattr *dst) { int ret; #ifdef IPCOM_USE_INET if (family == IP_AF_INET) { if ((ret = ipnet_rtnetlink_ip4_route_key_setup(ukey, ifindex, maskp, mask_len, dst)) < 0) return ret; } else #endif #ifdef IPCOM_USE_INET6 if (family == IP_AF_INET6) { if ((ret = ipnet_rtnetlink_ip6_route_key_setup(ukey, ifindex, maskp, mask_len, dst)) < 0) return ret; } else #endif { return -IP_ERRNO_EAFNOSUPPORT; } return 0; } /* *=========================================================================== * ipnet_rtnetlink_route_gw_setup *=========================================================================== * Description: * Parameters: * Returns: * */ IP_GLOBAL int ipnet_rtnetlink_route_gw_setup(int family, Ip_u32 ifindex, union Ip_sockaddr_union *ugw, struct Ip_sockaddr **gw, struct Ip_rtattr *rta) { int ret; #ifdef IPCOM_USE_INET if (family == IP_AF_INET) { if ((ret = ipnet_rtnetlink_ip4_route_gw_setup(ifindex, ugw, gw, rta)) < 0) return ret; } else #endif #ifdef IPCOM_USE_INET6 if (family == IP_AF_INET6) { if ((ret = ipnet_rtnetlink_ip6_route_gw_setup(ifindex, ugw, gw, rta)) < 0) return ret; } else #endif { return -IP_ERRNO_EAFNOSUPPORT; } return 0; } /* *=========================================================================== * ipnet_rtnetlink_ip6_addr_event *=========================================================================== * Description: Status of a network interface has changed, create a IFINFO * event on NETLNK.. * Parameters: netif - The interface. * Returns: - * */ IP_STATIC void ipnet_rtnetlink_route_event(struct Ipnet_route_entry_struct *rt, int event) { Ipcom_pkt *pkt = IP_NULL; Ipnet_netlink_mem_t mem; int ret = -1; int group; if (!ipnet_netlink_pkt_alloc(&pkt, IP_NULL, IP_TRUE, &mem, 512)) return; /* Must explicitly switch to the correct VR here */ pkt->vr_index = mem.vr = IPNET_ROUTE_GET_VR(rt->head); #ifdef IPCOM_USE_INET if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET) { ret = ipnet_rtnetlink_ip4_route_fill_info (&mem, rt, 0, event, 0); group = IP_RTNLGRP_IPV4_ROUTE; } #endif #ifdef IPCOM_USE_INET6 if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET6) { ret = ipnet_rtnetlink_ip6_route_fill_info (&mem, rt, 0, event, 0); group = IP_RTNLGRP_IPV6_ROUTE; } #endif if (ret < 0) ipcom_pkt_free(pkt); else { pkt->end += ret; /* We're done; do report this pkt */ ipnet_rtnetlink_broadcast(pkt, group); } } IP_GLOBAL void ipnet_rtnetlink_route_add(Ipnet_route_entry *rt) { ipnet_rtnetlink_route_event(rt, IP_RTM_NEWROUTE); } IP_GLOBAL void ipnet_rtnetlink_route_change(Ipnet_route_entry *rt) { ipnet_rtnetlink_route_event(rt, IP_RTM_NEWROUTE); } IP_GLOBAL void ipnet_rtnetlink_route_del(Ipnet_route_entry *rt) { ipnet_rtnetlink_route_event(rt, IP_RTM_DELROUTE); } IP_GLOBAL void ipnet_rtnetlink_route_miss(Ipcom_route *rtab, IP_CONST void *key) { /*!! TODO */ (void)rtab; (void)key; } IP_GLOBAL void ipnet_rtnetlink_route_redirect(Ipcom_route *rtab, Ip_u32 ifindex, IP_CONST void *dst, IP_CONST void *new_gw) { /*!! TODO */ (void)rtab; (void)ifindex; (void)dst; (void)new_gw; } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ #endif /* IPNET_USE_NETLINK */ /* **************************************************************************** * END OF FILE **************************************************************************** */