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