route.c revision 186119
178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD: head/usr.sbin/ppp/route.c 186119 2008-12-15 06:10:57Z qingli $ 296059Samurai */ 3030715Sbrian 3143313Sbrian#include <sys/param.h> 326059Samurai#include <sys/socket.h> 3331176Sbrian#include <net/if_types.h> 3430715Sbrian#include <net/route.h> 3530715Sbrian#include <net/if.h> 3630715Sbrian#include <netinet/in.h> 3730715Sbrian#include <arpa/inet.h> 3831176Sbrian#include <net/if_dl.h> 3936285Sbrian#include <netinet/in_systm.h> 4036285Sbrian#include <netinet/ip.h> 4136285Sbrian#include <sys/un.h> 4220287Swollman 4320287Swollman#include <errno.h> 44102500Sbrian#include <stdarg.h> 4530715Sbrian#include <stdio.h> 466059Samurai#include <stdlib.h> 476059Samurai#include <string.h> 4830715Sbrian#include <sys/sysctl.h> 4936285Sbrian#include <termios.h> 5075212Sbrian#include <unistd.h> 5120287Swollman 5246686Sbrian#include "layer.h" 5337009Sbrian#include "defs.h" 5431343Sbrian#include "command.h" 5530715Sbrian#include "mbuf.h" 569439Samurai#include "log.h" 5736285Sbrian#include "iplist.h" 5836285Sbrian#include "timer.h" 5936285Sbrian#include "throughput.h" 6036285Sbrian#include "lqr.h" 6136285Sbrian#include "hdlc.h" 6236285Sbrian#include "fsm.h" 6336285Sbrian#include "lcp.h" 6436285Sbrian#include "ccp.h" 6536285Sbrian#include "link.h" 6636285Sbrian#include "slcompress.h" 6781634Sbrian#include "ncpaddr.h" 6831690Sbrian#include "ipcp.h" 6936285Sbrian#include "filter.h" 7036285Sbrian#include "descriptor.h" 7136285Sbrian#include "mp.h" 7243313Sbrian#ifndef NORADIUS 7343313Sbrian#include "radius.h" 7443313Sbrian#endif 7581634Sbrian#include "ipv6cp.h" 7681634Sbrian#include "ncp.h" 7736285Sbrian#include "bundle.h" 7830715Sbrian#include "route.h" 7936285Sbrian#include "prompt.h" 8040561Sbrian#include "iface.h" 8175212Sbrian#include "id.h" 826059Samurai 8358032Sbrian 846059Samuraistatic void 8536285Sbrianp_sockaddr(struct prompt *prompt, struct sockaddr *phost, 8636285Sbrian struct sockaddr *pmask, int width) 876059Samurai{ 8881634Sbrian struct ncprange range; 8931343Sbrian char buf[29]; 9031176Sbrian struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 916059Samurai 9258031Sbrian if (log_IsKept(LogDEBUG)) { 9358031Sbrian char tmp[50]; 9458031Sbrian 9558031Sbrian log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 9658031Sbrian log_Printf(LogDEBUG, " Family %d, len %d\n", 9758031Sbrian (int)phost->sa_family, (int)phost->sa_len); 9858032Sbrian inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 9958031Sbrian log_Printf(LogDEBUG, " Addr %s\n", tmp); 10058031Sbrian if (pmask) { 10158032Sbrian inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 10258031Sbrian log_Printf(LogDEBUG, " Mask %s\n", tmp); 10358031Sbrian } 10458031Sbrian } 10558031Sbrian 10631176Sbrian switch (phost->sa_family) { 10731176Sbrian case AF_INET: 10881634Sbrian#ifndef NOINET6 10981634Sbrian case AF_INET6: 11081634Sbrian#endif 11181634Sbrian ncprange_setsa(&range, phost, pmask); 11281634Sbrian if (ncprange_isdefault(&range)) 11381634Sbrian prompt_Printf(prompt, "%-*s ", width - 1, "default"); 11481634Sbrian else 11581634Sbrian prompt_Printf(prompt, "%-*s ", width - 1, ncprange_ntoa(&range)); 11681634Sbrian return; 11731176Sbrian 11831176Sbrian case AF_LINK: 11931541Sbrian if (dl->sdl_nlen) 12031541Sbrian snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 12134536Sbrian else if (dl->sdl_alen) { 12234536Sbrian if (dl->sdl_type == IFT_ETHER) { 12331962Sbrian if (dl->sdl_alen < sizeof buf / 3) { 12431541Sbrian int f; 12531541Sbrian u_char *MAC; 12631541Sbrian 12731541Sbrian MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 12831541Sbrian for (f = 0; f < dl->sdl_alen; f++) 12931541Sbrian sprintf(buf+f*3, "%02x:", MAC[f]); 13031541Sbrian buf[f*3-1] = '\0'; 13131541Sbrian } else 13275212Sbrian strcpy(buf, "??:??:??:??:??:??"); 13334536Sbrian } else 13431541Sbrian sprintf(buf, "<IFT type %d>", dl->sdl_type); 13536285Sbrian } else if (dl->sdl_slen) 13631541Sbrian sprintf(buf, "<slen %d?>", dl->sdl_slen); 13731541Sbrian else 13831176Sbrian sprintf(buf, "link#%d", dl->sdl_index); 13931176Sbrian break; 14031176Sbrian 14131176Sbrian default: 14231541Sbrian sprintf(buf, "<AF type %d>", phost->sa_family); 14331176Sbrian break; 14426516Sbrian } 14531176Sbrian 14636285Sbrian prompt_Printf(prompt, "%-*s ", width-1, buf); 1476059Samurai} 1486059Samurai 14932663Sbrianstatic struct bits { 15037189Sbrian u_int32_t b_mask; 15128679Sbrian char b_val; 15231176Sbrian} bits[] = { 15331176Sbrian { RTF_UP, 'U' }, 15431176Sbrian { RTF_GATEWAY, 'G' }, 15531176Sbrian { RTF_HOST, 'H' }, 15631176Sbrian { RTF_REJECT, 'R' }, 15731176Sbrian { RTF_DYNAMIC, 'D' }, 15831176Sbrian { RTF_MODIFIED, 'M' }, 15931176Sbrian { RTF_DONE, 'd' }, 160186119Sqingli { RTF_XRESOLVE, 'X' }, 161186119Sqingli#ifdef RTF_CLONING 16231176Sbrian { RTF_CLONING, 'C' }, 163186119Sqingli#endif 16431176Sbrian { RTF_STATIC, 'S' }, 16531176Sbrian { RTF_PROTO1, '1' }, 16631176Sbrian { RTF_PROTO2, '2' }, 16731176Sbrian { RTF_BLACKHOLE, 'B' }, 168186119Sqingli 169186119Sqingli#ifdef RTF_LLINFO 170186119Sqingli { RTF_LLINFO, 'L' }, 171186119Sqingli#endif 172186119Sqingli#ifdef RTF_CLONING 173186119Sqingli { RTF_CLONING, 'C' }, 174186119Sqingli#endif 17531739Sbrian#ifdef RTF_WASCLONED 17631176Sbrian { RTF_WASCLONED, 'W' }, 17731739Sbrian#endif 17831739Sbrian#ifdef RTF_PRCLONING 17931176Sbrian { RTF_PRCLONING, 'c' }, 18031739Sbrian#endif 18131739Sbrian#ifdef RTF_PROTO3 18231176Sbrian { RTF_PROTO3, '3' }, 18331739Sbrian#endif 18431739Sbrian#ifdef RTF_BROADCAST 18531176Sbrian { RTF_BROADCAST, 'b' }, 18631176Sbrian#endif 18731176Sbrian { 0, '\0' } 1886059Samurai}; 1896059Samurai 19031739Sbrian#ifndef RTF_WASCLONED 19131739Sbrian#define RTF_WASCLONED (0) 19231739Sbrian#endif 19331739Sbrian 1946059Samuraistatic void 195134789Sbrianp_flags(struct prompt *prompt, u_int32_t f, unsigned max) 1966059Samurai{ 19736285Sbrian char name[33], *flags; 19836285Sbrian register struct bits *p = bits; 1996059Samurai 20036285Sbrian if (max > sizeof name - 1) 20136285Sbrian max = sizeof name - 1; 20231827Sbrian 203134789Sbrian for (flags = name; p->b_mask && flags - name < (int)max; p++) 20436285Sbrian if (p->b_mask & f) 20536285Sbrian *flags++ = p->b_val; 20636285Sbrian *flags = '\0'; 207139978Sbrian prompt_Printf(prompt, "%-*.*s", (int)max, (int)max, name); 2086059Samurai} 2096059Samurai 21096582Sbrianstatic int route_nifs = -1; 21196582Sbrian 21232616Sbrianconst char * 21331176SbrianIndex2Nam(int idx) 21431176Sbrian{ 21537010Sbrian /* 21637010Sbrian * XXX: Maybe we should select() on the routing socket so that we can 21737010Sbrian * notice interfaces that come & go (PCCARD support). 21837010Sbrian * Or we could even support a signal that resets these so that 21937010Sbrian * the PCCARD insert/remove events can signal ppp. 22037010Sbrian */ 22137010Sbrian static char **ifs; /* Figure these out once */ 22296582Sbrian static int debug_done; /* Debug once */ 22331176Sbrian 22496582Sbrian if (idx > route_nifs || (idx > 0 && ifs[idx-1] == NULL)) { 22532425Sbrian int mib[6], have, had; 22632021Sbrian size_t needed; 22731176Sbrian char *buf, *ptr, *end; 22831176Sbrian struct sockaddr_dl *dl; 22931176Sbrian struct if_msghdr *ifm; 23031176Sbrian 23150427Sbrian if (ifs) { 23250427Sbrian free(ifs); 23350427Sbrian ifs = NULL; 23496582Sbrian route_nifs = 0; 23550427Sbrian } 23650427Sbrian debug_done = 0; 23750427Sbrian 23831176Sbrian mib[0] = CTL_NET; 23931176Sbrian mib[1] = PF_ROUTE; 24031176Sbrian mib[2] = 0; 24131176Sbrian mib[3] = 0; 24231176Sbrian mib[4] = NET_RT_IFLIST; 24331176Sbrian mib[5] = 0; 24431176Sbrian 24531176Sbrian if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 24637019Sbrian log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 24737019Sbrian strerror(errno)); 24858034Sbrian return NumStr(idx, NULL, 0); 24931176Sbrian } 25031176Sbrian if ((buf = malloc(needed)) == NULL) 25158034Sbrian return NumStr(idx, NULL, 0); 25231176Sbrian if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 25331176Sbrian free(buf); 25458034Sbrian return NumStr(idx, NULL, 0); 25531176Sbrian } 25631176Sbrian end = buf + needed; 25731176Sbrian 25832425Sbrian have = 0; 25931354Sbrian for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 26031176Sbrian ifm = (struct if_msghdr *)ptr; 26158032Sbrian if (ifm->ifm_type != RTM_IFINFO) 26258035Sbrian continue; 26331176Sbrian dl = (struct sockaddr_dl *)(ifm + 1); 26432425Sbrian if (ifm->ifm_index > 0) { 26532425Sbrian if (ifm->ifm_index > have) { 26638381Sbrian char **newifs; 26738381Sbrian 26832425Sbrian had = have; 26932425Sbrian have = ifm->ifm_index + 5; 27032425Sbrian if (had) 27138381Sbrian newifs = (char **)realloc(ifs, sizeof(char *) * have); 27232425Sbrian else 27338381Sbrian newifs = (char **)malloc(sizeof(char *) * have); 27438381Sbrian if (!newifs) { 27536285Sbrian log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 27696582Sbrian route_nifs = 0; 27750427Sbrian if (ifs) { 27838381Sbrian free(ifs); 27950427Sbrian ifs = NULL; 28050427Sbrian } 28150427Sbrian free(buf); 28258034Sbrian return NumStr(idx, NULL, 0); 28332425Sbrian } 28438381Sbrian ifs = newifs; 28532425Sbrian memset(ifs + had, '\0', sizeof(char *) * (have - had)); 28632425Sbrian } 28732425Sbrian if (ifs[ifm->ifm_index-1] == NULL) { 28832425Sbrian ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 289136375Sbrian if (ifs[ifm->ifm_index-1] == NULL) 290136375Sbrian log_Printf(LogDEBUG, "Skipping interface %d: Out of memory\n", 291136375Sbrian ifm->ifm_index); 292136375Sbrian else { 293136375Sbrian memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 294136375Sbrian ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 295136375Sbrian if (route_nifs < ifm->ifm_index) 296136375Sbrian route_nifs = ifm->ifm_index; 297136375Sbrian } 29832425Sbrian } 29936285Sbrian } else if (log_IsKept(LogDEBUG)) 30036285Sbrian log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 30131354Sbrian ifm->ifm_index); 30231176Sbrian } 30331176Sbrian free(buf); 30431176Sbrian } 30531176Sbrian 30636285Sbrian if (log_IsKept(LogDEBUG) && !debug_done) { 30731354Sbrian int f; 30831354Sbrian 30936285Sbrian log_Printf(LogDEBUG, "Found the following interfaces:\n"); 31096582Sbrian for (f = 0; f < route_nifs; f++) 31132425Sbrian if (ifs[f] != NULL) 31236285Sbrian log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 31331354Sbrian debug_done = 1; 31431354Sbrian } 31531354Sbrian 31696582Sbrian if (idx < 1 || idx > route_nifs || ifs[idx-1] == NULL) 31758034Sbrian return NumStr(idx, NULL, 0); 31831354Sbrian 31931354Sbrian return ifs[idx-1]; 32031176Sbrian} 32131176Sbrian 32258032Sbrianvoid 32358032Sbrianroute_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 32458032Sbrian{ 32558032Sbrian char *wp; 32658032Sbrian int rtax; 32758032Sbrian 32858032Sbrian wp = (char *)(rtm + 1); 32958032Sbrian 33058032Sbrian for (rtax = 0; rtax < RTAX_MAX; rtax++) 33158032Sbrian if (rtm->rtm_addrs & (1 << rtax)) { 33258032Sbrian sa[rtax] = (struct sockaddr *)wp; 33358032Sbrian wp += ROUNDUP(sa[rtax]->sa_len); 33493463Sbrian if (sa[rtax]->sa_family == 0) 33586832Sbrian sa[rtax] = NULL; /* ??? */ 33658032Sbrian } else 33758032Sbrian sa[rtax] = NULL; 33858032Sbrian} 33958032Sbrian 3406059Samuraiint 34136285Sbrianroute_Show(struct cmdargs const *arg) 3426059Samurai{ 3436059Samurai struct rt_msghdr *rtm; 34458032Sbrian struct sockaddr *sa[RTAX_MAX]; 34558032Sbrian char *sp, *ep, *cp; 34632021Sbrian size_t needed; 3476735Samurai int mib[6]; 3486059Samurai 3496059Samurai mib[0] = CTL_NET; 3506059Samurai mib[1] = PF_ROUTE; 3516735Samurai mib[2] = 0; 3526735Samurai mib[3] = 0; 3536059Samurai mib[4] = NET_RT_DUMP; 3546735Samurai mib[5] = 0; 3556735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 35636285Sbrian log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 35728679Sbrian return (1); 3586735Samurai } 3596059Samurai sp = malloc(needed); 3606059Samurai if (sp == NULL) 36128679Sbrian return (1); 3626735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 36336285Sbrian log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 36418885Sjkh free(sp); 36528679Sbrian return (1); 3666735Samurai } 3676059Samurai ep = sp + needed; 3686059Samurai 36936285Sbrian prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 37036285Sbrian "Destination", "Gateway"); 3716059Samurai for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 37258032Sbrian rtm = (struct rt_msghdr *)cp; 37331176Sbrian 37458032Sbrian route_ParseHdr(rtm, sa); 37558031Sbrian 37658032Sbrian if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 37758032Sbrian p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 37858032Sbrian p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 37931176Sbrian 38058031Sbrian p_flags(arg->prompt, rtm->rtm_flags, 6); 38158031Sbrian prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 38258031Sbrian } else 38358031Sbrian prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 3846059Samurai } 38518885Sjkh free(sp); 38626516Sbrian return 0; 3876059Samurai} 3886059Samurai 3896059Samurai/* 3906059Samurai * Delete routes associated with our interface 3916059Samurai */ 3926059Samuraivoid 39336285Sbrianroute_IfDelete(struct bundle *bundle, int all) 3946059Samurai{ 3956059Samurai struct rt_msghdr *rtm; 39658032Sbrian struct sockaddr *sa[RTAX_MAX]; 39781634Sbrian struct ncprange range; 39832021Sbrian int pass; 39932021Sbrian size_t needed; 4006059Samurai char *sp, *cp, *ep; 4016735Samurai int mib[6]; 4026059Samurai 40340561Sbrian log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 40426516Sbrian 4056059Samurai mib[0] = CTL_NET; 4066059Samurai mib[1] = PF_ROUTE; 4076735Samurai mib[2] = 0; 4086735Samurai mib[3] = 0; 4096059Samurai mib[4] = NET_RT_DUMP; 4106735Samurai mib[5] = 0; 4116735Samurai if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 41236285Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 41375212Sbrian strerror(errno)); 4146735Samurai return; 4156735Samurai } 4166059Samurai 4176059Samurai sp = malloc(needed); 4186059Samurai if (sp == NULL) 4196059Samurai return; 4206059Samurai 4216735Samurai if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 42236285Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 42375212Sbrian strerror(errno)); 4246059Samurai free(sp); 4256059Samurai return; 4266059Samurai } 4276059Samurai ep = sp + needed; 4286059Samurai 42931739Sbrian for (pass = 0; pass < 2; pass++) { 43031739Sbrian /* 43131739Sbrian * We do 2 passes. The first deletes all cloned routes. The second 43258032Sbrian * deletes all non-cloned routes. This is done to avoid 43331739Sbrian * potential errors from trying to delete route X after route Y where 43436285Sbrian * route X was cloned from route Y (and is no longer there 'cos it 43536285Sbrian * may have gone with route Y). 43631739Sbrian */ 43731739Sbrian if (RTF_WASCLONED == 0 && pass == 0) 43831739Sbrian /* So we can't tell ! */ 43931739Sbrian continue; 44031739Sbrian for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 44158032Sbrian rtm = (struct rt_msghdr *)cp; 44258032Sbrian route_ParseHdr(rtm, sa); 44381634Sbrian if (rtm->rtm_index == bundle->iface->index && 44481634Sbrian sa[RTAX_DST] && sa[RTAX_GATEWAY] && 44581634Sbrian (sa[RTAX_DST]->sa_family == AF_INET 44681634Sbrian#ifndef NOINET6 44781634Sbrian || sa[RTAX_DST]->sa_family == AF_INET6 44881634Sbrian#endif 44981634Sbrian ) && 45081634Sbrian (all || (rtm->rtm_flags & RTF_GATEWAY))) { 45181634Sbrian if (log_IsKept(LogDEBUG)) { 45281634Sbrian char gwstr[41]; 45381634Sbrian struct ncpaddr gw; 45481634Sbrian ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 45581634Sbrian ncpaddr_setsa(&gw, sa[RTAX_GATEWAY]); 45681634Sbrian snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(&gw)); 45781634Sbrian log_Printf(LogDEBUG, "Found %s %s\n", ncprange_ntoa(&range), gwstr); 45881634Sbrian } 45981634Sbrian if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 46081634Sbrian#ifndef NOINET6 46181634Sbrian sa[RTAX_GATEWAY]->sa_family == AF_INET6 || 46281634Sbrian#endif 46381634Sbrian sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 46481634Sbrian if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 46581634Sbrian (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 46681634Sbrian ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]); 46781634Sbrian rt_Set(bundle, RTM_DELETE, &range, NULL, 0, 0); 46831739Sbrian } else 46981634Sbrian log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 47081634Sbrian } else 47181634Sbrian log_Printf(LogDEBUG, 47281634Sbrian "route_IfDelete: Can't remove routes for family %d\n", 47381634Sbrian sa[RTAX_GATEWAY]->sa_family); 47431739Sbrian } 4756059Samurai } 4766059Samurai } 4776059Samurai free(sp); 4786059Samurai} 4796059Samurai 48075212Sbrian 48175212Sbrian/* 48275212Sbrian * Update the MTU on all routes for the given interface 48375212Sbrian */ 48475212Sbrianvoid 48575212Sbrianroute_UpdateMTU(struct bundle *bundle) 48675212Sbrian{ 48775212Sbrian struct rt_msghdr *rtm; 48875212Sbrian struct sockaddr *sa[RTAX_MAX]; 48981634Sbrian struct ncprange dst; 49075212Sbrian size_t needed; 49175212Sbrian char *sp, *cp, *ep; 49275212Sbrian int mib[6]; 49375212Sbrian 49475212Sbrian log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 49575212Sbrian 49675212Sbrian mib[0] = CTL_NET; 49775212Sbrian mib[1] = PF_ROUTE; 49875212Sbrian mib[2] = 0; 49975212Sbrian mib[3] = 0; 50075212Sbrian mib[4] = NET_RT_DUMP; 50175212Sbrian mib[5] = 0; 50275212Sbrian if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 50375212Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 50475212Sbrian strerror(errno)); 50575212Sbrian return; 50675212Sbrian } 50775212Sbrian 50875212Sbrian sp = malloc(needed); 50975212Sbrian if (sp == NULL) 51075212Sbrian return; 51175212Sbrian 51275212Sbrian if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 51375212Sbrian log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 51475212Sbrian strerror(errno)); 51575212Sbrian free(sp); 51675212Sbrian return; 51775212Sbrian } 51875212Sbrian ep = sp + needed; 51975212Sbrian 52075212Sbrian for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 52175212Sbrian rtm = (struct rt_msghdr *)cp; 52275212Sbrian route_ParseHdr(rtm, sa); 52381886Sbrian if (sa[RTAX_DST] && (sa[RTAX_DST]->sa_family == AF_INET 52481739Sbrian#ifndef NOINET6 52581886Sbrian || sa[RTAX_DST]->sa_family == AF_INET6 52681739Sbrian#endif 52781739Sbrian ) && 52881739Sbrian sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index) { 52981739Sbrian if (log_IsKept(LogTCPIP)) { 53081739Sbrian ncprange_setsa(&dst, sa[RTAX_DST], sa[RTAX_NETMASK]); 53181739Sbrian log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s," 532134789Sbrian " mtu %lu\n", rtm->rtm_index, Index2Nam(rtm->rtm_index), 53381739Sbrian ncprange_ntoa(&dst), bundle->iface->mtu); 53481739Sbrian } 53581739Sbrian rt_Update(bundle, sa[RTAX_DST], sa[RTAX_GATEWAY], sa[RTAX_NETMASK]); 53675212Sbrian } 53775212Sbrian } 53875212Sbrian 53975212Sbrian free(sp); 54075212Sbrian} 54175212Sbrian 5426059Samuraiint 54328679SbrianGetIfIndex(char *name) 5446059Samurai{ 54531176Sbrian int idx; 54628679Sbrian 54731354Sbrian idx = 1; 54896582Sbrian while (route_nifs == -1 || idx < route_nifs) 54996582Sbrian if (strcmp(Index2Nam(idx), name) == 0) 55036285Sbrian return idx; 55131176Sbrian else 55231176Sbrian idx++; 55331176Sbrian return -1; 5546059Samurai} 55531690Sbrian 55636285Sbrianvoid 55736285Sbrianroute_Change(struct bundle *bundle, struct sticky_route *r, 55881634Sbrian const struct ncpaddr *me, const struct ncpaddr *peer) 55931690Sbrian{ 56081634Sbrian struct ncpaddr dst; 56131690Sbrian 56236285Sbrian for (; r; r = r->next) { 56381634Sbrian ncprange_getaddr(&r->dst, &dst); 56481634Sbrian if (ncpaddr_family(me) == AF_INET) { 56581634Sbrian if ((r->type & ROUTE_DSTMYADDR) && !ncpaddr_equal(&dst, me)) { 56681634Sbrian rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 56781634Sbrian ncprange_sethost(&r->dst, me); 56881634Sbrian if (r->type & ROUTE_GWHISADDR) 56981634Sbrian ncpaddr_copy(&r->gw, peer); 57081634Sbrian } else if ((r->type & ROUTE_DSTHISADDR) && !ncpaddr_equal(&dst, peer)) { 57181634Sbrian rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 57281634Sbrian ncprange_sethost(&r->dst, peer); 57381634Sbrian if (r->type & ROUTE_GWHISADDR) 57481634Sbrian ncpaddr_copy(&r->gw, peer); 57581634Sbrian } else if ((r->type & ROUTE_DSTDNS0) && !ncpaddr_equal(&dst, peer)) { 57681634Sbrian if (bundle->ncp.ipcp.ns.dns[0].s_addr == INADDR_NONE) 57781634Sbrian continue; 57881634Sbrian rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 57981634Sbrian if (r->type & ROUTE_GWHISADDR) 58081634Sbrian ncpaddr_copy(&r->gw, peer); 58181634Sbrian } else if ((r->type & ROUTE_DSTDNS1) && !ncpaddr_equal(&dst, peer)) { 58281634Sbrian if (bundle->ncp.ipcp.ns.dns[1].s_addr == INADDR_NONE) 58381634Sbrian continue; 58481634Sbrian rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 58581634Sbrian if (r->type & ROUTE_GWHISADDR) 58681634Sbrian ncpaddr_copy(&r->gw, peer); 58781634Sbrian } else if ((r->type & ROUTE_GWHISADDR) && !ncpaddr_equal(&r->gw, peer)) 58881634Sbrian ncpaddr_copy(&r->gw, peer); 58981634Sbrian#ifndef NOINET6 59081634Sbrian } else if (ncpaddr_family(me) == AF_INET6) { 59181634Sbrian if ((r->type & ROUTE_DSTMYADDR6) && !ncpaddr_equal(&dst, me)) { 59281634Sbrian rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 59381634Sbrian ncprange_sethost(&r->dst, me); 59481634Sbrian if (r->type & ROUTE_GWHISADDR) 59581634Sbrian ncpaddr_copy(&r->gw, peer); 59681634Sbrian } else if ((r->type & ROUTE_DSTHISADDR6) && !ncpaddr_equal(&dst, peer)) { 59781634Sbrian rt_Set(bundle, RTM_DELETE, &r->dst, NULL, 1, 0); 59881634Sbrian ncprange_sethost(&r->dst, peer); 59981634Sbrian if (r->type & ROUTE_GWHISADDR) 60081634Sbrian ncpaddr_copy(&r->gw, peer); 60181634Sbrian } else if ((r->type & ROUTE_GWHISADDR6) && !ncpaddr_equal(&r->gw, peer)) 60281634Sbrian ncpaddr_copy(&r->gw, peer); 60381634Sbrian#endif 60481634Sbrian } 60581634Sbrian rt_Set(bundle, RTM_ADD, &r->dst, &r->gw, 1, 0); 60636285Sbrian } 60736285Sbrian} 60836285Sbrian 60936285Sbrianvoid 61081634Sbrianroute_Add(struct sticky_route **rp, int type, const struct ncprange *dst, 61181634Sbrian const struct ncpaddr *gw) 61236285Sbrian{ 61343313Sbrian struct sticky_route *r; 61443313Sbrian int dsttype = type & ROUTE_DSTANY; 61536285Sbrian 61643313Sbrian r = NULL; 61743313Sbrian while (*rp) { 61843313Sbrian if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 61981634Sbrian (!dsttype && ncprange_equal(&(*rp)->dst, dst))) { 62043313Sbrian /* Oops, we already have this route - unlink it */ 62143313Sbrian free(r); /* impossible really */ 62243313Sbrian r = *rp; 62343313Sbrian *rp = r->next; 62443313Sbrian } else 62543313Sbrian rp = &(*rp)->next; 62643313Sbrian } 62736285Sbrian 628136375Sbrian if (r == NULL) { 62943313Sbrian r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 630136375Sbrian if (r == NULL) { 631136375Sbrian log_Printf(LogERROR, "route_Add: Out of memory!\n"); 632136375Sbrian return; 633136375Sbrian } 634136375Sbrian } 63543313Sbrian r->type = type; 63643313Sbrian r->next = NULL; 63781634Sbrian ncprange_copy(&r->dst, dst); 63881634Sbrian ncpaddr_copy(&r->gw, gw); 63981692Sbrian *rp = r; 64036285Sbrian} 64136285Sbrian 64236285Sbrianvoid 64381634Sbrianroute_Delete(struct sticky_route **rp, int type, const struct ncprange *dst) 64436285Sbrian{ 64536285Sbrian struct sticky_route *r; 64636285Sbrian int dsttype = type & ROUTE_DSTANY; 64736285Sbrian 64836285Sbrian for (; *rp; rp = &(*rp)->next) { 64936285Sbrian if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 65081634Sbrian (!dsttype && ncprange_equal(dst, &(*rp)->dst))) { 65136285Sbrian r = *rp; 65236285Sbrian *rp = r->next; 65336285Sbrian free(r); 65431690Sbrian break; 65531690Sbrian } 65631690Sbrian } 65736285Sbrian} 65831690Sbrian 65936285Sbrianvoid 66036285Sbrianroute_DeleteAll(struct sticky_route **rp) 66136285Sbrian{ 66236285Sbrian struct sticky_route *r, *rn; 66336285Sbrian 66436285Sbrian for (r = *rp; r; r = rn) { 66536285Sbrian rn = r->next; 66636285Sbrian free(r); 66731690Sbrian } 66836285Sbrian *rp = NULL; 66936285Sbrian} 67031690Sbrian 67136285Sbrianvoid 67243313Sbrianroute_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 67343313Sbrian int indent) 67436285Sbrian{ 67543313Sbrian int tlen = strlen(tag); 67636285Sbrian 67743313Sbrian if (tlen + 2 > indent) 67843313Sbrian prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 67943313Sbrian else 68043313Sbrian prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 68143313Sbrian 68236285Sbrian for (; r; r = r->next) { 68343313Sbrian prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 68443313Sbrian tlen = 0; 68536285Sbrian if (r->type & ROUTE_DSTMYADDR) 68636285Sbrian prompt_Printf(p, "MYADDR"); 68781634Sbrian else if (r->type & ROUTE_DSTMYADDR6) 68881634Sbrian prompt_Printf(p, "MYADDR6"); 68936285Sbrian else if (r->type & ROUTE_DSTHISADDR) 69036285Sbrian prompt_Printf(p, "HISADDR"); 69181634Sbrian else if (r->type & ROUTE_DSTHISADDR6) 69281634Sbrian prompt_Printf(p, "HISADDR6"); 69358044Sbrian else if (r->type & ROUTE_DSTDNS0) 69458044Sbrian prompt_Printf(p, "DNS0"); 69558044Sbrian else if (r->type & ROUTE_DSTDNS1) 69658044Sbrian prompt_Printf(p, "DNS1"); 69781634Sbrian else if (ncprange_isdefault(&r->dst)) 69881634Sbrian prompt_Printf(p, "default"); 69936285Sbrian else 70081634Sbrian prompt_Printf(p, "%s", ncprange_ntoa(&r->dst)); 70136285Sbrian 70236285Sbrian if (r->type & ROUTE_GWHISADDR) 70381634Sbrian prompt_Printf(p, " HISADDR\n"); 70481634Sbrian else if (r->type & ROUTE_GWHISADDR6) 70581634Sbrian prompt_Printf(p, " HISADDR6\n"); 70636285Sbrian else 70781634Sbrian prompt_Printf(p, " %s\n", ncpaddr_ntoa(&r->gw)); 70836285Sbrian } 70931690Sbrian} 71075212Sbrian 71175212Sbrianstruct rtmsg { 71275212Sbrian struct rt_msghdr m_rtm; 71381634Sbrian char m_space[256]; 71475212Sbrian}; 71575212Sbrian 71686833Sbrianstatic size_t 71786833Sbrianmemcpy_roundup(char *cp, const void *data, size_t len) 71886833Sbrian{ 71986833Sbrian size_t padlen; 72086833Sbrian 72186833Sbrian padlen = ROUNDUP(len); 72286833Sbrian memcpy(cp, data, len); 72386833Sbrian if (padlen > len) 72486833Sbrian memset(cp + len, '\0', padlen - len); 72586833Sbrian 72686833Sbrian return padlen; 72786833Sbrian} 72886833Sbrian 729112616Sume#if defined(__KAME__) && !defined(NOINET6) 730112616Sumestatic void 731112616Sumeadd_scope(struct sockaddr *sa, int ifindex) 732112616Sume{ 733112616Sume struct sockaddr_in6 *sa6; 734112616Sume 735112616Sume if (sa->sa_family != AF_INET6) 736112616Sume return; 737112616Sume sa6 = (struct sockaddr_in6 *)sa; 738112616Sume if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) && 739112616Sume !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr)) 740112616Sume return; 741112616Sume if (*(u_int16_t *)&sa6->sin6_addr.s6_addr[2] != 0) 742112616Sume return; 743112616Sume *(u_int16_t *)&sa6->sin6_addr.s6_addr[2] = htons(ifindex); 744112616Sume} 745112616Sume#endif 746112616Sume 74775212Sbrianint 74881634Sbrianrt_Set(struct bundle *bundle, int cmd, const struct ncprange *dst, 74981634Sbrian const struct ncpaddr *gw, int bang, int quiet) 75075212Sbrian{ 75175212Sbrian struct rtmsg rtmes; 75286825Sbrian int s, nb, wb; 75375212Sbrian char *cp; 75475212Sbrian const char *cmdstr; 75581634Sbrian struct sockaddr_storage sadst, samask, sagw; 75675212Sbrian int result = 1; 75775212Sbrian 75875212Sbrian if (bang) 75975212Sbrian cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 76075212Sbrian else 76175212Sbrian cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 76289422Sbrian s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 76375212Sbrian if (s < 0) { 76475212Sbrian log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 76575212Sbrian return result; 76675212Sbrian } 76775212Sbrian memset(&rtmes, '\0', sizeof rtmes); 76875212Sbrian rtmes.m_rtm.rtm_version = RTM_VERSION; 76975212Sbrian rtmes.m_rtm.rtm_type = cmd; 77075212Sbrian rtmes.m_rtm.rtm_addrs = RTA_DST; 77175212Sbrian rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 77275212Sbrian rtmes.m_rtm.rtm_pid = getpid(); 77375212Sbrian rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 77475212Sbrian 77575212Sbrian if (cmd == RTM_ADD) { 77681634Sbrian if (bundle->ncp.cfg.sendpipe > 0) { 77781634Sbrian rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 77875212Sbrian rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 77975212Sbrian } 78081634Sbrian if (bundle->ncp.cfg.recvpipe > 0) { 78181634Sbrian rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 78275212Sbrian rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 78375212Sbrian } 78475212Sbrian } 78575212Sbrian 78681634Sbrian ncprange_getsa(dst, &sadst, &samask); 787112616Sume#if defined(__KAME__) && !defined(NOINET6) 788112616Sume add_scope((struct sockaddr *)&sadst, bundle->iface->index); 789112616Sume#endif 79075212Sbrian 79175212Sbrian cp = rtmes.m_space; 79286833Sbrian cp += memcpy_roundup(cp, &sadst, sadst.ss_len); 79375212Sbrian if (cmd == RTM_ADD) { 79481634Sbrian if (gw == NULL) { 79581634Sbrian log_Printf(LogERROR, "rt_Set: Program error\n"); 79681634Sbrian close(s); 79781634Sbrian return result; 79881634Sbrian } 79981634Sbrian ncpaddr_getsa(gw, &sagw); 800112616Sume#if defined(__KAME__) && !defined(NOINET6) 801112616Sume add_scope((struct sockaddr *)&sagw, bundle->iface->index); 802112616Sume#endif 80381634Sbrian if (ncpaddr_isdefault(gw)) { 80481634Sbrian if (!quiet) 80575212Sbrian log_Printf(LogERROR, "rt_Set: Cannot add a route with" 80683031Sbrian " gateway 0.0.0.0\n"); 80775212Sbrian close(s); 80875212Sbrian return result; 80975212Sbrian } else { 81086833Sbrian cp += memcpy_roundup(cp, &sagw, sagw.ss_len); 81175212Sbrian rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 81275212Sbrian } 81375212Sbrian } 81475212Sbrian 81586815Sbrian if (!ncprange_ishost(dst)) { 81686833Sbrian cp += memcpy_roundup(cp, &samask, samask.ss_len); 81775212Sbrian rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 81875212Sbrian } 81975212Sbrian 82075212Sbrian nb = cp - (char *)&rtmes; 82175212Sbrian rtmes.m_rtm.rtm_msglen = nb; 82275212Sbrian wb = ID0write(s, &rtmes, nb); 82375212Sbrian if (wb < 0) { 82475212Sbrian log_Printf(LogTCPIP, "rt_Set failure:\n"); 82575212Sbrian log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 82681634Sbrian log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", ncprange_ntoa(dst)); 82781634Sbrian if (gw != NULL) 82881634Sbrian log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", ncpaddr_ntoa(gw)); 82975212Sbrianfailed: 83075212Sbrian if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 83175212Sbrian (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 83275212Sbrian if (!bang) { 83375212Sbrian log_Printf(LogWARN, "Add route failed: %s already exists\n", 83481634Sbrian ncprange_ntoa(dst)); 83575212Sbrian result = 0; /* Don't add to our dynamic list */ 83675212Sbrian } else { 83775212Sbrian rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 83875212Sbrian if ((wb = ID0write(s, &rtmes, nb)) < 0) 83975212Sbrian goto failed; 84075212Sbrian } 84175212Sbrian } else if (cmd == RTM_DELETE && 84275212Sbrian (rtmes.m_rtm.rtm_errno == ESRCH || 84375212Sbrian (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 84475212Sbrian if (!bang) 84575212Sbrian log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 84681634Sbrian ncprange_ntoa(dst)); 84775212Sbrian } else if (rtmes.m_rtm.rtm_errno == 0) { 84881634Sbrian if (!quiet || errno != ENETUNREACH) 84975212Sbrian log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 85081634Sbrian ncprange_ntoa(dst), strerror(errno)); 85175212Sbrian } else 85275212Sbrian log_Printf(LogWARN, "%s route failed: %s: %s\n", 85381634Sbrian cmdstr, ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 85475212Sbrian } 85575212Sbrian 85681634Sbrian if (log_IsKept(LogDEBUG)) { 85781634Sbrian char gwstr[40]; 85881634Sbrian 85981634Sbrian if (gw) 86081634Sbrian snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(gw)); 86181634Sbrian else 86281634Sbrian snprintf(gwstr, sizeof gwstr, "<none>"); 86381634Sbrian log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %s, gateway = %s\n", 86481634Sbrian wb, cmdstr, ncprange_ntoa(dst), gwstr); 86581634Sbrian } 86675212Sbrian close(s); 86775212Sbrian 86875212Sbrian return result; 86975212Sbrian} 87075212Sbrian 87175212Sbrianvoid 87281739Sbrianrt_Update(struct bundle *bundle, const struct sockaddr *dst, 87381739Sbrian const struct sockaddr *gw, const struct sockaddr *mask) 87475212Sbrian{ 87581739Sbrian struct ncprange ncpdst; 87675212Sbrian struct rtmsg rtmes; 87781739Sbrian char *p; 87875212Sbrian int s, wb; 87975212Sbrian 88089422Sbrian s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 88175212Sbrian if (s < 0) { 88275212Sbrian log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 88375212Sbrian return; 88475212Sbrian } 88575212Sbrian 88675212Sbrian memset(&rtmes, '\0', sizeof rtmes); 88775212Sbrian rtmes.m_rtm.rtm_version = RTM_VERSION; 88875212Sbrian rtmes.m_rtm.rtm_type = RTM_CHANGE; 88981934Sbrian rtmes.m_rtm.rtm_addrs = 0; 89075212Sbrian rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 89175212Sbrian rtmes.m_rtm.rtm_pid = getpid(); 89293421Sbrian rtmes.m_rtm.rtm_flags = RTF_UP | RTF_STATIC; 89375212Sbrian 89481634Sbrian if (bundle->ncp.cfg.sendpipe > 0) { 89581634Sbrian rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe; 89675212Sbrian rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 89775212Sbrian } 89875212Sbrian 89981634Sbrian if (bundle->ncp.cfg.recvpipe > 0) { 90081634Sbrian rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe; 90175212Sbrian rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 90275212Sbrian } 90375212Sbrian 90478410Sbrian rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->iface->mtu; 90575212Sbrian rtmes.m_rtm.rtm_inits |= RTV_MTU; 90681739Sbrian p = rtmes.m_space; 90775212Sbrian 90881739Sbrian if (dst) { 90981739Sbrian rtmes.m_rtm.rtm_addrs |= RTA_DST; 91086833Sbrian p += memcpy_roundup(p, dst, dst->sa_len); 91181739Sbrian } 91275212Sbrian 91393421Sbrian rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 91493421Sbrian p += memcpy_roundup(p, gw, gw->sa_len); 91593421Sbrian if (mask) { 91693421Sbrian rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 91793421Sbrian p += memcpy_roundup(p, mask, mask->sa_len); 91893421Sbrian } 91993421Sbrian 92081739Sbrian rtmes.m_rtm.rtm_msglen = p - (char *)&rtmes; 92175212Sbrian 92275212Sbrian wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); 92375212Sbrian if (wb < 0) { 92481739Sbrian ncprange_setsa(&ncpdst, dst, mask); 92581739Sbrian 92675212Sbrian log_Printf(LogTCPIP, "rt_Update failure:\n"); 92781739Sbrian log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", ncprange_ntoa(&ncpdst)); 92875212Sbrian 92975212Sbrian if (rtmes.m_rtm.rtm_errno == 0) 93075212Sbrian log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", 93181739Sbrian ncprange_ntoa(&ncpdst), strerror(errno)); 93275212Sbrian else 93375212Sbrian log_Printf(LogWARN, "%s: Change route failed: %s\n", 93481739Sbrian ncprange_ntoa(&ncpdst), strerror(rtmes.m_rtm.rtm_errno)); 93575212Sbrian } 93675212Sbrian close(s); 93775212Sbrian} 938