iface.c revision 43313
140561Sbrian/*-
240561Sbrian * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
340561Sbrian * All rights reserved.
440561Sbrian *
540561Sbrian * Redistribution and use in source and binary forms, with or without
640561Sbrian * modification, are permitted provided that the following conditions
740561Sbrian * are met:
840561Sbrian * 1. Redistributions of source code must retain the above copyright
940561Sbrian *    notice, this list of conditions and the following disclaimer.
1040561Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1140561Sbrian *    notice, this list of conditions and the following disclaimer in the
1240561Sbrian *    documentation and/or other materials provided with the distribution.
1340561Sbrian *
1440561Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1540561Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1640561Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1740561Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1840561Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1940561Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2040561Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2140561Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2240561Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2340561Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2440561Sbrian * SUCH DAMAGE.
2540561Sbrian *
2643313Sbrian *	$Id: iface.c,v 1.2 1998/10/26 19:07:36 brian Exp $
2740561Sbrian */
2840561Sbrian
2943313Sbrian#include <sys/param.h>
3040561Sbrian#include <sys/socket.h>
3140561Sbrian#include <netinet/in.h>
3240561Sbrian#include <net/if.h>
3340561Sbrian#include <net/if_dl.h>
3440561Sbrian#include <net/route.h>
3540561Sbrian#include <arpa/inet.h>
3640561Sbrian#include <netinet/in_systm.h>
3740561Sbrian#include <netinet/ip.h>
3840561Sbrian#include <sys/un.h>
3940561Sbrian
4040561Sbrian#include <sys/errno.h>
4140561Sbrian#include <sys/ioctl.h>
4240561Sbrian#include <sys/sysctl.h>
4340561Sbrian#include <string.h>
4440561Sbrian#include <stdio.h>
4540561Sbrian#include <stdlib.h>
4640561Sbrian#include <termios.h>
4740561Sbrian#include <unistd.h>
4840561Sbrian
4940561Sbrian#include "defs.h"
5040561Sbrian#include "command.h"
5140561Sbrian#include "mbuf.h"
5240561Sbrian#include "log.h"
5340561Sbrian#include "id.h"
5440561Sbrian#include "timer.h"
5540561Sbrian#include "fsm.h"
5640561Sbrian#include "iplist.h"
5740561Sbrian#include "lqr.h"
5840561Sbrian#include "hdlc.h"
5940561Sbrian#include "throughput.h"
6040561Sbrian#include "slcompress.h"
6140561Sbrian#include "filter.h"
6240561Sbrian#include "descriptor.h"
6340561Sbrian#include "ipcp.h"
6440561Sbrian#include "lcp.h"
6540561Sbrian#include "ccp.h"
6640561Sbrian#include "link.h"
6740561Sbrian#include "mp.h"
6843313Sbrian#ifndef NORADIUS
6943313Sbrian#include "radius.h"
7043313Sbrian#endif
7140561Sbrian#include "bundle.h"
7240561Sbrian#include "prompt.h"
7340561Sbrian#include "iface.h"
7440561Sbrian
7540561Sbrian
7640561Sbrianstatic int
7740561Sbrianbitsinmask(struct in_addr mask)
7840561Sbrian{
7940561Sbrian  u_int32_t bitmask, maskaddr;
8040561Sbrian  int bits;
8140561Sbrian
8240561Sbrian  bitmask = 0xffffffff;
8340561Sbrian  maskaddr = ntohl(mask.s_addr);
8440561Sbrian  for (bits = 32; bits >= 0; bits--) {
8540561Sbrian    if (maskaddr == bitmask)
8640561Sbrian      break;
8740561Sbrian    bitmask &= ~(1 << (32 - bits));
8840561Sbrian  }
8940561Sbrian
9040561Sbrian  return bits;
9140561Sbrian}
9240561Sbrian
9340561Sbrianstruct iface *
9440561Sbrianiface_Create(const char *name)
9540561Sbrian{
9640561Sbrian  int mib[6], i, s;
9740561Sbrian  size_t needed;
9840561Sbrian  char *buf, *ptr, *end, *cp, *lim;
9940561Sbrian  struct if_msghdr *ifm;
10040561Sbrian  struct ifa_msghdr *ifam;
10140561Sbrian  struct sockaddr_dl *dl;
10240561Sbrian  struct rt_addrinfo rti;
10340561Sbrian  struct iface *iface;
10440561Sbrian  struct iface_addr *addr;
10540561Sbrian
10640561Sbrian  s = socket(AF_INET, SOCK_DGRAM, 0);
10740561Sbrian  if (s < 0) {
10840561Sbrian    fprintf(stderr, "iface_Create: socket(): %s\n", strerror(errno));
10940561Sbrian    return NULL;
11040561Sbrian  }
11140561Sbrian
11240561Sbrian  mib[0] = CTL_NET;
11340561Sbrian  mib[1] = PF_ROUTE;
11440561Sbrian  mib[2] = 0;
11540561Sbrian  mib[3] = 0;
11640561Sbrian  mib[4] = NET_RT_IFLIST;
11740561Sbrian  mib[5] = 0;
11840561Sbrian
11940561Sbrian  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
12040561Sbrian    fprintf(stderr, "clean: sysctl: estimate: %s\n",
12140561Sbrian              strerror(errno));
12240561Sbrian    close(s);
12340561Sbrian    return NULL;
12440561Sbrian  }
12540561Sbrian
12640561Sbrian  if ((buf = (char *)malloc(needed)) == NULL) {
12740561Sbrian    close(s);
12840561Sbrian    return NULL;
12940561Sbrian  }
13040561Sbrian
13140561Sbrian  if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
13240561Sbrian    free(buf);
13340561Sbrian    close(s);
13440561Sbrian    return NULL;
13540561Sbrian  }
13640561Sbrian
13740561Sbrian  ptr = buf;
13840561Sbrian  end = buf + needed;
13940561Sbrian  iface = NULL;
14040561Sbrian
14140561Sbrian  while (ptr < end && iface == NULL) {
14240561Sbrian    ifm = (struct if_msghdr *)ptr;			/* On if_msghdr */
14340561Sbrian    if (ifm->ifm_type != RTM_IFINFO)
14440561Sbrian      break;
14540561Sbrian    dl = (struct sockaddr_dl *)(ifm + 1);		/* Single _dl at end */
14640561Sbrian    if (!strncmp(name, dl->sdl_data, dl->sdl_nlen)) {
14740561Sbrian      iface = (struct iface *)malloc(sizeof *iface);
14840561Sbrian      if (iface == NULL) {
14940561Sbrian        fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
15040561Sbrian        return NULL;
15140561Sbrian      }
15240561Sbrian      iface->name = strdup(name);
15340561Sbrian      iface->flags = ifm->ifm_flags;
15440561Sbrian      iface->index = ifm->ifm_index;
15540561Sbrian      iface->in_addrs = 0;
15640561Sbrian      iface->in_addr = NULL;
15740561Sbrian    }
15840561Sbrian    ptr += ifm->ifm_msglen;				/* First ifa_msghdr */
15940561Sbrian    for (; ptr < end; ptr += ifam->ifam_msglen) {
16040561Sbrian      ifam = (struct ifa_msghdr *)ptr;			/* Next if address */
16140561Sbrian
16240561Sbrian      if (ifam->ifam_type != RTM_NEWADDR)		/* finished this if */
16340561Sbrian        break;
16440561Sbrian
16540561Sbrian      if (iface == NULL)				/* Keep wading */
16640561Sbrian        continue;
16740561Sbrian
16840561Sbrian      /* Found an address ! */
16940561Sbrian
17040561Sbrian      if (ifam->ifam_addrs & (1 << RTAX_IFA)) {
17140561Sbrian        /* *And* it's configured ! */
17240561Sbrian        rti.rti_addrs = ifam->ifam_addrs;
17340561Sbrian        lim = (char *)ifam + ifam->ifam_msglen;
17440561Sbrian        cp = (char *)(ifam + 1);
17540561Sbrian        memset(rti.rti_info, '\0', sizeof(rti.rti_info));
17640561Sbrian        for (i = 0; i < RTAX_MAX && cp < lim; i++) {
17740561Sbrian          if ((rti.rti_addrs & (1 << i)) == 0)
17840561Sbrian            continue;
17940561Sbrian          rti.rti_info[i] = (struct sockaddr *)cp;
18040561Sbrian#define ROUNDUP(x) \
18140561Sbrian          ((x) > 0 ? (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long))
18240561Sbrian          cp += ROUNDUP(rti.rti_info[i]->sa_len);
18340561Sbrian        }
18440561Sbrian
18540561Sbrian        if (rti.rti_info[RTAX_IFA] &&
18640561Sbrian            rti.rti_info[RTAX_IFA]->sa_family == AF_INET) {
18740561Sbrian          /* Record the iface address rti */
18840561Sbrian
18940561Sbrian          addr = (struct iface_addr *)realloc
19040561Sbrian            (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
19140561Sbrian          if (addr == NULL)
19240561Sbrian            break;
19340561Sbrian          iface->in_addr = addr;
19440561Sbrian
19540561Sbrian          addr += iface->in_addrs;
19640561Sbrian          iface->in_addrs++;
19740561Sbrian
19840561Sbrian          addr->ifa.s_addr = ((struct sockaddr_in *)rti.rti_info[RTAX_IFA])->
19940561Sbrian            sin_addr.s_addr;
20040561Sbrian          addr->brd.s_addr = rti.rti_info[RTAX_BRD] ?
20140561Sbrian            ((struct sockaddr_in *)rti.rti_info[RTAX_BRD])->sin_addr.s_addr :
20240561Sbrian            INADDR_ANY;
20340561Sbrian          addr->mask.s_addr = rti.rti_info[RTAX_NETMASK] ?
20440561Sbrian            ((struct sockaddr_in *)rti.rti_info[RTAX_NETMASK])->sin_addr.s_addr:
20540561Sbrian            INADDR_ANY;
20640561Sbrian
20740561Sbrian          addr->bits = bitsinmask(addr->mask);
20840561Sbrian        }
20940561Sbrian      }
21040561Sbrian    }
21140561Sbrian  }
21240561Sbrian
21340561Sbrian  free(buf);
21440561Sbrian  close(s);
21540561Sbrian
21640561Sbrian  return iface;
21740561Sbrian}
21840561Sbrian
21940561Sbrianstatic void
22040561Sbrianiface_addr_Zap(const char *name, struct iface_addr *addr)
22140561Sbrian{
22240561Sbrian  struct ifaliasreq ifra;
22340561Sbrian  struct sockaddr_in *me, *peer;
22440561Sbrian  int s;
22540561Sbrian
22640561Sbrian  s = ID0socket(AF_INET, SOCK_DGRAM, 0);
22740561Sbrian  if (s < 0)
22840561Sbrian    log_Printf(LogERROR, "iface_addr_Zap: socket(): %s\n", strerror(errno));
22940561Sbrian  else {
23040561Sbrian    memset(&ifra, '\0', sizeof ifra);
23140561Sbrian    strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
23240561Sbrian    me = (struct sockaddr_in *)&ifra.ifra_addr;
23340561Sbrian    peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
23440561Sbrian    me->sin_family = peer->sin_family = AF_INET;
23540561Sbrian    me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
23640561Sbrian    me->sin_addr = addr->ifa;
23740561Sbrian    peer->sin_addr = addr->brd;
23840664Sbrian    log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(addr->ifa));
23940561Sbrian    if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0)
24040561Sbrian      log_Printf(LogWARN, "iface_addr_Zap: ioctl(SIOCDIFADDR, %s): %s\n",
24140561Sbrian                 inet_ntoa(addr->ifa), strerror(errno));
24240561Sbrian    close(s);
24340561Sbrian  }
24440561Sbrian}
24540561Sbrian
24640561Sbrianvoid
24740561Sbrianiface_inClear(struct iface *iface, int how)
24840561Sbrian{
24940561Sbrian  int n, addrs;
25040561Sbrian
25140561Sbrian  addrs = n = how == IFACE_CLEAR_ALL ? 0 : 1;
25240561Sbrian  for (; n < iface->in_addrs; n++)
25340561Sbrian    iface_addr_Zap(iface->name, iface->in_addr + n);
25440561Sbrian
25540561Sbrian  iface->in_addrs = addrs;
25640561Sbrian  /* Don't bother realloc()ing - we have little to gain */
25740561Sbrian}
25840561Sbrian
25940561Sbrianint
26040561Sbrianiface_inAdd(struct iface *iface, struct in_addr ifa, struct in_addr mask,
26140561Sbrian            struct in_addr brd, int how)
26240561Sbrian{
26340664Sbrian  int slot, s, chg;
26440561Sbrian  struct ifaliasreq ifra;
26540561Sbrian  struct sockaddr_in *me, *peer, *msk;
26640561Sbrian  struct iface_addr *addr;
26740561Sbrian
26840561Sbrian  for (slot = 0; slot < iface->in_addrs; slot++)
26940561Sbrian    if (iface->in_addr[slot].ifa.s_addr == ifa.s_addr) {
27040561Sbrian      if (how & IFACE_FORCE_ADD)
27140561Sbrian        break;
27240561Sbrian      else
27340561Sbrian        /* errno = EEXIST; */
27440561Sbrian        return 0;
27540561Sbrian    }
27640561Sbrian
27740561Sbrian  addr = (struct iface_addr *)realloc
27840561Sbrian    (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
27940561Sbrian  if (addr == NULL) {
28040561Sbrian    log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
28140561Sbrian    return 0;
28240561Sbrian  }
28340561Sbrian  iface->in_addr = addr;
28440561Sbrian
28540561Sbrian  s = ID0socket(AF_INET, SOCK_DGRAM, 0);
28640561Sbrian  if (s < 0) {
28740561Sbrian    log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno));
28840561Sbrian    return 0;
28940561Sbrian  }
29040561Sbrian
29140664Sbrian  /*
29240664Sbrian   * We've gotta be careful here.  If we try to add an address with the
29340664Sbrian   * same destination as an existing interface, nothing will work.
29440664Sbrian   * Instead, we tweak all previous address entries that match the
29540664Sbrian   * to-be-added destination to 255.255.255.255 (w/ a similar netmask).
29640664Sbrian   * There *may* be more than one - if the user has ``iface add''ed
29740664Sbrian   * stuff previously.
29840664Sbrian   */
29940664Sbrian  for (chg = 0; chg < iface->in_addrs; chg++) {
30040664Sbrian    if ((iface->in_addr[chg].brd.s_addr == brd.s_addr &&
30140664Sbrian         brd.s_addr != INADDR_BROADCAST) || chg == slot) {
30240664Sbrian      memset(&ifra, '\0', sizeof ifra);
30340664Sbrian      strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
30440664Sbrian      me = (struct sockaddr_in *)&ifra.ifra_addr;
30540664Sbrian      msk = (struct sockaddr_in *)&ifra.ifra_mask;
30640664Sbrian      peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
30740664Sbrian      me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
30840664Sbrian      me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
30940664Sbrian      me->sin_addr = iface->in_addr[chg].ifa;
31040664Sbrian      msk->sin_addr = iface->in_addr[chg].mask;
31140664Sbrian      peer->sin_addr = iface->in_addr[chg].brd;
31240664Sbrian      log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(me->sin_addr));
31340664Sbrian      ID0ioctl(s, SIOCDIFADDR, &ifra);	/* Don't care if it fails... */
31440664Sbrian      if (chg != slot) {
31540664Sbrian        peer->sin_addr.s_addr = iface->in_addr[chg].brd.s_addr =
31640664Sbrian          msk->sin_addr.s_addr = iface->in_addr[chg].mask.s_addr =
31740664Sbrian            INADDR_BROADCAST;
31840664Sbrian        iface->in_addr[chg].bits = 32;
31940664Sbrian        log_Printf(LogDEBUG, "Add %s -> 255.255.255.255\n",
32040664Sbrian                   inet_ntoa(me->sin_addr));
32140664Sbrian        if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 && errno != EEXIST) {
32240664Sbrian          /* Oops - that's bad(ish) news !  We've lost an alias ! */
32340664Sbrian          log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
32440664Sbrian               inet_ntoa(me->sin_addr), strerror(errno));
32540664Sbrian          iface->in_addrs--;
32640664Sbrian          bcopy(iface->in_addr + chg + 1, iface->in_addr + chg,
32740664Sbrian                (iface->in_addrs - chg) * sizeof iface->in_addr[0]);
32840664Sbrian          if (slot > chg)
32940664Sbrian            slot--;
33040664Sbrian          chg--;
33140664Sbrian        }
33240664Sbrian      }
33340664Sbrian    }
33440664Sbrian  }
33540664Sbrian
33640561Sbrian  memset(&ifra, '\0', sizeof ifra);
33740561Sbrian  strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
33840561Sbrian  me = (struct sockaddr_in *)&ifra.ifra_addr;
33940561Sbrian  msk = (struct sockaddr_in *)&ifra.ifra_mask;
34040561Sbrian  peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
34140561Sbrian  me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
34240561Sbrian  me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
34340561Sbrian  me->sin_addr = ifa;
34440561Sbrian  msk->sin_addr = mask;
34540561Sbrian  peer->sin_addr = brd;
34640561Sbrian
34740664Sbrian  if (log_IsKept(LogDEBUG)) {
34840664Sbrian    char buf[16];
34940664Sbrian
35040664Sbrian    strncpy(buf, inet_ntoa(brd), sizeof buf-1);
35140664Sbrian    buf[sizeof buf - 1] = '\0';
35240664Sbrian    log_Printf(LogDEBUG, "Add %s -> %s\n", inet_ntoa(ifa), buf);
35340664Sbrian  }
35440664Sbrian
35540664Sbrian  /* An EEXIST failure w/ brd == INADDR_BROADCAST is ok (and works!) */
35640664Sbrian  if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 &&
35740664Sbrian      (brd.s_addr != INADDR_BROADCAST || errno != EEXIST)) {
35840664Sbrian    log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
35940664Sbrian               inet_ntoa(ifa), strerror(errno));
36040664Sbrian    ID0ioctl(s, SIOCDIFADDR, &ifra);	/* EEXIST ? */
36140561Sbrian    close(s);
36240561Sbrian    return 0;
36340561Sbrian  }
36440561Sbrian  close(s);
36540561Sbrian
36640561Sbrian  if (slot == iface->in_addrs) {
36740561Sbrian    /* We're adding a new interface address */
36840561Sbrian
36940561Sbrian    if (how & IFACE_ADD_FIRST) {
37040561Sbrian      /* Stuff it at the start of our list */
37140561Sbrian      slot = 0;
37240561Sbrian      bcopy(iface->in_addr, iface->in_addr + 1,
37340561Sbrian            iface->in_addrs * sizeof iface->in_addr[0]);
37440561Sbrian    }
37540561Sbrian
37640561Sbrian    iface->in_addrs++;
37740561Sbrian  } else if (how & IFACE_ADD_FIRST) {
37840561Sbrian    /* Shift it up to the first slot */
37940561Sbrian    bcopy(iface->in_addr, iface->in_addr + 1, slot * sizeof iface->in_addr[0]);
38040561Sbrian    slot = 0;
38140561Sbrian  }
38240561Sbrian
38340561Sbrian  iface->in_addr[slot].ifa = ifa;
38440561Sbrian  iface->in_addr[slot].mask = mask;
38540561Sbrian  iface->in_addr[slot].brd = brd;
38640561Sbrian  iface->in_addr[slot].bits = bitsinmask(iface->in_addr[slot].mask);
38740561Sbrian
38840561Sbrian  return 1;
38940561Sbrian}
39040561Sbrian
39140561Sbrianint
39240561Sbrianiface_inDelete(struct iface *iface, struct in_addr ip)
39340561Sbrian{
39440561Sbrian  int n;
39540561Sbrian
39640561Sbrian  for (n = 0; n < iface->in_addrs; n++)
39740561Sbrian    if (iface->in_addr[n].ifa.s_addr == ip.s_addr) {
39840561Sbrian      iface_addr_Zap(iface->name, iface->in_addr + n);
39940561Sbrian      bcopy(iface->in_addr + n + 1, iface->in_addr + n,
40040561Sbrian            (iface->in_addrs - n - 1) * sizeof iface->in_addr[0]);
40140561Sbrian      iface->in_addrs--;
40240561Sbrian      return 1;
40340561Sbrian    }
40440561Sbrian
40540561Sbrian  return 0;
40640561Sbrian}
40740561Sbrian
40840561Sbrianvoid
40940561Sbrianiface_Destroy(struct iface *iface)
41040561Sbrian{
41140561Sbrian  /*
41240561Sbrian   * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually
41340561Sbrian   * if that's what the user wants.  It's better to leave the interface
41440561Sbrian   * allocated so that existing connections can continue to work.
41540561Sbrian   */
41640561Sbrian
41740561Sbrian  if (iface != NULL) {
41840561Sbrian    free(iface->name);
41940561Sbrian    free(iface->in_addr);
42040561Sbrian    free(iface);
42140561Sbrian  }
42240561Sbrian}
42340561Sbrian
42440561Sbrian#define if_entry(x) { IFF_##x, #x }
42540561Sbrian
42640561Sbrianstruct {
42740561Sbrian  int flag;
42840561Sbrian  const char *value;
42940561Sbrian} if_flags[] = {
43040561Sbrian  if_entry(UP),
43140561Sbrian  if_entry(BROADCAST),
43240561Sbrian  if_entry(DEBUG),
43340561Sbrian  if_entry(LOOPBACK),
43440561Sbrian  if_entry(POINTOPOINT),
43540561Sbrian  if_entry(RUNNING),
43640561Sbrian  if_entry(NOARP),
43740561Sbrian  if_entry(PROMISC),
43840561Sbrian  if_entry(ALLMULTI),
43940561Sbrian  if_entry(OACTIVE),
44040561Sbrian  if_entry(SIMPLEX),
44140561Sbrian  if_entry(LINK0),
44240561Sbrian  if_entry(LINK1),
44340561Sbrian  if_entry(LINK2),
44440561Sbrian  if_entry(MULTICAST),
44540561Sbrian  { 0, "???" }
44640561Sbrian};
44740561Sbrian
44840561Sbrianint
44940561Sbrianiface_Show(struct cmdargs const *arg)
45040561Sbrian{
45140561Sbrian  struct iface *iface = arg->bundle->iface, *current;
45240561Sbrian  int f, flags;
45340561Sbrian
45440561Sbrian  current = iface_Create(iface->name);
45540561Sbrian  flags = iface->flags = current->flags;
45640561Sbrian  iface_Destroy(current);
45740561Sbrian
45840561Sbrian  prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
45940561Sbrian  for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
46040561Sbrian    if ((if_flags[f].flag & flags) || (!if_flags[f].flag && flags)) {
46140561Sbrian      prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
46240561Sbrian                    if_flags[f].value);
46340561Sbrian      flags &= ~if_flags[f].flag;
46440561Sbrian    }
46540561Sbrian  prompt_Printf(arg->prompt, "> has %d address%s:\n", iface->in_addrs,
46640561Sbrian                iface->in_addrs == 1 ? "" : "es");
46740561Sbrian
46840561Sbrian  for (f = 0; f < iface->in_addrs; f++) {
46940561Sbrian    prompt_Printf(arg->prompt, "  %s", inet_ntoa(iface->in_addr[f].ifa));
47040561Sbrian    if (iface->in_addr[f].bits >= 0)
47140561Sbrian      prompt_Printf(arg->prompt, "/%d", iface->in_addr[f].bits);
47240561Sbrian    if (iface->flags & IFF_POINTOPOINT)
47340561Sbrian      prompt_Printf(arg->prompt, " -> %s", inet_ntoa(iface->in_addr[f].brd));
47440561Sbrian    else if (iface->flags & IFF_BROADCAST)
47540561Sbrian      prompt_Printf(arg->prompt, " broadcast %s",
47640561Sbrian                    inet_ntoa(iface->in_addr[f].brd));
47740561Sbrian    if (iface->in_addr[f].bits < 0)
47840561Sbrian      prompt_Printf(arg->prompt, " (mask %s)",
47940561Sbrian                    inet_ntoa(iface->in_addr[f].mask));
48040561Sbrian    prompt_Printf(arg->prompt, "\n");
48140561Sbrian  }
48240561Sbrian
48340561Sbrian  return 0;
48440561Sbrian}
485