xref: /freebsd/usr.sbin/ppp/iface.c (revision c0593e34b75b670f98f730106bb4dd78b30bb1a0)
18fa6ebe4SBrian Somers /*-
28fa6ebe4SBrian Somers  * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
38fa6ebe4SBrian Somers  * All rights reserved.
48fa6ebe4SBrian Somers  *
58fa6ebe4SBrian Somers  * Redistribution and use in source and binary forms, with or without
68fa6ebe4SBrian Somers  * modification, are permitted provided that the following conditions
78fa6ebe4SBrian Somers  * are met:
88fa6ebe4SBrian Somers  * 1. Redistributions of source code must retain the above copyright
98fa6ebe4SBrian Somers  *    notice, this list of conditions and the following disclaimer.
108fa6ebe4SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
118fa6ebe4SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
128fa6ebe4SBrian Somers  *    documentation and/or other materials provided with the distribution.
138fa6ebe4SBrian Somers  *
148fa6ebe4SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
158fa6ebe4SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168fa6ebe4SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
178fa6ebe4SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
188fa6ebe4SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
198fa6ebe4SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
208fa6ebe4SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
218fa6ebe4SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
228fa6ebe4SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
238fa6ebe4SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
248fa6ebe4SBrian Somers  * SUCH DAMAGE.
258fa6ebe4SBrian Somers  *
2697d92980SPeter Wemm  * $FreeBSD$
278fa6ebe4SBrian Somers  */
288fa6ebe4SBrian Somers 
29972a1bcfSBrian Somers #include <sys/param.h>
308fa6ebe4SBrian Somers #include <sys/socket.h>
318fa6ebe4SBrian Somers #include <netinet/in.h>
328fa6ebe4SBrian Somers #include <net/if.h>
338fa6ebe4SBrian Somers #include <net/if_dl.h>
348fa6ebe4SBrian Somers #include <net/route.h>
358fa6ebe4SBrian Somers #include <arpa/inet.h>
368fa6ebe4SBrian Somers #include <netinet/in_systm.h>
378fa6ebe4SBrian Somers #include <netinet/ip.h>
388fa6ebe4SBrian Somers #include <sys/un.h>
398fa6ebe4SBrian Somers 
40119386a3SBrian Somers #include <errno.h>
418fa6ebe4SBrian Somers #include <string.h>
428fa6ebe4SBrian Somers #include <stdio.h>
438fa6ebe4SBrian Somers #include <stdlib.h>
44119386a3SBrian Somers #include <sys/ioctl.h>
45119386a3SBrian Somers #include <sys/sysctl.h>
468fa6ebe4SBrian Somers #include <termios.h>
478fa6ebe4SBrian Somers #include <unistd.h>
488fa6ebe4SBrian Somers 
495d9e6103SBrian Somers #include "layer.h"
508fa6ebe4SBrian Somers #include "defs.h"
518fa6ebe4SBrian Somers #include "command.h"
528fa6ebe4SBrian Somers #include "mbuf.h"
538fa6ebe4SBrian Somers #include "log.h"
548fa6ebe4SBrian Somers #include "id.h"
558fa6ebe4SBrian Somers #include "timer.h"
568fa6ebe4SBrian Somers #include "fsm.h"
578fa6ebe4SBrian Somers #include "iplist.h"
588fa6ebe4SBrian Somers #include "lqr.h"
598fa6ebe4SBrian Somers #include "hdlc.h"
608fa6ebe4SBrian Somers #include "throughput.h"
618fa6ebe4SBrian Somers #include "slcompress.h"
628fa6ebe4SBrian Somers #include "descriptor.h"
638fa6ebe4SBrian Somers #include "ipcp.h"
641d1fc017SBrian Somers #include "filter.h"
658fa6ebe4SBrian Somers #include "lcp.h"
668fa6ebe4SBrian Somers #include "ccp.h"
678fa6ebe4SBrian Somers #include "link.h"
688fa6ebe4SBrian Somers #include "mp.h"
69972a1bcfSBrian Somers #ifndef NORADIUS
70972a1bcfSBrian Somers #include "radius.h"
71972a1bcfSBrian Somers #endif
728fa6ebe4SBrian Somers #include "bundle.h"
738fa6ebe4SBrian Somers #include "prompt.h"
748fa6ebe4SBrian Somers #include "iface.h"
758fa6ebe4SBrian Somers 
768fa6ebe4SBrian Somers 
778fa6ebe4SBrian Somers static int
788fa6ebe4SBrian Somers bitsinmask(struct in_addr mask)
798fa6ebe4SBrian Somers {
808fa6ebe4SBrian Somers   u_int32_t bitmask, maskaddr;
818fa6ebe4SBrian Somers   int bits;
828fa6ebe4SBrian Somers 
838fa6ebe4SBrian Somers   bitmask = 0xffffffff;
848fa6ebe4SBrian Somers   maskaddr = ntohl(mask.s_addr);
858fa6ebe4SBrian Somers   for (bits = 32; bits >= 0; bits--) {
868fa6ebe4SBrian Somers     if (maskaddr == bitmask)
878fa6ebe4SBrian Somers       break;
888fa6ebe4SBrian Somers     bitmask &= ~(1 << (32 - bits));
898fa6ebe4SBrian Somers   }
908fa6ebe4SBrian Somers 
918fa6ebe4SBrian Somers   return bits;
928fa6ebe4SBrian Somers }
938fa6ebe4SBrian Somers 
948fa6ebe4SBrian Somers struct iface *
958fa6ebe4SBrian Somers iface_Create(const char *name)
968fa6ebe4SBrian Somers {
978fa6ebe4SBrian Somers   int mib[6], i, s;
988fa6ebe4SBrian Somers   size_t needed;
998fa6ebe4SBrian Somers   char *buf, *ptr, *end, *cp, *lim;
1008fa6ebe4SBrian Somers   struct if_msghdr *ifm;
1018fa6ebe4SBrian Somers   struct ifa_msghdr *ifam;
1028fa6ebe4SBrian Somers   struct sockaddr_dl *dl;
1038fa6ebe4SBrian Somers   struct rt_addrinfo rti;
1048fa6ebe4SBrian Somers   struct iface *iface;
1058fa6ebe4SBrian Somers   struct iface_addr *addr;
1068fa6ebe4SBrian Somers 
1078fa6ebe4SBrian Somers   s = socket(AF_INET, SOCK_DGRAM, 0);
1088fa6ebe4SBrian Somers   if (s < 0) {
1098fa6ebe4SBrian Somers     fprintf(stderr, "iface_Create: socket(): %s\n", strerror(errno));
1108fa6ebe4SBrian Somers     return NULL;
1118fa6ebe4SBrian Somers   }
1128fa6ebe4SBrian Somers 
1138fa6ebe4SBrian Somers   mib[0] = CTL_NET;
1148fa6ebe4SBrian Somers   mib[1] = PF_ROUTE;
1158fa6ebe4SBrian Somers   mib[2] = 0;
1168fa6ebe4SBrian Somers   mib[3] = 0;
1178fa6ebe4SBrian Somers   mib[4] = NET_RT_IFLIST;
1188fa6ebe4SBrian Somers   mib[5] = 0;
1198fa6ebe4SBrian Somers 
1208fa6ebe4SBrian Somers   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
121c0593e34SBrian Somers     fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
1228fa6ebe4SBrian Somers               strerror(errno));
1238fa6ebe4SBrian Somers     close(s);
1248fa6ebe4SBrian Somers     return NULL;
1258fa6ebe4SBrian Somers   }
1268fa6ebe4SBrian Somers 
1278fa6ebe4SBrian Somers   if ((buf = (char *)malloc(needed)) == NULL) {
128c0593e34SBrian Somers     fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
1298fa6ebe4SBrian Somers     close(s);
1308fa6ebe4SBrian Somers     return NULL;
1318fa6ebe4SBrian Somers   }
1328fa6ebe4SBrian Somers 
1338fa6ebe4SBrian Somers   if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
134c0593e34SBrian Somers     fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(errno));
1358fa6ebe4SBrian Somers     free(buf);
1368fa6ebe4SBrian Somers     close(s);
1378fa6ebe4SBrian Somers     return NULL;
1388fa6ebe4SBrian Somers   }
1398fa6ebe4SBrian Somers 
1408fa6ebe4SBrian Somers   ptr = buf;
1418fa6ebe4SBrian Somers   end = buf + needed;
1428fa6ebe4SBrian Somers   iface = NULL;
1438fa6ebe4SBrian Somers 
1448fa6ebe4SBrian Somers   while (ptr < end && iface == NULL) {
1458fa6ebe4SBrian Somers     ifm = (struct if_msghdr *)ptr;			/* On if_msghdr */
1468fa6ebe4SBrian Somers     if (ifm->ifm_type != RTM_IFINFO)
1478fa6ebe4SBrian Somers       break;
1488fa6ebe4SBrian Somers     dl = (struct sockaddr_dl *)(ifm + 1);		/* Single _dl at end */
1498fa6ebe4SBrian Somers     if (!strncmp(name, dl->sdl_data, dl->sdl_nlen)) {
1508fa6ebe4SBrian Somers       iface = (struct iface *)malloc(sizeof *iface);
1518fa6ebe4SBrian Somers       if (iface == NULL) {
1528fa6ebe4SBrian Somers         fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
1538fa6ebe4SBrian Somers         return NULL;
1548fa6ebe4SBrian Somers       }
1558fa6ebe4SBrian Somers       iface->name = strdup(name);
1568fa6ebe4SBrian Somers       iface->flags = ifm->ifm_flags;
1578fa6ebe4SBrian Somers       iface->index = ifm->ifm_index;
1588fa6ebe4SBrian Somers       iface->in_addrs = 0;
1598fa6ebe4SBrian Somers       iface->in_addr = NULL;
1608fa6ebe4SBrian Somers     }
1618fa6ebe4SBrian Somers     ptr += ifm->ifm_msglen;				/* First ifa_msghdr */
1628fa6ebe4SBrian Somers     for (; ptr < end; ptr += ifam->ifam_msglen) {
1638fa6ebe4SBrian Somers       ifam = (struct ifa_msghdr *)ptr;			/* Next if address */
1648fa6ebe4SBrian Somers 
1658fa6ebe4SBrian Somers       if (ifam->ifam_type != RTM_NEWADDR)		/* finished this if */
1668fa6ebe4SBrian Somers         break;
1678fa6ebe4SBrian Somers 
1688fa6ebe4SBrian Somers       if (iface == NULL)				/* Keep wading */
1698fa6ebe4SBrian Somers         continue;
1708fa6ebe4SBrian Somers 
1718fa6ebe4SBrian Somers       /* Found an address ! */
1728fa6ebe4SBrian Somers 
1738fa6ebe4SBrian Somers       if (ifam->ifam_addrs & (1 << RTAX_IFA)) {
1748fa6ebe4SBrian Somers         /* *And* it's configured ! */
1758fa6ebe4SBrian Somers         rti.rti_addrs = ifam->ifam_addrs;
1768fa6ebe4SBrian Somers         lim = (char *)ifam + ifam->ifam_msglen;
1778fa6ebe4SBrian Somers         cp = (char *)(ifam + 1);
1788fa6ebe4SBrian Somers         memset(rti.rti_info, '\0', sizeof(rti.rti_info));
1798fa6ebe4SBrian Somers         for (i = 0; i < RTAX_MAX && cp < lim; i++) {
1808fa6ebe4SBrian Somers           if ((rti.rti_addrs & (1 << i)) == 0)
1818fa6ebe4SBrian Somers             continue;
1828fa6ebe4SBrian Somers           rti.rti_info[i] = (struct sockaddr *)cp;
1838fa6ebe4SBrian Somers #define ROUNDUP(x) \
1848fa6ebe4SBrian Somers           ((x) > 0 ? (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long))
1858fa6ebe4SBrian Somers           cp += ROUNDUP(rti.rti_info[i]->sa_len);
1868fa6ebe4SBrian Somers         }
1878fa6ebe4SBrian Somers 
1888fa6ebe4SBrian Somers         if (rti.rti_info[RTAX_IFA] &&
1898fa6ebe4SBrian Somers             rti.rti_info[RTAX_IFA]->sa_family == AF_INET) {
1908fa6ebe4SBrian Somers           /* Record the iface address rti */
1918fa6ebe4SBrian Somers 
1928fa6ebe4SBrian Somers           addr = (struct iface_addr *)realloc
1938fa6ebe4SBrian Somers             (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
1948fa6ebe4SBrian Somers           if (addr == NULL)
1958fa6ebe4SBrian Somers             break;
1968fa6ebe4SBrian Somers           iface->in_addr = addr;
1978fa6ebe4SBrian Somers 
1988fa6ebe4SBrian Somers           addr += iface->in_addrs;
1998fa6ebe4SBrian Somers           iface->in_addrs++;
2008fa6ebe4SBrian Somers 
2018fa6ebe4SBrian Somers           addr->ifa.s_addr = ((struct sockaddr_in *)rti.rti_info[RTAX_IFA])->
2028fa6ebe4SBrian Somers             sin_addr.s_addr;
2038fa6ebe4SBrian Somers           addr->brd.s_addr = rti.rti_info[RTAX_BRD] ?
2048fa6ebe4SBrian Somers             ((struct sockaddr_in *)rti.rti_info[RTAX_BRD])->sin_addr.s_addr :
2058fa6ebe4SBrian Somers             INADDR_ANY;
2068fa6ebe4SBrian Somers           addr->mask.s_addr = rti.rti_info[RTAX_NETMASK] ?
2078fa6ebe4SBrian Somers             ((struct sockaddr_in *)rti.rti_info[RTAX_NETMASK])->sin_addr.s_addr:
2088fa6ebe4SBrian Somers             INADDR_ANY;
2098fa6ebe4SBrian Somers 
2108fa6ebe4SBrian Somers           addr->bits = bitsinmask(addr->mask);
2118fa6ebe4SBrian Somers         }
2128fa6ebe4SBrian Somers       }
2138fa6ebe4SBrian Somers     }
2148fa6ebe4SBrian Somers   }
2158fa6ebe4SBrian Somers 
2168fa6ebe4SBrian Somers   free(buf);
2178fa6ebe4SBrian Somers   close(s);
2188fa6ebe4SBrian Somers 
2198fa6ebe4SBrian Somers   return iface;
2208fa6ebe4SBrian Somers }
2218fa6ebe4SBrian Somers 
2228fa6ebe4SBrian Somers static void
2238fa6ebe4SBrian Somers iface_addr_Zap(const char *name, struct iface_addr *addr)
2248fa6ebe4SBrian Somers {
2258fa6ebe4SBrian Somers   struct ifaliasreq ifra;
2268fa6ebe4SBrian Somers   struct sockaddr_in *me, *peer;
2278fa6ebe4SBrian Somers   int s;
2288fa6ebe4SBrian Somers 
2298fa6ebe4SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
2308fa6ebe4SBrian Somers   if (s < 0)
2318fa6ebe4SBrian Somers     log_Printf(LogERROR, "iface_addr_Zap: socket(): %s\n", strerror(errno));
2328fa6ebe4SBrian Somers   else {
2338fa6ebe4SBrian Somers     memset(&ifra, '\0', sizeof ifra);
2348fa6ebe4SBrian Somers     strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
2358fa6ebe4SBrian Somers     me = (struct sockaddr_in *)&ifra.ifra_addr;
2368fa6ebe4SBrian Somers     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
2378fa6ebe4SBrian Somers     me->sin_family = peer->sin_family = AF_INET;
2388fa6ebe4SBrian Somers     me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
2398fa6ebe4SBrian Somers     me->sin_addr = addr->ifa;
2408fa6ebe4SBrian Somers     peer->sin_addr = addr->brd;
24117871c5fSBrian Somers     log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(addr->ifa));
2428fa6ebe4SBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0)
2438fa6ebe4SBrian Somers       log_Printf(LogWARN, "iface_addr_Zap: ioctl(SIOCDIFADDR, %s): %s\n",
2448fa6ebe4SBrian Somers                  inet_ntoa(addr->ifa), strerror(errno));
2458fa6ebe4SBrian Somers     close(s);
2468fa6ebe4SBrian Somers   }
2478fa6ebe4SBrian Somers }
2488fa6ebe4SBrian Somers 
2498fa6ebe4SBrian Somers void
2508fa6ebe4SBrian Somers iface_inClear(struct iface *iface, int how)
2518fa6ebe4SBrian Somers {
2528fa6ebe4SBrian Somers   int n, addrs;
2538fa6ebe4SBrian Somers 
2548fa6ebe4SBrian Somers   addrs = n = how == IFACE_CLEAR_ALL ? 0 : 1;
2558fa6ebe4SBrian Somers   for (; n < iface->in_addrs; n++)
2568fa6ebe4SBrian Somers     iface_addr_Zap(iface->name, iface->in_addr + n);
2578fa6ebe4SBrian Somers 
2588fa6ebe4SBrian Somers   iface->in_addrs = addrs;
2598fa6ebe4SBrian Somers   /* Don't bother realloc()ing - we have little to gain */
2608fa6ebe4SBrian Somers }
2618fa6ebe4SBrian Somers 
2628fa6ebe4SBrian Somers int
2638fa6ebe4SBrian Somers iface_inAdd(struct iface *iface, struct in_addr ifa, struct in_addr mask,
2648fa6ebe4SBrian Somers             struct in_addr brd, int how)
2658fa6ebe4SBrian Somers {
26617871c5fSBrian Somers   int slot, s, chg;
2678fa6ebe4SBrian Somers   struct ifaliasreq ifra;
2688fa6ebe4SBrian Somers   struct sockaddr_in *me, *peer, *msk;
2698fa6ebe4SBrian Somers   struct iface_addr *addr;
2708fa6ebe4SBrian Somers 
2718fa6ebe4SBrian Somers   for (slot = 0; slot < iface->in_addrs; slot++)
2728fa6ebe4SBrian Somers     if (iface->in_addr[slot].ifa.s_addr == ifa.s_addr) {
2738fa6ebe4SBrian Somers       if (how & IFACE_FORCE_ADD)
2748fa6ebe4SBrian Somers         break;
2758fa6ebe4SBrian Somers       else
2768fa6ebe4SBrian Somers         /* errno = EEXIST; */
2778fa6ebe4SBrian Somers         return 0;
2788fa6ebe4SBrian Somers     }
2798fa6ebe4SBrian Somers 
2808fa6ebe4SBrian Somers   addr = (struct iface_addr *)realloc
2818fa6ebe4SBrian Somers     (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
2828fa6ebe4SBrian Somers   if (addr == NULL) {
2838fa6ebe4SBrian Somers     log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
2848fa6ebe4SBrian Somers     return 0;
2858fa6ebe4SBrian Somers   }
2868fa6ebe4SBrian Somers   iface->in_addr = addr;
2878fa6ebe4SBrian Somers 
2888fa6ebe4SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
2898fa6ebe4SBrian Somers   if (s < 0) {
2908fa6ebe4SBrian Somers     log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno));
2918fa6ebe4SBrian Somers     return 0;
2928fa6ebe4SBrian Somers   }
2938fa6ebe4SBrian Somers 
29417871c5fSBrian Somers   /*
29517871c5fSBrian Somers    * We've gotta be careful here.  If we try to add an address with the
29617871c5fSBrian Somers    * same destination as an existing interface, nothing will work.
29717871c5fSBrian Somers    * Instead, we tweak all previous address entries that match the
29817871c5fSBrian Somers    * to-be-added destination to 255.255.255.255 (w/ a similar netmask).
29917871c5fSBrian Somers    * There *may* be more than one - if the user has ``iface add''ed
30017871c5fSBrian Somers    * stuff previously.
30117871c5fSBrian Somers    */
30217871c5fSBrian Somers   for (chg = 0; chg < iface->in_addrs; chg++) {
30317871c5fSBrian Somers     if ((iface->in_addr[chg].brd.s_addr == brd.s_addr &&
30417871c5fSBrian Somers          brd.s_addr != INADDR_BROADCAST) || chg == slot) {
3058fa6ebe4SBrian Somers       memset(&ifra, '\0', sizeof ifra);
3068fa6ebe4SBrian Somers       strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
3078fa6ebe4SBrian Somers       me = (struct sockaddr_in *)&ifra.ifra_addr;
3088fa6ebe4SBrian Somers       msk = (struct sockaddr_in *)&ifra.ifra_mask;
3098fa6ebe4SBrian Somers       peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
3108fa6ebe4SBrian Somers       me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
3118fa6ebe4SBrian Somers       me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
31217871c5fSBrian Somers       me->sin_addr = iface->in_addr[chg].ifa;
31317871c5fSBrian Somers       msk->sin_addr = iface->in_addr[chg].mask;
31417871c5fSBrian Somers       peer->sin_addr = iface->in_addr[chg].brd;
31517871c5fSBrian Somers       log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(me->sin_addr));
31617871c5fSBrian Somers       ID0ioctl(s, SIOCDIFADDR, &ifra);	/* Don't care if it fails... */
31717871c5fSBrian Somers       if (chg != slot) {
31817871c5fSBrian Somers         peer->sin_addr.s_addr = iface->in_addr[chg].brd.s_addr =
31917871c5fSBrian Somers           msk->sin_addr.s_addr = iface->in_addr[chg].mask.s_addr =
32017871c5fSBrian Somers             INADDR_BROADCAST;
32117871c5fSBrian Somers         iface->in_addr[chg].bits = 32;
32217871c5fSBrian Somers         log_Printf(LogDEBUG, "Add %s -> 255.255.255.255\n",
32317871c5fSBrian Somers                    inet_ntoa(me->sin_addr));
32417871c5fSBrian Somers         if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 && errno != EEXIST) {
32517871c5fSBrian Somers           /* Oops - that's bad(ish) news !  We've lost an alias ! */
32617871c5fSBrian Somers           log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
32717871c5fSBrian Somers                inet_ntoa(me->sin_addr), strerror(errno));
32817871c5fSBrian Somers           iface->in_addrs--;
32917871c5fSBrian Somers           bcopy(iface->in_addr + chg + 1, iface->in_addr + chg,
33017871c5fSBrian Somers                 (iface->in_addrs - chg) * sizeof iface->in_addr[0]);
33117871c5fSBrian Somers           if (slot > chg)
33217871c5fSBrian Somers             slot--;
33317871c5fSBrian Somers           chg--;
33417871c5fSBrian Somers         }
33517871c5fSBrian Somers       }
33617871c5fSBrian Somers     }
33717871c5fSBrian Somers   }
3388fa6ebe4SBrian Somers 
33917871c5fSBrian Somers   memset(&ifra, '\0', sizeof ifra);
34017871c5fSBrian Somers   strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
34117871c5fSBrian Somers   me = (struct sockaddr_in *)&ifra.ifra_addr;
34217871c5fSBrian Somers   msk = (struct sockaddr_in *)&ifra.ifra_mask;
34317871c5fSBrian Somers   peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
34417871c5fSBrian Somers   me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
34517871c5fSBrian Somers   me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
3468fa6ebe4SBrian Somers   me->sin_addr = ifa;
3478fa6ebe4SBrian Somers   msk->sin_addr = mask;
3488fa6ebe4SBrian Somers   peer->sin_addr = brd;
3498fa6ebe4SBrian Somers 
35017871c5fSBrian Somers   if (log_IsKept(LogDEBUG)) {
35117871c5fSBrian Somers     char buf[16];
35217871c5fSBrian Somers 
35317871c5fSBrian Somers     strncpy(buf, inet_ntoa(brd), sizeof buf-1);
35417871c5fSBrian Somers     buf[sizeof buf - 1] = '\0';
35517871c5fSBrian Somers     log_Printf(LogDEBUG, "Add %s -> %s\n", inet_ntoa(ifa), buf);
35617871c5fSBrian Somers   }
35717871c5fSBrian Somers 
35817871c5fSBrian Somers   /* An EEXIST failure w/ brd == INADDR_BROADCAST is ok (and works!) */
35917871c5fSBrian Somers   if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 &&
36017871c5fSBrian Somers       (brd.s_addr != INADDR_BROADCAST || errno != EEXIST)) {
36117871c5fSBrian Somers     log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
36217871c5fSBrian Somers                inet_ntoa(ifa), strerror(errno));
36317871c5fSBrian Somers     ID0ioctl(s, SIOCDIFADDR, &ifra);	/* EEXIST ? */
3648fa6ebe4SBrian Somers     close(s);
3658fa6ebe4SBrian Somers     return 0;
3668fa6ebe4SBrian Somers   }
3678fa6ebe4SBrian Somers   close(s);
3688fa6ebe4SBrian Somers 
3698fa6ebe4SBrian Somers   if (slot == iface->in_addrs) {
3708fa6ebe4SBrian Somers     /* We're adding a new interface address */
3718fa6ebe4SBrian Somers 
3728fa6ebe4SBrian Somers     if (how & IFACE_ADD_FIRST) {
3738fa6ebe4SBrian Somers       /* Stuff it at the start of our list */
3748fa6ebe4SBrian Somers       slot = 0;
3758fa6ebe4SBrian Somers       bcopy(iface->in_addr, iface->in_addr + 1,
3768fa6ebe4SBrian Somers             iface->in_addrs * sizeof iface->in_addr[0]);
3778fa6ebe4SBrian Somers     }
3788fa6ebe4SBrian Somers 
3798fa6ebe4SBrian Somers     iface->in_addrs++;
3808fa6ebe4SBrian Somers   } else if (how & IFACE_ADD_FIRST) {
3818fa6ebe4SBrian Somers     /* Shift it up to the first slot */
3828fa6ebe4SBrian Somers     bcopy(iface->in_addr, iface->in_addr + 1, slot * sizeof iface->in_addr[0]);
3838fa6ebe4SBrian Somers     slot = 0;
3848fa6ebe4SBrian Somers   }
3858fa6ebe4SBrian Somers 
3868fa6ebe4SBrian Somers   iface->in_addr[slot].ifa = ifa;
3878fa6ebe4SBrian Somers   iface->in_addr[slot].mask = mask;
3888fa6ebe4SBrian Somers   iface->in_addr[slot].brd = brd;
3898fa6ebe4SBrian Somers   iface->in_addr[slot].bits = bitsinmask(iface->in_addr[slot].mask);
3908fa6ebe4SBrian Somers 
3918fa6ebe4SBrian Somers   return 1;
3928fa6ebe4SBrian Somers }
3938fa6ebe4SBrian Somers 
3948fa6ebe4SBrian Somers int
3958fa6ebe4SBrian Somers iface_inDelete(struct iface *iface, struct in_addr ip)
3968fa6ebe4SBrian Somers {
3978fa6ebe4SBrian Somers   int n;
3988fa6ebe4SBrian Somers 
3998fa6ebe4SBrian Somers   for (n = 0; n < iface->in_addrs; n++)
4008fa6ebe4SBrian Somers     if (iface->in_addr[n].ifa.s_addr == ip.s_addr) {
4018fa6ebe4SBrian Somers       iface_addr_Zap(iface->name, iface->in_addr + n);
4028fa6ebe4SBrian Somers       bcopy(iface->in_addr + n + 1, iface->in_addr + n,
4038fa6ebe4SBrian Somers             (iface->in_addrs - n - 1) * sizeof iface->in_addr[0]);
4048fa6ebe4SBrian Somers       iface->in_addrs--;
4058fa6ebe4SBrian Somers       return 1;
4068fa6ebe4SBrian Somers     }
4078fa6ebe4SBrian Somers 
4088fa6ebe4SBrian Somers   return 0;
4098fa6ebe4SBrian Somers }
4108fa6ebe4SBrian Somers 
4114e5196e9SBrian Somers #define IFACE_ADDFLAGS 1
4124e5196e9SBrian Somers #define IFACE_DELFLAGS 2
4134e5196e9SBrian Somers 
4144e5196e9SBrian Somers static int
4154e5196e9SBrian Somers iface_ChangeFlags(struct iface *iface, int flags, int how)
4164e5196e9SBrian Somers {
4174e5196e9SBrian Somers   struct ifreq ifrq;
4184e5196e9SBrian Somers   int s;
4194e5196e9SBrian Somers 
4204e5196e9SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
4214e5196e9SBrian Somers   if (s < 0) {
42253dc037cSBrian Somers     log_Printf(LogERROR, "iface_ChangeFlags: socket: %s\n", strerror(errno));
4234e5196e9SBrian Somers     return 0;
4244e5196e9SBrian Somers   }
4254e5196e9SBrian Somers 
4264e5196e9SBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
4274e5196e9SBrian Somers   strncpy(ifrq.ifr_name, iface->name, sizeof ifrq.ifr_name - 1);
4284e5196e9SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
4294e5196e9SBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
43053dc037cSBrian Somers     log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n",
4314e5196e9SBrian Somers        strerror(errno));
4324e5196e9SBrian Somers     close(s);
4334e5196e9SBrian Somers     return 0;
4344e5196e9SBrian Somers   }
4354e5196e9SBrian Somers 
4364e5196e9SBrian Somers   if (how == IFACE_ADDFLAGS)
4374e5196e9SBrian Somers     ifrq.ifr_flags |= flags;
4384e5196e9SBrian Somers   else
4394e5196e9SBrian Somers     ifrq.ifr_flags &= ~flags;
4404e5196e9SBrian Somers 
4414e5196e9SBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
44253dc037cSBrian Somers     log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n",
4434e5196e9SBrian Somers        strerror(errno));
4444e5196e9SBrian Somers     close(s);
4454e5196e9SBrian Somers     return 0;
4464e5196e9SBrian Somers   }
4474e5196e9SBrian Somers   close(s);
4484e5196e9SBrian Somers 
4494e5196e9SBrian Somers   return 1;	/* Success */
4504e5196e9SBrian Somers }
4514e5196e9SBrian Somers 
4524e5196e9SBrian Somers int
4534e5196e9SBrian Somers iface_SetFlags(struct iface *iface, int flags)
4544e5196e9SBrian Somers {
4554e5196e9SBrian Somers   return iface_ChangeFlags(iface, flags, IFACE_ADDFLAGS);
4564e5196e9SBrian Somers }
4574e5196e9SBrian Somers 
4584e5196e9SBrian Somers int
4594e5196e9SBrian Somers iface_ClearFlags(struct iface *iface, int flags)
4604e5196e9SBrian Somers {
4614e5196e9SBrian Somers   return iface_ChangeFlags(iface, flags, IFACE_DELFLAGS);
4624e5196e9SBrian Somers }
4634e5196e9SBrian Somers 
4648fa6ebe4SBrian Somers void
4658fa6ebe4SBrian Somers iface_Destroy(struct iface *iface)
4668fa6ebe4SBrian Somers {
4678fa6ebe4SBrian Somers   /*
4688fa6ebe4SBrian Somers    * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually
4698fa6ebe4SBrian Somers    * if that's what the user wants.  It's better to leave the interface
4708fa6ebe4SBrian Somers    * allocated so that existing connections can continue to work.
4718fa6ebe4SBrian Somers    */
4728fa6ebe4SBrian Somers 
4738fa6ebe4SBrian Somers   if (iface != NULL) {
4748fa6ebe4SBrian Somers     free(iface->name);
4758fa6ebe4SBrian Somers     free(iface->in_addr);
4768fa6ebe4SBrian Somers     free(iface);
4778fa6ebe4SBrian Somers   }
4788fa6ebe4SBrian Somers }
4798fa6ebe4SBrian Somers 
4808fa6ebe4SBrian Somers #define if_entry(x) { IFF_##x, #x }
4818fa6ebe4SBrian Somers 
4828fa6ebe4SBrian Somers struct {
4838fa6ebe4SBrian Somers   int flag;
4848fa6ebe4SBrian Somers   const char *value;
4858fa6ebe4SBrian Somers } if_flags[] = {
4868fa6ebe4SBrian Somers   if_entry(UP),
4878fa6ebe4SBrian Somers   if_entry(BROADCAST),
4888fa6ebe4SBrian Somers   if_entry(DEBUG),
4898fa6ebe4SBrian Somers   if_entry(LOOPBACK),
4908fa6ebe4SBrian Somers   if_entry(POINTOPOINT),
4918fa6ebe4SBrian Somers   if_entry(RUNNING),
4928fa6ebe4SBrian Somers   if_entry(NOARP),
4938fa6ebe4SBrian Somers   if_entry(PROMISC),
4948fa6ebe4SBrian Somers   if_entry(ALLMULTI),
4958fa6ebe4SBrian Somers   if_entry(OACTIVE),
4968fa6ebe4SBrian Somers   if_entry(SIMPLEX),
4978fa6ebe4SBrian Somers   if_entry(LINK0),
4988fa6ebe4SBrian Somers   if_entry(LINK1),
4998fa6ebe4SBrian Somers   if_entry(LINK2),
5008fa6ebe4SBrian Somers   if_entry(MULTICAST),
5018fa6ebe4SBrian Somers   { 0, "???" }
5028fa6ebe4SBrian Somers };
5038fa6ebe4SBrian Somers 
5048fa6ebe4SBrian Somers int
5058fa6ebe4SBrian Somers iface_Show(struct cmdargs const *arg)
5068fa6ebe4SBrian Somers {
5078fa6ebe4SBrian Somers   struct iface *iface = arg->bundle->iface, *current;
5088fa6ebe4SBrian Somers   int f, flags;
5098fa6ebe4SBrian Somers 
5108fa6ebe4SBrian Somers   current = iface_Create(iface->name);
5118fa6ebe4SBrian Somers   flags = iface->flags = current->flags;
5128fa6ebe4SBrian Somers   iface_Destroy(current);
5138fa6ebe4SBrian Somers 
5148fa6ebe4SBrian Somers   prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
5158fa6ebe4SBrian Somers   for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
5168fa6ebe4SBrian Somers     if ((if_flags[f].flag & flags) || (!if_flags[f].flag && flags)) {
5178fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
5188fa6ebe4SBrian Somers                     if_flags[f].value);
5198fa6ebe4SBrian Somers       flags &= ~if_flags[f].flag;
5208fa6ebe4SBrian Somers     }
5218fa6ebe4SBrian Somers   prompt_Printf(arg->prompt, "> has %d address%s:\n", iface->in_addrs,
5228fa6ebe4SBrian Somers                 iface->in_addrs == 1 ? "" : "es");
5238fa6ebe4SBrian Somers 
5248fa6ebe4SBrian Somers   for (f = 0; f < iface->in_addrs; f++) {
5258fa6ebe4SBrian Somers     prompt_Printf(arg->prompt, "  %s", inet_ntoa(iface->in_addr[f].ifa));
5268fa6ebe4SBrian Somers     if (iface->in_addr[f].bits >= 0)
5278fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, "/%d", iface->in_addr[f].bits);
5288fa6ebe4SBrian Somers     if (iface->flags & IFF_POINTOPOINT)
5298fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, " -> %s", inet_ntoa(iface->in_addr[f].brd));
5308fa6ebe4SBrian Somers     else if (iface->flags & IFF_BROADCAST)
5318fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, " broadcast %s",
5328fa6ebe4SBrian Somers                     inet_ntoa(iface->in_addr[f].brd));
5338fa6ebe4SBrian Somers     if (iface->in_addr[f].bits < 0)
5348fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, " (mask %s)",
5358fa6ebe4SBrian Somers                     inet_ntoa(iface->in_addr[f].mask));
5368fa6ebe4SBrian Somers     prompt_Printf(arg->prompt, "\n");
5378fa6ebe4SBrian Somers   }
5388fa6ebe4SBrian Somers 
5398fa6ebe4SBrian Somers   return 0;
5408fa6ebe4SBrian Somers }
541