xref: /freebsd/usr.sbin/ppp/iface.c (revision 1de7b4b805ddbf2429da511c053686ac4591ed89)
18fa6ebe4SBrian Somers /*-
2*1de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*1de7b4b8SPedro F. Giffuni  *
48fa6ebe4SBrian Somers  * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
58fa6ebe4SBrian Somers  * All rights reserved.
68fa6ebe4SBrian Somers  *
78fa6ebe4SBrian Somers  * Redistribution and use in source and binary forms, with or without
88fa6ebe4SBrian Somers  * modification, are permitted provided that the following conditions
98fa6ebe4SBrian Somers  * are met:
108fa6ebe4SBrian Somers  * 1. Redistributions of source code must retain the above copyright
118fa6ebe4SBrian Somers  *    notice, this list of conditions and the following disclaimer.
128fa6ebe4SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
138fa6ebe4SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
148fa6ebe4SBrian Somers  *    documentation and/or other materials provided with the distribution.
158fa6ebe4SBrian Somers  *
168fa6ebe4SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
178fa6ebe4SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188fa6ebe4SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198fa6ebe4SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
208fa6ebe4SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
218fa6ebe4SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
228fa6ebe4SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
238fa6ebe4SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
248fa6ebe4SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258fa6ebe4SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268fa6ebe4SBrian Somers  * SUCH DAMAGE.
278fa6ebe4SBrian Somers  *
2897d92980SPeter Wemm  * $FreeBSD$
298fa6ebe4SBrian Somers  */
308fa6ebe4SBrian Somers 
31972a1bcfSBrian Somers #include <sys/param.h>
328fa6ebe4SBrian Somers #include <sys/socket.h>
338fa6ebe4SBrian Somers #include <netinet/in.h>
348fa6ebe4SBrian Somers #include <net/if.h>
358fa6ebe4SBrian Somers #include <net/if_dl.h>
368fa6ebe4SBrian Somers #include <net/route.h>
378fa6ebe4SBrian Somers #include <netinet/in_systm.h>
3830949fd4SBrian Somers #include <netinet/in_var.h>
398fa6ebe4SBrian Somers #include <netinet/ip.h>
4030949fd4SBrian Somers #ifndef NOINET6
4130949fd4SBrian Somers #include <netinet6/nd6.h>
4230949fd4SBrian Somers #endif
438fa6ebe4SBrian Somers #include <sys/un.h>
448fa6ebe4SBrian Somers 
45119386a3SBrian Somers #include <errno.h>
468fa6ebe4SBrian Somers #include <string.h>
476eafd353SBrian Somers #include <stdarg.h>
488fa6ebe4SBrian Somers #include <stdio.h>
498fa6ebe4SBrian Somers #include <stdlib.h>
50119386a3SBrian Somers #include <sys/ioctl.h>
51119386a3SBrian Somers #include <sys/sysctl.h>
528fa6ebe4SBrian Somers #include <termios.h>
538fa6ebe4SBrian Somers #include <unistd.h>
548fa6ebe4SBrian Somers 
555d9e6103SBrian Somers #include "layer.h"
568fa6ebe4SBrian Somers #include "defs.h"
578fa6ebe4SBrian Somers #include "command.h"
588fa6ebe4SBrian Somers #include "mbuf.h"
598fa6ebe4SBrian Somers #include "log.h"
608fa6ebe4SBrian Somers #include "id.h"
618fa6ebe4SBrian Somers #include "timer.h"
628fa6ebe4SBrian Somers #include "fsm.h"
638fa6ebe4SBrian Somers #include "iplist.h"
648fa6ebe4SBrian Somers #include "lqr.h"
658fa6ebe4SBrian Somers #include "hdlc.h"
668fa6ebe4SBrian Somers #include "throughput.h"
678fa6ebe4SBrian Somers #include "slcompress.h"
688fa6ebe4SBrian Somers #include "descriptor.h"
6930949fd4SBrian Somers #include "ncpaddr.h"
708fa6ebe4SBrian Somers #include "ipcp.h"
711d1fc017SBrian Somers #include "filter.h"
728fa6ebe4SBrian Somers #include "lcp.h"
738fa6ebe4SBrian Somers #include "ccp.h"
748fa6ebe4SBrian Somers #include "link.h"
758fa6ebe4SBrian Somers #include "mp.h"
76972a1bcfSBrian Somers #ifndef NORADIUS
77972a1bcfSBrian Somers #include "radius.h"
78972a1bcfSBrian Somers #endif
7930949fd4SBrian Somers #include "ipv6cp.h"
8030949fd4SBrian Somers #include "ncp.h"
818fa6ebe4SBrian Somers #include "bundle.h"
828fa6ebe4SBrian Somers #include "prompt.h"
838fa6ebe4SBrian Somers #include "iface.h"
848fa6ebe4SBrian Somers 
85977e6c08SHajimu UMEMOTO #define IN6MASK128	{{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
86977e6c08SHajimu UMEMOTO 			    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
87977e6c08SHajimu UMEMOTO static const struct in6_addr in6mask128 = IN6MASK128;
88977e6c08SHajimu UMEMOTO 
898fa6ebe4SBrian Somers 
908fa6ebe4SBrian Somers struct iface *
918fa6ebe4SBrian Somers iface_Create(const char *name)
928fa6ebe4SBrian Somers {
9330949fd4SBrian Somers   int mib[6], maxtries, err;
9458a57513SBrian Somers   size_t needed, namelen;
956b457978SBrian Somers   char *buf, *ptr, *end;
968fa6ebe4SBrian Somers   struct if_msghdr *ifm;
978fa6ebe4SBrian Somers   struct ifa_msghdr *ifam;
988fa6ebe4SBrian Somers   struct sockaddr_dl *dl;
996b457978SBrian Somers   struct sockaddr *sa[RTAX_MAX];
1008fa6ebe4SBrian Somers   struct iface *iface;
1018fa6ebe4SBrian Somers   struct iface_addr *addr;
1028fa6ebe4SBrian Somers 
1038fa6ebe4SBrian Somers   mib[0] = CTL_NET;
1048fa6ebe4SBrian Somers   mib[1] = PF_ROUTE;
1058fa6ebe4SBrian Somers   mib[2] = 0;
1068fa6ebe4SBrian Somers   mib[3] = 0;
1078fa6ebe4SBrian Somers   mib[4] = NET_RT_IFLIST;
1088fa6ebe4SBrian Somers   mib[5] = 0;
1098fa6ebe4SBrian Somers 
110152a4390SBrian Somers   maxtries = 20;
111152a4390SBrian Somers   err = 0;
112152a4390SBrian Somers   do {
113152a4390SBrian Somers     if (maxtries-- == 0 || (err && err != ENOMEM)) {
114152a4390SBrian Somers       fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(err));
115152a4390SBrian Somers       return NULL;
116152a4390SBrian Somers     }
117152a4390SBrian Somers 
1188fa6ebe4SBrian Somers     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
119c0593e34SBrian Somers       fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
1208fa6ebe4SBrian Somers                 strerror(errno));
1218fa6ebe4SBrian Somers       return NULL;
1228fa6ebe4SBrian Somers     }
1238fa6ebe4SBrian Somers 
1248fa6ebe4SBrian Somers     if ((buf = (char *)malloc(needed)) == NULL) {
125c0593e34SBrian Somers       fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
1268fa6ebe4SBrian Somers       return NULL;
1278fa6ebe4SBrian Somers     }
1288fa6ebe4SBrian Somers 
1298fa6ebe4SBrian Somers     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
130152a4390SBrian Somers       err = errno;
1318fa6ebe4SBrian Somers       free(buf);
132152a4390SBrian Somers       buf = NULL;
1338fa6ebe4SBrian Somers     }
134152a4390SBrian Somers   } while (buf == NULL);
1358fa6ebe4SBrian Somers 
1368fa6ebe4SBrian Somers   ptr = buf;
1378fa6ebe4SBrian Somers   end = buf + needed;
1388fa6ebe4SBrian Somers   iface = NULL;
13958a57513SBrian Somers   namelen = strlen(name);
1408fa6ebe4SBrian Somers 
1418fa6ebe4SBrian Somers   while (ptr < end && iface == NULL) {
1428fa6ebe4SBrian Somers     ifm = (struct if_msghdr *)ptr;			/* On if_msghdr */
1438fa6ebe4SBrian Somers     if (ifm->ifm_type != RTM_IFINFO)
1448fa6ebe4SBrian Somers       break;
1458fa6ebe4SBrian Somers     dl = (struct sockaddr_dl *)(ifm + 1);		/* Single _dl at end */
14658a57513SBrian Somers     if (dl->sdl_nlen == namelen && !strncmp(name, dl->sdl_data, namelen)) {
1478fa6ebe4SBrian Somers       iface = (struct iface *)malloc(sizeof *iface);
1488fa6ebe4SBrian Somers       if (iface == NULL) {
1498fa6ebe4SBrian Somers         fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
150ba01ab64SStephen J. Kiernan 	free(buf);
1518fa6ebe4SBrian Somers         return NULL;
1528fa6ebe4SBrian Somers       }
1538fa6ebe4SBrian Somers       iface->name = strdup(name);
154f2f5156fSBrian Somers       iface->descr = NULL;
1558fa6ebe4SBrian Somers       iface->index = ifm->ifm_index;
156c8b9fb53SBrian Somers       iface->flags = ifm->ifm_flags;
157c8b9fb53SBrian Somers       iface->mtu = 0;
15830949fd4SBrian Somers       iface->addrs = 0;
15930949fd4SBrian Somers       iface->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 
1686b457978SBrian Somers       if (iface != NULL && ifam->ifam_addrs & RTA_IFA) {
1696b457978SBrian Somers         /* Found a configured interface ! */
1706b457978SBrian Somers         iface_ParseHdr(ifam, sa);
1718fa6ebe4SBrian Somers 
17230949fd4SBrian Somers         if (sa[RTAX_IFA] && (sa[RTAX_IFA]->sa_family == AF_INET
17330949fd4SBrian Somers #ifndef NOINET6
17430949fd4SBrian Somers                              || sa[RTAX_IFA]->sa_family == AF_INET6
17530949fd4SBrian Somers #endif
17630949fd4SBrian Somers                              )) {
1776b457978SBrian Somers           /* Record the address */
1788fa6ebe4SBrian Somers 
17930949fd4SBrian Somers           addr = (struct iface_addr *)
18030949fd4SBrian Somers             realloc(iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
1818fa6ebe4SBrian Somers           if (addr == NULL)
1828fa6ebe4SBrian Somers             break;
18330949fd4SBrian Somers           iface->addr = addr;
1848fa6ebe4SBrian Somers 
18530949fd4SBrian Somers           addr += iface->addrs;
18630949fd4SBrian Somers           iface->addrs++;
1878fa6ebe4SBrian Somers 
18830949fd4SBrian Somers           ncprange_setsa(&addr->ifa, sa[RTAX_IFA], sa[RTAX_NETMASK]);
1896b457978SBrian Somers           if (sa[RTAX_BRD])
19030949fd4SBrian Somers             ncpaddr_setsa(&addr->peer, sa[RTAX_BRD]);
1916b457978SBrian Somers           else
19230949fd4SBrian Somers             ncpaddr_init(&addr->peer);
1938fa6ebe4SBrian Somers         }
1948fa6ebe4SBrian Somers       }
1958fa6ebe4SBrian Somers     }
1968fa6ebe4SBrian Somers   }
1978fa6ebe4SBrian Somers 
1988fa6ebe4SBrian Somers   free(buf);
1998fa6ebe4SBrian Somers 
2008fa6ebe4SBrian Somers   return iface;
2018fa6ebe4SBrian Somers }
2028fa6ebe4SBrian Somers 
20330949fd4SBrian Somers static int
20430949fd4SBrian Somers iface_addr_Zap(const char *name, struct iface_addr *addr, int s)
2058fa6ebe4SBrian Somers {
2068fa6ebe4SBrian Somers   struct ifaliasreq ifra;
20730949fd4SBrian Somers #ifndef NOINET6
20830949fd4SBrian Somers   struct in6_aliasreq ifra6;
20930949fd4SBrian Somers #endif
21030949fd4SBrian Somers   struct sockaddr_in *me4, *msk4, *peer4;
21130949fd4SBrian Somers   struct sockaddr_storage ssme, sspeer, ssmsk;
21230949fd4SBrian Somers   int res;
2138fa6ebe4SBrian Somers 
21430949fd4SBrian Somers   ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
21530949fd4SBrian Somers   ncpaddr_getsa(&addr->peer, &sspeer);
21630949fd4SBrian Somers   res = 0;
21730949fd4SBrian Somers 
21830949fd4SBrian Somers   switch (ncprange_family(&addr->ifa)) {
21930949fd4SBrian Somers   case AF_INET:
2208fa6ebe4SBrian Somers     memset(&ifra, '\0', sizeof ifra);
2218fa6ebe4SBrian Somers     strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
22230949fd4SBrian Somers 
22330949fd4SBrian Somers     me4 = (struct sockaddr_in *)&ifra.ifra_addr;
22430949fd4SBrian Somers     memcpy(me4, &ssme, sizeof *me4);
22530949fd4SBrian Somers 
22630949fd4SBrian Somers     msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
22730949fd4SBrian Somers     memcpy(msk4, &ssmsk, sizeof *msk4);
22830949fd4SBrian Somers 
22930949fd4SBrian Somers     peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
23030949fd4SBrian Somers     if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
23130949fd4SBrian Somers       peer4->sin_family = AF_INET;
23230949fd4SBrian Somers       peer4->sin_len = sizeof(*peer4);
23330949fd4SBrian Somers       peer4->sin_addr.s_addr = INADDR_NONE;
23430949fd4SBrian Somers     } else
23530949fd4SBrian Somers       memcpy(peer4, &sspeer, sizeof *peer4);
23630949fd4SBrian Somers 
23730949fd4SBrian Somers     res = ID0ioctl(s, SIOCDIFADDR, &ifra);
2382ea80d6dSBrian Somers     if (log_IsKept(LogDEBUG)) {
2392ea80d6dSBrian Somers       char buf[100];
2402ea80d6dSBrian Somers 
2412ea80d6dSBrian Somers       snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa));
2422ea80d6dSBrian Somers       log_Printf(LogWARN, "%s: DIFADDR %s -> %s returns %d\n",
2432ea80d6dSBrian Somers                  ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res);
2442ea80d6dSBrian Somers     }
24530949fd4SBrian Somers     break;
24630949fd4SBrian Somers 
24730949fd4SBrian Somers #ifndef NOINET6
24830949fd4SBrian Somers   case AF_INET6:
24930949fd4SBrian Somers     memset(&ifra6, '\0', sizeof ifra6);
25030949fd4SBrian Somers     strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
25130949fd4SBrian Somers 
25230949fd4SBrian Somers     memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
25330949fd4SBrian Somers     memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
25430949fd4SBrian Somers     ifra6.ifra_prefixmask.sin6_family = AF_UNSPEC;
25530949fd4SBrian Somers     if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
25630949fd4SBrian Somers       ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
25730949fd4SBrian Somers     else
25830949fd4SBrian Somers       memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
25930949fd4SBrian Somers     ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
26030949fd4SBrian Somers     ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
26130949fd4SBrian Somers 
26230949fd4SBrian Somers     res = ID0ioctl(s, SIOCDIFADDR_IN6, &ifra6);
26330949fd4SBrian Somers     break;
26430949fd4SBrian Somers #endif
26530949fd4SBrian Somers   }
26630949fd4SBrian Somers 
26730949fd4SBrian Somers   if (res == -1) {
26830949fd4SBrian Somers     char dst[40];
26930949fd4SBrian Somers     const char *end =
27030949fd4SBrian Somers #ifndef NOINET6
27130949fd4SBrian Somers       ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
27230949fd4SBrian Somers #endif
27330949fd4SBrian Somers       "";
27430949fd4SBrian Somers 
27530949fd4SBrian Somers     if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
27630949fd4SBrian Somers       log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s): %s\n",
27730949fd4SBrian Somers                  end, ncprange_ntoa(&addr->ifa), strerror(errno));
27830949fd4SBrian Somers     else {
27930949fd4SBrian Somers       snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
28030949fd4SBrian Somers       log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
28130949fd4SBrian Somers                  end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
2828fa6ebe4SBrian Somers     }
2838fa6ebe4SBrian Somers   }
2848fa6ebe4SBrian Somers 
28530949fd4SBrian Somers   return res != -1;
28630949fd4SBrian Somers }
28730949fd4SBrian Somers 
288add3c041SBrian Somers static int
28930949fd4SBrian Somers iface_addr_Add(const char *name, struct iface_addr *addr, int s)
29030949fd4SBrian Somers {
29130949fd4SBrian Somers   struct ifaliasreq ifra;
29230949fd4SBrian Somers #ifndef NOINET6
29330949fd4SBrian Somers   struct in6_aliasreq ifra6;
29430949fd4SBrian Somers #endif
29530949fd4SBrian Somers   struct sockaddr_in *me4, *msk4, *peer4;
29630949fd4SBrian Somers   struct sockaddr_storage ssme, sspeer, ssmsk;
29730949fd4SBrian Somers   int res;
29830949fd4SBrian Somers 
29930949fd4SBrian Somers   ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
30030949fd4SBrian Somers   ncpaddr_getsa(&addr->peer, &sspeer);
30130949fd4SBrian Somers   res = 0;
30230949fd4SBrian Somers 
30330949fd4SBrian Somers   switch (ncprange_family(&addr->ifa)) {
30430949fd4SBrian Somers   case AF_INET:
30530949fd4SBrian Somers     memset(&ifra, '\0', sizeof ifra);
30630949fd4SBrian Somers     strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
30730949fd4SBrian Somers 
30830949fd4SBrian Somers     me4 = (struct sockaddr_in *)&ifra.ifra_addr;
30930949fd4SBrian Somers     memcpy(me4, &ssme, sizeof *me4);
31030949fd4SBrian Somers 
31130949fd4SBrian Somers     msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
31230949fd4SBrian Somers     memcpy(msk4, &ssmsk, sizeof *msk4);
31330949fd4SBrian Somers 
31430949fd4SBrian Somers     peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
31530949fd4SBrian Somers     if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
31630949fd4SBrian Somers       peer4->sin_family = AF_INET;
31730949fd4SBrian Somers       peer4->sin_len = sizeof(*peer4);
31830949fd4SBrian Somers       peer4->sin_addr.s_addr = INADDR_NONE;
31930949fd4SBrian Somers     } else
32030949fd4SBrian Somers       memcpy(peer4, &sspeer, sizeof *peer4);
32130949fd4SBrian Somers 
32230949fd4SBrian Somers     res = ID0ioctl(s, SIOCAIFADDR, &ifra);
3232ea80d6dSBrian Somers     if (log_IsKept(LogDEBUG)) {
3242ea80d6dSBrian Somers       char buf[100];
3252ea80d6dSBrian Somers 
3262ea80d6dSBrian Somers       snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa));
3272ea80d6dSBrian Somers       log_Printf(LogWARN, "%s: AIFADDR %s -> %s returns %d\n",
3282ea80d6dSBrian Somers                  ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res);
3292ea80d6dSBrian Somers     }
33030949fd4SBrian Somers     break;
33130949fd4SBrian Somers 
33230949fd4SBrian Somers #ifndef NOINET6
33330949fd4SBrian Somers   case AF_INET6:
33430949fd4SBrian Somers     memset(&ifra6, '\0', sizeof ifra6);
33530949fd4SBrian Somers     strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
33630949fd4SBrian Somers 
33730949fd4SBrian Somers     memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
33830949fd4SBrian Somers     memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
33930949fd4SBrian Somers     if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
34030949fd4SBrian Somers       ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
341977e6c08SHajimu UMEMOTO     else if (memcmp(&((struct sockaddr_in6 *)&ssmsk)->sin6_addr, &in6mask128,
342977e6c08SHajimu UMEMOTO 		    sizeof in6mask128) == 0)
34330949fd4SBrian Somers       memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
34430949fd4SBrian Somers     ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
34530949fd4SBrian Somers     ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
34630949fd4SBrian Somers 
34730949fd4SBrian Somers     res = ID0ioctl(s, SIOCAIFADDR_IN6, &ifra6);
34830949fd4SBrian Somers     break;
34930949fd4SBrian Somers #endif
35030949fd4SBrian Somers   }
35130949fd4SBrian Somers 
35230949fd4SBrian Somers   if (res == -1) {
35330949fd4SBrian Somers     char dst[40];
35430949fd4SBrian Somers     const char *end =
35530949fd4SBrian Somers #ifndef NOINET6
35630949fd4SBrian Somers       ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
35730949fd4SBrian Somers #endif
35830949fd4SBrian Somers       "";
35930949fd4SBrian Somers 
36030949fd4SBrian Somers     if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
36130949fd4SBrian Somers       log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n",
36230949fd4SBrian Somers                  end, ncprange_ntoa(&addr->ifa), strerror(errno));
36330949fd4SBrian Somers     else {
36430949fd4SBrian Somers       snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
36546df5aa7SBrian Somers       log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s -> %s): %s\n",
36630949fd4SBrian Somers                  end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
36730949fd4SBrian Somers     }
36830949fd4SBrian Somers   }
369add3c041SBrian Somers 
370add3c041SBrian Somers   return res != -1;
37130949fd4SBrian Somers }
37230949fd4SBrian Somers 
373f2f5156fSBrian Somers int
374f2f5156fSBrian Somers iface_Name(struct iface *iface, const char *name)
375f2f5156fSBrian Somers {
376f2f5156fSBrian Somers   struct ifreq ifr;
377f2f5156fSBrian Somers   int s;
378f2f5156fSBrian Somers   char *newname;
379f2f5156fSBrian Somers 
380f2f5156fSBrian Somers   if ((newname = strdup(name)) == NULL) {
381f2f5156fSBrian Somers     log_Printf(LogWARN, "iface name: strdup failed: %s\n", strerror(errno));
382f2f5156fSBrian Somers     return 0;
383f2f5156fSBrian Somers   }
384f2f5156fSBrian Somers 
385f2f5156fSBrian Somers   if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
386f2f5156fSBrian Somers     log_Printf(LogERROR, "iface name: socket(): %s\n", strerror(errno));
387f2f5156fSBrian Somers     free(newname);
388f2f5156fSBrian Somers     return 0;
389f2f5156fSBrian Somers   }
390f2f5156fSBrian Somers 
391f2f5156fSBrian Somers   strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
392f2f5156fSBrian Somers   ifr.ifr_data = newname;
393f2f5156fSBrian Somers   if (ID0ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
394f2f5156fSBrian Somers     log_Printf(LogWARN, "iface name: ioctl(SIOCSIFNAME, %s -> %s): %s\n",
395f2f5156fSBrian Somers                name, newname, strerror(errno));
396f2f5156fSBrian Somers     free(newname);
397f2f5156fSBrian Somers     return 0;
398f2f5156fSBrian Somers   }
399f2f5156fSBrian Somers 
400f2f5156fSBrian Somers   free(iface->name);
401f2f5156fSBrian Somers   iface->name = newname;
402f2f5156fSBrian Somers 
403f2f5156fSBrian Somers   return 1;
404f2f5156fSBrian Somers }
405f2f5156fSBrian Somers 
406f2f5156fSBrian Somers int
407f2f5156fSBrian Somers iface_Descr(struct cmdargs const *arg)
408f2f5156fSBrian Somers {
409f2f5156fSBrian Somers   struct ifreq ifr;
410f2f5156fSBrian Somers   struct iface *iface;
411f2f5156fSBrian Somers   size_t sz, len;
412f2f5156fSBrian Somers   int s, n, ifdescr_maxlen;
413f2f5156fSBrian Somers   char *descr;
414f2f5156fSBrian Somers 
415f2f5156fSBrian Somers   sz = sizeof(int);
416f2f5156fSBrian Somers   if (sysctlbyname("net.ifdescr_maxlen", &ifdescr_maxlen, &sz, NULL, 0) < 0) {
417f2f5156fSBrian Somers     log_Printf(LogERROR, "iface descr: sysctl failed: %s\n", strerror(errno));
418f2f5156fSBrian Somers     return 1;
419f2f5156fSBrian Somers   }
420f2f5156fSBrian Somers 
421f2f5156fSBrian Somers   if (ifdescr_maxlen < 1) {
422f2f5156fSBrian Somers     log_Printf(LogERROR, "iface descr: sysctl net.ifdescr_maxlen < 1\n");
423f2f5156fSBrian Somers     return 1;
424f2f5156fSBrian Somers   }
425f2f5156fSBrian Somers 
426f2f5156fSBrian Somers   sz = sizeof(char) * ifdescr_maxlen;
427f2f5156fSBrian Somers   if ((descr = malloc(sz)) == NULL) {
428f2f5156fSBrian Somers     log_Printf(LogERROR, "iface descr: malloc failed: %s\n", strerror(errno));
429f2f5156fSBrian Somers     return 1;
430f2f5156fSBrian Somers   }
431f2f5156fSBrian Somers 
432f2f5156fSBrian Somers   *descr = '\0';
433f2f5156fSBrian Somers   n = arg->argn;
434f2f5156fSBrian Somers   while (n < arg->argc) {
435f2f5156fSBrian Somers     if (n > arg->argn && (len = strlcat(descr, " ", sz)) >= sz)
436f2f5156fSBrian Somers       break;
437f2f5156fSBrian Somers     if ((len = strlcat(descr, arg->argv[n], sz)) >= sz)
438f2f5156fSBrian Somers       break;
439f2f5156fSBrian Somers     ++n;
440f2f5156fSBrian Somers   }
441f2f5156fSBrian Somers   if (len >= sz) {
442f2f5156fSBrian Somers     log_Printf(LogERROR, "iface descr: description exceeds maximum (%d)\n",
443f2f5156fSBrian Somers                ifdescr_maxlen-1);
444f2f5156fSBrian Somers     free(descr);
445f2f5156fSBrian Somers     return 1;
446f2f5156fSBrian Somers   }
447f2f5156fSBrian Somers 
448f2f5156fSBrian Somers   if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
449f2f5156fSBrian Somers     log_Printf(LogERROR, "iface descr: socket(): %s\n", strerror(errno));
450f2f5156fSBrian Somers     free(descr);
451f2f5156fSBrian Somers     return 1;
452f2f5156fSBrian Somers   }
453f2f5156fSBrian Somers 
454f2f5156fSBrian Somers   iface = arg->bundle->iface;
455f2f5156fSBrian Somers   strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
456f2f5156fSBrian Somers   ifr.ifr_buffer.length = strlen(descr) + 1;
457f2f5156fSBrian Somers   ifr.ifr_buffer.buffer = descr;
458f2f5156fSBrian Somers   if (ID0ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) {
459f2f5156fSBrian Somers     log_Printf(LogWARN, "iface descr: ioctl(SIOCSIFDESCR, %s): %s\n",
460f2f5156fSBrian Somers                descr, strerror(errno));
461f2f5156fSBrian Somers     free(descr);
462f2f5156fSBrian Somers     return 1;
463f2f5156fSBrian Somers   }
464f2f5156fSBrian Somers 
465f2f5156fSBrian Somers   free(iface->descr);
466f2f5156fSBrian Somers   iface->descr = descr;
467f2f5156fSBrian Somers 
468f2f5156fSBrian Somers   return 0;
469f2f5156fSBrian Somers }
47030949fd4SBrian Somers 
4718fa6ebe4SBrian Somers void
47230949fd4SBrian Somers iface_Clear(struct iface *iface, struct ncp *ncp, int family, int how)
4738fa6ebe4SBrian Somers {
4747268c7daSEitan Adler   int af, inskip, in6skip, s4 = -1, s6 = -1, *s;
475057f1760SBrian Somers   unsigned n;
4768fa6ebe4SBrian Somers 
47730949fd4SBrian Somers   if (iface->addrs) {
47830949fd4SBrian Somers     inskip = in6skip = how == IFACE_CLEAR_ALL ? 0 : 1;
4798fa6ebe4SBrian Somers 
48030949fd4SBrian Somers     for (n = 0; n < iface->addrs; n++) {
48130949fd4SBrian Somers       af = ncprange_family(&iface->addr[n].ifa);
48230949fd4SBrian Somers       if (family == 0 || family == af) {
48330949fd4SBrian Somers         if (!iface->addr[n].system && (how & IFACE_SYSTEM))
48430949fd4SBrian Somers           continue;
48530949fd4SBrian Somers         switch (af) {
48630949fd4SBrian Somers         case AF_INET:
48730949fd4SBrian Somers           if (inskip) {
48830949fd4SBrian Somers             inskip = 0;
48930949fd4SBrian Somers             continue;
49030949fd4SBrian Somers           }
49130949fd4SBrian Somers           s = &s4;
49230949fd4SBrian Somers           break;
49330949fd4SBrian Somers 
49430949fd4SBrian Somers #ifndef NOINET6
49530949fd4SBrian Somers         case AF_INET6:
49630949fd4SBrian Somers           if (in6skip) {
49730949fd4SBrian Somers             in6skip = 0;
49830949fd4SBrian Somers             continue;
49930949fd4SBrian Somers           }
50030949fd4SBrian Somers           s = &s6;
50130949fd4SBrian Somers           break;
50230949fd4SBrian Somers #endif
503856cf687SBrian Somers         default:
504856cf687SBrian Somers           continue;
50530949fd4SBrian Somers         }
50630949fd4SBrian Somers 
50730949fd4SBrian Somers         if (*s == -1 && (*s = ID0socket(af, SOCK_DGRAM, 0)) == -1)
50830949fd4SBrian Somers           log_Printf(LogERROR, "iface_Clear: socket(): %s\n", strerror(errno));
50930949fd4SBrian Somers         else if (iface_addr_Zap(iface->name, iface->addr + n, *s)) {
51030949fd4SBrian Somers           ncp_IfaceAddrDeleted(ncp, iface->addr + n);
51130949fd4SBrian Somers           bcopy(iface->addr + n + 1, iface->addr + n,
51230949fd4SBrian Somers                 (iface->addrs - n - 1) * sizeof *iface->addr);
51330949fd4SBrian Somers           iface->addrs--;
51430949fd4SBrian Somers           n--;
51530949fd4SBrian Somers         }
51630949fd4SBrian Somers       }
51730949fd4SBrian Somers     }
51830949fd4SBrian Somers 
5198fa6ebe4SBrian Somers     /* Don't bother realloc()ing - we have little to gain */
52030949fd4SBrian Somers 
52130949fd4SBrian Somers     if (s4)
52230949fd4SBrian Somers       close(s4);
52330949fd4SBrian Somers     if (s6)
52430949fd4SBrian Somers       close(s6);
5258fa6ebe4SBrian Somers   }
526278657c3SBrian Somers }
5278fa6ebe4SBrian Somers 
5288fa6ebe4SBrian Somers int
52930949fd4SBrian Somers iface_Add(struct iface *iface, struct ncp *ncp, const struct ncprange *ifa,
53030949fd4SBrian Somers           const struct ncpaddr *peer, int how)
5318fa6ebe4SBrian Somers {
532057f1760SBrian Somers   int af, removed, s;
533057f1760SBrian Somers   unsigned n;
534add3c041SBrian Somers   struct ncpaddr ncplocal;
535add3c041SBrian Somers   struct iface_addr *addr, newaddr;
5368fa6ebe4SBrian Somers 
53730949fd4SBrian Somers   af = ncprange_family(ifa);
53830949fd4SBrian Somers   if ((s = ID0socket(af, SOCK_DGRAM, 0)) == -1) {
53930949fd4SBrian Somers     log_Printf(LogERROR, "iface_Add: socket(): %s\n", strerror(errno));
5408fa6ebe4SBrian Somers     return 0;
5418fa6ebe4SBrian Somers   }
54230949fd4SBrian Somers   ncprange_getaddr(ifa, &ncplocal);
54330949fd4SBrian Somers 
54430949fd4SBrian Somers   for (n = 0; n < iface->addrs; n++) {
54584b0fe81SBrian Somers     if (ncprange_contains(&iface->addr[n].ifa, &ncplocal) ||
54684b0fe81SBrian Somers         ncpaddr_equal(&iface->addr[n].peer, peer)) {
547add3c041SBrian Somers       /* Replace this sockaddr */
54830949fd4SBrian Somers       if (!(how & IFACE_FORCE_ADD)) {
54930949fd4SBrian Somers         close(s);
55030949fd4SBrian Somers         return 0;	/* errno = EEXIST; */
55130949fd4SBrian Somers       }
55230949fd4SBrian Somers 
55330949fd4SBrian Somers       if (ncprange_equal(&iface->addr[n].ifa, ifa) &&
55430949fd4SBrian Somers           ncpaddr_equal(&iface->addr[n].peer, peer)) {
55530949fd4SBrian Somers         close(s);
5561de22c3bSBjoern A. Zeeb         ncp_IfaceAddrAdded(ncp, iface->addr + n);
55730949fd4SBrian Somers         return 1;	/* Already there */
55830949fd4SBrian Somers       }
55930949fd4SBrian Somers 
560add3c041SBrian Somers       removed = iface_addr_Zap(iface->name, iface->addr + n, s);
561add3c041SBrian Somers       if (removed)
562add3c041SBrian Somers         ncp_IfaceAddrDeleted(ncp, iface->addr + n);
563add3c041SBrian Somers       ncprange_copy(&iface->addr[n].ifa, ifa);
56430949fd4SBrian Somers       ncpaddr_copy(&iface->addr[n].peer, peer);
565add3c041SBrian Somers       if (!iface_addr_Add(iface->name, iface->addr + n, s)) {
566add3c041SBrian Somers         if (removed) {
567add3c041SBrian Somers           bcopy(iface->addr + n + 1, iface->addr + n,
568add3c041SBrian Somers                 (iface->addrs - n - 1) * sizeof *iface->addr);
569add3c041SBrian Somers           iface->addrs--;
570add3c041SBrian Somers           n--;
571add3c041SBrian Somers         }
572add3c041SBrian Somers         close(s);
573add3c041SBrian Somers         return 0;
574add3c041SBrian Somers       }
57530949fd4SBrian Somers       close(s);
57630949fd4SBrian Somers       ncp_IfaceAddrAdded(ncp, iface->addr + n);
57730949fd4SBrian Somers       return 1;
57830949fd4SBrian Somers     }
57930949fd4SBrian Somers   }
5808fa6ebe4SBrian Somers 
5818fa6ebe4SBrian Somers   addr = (struct iface_addr *)realloc
58230949fd4SBrian Somers     (iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
5838fa6ebe4SBrian Somers   if (addr == NULL) {
5848fa6ebe4SBrian Somers     log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
5858fa6ebe4SBrian Somers     close(s);
5868fa6ebe4SBrian Somers     return 0;
5878fa6ebe4SBrian Somers   }
58830949fd4SBrian Somers   iface->addr = addr;
5898fa6ebe4SBrian Somers 
590add3c041SBrian Somers   ncprange_copy(&newaddr.ifa, ifa);
591add3c041SBrian Somers   ncpaddr_copy(&newaddr.peer, peer);
592add3c041SBrian Somers   newaddr.system = !!(how & IFACE_SYSTEM);
593add3c041SBrian Somers   if (!iface_addr_Add(iface->name, &newaddr, s)) {
594add3c041SBrian Somers     close(s);
595add3c041SBrian Somers     return 0;
596add3c041SBrian Somers   }
597add3c041SBrian Somers 
5988fa6ebe4SBrian Somers   if (how & IFACE_ADD_FIRST) {
5998fa6ebe4SBrian Somers     /* Stuff it at the start of our list */
60030949fd4SBrian Somers     n = 0;
60130949fd4SBrian Somers     bcopy(iface->addr, iface->addr + 1, iface->addrs * sizeof *iface->addr);
60230949fd4SBrian Somers   } else
60330949fd4SBrian Somers     n = iface->addrs;
6048fa6ebe4SBrian Somers 
60530949fd4SBrian Somers   iface->addrs++;
606add3c041SBrian Somers   memcpy(iface->addr + n, &newaddr, sizeof(*iface->addr));
6078fa6ebe4SBrian Somers 
60830949fd4SBrian Somers   close(s);
60930949fd4SBrian Somers   ncp_IfaceAddrAdded(ncp, iface->addr + n);
6108fa6ebe4SBrian Somers 
6118fa6ebe4SBrian Somers   return 1;
6128fa6ebe4SBrian Somers }
6138fa6ebe4SBrian Somers 
6148fa6ebe4SBrian Somers int
61530949fd4SBrian Somers iface_Delete(struct iface *iface, struct ncp *ncp, const struct ncpaddr *del)
6168fa6ebe4SBrian Somers {
61730949fd4SBrian Somers   struct ncpaddr found;
618057f1760SBrian Somers   unsigned n;
619057f1760SBrian Somers   int res, s;
6208fa6ebe4SBrian Somers 
62130949fd4SBrian Somers   if ((s = ID0socket(ncpaddr_family(del), SOCK_DGRAM, 0)) == -1) {
62230949fd4SBrian Somers     log_Printf(LogERROR, "iface_Delete: socket(): %s\n", strerror(errno));
62330949fd4SBrian Somers     return 0;
6248fa6ebe4SBrian Somers   }
6258fa6ebe4SBrian Somers 
62630949fd4SBrian Somers   for (n = res = 0; n < iface->addrs; n++) {
62730949fd4SBrian Somers     ncprange_getaddr(&iface->addr[n].ifa, &found);
62830949fd4SBrian Somers     if (ncpaddr_equal(&found, del)) {
629add3c041SBrian Somers       if (iface_addr_Zap(iface->name, iface->addr + n, s)) {
63030949fd4SBrian Somers         ncp_IfaceAddrDeleted(ncp, iface->addr + n);
63130949fd4SBrian Somers         bcopy(iface->addr + n + 1, iface->addr + n,
63230949fd4SBrian Somers               (iface->addrs - n - 1) * sizeof *iface->addr);
63330949fd4SBrian Somers         iface->addrs--;
63430949fd4SBrian Somers         res = 1;
635add3c041SBrian Somers       }
63630949fd4SBrian Somers       break;
63730949fd4SBrian Somers     }
63830949fd4SBrian Somers   }
63930949fd4SBrian Somers 
64030949fd4SBrian Somers   close(s);
64130949fd4SBrian Somers 
64230949fd4SBrian Somers   return res;
6438fa6ebe4SBrian Somers }
6448fa6ebe4SBrian Somers 
6454e5196e9SBrian Somers #define IFACE_ADDFLAGS 1
6464e5196e9SBrian Somers #define IFACE_DELFLAGS 2
6474e5196e9SBrian Somers 
6484e5196e9SBrian Somers static int
649dc744e19SBrian Somers iface_ChangeFlags(const char *ifname, int flags, int how)
6504e5196e9SBrian Somers {
6514e5196e9SBrian Somers   struct ifreq ifrq;
65288202a1fSMaxim Sobolev   int s, new_flags;
6534e5196e9SBrian Somers 
65463c6cac9SBrian Somers   s = ID0socket(PF_INET, SOCK_DGRAM, 0);
6554e5196e9SBrian Somers   if (s < 0) {
65653dc037cSBrian Somers     log_Printf(LogERROR, "iface_ChangeFlags: socket: %s\n", strerror(errno));
6574e5196e9SBrian Somers     return 0;
6584e5196e9SBrian Somers   }
6594e5196e9SBrian Somers 
6604e5196e9SBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
661dc744e19SBrian Somers   strncpy(ifrq.ifr_name, ifname, sizeof ifrq.ifr_name - 1);
6624e5196e9SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
6634e5196e9SBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
66453dc037cSBrian Somers     log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n",
6654e5196e9SBrian Somers        strerror(errno));
6664e5196e9SBrian Somers     close(s);
6674e5196e9SBrian Somers     return 0;
6684e5196e9SBrian Somers   }
66950be714bSBrian Somers #ifdef __FreeBSD__
67088202a1fSMaxim Sobolev   new_flags = (ifrq.ifr_flags & 0xffff) | (ifrq.ifr_flagshigh << 16);
67150be714bSBrian Somers #else
67250be714bSBrian Somers   new_flags = ifrq.ifr_flags & 0xffff;
67350be714bSBrian Somers #endif
6744e5196e9SBrian Somers 
6754e5196e9SBrian Somers   if (how == IFACE_ADDFLAGS)
67688202a1fSMaxim Sobolev     new_flags |= flags;
6774e5196e9SBrian Somers   else
67888202a1fSMaxim Sobolev     new_flags &= ~flags;
67988202a1fSMaxim Sobolev   ifrq.ifr_flags = new_flags & 0xffff;
68050be714bSBrian Somers #ifdef __FreeBSD__
68188202a1fSMaxim Sobolev   ifrq.ifr_flagshigh = new_flags >> 16;
68250be714bSBrian Somers #endif
6834e5196e9SBrian Somers 
6844e5196e9SBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
68553dc037cSBrian Somers     log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n",
6864e5196e9SBrian Somers        strerror(errno));
6874e5196e9SBrian Somers     close(s);
6884e5196e9SBrian Somers     return 0;
6894e5196e9SBrian Somers   }
6904e5196e9SBrian Somers   close(s);
6914e5196e9SBrian Somers 
6924e5196e9SBrian Somers   return 1;	/* Success */
6934e5196e9SBrian Somers }
6944e5196e9SBrian Somers 
6954e5196e9SBrian Somers int
696dc744e19SBrian Somers iface_SetFlags(const char *ifname, int flags)
6974e5196e9SBrian Somers {
698dc744e19SBrian Somers   return iface_ChangeFlags(ifname, flags, IFACE_ADDFLAGS);
6994e5196e9SBrian Somers }
7004e5196e9SBrian Somers 
7014e5196e9SBrian Somers int
702dc744e19SBrian Somers iface_ClearFlags(const char *ifname, int flags)
7034e5196e9SBrian Somers {
704dc744e19SBrian Somers   return iface_ChangeFlags(ifname, flags, IFACE_DELFLAGS);
7054e5196e9SBrian Somers }
7064e5196e9SBrian Somers 
7078fa6ebe4SBrian Somers void
708f2f5156fSBrian Somers iface_Free(struct iface *iface)
7098fa6ebe4SBrian Somers {
7108fa6ebe4SBrian Somers     free(iface->name);
711f2f5156fSBrian Somers     free(iface->descr);
71230949fd4SBrian Somers     free(iface->addr);
7138fa6ebe4SBrian Somers     free(iface);
7148fa6ebe4SBrian Somers }
715f2f5156fSBrian Somers 
716f2f5156fSBrian Somers void
717f2f5156fSBrian Somers iface_Destroy(struct iface *iface)
718f2f5156fSBrian Somers {
719f2f5156fSBrian Somers   struct ifreq ifr;
720f2f5156fSBrian Somers   int s;
721f2f5156fSBrian Somers 
722f2f5156fSBrian Somers   if (iface != NULL) {
723f2f5156fSBrian Somers     if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
724f2f5156fSBrian Somers       log_Printf(LogERROR, "iface_Destroy: socket(): %s\n", strerror(errno));
725f2f5156fSBrian Somers     } else {
726f2f5156fSBrian Somers       strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
727f2f5156fSBrian Somers       if (ID0ioctl(s, SIOCIFDESTROY, (caddr_t)&ifr) < 0)
728f2f5156fSBrian Somers         log_Printf(LogWARN, "iface_Destroy: ioctl(SIOCIFDESTROY, %s): %s\n",
729f2f5156fSBrian Somers                iface->name, strerror(errno));
730f2f5156fSBrian Somers     }
731f2f5156fSBrian Somers     iface_Free(iface);
732f2f5156fSBrian Somers   }
7338fa6ebe4SBrian Somers }
7348fa6ebe4SBrian Somers 
7358fa6ebe4SBrian Somers #define if_entry(x) { IFF_##x, #x }
7368fa6ebe4SBrian Somers 
7378fa6ebe4SBrian Somers struct {
7388fa6ebe4SBrian Somers   int flag;
7398fa6ebe4SBrian Somers   const char *value;
7408fa6ebe4SBrian Somers } if_flags[] = {
7418fa6ebe4SBrian Somers   if_entry(UP),
7428fa6ebe4SBrian Somers   if_entry(BROADCAST),
7438fa6ebe4SBrian Somers   if_entry(DEBUG),
7448fa6ebe4SBrian Somers   if_entry(LOOPBACK),
7458fa6ebe4SBrian Somers   if_entry(POINTOPOINT),
7468fa6ebe4SBrian Somers   if_entry(RUNNING),
7478fa6ebe4SBrian Somers   if_entry(NOARP),
7488fa6ebe4SBrian Somers   if_entry(PROMISC),
7498fa6ebe4SBrian Somers   if_entry(ALLMULTI),
7508fa6ebe4SBrian Somers   if_entry(OACTIVE),
7518fa6ebe4SBrian Somers   if_entry(SIMPLEX),
7528fa6ebe4SBrian Somers   if_entry(LINK0),
7538fa6ebe4SBrian Somers   if_entry(LINK1),
7548fa6ebe4SBrian Somers   if_entry(LINK2),
7558fa6ebe4SBrian Somers   if_entry(MULTICAST),
7568fa6ebe4SBrian Somers   { 0, "???" }
7578fa6ebe4SBrian Somers };
7588fa6ebe4SBrian Somers 
7598fa6ebe4SBrian Somers int
7608fa6ebe4SBrian Somers iface_Show(struct cmdargs const *arg)
7618fa6ebe4SBrian Somers {
76230949fd4SBrian Somers   struct ncpaddr ncpaddr;
7638fa6ebe4SBrian Somers   struct iface *iface = arg->bundle->iface, *current;
764057f1760SBrian Somers   unsigned f;
765057f1760SBrian Somers   int flags;
76630949fd4SBrian Somers #ifndef NOINET6
76730949fd4SBrian Somers   int scopeid, width;
76830949fd4SBrian Somers #endif
76930949fd4SBrian Somers   struct in_addr mask;
7708fa6ebe4SBrian Somers 
7718fa6ebe4SBrian Somers   current = iface_Create(iface->name);
7728fa6ebe4SBrian Somers   flags = iface->flags = current->flags;
773f2f5156fSBrian Somers   iface_Free(current);
7748fa6ebe4SBrian Somers 
7758fa6ebe4SBrian Somers   prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
7768fa6ebe4SBrian Somers   for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
777ebdcbc67SBrian Somers     if ((if_flags[f].flag & flags)) {
7788fa6ebe4SBrian Somers       prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
7798fa6ebe4SBrian Somers                     if_flags[f].value);
7808fa6ebe4SBrian Somers       flags &= ~if_flags[f].flag;
7818fa6ebe4SBrian Somers     }
782ebdcbc67SBrian Somers 
783ebdcbc67SBrian Somers #if 0
784ebdcbc67SBrian Somers   if (flags)
785ebdcbc67SBrian Somers     prompt_Printf(arg->prompt, "%s0x%x", flags == iface->flags ? "" : ",",
786ebdcbc67SBrian Somers                   flags);
787ebdcbc67SBrian Somers #endif
788ebdcbc67SBrian Somers 
789057f1760SBrian Somers   prompt_Printf(arg->prompt, "> mtu %lu has %d address%s:\n", iface->mtu,
79030949fd4SBrian Somers                 iface->addrs, iface->addrs == 1 ? "" : "es");
7918fa6ebe4SBrian Somers 
79230949fd4SBrian Somers   for (f = 0; f < iface->addrs; f++) {
79330949fd4SBrian Somers     ncprange_getaddr(&iface->addr[f].ifa, &ncpaddr);
79430949fd4SBrian Somers     switch (ncprange_family(&iface->addr[f].ifa)) {
79530949fd4SBrian Somers     case AF_INET:
79630949fd4SBrian Somers       prompt_Printf(arg->prompt, "  inet %s --> ", ncpaddr_ntoa(&ncpaddr));
79730949fd4SBrian Somers       if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
79830949fd4SBrian Somers         prompt_Printf(arg->prompt, "255.255.255.255");
79930949fd4SBrian Somers       else
80030949fd4SBrian Somers         prompt_Printf(arg->prompt, "%s", ncpaddr_ntoa(&iface->addr[f].peer));
80130949fd4SBrian Somers       ncprange_getip4mask(&iface->addr[f].ifa, &mask);
80230949fd4SBrian Somers       prompt_Printf(arg->prompt, " netmask 0x%08lx", (long)ntohl(mask.s_addr));
80330949fd4SBrian Somers       break;
80430949fd4SBrian Somers 
80530949fd4SBrian Somers #ifndef NOINET6
80630949fd4SBrian Somers     case AF_INET6:
80730949fd4SBrian Somers       prompt_Printf(arg->prompt, "  inet6 %s", ncpaddr_ntoa(&ncpaddr));
80830949fd4SBrian Somers       if (ncpaddr_family(&iface->addr[f].peer) != AF_UNSPEC)
80930949fd4SBrian Somers         prompt_Printf(arg->prompt, " --> %s",
81030949fd4SBrian Somers                       ncpaddr_ntoa(&iface->addr[f].peer));
81130949fd4SBrian Somers       ncprange_getwidth(&iface->addr[f].ifa, &width);
812a8862471SBrian Somers       if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
81330949fd4SBrian Somers         prompt_Printf(arg->prompt, " prefixlen %d", width);
81430949fd4SBrian Somers       if ((scopeid = ncprange_scopeid(&iface->addr[f].ifa)) != -1)
81530949fd4SBrian Somers         prompt_Printf(arg->prompt, " scopeid 0x%x", (unsigned)scopeid);
81630949fd4SBrian Somers       break;
81730949fd4SBrian Somers #endif
81830949fd4SBrian Somers     }
8198fa6ebe4SBrian Somers     prompt_Printf(arg->prompt, "\n");
8208fa6ebe4SBrian Somers   }
8218fa6ebe4SBrian Somers 
8228fa6ebe4SBrian Somers   return 0;
8238fa6ebe4SBrian Somers }
8246b457978SBrian Somers 
8256b457978SBrian Somers void
8266b457978SBrian Somers iface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX])
8276b457978SBrian Somers {
8286b457978SBrian Somers   char *wp;
8296b457978SBrian Somers   int rtax;
8306b457978SBrian Somers 
8316b457978SBrian Somers   wp = (char *)(ifam + 1);
8326b457978SBrian Somers 
8336b457978SBrian Somers   for (rtax = 0; rtax < RTAX_MAX; rtax++)
8346b457978SBrian Somers     if (ifam->ifam_addrs & (1 << rtax)) {
8356b457978SBrian Somers       sa[rtax] = (struct sockaddr *)wp;
8366b457978SBrian Somers       wp += ROUNDUP(sa[rtax]->sa_len);
8376b457978SBrian Somers     } else
8386b457978SBrian Somers       sa[rtax] = NULL;
8396b457978SBrian Somers }
840