18fa6ebe4SBrian Somers /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro 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 */
288fa6ebe4SBrian Somers
29972a1bcfSBrian Somers #include <sys/param.h>
308fa6ebe4SBrian Somers #include <sys/socket.h>
318fa6ebe4SBrian Somers #include <netinet/in.h>
328fa6ebe4SBrian Somers #include <net/if.h>
338fa6ebe4SBrian Somers #include <net/if_dl.h>
348fa6ebe4SBrian Somers #include <net/route.h>
358fa6ebe4SBrian Somers #include <netinet/in_systm.h>
3630949fd4SBrian Somers #include <netinet/in_var.h>
378fa6ebe4SBrian Somers #include <netinet/ip.h>
3830949fd4SBrian Somers #ifndef NOINET6
3930949fd4SBrian Somers #include <netinet6/nd6.h>
4030949fd4SBrian Somers #endif
418fa6ebe4SBrian Somers #include <sys/un.h>
428fa6ebe4SBrian Somers
43119386a3SBrian Somers #include <errno.h>
448fa6ebe4SBrian Somers #include <string.h>
456eafd353SBrian Somers #include <stdarg.h>
468fa6ebe4SBrian Somers #include <stdio.h>
478fa6ebe4SBrian Somers #include <stdlib.h>
48119386a3SBrian Somers #include <sys/ioctl.h>
49119386a3SBrian Somers #include <sys/sysctl.h>
508fa6ebe4SBrian Somers #include <termios.h>
518fa6ebe4SBrian Somers #include <unistd.h>
528fa6ebe4SBrian Somers
535d9e6103SBrian Somers #include "layer.h"
548fa6ebe4SBrian Somers #include "defs.h"
558fa6ebe4SBrian Somers #include "command.h"
568fa6ebe4SBrian Somers #include "mbuf.h"
578fa6ebe4SBrian Somers #include "log.h"
588fa6ebe4SBrian Somers #include "id.h"
598fa6ebe4SBrian Somers #include "timer.h"
608fa6ebe4SBrian Somers #include "fsm.h"
618fa6ebe4SBrian Somers #include "iplist.h"
628fa6ebe4SBrian Somers #include "lqr.h"
638fa6ebe4SBrian Somers #include "hdlc.h"
648fa6ebe4SBrian Somers #include "throughput.h"
658fa6ebe4SBrian Somers #include "slcompress.h"
668fa6ebe4SBrian Somers #include "descriptor.h"
6730949fd4SBrian Somers #include "ncpaddr.h"
688fa6ebe4SBrian Somers #include "ipcp.h"
691d1fc017SBrian Somers #include "filter.h"
708fa6ebe4SBrian Somers #include "lcp.h"
718fa6ebe4SBrian Somers #include "ccp.h"
728fa6ebe4SBrian Somers #include "link.h"
738fa6ebe4SBrian Somers #include "mp.h"
74972a1bcfSBrian Somers #ifndef NORADIUS
75972a1bcfSBrian Somers #include "radius.h"
76972a1bcfSBrian Somers #endif
7730949fd4SBrian Somers #include "ipv6cp.h"
7830949fd4SBrian Somers #include "ncp.h"
798fa6ebe4SBrian Somers #include "bundle.h"
808fa6ebe4SBrian Somers #include "prompt.h"
818fa6ebe4SBrian Somers #include "iface.h"
828fa6ebe4SBrian Somers
83977e6c08SHajimu UMEMOTO #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
84977e6c08SHajimu UMEMOTO 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
85977e6c08SHajimu UMEMOTO static const struct in6_addr in6mask128 = IN6MASK128;
86977e6c08SHajimu UMEMOTO
878fa6ebe4SBrian Somers
888fa6ebe4SBrian Somers struct iface *
iface_Create(const char * name)898fa6ebe4SBrian Somers iface_Create(const char *name)
908fa6ebe4SBrian Somers {
9130949fd4SBrian Somers int mib[6], maxtries, err;
9258a57513SBrian Somers size_t needed, namelen;
936b457978SBrian Somers char *buf, *ptr, *end;
948fa6ebe4SBrian Somers struct if_msghdr *ifm;
958fa6ebe4SBrian Somers struct ifa_msghdr *ifam;
968fa6ebe4SBrian Somers struct sockaddr_dl *dl;
976b457978SBrian Somers struct sockaddr *sa[RTAX_MAX];
988fa6ebe4SBrian Somers struct iface *iface;
998fa6ebe4SBrian Somers struct iface_addr *addr;
1008fa6ebe4SBrian Somers
1018fa6ebe4SBrian Somers mib[0] = CTL_NET;
1028fa6ebe4SBrian Somers mib[1] = PF_ROUTE;
1038fa6ebe4SBrian Somers mib[2] = 0;
1048fa6ebe4SBrian Somers mib[3] = 0;
1058fa6ebe4SBrian Somers mib[4] = NET_RT_IFLIST;
1068fa6ebe4SBrian Somers mib[5] = 0;
1078fa6ebe4SBrian Somers
108152a4390SBrian Somers maxtries = 20;
109152a4390SBrian Somers err = 0;
110152a4390SBrian Somers do {
111152a4390SBrian Somers if (maxtries-- == 0 || (err && err != ENOMEM)) {
112152a4390SBrian Somers fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(err));
113152a4390SBrian Somers return NULL;
114152a4390SBrian Somers }
115152a4390SBrian Somers
1168fa6ebe4SBrian Somers if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
117c0593e34SBrian Somers fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
1188fa6ebe4SBrian Somers strerror(errno));
1198fa6ebe4SBrian Somers return NULL;
1208fa6ebe4SBrian Somers }
1218fa6ebe4SBrian Somers
1228fa6ebe4SBrian Somers if ((buf = (char *)malloc(needed)) == NULL) {
123c0593e34SBrian Somers fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
1248fa6ebe4SBrian Somers return NULL;
1258fa6ebe4SBrian Somers }
1268fa6ebe4SBrian Somers
1278fa6ebe4SBrian Somers if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
128152a4390SBrian Somers err = errno;
1298fa6ebe4SBrian Somers free(buf);
130152a4390SBrian Somers buf = NULL;
1318fa6ebe4SBrian Somers }
132152a4390SBrian Somers } while (buf == NULL);
1338fa6ebe4SBrian Somers
1348fa6ebe4SBrian Somers ptr = buf;
1358fa6ebe4SBrian Somers end = buf + needed;
1368fa6ebe4SBrian Somers iface = NULL;
13758a57513SBrian Somers namelen = strlen(name);
1388fa6ebe4SBrian Somers
1398fa6ebe4SBrian Somers while (ptr < end && iface == NULL) {
1408fa6ebe4SBrian Somers ifm = (struct if_msghdr *)ptr; /* On if_msghdr */
1418fa6ebe4SBrian Somers if (ifm->ifm_type != RTM_IFINFO)
1428fa6ebe4SBrian Somers break;
1438fa6ebe4SBrian Somers dl = (struct sockaddr_dl *)(ifm + 1); /* Single _dl at end */
14458a57513SBrian Somers if (dl->sdl_nlen == namelen && !strncmp(name, dl->sdl_data, namelen)) {
1458fa6ebe4SBrian Somers iface = (struct iface *)malloc(sizeof *iface);
1468fa6ebe4SBrian Somers if (iface == NULL) {
1478fa6ebe4SBrian Somers fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
148ba01ab64SStephen J. Kiernan free(buf);
1498fa6ebe4SBrian Somers return NULL;
1508fa6ebe4SBrian Somers }
1518fa6ebe4SBrian Somers iface->name = strdup(name);
152f2f5156fSBrian Somers iface->descr = NULL;
1538fa6ebe4SBrian Somers iface->index = ifm->ifm_index;
154c8b9fb53SBrian Somers iface->flags = ifm->ifm_flags;
155c8b9fb53SBrian Somers iface->mtu = 0;
15630949fd4SBrian Somers iface->addrs = 0;
15730949fd4SBrian Somers iface->addr = NULL;
1588fa6ebe4SBrian Somers }
1598fa6ebe4SBrian Somers ptr += ifm->ifm_msglen; /* First ifa_msghdr */
1608fa6ebe4SBrian Somers for (; ptr < end; ptr += ifam->ifam_msglen) {
1618fa6ebe4SBrian Somers ifam = (struct ifa_msghdr *)ptr; /* Next if address */
1628fa6ebe4SBrian Somers
1638fa6ebe4SBrian Somers if (ifam->ifam_type != RTM_NEWADDR) /* finished this if */
1648fa6ebe4SBrian Somers break;
1658fa6ebe4SBrian Somers
1666b457978SBrian Somers if (iface != NULL && ifam->ifam_addrs & RTA_IFA) {
1676b457978SBrian Somers /* Found a configured interface ! */
1686b457978SBrian Somers iface_ParseHdr(ifam, sa);
1698fa6ebe4SBrian Somers
17030949fd4SBrian Somers if (sa[RTAX_IFA] && (sa[RTAX_IFA]->sa_family == AF_INET
17130949fd4SBrian Somers #ifndef NOINET6
17230949fd4SBrian Somers || sa[RTAX_IFA]->sa_family == AF_INET6
17330949fd4SBrian Somers #endif
17430949fd4SBrian Somers )) {
1756b457978SBrian Somers /* Record the address */
1768fa6ebe4SBrian Somers
17730949fd4SBrian Somers addr = (struct iface_addr *)
17830949fd4SBrian Somers realloc(iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
1798fa6ebe4SBrian Somers if (addr == NULL)
1808fa6ebe4SBrian Somers break;
18130949fd4SBrian Somers iface->addr = addr;
1828fa6ebe4SBrian Somers
18330949fd4SBrian Somers addr += iface->addrs;
18430949fd4SBrian Somers iface->addrs++;
1858fa6ebe4SBrian Somers
18630949fd4SBrian Somers ncprange_setsa(&addr->ifa, sa[RTAX_IFA], sa[RTAX_NETMASK]);
1876b457978SBrian Somers if (sa[RTAX_BRD])
18830949fd4SBrian Somers ncpaddr_setsa(&addr->peer, sa[RTAX_BRD]);
1896b457978SBrian Somers else
19030949fd4SBrian Somers ncpaddr_init(&addr->peer);
1918fa6ebe4SBrian Somers }
1928fa6ebe4SBrian Somers }
1938fa6ebe4SBrian Somers }
1948fa6ebe4SBrian Somers }
1958fa6ebe4SBrian Somers
1968fa6ebe4SBrian Somers free(buf);
1978fa6ebe4SBrian Somers
1988fa6ebe4SBrian Somers return iface;
1998fa6ebe4SBrian Somers }
2008fa6ebe4SBrian Somers
20130949fd4SBrian Somers static int
iface_addr_Zap(const char * name,struct iface_addr * addr,int s)20230949fd4SBrian Somers iface_addr_Zap(const char *name, struct iface_addr *addr, int s)
2038fa6ebe4SBrian Somers {
204*2ab55150SKonrad Witaszczyk struct ifreq ifr;
20530949fd4SBrian Somers #ifndef NOINET6
206*2ab55150SKonrad Witaszczyk struct in6_ifreq ifr6;
20730949fd4SBrian Somers #endif
208*2ab55150SKonrad Witaszczyk struct sockaddr_in *me4;
209*2ab55150SKonrad Witaszczyk struct sockaddr_storage ssme;
2106cd3353bSEugene Grosbein int res, saved_errno;
2118fa6ebe4SBrian Somers
212*2ab55150SKonrad Witaszczyk ncprange_getsa(&addr->ifa, &ssme, NULL);
21330949fd4SBrian Somers res = 0;
21430949fd4SBrian Somers
21530949fd4SBrian Somers switch (ncprange_family(&addr->ifa)) {
21630949fd4SBrian Somers case AF_INET:
217*2ab55150SKonrad Witaszczyk memset(&ifr, '\0', sizeof ifr);
218*2ab55150SKonrad Witaszczyk strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name - 1);
219*2ab55150SKonrad Witaszczyk me4 = (struct sockaddr_in *)&ifr.ifr_addr;
22030949fd4SBrian Somers memcpy(me4, &ssme, sizeof *me4);
22130949fd4SBrian Somers
222*2ab55150SKonrad Witaszczyk res = ID0ioctl(s, SIOCDIFADDR, &ifr);
2236cd3353bSEugene Grosbein saved_errno = errno;
2242ea80d6dSBrian Somers if (log_IsKept(LogDEBUG)) {
2256cd3353bSEugene Grosbein char buf[NCP_ASCIIBUFFERSIZE];
2262ea80d6dSBrian Somers
2272ea80d6dSBrian Somers snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa));
2282ea80d6dSBrian Somers log_Printf(LogWARN, "%s: DIFADDR %s -> %s returns %d\n",
229*2ab55150SKonrad Witaszczyk ifr.ifr_name, buf, ncpaddr_ntoa(&addr->peer), res);
2302ea80d6dSBrian Somers }
23130949fd4SBrian Somers break;
23230949fd4SBrian Somers
23330949fd4SBrian Somers #ifndef NOINET6
23430949fd4SBrian Somers case AF_INET6:
235*2ab55150SKonrad Witaszczyk memset(&ifr6, '\0', sizeof ifr6);
236*2ab55150SKonrad Witaszczyk strncpy(ifr6.ifr_name, name, sizeof ifr6.ifr_name - 1);
237*2ab55150SKonrad Witaszczyk memcpy(&ifr6.ifr_addr, &ssme, sizeof ifr6.ifr_addr);
23830949fd4SBrian Somers
239*2ab55150SKonrad Witaszczyk res = ID0ioctl(s, SIOCDIFADDR_IN6, &ifr6);
2406cd3353bSEugene Grosbein saved_errno = errno;
24130949fd4SBrian Somers break;
24230949fd4SBrian Somers #endif
24330949fd4SBrian Somers }
24430949fd4SBrian Somers
24530949fd4SBrian Somers if (res == -1) {
2466cd3353bSEugene Grosbein char dst[NCP_ASCIIBUFFERSIZE];
24730949fd4SBrian Somers const char *end =
24830949fd4SBrian Somers #ifndef NOINET6
24930949fd4SBrian Somers ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
25030949fd4SBrian Somers #endif
25130949fd4SBrian Somers "";
25230949fd4SBrian Somers
25330949fd4SBrian Somers if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
25430949fd4SBrian Somers log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s): %s\n",
2556cd3353bSEugene Grosbein end, ncprange_ntoa(&addr->ifa), strerror(saved_errno));
25630949fd4SBrian Somers else {
25730949fd4SBrian Somers snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
25830949fd4SBrian Somers log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
2596cd3353bSEugene Grosbein end, ncprange_ntoa(&addr->ifa), dst, strerror(saved_errno));
2608fa6ebe4SBrian Somers }
2618fa6ebe4SBrian Somers }
2628fa6ebe4SBrian Somers
26330949fd4SBrian Somers return res != -1;
26430949fd4SBrian Somers }
26530949fd4SBrian Somers
266add3c041SBrian Somers static int
iface_addr_Add(const char * name,struct iface_addr * addr,int s)26730949fd4SBrian Somers iface_addr_Add(const char *name, struct iface_addr *addr, int s)
26830949fd4SBrian Somers {
26930949fd4SBrian Somers struct ifaliasreq ifra;
27030949fd4SBrian Somers #ifndef NOINET6
27130949fd4SBrian Somers struct in6_aliasreq ifra6;
27230949fd4SBrian Somers #endif
27330949fd4SBrian Somers struct sockaddr_in *me4, *msk4, *peer4;
27430949fd4SBrian Somers struct sockaddr_storage ssme, sspeer, ssmsk;
2756cd3353bSEugene Grosbein int res, saved_errno;
27630949fd4SBrian Somers
27730949fd4SBrian Somers ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
27830949fd4SBrian Somers ncpaddr_getsa(&addr->peer, &sspeer);
27930949fd4SBrian Somers res = 0;
28030949fd4SBrian Somers
28130949fd4SBrian Somers switch (ncprange_family(&addr->ifa)) {
28230949fd4SBrian Somers case AF_INET:
28330949fd4SBrian Somers memset(&ifra, '\0', sizeof ifra);
28430949fd4SBrian Somers strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
28530949fd4SBrian Somers
28630949fd4SBrian Somers me4 = (struct sockaddr_in *)&ifra.ifra_addr;
28730949fd4SBrian Somers memcpy(me4, &ssme, sizeof *me4);
28830949fd4SBrian Somers
28930949fd4SBrian Somers msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
29030949fd4SBrian Somers memcpy(msk4, &ssmsk, sizeof *msk4);
29130949fd4SBrian Somers
29230949fd4SBrian Somers peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
29330949fd4SBrian Somers if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
29430949fd4SBrian Somers peer4->sin_family = AF_INET;
29530949fd4SBrian Somers peer4->sin_len = sizeof(*peer4);
29630949fd4SBrian Somers peer4->sin_addr.s_addr = INADDR_NONE;
29730949fd4SBrian Somers } else
29830949fd4SBrian Somers memcpy(peer4, &sspeer, sizeof *peer4);
29930949fd4SBrian Somers
30030949fd4SBrian Somers res = ID0ioctl(s, SIOCAIFADDR, &ifra);
3016cd3353bSEugene Grosbein saved_errno = errno;
3022ea80d6dSBrian Somers if (log_IsKept(LogDEBUG)) {
3036cd3353bSEugene Grosbein char buf[NCP_ASCIIBUFFERSIZE];
3042ea80d6dSBrian Somers
3052ea80d6dSBrian Somers snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa));
3062ea80d6dSBrian Somers log_Printf(LogWARN, "%s: AIFADDR %s -> %s returns %d\n",
3072ea80d6dSBrian Somers ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res);
3082ea80d6dSBrian Somers }
30930949fd4SBrian Somers break;
31030949fd4SBrian Somers
31130949fd4SBrian Somers #ifndef NOINET6
31230949fd4SBrian Somers case AF_INET6:
31330949fd4SBrian Somers memset(&ifra6, '\0', sizeof ifra6);
31430949fd4SBrian Somers strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
31530949fd4SBrian Somers
31630949fd4SBrian Somers memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
31730949fd4SBrian Somers memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
31830949fd4SBrian Somers if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
31930949fd4SBrian Somers ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
320977e6c08SHajimu UMEMOTO else if (memcmp(&((struct sockaddr_in6 *)&ssmsk)->sin6_addr, &in6mask128,
321977e6c08SHajimu UMEMOTO sizeof in6mask128) == 0)
32230949fd4SBrian Somers memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
32330949fd4SBrian Somers ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
32430949fd4SBrian Somers ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
32530949fd4SBrian Somers
32630949fd4SBrian Somers res = ID0ioctl(s, SIOCAIFADDR_IN6, &ifra6);
3276cd3353bSEugene Grosbein saved_errno = errno;
32830949fd4SBrian Somers break;
32930949fd4SBrian Somers #endif
33030949fd4SBrian Somers }
33130949fd4SBrian Somers
33230949fd4SBrian Somers if (res == -1) {
3336cd3353bSEugene Grosbein char dst[NCP_ASCIIBUFFERSIZE];
33430949fd4SBrian Somers const char *end =
33530949fd4SBrian Somers #ifndef NOINET6
33630949fd4SBrian Somers ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
33730949fd4SBrian Somers #endif
33830949fd4SBrian Somers "";
33930949fd4SBrian Somers
34030949fd4SBrian Somers if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
34130949fd4SBrian Somers log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n",
3426cd3353bSEugene Grosbein end, ncprange_ntoa(&addr->ifa), strerror(saved_errno));
34330949fd4SBrian Somers else {
34430949fd4SBrian Somers snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
34546df5aa7SBrian Somers log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s -> %s): %s\n",
3466cd3353bSEugene Grosbein end, ncprange_ntoa(&addr->ifa), dst, strerror(saved_errno));
34730949fd4SBrian Somers }
34830949fd4SBrian Somers }
349add3c041SBrian Somers
350add3c041SBrian Somers return res != -1;
35130949fd4SBrian Somers }
35230949fd4SBrian Somers
353f2f5156fSBrian Somers int
iface_Name(struct iface * iface,const char * name)354f2f5156fSBrian Somers iface_Name(struct iface *iface, const char *name)
355f2f5156fSBrian Somers {
356f2f5156fSBrian Somers struct ifreq ifr;
357f2f5156fSBrian Somers int s;
358f2f5156fSBrian Somers char *newname;
359f2f5156fSBrian Somers
360f2f5156fSBrian Somers if ((newname = strdup(name)) == NULL) {
361f2f5156fSBrian Somers log_Printf(LogWARN, "iface name: strdup failed: %s\n", strerror(errno));
362f2f5156fSBrian Somers return 0;
363f2f5156fSBrian Somers }
364f2f5156fSBrian Somers
365f2f5156fSBrian Somers if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
366f2f5156fSBrian Somers log_Printf(LogERROR, "iface name: socket(): %s\n", strerror(errno));
367f2f5156fSBrian Somers free(newname);
368f2f5156fSBrian Somers return 0;
369f2f5156fSBrian Somers }
370f2f5156fSBrian Somers
371f2f5156fSBrian Somers strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
372f2f5156fSBrian Somers ifr.ifr_data = newname;
373f2f5156fSBrian Somers if (ID0ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
374f2f5156fSBrian Somers log_Printf(LogWARN, "iface name: ioctl(SIOCSIFNAME, %s -> %s): %s\n",
375f2f5156fSBrian Somers name, newname, strerror(errno));
376f2f5156fSBrian Somers free(newname);
377f2f5156fSBrian Somers return 0;
378f2f5156fSBrian Somers }
379f2f5156fSBrian Somers
380f2f5156fSBrian Somers free(iface->name);
381f2f5156fSBrian Somers iface->name = newname;
382f2f5156fSBrian Somers
383f2f5156fSBrian Somers return 1;
384f2f5156fSBrian Somers }
385f2f5156fSBrian Somers
386f2f5156fSBrian Somers int
iface_Descr(struct cmdargs const * arg)387f2f5156fSBrian Somers iface_Descr(struct cmdargs const *arg)
388f2f5156fSBrian Somers {
389f2f5156fSBrian Somers struct ifreq ifr;
390f2f5156fSBrian Somers struct iface *iface;
391f2f5156fSBrian Somers size_t sz, len;
392f2f5156fSBrian Somers int s, n, ifdescr_maxlen;
393f2f5156fSBrian Somers char *descr;
394f2f5156fSBrian Somers
395f2f5156fSBrian Somers sz = sizeof(int);
396f2f5156fSBrian Somers if (sysctlbyname("net.ifdescr_maxlen", &ifdescr_maxlen, &sz, NULL, 0) < 0) {
397f2f5156fSBrian Somers log_Printf(LogERROR, "iface descr: sysctl failed: %s\n", strerror(errno));
398f2f5156fSBrian Somers return 1;
399f2f5156fSBrian Somers }
400f2f5156fSBrian Somers
401f2f5156fSBrian Somers if (ifdescr_maxlen < 1) {
402f2f5156fSBrian Somers log_Printf(LogERROR, "iface descr: sysctl net.ifdescr_maxlen < 1\n");
403f2f5156fSBrian Somers return 1;
404f2f5156fSBrian Somers }
405f2f5156fSBrian Somers
406f2f5156fSBrian Somers sz = sizeof(char) * ifdescr_maxlen;
407f2f5156fSBrian Somers if ((descr = malloc(sz)) == NULL) {
408f2f5156fSBrian Somers log_Printf(LogERROR, "iface descr: malloc failed: %s\n", strerror(errno));
409f2f5156fSBrian Somers return 1;
410f2f5156fSBrian Somers }
411f2f5156fSBrian Somers
412f2f5156fSBrian Somers *descr = '\0';
413f2f5156fSBrian Somers n = arg->argn;
414f2f5156fSBrian Somers while (n < arg->argc) {
415f2f5156fSBrian Somers if (n > arg->argn && (len = strlcat(descr, " ", sz)) >= sz)
416f2f5156fSBrian Somers break;
417f2f5156fSBrian Somers if ((len = strlcat(descr, arg->argv[n], sz)) >= sz)
418f2f5156fSBrian Somers break;
419f2f5156fSBrian Somers ++n;
420f2f5156fSBrian Somers }
421f2f5156fSBrian Somers if (len >= sz) {
422f2f5156fSBrian Somers log_Printf(LogERROR, "iface descr: description exceeds maximum (%d)\n",
423f2f5156fSBrian Somers ifdescr_maxlen-1);
424f2f5156fSBrian Somers free(descr);
425f2f5156fSBrian Somers return 1;
426f2f5156fSBrian Somers }
427f2f5156fSBrian Somers
428f2f5156fSBrian Somers if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
429f2f5156fSBrian Somers log_Printf(LogERROR, "iface descr: socket(): %s\n", strerror(errno));
430f2f5156fSBrian Somers free(descr);
431f2f5156fSBrian Somers return 1;
432f2f5156fSBrian Somers }
433f2f5156fSBrian Somers
434f2f5156fSBrian Somers iface = arg->bundle->iface;
435f2f5156fSBrian Somers strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
436f2f5156fSBrian Somers ifr.ifr_buffer.length = strlen(descr) + 1;
437f2f5156fSBrian Somers ifr.ifr_buffer.buffer = descr;
438f2f5156fSBrian Somers if (ID0ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) {
439f2f5156fSBrian Somers log_Printf(LogWARN, "iface descr: ioctl(SIOCSIFDESCR, %s): %s\n",
440f2f5156fSBrian Somers descr, strerror(errno));
441f2f5156fSBrian Somers free(descr);
442f2f5156fSBrian Somers return 1;
443f2f5156fSBrian Somers }
444f2f5156fSBrian Somers
445f2f5156fSBrian Somers free(iface->descr);
446f2f5156fSBrian Somers iface->descr = descr;
447f2f5156fSBrian Somers
448f2f5156fSBrian Somers return 0;
449f2f5156fSBrian Somers }
45030949fd4SBrian Somers
4518fa6ebe4SBrian Somers void
iface_Clear(struct iface * iface,struct ncp * ncp,int family,int how)45230949fd4SBrian Somers iface_Clear(struct iface *iface, struct ncp *ncp, int family, int how)
4538fa6ebe4SBrian Somers {
4547268c7daSEitan Adler int af, inskip, in6skip, s4 = -1, s6 = -1, *s;
455057f1760SBrian Somers unsigned n;
4568fa6ebe4SBrian Somers
45730949fd4SBrian Somers if (iface->addrs) {
45830949fd4SBrian Somers inskip = in6skip = how == IFACE_CLEAR_ALL ? 0 : 1;
4598fa6ebe4SBrian Somers
46030949fd4SBrian Somers for (n = 0; n < iface->addrs; n++) {
46130949fd4SBrian Somers af = ncprange_family(&iface->addr[n].ifa);
46230949fd4SBrian Somers if (family == 0 || family == af) {
46330949fd4SBrian Somers if (!iface->addr[n].system && (how & IFACE_SYSTEM))
46430949fd4SBrian Somers continue;
46530949fd4SBrian Somers switch (af) {
46630949fd4SBrian Somers case AF_INET:
46730949fd4SBrian Somers if (inskip) {
46830949fd4SBrian Somers inskip = 0;
46930949fd4SBrian Somers continue;
47030949fd4SBrian Somers }
47130949fd4SBrian Somers s = &s4;
47230949fd4SBrian Somers break;
47330949fd4SBrian Somers
47430949fd4SBrian Somers #ifndef NOINET6
47530949fd4SBrian Somers case AF_INET6:
47630949fd4SBrian Somers if (in6skip) {
47730949fd4SBrian Somers in6skip = 0;
47830949fd4SBrian Somers continue;
47930949fd4SBrian Somers }
48030949fd4SBrian Somers s = &s6;
48130949fd4SBrian Somers break;
48230949fd4SBrian Somers #endif
483856cf687SBrian Somers default:
484856cf687SBrian Somers continue;
48530949fd4SBrian Somers }
48630949fd4SBrian Somers
48730949fd4SBrian Somers if (*s == -1 && (*s = ID0socket(af, SOCK_DGRAM, 0)) == -1)
48830949fd4SBrian Somers log_Printf(LogERROR, "iface_Clear: socket(): %s\n", strerror(errno));
48930949fd4SBrian Somers else if (iface_addr_Zap(iface->name, iface->addr + n, *s)) {
49030949fd4SBrian Somers ncp_IfaceAddrDeleted(ncp, iface->addr + n);
49130949fd4SBrian Somers bcopy(iface->addr + n + 1, iface->addr + n,
49230949fd4SBrian Somers (iface->addrs - n - 1) * sizeof *iface->addr);
49330949fd4SBrian Somers iface->addrs--;
49430949fd4SBrian Somers n--;
49530949fd4SBrian Somers }
49630949fd4SBrian Somers }
49730949fd4SBrian Somers }
49830949fd4SBrian Somers
4998fa6ebe4SBrian Somers /* Don't bother realloc()ing - we have little to gain */
50030949fd4SBrian Somers
50130949fd4SBrian Somers if (s4)
50230949fd4SBrian Somers close(s4);
50330949fd4SBrian Somers if (s6)
50430949fd4SBrian Somers close(s6);
5058fa6ebe4SBrian Somers }
506278657c3SBrian Somers }
5078fa6ebe4SBrian Somers
5088fa6ebe4SBrian Somers int
iface_Add(struct iface * iface,struct ncp * ncp,const struct ncprange * ifa,const struct ncpaddr * peer,int how)50930949fd4SBrian Somers iface_Add(struct iface *iface, struct ncp *ncp, const struct ncprange *ifa,
51030949fd4SBrian Somers const struct ncpaddr *peer, int how)
5118fa6ebe4SBrian Somers {
512057f1760SBrian Somers int af, removed, s;
513057f1760SBrian Somers unsigned n;
514add3c041SBrian Somers struct ncpaddr ncplocal;
515add3c041SBrian Somers struct iface_addr *addr, newaddr;
5168fa6ebe4SBrian Somers
51730949fd4SBrian Somers af = ncprange_family(ifa);
51830949fd4SBrian Somers if ((s = ID0socket(af, SOCK_DGRAM, 0)) == -1) {
51930949fd4SBrian Somers log_Printf(LogERROR, "iface_Add: socket(): %s\n", strerror(errno));
5208fa6ebe4SBrian Somers return 0;
5218fa6ebe4SBrian Somers }
52230949fd4SBrian Somers ncprange_getaddr(ifa, &ncplocal);
52330949fd4SBrian Somers
52430949fd4SBrian Somers for (n = 0; n < iface->addrs; n++) {
52584b0fe81SBrian Somers if (ncprange_contains(&iface->addr[n].ifa, &ncplocal) ||
52684b0fe81SBrian Somers ncpaddr_equal(&iface->addr[n].peer, peer)) {
527add3c041SBrian Somers /* Replace this sockaddr */
52830949fd4SBrian Somers if (!(how & IFACE_FORCE_ADD)) {
52930949fd4SBrian Somers close(s);
53030949fd4SBrian Somers return 0; /* errno = EEXIST; */
53130949fd4SBrian Somers }
53230949fd4SBrian Somers
53330949fd4SBrian Somers if (ncprange_equal(&iface->addr[n].ifa, ifa) &&
53430949fd4SBrian Somers ncpaddr_equal(&iface->addr[n].peer, peer)) {
53530949fd4SBrian Somers close(s);
5361de22c3bSBjoern A. Zeeb ncp_IfaceAddrAdded(ncp, iface->addr + n);
53730949fd4SBrian Somers return 1; /* Already there */
53830949fd4SBrian Somers }
53930949fd4SBrian Somers
540add3c041SBrian Somers removed = iface_addr_Zap(iface->name, iface->addr + n, s);
541add3c041SBrian Somers if (removed)
542add3c041SBrian Somers ncp_IfaceAddrDeleted(ncp, iface->addr + n);
543add3c041SBrian Somers ncprange_copy(&iface->addr[n].ifa, ifa);
54430949fd4SBrian Somers ncpaddr_copy(&iface->addr[n].peer, peer);
545add3c041SBrian Somers if (!iface_addr_Add(iface->name, iface->addr + n, s)) {
546add3c041SBrian Somers if (removed) {
547add3c041SBrian Somers bcopy(iface->addr + n + 1, iface->addr + n,
548add3c041SBrian Somers (iface->addrs - n - 1) * sizeof *iface->addr);
549add3c041SBrian Somers iface->addrs--;
550add3c041SBrian Somers n--;
551add3c041SBrian Somers }
552add3c041SBrian Somers close(s);
553add3c041SBrian Somers return 0;
554add3c041SBrian Somers }
55530949fd4SBrian Somers close(s);
55630949fd4SBrian Somers ncp_IfaceAddrAdded(ncp, iface->addr + n);
55730949fd4SBrian Somers return 1;
55830949fd4SBrian Somers }
55930949fd4SBrian Somers }
5608fa6ebe4SBrian Somers
5618fa6ebe4SBrian Somers addr = (struct iface_addr *)realloc
56230949fd4SBrian Somers (iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
5638fa6ebe4SBrian Somers if (addr == NULL) {
5648fa6ebe4SBrian Somers log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
5658fa6ebe4SBrian Somers close(s);
5668fa6ebe4SBrian Somers return 0;
5678fa6ebe4SBrian Somers }
56830949fd4SBrian Somers iface->addr = addr;
5698fa6ebe4SBrian Somers
570add3c041SBrian Somers ncprange_copy(&newaddr.ifa, ifa);
571add3c041SBrian Somers ncpaddr_copy(&newaddr.peer, peer);
572add3c041SBrian Somers newaddr.system = !!(how & IFACE_SYSTEM);
573add3c041SBrian Somers if (!iface_addr_Add(iface->name, &newaddr, s)) {
574add3c041SBrian Somers close(s);
575add3c041SBrian Somers return 0;
576add3c041SBrian Somers }
577add3c041SBrian Somers
5788fa6ebe4SBrian Somers if (how & IFACE_ADD_FIRST) {
5798fa6ebe4SBrian Somers /* Stuff it at the start of our list */
58030949fd4SBrian Somers n = 0;
58130949fd4SBrian Somers bcopy(iface->addr, iface->addr + 1, iface->addrs * sizeof *iface->addr);
58230949fd4SBrian Somers } else
58330949fd4SBrian Somers n = iface->addrs;
5848fa6ebe4SBrian Somers
58530949fd4SBrian Somers iface->addrs++;
586add3c041SBrian Somers memcpy(iface->addr + n, &newaddr, sizeof(*iface->addr));
5878fa6ebe4SBrian Somers
58830949fd4SBrian Somers close(s);
58930949fd4SBrian Somers ncp_IfaceAddrAdded(ncp, iface->addr + n);
5908fa6ebe4SBrian Somers
5918fa6ebe4SBrian Somers return 1;
5928fa6ebe4SBrian Somers }
5938fa6ebe4SBrian Somers
5948fa6ebe4SBrian Somers int
iface_Delete(struct iface * iface,struct ncp * ncp,const struct ncpaddr * del)59530949fd4SBrian Somers iface_Delete(struct iface *iface, struct ncp *ncp, const struct ncpaddr *del)
5968fa6ebe4SBrian Somers {
59730949fd4SBrian Somers struct ncpaddr found;
598057f1760SBrian Somers unsigned n;
599057f1760SBrian Somers int res, s;
6008fa6ebe4SBrian Somers
60130949fd4SBrian Somers if ((s = ID0socket(ncpaddr_family(del), SOCK_DGRAM, 0)) == -1) {
60230949fd4SBrian Somers log_Printf(LogERROR, "iface_Delete: socket(): %s\n", strerror(errno));
60330949fd4SBrian Somers return 0;
6048fa6ebe4SBrian Somers }
6058fa6ebe4SBrian Somers
60630949fd4SBrian Somers for (n = res = 0; n < iface->addrs; n++) {
60730949fd4SBrian Somers ncprange_getaddr(&iface->addr[n].ifa, &found);
60830949fd4SBrian Somers if (ncpaddr_equal(&found, del)) {
609add3c041SBrian Somers if (iface_addr_Zap(iface->name, iface->addr + n, s)) {
61030949fd4SBrian Somers ncp_IfaceAddrDeleted(ncp, iface->addr + n);
61130949fd4SBrian Somers bcopy(iface->addr + n + 1, iface->addr + n,
61230949fd4SBrian Somers (iface->addrs - n - 1) * sizeof *iface->addr);
61330949fd4SBrian Somers iface->addrs--;
61430949fd4SBrian Somers res = 1;
615add3c041SBrian Somers }
61630949fd4SBrian Somers break;
61730949fd4SBrian Somers }
61830949fd4SBrian Somers }
61930949fd4SBrian Somers
62030949fd4SBrian Somers close(s);
62130949fd4SBrian Somers
62230949fd4SBrian Somers return res;
6238fa6ebe4SBrian Somers }
6248fa6ebe4SBrian Somers
6254e5196e9SBrian Somers #define IFACE_ADDFLAGS 1
6264e5196e9SBrian Somers #define IFACE_DELFLAGS 2
6274e5196e9SBrian Somers
6284e5196e9SBrian Somers static int
iface_ChangeFlags(const char * ifname,int flags,int how)629dc744e19SBrian Somers iface_ChangeFlags(const char *ifname, int flags, int how)
6304e5196e9SBrian Somers {
6314e5196e9SBrian Somers struct ifreq ifrq;
63288202a1fSMaxim Sobolev int s, new_flags;
6334e5196e9SBrian Somers
63463c6cac9SBrian Somers s = ID0socket(PF_INET, SOCK_DGRAM, 0);
6354e5196e9SBrian Somers if (s < 0) {
63653dc037cSBrian Somers log_Printf(LogERROR, "iface_ChangeFlags: socket: %s\n", strerror(errno));
6374e5196e9SBrian Somers return 0;
6384e5196e9SBrian Somers }
6394e5196e9SBrian Somers
6404e5196e9SBrian Somers memset(&ifrq, '\0', sizeof ifrq);
641dc744e19SBrian Somers strncpy(ifrq.ifr_name, ifname, sizeof ifrq.ifr_name - 1);
6424e5196e9SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
6434e5196e9SBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
64453dc037cSBrian Somers log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n",
6454e5196e9SBrian Somers strerror(errno));
6464e5196e9SBrian Somers close(s);
6474e5196e9SBrian Somers return 0;
6484e5196e9SBrian Somers }
64950be714bSBrian Somers #ifdef __FreeBSD__
65088202a1fSMaxim Sobolev new_flags = (ifrq.ifr_flags & 0xffff) | (ifrq.ifr_flagshigh << 16);
65150be714bSBrian Somers #else
65250be714bSBrian Somers new_flags = ifrq.ifr_flags & 0xffff;
65350be714bSBrian Somers #endif
6544e5196e9SBrian Somers
6554e5196e9SBrian Somers if (how == IFACE_ADDFLAGS)
65688202a1fSMaxim Sobolev new_flags |= flags;
6574e5196e9SBrian Somers else
65888202a1fSMaxim Sobolev new_flags &= ~flags;
65988202a1fSMaxim Sobolev ifrq.ifr_flags = new_flags & 0xffff;
66050be714bSBrian Somers #ifdef __FreeBSD__
66188202a1fSMaxim Sobolev ifrq.ifr_flagshigh = new_flags >> 16;
66250be714bSBrian Somers #endif
6634e5196e9SBrian Somers
6644e5196e9SBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
66553dc037cSBrian Somers log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n",
6664e5196e9SBrian Somers strerror(errno));
6674e5196e9SBrian Somers close(s);
6684e5196e9SBrian Somers return 0;
6694e5196e9SBrian Somers }
6704e5196e9SBrian Somers close(s);
6714e5196e9SBrian Somers
6724e5196e9SBrian Somers return 1; /* Success */
6734e5196e9SBrian Somers }
6744e5196e9SBrian Somers
6754e5196e9SBrian Somers int
iface_SetFlags(const char * ifname,int flags)676dc744e19SBrian Somers iface_SetFlags(const char *ifname, int flags)
6774e5196e9SBrian Somers {
678dc744e19SBrian Somers return iface_ChangeFlags(ifname, flags, IFACE_ADDFLAGS);
6794e5196e9SBrian Somers }
6804e5196e9SBrian Somers
6814e5196e9SBrian Somers int
iface_ClearFlags(const char * ifname,int flags)682dc744e19SBrian Somers iface_ClearFlags(const char *ifname, int flags)
6834e5196e9SBrian Somers {
684dc744e19SBrian Somers return iface_ChangeFlags(ifname, flags, IFACE_DELFLAGS);
6854e5196e9SBrian Somers }
6864e5196e9SBrian Somers
6878fa6ebe4SBrian Somers void
iface_Free(struct iface * iface)688f2f5156fSBrian Somers iface_Free(struct iface *iface)
6898fa6ebe4SBrian Somers {
6908fa6ebe4SBrian Somers free(iface->name);
691f2f5156fSBrian Somers free(iface->descr);
69230949fd4SBrian Somers free(iface->addr);
6938fa6ebe4SBrian Somers free(iface);
6948fa6ebe4SBrian Somers }
695f2f5156fSBrian Somers
696f2f5156fSBrian Somers void
iface_Destroy(struct iface * iface)697f2f5156fSBrian Somers iface_Destroy(struct iface *iface)
698f2f5156fSBrian Somers {
699f2f5156fSBrian Somers struct ifreq ifr;
700f2f5156fSBrian Somers int s;
701f2f5156fSBrian Somers
702f2f5156fSBrian Somers if (iface != NULL) {
703f2f5156fSBrian Somers if ((s = ID0socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
704f2f5156fSBrian Somers log_Printf(LogERROR, "iface_Destroy: socket(): %s\n", strerror(errno));
705f2f5156fSBrian Somers } else {
706f2f5156fSBrian Somers strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name));
707f2f5156fSBrian Somers if (ID0ioctl(s, SIOCIFDESTROY, (caddr_t)&ifr) < 0)
708f2f5156fSBrian Somers log_Printf(LogWARN, "iface_Destroy: ioctl(SIOCIFDESTROY, %s): %s\n",
709f2f5156fSBrian Somers iface->name, strerror(errno));
710f2f5156fSBrian Somers }
711f2f5156fSBrian Somers iface_Free(iface);
712f2f5156fSBrian Somers }
7138fa6ebe4SBrian Somers }
7148fa6ebe4SBrian Somers
7158fa6ebe4SBrian Somers #define if_entry(x) { IFF_##x, #x }
7168fa6ebe4SBrian Somers
7178fa6ebe4SBrian Somers struct {
7188fa6ebe4SBrian Somers int flag;
7198fa6ebe4SBrian Somers const char *value;
7208fa6ebe4SBrian Somers } if_flags[] = {
7218fa6ebe4SBrian Somers if_entry(UP),
7228fa6ebe4SBrian Somers if_entry(BROADCAST),
7238fa6ebe4SBrian Somers if_entry(DEBUG),
7248fa6ebe4SBrian Somers if_entry(LOOPBACK),
7258fa6ebe4SBrian Somers if_entry(POINTOPOINT),
7268fa6ebe4SBrian Somers if_entry(RUNNING),
7278fa6ebe4SBrian Somers if_entry(NOARP),
7288fa6ebe4SBrian Somers if_entry(PROMISC),
7298fa6ebe4SBrian Somers if_entry(ALLMULTI),
7308fa6ebe4SBrian Somers if_entry(OACTIVE),
7318fa6ebe4SBrian Somers if_entry(SIMPLEX),
7328fa6ebe4SBrian Somers if_entry(LINK0),
7338fa6ebe4SBrian Somers if_entry(LINK1),
7348fa6ebe4SBrian Somers if_entry(LINK2),
7358fa6ebe4SBrian Somers if_entry(MULTICAST),
7368fa6ebe4SBrian Somers { 0, "???" }
7378fa6ebe4SBrian Somers };
7388fa6ebe4SBrian Somers
7398fa6ebe4SBrian Somers int
iface_Show(struct cmdargs const * arg)7408fa6ebe4SBrian Somers iface_Show(struct cmdargs const *arg)
7418fa6ebe4SBrian Somers {
74230949fd4SBrian Somers struct ncpaddr ncpaddr;
7438fa6ebe4SBrian Somers struct iface *iface = arg->bundle->iface, *current;
744057f1760SBrian Somers unsigned f;
745057f1760SBrian Somers int flags;
74630949fd4SBrian Somers #ifndef NOINET6
74730949fd4SBrian Somers int scopeid, width;
74830949fd4SBrian Somers #endif
74930949fd4SBrian Somers struct in_addr mask;
7508fa6ebe4SBrian Somers
7518fa6ebe4SBrian Somers current = iface_Create(iface->name);
7528fa6ebe4SBrian Somers flags = iface->flags = current->flags;
753f2f5156fSBrian Somers iface_Free(current);
7548fa6ebe4SBrian Somers
7558fa6ebe4SBrian Somers prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
7568fa6ebe4SBrian Somers for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
757ebdcbc67SBrian Somers if ((if_flags[f].flag & flags)) {
7588fa6ebe4SBrian Somers prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
7598fa6ebe4SBrian Somers if_flags[f].value);
7608fa6ebe4SBrian Somers flags &= ~if_flags[f].flag;
7618fa6ebe4SBrian Somers }
762ebdcbc67SBrian Somers
763ebdcbc67SBrian Somers #if 0
764ebdcbc67SBrian Somers if (flags)
765ebdcbc67SBrian Somers prompt_Printf(arg->prompt, "%s0x%x", flags == iface->flags ? "" : ",",
766ebdcbc67SBrian Somers flags);
767ebdcbc67SBrian Somers #endif
768ebdcbc67SBrian Somers
769057f1760SBrian Somers prompt_Printf(arg->prompt, "> mtu %lu has %d address%s:\n", iface->mtu,
77030949fd4SBrian Somers iface->addrs, iface->addrs == 1 ? "" : "es");
7718fa6ebe4SBrian Somers
77230949fd4SBrian Somers for (f = 0; f < iface->addrs; f++) {
77330949fd4SBrian Somers ncprange_getaddr(&iface->addr[f].ifa, &ncpaddr);
77430949fd4SBrian Somers switch (ncprange_family(&iface->addr[f].ifa)) {
77530949fd4SBrian Somers case AF_INET:
77630949fd4SBrian Somers prompt_Printf(arg->prompt, " inet %s --> ", ncpaddr_ntoa(&ncpaddr));
77730949fd4SBrian Somers if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
77830949fd4SBrian Somers prompt_Printf(arg->prompt, "255.255.255.255");
77930949fd4SBrian Somers else
78030949fd4SBrian Somers prompt_Printf(arg->prompt, "%s", ncpaddr_ntoa(&iface->addr[f].peer));
78130949fd4SBrian Somers ncprange_getip4mask(&iface->addr[f].ifa, &mask);
78230949fd4SBrian Somers prompt_Printf(arg->prompt, " netmask 0x%08lx", (long)ntohl(mask.s_addr));
78330949fd4SBrian Somers break;
78430949fd4SBrian Somers
78530949fd4SBrian Somers #ifndef NOINET6
78630949fd4SBrian Somers case AF_INET6:
78730949fd4SBrian Somers prompt_Printf(arg->prompt, " inet6 %s", ncpaddr_ntoa(&ncpaddr));
78830949fd4SBrian Somers if (ncpaddr_family(&iface->addr[f].peer) != AF_UNSPEC)
78930949fd4SBrian Somers prompt_Printf(arg->prompt, " --> %s",
79030949fd4SBrian Somers ncpaddr_ntoa(&iface->addr[f].peer));
79130949fd4SBrian Somers ncprange_getwidth(&iface->addr[f].ifa, &width);
792a8862471SBrian Somers if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
79330949fd4SBrian Somers prompt_Printf(arg->prompt, " prefixlen %d", width);
79430949fd4SBrian Somers if ((scopeid = ncprange_scopeid(&iface->addr[f].ifa)) != -1)
79530949fd4SBrian Somers prompt_Printf(arg->prompt, " scopeid 0x%x", (unsigned)scopeid);
79630949fd4SBrian Somers break;
79730949fd4SBrian Somers #endif
79830949fd4SBrian Somers }
7998fa6ebe4SBrian Somers prompt_Printf(arg->prompt, "\n");
8008fa6ebe4SBrian Somers }
8018fa6ebe4SBrian Somers
8028fa6ebe4SBrian Somers return 0;
8038fa6ebe4SBrian Somers }
8046b457978SBrian Somers
8056b457978SBrian Somers void
iface_ParseHdr(struct ifa_msghdr * ifam,struct sockaddr * sa[RTAX_MAX])8066b457978SBrian Somers iface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX])
8076b457978SBrian Somers {
8086b457978SBrian Somers char *wp;
8096b457978SBrian Somers int rtax;
8106b457978SBrian Somers
8116b457978SBrian Somers wp = (char *)(ifam + 1);
8126b457978SBrian Somers
8136b457978SBrian Somers for (rtax = 0; rtax < RTAX_MAX; rtax++)
8146b457978SBrian Somers if (ifam->ifam_addrs & (1 << rtax)) {
8156b457978SBrian Somers sa[rtax] = (struct sockaddr *)wp;
8166b457978SBrian Somers wp += ROUNDUP(sa[rtax]->sa_len);
8176b457978SBrian Somers } else
8186b457978SBrian Somers sa[rtax] = NULL;
8196b457978SBrian Somers }
820