iface.c revision 102500
1183867Sraj/*-
2183867Sraj * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
3183867Sraj * All rights reserved.
4183867Sraj *
5183867Sraj * Redistribution and use in source and binary forms, with or without
6183867Sraj * modification, are permitted provided that the following conditions
7183867Sraj * are met:
8183867Sraj * 1. Redistributions of source code must retain the above copyright
9183867Sraj *    notice, this list of conditions and the following disclaimer.
10183867Sraj * 2. Redistributions in binary form must reproduce the above copyright
11183867Sraj *    notice, this list of conditions and the following disclaimer in the
12183867Sraj *    documentation and/or other materials provided with the distribution.
13183867Sraj *
14183867Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15183867Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16183867Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17183867Sraj * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18183867Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19183867Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20183867Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21183867Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22183867Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23183867Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24183867Sraj * SUCH DAMAGE.
25183867Sraj *
26183867Sraj * $FreeBSD: head/usr.sbin/ppp/iface.c 102500 2002-08-27 20:11:58Z brian $
27183867Sraj */
28183867Sraj
29183867Sraj#include <sys/param.h>
30183867Sraj#include <sys/socket.h>
31183867Sraj#include <netinet/in.h>
32183867Sraj#include <net/if.h>
33183867Sraj#include <net/if_dl.h>
34183867Sraj#ifdef __FreeBSD__
35183867Sraj#include <net/if_var.h>
36183867Sraj#endif
37183867Sraj#include <net/route.h>
38183867Sraj#include <netinet/in_systm.h>
39183867Sraj#include <netinet/in_var.h>
40183867Sraj#include <netinet/ip.h>
41183867Sraj#ifndef NOINET6
42183867Sraj#include <netinet6/nd6.h>
43183867Sraj#endif
44183867Sraj#include <sys/un.h>
45183867Sraj
46183867Sraj#include <errno.h>
47183867Sraj#include <string.h>
48183867Sraj#include <stdarg.h>
49183867Sraj#include <stdio.h>
50183867Sraj#include <stdlib.h>
51183867Sraj#include <sys/ioctl.h>
52183867Sraj#include <sys/sysctl.h>
53183867Sraj#include <termios.h>
54183867Sraj#include <unistd.h>
55183867Sraj
56183867Sraj#include "layer.h"
57183867Sraj#include "defs.h"
58183867Sraj#include "command.h"
59183867Sraj#include "mbuf.h"
60183867Sraj#include "log.h"
61183867Sraj#include "id.h"
62183867Sraj#include "timer.h"
63183867Sraj#include "fsm.h"
64183867Sraj#include "iplist.h"
65183867Sraj#include "lqr.h"
66183867Sraj#include "hdlc.h"
67183867Sraj#include "throughput.h"
68183867Sraj#include "slcompress.h"
69183867Sraj#include "descriptor.h"
70183867Sraj#include "ncpaddr.h"
71183867Sraj#include "ipcp.h"
72209131Sraj#include "filter.h"
73209131Sraj#include "lcp.h"
74209131Sraj#include "ccp.h"
75183867Sraj#include "link.h"
76183867Sraj#include "mp.h"
77183867Sraj#ifndef NORADIUS
78186892Sraj#include "radius.h"
79183867Sraj#endif
80183867Sraj#include "ipv6cp.h"
81183867Sraj#include "ncp.h"
82183867Sraj#include "bundle.h"
83183867Sraj#include "prompt.h"
84183867Sraj#include "iface.h"
85183867Sraj
86183867Sraj
87183867Srajstruct iface *
88183867Srajiface_Create(const char *name)
89183867Sraj{
90194024Savg  int mib[6], maxtries, err;
91183867Sraj  size_t needed, namelen;
92183867Sraj  char *buf, *ptr, *end;
93183867Sraj  struct if_msghdr *ifm;
94183867Sraj  struct ifa_msghdr *ifam;
95183867Sraj  struct sockaddr_dl *dl;
96183867Sraj  struct sockaddr *sa[RTAX_MAX];
97183867Sraj  struct iface *iface;
98183867Sraj  struct iface_addr *addr;
99183867Sraj
100183867Sraj  mib[0] = CTL_NET;
101183867Sraj  mib[1] = PF_ROUTE;
102186892Sraj  mib[2] = 0;
103186892Sraj  mib[3] = 0;
104186892Sraj  mib[4] = NET_RT_IFLIST;
105186892Sraj  mib[5] = 0;
106183867Sraj
107239276Sgonzo  maxtries = 20;
108183867Sraj  err = 0;
109239276Sgonzo  do {
110239276Sgonzo    if (maxtries-- == 0 || (err && err != ENOMEM)) {
111193096Sattilio      fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(err));
112183867Sraj      return NULL;
113183867Sraj    }
114183867Sraj
115183867Sraj    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
116183867Sraj      fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
117183867Sraj                strerror(errno));
118183867Sraj      return NULL;
119183867Sraj    }
120183867Sraj
121183867Sraj    if ((buf = (char *)malloc(needed)) == NULL) {
122183867Sraj      fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
123183867Sraj      return NULL;
124183867Sraj    }
125183867Sraj
126183867Sraj    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
127183867Sraj      err = errno;
128183867Sraj      free(buf);
129183867Sraj      buf = NULL;
130183867Sraj    }
131183867Sraj  } while (buf == NULL);
132183867Sraj
133183867Sraj  ptr = buf;
134183867Sraj  end = buf + needed;
135183867Sraj  iface = NULL;
136183867Sraj  namelen = strlen(name);
137183867Sraj
138183867Sraj  while (ptr < end && iface == NULL) {
139183867Sraj    ifm = (struct if_msghdr *)ptr;			/* On if_msghdr */
140183867Sraj    if (ifm->ifm_type != RTM_IFINFO)
141183867Sraj      break;
142183867Sraj    dl = (struct sockaddr_dl *)(ifm + 1);		/* Single _dl at end */
143183867Sraj    if (dl->sdl_nlen == namelen && !strncmp(name, dl->sdl_data, namelen)) {
144183867Sraj      iface = (struct iface *)malloc(sizeof *iface);
145183867Sraj      if (iface == NULL) {
146183867Sraj        fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
147183867Sraj        return NULL;
148183867Sraj      }
149183867Sraj      iface->name = strdup(name);
150183867Sraj      iface->index = ifm->ifm_index;
151183867Sraj      iface->flags = ifm->ifm_flags;
152183867Sraj      iface->mtu = 0;
153183867Sraj      iface->addrs = 0;
154183867Sraj      iface->addr = NULL;
155183867Sraj    }
156183867Sraj    ptr += ifm->ifm_msglen;				/* First ifa_msghdr */
157183867Sraj    for (; ptr < end; ptr += ifam->ifam_msglen) {
158183867Sraj      ifam = (struct ifa_msghdr *)ptr;			/* Next if address */
159183867Sraj
160183867Sraj      if (ifam->ifam_type != RTM_NEWADDR)		/* finished this if */
161183867Sraj        break;
162183867Sraj
163183867Sraj      if (iface != NULL && ifam->ifam_addrs & RTA_IFA) {
164183867Sraj        /* Found a configured interface ! */
165183867Sraj        iface_ParseHdr(ifam, sa);
166183867Sraj
167209131Sraj        if (sa[RTAX_IFA] && (sa[RTAX_IFA]->sa_family == AF_INET
168183867Sraj#ifndef NOINET6
169183867Sraj                             || sa[RTAX_IFA]->sa_family == AF_INET6
170183867Sraj#endif
171183867Sraj                             )) {
172183867Sraj          /* Record the address */
173183867Sraj
174183867Sraj          addr = (struct iface_addr *)
175183867Sraj            realloc(iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
176183867Sraj          if (addr == NULL)
177183867Sraj            break;
178183867Sraj          iface->addr = addr;
179183867Sraj
180183867Sraj          addr += iface->addrs;
181183867Sraj          iface->addrs++;
182183867Sraj
183239276Sgonzo          ncprange_setsa(&addr->ifa, sa[RTAX_IFA], sa[RTAX_NETMASK]);
184239276Sgonzo          if (sa[RTAX_BRD])
185183867Sraj            ncpaddr_setsa(&addr->peer, sa[RTAX_BRD]);
186183867Sraj          else
187183867Sraj            ncpaddr_init(&addr->peer);
188183867Sraj        }
189183867Sraj      }
190183867Sraj    }
191183867Sraj  }
192183867Sraj
193183867Sraj  free(buf);
194183867Sraj
195183867Sraj  return iface;
196209131Sraj}
197209131Sraj
198183867Srajstatic int
199209131Srajiface_addr_Zap(const char *name, struct iface_addr *addr, int s)
200209131Sraj{
201209131Sraj  struct ifaliasreq ifra;
202209131Sraj#ifndef NOINET6
203209131Sraj  struct in6_aliasreq ifra6;
204209131Sraj#endif
205209131Sraj  struct sockaddr_in *me4, *msk4, *peer4;
206209131Sraj  struct sockaddr_storage ssme, sspeer, ssmsk;
207209131Sraj  int res;
208209131Sraj
209209131Sraj  ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
210183867Sraj  ncpaddr_getsa(&addr->peer, &sspeer);
211209131Sraj  res = 0;
212209131Sraj
213209131Sraj  switch (ncprange_family(&addr->ifa)) {
214209131Sraj  case AF_INET:
215209131Sraj    memset(&ifra, '\0', sizeof ifra);
216209131Sraj    strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
217209131Sraj
218209131Sraj    me4 = (struct sockaddr_in *)&ifra.ifra_addr;
219209131Sraj    memcpy(me4, &ssme, sizeof *me4);
220183867Sraj
221183867Sraj    msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
222183867Sraj    memcpy(msk4, &ssmsk, sizeof *msk4);
223183867Sraj
224183867Sraj    peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
225183867Sraj    if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
226183867Sraj      peer4->sin_family = AF_INET;
227183867Sraj      peer4->sin_len = sizeof(*peer4);
228183867Sraj      peer4->sin_addr.s_addr = INADDR_NONE;
229183867Sraj    } else
230183867Sraj      memcpy(peer4, &sspeer, sizeof *peer4);
231186892Sraj
232186892Sraj    res = ID0ioctl(s, SIOCDIFADDR, &ifra);
233186892Sraj    if (log_IsKept(LogDEBUG)) {
234186892Sraj      char buf[100];
235186892Sraj
236186892Sraj      snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa));
237186892Sraj      log_Printf(LogWARN, "%s: DIFADDR %s -> %s returns %d\n",
238186892Sraj                 ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res);
239186892Sraj    }
240186892Sraj    break;
241186892Sraj
242186892Sraj#ifndef NOINET6
243186892Sraj  case AF_INET6:
244186892Sraj    memset(&ifra6, '\0', sizeof ifra6);
245186892Sraj    strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
246186892Sraj
247186892Sraj    memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
248186892Sraj    memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
249186892Sraj    ifra6.ifra_prefixmask.sin6_family = AF_UNSPEC;
250186892Sraj    if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
251186892Sraj      ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
252186892Sraj    else
253186892Sraj      memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
254186892Sraj    ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
255186892Sraj    ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
256186892Sraj
257183867Sraj    res = ID0ioctl(s, SIOCDIFADDR_IN6, &ifra6);
258186892Sraj    break;
259186892Sraj#endif
260186892Sraj  }
261186892Sraj
262186892Sraj  if (res == -1) {
263239276Sgonzo    char dst[40];
264238873Shrs    const char *end =
265238873Shrs#ifndef NOINET6
266239276Sgonzo      ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
267239276Sgonzo#endif
268186892Sraj      "";
269186892Sraj
270186892Sraj    if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
271186892Sraj      log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s): %s\n",
272186892Sraj                 end, ncprange_ntoa(&addr->ifa), strerror(errno));
273186892Sraj    else {
274186892Sraj      snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
275186892Sraj      log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
276186892Sraj                 end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
277186892Sraj    }
278186892Sraj  }
279186892Sraj
280186892Sraj  return res != -1;
281186892Sraj}
282186892Sraj
283186892Srajstatic int
284239276Sgonzoiface_addr_Add(const char *name, struct iface_addr *addr, int s)
285239276Sgonzo{
286239276Sgonzo  struct ifaliasreq ifra;
287239276Sgonzo#ifndef NOINET6
288239276Sgonzo  struct in6_aliasreq ifra6;
289239276Sgonzo#endif
290239276Sgonzo  struct sockaddr_in *me4, *msk4, *peer4;
291239276Sgonzo  struct sockaddr_storage ssme, sspeer, ssmsk;
292239276Sgonzo  int res;
293186892Sraj
294186892Sraj  ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
295186892Sraj  ncpaddr_getsa(&addr->peer, &sspeer);
296183867Sraj  res = 0;
297183867Sraj
298183867Sraj  switch (ncprange_family(&addr->ifa)) {
299183867Sraj  case AF_INET:
300183867Sraj    memset(&ifra, '\0', sizeof ifra);
301183867Sraj    strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
302183867Sraj
303183867Sraj    me4 = (struct sockaddr_in *)&ifra.ifra_addr;
304183867Sraj    memcpy(me4, &ssme, sizeof *me4);
305183867Sraj
306183867Sraj    msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
307183867Sraj    memcpy(msk4, &ssmsk, sizeof *msk4);
308183867Sraj
309183867Sraj    peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
310183867Sraj    if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
311183867Sraj      peer4->sin_family = AF_INET;
312183867Sraj      peer4->sin_len = sizeof(*peer4);
313183867Sraj      peer4->sin_addr.s_addr = INADDR_NONE;
314183867Sraj    } else
315183867Sraj      memcpy(peer4, &sspeer, sizeof *peer4);
316183867Sraj
317183867Sraj    res = ID0ioctl(s, SIOCAIFADDR, &ifra);
318183867Sraj    if (log_IsKept(LogDEBUG)) {
319183867Sraj      char buf[100];
320183867Sraj
321183867Sraj      snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa));
322183867Sraj      log_Printf(LogWARN, "%s: AIFADDR %s -> %s returns %d\n",
323183867Sraj                 ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res);
324183867Sraj    }
325183867Sraj    break;
326183867Sraj
327183867Sraj#ifndef NOINET6
328183867Sraj  case AF_INET6:
329183867Sraj    memset(&ifra6, '\0', sizeof ifra6);
330183867Sraj    strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
331183867Sraj
332183867Sraj    memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
333183867Sraj    memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
334183867Sraj    if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
335183867Sraj      ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
336183867Sraj    else
337183867Sraj      memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
338183867Sraj    ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
339183867Sraj    ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
340183867Sraj
341183867Sraj    res = ID0ioctl(s, SIOCAIFADDR_IN6, &ifra6);
342183867Sraj    break;
343183867Sraj#endif
344183867Sraj  }
345183867Sraj
346183867Sraj  if (res == -1) {
347183867Sraj    char dst[40];
348183867Sraj    const char *end =
349183867Sraj#ifndef NOINET6
350183867Sraj      ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
351183867Sraj#endif
352183867Sraj      "";
353183867Sraj
354183867Sraj    if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
355183867Sraj      log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n",
356183867Sraj                 end, ncprange_ntoa(&addr->ifa), strerror(errno));
357183867Sraj    else {
358183867Sraj      snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
359183867Sraj      log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s -> %s): %s\n",
360183867Sraj                 end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
361183867Sraj    }
362183867Sraj  }
363183867Sraj
364183867Sraj  return res != -1;
365183867Sraj}
366183867Sraj
367183867Sraj
368183867Srajvoid
369183867Srajiface_Clear(struct iface *iface, struct ncp *ncp, int family, int how)
370183867Sraj{
371183867Sraj  int addrs, af, inskip, in6skip, n, s4 = -1, s6 = -1, *s;
372183867Sraj
373183867Sraj  if (iface->addrs) {
374183867Sraj    inskip = in6skip = how == IFACE_CLEAR_ALL ? 0 : 1;
375183867Sraj    addrs = 0;
376183867Sraj
377183867Sraj    for (n = 0; n < iface->addrs; n++) {
378183867Sraj      af = ncprange_family(&iface->addr[n].ifa);
379183867Sraj      if (family == 0 || family == af) {
380183867Sraj        if (!iface->addr[n].system && (how & IFACE_SYSTEM))
381183867Sraj          continue;
382183867Sraj        switch (af) {
383183867Sraj        case AF_INET:
384183867Sraj          if (inskip) {
385183867Sraj            inskip = 0;
386183867Sraj            continue;
387183867Sraj          }
388183867Sraj          s = &s4;
389183867Sraj          break;
390183867Sraj
391183867Sraj#ifndef NOINET6
392243857Sglebius        case AF_INET6:
393183867Sraj          if (in6skip) {
394183867Sraj            in6skip = 0;
395183867Sraj            continue;
396183867Sraj          }
397183867Sraj          s = &s6;
398183867Sraj          break;
399183867Sraj#endif
400183867Sraj        default:
401183867Sraj          continue;
402183867Sraj        }
403183867Sraj
404183867Sraj        if (*s == -1 && (*s = ID0socket(af, SOCK_DGRAM, 0)) == -1)
405183867Sraj          log_Printf(LogERROR, "iface_Clear: socket(): %s\n", strerror(errno));
406183867Sraj        else if (iface_addr_Zap(iface->name, iface->addr + n, *s)) {
407183867Sraj          ncp_IfaceAddrDeleted(ncp, iface->addr + n);
408183867Sraj          bcopy(iface->addr + n + 1, iface->addr + n,
409183867Sraj                (iface->addrs - n - 1) * sizeof *iface->addr);
410183867Sraj          iface->addrs--;
411183867Sraj          n--;
412183867Sraj        }
413183867Sraj      }
414183867Sraj    }
415183867Sraj
416183867Sraj    /* Don't bother realloc()ing - we have little to gain */
417183867Sraj
418183867Sraj    if (s4)
419183867Sraj      close(s4);
420183867Sraj    if (s6)
421183867Sraj      close(s6);
422183867Sraj  }
423183867Sraj}
424183867Sraj
425183867Srajint
426183867Srajiface_Add(struct iface *iface, struct ncp *ncp, const struct ncprange *ifa,
427183867Sraj          const struct ncpaddr *peer, int how)
428183867Sraj{
429183867Sraj  int af, n, removed, s, width;
430183867Sraj  struct ncpaddr ncplocal;
431183867Sraj  struct iface_addr *addr, newaddr;
432183867Sraj
433183867Sraj  af = ncprange_family(ifa);
434183867Sraj  if ((s = ID0socket(af, SOCK_DGRAM, 0)) == -1) {
435183867Sraj    log_Printf(LogERROR, "iface_Add: socket(): %s\n", strerror(errno));
436183867Sraj    return 0;
437183867Sraj  }
438183867Sraj  ncprange_getaddr(ifa, &ncplocal);
439183867Sraj
440183867Sraj  for (n = 0; n < iface->addrs; n++) {
441183867Sraj    if (ncprange_contains(&iface->addr[n].ifa, &ncplocal) ||
442183867Sraj        ncpaddr_equal(&iface->addr[n].peer, peer)) {
443183867Sraj      /* Replace this sockaddr */
444183867Sraj      if (!(how & IFACE_FORCE_ADD)) {
445183867Sraj        close(s);
446183867Sraj        return 0;	/* errno = EEXIST; */
447183867Sraj      }
448183867Sraj
449183867Sraj      if (ncprange_equal(&iface->addr[n].ifa, ifa) &&
450183867Sraj          ncpaddr_equal(&iface->addr[n].peer, peer)) {
451183867Sraj        close(s);
452183867Sraj        return 1;	/* Already there */
453183867Sraj      }
454183867Sraj
455183867Sraj      width =
456232874Sscottl#ifndef NOINET6
457239276Sgonzo        (af == AF_INET6) ? 128 :
458183867Sraj#endif
459183867Sraj      32;
460183867Sraj      removed = iface_addr_Zap(iface->name, iface->addr + n, s);
461183867Sraj      if (removed)
462183867Sraj        ncp_IfaceAddrDeleted(ncp, iface->addr + n);
463183867Sraj      ncprange_copy(&iface->addr[n].ifa, ifa);
464183867Sraj      ncpaddr_copy(&iface->addr[n].peer, peer);
465183867Sraj      if (!iface_addr_Add(iface->name, iface->addr + n, s)) {
466183867Sraj        if (removed) {
467183867Sraj          bcopy(iface->addr + n + 1, iface->addr + n,
468183867Sraj                (iface->addrs - n - 1) * sizeof *iface->addr);
469183867Sraj          iface->addrs--;
470183867Sraj          n--;
471183867Sraj        }
472183867Sraj        close(s);
473183867Sraj        return 0;
474183867Sraj      }
475183867Sraj      close(s);
476183867Sraj      ncp_IfaceAddrAdded(ncp, iface->addr + n);
477183867Sraj      return 1;
478183867Sraj    }
479183867Sraj  }
480183867Sraj
481183867Sraj  addr = (struct iface_addr *)realloc
482183867Sraj    (iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
483183867Sraj  if (addr == NULL) {
484183867Sraj    log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
485183867Sraj    close(s);
486183867Sraj    return 0;
487183867Sraj  }
488183867Sraj  iface->addr = addr;
489183867Sraj
490183867Sraj  ncprange_copy(&newaddr.ifa, ifa);
491204009Sraj  ncpaddr_copy(&newaddr.peer, peer);
492183867Sraj  newaddr.system = !!(how & IFACE_SYSTEM);
493183867Sraj  if (!iface_addr_Add(iface->name, &newaddr, s)) {
494232874Sscottl    close(s);
495183867Sraj    return 0;
496183867Sraj  }
497183867Sraj
498183867Sraj  if (how & IFACE_ADD_FIRST) {
499183867Sraj    /* Stuff it at the start of our list */
500183867Sraj    n = 0;
501183867Sraj    bcopy(iface->addr, iface->addr + 1, iface->addrs * sizeof *iface->addr);
502183867Sraj  } else
503183867Sraj    n = iface->addrs;
504183867Sraj
505183867Sraj  iface->addrs++;
506183867Sraj  memcpy(iface->addr + n, &newaddr, sizeof(*iface->addr));
507183867Sraj
508183867Sraj  close(s);
509183867Sraj  ncp_IfaceAddrAdded(ncp, iface->addr + n);
510183867Sraj
511183867Sraj  return 1;
512183867Sraj}
513183867Sraj
514183867Srajint
515183867Srajiface_Delete(struct iface *iface, struct ncp *ncp, const struct ncpaddr *del)
516183867Sraj{
517183867Sraj  struct ncpaddr found;
518183867Sraj  int n, res, s;
519183867Sraj
520183867Sraj  if ((s = ID0socket(ncpaddr_family(del), SOCK_DGRAM, 0)) == -1) {
521183867Sraj    log_Printf(LogERROR, "iface_Delete: socket(): %s\n", strerror(errno));
522183867Sraj    return 0;
523183867Sraj  }
524183867Sraj
525183867Sraj  for (n = res = 0; n < iface->addrs; n++) {
526183867Sraj    ncprange_getaddr(&iface->addr[n].ifa, &found);
527183867Sraj    if (ncpaddr_equal(&found, del)) {
528183867Sraj      if (iface_addr_Zap(iface->name, iface->addr + n, s)) {
529183867Sraj        ncp_IfaceAddrDeleted(ncp, iface->addr + n);
530183867Sraj        bcopy(iface->addr + n + 1, iface->addr + n,
531183867Sraj              (iface->addrs - n - 1) * sizeof *iface->addr);
532183867Sraj        iface->addrs--;
533183867Sraj        res = 1;
534183867Sraj      }
535183867Sraj      break;
536183867Sraj    }
537183867Sraj  }
538183867Sraj
539183867Sraj  close(s);
540183867Sraj
541183867Sraj  return res;
542183867Sraj}
543183867Sraj
544183867Sraj#define IFACE_ADDFLAGS 1
545183867Sraj#define IFACE_DELFLAGS 2
546183867Sraj
547183867Srajstatic int
548183867Srajiface_ChangeFlags(const char *ifname, int flags, int how)
549183867Sraj{
550183867Sraj  struct ifreq ifrq;
551183867Sraj  int s;
552183867Sraj
553183867Sraj  s = ID0socket(PF_INET, SOCK_DGRAM, 0);
554183867Sraj  if (s < 0) {
555183867Sraj    log_Printf(LogERROR, "iface_ChangeFlags: socket: %s\n", strerror(errno));
556183867Sraj    return 0;
557183867Sraj  }
558183867Sraj
559183867Sraj  memset(&ifrq, '\0', sizeof ifrq);
560183867Sraj  strncpy(ifrq.ifr_name, ifname, sizeof ifrq.ifr_name - 1);
561183867Sraj  ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
562183867Sraj  if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
563183867Sraj    log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n",
564183867Sraj       strerror(errno));
565183867Sraj    close(s);
566183867Sraj    return 0;
567183867Sraj  }
568183867Sraj
569183867Sraj  if (how == IFACE_ADDFLAGS)
570183867Sraj    ifrq.ifr_flags |= flags;
571183867Sraj  else
572183867Sraj    ifrq.ifr_flags &= ~flags;
573183867Sraj
574204009Sraj  if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
575183867Sraj    log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n",
576183867Sraj       strerror(errno));
577183867Sraj    close(s);
578183867Sraj    return 0;
579183867Sraj  }
580183867Sraj  close(s);
581183867Sraj
582183867Sraj  return 1;	/* Success */
583183867Sraj}
584183867Sraj
585183867Srajint
586183867Srajiface_SetFlags(const char *ifname, int flags)
587183867Sraj{
588183867Sraj  return iface_ChangeFlags(ifname, flags, IFACE_ADDFLAGS);
589183867Sraj}
590183867Sraj
591183867Srajint
592183867Srajiface_ClearFlags(const char *ifname, int flags)
593183867Sraj{
594183867Sraj  return iface_ChangeFlags(ifname, flags, IFACE_DELFLAGS);
595183867Sraj}
596183867Sraj
597183867Srajvoid
598183867Srajiface_Destroy(struct iface *iface)
599183867Sraj{
600193096Sattilio  /*
601183867Sraj   * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually
602183867Sraj   * if that's what the user wants.  It's better to leave the interface
603183867Sraj   * allocated so that existing connections can continue to work.
604183867Sraj   */
605193096Sattilio
606183867Sraj  if (iface != NULL) {
607183867Sraj    free(iface->name);
608183867Sraj    free(iface->addr);
609183867Sraj    free(iface);
610183867Sraj  }
611193096Sattilio}
612183867Sraj
613183867Sraj#define if_entry(x) { IFF_##x, #x }
614183867Sraj
615183867Srajstruct {
616183867Sraj  int flag;
617183867Sraj  const char *value;
618183867Sraj} if_flags[] = {
619183867Sraj  if_entry(UP),
620183867Sraj  if_entry(BROADCAST),
621183867Sraj  if_entry(DEBUG),
622183867Sraj  if_entry(LOOPBACK),
623183867Sraj  if_entry(POINTOPOINT),
624183867Sraj  if_entry(RUNNING),
625183867Sraj  if_entry(NOARP),
626183867Sraj  if_entry(PROMISC),
627183867Sraj  if_entry(ALLMULTI),
628183867Sraj  if_entry(OACTIVE),
629193096Sattilio  if_entry(SIMPLEX),
630183867Sraj  if_entry(LINK0),
631183867Sraj  if_entry(LINK1),
632193096Sattilio  if_entry(LINK2),
633183867Sraj  if_entry(MULTICAST),
634183867Sraj  { 0, "???" }
635183867Sraj};
636183867Sraj
637183867Srajint
638183867Srajiface_Show(struct cmdargs const *arg)
639183867Sraj{
640201198Sphilip  struct ncpaddr ncpaddr;
641183867Sraj  struct iface *iface = arg->bundle->iface, *current;
642183867Sraj  int f, flags;
643213893Smarius#ifndef NOINET6
644183867Sraj  int scopeid, width;
645183867Sraj#endif
646183867Sraj  struct in_addr mask;
647209131Sraj
648183867Sraj  current = iface_Create(iface->name);
649186892Sraj  flags = iface->flags = current->flags;
650186892Sraj  iface_Destroy(current);
651186892Sraj
652232518Sraj  prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
653232518Sraj  for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
654209131Sraj    if ((if_flags[f].flag & flags)) {
655209131Sraj      prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
656183867Sraj                    if_flags[f].value);
657183867Sraj      flags &= ~if_flags[f].flag;
658183867Sraj    }
659183867Sraj
660183867Sraj#if 0
661183867Sraj  if (flags)
662183867Sraj    prompt_Printf(arg->prompt, "%s0x%x", flags == iface->flags ? "" : ",",
663183867Sraj                  flags);
664183867Sraj#endif
665183867Sraj
666183867Sraj  prompt_Printf(arg->prompt, "> mtu %d has %d address%s:\n", iface->mtu,
667183867Sraj                iface->addrs, iface->addrs == 1 ? "" : "es");
668183867Sraj
669183867Sraj  for (f = 0; f < iface->addrs; f++) {
670183867Sraj    ncprange_getaddr(&iface->addr[f].ifa, &ncpaddr);
671183867Sraj    switch (ncprange_family(&iface->addr[f].ifa)) {
672183867Sraj    case AF_INET:
673183867Sraj      prompt_Printf(arg->prompt, "  inet %s --> ", ncpaddr_ntoa(&ncpaddr));
674183867Sraj      if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
675183867Sraj        prompt_Printf(arg->prompt, "255.255.255.255");
676183867Sraj      else
677183867Sraj        prompt_Printf(arg->prompt, "%s", ncpaddr_ntoa(&iface->addr[f].peer));
678191142Sraj      ncprange_getip4mask(&iface->addr[f].ifa, &mask);
679183867Sraj      prompt_Printf(arg->prompt, " netmask 0x%08lx", (long)ntohl(mask.s_addr));
680183867Sraj      break;
681183867Sraj
682183867Sraj#ifndef NOINET6
683183867Sraj    case AF_INET6:
684183867Sraj      prompt_Printf(arg->prompt, "  inet6 %s", ncpaddr_ntoa(&ncpaddr));
685183867Sraj      if (ncpaddr_family(&iface->addr[f].peer) != AF_UNSPEC)
686183867Sraj        prompt_Printf(arg->prompt, " --> %s",
687183867Sraj                      ncpaddr_ntoa(&iface->addr[f].peer));
688183867Sraj      ncprange_getwidth(&iface->addr[f].ifa, &width);
689183867Sraj      if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
690183867Sraj        prompt_Printf(arg->prompt, " prefixlen %d", width);
691183867Sraj      if ((scopeid = ncprange_scopeid(&iface->addr[f].ifa)) != -1)
692183867Sraj        prompt_Printf(arg->prompt, " scopeid 0x%x", (unsigned)scopeid);
693183867Sraj      break;
694183867Sraj#endif
695183867Sraj    }
696239276Sgonzo    prompt_Printf(arg->prompt, "\n");
697239276Sgonzo  }
698239276Sgonzo
699239276Sgonzo  return 0;
700239276Sgonzo}
701183867Sraj
702183867Srajvoid
703183867Srajiface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX])
704183867Sraj{
705183867Sraj  char *wp;
706183867Sraj  int rtax;
707183867Sraj
708183867Sraj  wp = (char *)(ifam + 1);
709183867Sraj
710183867Sraj  for (rtax = 0; rtax < RTAX_MAX; rtax++)
711183867Sraj    if (ifam->ifam_addrs & (1 << rtax)) {
712183867Sraj      sa[rtax] = (struct sockaddr *)wp;
713183867Sraj      wp += ROUNDUP(sa[rtax]->sa_len);
714183867Sraj    } else
715183867Sraj      sa[rtax] = NULL;
716183867Sraj}
717183867Sraj