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 *
2650479Speter * $FreeBSD$
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>
3482437Sbrian#ifdef __FreeBSD__
3581634Sbrian#include <net/if_var.h>
3682437Sbrian#endif
3740561Sbrian#include <net/route.h>
3840561Sbrian#include <netinet/in_systm.h>
3981634Sbrian#include <netinet/in_var.h>
4040561Sbrian#include <netinet/ip.h>
4181634Sbrian#ifndef NOINET6
4281634Sbrian#include <netinet6/nd6.h>
4381634Sbrian#endif
4440561Sbrian#include <sys/un.h>
4540561Sbrian
4646085Sbrian#include <errno.h>
4740561Sbrian#include <string.h>
48102500Sbrian#include <stdarg.h>
4940561Sbrian#include <stdio.h>
5040561Sbrian#include <stdlib.h>
5146085Sbrian#include <sys/ioctl.h>
5246085Sbrian#include <sys/sysctl.h>
5340561Sbrian#include <termios.h>
5440561Sbrian#include <unistd.h>
5540561Sbrian
5646686Sbrian#include "layer.h"
5740561Sbrian#include "defs.h"
5840561Sbrian#include "command.h"
5940561Sbrian#include "mbuf.h"
6040561Sbrian#include "log.h"
6140561Sbrian#include "id.h"
6240561Sbrian#include "timer.h"
6340561Sbrian#include "fsm.h"
6440561Sbrian#include "iplist.h"
6540561Sbrian#include "lqr.h"
6640561Sbrian#include "hdlc.h"
6740561Sbrian#include "throughput.h"
6840561Sbrian#include "slcompress.h"
6940561Sbrian#include "descriptor.h"
7081634Sbrian#include "ncpaddr.h"
7140561Sbrian#include "ipcp.h"
7247648Sbrian#include "filter.h"
7340561Sbrian#include "lcp.h"
7440561Sbrian#include "ccp.h"
7540561Sbrian#include "link.h"
7640561Sbrian#include "mp.h"
7743313Sbrian#ifndef NORADIUS
7843313Sbrian#include "radius.h"
7943313Sbrian#endif
8081634Sbrian#include "ipv6cp.h"
8181634Sbrian#include "ncp.h"
8240561Sbrian#include "bundle.h"
8340561Sbrian#include "prompt.h"
8440561Sbrian#include "iface.h"
8540561Sbrian
86113067Sume#define IN6MASK128	{{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
87113067Sume			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
88113067Sumestatic const struct in6_addr in6mask128 = IN6MASK128;
8940561Sbrian
90113067Sume
9140561Sbrianstruct iface *
9240561Sbrianiface_Create(const char *name)
9340561Sbrian{
9481634Sbrian  int mib[6], maxtries, err;
9561830Sbrian  size_t needed, namelen;
9658032Sbrian  char *buf, *ptr, *end;
9740561Sbrian  struct if_msghdr *ifm;
9840561Sbrian  struct ifa_msghdr *ifam;
9940561Sbrian  struct sockaddr_dl *dl;
10058032Sbrian  struct sockaddr *sa[RTAX_MAX];
10140561Sbrian  struct iface *iface;
10240561Sbrian  struct iface_addr *addr;
10340561Sbrian
10440561Sbrian  mib[0] = CTL_NET;
10540561Sbrian  mib[1] = PF_ROUTE;
10640561Sbrian  mib[2] = 0;
10740561Sbrian  mib[3] = 0;
10840561Sbrian  mib[4] = NET_RT_IFLIST;
10940561Sbrian  mib[5] = 0;
11040561Sbrian
11175121Sbrian  maxtries = 20;
11275121Sbrian  err = 0;
11375121Sbrian  do {
11475121Sbrian    if (maxtries-- == 0 || (err && err != ENOMEM)) {
11575121Sbrian      fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(err));
11675121Sbrian      return NULL;
11775121Sbrian    }
11840561Sbrian
11975121Sbrian    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
12075121Sbrian      fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
12175121Sbrian                strerror(errno));
12275121Sbrian      return NULL;
12375121Sbrian    }
12440561Sbrian
12575121Sbrian    if ((buf = (char *)malloc(needed)) == NULL) {
12675121Sbrian      fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
12775121Sbrian      return NULL;
12875121Sbrian    }
12940561Sbrian
13075121Sbrian    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
13175121Sbrian      err = errno;
13275121Sbrian      free(buf);
13375121Sbrian      buf = NULL;
13475121Sbrian    }
13575121Sbrian  } while (buf == NULL);
13675121Sbrian
13740561Sbrian  ptr = buf;
13840561Sbrian  end = buf + needed;
13940561Sbrian  iface = NULL;
14061830Sbrian  namelen = strlen(name);
14140561Sbrian
14240561Sbrian  while (ptr < end && iface == NULL) {
14340561Sbrian    ifm = (struct if_msghdr *)ptr;			/* On if_msghdr */
14440561Sbrian    if (ifm->ifm_type != RTM_IFINFO)
14540561Sbrian      break;
14640561Sbrian    dl = (struct sockaddr_dl *)(ifm + 1);		/* Single _dl at end */
14761830Sbrian    if (dl->sdl_nlen == namelen && !strncmp(name, dl->sdl_data, namelen)) {
14840561Sbrian      iface = (struct iface *)malloc(sizeof *iface);
14940561Sbrian      if (iface == NULL) {
15040561Sbrian        fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
15140561Sbrian        return NULL;
15240561Sbrian      }
15340561Sbrian      iface->name = strdup(name);
154218397Sbrian      iface->descr = NULL;
15578410Sbrian      iface->index = ifm->ifm_index;
15640561Sbrian      iface->flags = ifm->ifm_flags;
15778410Sbrian      iface->mtu = 0;
15881634Sbrian      iface->addrs = 0;
15981634Sbrian      iface->addr = NULL;
16040561Sbrian    }
16140561Sbrian    ptr += ifm->ifm_msglen;				/* First ifa_msghdr */
16240561Sbrian    for (; ptr < end; ptr += ifam->ifam_msglen) {
16340561Sbrian      ifam = (struct ifa_msghdr *)ptr;			/* Next if address */
16440561Sbrian
16540561Sbrian      if (ifam->ifam_type != RTM_NEWADDR)		/* finished this if */
16640561Sbrian        break;
16740561Sbrian
16858032Sbrian      if (iface != NULL && ifam->ifam_addrs & RTA_IFA) {
16958032Sbrian        /* Found a configured interface ! */
17058032Sbrian        iface_ParseHdr(ifam, sa);
17140561Sbrian
17281634Sbrian        if (sa[RTAX_IFA] && (sa[RTAX_IFA]->sa_family == AF_INET
17381634Sbrian#ifndef NOINET6
17481634Sbrian                             || sa[RTAX_IFA]->sa_family == AF_INET6
17581634Sbrian#endif
17681634Sbrian                             )) {
17758032Sbrian          /* Record the address */
17840561Sbrian
17981634Sbrian          addr = (struct iface_addr *)
18081634Sbrian            realloc(iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
18140561Sbrian          if (addr == NULL)
18240561Sbrian            break;
18381634Sbrian          iface->addr = addr;
18440561Sbrian
18581634Sbrian          addr += iface->addrs;
18681634Sbrian          iface->addrs++;
18740561Sbrian
18881634Sbrian          ncprange_setsa(&addr->ifa, sa[RTAX_IFA], sa[RTAX_NETMASK]);
18958032Sbrian          if (sa[RTAX_BRD])
19081634Sbrian            ncpaddr_setsa(&addr->peer, sa[RTAX_BRD]);
19158032Sbrian          else
19281634Sbrian            ncpaddr_init(&addr->peer);
19340561Sbrian        }
19440561Sbrian      }
19540561Sbrian    }
19640561Sbrian  }
19740561Sbrian
19840561Sbrian  free(buf);
19940561Sbrian
20040561Sbrian  return iface;
20140561Sbrian}
20240561Sbrian
20381634Sbrianstatic int
20481634Sbrianiface_addr_Zap(const char *name, struct iface_addr *addr, int s)
20581634Sbrian{
20681634Sbrian  struct ifaliasreq ifra;
20781634Sbrian#ifndef NOINET6
20881634Sbrian  struct in6_aliasreq ifra6;
20981634Sbrian#endif
21081634Sbrian  struct sockaddr_in *me4, *msk4, *peer4;
21181634Sbrian  struct sockaddr_storage ssme, sspeer, ssmsk;
21281634Sbrian  int res;
21381634Sbrian
21481634Sbrian  ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
21581634Sbrian  ncpaddr_getsa(&addr->peer, &sspeer);
21681634Sbrian  res = 0;
21781634Sbrian
21881634Sbrian  switch (ncprange_family(&addr->ifa)) {
21981634Sbrian  case AF_INET:
22081634Sbrian    memset(&ifra, '\0', sizeof ifra);
22181634Sbrian    strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
22281634Sbrian
22381634Sbrian    me4 = (struct sockaddr_in *)&ifra.ifra_addr;
22481634Sbrian    memcpy(me4, &ssme, sizeof *me4);
22581634Sbrian
22681634Sbrian    msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
22781634Sbrian    memcpy(msk4, &ssmsk, sizeof *msk4);
22881634Sbrian
22981634Sbrian    peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
23081634Sbrian    if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
23181634Sbrian      peer4->sin_family = AF_INET;
23281634Sbrian      peer4->sin_len = sizeof(*peer4);
23381634Sbrian      peer4->sin_addr.s_addr = INADDR_NONE;
23481634Sbrian    } else
23581634Sbrian      memcpy(peer4, &sspeer, sizeof *peer4);
23681634Sbrian
23781634Sbrian    res = ID0ioctl(s, SIOCDIFADDR, &ifra);
23887125Sbrian    if (log_IsKept(LogDEBUG)) {
23987125Sbrian      char buf[100];
24087125Sbrian
24187125Sbrian      snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa));
24287125Sbrian      log_Printf(LogWARN, "%s: DIFADDR %s -> %s returns %d\n",
24387125Sbrian                 ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res);
24487125Sbrian    }
24581634Sbrian    break;
24681634Sbrian
24781634Sbrian#ifndef NOINET6
24881634Sbrian  case AF_INET6:
24981634Sbrian    memset(&ifra6, '\0', sizeof ifra6);
25081634Sbrian    strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
25181634Sbrian
25281634Sbrian    memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
25381634Sbrian    memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
25481634Sbrian    ifra6.ifra_prefixmask.sin6_family = AF_UNSPEC;
25581634Sbrian    if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
25681634Sbrian      ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
25781634Sbrian    else
25881634Sbrian      memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
25981634Sbrian    ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
26081634Sbrian    ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
26198243Sbrian
26281634Sbrian    res = ID0ioctl(s, SIOCDIFADDR_IN6, &ifra6);
26381634Sbrian    break;
26481634Sbrian#endif
26581634Sbrian  }
26681634Sbrian
26781634Sbrian  if (res == -1) {
26881634Sbrian    char dst[40];
26981634Sbrian    const char *end =
27081634Sbrian#ifndef NOINET6
27181634Sbrian      ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
27281634Sbrian#endif
27381634Sbrian      "";
27481634Sbrian
27581634Sbrian    if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
27681634Sbrian      log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s): %s\n",
27781634Sbrian                 end, ncprange_ntoa(&addr->ifa), strerror(errno));
27881634Sbrian    else {
27981634Sbrian      snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
28081634Sbrian      log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
28181634Sbrian                 end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
28281634Sbrian    }
28381634Sbrian  }
28481634Sbrian
28581634Sbrian  return res != -1;
28681634Sbrian}
28781634Sbrian
28887127Sbrianstatic int
28981634Sbrianiface_addr_Add(const char *name, struct iface_addr *addr, int s)
29040561Sbrian{
29140561Sbrian  struct ifaliasreq ifra;
29281634Sbrian#ifndef NOINET6
29381634Sbrian  struct in6_aliasreq ifra6;
29481634Sbrian#endif
29581634Sbrian  struct sockaddr_in *me4, *msk4, *peer4;
29681634Sbrian  struct sockaddr_storage ssme, sspeer, ssmsk;
29781634Sbrian  int res;
29840561Sbrian
29981634Sbrian  ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
30081634Sbrian  ncpaddr_getsa(&addr->peer, &sspeer);
30181634Sbrian  res = 0;
30281634Sbrian
30381634Sbrian  switch (ncprange_family(&addr->ifa)) {
30481634Sbrian  case AF_INET:
30540561Sbrian    memset(&ifra, '\0', sizeof ifra);
30640561Sbrian    strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
30781634Sbrian
30881634Sbrian    me4 = (struct sockaddr_in *)&ifra.ifra_addr;
30981634Sbrian    memcpy(me4, &ssme, sizeof *me4);
31081634Sbrian
31181634Sbrian    msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
31281634Sbrian    memcpy(msk4, &ssmsk, sizeof *msk4);
31381634Sbrian
31481634Sbrian    peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
31581634Sbrian    if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
31681634Sbrian      peer4->sin_family = AF_INET;
31781634Sbrian      peer4->sin_len = sizeof(*peer4);
31881634Sbrian      peer4->sin_addr.s_addr = INADDR_NONE;
31981634Sbrian    } else
32081634Sbrian      memcpy(peer4, &sspeer, sizeof *peer4);
32181634Sbrian
32281634Sbrian    res = ID0ioctl(s, SIOCAIFADDR, &ifra);
32387125Sbrian    if (log_IsKept(LogDEBUG)) {
32487125Sbrian      char buf[100];
32587125Sbrian
32687125Sbrian      snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa));
32787125Sbrian      log_Printf(LogWARN, "%s: AIFADDR %s -> %s returns %d\n",
32887125Sbrian                 ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res);
32987125Sbrian    }
33081634Sbrian    break;
33181634Sbrian
33281634Sbrian#ifndef NOINET6
33381634Sbrian  case AF_INET6:
33481634Sbrian    memset(&ifra6, '\0', sizeof ifra6);
33581634Sbrian    strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
33681634Sbrian
33781634Sbrian    memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
33881634Sbrian    memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
33981634Sbrian    if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
34081634Sbrian      ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
341113067Sume    else if (memcmp(&((struct sockaddr_in6 *)&ssmsk)->sin6_addr, &in6mask128,
342113067Sume		    sizeof in6mask128) == 0)
34381634Sbrian      memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
34481634Sbrian    ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
34581634Sbrian    ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
34681634Sbrian
34781634Sbrian    res = ID0ioctl(s, SIOCAIFADDR_IN6, &ifra6);
34881634Sbrian    break;
34981634Sbrian#endif
35040561Sbrian  }
35181634Sbrian
35281634Sbrian  if (res == -1) {
35381634Sbrian    char dst[40];
35481634Sbrian    const char *end =
35581634Sbrian#ifndef NOINET6
35681634Sbrian      ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
35781634Sbrian#endif
35881634Sbrian      "";
35981634Sbrian
36081634Sbrian    if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
36181634Sbrian      log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n",
36281634Sbrian                 end, ncprange_ntoa(&addr->ifa), strerror(errno));
36381634Sbrian    else {
36481634Sbrian      snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
36585991Sbrian      log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s -> %s): %s\n",
36681634Sbrian                 end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
36781634Sbrian    }
36881634Sbrian  }
36987127Sbrian
37087127Sbrian  return res != -1;
37140561Sbrian}
37240561Sbrian
373218397Sbrianint
374218397Sbrianiface_Name(struct iface *iface, const char *name)
375218397Sbrian{
376218397Sbrian  struct ifreq ifr;
377218397Sbrian  int s;
378218397Sbrian  char *newname;
37981634Sbrian
380218397Sbrian  if ((newname = strdup(name)) == NULL) {
381218397Sbrian    log_Printf(LogWARN, "iface name: strdup failed: %s\n", strerror(errno));
382218397Sbrian    return 0;
383218397Sbrian  }
384218397Sbrian
385218397Sbrian  if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
386218397Sbrian    log_Printf(LogERROR, "iface name: socket(): %s\n", strerror(errno));
387218397Sbrian    free(newname);
388218397Sbrian    return 0;
389218397Sbrian  }
390218397Sbrian
391218397Sbrian  strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
392218397Sbrian  ifr.ifr_data = newname;
393218397Sbrian  if (ID0ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
394218397Sbrian    log_Printf(LogWARN, "iface name: ioctl(SIOCSIFNAME, %s -> %s): %s\n",
395218397Sbrian               name, newname, strerror(errno));
396218397Sbrian    free(newname);
397218397Sbrian    return 0;
398218397Sbrian  }
399218397Sbrian
400218397Sbrian  free(iface->name);
401218397Sbrian  iface->name = newname;
402218397Sbrian
403218397Sbrian  return 1;
404218397Sbrian}
405218397Sbrian
406218397Sbrianint
407218397Sbrianiface_Descr(struct cmdargs const *arg)
408218397Sbrian{
409218397Sbrian  struct ifreq ifr;
410218397Sbrian  struct iface *iface;
411218397Sbrian  size_t sz, len;
412218397Sbrian  int s, n, ifdescr_maxlen;
413218397Sbrian  char *descr;
414218397Sbrian
415218397Sbrian  sz = sizeof(int);
416218397Sbrian  if (sysctlbyname("net.ifdescr_maxlen", &ifdescr_maxlen, &sz, NULL, 0) < 0) {
417218397Sbrian    log_Printf(LogERROR, "iface descr: sysctl failed: %s\n", strerror(errno));
418218397Sbrian    return 1;
419218397Sbrian  }
420218397Sbrian
421218397Sbrian  if (ifdescr_maxlen < 1) {
422218397Sbrian    log_Printf(LogERROR, "iface descr: sysctl net.ifdescr_maxlen < 1\n");
423218397Sbrian    return 1;
424218397Sbrian  }
425218397Sbrian
426218397Sbrian  sz = sizeof(char) * ifdescr_maxlen;
427218397Sbrian  if ((descr = malloc(sz)) == NULL) {
428218397Sbrian    log_Printf(LogERROR, "iface descr: malloc failed: %s\n", strerror(errno));
429218397Sbrian    return 1;
430218397Sbrian  }
431218397Sbrian
432218397Sbrian  *descr = '\0';
433218397Sbrian  n = arg->argn;
434218397Sbrian  while (n < arg->argc) {
435218397Sbrian    if (n > arg->argn && (len = strlcat(descr, " ", sz)) >= sz)
436218397Sbrian      break;
437218397Sbrian    if ((len = strlcat(descr, arg->argv[n], sz)) >= sz)
438218397Sbrian      break;
439218397Sbrian    ++n;
440218397Sbrian  }
441218397Sbrian  if (len >= sz) {
442218397Sbrian    log_Printf(LogERROR, "iface descr: description exceeds maximum (%d)\n",
443218397Sbrian               ifdescr_maxlen-1);
444218397Sbrian    free(descr);
445218397Sbrian    return 1;
446218397Sbrian  }
447218397Sbrian
448218397Sbrian  if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
449218397Sbrian    log_Printf(LogERROR, "iface descr: socket(): %s\n", strerror(errno));
450218397Sbrian    free(descr);
451218397Sbrian    return 1;
452218397Sbrian  }
453218397Sbrian
454218397Sbrian  iface = arg->bundle->iface;
455218397Sbrian  strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
456218397Sbrian  ifr.ifr_buffer.length = strlen(descr) + 1;
457218397Sbrian  ifr.ifr_buffer.buffer = descr;
458218397Sbrian  if (ID0ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) {
459218397Sbrian    log_Printf(LogWARN, "iface descr: ioctl(SIOCSIFDESCR, %s): %s\n",
460218397Sbrian               descr, strerror(errno));
461218397Sbrian    free(descr);
462218397Sbrian    return 1;
463218397Sbrian  }
464218397Sbrian
465218397Sbrian  free(iface->descr);
466218397Sbrian  iface->descr = descr;
467218397Sbrian
468218397Sbrian  return 0;
469218397Sbrian}
470218397Sbrian
47140561Sbrianvoid
47281634Sbrianiface_Clear(struct iface *iface, struct ncp *ncp, int family, int how)
47340561Sbrian{
474230347Seadler  int af, inskip, in6skip, s4 = -1, s6 = -1, *s;
475134789Sbrian  unsigned n;
47640561Sbrian
47781634Sbrian  if (iface->addrs) {
47881634Sbrian    inskip = in6skip = how == IFACE_CLEAR_ALL ? 0 : 1;
47940561Sbrian
48081634Sbrian    for (n = 0; n < iface->addrs; n++) {
48181634Sbrian      af = ncprange_family(&iface->addr[n].ifa);
48281634Sbrian      if (family == 0 || family == af) {
48381634Sbrian        if (!iface->addr[n].system && (how & IFACE_SYSTEM))
48481634Sbrian          continue;
48581634Sbrian        switch (af) {
48681634Sbrian        case AF_INET:
48781634Sbrian          if (inskip) {
48881634Sbrian            inskip = 0;
48981634Sbrian            continue;
49081634Sbrian          }
49181634Sbrian          s = &s4;
49281634Sbrian          break;
49398243Sbrian
49481634Sbrian#ifndef NOINET6
49581634Sbrian        case AF_INET6:
49681634Sbrian          if (in6skip) {
49781634Sbrian            in6skip = 0;
49881634Sbrian            continue;
49981634Sbrian          }
50081634Sbrian          s = &s6;
50181634Sbrian          break;
50281634Sbrian#endif
50381922Sbrian        default:
50481922Sbrian          continue;
50581634Sbrian        }
50681634Sbrian
50781634Sbrian        if (*s == -1 && (*s = ID0socket(af, SOCK_DGRAM, 0)) == -1)
50881634Sbrian          log_Printf(LogERROR, "iface_Clear: socket(): %s\n", strerror(errno));
50981634Sbrian        else if (iface_addr_Zap(iface->name, iface->addr + n, *s)) {
51081634Sbrian          ncp_IfaceAddrDeleted(ncp, iface->addr + n);
51181634Sbrian          bcopy(iface->addr + n + 1, iface->addr + n,
51281634Sbrian                (iface->addrs - n - 1) * sizeof *iface->addr);
51381634Sbrian          iface->addrs--;
51481634Sbrian          n--;
51581634Sbrian        }
51681634Sbrian      }
51781634Sbrian    }
51881634Sbrian
51955531Sbrian    /* Don't bother realloc()ing - we have little to gain */
52081634Sbrian
52181634Sbrian    if (s4)
52281634Sbrian      close(s4);
52381634Sbrian    if (s6)
52481634Sbrian      close(s6);
52555531Sbrian  }
52640561Sbrian}
52740561Sbrian
52840561Sbrianint
52981634Sbrianiface_Add(struct iface *iface, struct ncp *ncp, const struct ncprange *ifa,
53081634Sbrian          const struct ncpaddr *peer, int how)
53140561Sbrian{
532134789Sbrian  int af, removed, s;
533134789Sbrian  unsigned n;
53487127Sbrian  struct ncpaddr ncplocal;
53587127Sbrian  struct iface_addr *addr, newaddr;
53640561Sbrian
53781634Sbrian  af = ncprange_family(ifa);
53881634Sbrian  if ((s = ID0socket(af, SOCK_DGRAM, 0)) == -1) {
53981634Sbrian    log_Printf(LogERROR, "iface_Add: socket(): %s\n", strerror(errno));
54040561Sbrian    return 0;
54140561Sbrian  }
54281634Sbrian  ncprange_getaddr(ifa, &ncplocal);
54340561Sbrian
54481634Sbrian  for (n = 0; n < iface->addrs; n++) {
54581959Sbrian    if (ncprange_contains(&iface->addr[n].ifa, &ncplocal) ||
54681959Sbrian        ncpaddr_equal(&iface->addr[n].peer, peer)) {
54787127Sbrian      /* Replace this sockaddr */
54881634Sbrian      if (!(how & IFACE_FORCE_ADD)) {
54981634Sbrian        close(s);
55081634Sbrian        return 0;	/* errno = EEXIST; */
55174765Sbrian      }
55281634Sbrian
55381634Sbrian      if (ncprange_equal(&iface->addr[n].ifa, ifa) &&
55481634Sbrian          ncpaddr_equal(&iface->addr[n].peer, peer)) {
55581634Sbrian        close(s);
556191006Sbz        ncp_IfaceAddrAdded(ncp, iface->addr + n);
55781634Sbrian        return 1;	/* Already there */
55874765Sbrian      }
55974765Sbrian
56087127Sbrian      removed = iface_addr_Zap(iface->name, iface->addr + n, s);
56187127Sbrian      if (removed)
56287127Sbrian        ncp_IfaceAddrDeleted(ncp, iface->addr + n);
56387127Sbrian      ncprange_copy(&iface->addr[n].ifa, ifa);
56487127Sbrian      ncpaddr_copy(&iface->addr[n].peer, peer);
56587127Sbrian      if (!iface_addr_Add(iface->name, iface->addr + n, s)) {
56687127Sbrian        if (removed) {
56787127Sbrian          bcopy(iface->addr + n + 1, iface->addr + n,
56887127Sbrian                (iface->addrs - n - 1) * sizeof *iface->addr);
56987127Sbrian          iface->addrs--;
57087127Sbrian          n--;
57187127Sbrian        }
57281634Sbrian        close(s);
57387127Sbrian        return 0;
57440664Sbrian      }
57587127Sbrian      close(s);
57687127Sbrian      ncp_IfaceAddrAdded(ncp, iface->addr + n);
57787127Sbrian      return 1;
57840664Sbrian    }
57940664Sbrian  }
58040664Sbrian
58181634Sbrian  addr = (struct iface_addr *)realloc
58281634Sbrian    (iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
58381634Sbrian  if (addr == NULL) {
58481634Sbrian    log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
58581634Sbrian    close(s);
58681634Sbrian    return 0;
58740664Sbrian  }
58881634Sbrian  iface->addr = addr;
58940664Sbrian
59087127Sbrian  ncprange_copy(&newaddr.ifa, ifa);
59187127Sbrian  ncpaddr_copy(&newaddr.peer, peer);
59287127Sbrian  newaddr.system = !!(how & IFACE_SYSTEM);
59387127Sbrian  if (!iface_addr_Add(iface->name, &newaddr, s)) {
59487127Sbrian    close(s);
59587127Sbrian    return 0;
59687127Sbrian  }
59787127Sbrian
59881634Sbrian  if (how & IFACE_ADD_FIRST) {
59981634Sbrian    /* Stuff it at the start of our list */
60081634Sbrian    n = 0;
60181634Sbrian    bcopy(iface->addr, iface->addr + 1, iface->addrs * sizeof *iface->addr);
60281634Sbrian  } else
60381634Sbrian    n = iface->addrs;
60440561Sbrian
60581634Sbrian  iface->addrs++;
60687127Sbrian  memcpy(iface->addr + n, &newaddr, sizeof(*iface->addr));
60740561Sbrian
60881634Sbrian  close(s);
60981634Sbrian  ncp_IfaceAddrAdded(ncp, iface->addr + n);
61040561Sbrian
61140561Sbrian  return 1;
61240561Sbrian}
61340561Sbrian
61440561Sbrianint
61581634Sbrianiface_Delete(struct iface *iface, struct ncp *ncp, const struct ncpaddr *del)
61640561Sbrian{
61781634Sbrian  struct ncpaddr found;
618134789Sbrian  unsigned n;
619134789Sbrian  int res, s;
62040561Sbrian
62181634Sbrian  if ((s = ID0socket(ncpaddr_family(del), SOCK_DGRAM, 0)) == -1) {
62281634Sbrian    log_Printf(LogERROR, "iface_Delete: socket(): %s\n", strerror(errno));
62381634Sbrian    return 0;
62481634Sbrian  }
62581634Sbrian
62681634Sbrian  for (n = res = 0; n < iface->addrs; n++) {
62781634Sbrian    ncprange_getaddr(&iface->addr[n].ifa, &found);
62881634Sbrian    if (ncpaddr_equal(&found, del)) {
62987127Sbrian      if (iface_addr_Zap(iface->name, iface->addr + n, s)) {
63087127Sbrian        ncp_IfaceAddrDeleted(ncp, iface->addr + n);
63187127Sbrian        bcopy(iface->addr + n + 1, iface->addr + n,
63287127Sbrian              (iface->addrs - n - 1) * sizeof *iface->addr);
63387127Sbrian        iface->addrs--;
63487127Sbrian        res = 1;
63587127Sbrian      }
63681634Sbrian      break;
63740561Sbrian    }
63881634Sbrian  }
63940561Sbrian
64081634Sbrian  close(s);
64181634Sbrian
64281634Sbrian  return res;
64340561Sbrian}
64440561Sbrian
64547538Sbrian#define IFACE_ADDFLAGS 1
64647538Sbrian#define IFACE_DELFLAGS 2
64747538Sbrian
64847538Sbrianstatic int
64974916Sbrianiface_ChangeFlags(const char *ifname, int flags, int how)
65047538Sbrian{
65147538Sbrian  struct ifreq ifrq;
652102574Ssobomax  int s, new_flags;
65347538Sbrian
65489422Sbrian  s = ID0socket(PF_INET, SOCK_DGRAM, 0);
65547538Sbrian  if (s < 0) {
65652315Sbrian    log_Printf(LogERROR, "iface_ChangeFlags: socket: %s\n", strerror(errno));
65747538Sbrian    return 0;
65847538Sbrian  }
65947538Sbrian
66047538Sbrian  memset(&ifrq, '\0', sizeof ifrq);
66174916Sbrian  strncpy(ifrq.ifr_name, ifname, sizeof ifrq.ifr_name - 1);
66247538Sbrian  ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
66347538Sbrian  if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
66452315Sbrian    log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n",
66547538Sbrian       strerror(errno));
66647538Sbrian    close(s);
66747538Sbrian    return 0;
66847538Sbrian  }
669139977Sbrian#ifdef __FreeBSD__
670102574Ssobomax  new_flags = (ifrq.ifr_flags & 0xffff) | (ifrq.ifr_flagshigh << 16);
671139977Sbrian#else
672139977Sbrian  new_flags = ifrq.ifr_flags & 0xffff;
673139977Sbrian#endif
67447538Sbrian
67547538Sbrian  if (how == IFACE_ADDFLAGS)
676102574Ssobomax    new_flags |= flags;
67747538Sbrian  else
678102574Ssobomax    new_flags &= ~flags;
679102574Ssobomax  ifrq.ifr_flags = new_flags & 0xffff;
680139977Sbrian#ifdef __FreeBSD__
681102574Ssobomax  ifrq.ifr_flagshigh = new_flags >> 16;
682139977Sbrian#endif
68347538Sbrian
68447538Sbrian  if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
68552315Sbrian    log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n",
68647538Sbrian       strerror(errno));
68747538Sbrian    close(s);
68847538Sbrian    return 0;
68947538Sbrian  }
69047538Sbrian  close(s);
69147538Sbrian
69247538Sbrian  return 1;	/* Success */
69347538Sbrian}
69447538Sbrian
69547538Sbrianint
69674916Sbrianiface_SetFlags(const char *ifname, int flags)
69747538Sbrian{
69874916Sbrian  return iface_ChangeFlags(ifname, flags, IFACE_ADDFLAGS);
69947538Sbrian}
70047538Sbrian
70147538Sbrianint
70274916Sbrianiface_ClearFlags(const char *ifname, int flags)
70347538Sbrian{
70474916Sbrian  return iface_ChangeFlags(ifname, flags, IFACE_DELFLAGS);
70547538Sbrian}
70647538Sbrian
70740561Sbrianvoid
708218397Sbrianiface_Free(struct iface *iface)
709218397Sbrian{
710218397Sbrian    free(iface->name);
711218397Sbrian    free(iface->descr);
712218397Sbrian    free(iface->addr);
713218397Sbrian    free(iface);
714218397Sbrian}
715218397Sbrian
716218397Sbrianvoid
71740561Sbrianiface_Destroy(struct iface *iface)
71840561Sbrian{
719218397Sbrian  struct ifreq ifr;
720218397Sbrian  int s;
72140561Sbrian
72240561Sbrian  if (iface != NULL) {
723218397Sbrian    if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
724218397Sbrian      log_Printf(LogERROR, "iface_Destroy: socket(): %s\n", strerror(errno));
725218397Sbrian    } else {
726218397Sbrian      strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
727218397Sbrian      if (ID0ioctl(s, SIOCIFDESTROY, (caddr_t)&ifr) < 0)
728218397Sbrian        log_Printf(LogWARN, "iface_Destroy: ioctl(SIOCIFDESTROY, %s): %s\n",
729218397Sbrian               iface->name, strerror(errno));
730218397Sbrian    }
731218397Sbrian    iface_Free(iface);
73240561Sbrian  }
73340561Sbrian}
73440561Sbrian
73540561Sbrian#define if_entry(x) { IFF_##x, #x }
73640561Sbrian
73740561Sbrianstruct {
73840561Sbrian  int flag;
73940561Sbrian  const char *value;
74040561Sbrian} if_flags[] = {
74140561Sbrian  if_entry(UP),
74240561Sbrian  if_entry(BROADCAST),
74340561Sbrian  if_entry(DEBUG),
74440561Sbrian  if_entry(LOOPBACK),
74540561Sbrian  if_entry(POINTOPOINT),
74640561Sbrian  if_entry(RUNNING),
74740561Sbrian  if_entry(NOARP),
74840561Sbrian  if_entry(PROMISC),
74940561Sbrian  if_entry(ALLMULTI),
75040561Sbrian  if_entry(OACTIVE),
75140561Sbrian  if_entry(SIMPLEX),
75240561Sbrian  if_entry(LINK0),
75340561Sbrian  if_entry(LINK1),
75440561Sbrian  if_entry(LINK2),
75540561Sbrian  if_entry(MULTICAST),
75640561Sbrian  { 0, "???" }
75740561Sbrian};
75840561Sbrian
75940561Sbrianint
76040561Sbrianiface_Show(struct cmdargs const *arg)
76140561Sbrian{
76281634Sbrian  struct ncpaddr ncpaddr;
76340561Sbrian  struct iface *iface = arg->bundle->iface, *current;
764134789Sbrian  unsigned f;
765134789Sbrian  int flags;
76681634Sbrian#ifndef NOINET6
76781634Sbrian  int scopeid, width;
76881634Sbrian#endif
76981634Sbrian  struct in_addr mask;
77040561Sbrian
77140561Sbrian  current = iface_Create(iface->name);
77240561Sbrian  flags = iface->flags = current->flags;
773218397Sbrian  iface_Free(current);
77440561Sbrian
77540561Sbrian  prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
77640561Sbrian  for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
77782048Sbrian    if ((if_flags[f].flag & flags)) {
77840561Sbrian      prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
77940561Sbrian                    if_flags[f].value);
78040561Sbrian      flags &= ~if_flags[f].flag;
78140561Sbrian    }
78282048Sbrian
78382048Sbrian#if 0
78482048Sbrian  if (flags)
78582048Sbrian    prompt_Printf(arg->prompt, "%s0x%x", flags == iface->flags ? "" : ",",
78682048Sbrian                  flags);
78782048Sbrian#endif
78882048Sbrian
789134789Sbrian  prompt_Printf(arg->prompt, "> mtu %lu has %d address%s:\n", iface->mtu,
79081634Sbrian                iface->addrs, iface->addrs == 1 ? "" : "es");
79140561Sbrian
79281634Sbrian  for (f = 0; f < iface->addrs; f++) {
79381634Sbrian    ncprange_getaddr(&iface->addr[f].ifa, &ncpaddr);
79481634Sbrian    switch (ncprange_family(&iface->addr[f].ifa)) {
79581634Sbrian    case AF_INET:
79681634Sbrian      prompt_Printf(arg->prompt, "  inet %s --> ", ncpaddr_ntoa(&ncpaddr));
79781634Sbrian      if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
79881634Sbrian        prompt_Printf(arg->prompt, "255.255.255.255");
79981634Sbrian      else
80081634Sbrian        prompt_Printf(arg->prompt, "%s", ncpaddr_ntoa(&iface->addr[f].peer));
80181634Sbrian      ncprange_getip4mask(&iface->addr[f].ifa, &mask);
80281634Sbrian      prompt_Printf(arg->prompt, " netmask 0x%08lx", (long)ntohl(mask.s_addr));
80381634Sbrian      break;
80481634Sbrian
80581634Sbrian#ifndef NOINET6
80681634Sbrian    case AF_INET6:
80781634Sbrian      prompt_Printf(arg->prompt, "  inet6 %s", ncpaddr_ntoa(&ncpaddr));
80881634Sbrian      if (ncpaddr_family(&iface->addr[f].peer) != AF_UNSPEC)
80981634Sbrian        prompt_Printf(arg->prompt, " --> %s",
81081634Sbrian                      ncpaddr_ntoa(&iface->addr[f].peer));
81181634Sbrian      ncprange_getwidth(&iface->addr[f].ifa, &width);
81281695Sbrian      if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
81381695Sbrian        prompt_Printf(arg->prompt, " prefixlen %d", width);
81481634Sbrian      if ((scopeid = ncprange_scopeid(&iface->addr[f].ifa)) != -1)
81581634Sbrian        prompt_Printf(arg->prompt, " scopeid 0x%x", (unsigned)scopeid);
81681634Sbrian      break;
81781634Sbrian#endif
81881634Sbrian    }
81940561Sbrian    prompt_Printf(arg->prompt, "\n");
82040561Sbrian  }
82140561Sbrian
82240561Sbrian  return 0;
82340561Sbrian}
82458032Sbrian
82558032Sbrianvoid
82658032Sbrianiface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX])
82758032Sbrian{
82858032Sbrian  char *wp;
82958032Sbrian  int rtax;
83058032Sbrian
83158032Sbrian  wp = (char *)(ifam + 1);
83258032Sbrian
83358032Sbrian  for (rtax = 0; rtax < RTAX_MAX; rtax++)
83458032Sbrian    if (ifam->ifam_addrs & (1 << rtax)) {
83558032Sbrian      sa[rtax] = (struct sockaddr *)wp;
83658032Sbrian      wp += ROUNDUP(sa[rtax]->sa_len);
83758032Sbrian    } else
83858032Sbrian      sa[rtax] = NULL;
83958032Sbrian}
840