/** * Process a route from the kernel deletion list. * *@return -1 on error, else 0 */ static int olsr_delete_kernel_route(struct rt_entry *rt) { if (rt->rt_metric.hops > 1) { /* multihop route */ if (ip_is_linklocal(&rt->rt_dst.prefix)) { /* do not delete a route with a LL IP as a destination */ return 0; } } if (!olsr_cnf->host_emul) { int16_t error = olsr_cnf->ip_version == AF_INET ? olsr_delroute_function(rt) : olsr_delroute6_function(rt); if (error != 0) { const char *const err_msg = strerror(errno); const char *const routestr = olsr_rt_to_string(rt); OLSR_PRINTF(1, "KERN: ERROR deleting %s: %s\n", routestr, err_msg); olsr_syslog(OLSR_LOG_ERR, "Delete route %s: %s", routestr, err_msg); return -1; } #ifdef linux /* call NIIT handler (always)*/ if (olsr_cnf->use_niit) { olsr_niit_handle_route(rt, false); } #endif } return 0; }
/** *Remove a route from the kernel * *@param destination the route to remove * *@return negative on error */ int olsr_ioctl_del_route6(const struct rt_entry *rt) { struct in6_rtmsg kernel_route; int rslt; OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt)); memset(&kernel_route, 0, sizeof(struct in6_rtmsg)); kernel_route.rtmsg_dst = rt->rt_dst.prefix.v6; kernel_route.rtmsg_dst_len = rt->rt_dst.prefix_len; kernel_route.rtmsg_gateway = rt->rt_best->rtp_nexthop.gateway.v6; kernel_route.rtmsg_flags = olsr_rt_flags(rt); kernel_route.rtmsg_metric = olsr_fib_metric(&rt->rt_best->rtp_metric); if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route) >= 0)) { /* * Send IPC route update message */ ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL); } return rslt; }
/* * Remove a route from the kernel * @param destination the route to remove * @return negative on error */ int os_route_del_rtentry(const struct rt_entry *rt, int ip_version) { MIB_IPFORWARDROW Row; union olsr_ip_addr mask; unsigned long Res; struct interface *iface = rt->rt_nexthop.interface; if (AF_INET != ip_version) { /* * Not implemented */ return -1; } OLSR_DEBUG(LOG_NETWORKING, "KERN: Deleting %s\n", olsr_rt_to_string(rt)); memset(&Row, 0, sizeof(Row)); Row.dwForwardDest = rt->rt_dst.prefix.v4.s_addr; if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) { return -1; } Row.dwForwardMask = mask.v4.s_addr; Row.dwForwardPolicy = 0; Row.dwForwardNextHop = rt->rt_nexthop.gateway.v4.s_addr; Row.dwForwardIfIndex = iface->if_index; // MIB_IPROUTE_TYPE_DIRECT and MIB_IPROUTE_TYPE_INDIRECT Row.dwForwardType = (rt->rt_dst.prefix.v4.s_addr == rt->rt_nexthop.gateway.v4.s_addr) ? 3 : 4; Row.dwForwardProto = 3; // MIB_IPPROTO_NETMGMT Row.dwForwardAge = INFINITE; Row.dwForwardNextHopAS = 0; Row.dwForwardMetric1 = olsr_fib_metric(&rt->rt_metric); Row.dwForwardMetric2 = -1; Row.dwForwardMetric3 = -1; Row.dwForwardMetric4 = -1; Row.dwForwardMetric5 = -1; Res = DeleteIpForwardEntry(&Row); if (Res != NO_ERROR) { OLSR_WARN(LOG_NETWORKING, "DeleteIpForwardEntry() = %08lx, %s", Res, win32_strerror(Res)); // XXX - report error in a different way errno = Res; return -1; } return 0; }
/** *Remove a route from the kernel * *@param destination the route to remove * *@return negative on error */ int olsr_ioctl_del_route(const struct rt_entry *rt) { struct rtentry kernel_route; union olsr_ip_addr mask; int rslt; OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt)); memset(&kernel_route, 0, sizeof(struct rtentry)); ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_family = AF_INET; ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_family = AF_INET; ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_family = AF_INET; ((struct sockaddr_in *)&kernel_route.rt_dst)->sin_addr = rt->rt_dst.prefix.v4; if (rt->rt_dst.prefix.v4.s_addr != rt->rt_nexthop.gateway.v4.s_addr) { ((struct sockaddr_in *)&kernel_route.rt_gateway)->sin_addr = rt->rt_nexthop.gateway.v4; } if (!olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len)) { return -1; } else { ((struct sockaddr_in *)&kernel_route.rt_genmask)->sin_addr = mask.v4; } kernel_route.rt_flags = olsr_rt_flags(rt); kernel_route.rt_metric = olsr_fib_metric(&rt->rt_metric); /* * Set interface */ kernel_route.rt_dev = NULL; if ((rslt = ioctl(olsr_cnf->ioctl_s, SIOCDELRT, &kernel_route)) >= 0) { /* * Send IPC route update message */ ipc_route_send_rtentry(&rt->rt_dst.prefix, NULL, 0, 0, NULL); } return rslt; }
/* * Sends an add or delete message via the routing socket. * The message consists of: * - a header i.e. struct rt_msghdr * - 0-8 socket address structures */ static int add_del_route(const struct rt_entry *rt, int add) { struct rt_msghdr *rtm; /* message to send to the routing socket */ unsigned char buff[512]; unsigned char *walker; /* points within the buffer */ struct sockaddr_in sin4; /* internet style sockaddr */ struct sockaddr_dl *sdl; /* link level sockaddr */ struct ifaddrs *addrs; struct ifaddrs *awalker; const struct rt_nexthop *nexthop; union olsr_ip_addr mask; /* netmask as ip address */ int sin_size, sdl_size; /* payload of the message */ int len; /* message size written to routing socket */ if (add) { OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best)); } else { OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt)); } memset(buff, 0, sizeof(buff)); memset(&sin4, 0, sizeof(sin4)); sin4.sin_len = sizeof(sin4); sin4.sin_family = AF_INET; sin_size = 1 + ((sizeof(struct sockaddr_in) - 1) | (sizeof(long) - 1)); sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | (sizeof(long) - 1)); /********************************************************************** * FILL THE ROUTING MESSAGE HEADER **********************************************************************/ /* position header to the beginning of the buffer */ rtm = (struct rt_msghdr *)buff; rtm->rtm_version = RTM_VERSION; rtm->rtm_type = add ? RTM_ADD : RTM_DELETE; rtm->rtm_index = 0; /* is ignored in outgoing messages */ rtm->rtm_flags = olsr_rt_flags(rt); rtm->rtm_pid = OLSR_PID; rtm->rtm_seq = ++seq; /* walk to the end of the header */ walker = buff + sizeof(struct rt_msghdr); /********************************************************************** * SET DESTINATION OF THE ROUTE **********************************************************************/ #ifdef _WRS_KERNEL /* * vxWorks: change proto or tos */ OLSR_PRINTF(8, "\t- Setting Protocol: 0\n"); ((struct sockaddr_rt *)(&sin4))->srt_proto = 0; OLSR_PRINTF(8, "\t- Setting TOS: 0\n"); ((struct sockaddr_rt *)(&sin4))->srt_tos = 0; #endif sin4.sin_addr = rt->rt_dst.prefix.v4; memcpy(walker, &sin4, sizeof(sin4)); walker += sin_size; rtm->rtm_addrs = RTA_DST; /********************************************************************** * SET GATEWAY OF THE ROUTE **********************************************************************/ #ifdef _WRS_KERNEL /* * vxWorks: Route with no gateway is deleted */ if (add) { #endif nexthop = olsr_get_nh(rt); if (0 != (rtm->rtm_flags & RTF_GATEWAY)) { sin4.sin_addr = nexthop->gateway.v4; memcpy(walker, &sin4, sizeof(sin4)); walker += sin_size; rtm->rtm_addrs |= RTA_GATEWAY; } else { /* * Host is directly reachable, so add * the output interface MAC address. */ if (getifaddrs(&addrs)) { fprintf(stderr, "\ngetifaddrs() failed\n"); return -1; } for (awalker = addrs; awalker != NULL; awalker = awalker->ifa_next) if (awalker->ifa_addr->sa_family == AF_LINK && strcmp(awalker->ifa_name, if_ifwithindex_name(nexthop->iif_index)) == 0) break; if (awalker == NULL) { fprintf(stderr, "\nInterface %s not found\n", if_ifwithindex_name(nexthop->iif_index)); freeifaddrs(addrs); return -1; } /* sdl is "struct sockaddr_dl" */ sdl = (struct sockaddr_dl *)awalker->ifa_addr; memcpy(walker, sdl, sdl->sdl_len); walker += sdl_size; rtm->rtm_addrs |= RTA_GATEWAY; #ifdef RTF_CLONING rtm->rtm_flags |= RTF_CLONING; #endif #ifndef _WRS_KERNEL rtm->rtm_flags &= ~RTF_HOST; #endif freeifaddrs(addrs); } #ifdef _WRS_KERNEL } #endif /********************************************************************** * SET NETMASK **********************************************************************/ if (0 == (rtm->rtm_flags & RTF_HOST)) { olsr_prefix_to_netmask(&mask, rt->rt_dst.prefix_len); sin4.sin_addr = mask.v4; memcpy(walker, &sin4, sizeof(sin4)); walker += sin_size; rtm->rtm_addrs |= RTA_NETMASK; } /********************************************************************** * WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET **********************************************************************/ rtm->rtm_msglen = (unsigned short)(walker - buff); len = write(olsr_cnf->rts, buff, rtm->rtm_msglen); if (0 != rtm->rtm_errno || len < rtm->rtm_msglen) { fprintf(stderr, "\nCannot write to routing socket: (rtm_errno= 0x%x) (last error message: %s)\n", rtm->rtm_errno,strerror(errno)); if (add) { fprintf(stderr, " Failed on Adding %s\n", olsr_rtp_to_string(rt->rt_best)); } else { fprintf(stderr, " Failed on Deleting %s\n",olsr_rt_to_string(rt)); } } return 0; }
static int add_del_route6(const struct rt_entry *rt, int add) { struct rt_msghdr *rtm; unsigned char buff[512]; unsigned char *walker; struct sockaddr_in6 sin6; struct sockaddr_dl sdl; const struct rt_nexthop *nexthop; int sin_size, sdl_size; int len; if (add) { OLSR_PRINTF(2, "KERN: Adding %s\n", olsr_rtp_to_string(rt->rt_best)); } else { OLSR_PRINTF(2, "KERN: Deleting %s\n", olsr_rt_to_string(rt)); } memset(buff, 0, sizeof(buff)); memset(&sin6, 0, sizeof(sin6)); memset(&sdl, 0, sizeof(sdl)); sin6.sin6_len = sizeof(sin6); sin6.sin6_family = AF_INET6; sdl.sdl_len = sizeof(sdl); sdl.sdl_family = AF_LINK; sin_size = 1 + ((sizeof(struct sockaddr_in6) - 1) | (sizeof(long) - 1)); sdl_size = 1 + ((sizeof(struct sockaddr_dl) - 1) | (sizeof(long) - 1)); /********************************************************************** * FILL THE ROUTING MESSAGE HEADER **********************************************************************/ /* position header to the beginning of the buffer */ rtm = (struct rt_msghdr *)buff; rtm->rtm_version = RTM_VERSION; rtm->rtm_type = (add != 0) ? RTM_ADD : RTM_DELETE; rtm->rtm_index = 0; rtm->rtm_flags = olsr_rt_flags(rt); rtm->rtm_pid = OLSR_PID; rtm->rtm_seq = ++seq; /* walk to the end of the header */ walker = buff + sizeof(struct rt_msghdr); /********************************************************************** * SET DESTINATION OF THE ROUTE **********************************************************************/ memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr)); memcpy(walker, &sin6, sizeof(sin6)); walker += sin_size; rtm->rtm_addrs = RTA_DST; /********************************************************************** * SET GATEWAY OF THE ROUTE **********************************************************************/ nexthop = olsr_get_nh(rt); if (0 != (rtm->rtm_flags & RTF_GATEWAY)) { memcpy(&sin6.sin6_addr.s6_addr, &nexthop->gateway.v6, sizeof(struct in6_addr)); memset(&sin6.sin6_addr.s6_addr, 0, 8); sin6.sin6_addr.s6_addr[0] = 0xfe; sin6.sin6_addr.s6_addr[1] = 0x80; sin6.sin6_scope_id = nexthop->iif_index; #ifdef __KAME__ *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id); sin6.sin6_scope_id = 0; #endif memcpy(walker, &sin6, sizeof(sin6)); walker += sin_size; rtm->rtm_addrs |= RTA_GATEWAY; } else { /* * Host is directly reachable, so add * the output interface MAC address. */ memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr)); memset(&sin6.sin6_addr.s6_addr, 0, 8); sin6.sin6_addr.s6_addr[0] = 0xfe; sin6.sin6_addr.s6_addr[1] = 0x80; sin6.sin6_scope_id = nexthop->iif_index; #ifdef __KAME__ *(u_int16_t *) & sin6.sin6_addr.s6_addr[2] = htons(sin6.sin6_scope_id); sin6.sin6_scope_id = 0; #endif memcpy(walker, &sin6, sizeof(sin6)); walker += sin_size; rtm->rtm_addrs |= RTA_GATEWAY; rtm->rtm_flags |= RTF_GATEWAY; } /********************************************************************** * SET NETMASK **********************************************************************/ if (0 == (rtm->rtm_flags & RTF_HOST)) { olsr_prefix_to_netmask((union olsr_ip_addr *)&sin6.sin6_addr, rt->rt_dst.prefix_len); memcpy(walker, &sin6, sizeof(sin6)); walker += sin_size; rtm->rtm_addrs |= RTA_NETMASK; } /********************************************************************** * WRITE CONFIGURATION MESSAGE TO THE ROUTING SOCKET **********************************************************************/ rtm->rtm_msglen = (unsigned short)(walker - buff); len = write(olsr_cnf->rts, buff, rtm->rtm_msglen); if (len < 0 && !(errno == EEXIST || errno == ESRCH)) { fprintf(stderr, "cannot write to routing socket: %s\n", strerror(errno)); } /* * If we get an EEXIST error while adding, delete and retry. */ if (len < 0 && errno == EEXIST && rtm->rtm_type == RTM_ADD) { struct rt_msghdr *drtm; unsigned char dbuff[512]; memset(dbuff, 0, sizeof(dbuff)); drtm = (struct rt_msghdr *)dbuff; drtm->rtm_version = RTM_VERSION; drtm->rtm_type = RTM_DELETE; drtm->rtm_index = 0; drtm->rtm_flags = olsr_rt_flags(rt); drtm->rtm_seq = ++seq; walker = dbuff + sizeof(struct rt_msghdr); memcpy(&sin6.sin6_addr.s6_addr, &rt->rt_dst.prefix.v6, sizeof(struct in6_addr)); memcpy(walker, &sin6, sizeof(sin6)); walker += sin_size; drtm->rtm_addrs = RTA_DST; drtm->rtm_msglen = (unsigned short)(walker - dbuff); len = write(olsr_cnf->rts, dbuff, drtm->rtm_msglen); if (len < 0) { fprintf(stderr, "cannot delete route: %s\n", strerror(errno)); } rtm->rtm_seq = ++seq; len = write(olsr_cnf->rts, buff, rtm->rtm_msglen); if (len < 0) { fprintf(stderr, "still cannot add route: %s\n", strerror(errno)); } } return 0; }