/* *=========================================================================== * ipnet_sysctl_route_dump_elem_len *=========================================================================== * Description: Calculates the length needed to write down address information * for the specified route entry. * Parameters: rt - a route entry. * Returns: Length in bytes. * */ IP_STATIC Ip_u16 ipnet_sysctl_route_dump_elem_len(Ipnet_route_entry *rt) { Ip_u16 len; Ip_u16 addr_len; len = sizeof(struct Ipnet_rt_msghdr); if (IPNET_ROUTE_GET_FAMILY(rt->head) == IP_AF_INET) addr_len = sizeof(struct Ip_sockaddr_in); else addr_len = sizeof(struct Ip_sockaddr_in6); /* Length of destination address */ len += addr_len; /* Length of destination mask */ if (rt->hdr.mask) len += addr_len; /* Length of gateway address */ if (rt->gateway) len += IPCOM_SA_LEN_GET(rt->gateway); else if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_CLONING)) len += sizeof(struct Ip_sockaddr_dl); return len; }
/* *=========================================================================== * 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); } }
/* *=========================================================================== * ipnet_sysctl_for_each_rtab_cb *=========================================================================== * Description: Dumps all routes entries for every route table. * Parameters: rtab - The route table to dump. * d - The route dump parameters. * Returns: * */ IP_STATIC void ipnet_sysctl_for_each_rtab_cb(Ipcom_route *rtab, Ipnet_sysctl_route_data *d) { if (d->vr != IPNET_ROUTE_GET_VR(rtab)) return; if (d->domain != 0 && d->domain != IPNET_ROUTE_GET_FAMILY(rtab)) return; d->table = IPNET_ROUTE_GET_TABLE(rtab); ipcom_route_walk_tree(rtab, (Ipcom_route_walk_cb) ipnet_sysctl_route_dump_cb, d); }
/* *=========================================================================== * ipnet_sysctl_route_dump_cb *=========================================================================== * Description: Checks if this entry should be added and adds it if it should. * Parameters: rt - the route entry to add * data - callback data. * Returns: IP_FALSE (the entry should never be deleted). * */ IP_STATIC Ip_bool ipnet_sysctl_route_dump_cb(Ipnet_route_entry *rt, Ipnet_sysctl_route_data *data) { struct Ipnet_rt_msghdr *rt_msg; Ip_u16 len; if (rt->next) (void)ipnet_sysctl_route_dump_cb(rt->next, data); if (rt->narrow) (void) ipnet_sysctl_route_dump_cb(rt->narrow, data); if ((rt->hdr.flags & data->flags) != data->flags) return IP_FALSE; /* Do not list the 255.255.255.255, 224.0.0.0/4 or IPv6 multicast routes. */ if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_X_MCAST_RO | IPNET_RTF_X_BCAST_RO | IPNET_RTF_X_HIDDEN)) return IP_FALSE; len = ipnet_sysctl_route_dump_elem_len(rt); data->bytes_written += len; if (data->bytes_written > data->buf_len) { /* Buffer to small */ if (data->buf != IP_NULL) data->soerrno = -IP_ERRNO_ENOMEM; return IP_FALSE; } rt_msg = (struct Ipnet_rt_msghdr *) data->buf; data->buf = (Ip_u8 *) data->buf + sizeof(struct Ipnet_rt_msghdr); ipcom_memset(rt_msg, 0, sizeof(struct Ipnet_rt_msghdr)); rt_msg->rtm_msglen = len; rt_msg->rtm_version = IPNET_RTM_VERSION; rt_msg->rtm_type = IPNET_RTM_GET; rt_msg->rtm_index = rt->netif ? rt->netif->ipcom.ifindex : 0; rt_msg->rtm_table = data->table; rt_msg->rtm_flags = rt->hdr.flags; rt_msg->rtm_use = rt->use; rt_msg->rtm_rmx = rt->metrics; /* add destination address */ IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_DST); data->buf = ipnet_sysctl_route_add_addr(data->buf, IPNET_ROUTE_GET_FAMILY(rt->head), rt->hdr.key); if (rt->gateway) { IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY); ipcom_memcpy(data->buf, rt->gateway, IPCOM_SA_LEN_GET(rt->gateway)); data->buf = (Ip_u8 *) data->buf + IPCOM_SA_LEN_GET(rt->gateway); } else if (IP_BIT_ISSET(rt->hdr.flags, IPNET_RTF_CLONING)) { struct Ip_sockaddr_dl *dl = data->buf; IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_GATEWAY); ipcom_memset(data->buf, 0, sizeof(struct Ip_sockaddr_dl)); IPCOM_SA_LEN_SET(dl, sizeof(struct Ip_sockaddr_dl)); dl->sdl_family = IP_AF_LINK; ip_assert(rt->netif != IP_NULL); if (rt->netif != IP_NULL) { dl->sdl_index = (Ip_u16)rt->netif->ipcom.ifindex; dl->sdl_type = (Ip_u8)rt->netif->ipcom.type; } data->buf = (Ip_u8 *) data->buf + sizeof(struct Ip_sockaddr_dl); } if (rt->hdr.mask) { /* add destination mask */ IP_BIT_SET(rt_msg->rtm_addrs, IPNET_RTA_NETMASK); data->buf = ipnet_sysctl_route_add_addr(data->buf, IPNET_ROUTE_GET_FAMILY(rt->head), rt->hdr.mask); } ip_assert((Ip_u16)((Ip_ptrdiff_t) data->buf - (Ip_ptrdiff_t) rt_msg) == len); return IP_FALSE; }
/* *=========================================================================== * 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, 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, 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; }
/* *=========================================================================== * 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_neigh_foreach_vr_family(Ipcom_route *rtab, Ipnet_rtnetlink_neigh_family_t *param) { 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 (param->family != IP_AF_UNSPEC && IPNET_ROUTE_GET_FAMILY(rtab) != param->family) return; /* We only have neigh values in the default table */ if (IPNET_ROUTE_GET_TABLE(rtab) != IPCOM_ROUTE_TABLE_DEFAULT) 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) return; if (rtt != IP_NULL) { rt = ipnet_route_first_entry(IPNET_ROUTE_GET_FAMILY(rtab), vr, IPNET_ROUTE_GET_TABLE(rtab)); 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, IPNET_ROUTE_GET_TABLE(rtab)); /* */ while (rt) { do { if (ipnet_rtnetlink_neigh_is(rt)) break; rt = ipnet_route_next_entry(rt); } while (rt != IP_NULL); if (rt != IP_NULL) { int ret = 0; /* Verify this particular NC entry */ #ifdef IPCOM_USE_INET if (IPNET_ROUTE_GET_FAMILY(rtab) == IP_AF_INET) ret = ipnet_rtnetlink_ip4_neigh_fill_info(param->mem, rt, param->nlmsg->nlmsg_seq, IP_RTM_NEWNEIGH, IP_NLM_F_MULTI); #endif #ifdef IPCOM_USE_INET6 if (IPNET_ROUTE_GET_FAMILY(rtab) == IP_AF_INET6) ret = ipnet_rtnetlink_ip6_neigh_fill_info(param->mem, rt, param->nlmsg->nlmsg_seq, IP_RTM_NEWNEIGH, IP_NLM_F_MULTI); #endif if (ret < 0) goto aborted; /* Get next */ rt = ipnet_route_next_entry(rt); } } return; aborted: param->state.aborted = 1; *param->state.rt = (Ip_ptrdiff_t)rt; *param->state.vr = (Ip_ptrdiff_t)vr; }