xref: /freebsd/usr.sbin/ppp/route.c (revision 183df580c7eef868f7b95a6b2858452bb49a162f)
11ae349f5Scvs2svn /*
21ae349f5Scvs2svn  *	      PPP Routing related Module
31ae349f5Scvs2svn  *
41ae349f5Scvs2svn  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
51ae349f5Scvs2svn  *
61ae349f5Scvs2svn  *   Copyright (C) 1994, Internet Initiative Japan, Inc. All rights reserverd.
71ae349f5Scvs2svn  *
81ae349f5Scvs2svn  * Redistribution and use in source and binary forms are permitted
91ae349f5Scvs2svn  * provided that the above copyright notice and this paragraph are
101ae349f5Scvs2svn  * duplicated in all such forms and that any documentation,
111ae349f5Scvs2svn  * advertising materials, and other materials related to such
121ae349f5Scvs2svn  * distribution and use acknowledge that the software was developed
131ae349f5Scvs2svn  * by the Internet Initiative Japan, Inc.  The name of the
141ae349f5Scvs2svn  * IIJ may not be used to endorse or promote products derived
151ae349f5Scvs2svn  * from this software without specific prior written permission.
161ae349f5Scvs2svn  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171ae349f5Scvs2svn  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181ae349f5Scvs2svn  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191ae349f5Scvs2svn  *
20183df580SBrian Somers  * $Id: route.c,v 1.42.2.22 1998/05/05 23:30:12 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  */
231ae349f5Scvs2svn 
242764b86aSBrian Somers #include <sys/types.h>
251ae349f5Scvs2svn #include <sys/socket.h>
261ae349f5Scvs2svn #include <net/if_types.h>
271ae349f5Scvs2svn #include <net/route.h>
281ae349f5Scvs2svn #include <net/if.h>
291ae349f5Scvs2svn #include <netinet/in.h>
301ae349f5Scvs2svn #include <arpa/inet.h>
311ae349f5Scvs2svn #include <net/if_dl.h>
32eaa4df37SBrian Somers #include <netinet/in_systm.h>
33eaa4df37SBrian Somers #include <netinet/ip.h>
341fa665f5SBrian Somers #include <sys/un.h>
351ae349f5Scvs2svn 
361ae349f5Scvs2svn #include <errno.h>
371ae349f5Scvs2svn #include <stdio.h>
381ae349f5Scvs2svn #include <stdlib.h>
391ae349f5Scvs2svn #include <string.h>
401ae349f5Scvs2svn #include <sys/sysctl.h>
4185b542cfSBrian Somers #include <termios.h>
421ae349f5Scvs2svn 
431ae349f5Scvs2svn #include "command.h"
441ae349f5Scvs2svn #include "mbuf.h"
451ae349f5Scvs2svn #include "log.h"
461ae349f5Scvs2svn #include "defs.h"
471ae349f5Scvs2svn #include "iplist.h"
4829e275ceSBrian Somers #include "timer.h"
4929e275ceSBrian Somers #include "throughput.h"
50879ed6faSBrian Somers #include "lqr.h"
518c07a7b2SBrian Somers #include "hdlc.h"
527308ec68SBrian Somers #include "fsm.h"
533b0f8d2eSBrian Somers #include "lcp.h"
543b0f8d2eSBrian Somers #include "ccp.h"
553b0f8d2eSBrian Somers #include "link.h"
56eaa4df37SBrian Somers #include "slcompress.h"
5729e275ceSBrian Somers #include "ipcp.h"
585ca5389aSBrian Somers #include "filter.h"
592f786681SBrian Somers #include "descriptor.h"
603b0f8d2eSBrian Somers #include "mp.h"
615828db6dSBrian Somers #include "bundle.h"
621ae349f5Scvs2svn #include "route.h"
6385b542cfSBrian Somers #include "prompt.h"
641ae349f5Scvs2svn 
651ae349f5Scvs2svn static void
66b6217683SBrian Somers p_sockaddr(struct prompt *prompt, struct sockaddr *phost,
67b6217683SBrian Somers            struct sockaddr *pmask, int width)
681ae349f5Scvs2svn {
691ae349f5Scvs2svn   char buf[29];
701ae349f5Scvs2svn   struct sockaddr_in *ihost = (struct sockaddr_in *)phost;
711ae349f5Scvs2svn   struct sockaddr_in *mask = (struct sockaddr_in *)pmask;
721ae349f5Scvs2svn   struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;
731ae349f5Scvs2svn 
741ae349f5Scvs2svn   switch (phost->sa_family) {
751ae349f5Scvs2svn   case AF_INET:
761ae349f5Scvs2svn     if (!phost)
771ae349f5Scvs2svn       buf[0] = '\0';
781ae349f5Scvs2svn     else if (ihost->sin_addr.s_addr == INADDR_ANY)
791ae349f5Scvs2svn       strcpy(buf, "default");
801ae349f5Scvs2svn     else if (!mask)
811ae349f5Scvs2svn       strcpy(buf, inet_ntoa(ihost->sin_addr));
821ae349f5Scvs2svn     else {
831ae349f5Scvs2svn       u_int msk = ntohl(mask->sin_addr.s_addr);
841ae349f5Scvs2svn       u_int tst;
851ae349f5Scvs2svn       int bits;
861ae349f5Scvs2svn       int len;
871ae349f5Scvs2svn       struct sockaddr_in net;
881ae349f5Scvs2svn 
891ae349f5Scvs2svn       for (tst = 1, bits=32; tst; tst <<= 1, bits--)
901ae349f5Scvs2svn         if (msk & tst)
911ae349f5Scvs2svn           break;
921ae349f5Scvs2svn 
931ae349f5Scvs2svn       for (tst <<=1; tst; tst <<= 1)
941ae349f5Scvs2svn         if (!(msk & tst))
951ae349f5Scvs2svn           break;
961ae349f5Scvs2svn 
971ae349f5Scvs2svn       net.sin_addr.s_addr = ihost->sin_addr.s_addr & mask->sin_addr.s_addr;
981ae349f5Scvs2svn       strcpy(buf, inet_ntoa(net.sin_addr));
991ae349f5Scvs2svn       for (len = strlen(buf); len > 3; buf[len-=2] = '\0')
1001ae349f5Scvs2svn         if (strcmp(buf+len-2, ".0"))
1011ae349f5Scvs2svn           break;
1021ae349f5Scvs2svn 
1031ae349f5Scvs2svn       if (tst)    /* non-contiguous :-( */
1041ae349f5Scvs2svn         sprintf(buf+strlen(buf),"&0x%08x", msk);
1051ae349f5Scvs2svn       else
1061ae349f5Scvs2svn         sprintf(buf+strlen(buf), "/%d", bits);
1071ae349f5Scvs2svn     }
1081ae349f5Scvs2svn     break;
1091ae349f5Scvs2svn 
1101ae349f5Scvs2svn   case AF_LINK:
1111ae349f5Scvs2svn     if (dl->sdl_nlen)
1121ae349f5Scvs2svn       snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
113e43ebac1SBrian Somers     else if (dl->sdl_alen) {
114e43ebac1SBrian Somers       if (dl->sdl_type == IFT_ETHER) {
1151ae349f5Scvs2svn         if (dl->sdl_alen < sizeof buf / 3) {
1161ae349f5Scvs2svn           int f;
1171ae349f5Scvs2svn           u_char *MAC;
1181ae349f5Scvs2svn 
1191ae349f5Scvs2svn           MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
1201ae349f5Scvs2svn           for (f = 0; f < dl->sdl_alen; f++)
1211ae349f5Scvs2svn             sprintf(buf+f*3, "%02x:", MAC[f]);
1221ae349f5Scvs2svn           buf[f*3-1] = '\0';
1231ae349f5Scvs2svn         } else
1241ae349f5Scvs2svn 	  strcpy(buf, "??:??:??:??:??:??");
125e43ebac1SBrian Somers       } else
1261ae349f5Scvs2svn         sprintf(buf, "<IFT type %d>", dl->sdl_type);
127e43ebac1SBrian Somers     }  else if (dl->sdl_slen)
1281ae349f5Scvs2svn       sprintf(buf, "<slen %d?>", dl->sdl_slen);
1291ae349f5Scvs2svn     else
1301ae349f5Scvs2svn       sprintf(buf, "link#%d", dl->sdl_index);
1311ae349f5Scvs2svn     break;
1321ae349f5Scvs2svn 
1331ae349f5Scvs2svn   default:
1341ae349f5Scvs2svn     sprintf(buf, "<AF type %d>", phost->sa_family);
1351ae349f5Scvs2svn     break;
1361ae349f5Scvs2svn   }
1371ae349f5Scvs2svn 
138b6217683SBrian Somers   prompt_Printf(prompt, "%-*s ", width-1, buf);
1391ae349f5Scvs2svn }
1401ae349f5Scvs2svn 
1411ae349f5Scvs2svn static struct bits {
1421ae349f5Scvs2svn   u_long b_mask;
1431ae349f5Scvs2svn   char b_val;
1441ae349f5Scvs2svn } bits[] = {
1451ae349f5Scvs2svn   { RTF_UP, 'U' },
1461ae349f5Scvs2svn   { RTF_GATEWAY, 'G' },
1471ae349f5Scvs2svn   { RTF_HOST, 'H' },
1481ae349f5Scvs2svn   { RTF_REJECT, 'R' },
1491ae349f5Scvs2svn   { RTF_DYNAMIC, 'D' },
1501ae349f5Scvs2svn   { RTF_MODIFIED, 'M' },
1511ae349f5Scvs2svn   { RTF_DONE, 'd' },
1521ae349f5Scvs2svn   { RTF_CLONING, 'C' },
1531ae349f5Scvs2svn   { RTF_XRESOLVE, 'X' },
1541ae349f5Scvs2svn   { RTF_LLINFO, 'L' },
1551ae349f5Scvs2svn   { RTF_STATIC, 'S' },
1561ae349f5Scvs2svn   { RTF_PROTO1, '1' },
1571ae349f5Scvs2svn   { RTF_PROTO2, '2' },
1581ae349f5Scvs2svn   { RTF_BLACKHOLE, 'B' },
1591ae349f5Scvs2svn #ifdef RTF_WASCLONED
1601ae349f5Scvs2svn   { RTF_WASCLONED, 'W' },
1611ae349f5Scvs2svn #endif
1621ae349f5Scvs2svn #ifdef RTF_PRCLONING
1631ae349f5Scvs2svn   { RTF_PRCLONING, 'c' },
1641ae349f5Scvs2svn #endif
1651ae349f5Scvs2svn #ifdef RTF_PROTO3
1661ae349f5Scvs2svn   { RTF_PROTO3, '3' },
1671ae349f5Scvs2svn #endif
1681ae349f5Scvs2svn #ifdef RTF_BROADCAST
1691ae349f5Scvs2svn   { RTF_BROADCAST, 'b' },
1701ae349f5Scvs2svn #endif
1711ae349f5Scvs2svn   { 0, '\0' }
1721ae349f5Scvs2svn };
1731ae349f5Scvs2svn 
1741ae349f5Scvs2svn #ifndef RTF_WASCLONED
1751ae349f5Scvs2svn #define RTF_WASCLONED (0)
1761ae349f5Scvs2svn #endif
1771ae349f5Scvs2svn 
1781ae349f5Scvs2svn static void
179b6217683SBrian Somers p_flags(struct prompt *prompt, u_long f, int max)
1801ae349f5Scvs2svn {
1811ae349f5Scvs2svn   char name[33], *flags;
1821ae349f5Scvs2svn   register struct bits *p = bits;
1831ae349f5Scvs2svn 
1841ae349f5Scvs2svn   if (max > sizeof name - 1)
1851ae349f5Scvs2svn     max = sizeof name - 1;
1861ae349f5Scvs2svn 
1871ae349f5Scvs2svn   for (flags = name; p->b_mask && flags - name < max; p++)
1881ae349f5Scvs2svn     if (p->b_mask & f)
1891ae349f5Scvs2svn       *flags++ = p->b_val;
1901ae349f5Scvs2svn   *flags = '\0';
191b6217683SBrian Somers   prompt_Printf(prompt, "%-*.*s", max, max, name);
1921ae349f5Scvs2svn }
1931ae349f5Scvs2svn 
1941ae349f5Scvs2svn const char *
1951ae349f5Scvs2svn Index2Nam(int idx)
1961ae349f5Scvs2svn {
1971ae349f5Scvs2svn   static char **ifs;
1981ae349f5Scvs2svn   static int nifs, debug_done;
1991ae349f5Scvs2svn 
2001ae349f5Scvs2svn   if (!nifs) {
2011ae349f5Scvs2svn     int mib[6], have, had;
2021ae349f5Scvs2svn     size_t needed;
2031ae349f5Scvs2svn     char *buf, *ptr, *end;
2041ae349f5Scvs2svn     struct sockaddr_dl *dl;
2051ae349f5Scvs2svn     struct if_msghdr *ifm;
2061ae349f5Scvs2svn 
2071ae349f5Scvs2svn     mib[0] = CTL_NET;
2081ae349f5Scvs2svn     mib[1] = PF_ROUTE;
2091ae349f5Scvs2svn     mib[2] = 0;
2101ae349f5Scvs2svn     mib[3] = 0;
2111ae349f5Scvs2svn     mib[4] = NET_RT_IFLIST;
2121ae349f5Scvs2svn     mib[5] = 0;
2131ae349f5Scvs2svn 
2141ae349f5Scvs2svn     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
215dd7e2610SBrian Somers       log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n", strerror(errno));
2161ae349f5Scvs2svn       return "???";
2171ae349f5Scvs2svn     }
2181ae349f5Scvs2svn     if ((buf = malloc(needed)) == NULL)
2191ae349f5Scvs2svn       return "???";
2201ae349f5Scvs2svn     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
2211ae349f5Scvs2svn       free(buf);
2221ae349f5Scvs2svn       return "???";
2231ae349f5Scvs2svn     }
2241ae349f5Scvs2svn     end = buf + needed;
2251ae349f5Scvs2svn 
2261ae349f5Scvs2svn     have = 0;
2271ae349f5Scvs2svn     for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
2281ae349f5Scvs2svn       ifm = (struct if_msghdr *)ptr;
2291ae349f5Scvs2svn       dl = (struct sockaddr_dl *)(ifm + 1);
2301ae349f5Scvs2svn       if (ifm->ifm_index > 0) {
2311ae349f5Scvs2svn         if (ifm->ifm_index > have) {
2321ae349f5Scvs2svn           had = have;
2331ae349f5Scvs2svn           have = ifm->ifm_index + 5;
2341ae349f5Scvs2svn           if (had)
2351ae349f5Scvs2svn             ifs = (char **)realloc(ifs, sizeof(char *) * have);
2361ae349f5Scvs2svn           else
2371ae349f5Scvs2svn             ifs = (char **)malloc(sizeof(char *) * have);
2381ae349f5Scvs2svn           if (!ifs) {
239dd7e2610SBrian Somers             log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno));
2401ae349f5Scvs2svn             nifs = 0;
2411ae349f5Scvs2svn             return "???";
2421ae349f5Scvs2svn           }
2431ae349f5Scvs2svn           memset(ifs + had, '\0', sizeof(char *) * (have - had));
2441ae349f5Scvs2svn         }
2451ae349f5Scvs2svn         if (ifs[ifm->ifm_index-1] == NULL) {
2461ae349f5Scvs2svn           ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1);
2471ae349f5Scvs2svn           memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen);
2481ae349f5Scvs2svn           ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0';
2491ae349f5Scvs2svn           if (nifs < ifm->ifm_index)
2501ae349f5Scvs2svn             nifs = ifm->ifm_index;
2511ae349f5Scvs2svn         }
252dd7e2610SBrian Somers       } else if (log_IsKept(LogDEBUG))
253dd7e2610SBrian Somers         log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n",
2541ae349f5Scvs2svn                   ifm->ifm_index);
2551ae349f5Scvs2svn     }
2561ae349f5Scvs2svn     free(buf);
2571ae349f5Scvs2svn   }
2581ae349f5Scvs2svn 
259dd7e2610SBrian Somers   if (log_IsKept(LogDEBUG) && !debug_done) {
2601ae349f5Scvs2svn     int f;
2611ae349f5Scvs2svn 
262dd7e2610SBrian Somers     log_Printf(LogDEBUG, "Found the following interfaces:\n");
2631ae349f5Scvs2svn     for (f = 0; f < nifs; f++)
2641ae349f5Scvs2svn       if (ifs[f] != NULL)
265dd7e2610SBrian Somers         log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
2661ae349f5Scvs2svn     debug_done = 1;
2671ae349f5Scvs2svn   }
2681ae349f5Scvs2svn 
2691ae349f5Scvs2svn   if (idx < 1 || idx > nifs || ifs[idx-1] == NULL)
2701ae349f5Scvs2svn     return "???";
2711ae349f5Scvs2svn 
2721ae349f5Scvs2svn   return ifs[idx-1];
2731ae349f5Scvs2svn }
2741ae349f5Scvs2svn 
2751ae349f5Scvs2svn int
276dd7e2610SBrian Somers route_Show(struct cmdargs const *arg)
2771ae349f5Scvs2svn {
2781ae349f5Scvs2svn   struct rt_msghdr *rtm;
2791ae349f5Scvs2svn   struct sockaddr *sa_dst, *sa_gw, *sa_mask;
2801ae349f5Scvs2svn   char *sp, *ep, *cp, *wp;
2811ae349f5Scvs2svn   size_t needed;
2821ae349f5Scvs2svn   int mib[6];
2831ae349f5Scvs2svn 
2841ae349f5Scvs2svn   mib[0] = CTL_NET;
2851ae349f5Scvs2svn   mib[1] = PF_ROUTE;
2861ae349f5Scvs2svn   mib[2] = 0;
2871ae349f5Scvs2svn   mib[3] = 0;
2881ae349f5Scvs2svn   mib[4] = NET_RT_DUMP;
2891ae349f5Scvs2svn   mib[5] = 0;
2901ae349f5Scvs2svn   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
291dd7e2610SBrian Somers     log_Printf(LogERROR, "route_Show: sysctl: estimate: %s\n", strerror(errno));
2921ae349f5Scvs2svn     return (1);
2931ae349f5Scvs2svn   }
2941ae349f5Scvs2svn   if (needed < 0)
2951ae349f5Scvs2svn     return (1);
2961ae349f5Scvs2svn   sp = malloc(needed);
2971ae349f5Scvs2svn   if (sp == NULL)
2981ae349f5Scvs2svn     return (1);
2991ae349f5Scvs2svn   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
300dd7e2610SBrian Somers     log_Printf(LogERROR, "route_Show: sysctl: getroute: %s\n", strerror(errno));
3011ae349f5Scvs2svn     free(sp);
3021ae349f5Scvs2svn     return (1);
3031ae349f5Scvs2svn   }
3041ae349f5Scvs2svn   ep = sp + needed;
3051ae349f5Scvs2svn 
306b6217683SBrian Somers   prompt_Printf(arg->prompt, "%-20s%-20sFlags  Netif\n",
307b6217683SBrian Somers                 "Destination", "Gateway");
3081ae349f5Scvs2svn   for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
3091ae349f5Scvs2svn     rtm = (struct rt_msghdr *) cp;
3101ae349f5Scvs2svn     wp = (char *)(rtm+1);
3111ae349f5Scvs2svn 
3121ae349f5Scvs2svn     if (rtm->rtm_addrs & RTA_DST) {
3131ae349f5Scvs2svn       sa_dst = (struct sockaddr *)wp;
3141ae349f5Scvs2svn       wp += sa_dst->sa_len;
3151ae349f5Scvs2svn     } else
3161ae349f5Scvs2svn       sa_dst = NULL;
3171ae349f5Scvs2svn 
3181ae349f5Scvs2svn     if (rtm->rtm_addrs & RTA_GATEWAY) {
3191ae349f5Scvs2svn       sa_gw = (struct sockaddr *)wp;
3201ae349f5Scvs2svn       wp += sa_gw->sa_len;
3211ae349f5Scvs2svn     } else
3221ae349f5Scvs2svn       sa_gw = NULL;
3231ae349f5Scvs2svn 
3241ae349f5Scvs2svn     if (rtm->rtm_addrs & RTA_NETMASK) {
3251ae349f5Scvs2svn       sa_mask = (struct sockaddr *)wp;
3261ae349f5Scvs2svn       wp += sa_mask->sa_len;
3271ae349f5Scvs2svn     } else
3281ae349f5Scvs2svn       sa_mask = NULL;
3291ae349f5Scvs2svn 
330b6217683SBrian Somers     p_sockaddr(arg->prompt, sa_dst, sa_mask, 20);
331b6217683SBrian Somers     p_sockaddr(arg->prompt, sa_gw, NULL, 20);
3321ae349f5Scvs2svn 
333b6217683SBrian Somers     p_flags(arg->prompt, rtm->rtm_flags, 6);
334b6217683SBrian Somers     prompt_Printf(arg->prompt, " %s\n", Index2Nam(rtm->rtm_index));
3351ae349f5Scvs2svn   }
3361ae349f5Scvs2svn   free(sp);
3371ae349f5Scvs2svn   return 0;
3381ae349f5Scvs2svn }
3391ae349f5Scvs2svn 
3401ae349f5Scvs2svn /*
3411ae349f5Scvs2svn  *  Delete routes associated with our interface
3421ae349f5Scvs2svn  */
3431ae349f5Scvs2svn void
344dd7e2610SBrian Somers route_IfDelete(struct bundle *bundle, int all)
3451ae349f5Scvs2svn {
3461ae349f5Scvs2svn   struct rt_msghdr *rtm;
3471ae349f5Scvs2svn   struct sockaddr *sa;
3481ae349f5Scvs2svn   struct in_addr sa_dst, sa_none;
3491ae349f5Scvs2svn   int pass;
3501ae349f5Scvs2svn   size_t needed;
3511ae349f5Scvs2svn   char *sp, *cp, *ep;
3521ae349f5Scvs2svn   int mib[6];
3531ae349f5Scvs2svn 
354dd7e2610SBrian Somers   log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->ifIndex);
3551ae349f5Scvs2svn   sa_none.s_addr = INADDR_ANY;
3561ae349f5Scvs2svn 
3571ae349f5Scvs2svn   mib[0] = CTL_NET;
3581ae349f5Scvs2svn   mib[1] = PF_ROUTE;
3591ae349f5Scvs2svn   mib[2] = 0;
3601ae349f5Scvs2svn   mib[3] = 0;
3611ae349f5Scvs2svn   mib[4] = NET_RT_DUMP;
3621ae349f5Scvs2svn   mib[5] = 0;
3631ae349f5Scvs2svn   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
364dd7e2610SBrian Somers     log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n",
3651ae349f5Scvs2svn 	      strerror(errno));
3661ae349f5Scvs2svn     return;
3671ae349f5Scvs2svn   }
3681ae349f5Scvs2svn   if (needed < 0)
3691ae349f5Scvs2svn     return;
3701ae349f5Scvs2svn 
3711ae349f5Scvs2svn   sp = malloc(needed);
3721ae349f5Scvs2svn   if (sp == NULL)
3731ae349f5Scvs2svn     return;
3741ae349f5Scvs2svn 
3751ae349f5Scvs2svn   if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
376dd7e2610SBrian Somers     log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n",
3771ae349f5Scvs2svn 	      strerror(errno));
3781ae349f5Scvs2svn     free(sp);
3791ae349f5Scvs2svn     return;
3801ae349f5Scvs2svn   }
3811ae349f5Scvs2svn   ep = sp + needed;
3821ae349f5Scvs2svn 
3831ae349f5Scvs2svn   for (pass = 0; pass < 2; pass++) {
3841ae349f5Scvs2svn     /*
3851ae349f5Scvs2svn      * We do 2 passes.  The first deletes all cloned routes.  The second
3861ae349f5Scvs2svn      * deletes all non-cloned routes.  This is necessary to avoid
3871ae349f5Scvs2svn      * potential errors from trying to delete route X after route Y where
388ba081e43SBrian Somers      * route X was cloned from route Y (and is no longer there 'cos it
389ba081e43SBrian Somers      * may have gone with route Y).
3901ae349f5Scvs2svn      */
3911ae349f5Scvs2svn     if (RTF_WASCLONED == 0 && pass == 0)
3921ae349f5Scvs2svn       /* So we can't tell ! */
3931ae349f5Scvs2svn       continue;
3941ae349f5Scvs2svn     for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
3951ae349f5Scvs2svn       rtm = (struct rt_msghdr *) cp;
3961ae349f5Scvs2svn       sa = (struct sockaddr *) (rtm + 1);
397dd7e2610SBrian Somers       log_Printf(LogDEBUG, "route_IfDelete: addrs: %x, Netif: %d (%s),"
3981ae349f5Scvs2svn                 " flags: %x, dst: %s ?\n", rtm->rtm_addrs, rtm->rtm_index,
3991ae349f5Scvs2svn                 Index2Nam(rtm->rtm_index), rtm->rtm_flags,
4001ae349f5Scvs2svn 	        inet_ntoa(((struct sockaddr_in *) sa)->sin_addr));
4011ae349f5Scvs2svn       if (rtm->rtm_addrs & RTA_DST && rtm->rtm_addrs & RTA_GATEWAY &&
4027a6f8720SBrian Somers 	  rtm->rtm_index == bundle->ifIndex &&
4031ae349f5Scvs2svn 	  (all || (rtm->rtm_flags & RTF_GATEWAY))) {
4041ae349f5Scvs2svn         sa_dst.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
4051ae349f5Scvs2svn         sa = (struct sockaddr *)((char *)sa + sa->sa_len);
4061ae349f5Scvs2svn         if (sa->sa_family == AF_INET || sa->sa_family == AF_LINK) {
4071ae349f5Scvs2svn           if ((pass == 0 && (rtm->rtm_flags & RTF_WASCLONED)) ||
4081ae349f5Scvs2svn               (pass == 1 && !(rtm->rtm_flags & RTF_WASCLONED))) {
409dd7e2610SBrian Somers             log_Printf(LogDEBUG, "route_IfDelete: Remove it (pass %d)\n", pass);
4107a6f8720SBrian Somers             bundle_SetRoute(bundle, RTM_DELETE, sa_dst, sa_none, sa_none, 0);
4111ae349f5Scvs2svn           } else
412dd7e2610SBrian Somers             log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass);
4131ae349f5Scvs2svn         } else
414dd7e2610SBrian Somers           log_Printf(LogDEBUG,
415dd7e2610SBrian Somers                     "route_IfDelete: Can't remove routes of %d family !\n",
4161ae349f5Scvs2svn                     sa->sa_family);
4171ae349f5Scvs2svn       }
4181ae349f5Scvs2svn     }
4191ae349f5Scvs2svn   }
4201ae349f5Scvs2svn   free(sp);
4211ae349f5Scvs2svn }
4221ae349f5Scvs2svn 
4231ae349f5Scvs2svn int
4241ae349f5Scvs2svn GetIfIndex(char *name)
4251ae349f5Scvs2svn {
4261ae349f5Scvs2svn   int idx;
4271ae349f5Scvs2svn   const char *got;
4281ae349f5Scvs2svn 
4291ae349f5Scvs2svn   idx = 1;
4301ae349f5Scvs2svn   while (strcmp(got = Index2Nam(idx), "???"))
4311ae349f5Scvs2svn     if (!strcmp(got, name))
4327a6f8720SBrian Somers       return idx;
4331ae349f5Scvs2svn     else
4341ae349f5Scvs2svn       idx++;
4351ae349f5Scvs2svn   return -1;
4361ae349f5Scvs2svn }
437610b185fSBrian Somers 
438610b185fSBrian Somers void
439610b185fSBrian Somers route_Change(struct bundle *bundle, struct sticky_route *r,
440610b185fSBrian Somers              struct in_addr me, struct in_addr peer)
441610b185fSBrian Somers {
442610b185fSBrian Somers   struct in_addr none, del;
443610b185fSBrian Somers 
444610b185fSBrian Somers   none.s_addr = INADDR_ANY;
445610b185fSBrian Somers   for (; r; r = r->next) {
446610b185fSBrian Somers     if ((r->type & ROUTE_DSTMYADDR) && r->dst.s_addr != me.s_addr) {
447610b185fSBrian Somers       del.s_addr = r->dst.s_addr & r->mask.s_addr;
448610b185fSBrian Somers       bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1);
449610b185fSBrian Somers       r->dst = me;
450610b185fSBrian Somers       if (r->type & ROUTE_GWHISADDR)
451610b185fSBrian Somers         r->gw = peer;
452610b185fSBrian Somers     } else if ((r->type & ROUTE_DSTHISADDR) && r->dst.s_addr != peer.s_addr) {
453610b185fSBrian Somers       del.s_addr = r->dst.s_addr & r->mask.s_addr;
454610b185fSBrian Somers       bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1);
455610b185fSBrian Somers       r->dst = peer;
456610b185fSBrian Somers       if (r->type & ROUTE_GWHISADDR)
457610b185fSBrian Somers         r->gw = peer;
458610b185fSBrian Somers     } else if ((r->type & ROUTE_GWHISADDR) && r->gw.s_addr != peer.s_addr)
459610b185fSBrian Somers       r->gw = peer;
460610b185fSBrian Somers     else
461610b185fSBrian Somers       continue;
462610b185fSBrian Somers     bundle_SetRoute(bundle, RTM_ADD, r->dst, r->gw, r->mask, 1);
463610b185fSBrian Somers   }
464610b185fSBrian Somers }
465610b185fSBrian Somers 
466610b185fSBrian Somers void
467610b185fSBrian Somers route_Clean(struct bundle *bundle, struct sticky_route *r)
468610b185fSBrian Somers {
469610b185fSBrian Somers   struct in_addr none, del;
470610b185fSBrian Somers 
471610b185fSBrian Somers   none.s_addr = INADDR_ANY;
472610b185fSBrian Somers   for (; r; r = r->next) {
473610b185fSBrian Somers     del.s_addr = r->dst.s_addr & r->mask.s_addr;
474610b185fSBrian Somers     bundle_SetRoute(bundle, RTM_DELETE, del, none, none, 1);
475610b185fSBrian Somers   }
476610b185fSBrian Somers }
477610b185fSBrian Somers 
478610b185fSBrian Somers void
479610b185fSBrian Somers route_Add(struct sticky_route **rp, int type, struct in_addr dst,
480610b185fSBrian Somers           struct in_addr mask, struct in_addr gw)
481610b185fSBrian Somers {
482610b185fSBrian Somers   if (type != ROUTE_STATIC) {
483610b185fSBrian Somers     struct sticky_route *r;
484610b185fSBrian Somers     int dsttype = type & ROUTE_DSTANY;
485610b185fSBrian Somers 
486610b185fSBrian Somers     r = NULL;
487610b185fSBrian Somers     while (*rp) {
488183df580SBrian Somers       if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
489183df580SBrian Somers           (!dsttype && (*rp)->dst.s_addr == dst.s_addr)) {
490610b185fSBrian Somers         r = *rp;
491610b185fSBrian Somers         *rp = r->next;
492610b185fSBrian Somers       } else
493610b185fSBrian Somers         rp = &(*rp)->next;
494610b185fSBrian Somers     }
495610b185fSBrian Somers 
496610b185fSBrian Somers     if (!r)
497610b185fSBrian Somers       r = (struct sticky_route *)malloc(sizeof(struct sticky_route));
498610b185fSBrian Somers     r->type = type;
499610b185fSBrian Somers     r->next = NULL;
500610b185fSBrian Somers     r->dst = dst;
501610b185fSBrian Somers     r->mask = mask;
502610b185fSBrian Somers     r->gw = gw;
503610b185fSBrian Somers     *rp = r;
504610b185fSBrian Somers   }
505610b185fSBrian Somers }
506610b185fSBrian Somers 
507610b185fSBrian Somers void
508610b185fSBrian Somers route_Delete(struct sticky_route **rp, int type, struct in_addr dst)
509610b185fSBrian Somers {
510610b185fSBrian Somers   struct sticky_route *r;
511610b185fSBrian Somers   int dsttype = type & ROUTE_DSTANY;
512610b185fSBrian Somers 
513610b185fSBrian Somers   for (; *rp; rp = &(*rp)->next) {
514610b185fSBrian Somers     if ((dsttype && dsttype == ((*rp)->type & ROUTE_DSTANY)) ||
515610b185fSBrian Somers         (!dsttype && dst.s_addr == ((*rp)->dst.s_addr & (*rp)->mask.s_addr))) {
516610b185fSBrian Somers       r = *rp;
517610b185fSBrian Somers       *rp = r->next;
518610b185fSBrian Somers       free(r);
519610b185fSBrian Somers       break;
520610b185fSBrian Somers     }
521610b185fSBrian Somers   }
522610b185fSBrian Somers }
523610b185fSBrian Somers 
524610b185fSBrian Somers void
525610b185fSBrian Somers route_DeleteAll(struct sticky_route **rp)
526610b185fSBrian Somers {
527610b185fSBrian Somers   struct sticky_route *r, *rn;
528610b185fSBrian Somers 
529610b185fSBrian Somers   for (r = *rp; r; r = rn) {
530610b185fSBrian Somers     rn = r->next;
531610b185fSBrian Somers     free(r);
532610b185fSBrian Somers   }
533610b185fSBrian Somers   *rp = NULL;
534610b185fSBrian Somers }
535610b185fSBrian Somers 
536610b185fSBrian Somers void
537610b185fSBrian Somers route_ShowSticky(struct prompt *p, struct sticky_route *r)
538610b185fSBrian Somers {
539610b185fSBrian Somers   int def;
540610b185fSBrian Somers 
541610b185fSBrian Somers   prompt_Printf(p, "Sticky routes:\n");
542610b185fSBrian Somers   for (; r; r = r->next) {
543610b185fSBrian Somers     def = r->dst.s_addr == INADDR_ANY && r->mask.s_addr == INADDR_ANY;
544610b185fSBrian Somers 
545610b185fSBrian Somers     prompt_Printf(p, " add ");
546610b185fSBrian Somers     if (r->type & ROUTE_DSTMYADDR)
547610b185fSBrian Somers       prompt_Printf(p, "MYADDR");
548610b185fSBrian Somers     else if (r->type & ROUTE_DSTHISADDR)
549610b185fSBrian Somers       prompt_Printf(p, "HISADDR");
550610b185fSBrian Somers     else if (!def)
551610b185fSBrian Somers       prompt_Printf(p, "%s", inet_ntoa(r->dst));
552610b185fSBrian Somers 
553610b185fSBrian Somers     if (def)
554610b185fSBrian Somers       prompt_Printf(p, "default ");
555610b185fSBrian Somers     else
556610b185fSBrian Somers       prompt_Printf(p, " %s ", inet_ntoa(r->mask));
557610b185fSBrian Somers 
558610b185fSBrian Somers     if (r->type & ROUTE_GWHISADDR)
559610b185fSBrian Somers       prompt_Printf(p, "HISADDR\n");
560610b185fSBrian Somers     else
561610b185fSBrian Somers       prompt_Printf(p, "%s\n", inet_ntoa(r->gw));
562610b185fSBrian Somers   }
563610b185fSBrian Somers }
564