route.c revision 78189
152400Sbillf/*- 252400Sbillf * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 352400Sbillf * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 452400Sbillf * Internet Initiative Japan, Inc (IIJ) 552400Sbillf * All rights reserved. 652400Sbillf * 752400Sbillf * Redistribution and use in source and binary forms, with or without 873651Sdougb * modification, are permitted provided that the following conditions 973651Sdougb * are met: 1052400Sbillf * 1. Redistributions of source code must retain the above copyright 1152495Sbillf * notice, this list of conditions and the following disclaimer. 1252400Sbillf * 2. Redistributions in binary form must reproduce the above copyright 1368507Sdougb * notice, this list of conditions and the following disclaimer in the 1452400Sbillf * documentation and/or other materials provided with the distribution. 1552400Sbillf * 1652533Sbillf * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1752400Sbillf * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1867949Sdougb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1967949Sdougb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2052400Sbillf * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2152400Sbillf * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2252400Sbillf * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2352400Sbillf * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2452400Sbillf * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2552400Sbillf * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2652400Sbillf * SUCH DAMAGE. 2767949Sdougb * 2852400Sbillf * $FreeBSD: head/usr.sbin/ppp/route.c 78189 2001-06-13 21:52:19Z brian $ 2952400Sbillf */ 3052400Sbillf 3152400Sbillf#include <sys/param.h> 3252400Sbillf#include <sys/socket.h> 3367949Sdougb#include <net/if_types.h> 3452400Sbillf#include <net/route.h> 3552400Sbillf#include <net/if.h> 3652400Sbillf#include <netinet/in.h> 3752400Sbillf#include <arpa/inet.h> 3852400Sbillf#include <net/if_dl.h> 3952400Sbillf#include <netinet/in_systm.h> 4052400Sbillf#include <netinet/ip.h> 4167859Sdougb#include <sys/un.h> 4267949Sdougb#include <netdb.h> 4352400Sbillf 4452400Sbillf#include <errno.h> 4558910Salfred#include <stdio.h> 4658910Salfred#include <stdlib.h> 4758910Salfred#include <string.h> 4867850Sdougb#include <sys/sysctl.h> 4967850Sdougb#include <termios.h> 5067850Sdougb#include <unistd.h> 5167850Sdougb 5267850Sdougb#include "layer.h" 5367850Sdougb#include "defs.h" 5467850Sdougb#include "command.h" 5567850Sdougb#include "mbuf.h" 5667850Sdougb#include "log.h" 5767850Sdougb#include "iplist.h" 5867850Sdougb#include "timer.h" 5967850Sdougb#include "throughput.h" 6067949Sdougb#include "lqr.h" 6167850Sdougb#include "hdlc.h" 6267850Sdougb#include "fsm.h" 6367850Sdougb#include "lcp.h" 6467850Sdougb#include "ccp.h" 6567850Sdougb#include "link.h" 6667850Sdougb#include "slcompress.h" 6767850Sdougb#include "ipcp.h" 6867850Sdougb#include "filter.h" 6967859Sdougb#include "descriptor.h" 7067859Sdougb#include "mp.h" 7158910Salfred#ifndef NORADIUS 7267850Sdougb#include "radius.h" 7367850Sdougb#endif 7467850Sdougb#include "bundle.h" 7567850Sdougb#include "route.h" 7667850Sdougb#include "prompt.h" 7767850Sdougb#include "iface.h" 7867859Sdougb#include "id.h" 7967850Sdougb 8067859Sdougb 8167850Sdougbstatic void 8267850Sdougbp_sockaddr(struct prompt *prompt, struct sockaddr *phost, 8367850Sdougb struct sockaddr *pmask, int width) 8467850Sdougb{ 8567859Sdougb char buf[29]; 8667850Sdougb struct sockaddr_in *ihost4 = (struct sockaddr_in *)phost; 8767850Sdougb struct sockaddr_in *mask4 = (struct sockaddr_in *)pmask; 8867850Sdougb struct sockaddr_dl *dl = (struct sockaddr_dl *)phost; 8967850Sdougb 9067850Sdougb if (log_IsKept(LogDEBUG)) { 9167850Sdougb char tmp[50]; 9267850Sdougb 9367850Sdougb log_Printf(LogDEBUG, "Found the following sockaddr:\n"); 9467850Sdougb log_Printf(LogDEBUG, " Family %d, len %d\n", 9567850Sdougb (int)phost->sa_family, (int)phost->sa_len); 9667850Sdougb inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp); 9767850Sdougb log_Printf(LogDEBUG, " Addr %s\n", tmp); 9867850Sdougb if (pmask) { 9967850Sdougb inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp); 10058910Salfred log_Printf(LogDEBUG, " Mask %s\n", tmp); 10158910Salfred } 10258910Salfred } 10358910Salfred 10458910Salfred switch (phost->sa_family) { 10558910Salfred case AF_INET: 10667850Sdougb if (!phost) 10758910Salfred buf[0] = '\0'; 10877323Sdougb else if (ihost4->sin_addr.s_addr == INADDR_ANY) 10977323Sdougb strcpy(buf, "default"); 11067949Sdougb else if (!pmask) 11167850Sdougb strcpy(buf, inet_ntoa(ihost4->sin_addr)); 11267850Sdougb else { 11367949Sdougb u_int32_t msk = ntohl(mask4->sin_addr.s_addr); 11467850Sdougb u_int32_t tst; 11567850Sdougb int bits; 11667949Sdougb int len; 11767850Sdougb struct sockaddr_in net; 11867850Sdougb 11967850Sdougb for (tst = 1, bits = 32; tst; tst <<= 1, bits--) 12067850Sdougb if (msk & tst) 12167949Sdougb break; 12267850Sdougb 12367949Sdougb for (tst <<= 1; tst; tst <<= 1) 12467949Sdougb if (!(msk & tst)) 12567949Sdougb break; 12667949Sdougb 12767949Sdougb net.sin_addr.s_addr = ihost4->sin_addr.s_addr & mask4->sin_addr.s_addr; 12868507Sdougb strcpy(buf, inet_ntoa(net.sin_addr)); 12967949Sdougb for (len = strlen(buf); len > 3; buf[len -= 2] = '\0') 13067949Sdougb if (strcmp(buf + len - 2, ".0")) 13167949Sdougb break; 13267949Sdougb 13367949Sdougb if (tst) /* non-contiguous :-( */ 13467949Sdougb sprintf(buf + strlen(buf),"&0x%08lx", (u_long)msk); 13567949Sdougb else 13667949Sdougb sprintf(buf + strlen(buf), "/%d", bits); 13767949Sdougb } 13867949Sdougb break; 13967949Sdougb 14067949Sdougb case AF_LINK: 14167850Sdougb if (dl->sdl_nlen) 14267859Sdougb snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data); 14367850Sdougb else if (dl->sdl_alen) { 14467850Sdougb if (dl->sdl_type == IFT_ETHER) { 14567850Sdougb if (dl->sdl_alen < sizeof buf / 3) { 14667850Sdougb int f; 14777326Sdougb u_char *MAC; 14877326Sdougb 14967850Sdougb MAC = (u_char *)dl->sdl_data + dl->sdl_nlen; 15067850Sdougb for (f = 0; f < dl->sdl_alen; f++) 15167850Sdougb sprintf(buf+f*3, "%02x:", MAC[f]); 15267850Sdougb buf[f*3-1] = '\0'; 15367850Sdougb } else 15467859Sdougb strcpy(buf, "??:??:??:??:??:??"); 15567859Sdougb } else 15667859Sdougb sprintf(buf, "<IFT type %d>", dl->sdl_type); 15767850Sdougb } else if (dl->sdl_slen) 15867850Sdougb sprintf(buf, "<slen %d?>", dl->sdl_slen); 15967850Sdougb else 16067850Sdougb sprintf(buf, "link#%d", dl->sdl_index); 16167850Sdougb break; 16267850Sdougb 16367850Sdougb#ifndef NOINET6 16467850Sdougb case AF_INET6: 16567850Sdougb if (!phost) 16667850Sdougb buf[0] = '\0'; 16767850Sdougb else { 16867850Sdougb const u_char masks[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe }; 16967850Sdougb struct sockaddr_in6 *ihost6 = (struct sockaddr_in6 *)phost; 17067850Sdougb struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)pmask; 17167850Sdougb int masklen, len; 17267850Sdougb const u_char *c; 17367850Sdougb 17467850Sdougb /* XXX: ?????!?!?!!!!! This is horrible ! */ 17567850Sdougb if (IN6_IS_ADDR_LINKLOCAL(&ihost6->sin6_addr) || 17667850Sdougb IN6_IS_ADDR_MC_LINKLOCAL(&ihost6->sin6_addr)) { 17767850Sdougb ihost6->sin6_scope_id = 17867850Sdougb ntohs(*(u_short *)&ihost6->sin6_addr.s6_addr[2]); 17967850Sdougb *(u_short *)&ihost6->sin6_addr.s6_addr[2] = 0; 18067850Sdougb } 18167850Sdougb 18267850Sdougb if (mask6) { 18367850Sdougb const u_char *p, *end; 18467850Sdougb 18567850Sdougb p = (const u_char *)&mask6->sin6_addr; 18667850Sdougb end = p + 16; 18767850Sdougb for (masklen = 0, end = p + 16; p < end && *p == 0xff; p++) 18867850Sdougb masklen += 8; 18967850Sdougb 19067850Sdougb if (p < end) { 19167850Sdougb for (c = masks; c < masks + sizeof masks; c++) 19267850Sdougb if (*c == *p) { 19367850Sdougb masklen += c - masks; 19467850Sdougb break; 19567850Sdougb } 19667850Sdougb } 19767850Sdougb } else 19867850Sdougb masklen = 128; 19967850Sdougb 20067859Sdougb if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&ihost6->sin6_addr)) 20167850Sdougb snprintf(buf, sizeof buf, "default"); 20267850Sdougb else { 20367850Sdougb getnameinfo(phost, ihost6->sin6_len, buf, sizeof buf, 20467850Sdougb NULL, 0, NI_WITHSCOPEID | NI_NUMERICHOST); 20567850Sdougb if (mask6 && (len = strlen(buf)) < sizeof buf - 1) 20667850Sdougb snprintf(buf + len, sizeof buf - len, "/%d", masklen); 20767850Sdougb } 20867850Sdougb } 20958910Salfred break; 21058910Salfred#endif 21152400Sbillf 21252400Sbillf default: 21352400Sbillf sprintf(buf, "<AF type %d>", phost->sa_family); 21452400Sbillf break; 21573651Sdougb } 21673651Sdougb 21773651Sdougb prompt_Printf(prompt, "%-*s ", width-1, buf); 21873651Sdougb} 21973651Sdougb 22073651Sdougbstatic struct bits { 22152400Sbillf u_int32_t b_mask; 22252400Sbillf char b_val; 22367949Sdougb} bits[] = { 22452400Sbillf { RTF_UP, 'U' }, 22552400Sbillf { RTF_GATEWAY, 'G' }, 22652400Sbillf { RTF_HOST, 'H' }, 22752400Sbillf { RTF_REJECT, 'R' }, 22852400Sbillf { RTF_DYNAMIC, 'D' }, 22967949Sdougb { RTF_MODIFIED, 'M' }, 23052400Sbillf { RTF_DONE, 'd' }, 23152400Sbillf { RTF_CLONING, 'C' }, 23252400Sbillf { RTF_XRESOLVE, 'X' }, 23352400Sbillf { RTF_LLINFO, 'L' }, 23452400Sbillf { RTF_STATIC, 'S' }, 23552400Sbillf { RTF_PROTO1, '1' }, 23652400Sbillf { RTF_PROTO2, '2' }, 23752400Sbillf { RTF_BLACKHOLE, 'B' }, 23852400Sbillf#ifdef RTF_WASCLONED 23952400Sbillf { RTF_WASCLONED, 'W' }, 24052400Sbillf#endif 24152400Sbillf#ifdef RTF_PRCLONING 24252400Sbillf { RTF_PRCLONING, 'c' }, 24352400Sbillf#endif 24452400Sbillf#ifdef RTF_PROTO3 24552400Sbillf { RTF_PROTO3, '3' }, 24652400Sbillf#endif 24752400Sbillf#ifdef RTF_BROADCAST 24852400Sbillf { RTF_BROADCAST, 'b' }, 24952400Sbillf#endif 25052400Sbillf { 0, '\0' } 25152400Sbillf}; 25252400Sbillf 25352400Sbillf#ifndef RTF_WASCLONED 25467949Sdougb#define RTF_WASCLONED (0) 25567949Sdougb#endif 25667949Sdougb 25752400Sbillfstatic void 25852400Sbillfp_flags(struct prompt *prompt, u_int32_t f, int max) 25952400Sbillf{ 26052400Sbillf char name[33], *flags; 26152400Sbillf register struct bits *p = bits; 26252400Sbillf 26352400Sbillf if (max > sizeof name - 1) 26452400Sbillf max = sizeof name - 1; 26552400Sbillf 26652400Sbillf for (flags = name; p->b_mask && flags - name < max; p++) 26752400Sbillf if (p->b_mask & f) 26852400Sbillf *flags++ = p->b_val; 26952400Sbillf *flags = '\0'; 27052400Sbillf prompt_Printf(prompt, "%-*.*s", max, max, name); 27152400Sbillf} 27267949Sdougb 27367949Sdougbconst char * 27467949SdougbIndex2Nam(int idx) 27552400Sbillf{ 27652400Sbillf /* 27752400Sbillf * XXX: Maybe we should select() on the routing socket so that we can 27852400Sbillf * notice interfaces that come & go (PCCARD support). 27952400Sbillf * Or we could even support a signal that resets these so that 28052400Sbillf * the PCCARD insert/remove events can signal ppp. 28152400Sbillf */ 28252400Sbillf static char **ifs; /* Figure these out once */ 28352400Sbillf static int nifs, debug_done; /* Figure out how many once, and debug once */ 28452400Sbillf 28552400Sbillf if (idx > nifs || (idx > 0 && ifs[idx-1] == NULL)) { 28652400Sbillf int mib[6], have, had; 28752400Sbillf size_t needed; 28864467Sbrian char *buf, *ptr, *end; 28952400Sbillf struct sockaddr_dl *dl; 29064467Sbrian struct if_msghdr *ifm; 29167859Sdougb 29252400Sbillf if (ifs) { 29352400Sbillf free(ifs); 29464467Sbrian ifs = NULL; 29564467Sbrian nifs = 0; 29652400Sbillf } 29752400Sbillf debug_done = 0; 29852400Sbillf 29952400Sbillf mib[0] = CTL_NET; 30052400Sbillf mib[1] = PF_ROUTE; 30167859Sdougb mib[2] = 0; 30267859Sdougb mib[3] = 0; 30367859Sdougb mib[4] = NET_RT_IFLIST; 30452400Sbillf mib[5] = 0; 30558910Salfred 30652400Sbillf if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 30752400Sbillf log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", 30858910Salfred strerror(errno)); 30964467Sbrian return NumStr(idx, NULL, 0); 31064467Sbrian } 31164467Sbrian if ((buf = malloc(needed)) == NULL) 31258910Salfred return NumStr(idx, NULL, 0); 31364467Sbrian if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 31464467Sbrian free(buf); 31564467Sbrian return NumStr(idx, NULL, 0); 31664467Sbrian } 31764467Sbrian end = buf + needed; 31864467Sbrian 31958910Salfred have = 0; 32052400Sbillf for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) { 32160420Sbsd ifm = (struct if_msghdr *)ptr; 32252400Sbillf if (ifm->ifm_type != RTM_IFINFO) 32352400Sbillf continue; 32458910Salfred dl = (struct sockaddr_dl *)(ifm + 1); 32558910Salfred if (ifm->ifm_index > 0) { 32658910Salfred if (ifm->ifm_index > have) { 32752400Sbillf char **newifs; 32852400Sbillf 32958910Salfred had = have; 33052400Sbillf have = ifm->ifm_index + 5; 33152400Sbillf if (had) 33252400Sbillf newifs = (char **)realloc(ifs, sizeof(char *) * have); 33352400Sbillf else 33452400Sbillf newifs = (char **)malloc(sizeof(char *) * have); 33552400Sbillf if (!newifs) { 33652400Sbillf log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno)); 33752400Sbillf nifs = 0; 33852400Sbillf if (ifs) { 33952400Sbillf free(ifs); 34052400Sbillf ifs = NULL; 34152400Sbillf } 34252400Sbillf free(buf); 34352400Sbillf return NumStr(idx, NULL, 0); 34452400Sbillf } 34552400Sbillf ifs = newifs; 34652400Sbillf memset(ifs + had, '\0', sizeof(char *) * (have - had)); 34752400Sbillf } 34852400Sbillf if (ifs[ifm->ifm_index-1] == NULL) { 34952400Sbillf ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1); 35052400Sbillf memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen); 35152400Sbillf ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0'; 35273651Sdougb if (nifs < ifm->ifm_index) 35373651Sdougb nifs = ifm->ifm_index; 35473651Sdougb } 35573651Sdougb } else if (log_IsKept(LogDEBUG)) 35652400Sbillf log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n", 35752400Sbillf ifm->ifm_index); 35852400Sbillf } 35952400Sbillf free(buf); 36052400Sbillf } 36152400Sbillf 36252400Sbillf if (log_IsKept(LogDEBUG) && !debug_done) { 36352400Sbillf int f; 36452400Sbillf 36567859Sdougb log_Printf(LogDEBUG, "Found the following interfaces:\n"); 36652400Sbillf for (f = 0; f < nifs; f++) 36752400Sbillf if (ifs[f] != NULL) 36852400Sbillf log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]); 36952400Sbillf debug_done = 1; 37052400Sbillf } 37152400Sbillf 37252400Sbillf if (idx < 1 || idx > nifs || ifs[idx-1] == NULL) 37352400Sbillf return NumStr(idx, NULL, 0); 37452400Sbillf 37552400Sbillf return ifs[idx-1]; 37667859Sdougb} 37767859Sdougb 37867859Sdougbvoid 37967859Sdougbroute_ParseHdr(struct rt_msghdr *rtm, struct sockaddr *sa[RTAX_MAX]) 38067859Sdougb{ 38167859Sdougb char *wp; 38267859Sdougb int rtax; 38367859Sdougb 38467859Sdougb wp = (char *)(rtm + 1); 38567859Sdougb 38652400Sbillf for (rtax = 0; rtax < RTAX_MAX; rtax++) 38767859Sdougb if (rtm->rtm_addrs & (1 << rtax)) { 38867859Sdougb sa[rtax] = (struct sockaddr *)wp; 38967859Sdougb wp += ROUNDUP(sa[rtax]->sa_len); 39067859Sdougb } else 39167859Sdougb sa[rtax] = NULL; 39267859Sdougb} 39367859Sdougb 39467859Sdougbint 39567859Sdougbroute_Show(struct cmdargs const *arg) 39667859Sdougb{ 39767859Sdougb struct rt_msghdr *rtm; 39867859Sdougb struct sockaddr *sa[RTAX_MAX]; 39967859Sdougb char *sp, *ep, *cp; 40067859Sdougb size_t needed; 40167859Sdougb int mib[6]; 40267859Sdougb 40367859Sdougb mib[0] = CTL_NET; 40467859Sdougb mib[1] = PF_ROUTE; 40567859Sdougb mib[2] = 0; 40667859Sdougb mib[3] = 0; 40752400Sbillf mib[4] = NET_RT_DUMP; 40877323Sdougb mib[5] = 0; 40977323Sdougb if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 41052400Sbillf log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno)); 41152400Sbillf return (1); 41252400Sbillf } 41352400Sbillf sp = malloc(needed); 41452400Sbillf if (sp == NULL) 41552400Sbillf return (1); 41652400Sbillf if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 41752400Sbillf log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno)); 41852400Sbillf free(sp); 41952400Sbillf return (1); 42052400Sbillf } 42152400Sbillf ep = sp + needed; 42252400Sbillf 42352400Sbillf prompt_Printf(arg->prompt, "%-20s%-20sFlags Netif\n", 42452400Sbillf "Destination", "Gateway"); 42552400Sbillf for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 42652400Sbillf rtm = (struct rt_msghdr *)cp; 42752400Sbillf 42852400Sbillf route_ParseHdr(rtm, sa); 42952400Sbillf 43052400Sbillf if (sa[RTAX_DST] && sa[RTAX_GATEWAY]) { 43152400Sbillf p_sockaddr(arg->prompt, sa[RTAX_DST], sa[RTAX_NETMASK], 20); 43252400Sbillf p_sockaddr(arg->prompt, sa[RTAX_GATEWAY], NULL, 20); 43352400Sbillf 43452400Sbillf p_flags(arg->prompt, rtm->rtm_flags, 6); 43552400Sbillf prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index)); 43652400Sbillf } else 43752400Sbillf prompt_Printf(arg->prompt, "<can't parse routing entry>\n"); 43852400Sbillf } 43952400Sbillf free(sp); 44052400Sbillf return 0; 44152400Sbillf} 44252400Sbillf 44352400Sbillf/* 44468507Sdougb * Delete routes associated with our interface 44568507Sdougb */ 44668507Sdougbvoid 44768507Sdougbroute_IfDelete(struct bundle *bundle, int all) 44868507Sdougb{ 44968507Sdougb struct rt_msghdr *rtm; 45052400Sbillf struct sockaddr *sa[RTAX_MAX]; 45174992Sasmodai struct sockaddr_in **in; 45252400Sbillf struct in_addr sa_none; 45377323Sdougb int pass; 45477323Sdougb size_t needed; 45552400Sbillf char *sp, *cp, *ep; 45652400Sbillf int mib[6]; 45752400Sbillf 45877323Sdougb log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index); 45977323Sdougb sa_none.s_addr = INADDR_ANY; 46077323Sdougb in = (struct sockaddr_in **)sa; 46167949Sdougb 46267949Sdougb mib[0] = CTL_NET; 46367949Sdougb mib[1] = PF_ROUTE; 46467949Sdougb mib[2] = 0; 46567949Sdougb mib[3] = 0; 46667949Sdougb mib[4] = NET_RT_DUMP; 46767949Sdougb mib[5] = 0; 46867949Sdougb if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 46967949Sdougb log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 47067949Sdougb strerror(errno)); 47167949Sdougb return; 47267949Sdougb } 47367949Sdougb 47467949Sdougb sp = malloc(needed); 47567949Sdougb if (sp == NULL) 47667949Sdougb return; 47767949Sdougb 47867949Sdougb if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 47967949Sdougb log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 48067949Sdougb strerror(errno)); 48167949Sdougb free(sp); 48252400Sbillf return; 48352400Sbillf } 48452400Sbillf ep = sp + needed; 48552400Sbillf 48652400Sbillf for (pass = 0; pass < 2; pass++) { 48752400Sbillf /* 48852534Sbillf * We do 2 passes. The first deletes all cloned routes. The second 48952534Sbillf * deletes all non-cloned routes. This is done to avoid 49052534Sbillf * potential errors from trying to delete route X after route Y where 49152534Sbillf * route X was cloned from route Y (and is no longer there 'cos it 49252534Sbillf * may have gone with route Y). 49352534Sbillf */ 49452534Sbillf if (RTF_WASCLONED == 0 && pass == 0) 49565115Sben /* So we can't tell ! */ 49668507Sdougb continue; 49765115Sben for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 49865115Sben rtm = (struct rt_msghdr *)cp; 49965115Sben route_ParseHdr(rtm, sa); 50052400Sbillf if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET) { 50152400Sbillf log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s)," 50252400Sbillf " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index, 50352400Sbillf Index2Nam(rtm->rtm_index), rtm->rtm_flags, 50452400Sbillf inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr)); 50552400Sbillf if (sa[RTAX_GATEWAY] && rtm->rtm_index == bundle->iface->index && 50652400Sbillf (all || (rtm->rtm_flags & RTF_GATEWAY))) { 50752400Sbillf if (sa[RTAX_GATEWAY]->sa_family == AF_INET || 50852400Sbillf sa[RTAX_GATEWAY]->sa_family == AF_LINK) { 50952400Sbillf if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) || 51052400Sbillf (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) { 51177335Sdougb log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", 51252400Sbillf pass); 51352400Sbillf rt_Set(bundle, RTM_DELETE, in[RTAX_DST]->sin_addr, 51467859Sdougb sa_none, sa_none, 0, 0); 51552400Sbillf } else 51652400Sbillf log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass); 51767859Sdougb } else 51852400Sbillf log_Printf(LogDEBUG, 51967859Sdougb "route_IfDelete: Can't remove routes of %d family !\n", 52052400Sbillf sa[RTAX_GATEWAY]->sa_family); 52167859Sdougb } 52252400Sbillf } 52352400Sbillf } 52467859Sdougb } 52567859Sdougb free(sp); 52667859Sdougb} 52752400Sbillf 52852400Sbillf 52952400Sbillf/* 53052400Sbillf * Update the MTU on all routes for the given interface 53152400Sbillf */ 53252400Sbillfvoid 53352400Sbillfroute_UpdateMTU(struct bundle *bundle) 53452400Sbillf{ 53567949Sdougb struct rt_msghdr *rtm; 53652400Sbillf struct sockaddr *sa[RTAX_MAX]; 53767949Sdougb struct sockaddr_in **in; 53852400Sbillf size_t needed; 53967949Sdougb char *sp, *cp, *ep; 54067949Sdougb int mib[6]; 54167949Sdougb 54267949Sdougb log_Printf(LogDEBUG, "route_UpdateMTU (%d)\n", bundle->iface->index); 54367949Sdougb in = (struct sockaddr_in **)sa; 54467949Sdougb 54567949Sdougb mib[0] = CTL_NET; 54667949Sdougb mib[1] = PF_ROUTE; 54767949Sdougb mib[2] = 0; 54852400Sbillf mib[3] = 0; 54952400Sbillf mib[4] = NET_RT_DUMP; 55067859Sdougb mib[5] = 0; 55167859Sdougb if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 55267859Sdougb log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n", 55352400Sbillf strerror(errno)); 55452400Sbillf return; 55552400Sbillf } 55652400Sbillf 55752400Sbillf sp = malloc(needed); 55852400Sbillf if (sp == NULL) 55952400Sbillf return; 56052400Sbillf 56152400Sbillf if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 56252400Sbillf log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n", 56352400Sbillf strerror(errno)); 56452400Sbillf free(sp); 56552400Sbillf return; 56652400Sbillf } 56752400Sbillf ep = sp + needed; 56852400Sbillf 56952400Sbillf for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 57052400Sbillf rtm = (struct rt_msghdr *)cp; 57152400Sbillf route_ParseHdr(rtm, sa); 57252400Sbillf if (sa[RTAX_DST] && sa[RTAX_DST]->sa_family == AF_INET && 57352400Sbillf sa[RTAX_GATEWAY] && /* sa[RTAX_NETMASK] && */ 57467949Sdougb rtm->rtm_index == bundle->iface->index && 57552400Sbillf (sa[RTAX_GATEWAY]->sa_family == AF_INET || 57652400Sbillf sa[RTAX_GATEWAY]->sa_family == AF_LINK)) { 57752400Sbillf log_Printf(LogTCPIP, "route_UpdateMTU: Netif: %d (%s), dst %s, mtu %d\n", 57852400Sbillf rtm->rtm_index, Index2Nam(rtm->rtm_index), 57952400Sbillf inet_ntoa(((struct sockaddr_in *)sa[RTAX_DST])->sin_addr), 58052400Sbillf bundle->mtu); 58167949Sdougb rt_Update(bundle, in[RTAX_DST]->sin_addr, 58277323Sdougb in[RTAX_GATEWAY]->sin_addr); 58377323Sdougb } 58467949Sdougb } 58552400Sbillf 58652400Sbillf free(sp); 58777323Sdougb} 58877323Sdougb 58952400Sbillfint 59052400SbillfGetIfIndex(char *name) 59152400Sbillf{ 59264625Sgshapiro int idx; 59352400Sbillf const char *got; 59452400Sbillf 59552400Sbillf idx = 1; 59652400Sbillf while (strcmp(got = Index2Nam(idx), "???")) 59752400Sbillf if (!strcmp(got, name)) 59852400Sbillf return idx; 59967949Sdougb else 60052400Sbillf idx++; 60152400Sbillf return -1; 60252400Sbillf} 60352400Sbillf 60477335Sdougbvoid 60577335Sdougbroute_Change(struct bundle *bundle, struct sticky_route *r, 60652400Sbillf struct in_addr me, struct in_addr peer, struct in_addr dns[2]) 60752400Sbillf{ 60867859Sdougb struct in_addr none, del; 60967859Sdougb 61067859Sdougb none.s_addr = INADDR_ANY; 61167859Sdougb for (; r; r = r->next) { 61267859Sdougb if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) { 61352400Sbillf del.s_addr = r->dst.s_addr & r->mask.s_addr; 61452400Sbillf rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 61552400Sbillf r->dst = me; 61652400Sbillf if (r->type & ROUTE_GWHISADDR) 61752400Sbillf r->gw = peer; 61852400Sbillf } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) { 61967949Sdougb del.s_addr = r->dst.s_addr & r->mask.s_addr; 62052400Sbillf rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 62152400Sbillf r->dst = peer; 62252400Sbillf if (r->type & ROUTE_GWHISADDR) 62367859Sdougb r->gw = peer; 62467859Sdougb } else if ((r->type & ROUTE_DSTDNS0) && r->dst.s_addr != peer.s_addr) { 62577335Sdougb del.s_addr = r->dst.s_addr & r->mask.s_addr; 62677335Sdougb rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 62777335Sdougb r->dst = dns[0]; 62877335Sdougb if (r->type & ROUTE_GWHISADDR) 62977335Sdougb r->gw = peer; 63067859Sdougb } else if ((r->type & ROUTE_DSTDNS1) && r->dst.s_addr != peer.s_addr) { 63152400Sbillf del.s_addr = r->dst.s_addr & r->mask.s_addr; 63252400Sbillf rt_Set(bundle, RTM_DELETE, del, none, none, 1, 0); 63352400Sbillf r->dst = dns[1]; 63452400Sbillf if (r->type & ROUTE_GWHISADDR) 63552400Sbillf r->gw = peer; 63652400Sbillf } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr) 63752400Sbillf r->gw = peer; 63852400Sbillf rt_Set(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1, 0); 63967949Sdougb } 64067949Sdougb} 64167949Sdougb 64252400Sbillfvoid 64352400Sbillfroute_Add(struct sticky_route **rp, int type, struct in_addr dst, 64467949Sdougb struct in_addr mask, struct in_addr gw) 64552400Sbillf{ 64652400Sbillf struct sticky_route *r; 64752400Sbillf int dsttype = type & ROUTE_DSTANY; 64852400Sbillf 64952400Sbillf r = NULL; 65052400Sbillf while (*rp) { 65152400Sbillf if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 65252400Sbillf (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) { 65352400Sbillf /* Oops, we already have this route - unlink it */ 65452400Sbillf free(r); /* impossible really */ 65552400Sbillf r = *rp; 65652400Sbillf *rp = r->next; 65767949Sdougb } else 65852400Sbillf rp = &(*rp)->next; 65952400Sbillf } 66052400Sbillf 66152400Sbillf if (!r) 66252400Sbillf r = (struct sticky_route *)malloc(sizeof(struct sticky_route)); 66352400Sbillf r->type = type; 66467949Sdougb r->next = NULL; 66567949Sdougb r->dst = dst; 66667949Sdougb r->mask = mask; 66767949Sdougb r->gw = gw; 66867949Sdougb *rp = r; 66967949Sdougb} 67052400Sbillf 67152400Sbillfvoid 67252400Sbillfroute_Delete(struct sticky_route **rp, int type, struct in_addr dst) 67352400Sbillf{ 67467949Sdougb struct sticky_route *r; 67567949Sdougb int dsttype = type & ROUTE_DSTANY; 67667949Sdougb 67752400Sbillf for (; *rp; rp = &(*rp)->next) { 67867949Sdougb if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) || 67967949Sdougb (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) { 68067949Sdougb r = *rp; 68167949Sdougb *rp = r->next; 68267949Sdougb free(r); 68367949Sdougb break; 68452400Sbillf } 68552400Sbillf } 68667949Sdougb} 68752400Sbillf 68852400Sbillfvoid 68967949Sdougbroute_DeleteAll(struct sticky_route **rp) 69067949Sdougb{ 69167949Sdougb struct sticky_route *r, *rn; 69267949Sdougb 69367949Sdougb for (r = *rp; r; r = rn) { 69477325Sdougb rn = r->next; 69577325Sdougb free(r); 69677325Sdougb } 69777325Sdougb *rp = NULL; 69877325Sdougb} 69977325Sdougb 70077325Sdougbvoid 70177325Sdougbroute_ShowSticky(struct prompt *p, struct sticky_route *r, const char *tag, 70277325Sdougb int indent) 70377325Sdougb{ 70477325Sdougb int def; 70577325Sdougb int tlen = strlen(tag); 70677325Sdougb 70777325Sdougb if (tlen + 2 > indent) 70877325Sdougb prompt_Printf(p, "%s:\n%*s", tag, indent, ""); 70977325Sdougb else 71067949Sdougb prompt_Printf(p, "%s:%*s", tag, indent - tlen - 1, ""); 71167949Sdougb 71267949Sdougb for (; r; r = r->next) { 71352400Sbillf def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY; 71452400Sbillf 71552400Sbillf prompt_Printf(p, "%*sadd ", tlen ? 0 : indent, ""); 71652400Sbillf tlen = 0; 71752400Sbillf if (r->type & ROUTE_DSTMYADDR) 71852400Sbillf prompt_Printf(p, "MYADDR"); 71952400Sbillf else if (r->type & ROUTE_DSTHISADDR) 72073651Sdougb prompt_Printf(p, "HISADDR"); 72173651Sdougb else if (r->type & ROUTE_DSTDNS0) 72252400Sbillf prompt_Printf(p, "DNS0"); 72367949Sdougb else if (r->type & ROUTE_DSTDNS1) 72473651Sdougb prompt_Printf(p, "DNS1"); 72567949Sdougb else if (!def) 72667949Sdougb prompt_Printf(p, "%s", inet_ntoa(r->dst)); 72767949Sdougb 72867949Sdougb if (def) 72952400Sbillf prompt_Printf(p, "default "); 73052400Sbillf else 73152400Sbillf prompt_Printf(p, " %s ", inet_ntoa(r->mask)); 73252400Sbillf 73352400Sbillf if (r->type & ROUTE_GWHISADDR) 73452400Sbillf prompt_Printf(p, "HISADDR\n"); 73552400Sbillf else 73652400Sbillf prompt_Printf(p, "%s\n", inet_ntoa(r->gw)); 73752400Sbillf } 73852400Sbillf} 73952400Sbillf 74067949Sdougbstruct rtmsg { 74152400Sbillf struct rt_msghdr m_rtm; 74252400Sbillf char m_space[64]; 74352400Sbillf}; 74477323Sdougb 74577323Sdougbint 74677323Sdougbrt_Set(struct bundle *bundle, int cmd, struct in_addr dst, 74767859Sdougb struct in_addr gateway, struct in_addr mask, int bang, int ssh) 74852400Sbillf{ 74952400Sbillf struct rtmsg rtmes; 75052400Sbillf int s, nb, wb; 75158910Salfred char *cp; 75258910Salfred const char *cmdstr; 75352400Sbillf struct sockaddr_in rtdata; 75452400Sbillf int result = 1; 75552400Sbillf 75652400Sbillf if (bang) 75752400Sbillf cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 75852400Sbillf else 75952400Sbillf cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 76052400Sbillf s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 76152400Sbillf if (s < 0) { 76252400Sbillf log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno)); 76352534Sbillf return result; 76452400Sbillf } 76552400Sbillf memset(&rtmes, '\0', sizeof rtmes); 76652400Sbillf rtmes.m_rtm.rtm_version = RTM_VERSION; 76752400Sbillf rtmes.m_rtm.rtm_type = cmd; 76852400Sbillf rtmes.m_rtm.rtm_addrs = RTA_DST; 76952400Sbillf rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 77052400Sbillf rtmes.m_rtm.rtm_pid = getpid(); 77177335Sdougb rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 77252400Sbillf 77352400Sbillf if (cmd == RTM_ADD) { 77452400Sbillf if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 77552400Sbillf rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 77667859Sdougb rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 77767859Sdougb } 77867859Sdougb if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 77952400Sbillf rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 78052400Sbillf rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 78152400Sbillf } 78252400Sbillf } 78352400Sbillf 78452400Sbillf memset(&rtdata, '\0', sizeof rtdata); 78552400Sbillf rtdata.sin_len = sizeof rtdata; 78652400Sbillf rtdata.sin_family = AF_INET; 78752400Sbillf rtdata.sin_port = 0; 78852400Sbillf rtdata.sin_addr = dst; 78952400Sbillf 79052400Sbillf cp = rtmes.m_space; 79152400Sbillf memcpy(cp, &rtdata, rtdata.sin_len); 79252400Sbillf cp += rtdata.sin_len; 79352400Sbillf if (cmd == RTM_ADD) { 79452400Sbillf if (gateway.s_addr == INADDR_ANY) { 79568153Sdougb if (!ssh) 79668153Sdougb log_Printf(LogERROR, "rt_Set: Cannot add a route with" 79768153Sdougb " destination 0.0.0.0\n"); 79873651Sdougb close(s); 79973651Sdougb return result; 80073651Sdougb } else { 80173651Sdougb rtdata.sin_addr = gateway; 80277323Sdougb memcpy(cp, &rtdata, rtdata.sin_len); 80377323Sdougb cp += rtdata.sin_len; 80473651Sdougb rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 80573651Sdougb } 80673651Sdougb } 80773651Sdougb 80868153Sdougb if (dst.s_addr == INADDR_ANY) 80977323Sdougb mask.s_addr = INADDR_ANY; 81077323Sdougb 81168153Sdougb if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 81273651Sdougb rtdata.sin_addr = mask; 81373651Sdougb memcpy(cp, &rtdata, rtdata.sin_len); 81468153Sdougb cp += rtdata.sin_len; 81568153Sdougb rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 81668153Sdougb } 81773651Sdougb 81873651Sdougb nb = cp - (char *)&rtmes; 81973651Sdougb rtmes.m_rtm.rtm_msglen = nb; 82073651Sdougb wb = ID0write(s, &rtmes, nb); 82173651Sdougb if (wb < 0) { 82277335Sdougb log_Printf(LogTCPIP, "rt_Set failure:\n"); 82373651Sdougb log_Printf(LogTCPIP, "rt_Set: Cmd = %s\n", cmdstr); 82473651Sdougb log_Printf(LogTCPIP, "rt_Set: Dst = %s\n", inet_ntoa(dst)); 82573651Sdougb log_Printf(LogTCPIP, "rt_Set: Gateway = %s\n", 82673651Sdougb inet_ntoa(gateway)); 82777335Sdougb log_Printf(LogTCPIP, "rt_Set: Mask = %s\n", inet_ntoa(mask)); 82877335Sdougbfailed: 82973651Sdougb if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 83073651Sdougb (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 83177335Sdougb if (!bang) { 83277335Sdougb log_Printf(LogWARN, "Add route failed: %s already exists\n", 83377335Sdougb dst.s_addr == 0 ? "default" : inet_ntoa(dst)); 83477335Sdougb result = 0; /* Don't add to our dynamic list */ 83577335Sdougb } else { 83677335Sdougb rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 83773651Sdougb if ((wb = ID0write(s, &rtmes, nb)) < 0) 83877335Sdougb goto failed; 83977335Sdougb } 84077335Sdougb } else if (cmd == RTM_DELETE && 84177335Sdougb (rtmes.m_rtm.rtm_errno == ESRCH || 84273651Sdougb (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 84373651Sdougb if (!bang) 84473651Sdougb log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 84573651Sdougb inet_ntoa(dst)); 84673651Sdougb } else if (rtmes.m_rtm.rtm_errno == 0) { 84773651Sdougb if (!ssh || errno != ENETUNREACH) 84852400Sbillf log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 84952400Sbillf inet_ntoa(dst), strerror(errno)); 85052400Sbillf } else 85152400Sbillf log_Printf(LogWARN, "%s route failed: %s: %s\n", 85277335Sdougb cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 85377335Sdougb } 85477335Sdougb 85552400Sbillf log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 85652400Sbillf wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 85752400Sbillf close(s); 85852400Sbillf 85952400Sbillf return result; 86052400Sbillf} 86152400Sbillf 86277335Sdougbvoid 86377335Sdougbrt_Update(struct bundle *bundle, struct in_addr dst, struct in_addr gw) 86477335Sdougb{ 86577335Sdougb struct rtmsg rtmes; 86677335Sdougb int s, wb; 86777335Sdougb struct sockaddr_in rtdata; 86877335Sdougb 86977335Sdougb s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 87077335Sdougb if (s < 0) { 87177335Sdougb log_Printf(LogERROR, "rt_Update: socket(): %s\n", strerror(errno)); 87252400Sbillf return; 87352400Sbillf } 87452400Sbillf 87552400Sbillf memset(&rtmes, '\0', sizeof rtmes); 87652400Sbillf rtmes.m_rtm.rtm_version = RTM_VERSION; 87752400Sbillf rtmes.m_rtm.rtm_type = RTM_CHANGE; 87852400Sbillf rtmes.m_rtm.rtm_addrs = RTA_DST; 87952400Sbillf rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 88077335Sdougb rtmes.m_rtm.rtm_pid = getpid(); 88177335Sdougb rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 88277335Sdougb 88352400Sbillf if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 88452400Sbillf rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 88552400Sbillf rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 88652400Sbillf } 88752400Sbillf 88852400Sbillf if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 88952400Sbillf rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 89052400Sbillf rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 89177335Sdougb } 89277335Sdougb 89377335Sdougb rtmes.m_rtm.rtm_rmx.rmx_mtu = bundle->mtu; 89477335Sdougb rtmes.m_rtm.rtm_inits |= RTV_MTU; 89577335Sdougb 89677335Sdougb memset(&rtdata, '\0', sizeof rtdata); 89777335Sdougb rtdata.sin_len = sizeof rtdata; 89877335Sdougb rtdata.sin_family = AF_INET; 89977335Sdougb rtdata.sin_port = 0; 90052400Sbillf rtdata.sin_addr = dst; 90152400Sbillf 90252400Sbillf memcpy(rtmes.m_space, &rtdata, rtdata.sin_len); 90352400Sbillf rtmes.m_rtm.rtm_msglen = rtmes.m_space + rtdata.sin_len - (char *)&rtmes; 90452400Sbillf 90567949Sdougb wb = ID0write(s, &rtmes, rtmes.m_rtm.rtm_msglen); 90667949Sdougb if (wb < 0) { 90767949Sdougb log_Printf(LogTCPIP, "rt_Update failure:\n"); 90867949Sdougb log_Printf(LogTCPIP, "rt_Update: Dst = %s\n", inet_ntoa(dst)); 90952400Sbillf log_Printf(LogTCPIP, "rt_Update: Gateway = %s\n", inet_ntoa(gw)); 91067850Sdougb 911 if (rtmes.m_rtm.rtm_errno == 0) 912 log_Printf(LogWARN, "%s: Change route failed: errno: %s\n", 913 inet_ntoa(dst), strerror(errno)); 914 else 915 log_Printf(LogWARN, "%s: Change route failed: %s\n", 916 inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 917 } 918 log_Printf(LogDEBUG, "wrote %d: cmd = Change, dst = %x, gateway = %x\n", 919 wb, (unsigned)dst.s_addr, (unsigned)gw.s_addr); 920 close(s); 921} 922