ca4d373730
network interfaces. This works by pre-computing the pseudo-header checksum and caching it, delaying the actual checksum to ip_output() if the hardware cannot perform the sum for us. In-bound checksums can either be fully-checked by hardware, or summed up for final verification by software. This method was modeled after how this is done in FreeBSD, although the code is significantly different in most places. We don't delay checksums for IPv6/TCP, but we do take advantage of the cached pseudo-header checksum. Note: hardware-assisted checksumming defaults to "off". It is enabled with ifconfig(8). See the manual page for details. Implement hardware-assisted checksumming on the DP83820 Gigabit Ethernet, 3c90xB/3c90xC 10/100 Ethernet, and Alteon Tigon/Tigon2 Gigabit Ethernet.
2803 lines
66 KiB
C
2803 lines
66 KiB
C
/* $NetBSD: ifconfig.c,v 1.108 2001/06/02 16:17:06 thorpej Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
|
|
* NASA Ames Research Center.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the NetBSD
|
|
* Foundation, Inc. and its contributors.
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 1983, 1993
|
|
* The Regents of the University of California. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by the University of
|
|
* California, Berkeley and its contributors.
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#ifndef lint
|
|
__COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
|
|
The Regents of the University of California. All rights reserved.\n");
|
|
#endif /* not lint */
|
|
|
|
#ifndef lint
|
|
#if 0
|
|
static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
|
|
#else
|
|
__RCSID("$NetBSD: ifconfig.c,v 1.108 2001/06/02 16:17:06 thorpej Exp $");
|
|
#endif
|
|
#endif /* not lint */
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <net/if.h>
|
|
#include <net/if_dl.h>
|
|
#include <net/if_media.h>
|
|
#include <net/if_ether.h>
|
|
#include <net/if_ieee80211.h>
|
|
#include <net/if_vlanvar.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/in_var.h>
|
|
#ifdef INET6
|
|
#include <netinet6/nd6.h>
|
|
#endif
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netatalk/at.h>
|
|
|
|
#define NSIP
|
|
#include <netns/ns.h>
|
|
#include <netns/ns_if.h>
|
|
#include <netdb.h>
|
|
|
|
#define EON
|
|
#include <netiso/iso.h>
|
|
#include <netiso/iso_var.h>
|
|
#include <sys/protosw.h>
|
|
|
|
#include <ctype.h>
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <ifaddrs.h>
|
|
|
|
struct ifreq ifr, ridreq;
|
|
struct ifaliasreq addreq __attribute__((aligned(4)));
|
|
#ifdef INET6
|
|
struct in6_ifreq ifr6;
|
|
struct in6_ifreq in6_ridreq;
|
|
struct in6_aliasreq in6_addreq __attribute__((aligned(4)));
|
|
#endif
|
|
struct iso_ifreq iso_ridreq;
|
|
struct iso_aliasreq iso_addreq;
|
|
struct sockaddr_in netmask;
|
|
struct netrange at_nr; /* AppleTalk net range */
|
|
|
|
char name[30];
|
|
int flags, metric, mtu, setaddr, setipdst, doalias;
|
|
int clearaddr, s;
|
|
int newaddr = -1;
|
|
int nsellength = 1;
|
|
int af;
|
|
int aflag, bflag, Cflag, dflag, lflag, mflag, sflag, uflag;
|
|
#ifdef INET6
|
|
int Lflag;
|
|
#endif
|
|
int reset_if_flags;
|
|
int explicit_prefix = 0;
|
|
u_int vlan_tag = (u_int)-1;
|
|
|
|
struct ifcapreq g_ifcr;
|
|
int g_ifcr_updated;
|
|
|
|
void notealias __P((const char *, int));
|
|
void notrailers __P((const char *, int));
|
|
void setifaddr __P((const char *, int));
|
|
void setifdstaddr __P((const char *, int));
|
|
void setifflags __P((const char *, int));
|
|
void setifcaps __P((const char *, int));
|
|
void setifbroadaddr __P((const char *, int));
|
|
void setifipdst __P((const char *, int));
|
|
void setifmetric __P((const char *, int));
|
|
void setifmtu __P((const char *, int));
|
|
void setifnwid __P((const char *, int));
|
|
void setifnwkey __P((const char *, int));
|
|
void setifpowersave __P((const char *, int));
|
|
void setifpowersavesleep __P((const char *, int));
|
|
void setifnetmask __P((const char *, int));
|
|
void setifprefixlen __P((const char *, int));
|
|
void setnsellength __P((const char *, int));
|
|
void setsnpaoffset __P((const char *, int));
|
|
void setatrange __P((const char *, int));
|
|
void setatphase __P((const char *, int));
|
|
void settunnel __P((const char *, const char *));
|
|
void deletetunnel __P((const char *, int));
|
|
#ifdef INET6
|
|
void setia6flags __P((const char *, int));
|
|
void setia6pltime __P((const char *, int));
|
|
void setia6vltime __P((const char *, int));
|
|
void setia6lifetime __P((const char *, const char *));
|
|
#endif
|
|
void checkatrange __P ((struct sockaddr_at *));
|
|
void setmedia __P((const char *, int));
|
|
void setmediaopt __P((const char *, int));
|
|
void unsetmediaopt __P((const char *, int));
|
|
void setmediainst __P((const char *, int));
|
|
void clone_create __P((const char *, int));
|
|
void clone_destroy __P((const char *, int));
|
|
void fixnsel __P((struct sockaddr_iso *));
|
|
void setvlan __P((const char *, int));
|
|
void setvlanif __P((const char *, int));
|
|
void unsetvlanif __P((const char *, int));
|
|
int main __P((int, char *[]));
|
|
|
|
/*
|
|
* Media stuff. Whenever a media command is first performed, the
|
|
* currently select media is grabbed for this interface. If `media'
|
|
* is given, the current media word is modifed. `mediaopt' commands
|
|
* only modify the set and clear words. They then operate on the
|
|
* current media word later.
|
|
*/
|
|
int media_current;
|
|
int mediaopt_set;
|
|
int mediaopt_clear;
|
|
|
|
int actions; /* Actions performed */
|
|
|
|
#define A_MEDIA 0x0001 /* media command */
|
|
#define A_MEDIAOPTSET 0x0002 /* mediaopt command */
|
|
#define A_MEDIAOPTCLR 0x0004 /* -mediaopt command */
|
|
#define A_MEDIAOPT (A_MEDIAOPTSET|A_MEDIAOPTCLR)
|
|
#define A_MEDIAINST 0x0008 /* instance or inst command */
|
|
|
|
#define NEXTARG 0xffffff
|
|
#define NEXTARG2 0xfffffe
|
|
|
|
const struct cmd {
|
|
const char *c_name;
|
|
int c_parameter; /* NEXTARG means next argv */
|
|
int c_action; /* defered action */
|
|
void (*c_func) __P((const char *, int));
|
|
void (*c_func2) __P((const char *, const char *));
|
|
} cmds[] = {
|
|
{ "up", IFF_UP, 0, setifflags } ,
|
|
{ "down", -IFF_UP, 0, setifflags },
|
|
{ "trailers", -1, 0, notrailers },
|
|
{ "-trailers", 1, 0, notrailers },
|
|
{ "arp", -IFF_NOARP, 0, setifflags },
|
|
{ "-arp", IFF_NOARP, 0, setifflags },
|
|
{ "debug", IFF_DEBUG, 0, setifflags },
|
|
{ "-debug", -IFF_DEBUG, 0, setifflags },
|
|
{ "alias", IFF_UP, 0, notealias },
|
|
{ "-alias", -IFF_UP, 0, notealias },
|
|
{ "delete", -IFF_UP, 0, notealias },
|
|
#ifdef notdef
|
|
#define EN_SWABIPS 0x1000
|
|
{ "swabips", EN_SWABIPS, 0, setifflags },
|
|
{ "-swabips", -EN_SWABIPS, 0, setifflags },
|
|
#endif
|
|
{ "netmask", NEXTARG, 0, setifnetmask },
|
|
{ "metric", NEXTARG, 0, setifmetric },
|
|
{ "mtu", NEXTARG, 0, setifmtu },
|
|
{ "nwid", NEXTARG, 0, setifnwid },
|
|
{ "nwkey", NEXTARG, 0, setifnwkey },
|
|
{ "-nwkey", -1, 0, setifnwkey },
|
|
{ "powersave", 1, 0, setifpowersave },
|
|
{ "-powersave", 0, 0, setifpowersave },
|
|
{ "powersavesleep", NEXTARG, 0, setifpowersavesleep },
|
|
{ "broadcast", NEXTARG, 0, setifbroadaddr },
|
|
{ "ipdst", NEXTARG, 0, setifipdst },
|
|
{ "prefixlen", NEXTARG, 0, setifprefixlen},
|
|
#ifdef INET6
|
|
{ "anycast", IN6_IFF_ANYCAST, 0, setia6flags },
|
|
{ "-anycast", -IN6_IFF_ANYCAST, 0, setia6flags },
|
|
{ "tentative", IN6_IFF_TENTATIVE, 0, setia6flags },
|
|
{ "-tentative", -IN6_IFF_TENTATIVE, 0, setia6flags },
|
|
{ "deprecated", IN6_IFF_DEPRECATED, 0, setia6flags },
|
|
{ "-deprecated", -IN6_IFF_DEPRECATED, 0, setia6flags },
|
|
{ "pltime", NEXTARG, 0, setia6pltime },
|
|
{ "vltime", NEXTARG, 0, setia6vltime },
|
|
#endif /*INET6*/
|
|
#ifndef INET_ONLY
|
|
{ "range", NEXTARG, 0, setatrange },
|
|
{ "phase", NEXTARG, 0, setatphase },
|
|
{ "snpaoffset", NEXTARG, 0, setsnpaoffset },
|
|
{ "nsellength", NEXTARG, 0, setnsellength },
|
|
#endif /* INET_ONLY */
|
|
{ "tunnel", NEXTARG2, 0, NULL,
|
|
settunnel } ,
|
|
{ "deletetunnel", 0, 0, deletetunnel },
|
|
{ "vlan", NEXTARG, 0, setvlan } ,
|
|
{ "vlanif", NEXTARG, 0, setvlanif } ,
|
|
{ "-vlanif", 0, 0, unsetvlanif } ,
|
|
{ "deletetunnel", 0, 0, deletetunnel },
|
|
#if 0
|
|
/* XXX `create' special-cased below */
|
|
{ "create", 0, 0, clone_create } ,
|
|
#endif
|
|
{ "destroy", 0, 0, clone_destroy } ,
|
|
{ "link0", IFF_LINK0, 0, setifflags } ,
|
|
{ "-link0", -IFF_LINK0, 0, setifflags } ,
|
|
{ "link1", IFF_LINK1, 0, setifflags } ,
|
|
{ "-link1", -IFF_LINK1, 0, setifflags } ,
|
|
{ "link2", IFF_LINK2, 0, setifflags } ,
|
|
{ "-link2", -IFF_LINK2, 0, setifflags } ,
|
|
{ "media", NEXTARG, A_MEDIA, setmedia },
|
|
{ "mediaopt", NEXTARG, A_MEDIAOPTSET, setmediaopt },
|
|
{ "-mediaopt", NEXTARG, A_MEDIAOPTCLR, unsetmediaopt },
|
|
{ "instance", NEXTARG, A_MEDIAINST, setmediainst },
|
|
{ "inst", NEXTARG, A_MEDIAINST, setmediainst },
|
|
{ "ip4csum", IFCAP_CSUM_IPv4,0, setifcaps },
|
|
{ "-ip4csum", -IFCAP_CSUM_IPv4,0, setifcaps },
|
|
{ "tcp4csum", IFCAP_CSUM_TCPv4,0, setifcaps },
|
|
{ "-tcp4csum", -IFCAP_CSUM_TCPv4,0, setifcaps },
|
|
{ "udp4csum", IFCAP_CSUM_UDPv4,0, setifcaps },
|
|
{ "-udp4csum", -IFCAP_CSUM_UDPv4,0, setifcaps },
|
|
{ "tcp6csum", IFCAP_CSUM_TCPv6,0, setifcaps },
|
|
{ "-tcp6csum", -IFCAP_CSUM_TCPv6,0, setifcaps },
|
|
{ "udp6csum", IFCAP_CSUM_UDPv6,0, setifcaps },
|
|
{ "-udp6csum", -IFCAP_CSUM_UDPv6,0, setifcaps },
|
|
{ 0, 0, 0, setifaddr },
|
|
{ 0, 0, 0, setifdstaddr },
|
|
};
|
|
|
|
void adjust_nsellength __P((void));
|
|
int getinfo __P((struct ifreq *));
|
|
int carrier __P((void));
|
|
void getsock __P((int));
|
|
void printall __P((const char *));
|
|
void list_cloners __P((void));
|
|
void printb __P((const char *, unsigned short, const char *));
|
|
int prefix __P((void *, int));
|
|
void status __P((const u_int8_t *, int));
|
|
void usage __P((void));
|
|
const char *get_string __P((const char *, const char *, u_int8_t *, int *));
|
|
void print_string __P((const u_int8_t *, int));
|
|
char *sec2str __P((time_t));
|
|
|
|
const char *get_media_type_string __P((int));
|
|
const char *get_media_subtype_string __P((int));
|
|
int get_media_subtype __P((int, const char *));
|
|
int get_media_options __P((int, const char *));
|
|
int lookup_media_word __P((struct ifmedia_description *, int,
|
|
const char *));
|
|
void print_media_word __P((int, int, int));
|
|
void process_media_commands __P((void));
|
|
void init_current_media __P((void));
|
|
|
|
/*
|
|
* XNS support liberally adapted from code written at the University of
|
|
* Maryland principally by James O'Toole and Chris Torek.
|
|
*/
|
|
void in_alias __P((struct ifreq *));
|
|
void in_status __P((int));
|
|
void in_getaddr __P((const char *, int));
|
|
void in_getprefix __P((const char *, int));
|
|
#ifdef INET6
|
|
void in6_fillscopeid __P((struct sockaddr_in6 *sin6));
|
|
void in6_alias __P((struct in6_ifreq *));
|
|
void in6_status __P((int));
|
|
void in6_getaddr __P((const char *, int));
|
|
void in6_getprefix __P((const char *, int));
|
|
#endif
|
|
void at_status __P((int));
|
|
void at_getaddr __P((const char *, int));
|
|
void xns_status __P((int));
|
|
void xns_getaddr __P((const char *, int));
|
|
void iso_status __P((int));
|
|
void iso_getaddr __P((const char *, int));
|
|
|
|
void ieee80211_status __P((void));
|
|
void tunnel_status __P((void));
|
|
void vlan_status __P((void));
|
|
|
|
/* Known address families */
|
|
struct afswtch {
|
|
const char *af_name;
|
|
short af_af;
|
|
void (*af_status) __P((int));
|
|
void (*af_getaddr) __P((const char *, int));
|
|
void (*af_getprefix) __P((const char *, int));
|
|
u_long af_difaddr;
|
|
u_long af_aifaddr;
|
|
u_long af_gifaddr;
|
|
caddr_t af_ridreq;
|
|
caddr_t af_addreq;
|
|
} afs[] = {
|
|
#define C(x) ((caddr_t) &x)
|
|
{ "inet", AF_INET, in_status, in_getaddr, in_getprefix,
|
|
SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, C(ridreq), C(addreq) },
|
|
#ifdef INET6
|
|
{ "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix,
|
|
SIOCDIFADDR_IN6, SIOCAIFADDR_IN6,
|
|
/*
|
|
* Deleting the first address before setting new one is
|
|
* not prefered way in this protocol.
|
|
*/
|
|
0,
|
|
C(in6_ridreq), C(in6_addreq) },
|
|
#endif
|
|
#ifndef INET_ONLY /* small version, for boot media */
|
|
{ "atalk", AF_APPLETALK, at_status, at_getaddr, NULL,
|
|
SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, C(addreq), C(addreq) },
|
|
{ "ns", AF_NS, xns_status, xns_getaddr, NULL,
|
|
SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, C(ridreq), C(addreq) },
|
|
{ "iso", AF_ISO, iso_status, iso_getaddr, NULL,
|
|
SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, SIOCGIFADDR_ISO,
|
|
C(iso_ridreq), C(iso_addreq) },
|
|
#endif /* INET_ONLY */
|
|
{ 0, 0, 0, 0 }
|
|
};
|
|
|
|
struct afswtch *afp; /*the address family being set or asked about*/
|
|
|
|
struct afswtch *lookup_af __P((const char *));
|
|
|
|
int
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
struct ifreq ifreq;
|
|
int ch;
|
|
|
|
/* Parse command-line options */
|
|
aflag = mflag = 0;
|
|
while ((ch = getopt(argc, argv, "AabCdlmsu"
|
|
#ifdef INET6
|
|
"L"
|
|
#endif
|
|
)) != -1) {
|
|
switch (ch) {
|
|
case 'A':
|
|
warnx("-A is deprecated");
|
|
break;
|
|
|
|
case 'a':
|
|
aflag = 1;
|
|
break;
|
|
|
|
case 'b':
|
|
bflag = 1;
|
|
break;
|
|
|
|
|
|
case 'C':
|
|
Cflag = 1;
|
|
break;
|
|
|
|
case 'd':
|
|
dflag = 1;
|
|
break;
|
|
|
|
#ifdef INET6
|
|
case 'L':
|
|
Lflag = 1;
|
|
break;
|
|
#endif
|
|
|
|
case 'l':
|
|
lflag = 1;
|
|
break;
|
|
|
|
case 'm':
|
|
mflag = 1;
|
|
break;
|
|
|
|
case 's':
|
|
sflag = 1;
|
|
break;
|
|
|
|
case 'u':
|
|
uflag = 1;
|
|
break;
|
|
|
|
|
|
default:
|
|
usage();
|
|
/* NOTREACHED */
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
/*
|
|
* -l means "list all interfaces", and is mutally exclusive with
|
|
* all other flags/commands.
|
|
*
|
|
* -C means "list all names of cloners", and it mutually exclusive
|
|
* with all other flags/commands.
|
|
*
|
|
* -a means "print status of all interfaces".
|
|
*/
|
|
if ((lflag || Cflag) && (aflag || mflag || argc))
|
|
usage();
|
|
#ifdef INET6
|
|
if ((lflag || Cflag) && Lflag)
|
|
usage();
|
|
#endif
|
|
if (lflag && Cflag)
|
|
usage();
|
|
if (Cflag) {
|
|
if (argc)
|
|
usage();
|
|
list_cloners();
|
|
exit(0);
|
|
}
|
|
if (aflag || lflag) {
|
|
if (argc > 1)
|
|
usage();
|
|
else if (argc == 1) {
|
|
afp = lookup_af(argv[0]);
|
|
if (afp == NULL)
|
|
usage();
|
|
}
|
|
if (afp)
|
|
af = ifr.ifr_addr.sa_family = afp->af_af;
|
|
else
|
|
af = ifr.ifr_addr.sa_family = afs[0].af_af;
|
|
printall(NULL);
|
|
exit(0);
|
|
}
|
|
|
|
/* Make sure there's an interface name. */
|
|
if (argc < 1)
|
|
usage();
|
|
(void) strncpy(name, argv[0], sizeof(name));
|
|
argc--; argv++;
|
|
|
|
/*
|
|
* NOTE: We must special-case the `create' command right
|
|
* here as we would otherwise fail in getinfo().
|
|
*/
|
|
if (argc > 0 && strcmp(argv[0], "create") == 0) {
|
|
clone_create(argv[0], 0);
|
|
argc--, argv++;
|
|
if (argc == 0)
|
|
exit(0);
|
|
}
|
|
|
|
/* Check for address family. */
|
|
afp = NULL;
|
|
if (argc > 0) {
|
|
afp = lookup_af(argv[0]);
|
|
if (afp != NULL) {
|
|
argv++;
|
|
argc--;
|
|
}
|
|
}
|
|
|
|
/* Initialize af, just for use in getinfo(). */
|
|
if (afp == NULL)
|
|
af = afs->af_af;
|
|
else
|
|
af = afp->af_af;
|
|
|
|
/* Get information about the interface. */
|
|
(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
if (getinfo(&ifr) < 0)
|
|
exit(1);
|
|
|
|
if (sflag) {
|
|
if (argc != 0)
|
|
usage();
|
|
else
|
|
exit(carrier());
|
|
}
|
|
|
|
/* No more arguments means interface status. */
|
|
if (argc == 0) {
|
|
printall(name);
|
|
exit(0);
|
|
}
|
|
|
|
/* The following operations assume inet family as the default. */
|
|
if (afp == NULL)
|
|
afp = afs;
|
|
af = ifr.ifr_addr.sa_family = afp->af_af;
|
|
|
|
#ifdef INET6
|
|
/* initialization */
|
|
in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
|
|
in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
|
|
#endif
|
|
|
|
/* Process commands. */
|
|
while (argc > 0) {
|
|
const struct cmd *p;
|
|
|
|
for (p = cmds; p->c_name; p++)
|
|
if (strcmp(argv[0], p->c_name) == 0)
|
|
break;
|
|
if (p->c_name == 0 && setaddr) {
|
|
if ((flags & IFF_POINTOPOINT) == 0) {
|
|
errx(1, "can't set destination address %s",
|
|
"on non-point-to-point link");
|
|
}
|
|
p++; /* got src, do dst */
|
|
}
|
|
if (p->c_func != NULL || p->c_func2 != NULL) {
|
|
if (p->c_parameter == NEXTARG) {
|
|
if (argc < 2)
|
|
errx(1, "'%s' requires argument",
|
|
p->c_name);
|
|
(*p->c_func)(argv[1], 0);
|
|
argc--, argv++;
|
|
} else if (p->c_parameter == NEXTARG2) {
|
|
if (argc < 3)
|
|
errx(1, "'%s' requires 2 arguments",
|
|
p->c_name);
|
|
(*p->c_func2)(argv[1], argv[2]);
|
|
argc -= 2, argv += 2;
|
|
} else
|
|
(*p->c_func)(argv[0], p->c_parameter);
|
|
actions |= p->c_action;
|
|
}
|
|
argc--, argv++;
|
|
}
|
|
|
|
/* Process any media commands that may have been issued. */
|
|
process_media_commands();
|
|
|
|
if (af == AF_INET6 && explicit_prefix == 0) {
|
|
/*
|
|
* Aggregatable address architecture defines all prefixes
|
|
* are 64. So, it is convenient to set prefixlen to 64 if
|
|
* it is not specified.
|
|
*/
|
|
setifprefixlen("64", 0);
|
|
/* in6_getprefix("64", MASK) if MASK is available here... */
|
|
}
|
|
|
|
#ifndef INET_ONLY
|
|
if (af == AF_ISO)
|
|
adjust_nsellength();
|
|
|
|
if (af == AF_APPLETALK)
|
|
checkatrange((struct sockaddr_at *) &addreq.ifra_addr);
|
|
|
|
if (setipdst && af==AF_NS) {
|
|
struct nsip_req rq;
|
|
int size = sizeof(rq);
|
|
|
|
rq.rq_ns = addreq.ifra_addr;
|
|
rq.rq_ip = addreq.ifra_dstaddr;
|
|
|
|
if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
|
|
warn("encapsulation routing");
|
|
}
|
|
|
|
#endif /* INET_ONLY */
|
|
|
|
if (clearaddr) {
|
|
(void) strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
|
|
if (ioctl(s, afp->af_difaddr, afp->af_ridreq) < 0)
|
|
err(1, "SIOCDIFADDR");
|
|
}
|
|
if (newaddr > 0) {
|
|
(void) strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
|
|
if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
|
|
warn("SIOCAIFADDR");
|
|
}
|
|
|
|
if (g_ifcr_updated) {
|
|
(void) strncpy(g_ifcr.ifcr_name, name,
|
|
sizeof(g_ifcr.ifcr_name));
|
|
if (ioctl(s, SIOCSIFCAP, (caddr_t) &g_ifcr) < 0)
|
|
err(1, "SIOCSIFCAP");
|
|
}
|
|
|
|
if (reset_if_flags) {
|
|
(void) strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
|
|
ifreq.ifr_flags = flags;
|
|
if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) < 0)
|
|
err(1, "SIOCSIFFLAGS");
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
struct afswtch *
|
|
lookup_af(cp)
|
|
const char *cp;
|
|
{
|
|
struct afswtch *a;
|
|
|
|
for (a = afs; a->af_name != NULL; a++)
|
|
if (strcmp(a->af_name, cp) == 0)
|
|
return (a);
|
|
return (NULL);
|
|
}
|
|
|
|
void
|
|
getsock(naf)
|
|
int naf;
|
|
{
|
|
static int oaf = -1;
|
|
|
|
if (oaf == naf)
|
|
return;
|
|
if (oaf != -1)
|
|
close(s);
|
|
s = socket(naf, SOCK_DGRAM, 0);
|
|
if (s < 0)
|
|
oaf = -1;
|
|
else
|
|
oaf = naf;
|
|
}
|
|
|
|
int
|
|
getinfo(ifr)
|
|
struct ifreq *ifr;
|
|
{
|
|
|
|
getsock(af);
|
|
if (s < 0)
|
|
err(1, "socket");
|
|
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
|
|
warn("SIOCGIFFLAGS %s", ifr->ifr_name);
|
|
return (-1);
|
|
}
|
|
flags = ifr->ifr_flags;
|
|
if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0) {
|
|
warn("SIOCGIFMETRIC %s", ifr->ifr_name);
|
|
metric = 0;
|
|
} else
|
|
metric = ifr->ifr_metric;
|
|
if (ioctl(s, SIOCGIFMTU, (caddr_t)ifr) < 0)
|
|
mtu = 0;
|
|
else
|
|
mtu = ifr->ifr_mtu;
|
|
|
|
memset(&g_ifcr, 0, sizeof(g_ifcr));
|
|
strcpy(g_ifcr.ifcr_name, ifr->ifr_name);
|
|
(void) ioctl(s, SIOCGIFCAP, (caddr_t) &g_ifcr);
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
printall(ifname)
|
|
const char *ifname;
|
|
{
|
|
struct ifaddrs *ifap, *ifa;
|
|
struct ifreq ifr;
|
|
const struct sockaddr_dl *sdl = NULL;
|
|
int idx;
|
|
char *p;
|
|
|
|
if (getifaddrs(&ifap) != 0)
|
|
err(1, "getifaddrs");
|
|
p = NULL;
|
|
idx = 0;
|
|
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
|
|
if (sizeof(ifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
|
|
memcpy(&ifr.ifr_addr, ifa->ifa_addr,
|
|
ifa->ifa_addr->sa_len);
|
|
}
|
|
|
|
if (ifname && strcmp(ifname, ifa->ifa_name) != 0)
|
|
continue;
|
|
if (ifa->ifa_addr->sa_family == AF_LINK)
|
|
sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
|
|
if (p && strcmp(p, ifa->ifa_name) == 0)
|
|
continue;
|
|
(void) strncpy(name, ifa->ifa_name, sizeof(name));
|
|
name[sizeof(name) - 1] = '\0';
|
|
p = ifa->ifa_name;
|
|
|
|
if (getinfo(&ifr) < 0)
|
|
continue;
|
|
if (bflag && (ifa->ifa_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)))
|
|
continue;
|
|
if (dflag && (ifa->ifa_flags & IFF_UP) != 0)
|
|
continue;
|
|
if (uflag && (ifa->ifa_flags & IFF_UP) == 0)
|
|
continue;
|
|
|
|
if (sflag && carrier())
|
|
continue;
|
|
idx++;
|
|
/*
|
|
* Are we just listing the interfaces?
|
|
*/
|
|
if (lflag) {
|
|
if (idx > 1)
|
|
putchar(' ');
|
|
fputs(name, stdout);
|
|
continue;
|
|
}
|
|
|
|
if (sdl == NULL) {
|
|
status(NULL, 0);
|
|
} else {
|
|
status(LLADDR(sdl), sdl->sdl_alen);
|
|
sdl = NULL;
|
|
}
|
|
}
|
|
if (lflag)
|
|
putchar('\n');
|
|
freeifaddrs(ifap);
|
|
}
|
|
|
|
void
|
|
list_cloners(void)
|
|
{
|
|
struct if_clonereq ifcr;
|
|
char *cp, *buf;
|
|
int idx;
|
|
|
|
memset(&ifcr, 0, sizeof(ifcr));
|
|
|
|
getsock(AF_INET);
|
|
|
|
if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
|
|
err(1, "SIOCIFGCLONERS for count");
|
|
|
|
buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
|
|
if (buf == NULL)
|
|
err(1, "unable to allocate cloner name buffer");
|
|
|
|
ifcr.ifcr_count = ifcr.ifcr_total;
|
|
ifcr.ifcr_buffer = buf;
|
|
|
|
if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
|
|
err(1, "SIOCIFGCLONERS for names");
|
|
|
|
/*
|
|
* In case some disappeared in the mean time, clamp it down.
|
|
*/
|
|
if (ifcr.ifcr_count > ifcr.ifcr_total)
|
|
ifcr.ifcr_count = ifcr.ifcr_total;
|
|
|
|
for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
|
|
if (idx > 0)
|
|
putchar(' ');
|
|
printf("%s", cp);
|
|
}
|
|
|
|
putchar('\n');
|
|
free(buf);
|
|
return;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
clone_create(addr, param)
|
|
const char *addr;
|
|
int param;
|
|
{
|
|
|
|
/* We're called early... */
|
|
getsock(AF_INET);
|
|
|
|
(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
|
|
err(1, "SIOCIFCREATE");
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
clone_destroy(addr, param)
|
|
const char *addr;
|
|
int param;
|
|
{
|
|
|
|
(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
|
|
err(1, "SIOCIFDESTROY");
|
|
}
|
|
|
|
#define RIDADDR 0
|
|
#define ADDR 1
|
|
#define MASK 2
|
|
#define DSTADDR 3
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
setifaddr(addr, param)
|
|
const char *addr;
|
|
int param;
|
|
{
|
|
struct ifreq *ifr; /* XXX */
|
|
|
|
/*
|
|
* Delay the ioctl to set the interface addr until flags are all set.
|
|
* The address interpretation may depend on the flags,
|
|
* and the flags may change when the address is set.
|
|
*/
|
|
setaddr++;
|
|
if (newaddr == -1)
|
|
newaddr = 1;
|
|
if (doalias == 0 && afp->af_gifaddr != 0) {
|
|
ifr = (struct ifreq *)afp->af_ridreq;
|
|
(void) strncpy(ifr->ifr_name, name, sizeof(ifr->ifr_name));
|
|
ifr->ifr_addr.sa_family = afp->af_af;
|
|
if (ioctl(s, afp->af_gifaddr, afp->af_ridreq) == 0)
|
|
clearaddr = 1;
|
|
else if (errno == EADDRNOTAVAIL)
|
|
/* No address was assigned yet. */
|
|
;
|
|
else
|
|
err(1, "SIOCGIFADDR");
|
|
}
|
|
|
|
(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
|
|
}
|
|
|
|
void
|
|
settunnel(src, dst)
|
|
const char *src, *dst;
|
|
{
|
|
struct addrinfo hints, *srcres, *dstres;
|
|
int ecode;
|
|
struct if_laddrreq req;
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = afp->af_af;
|
|
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
|
|
|
|
if ((ecode = getaddrinfo(src, NULL, &hints, &srcres)) != 0)
|
|
errx(1, "error in parsing address string: %s",
|
|
gai_strerror(ecode));
|
|
|
|
if ((ecode = getaddrinfo(dst, NULL, &hints, &dstres)) != 0)
|
|
errx(1, "error in parsing address string: %s",
|
|
gai_strerror(ecode));
|
|
|
|
if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
|
|
errx(1,
|
|
"source and destination address families do not match");
|
|
|
|
if (srcres->ai_addrlen > sizeof(req.addr) ||
|
|
dstres->ai_addrlen > sizeof(req.dstaddr))
|
|
errx(1, "invalid sockaddr");
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
strncpy(req.iflr_name, name, sizeof(req.iflr_name));
|
|
memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen);
|
|
memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen);
|
|
if (ioctl(s, SIOCSLIFPHYADDR, &req) < 0)
|
|
warn("SIOCSLIFPHYADDR");
|
|
|
|
freeaddrinfo(srcres);
|
|
freeaddrinfo(dstres);
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
void
|
|
deletetunnel(vname, param)
|
|
const char *vname;
|
|
int param;
|
|
{
|
|
|
|
if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
|
|
err(1, "SIOCDIFPHYADDR");
|
|
}
|
|
|
|
void setvlan(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
struct vlanreq vlr;
|
|
|
|
if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
|
|
!isdigit(ifr.ifr_name[4]))
|
|
errx(EXIT_FAILURE,
|
|
"``vlan'' valid only with vlan(4) interfaces");
|
|
|
|
vlan_tag = atoi(val);
|
|
|
|
memset(&vlr, 0, sizeof(vlr));
|
|
ifr.ifr_data = (caddr_t)&vlr;
|
|
|
|
if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
|
|
err(EXIT_FAILURE, "SIOCGETVLAN");
|
|
|
|
vlr.vlr_tag = vlan_tag;
|
|
|
|
if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
|
|
err(EXIT_FAILURE, "SIOCSETVLAN");
|
|
}
|
|
|
|
void setvlanif(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
struct vlanreq vlr;
|
|
|
|
if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
|
|
!isdigit(ifr.ifr_name[4]))
|
|
errx(EXIT_FAILURE,
|
|
"``vlanif'' valid only with vlan(4) interfaces");
|
|
|
|
if (vlan_tag == (u_int)-1)
|
|
errx(EXIT_FAILURE,
|
|
"must specify both ``vlan'' and ``vlanif''");
|
|
|
|
memset(&vlr, 0, sizeof(vlr));
|
|
ifr.ifr_data = (caddr_t)&vlr;
|
|
|
|
if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
|
|
err(EXIT_FAILURE, "SIOCGETVLAN");
|
|
|
|
strlcpy(vlr.vlr_parent, val, sizeof(vlr.vlr_parent));
|
|
vlr.vlr_tag = vlan_tag;
|
|
|
|
if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
|
|
err(EXIT_FAILURE, "SIOCSETVLAN");
|
|
}
|
|
|
|
void unsetvlanif(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
struct vlanreq vlr;
|
|
|
|
if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
|
|
!isdigit(ifr.ifr_name[4]))
|
|
errx(EXIT_FAILURE,
|
|
"``vlanif'' valid only with vlan(4) interfaces");
|
|
|
|
memset(&vlr, 0, sizeof(vlr));
|
|
ifr.ifr_data = (caddr_t)&vlr;
|
|
|
|
if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
|
|
err(EXIT_FAILURE, "SIOCGETVLAN");
|
|
|
|
vlr.vlr_parent[0] = '\0';
|
|
vlr.vlr_tag = 0;
|
|
|
|
if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
|
|
err(EXIT_FAILURE, "SIOCSETVLAN");
|
|
}
|
|
|
|
void
|
|
setifnetmask(addr, d)
|
|
const char *addr;
|
|
int d;
|
|
{
|
|
(*afp->af_getaddr)(addr, MASK);
|
|
}
|
|
|
|
void
|
|
setifbroadaddr(addr, d)
|
|
const char *addr;
|
|
int d;
|
|
{
|
|
(*afp->af_getaddr)(addr, DSTADDR);
|
|
}
|
|
|
|
void
|
|
setifipdst(addr, d)
|
|
const char *addr;
|
|
int d;
|
|
{
|
|
in_getaddr(addr, DSTADDR);
|
|
setipdst++;
|
|
clearaddr = 0;
|
|
newaddr = 0;
|
|
}
|
|
|
|
#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
|
|
/*ARGSUSED*/
|
|
void
|
|
notealias(addr, param)
|
|
const char *addr;
|
|
int param;
|
|
{
|
|
if (setaddr && doalias == 0 && param < 0)
|
|
(void) memcpy(rqtosa(af_ridreq), rqtosa(af_addreq),
|
|
rqtosa(af_addreq)->sa_len);
|
|
doalias = param;
|
|
if (param < 0) {
|
|
clearaddr = 1;
|
|
newaddr = 0;
|
|
} else
|
|
clearaddr = 0;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
notrailers(vname, value)
|
|
const char *vname;
|
|
int value;
|
|
{
|
|
puts("Note: trailers are no longer sent, but always received");
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
setifdstaddr(addr, param)
|
|
const char *addr;
|
|
int param;
|
|
{
|
|
(*afp->af_getaddr)(addr, DSTADDR);
|
|
}
|
|
|
|
void
|
|
setifflags(vname, value)
|
|
const char *vname;
|
|
int value;
|
|
{
|
|
struct ifreq ifreq;
|
|
|
|
(void) strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
|
|
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifreq) < 0)
|
|
err(1, "SIOCGIFFLAGS");
|
|
flags = ifreq.ifr_flags;
|
|
|
|
if (value < 0) {
|
|
value = -value;
|
|
flags &= ~value;
|
|
} else
|
|
flags |= value;
|
|
ifreq.ifr_flags = flags;
|
|
if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) < 0)
|
|
err(1, "SIOCSIFFLAGS");
|
|
|
|
reset_if_flags = 1;
|
|
}
|
|
|
|
void
|
|
setifcaps(vname, value)
|
|
const char *vname;
|
|
int value;
|
|
{
|
|
|
|
if (value < 0) {
|
|
value = -value;
|
|
g_ifcr.ifcr_capenable &= ~value;
|
|
} else
|
|
g_ifcr.ifcr_capenable |= value;
|
|
|
|
g_ifcr_updated = 1;
|
|
}
|
|
|
|
#ifdef INET6
|
|
void
|
|
setia6flags(vname, value)
|
|
const char *vname;
|
|
int value;
|
|
{
|
|
if (value < 0) {
|
|
value = -value;
|
|
in6_addreq.ifra_flags &= ~value;
|
|
} else
|
|
in6_addreq.ifra_flags |= value;
|
|
}
|
|
|
|
void
|
|
setia6pltime(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
setia6lifetime("pltime", val);
|
|
}
|
|
|
|
void
|
|
setia6vltime(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
setia6lifetime("vltime", val);
|
|
}
|
|
|
|
void
|
|
setia6lifetime(cmd, val)
|
|
const char *cmd;
|
|
const char *val;
|
|
{
|
|
time_t newval, t;
|
|
char *ep;
|
|
|
|
t = time(NULL);
|
|
newval = (time_t)strtoul(val, &ep, 0);
|
|
if (val == ep)
|
|
errx(1, "invalid %s", cmd);
|
|
if (afp->af_af != AF_INET6)
|
|
errx(1, "%s not allowed for the AF", cmd);
|
|
if (strcmp(cmd, "vltime") == 0) {
|
|
in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
|
|
in6_addreq.ifra_lifetime.ia6t_vltime = newval;
|
|
} else if (strcmp(cmd, "pltime") == 0) {
|
|
in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
|
|
in6_addreq.ifra_lifetime.ia6t_pltime = newval;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void
|
|
setifmetric(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
|
|
ifr.ifr_metric = atoi(val);
|
|
if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
|
|
warn("SIOCSIFMETRIC");
|
|
}
|
|
|
|
void
|
|
setifmtu(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
ifr.ifr_mtu = atoi(val);
|
|
if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
|
|
warn("SIOCSIFMTU");
|
|
}
|
|
|
|
const char *
|
|
get_string(val, sep, buf, lenp)
|
|
const char *val, *sep;
|
|
u_int8_t *buf;
|
|
int *lenp;
|
|
{
|
|
int len;
|
|
int hexstr;
|
|
u_int8_t *p;
|
|
|
|
len = *lenp;
|
|
p = buf;
|
|
hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x');
|
|
if (hexstr)
|
|
val += 2;
|
|
for (;;) {
|
|
if (*val == '\0')
|
|
break;
|
|
if (sep != NULL && strchr(sep, *val) != NULL) {
|
|
val++;
|
|
break;
|
|
}
|
|
if (hexstr) {
|
|
if (!isxdigit((u_char)val[0]) ||
|
|
!isxdigit((u_char)val[1])) {
|
|
warnx("bad hexadecimal digits");
|
|
return NULL;
|
|
}
|
|
}
|
|
if (p > buf + len) {
|
|
if (hexstr)
|
|
warnx("hexadecimal digits too long");
|
|
else
|
|
warnx("strings too long");
|
|
return NULL;
|
|
}
|
|
if (hexstr) {
|
|
#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10)
|
|
*p++ = (tohex((u_char)val[0]) << 4) |
|
|
tohex((u_char)val[1]);
|
|
#undef tohex
|
|
val += 2;
|
|
} else
|
|
*p++ = *val++;
|
|
}
|
|
len = p - buf;
|
|
if (len < *lenp)
|
|
memset(p, 0, *lenp - len);
|
|
*lenp = len;
|
|
return val;
|
|
}
|
|
|
|
void
|
|
print_string(buf, len)
|
|
const u_int8_t *buf;
|
|
int len;
|
|
{
|
|
int i;
|
|
int hasspc;
|
|
|
|
i = 0;
|
|
hasspc = 0;
|
|
if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') {
|
|
for (; i < len; i++) {
|
|
if (!isprint(buf[i]))
|
|
break;
|
|
if (isspace(buf[i]))
|
|
hasspc++;
|
|
}
|
|
}
|
|
if (i == len) {
|
|
if (hasspc || len == 0)
|
|
printf("\"%.*s\"", len, buf);
|
|
else
|
|
printf("%.*s", len, buf);
|
|
} else {
|
|
printf("0x");
|
|
for (i = 0; i < len; i++)
|
|
printf("%02x", buf[i]);
|
|
}
|
|
}
|
|
|
|
void
|
|
setifnwid(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
struct ieee80211_nwid nwid;
|
|
int len;
|
|
|
|
len = sizeof(nwid.i_nwid);
|
|
if (get_string(val, NULL, nwid.i_nwid, &len) == NULL)
|
|
return;
|
|
nwid.i_len = len;
|
|
(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
ifr.ifr_data = (caddr_t)&nwid;
|
|
if (ioctl(s, SIOCS80211NWID, (caddr_t)&ifr) < 0)
|
|
warn("SIOCS80211NWID");
|
|
}
|
|
|
|
void
|
|
setifnwkey(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
struct ieee80211_nwkey nwkey;
|
|
int i;
|
|
u_int8_t keybuf[IEEE80211_WEP_NKID][16];
|
|
|
|
nwkey.i_wepon = 1;
|
|
nwkey.i_defkid = 1;
|
|
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
|
|
nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
|
|
nwkey.i_key[i].i_keydat = keybuf[i];
|
|
}
|
|
if (d != 0) {
|
|
/* disable WEP encryption */
|
|
nwkey.i_wepon = 0;
|
|
i = 0;
|
|
} else if (isdigit(val[0]) && val[1] == ':') {
|
|
/* specifying a full set of four keys */
|
|
nwkey.i_defkid = val[0] - '0';
|
|
val += 2;
|
|
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
|
|
val = get_string(val, ",", keybuf[i],
|
|
&nwkey.i_key[i].i_keylen);
|
|
if (val == NULL)
|
|
return;
|
|
}
|
|
if (*val != '\0') {
|
|
warnx("SIOCS80211NWKEY: too many keys.");
|
|
return;
|
|
}
|
|
} else {
|
|
val = get_string(val, NULL, keybuf[0],
|
|
&nwkey.i_key[0].i_keylen);
|
|
if (val == NULL)
|
|
return;
|
|
i = 1;
|
|
}
|
|
for (; i < IEEE80211_WEP_NKID; i++)
|
|
nwkey.i_key[i].i_keylen = 0;
|
|
(void)strncpy(nwkey.i_name, name, sizeof(nwkey.i_name));
|
|
if (ioctl(s, SIOCS80211NWKEY, (caddr_t)&nwkey) < 0)
|
|
warn("SIOCS80211NWKEY");
|
|
}
|
|
|
|
void
|
|
setifpowersave(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
struct ieee80211_power power;
|
|
|
|
(void)strncpy(power.i_name, name, sizeof(power.i_name));
|
|
if (ioctl(s, SIOCG80211POWER, (caddr_t)&power) < 0) {
|
|
warn("SIOCG80211POWER");
|
|
return;
|
|
}
|
|
|
|
power.i_enabled = d;
|
|
if (ioctl(s, SIOCS80211POWER, (caddr_t)&power) < 0)
|
|
warn("SIOCS80211POWER");
|
|
}
|
|
|
|
void
|
|
setifpowersavesleep(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
struct ieee80211_power power;
|
|
|
|
(void)strncpy(power.i_name, name, sizeof(power.i_name));
|
|
if (ioctl(s, SIOCG80211POWER, (caddr_t)&power) < 0) {
|
|
warn("SIOCG80211POWER");
|
|
return;
|
|
}
|
|
|
|
power.i_maxsleep = atoi(val);
|
|
if (ioctl(s, SIOCS80211POWER, (caddr_t)&power) < 0)
|
|
warn("SIOCS80211POWER");
|
|
}
|
|
|
|
void
|
|
ieee80211_status()
|
|
{
|
|
int i;
|
|
struct ieee80211_nwid nwid;
|
|
struct ieee80211_nwkey nwkey;
|
|
struct ieee80211_power power;
|
|
u_int8_t keybuf[IEEE80211_WEP_NKID][16];
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
ifr.ifr_data = (caddr_t)&nwid;
|
|
(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
if (ioctl(s, SIOCG80211NWID, (caddr_t)&ifr) != 0)
|
|
return;
|
|
if (nwid.i_len > IEEE80211_NWID_LEN) {
|
|
warnx("SIOCG80211NWID: wrong length of nwid (%d)", nwid.i_len);
|
|
return;
|
|
}
|
|
printf("\tnwid ");
|
|
print_string(nwid.i_nwid, nwid.i_len);
|
|
memset(&nwkey, 0, sizeof(nwkey));
|
|
(void)strncpy(nwkey.i_name, name, sizeof(nwkey.i_name));
|
|
/* show nwkey only when WEP is enabled */
|
|
if (ioctl(s, SIOCG80211NWKEY, (caddr_t)&nwkey) != 0 ||
|
|
nwkey.i_wepon == 0) {
|
|
printf("\n");
|
|
goto skip_wep;
|
|
}
|
|
|
|
printf(" nwkey ");
|
|
/* try to retrieve WEP keys */
|
|
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
|
|
nwkey.i_key[i].i_keydat = keybuf[i];
|
|
nwkey.i_key[i].i_keylen = sizeof(keybuf[i]);
|
|
}
|
|
if (ioctl(s, SIOCG80211NWKEY, (caddr_t)&nwkey) != 0) {
|
|
printf("*****");
|
|
} else {
|
|
if (nwkey.i_defkid != 1) {
|
|
/* non default key or multiple keys defined */
|
|
i = 0;
|
|
} else if (nwkey.i_key[0].i_keylen >= 2 &&
|
|
isdigit(nwkey.i_key[0].i_keydat[0]) &&
|
|
nwkey.i_key[0].i_keydat[1] == ':') {
|
|
/* ambiguous */
|
|
i = 0;
|
|
} else {
|
|
for (i = 1; i < IEEE80211_WEP_NKID; i++) {
|
|
if (nwkey.i_key[i].i_keylen != 0)
|
|
break;
|
|
}
|
|
}
|
|
if (i == IEEE80211_WEP_NKID) {
|
|
/* only show the first key */
|
|
print_string(nwkey.i_key[0].i_keydat,
|
|
nwkey.i_key[0].i_keylen);
|
|
} else {
|
|
printf("%d:", nwkey.i_defkid);
|
|
for (i = 0; i < IEEE80211_WEP_NKID; i++) {
|
|
if (i > 0)
|
|
printf(",");
|
|
print_string(nwkey.i_key[i].i_keydat,
|
|
nwkey.i_key[i].i_keylen);
|
|
}
|
|
}
|
|
}
|
|
printf("\n");
|
|
|
|
skip_wep:
|
|
(void)strncpy(power.i_name, name, sizeof(power.i_name));
|
|
if (ioctl(s, SIOCG80211POWER, &power) != 0)
|
|
return;
|
|
printf("\tpowersave ");
|
|
if (power.i_enabled)
|
|
printf("on (%dms sleep)", power.i_maxsleep);
|
|
else
|
|
printf("off");
|
|
printf("\n");
|
|
}
|
|
|
|
void
|
|
init_current_media()
|
|
{
|
|
struct ifmediareq ifmr;
|
|
|
|
/*
|
|
* If we have not yet done so, grab the currently-selected
|
|
* media.
|
|
*/
|
|
if ((actions & (A_MEDIA|A_MEDIAOPT)) == 0) {
|
|
(void) memset(&ifmr, 0, sizeof(ifmr));
|
|
(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
|
|
|
|
if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
|
|
/*
|
|
* If we get E2BIG, the kernel is telling us
|
|
* that there are more, so we can ignore it.
|
|
*/
|
|
if (errno != E2BIG)
|
|
err(1, "SGIOCGIFMEDIA");
|
|
}
|
|
|
|
media_current = ifmr.ifm_current;
|
|
}
|
|
|
|
/* Sanity. */
|
|
if (IFM_TYPE(media_current) == 0)
|
|
errx(1, "%s: no link type?", name);
|
|
}
|
|
|
|
void
|
|
process_media_commands()
|
|
{
|
|
|
|
if ((actions & (A_MEDIA|A_MEDIAOPT)) == 0) {
|
|
/* Nothing to do. */
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Media already set up, and commands sanity-checked. Set/clear
|
|
* any options, and we're ready to go.
|
|
*/
|
|
media_current |= mediaopt_set;
|
|
media_current &= ~mediaopt_clear;
|
|
|
|
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
ifr.ifr_media = media_current;
|
|
|
|
if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
|
|
err(1, "SIOCSIFMEDIA");
|
|
}
|
|
|
|
void
|
|
setmedia(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
int type, subtype, inst;
|
|
|
|
init_current_media();
|
|
|
|
/* Only one media command may be given. */
|
|
if (actions & A_MEDIA)
|
|
errx(1, "only one `media' command may be issued");
|
|
|
|
/* Must not come after mediaopt commands */
|
|
if (actions & A_MEDIAOPT)
|
|
errx(1, "may not issue `media' after `mediaopt' commands");
|
|
|
|
/*
|
|
* No need to check if `instance' has been issued; setmediainst()
|
|
* craps out if `media' has not been specified.
|
|
*/
|
|
|
|
type = IFM_TYPE(media_current);
|
|
inst = IFM_INST(media_current);
|
|
|
|
/* Look up the subtype. */
|
|
subtype = get_media_subtype(type, val);
|
|
|
|
/* Build the new current media word. */
|
|
media_current = IFM_MAKEWORD(type, subtype, 0, inst);
|
|
|
|
/* Media will be set after other processing is complete. */
|
|
}
|
|
|
|
void
|
|
setmediaopt(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
|
|
init_current_media();
|
|
|
|
/* Can only issue `mediaopt' once. */
|
|
if (actions & A_MEDIAOPTSET)
|
|
errx(1, "only one `mediaopt' command may be issued");
|
|
|
|
/* Can't issue `mediaopt' if `instance' has already been issued. */
|
|
if (actions & A_MEDIAINST)
|
|
errx(1, "may not issue `mediaopt' after `instance'");
|
|
|
|
mediaopt_set = get_media_options(IFM_TYPE(media_current), val);
|
|
|
|
/* Media will be set after other processing is complete. */
|
|
}
|
|
|
|
void
|
|
unsetmediaopt(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
|
|
init_current_media();
|
|
|
|
/* Can only issue `-mediaopt' once. */
|
|
if (actions & A_MEDIAOPTCLR)
|
|
errx(1, "only one `-mediaopt' command may be issued");
|
|
|
|
/* May not issue `media' and `-mediaopt'. */
|
|
if (actions & A_MEDIA)
|
|
errx(1, "may not issue both `media' and `-mediaopt'");
|
|
|
|
/*
|
|
* No need to check for A_MEDIAINST, since the test for A_MEDIA
|
|
* implicitly checks for A_MEDIAINST.
|
|
*/
|
|
|
|
mediaopt_clear = get_media_options(IFM_TYPE(media_current), val);
|
|
|
|
/* Media will be set after other processing is complete. */
|
|
}
|
|
|
|
void
|
|
setmediainst(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
int type, subtype, options, inst;
|
|
|
|
init_current_media();
|
|
|
|
/* Can only issue `instance' once. */
|
|
if (actions & A_MEDIAINST)
|
|
errx(1, "only one `instance' command may be issued");
|
|
|
|
/* Must have already specified `media' */
|
|
if ((actions & A_MEDIA) == 0)
|
|
errx(1, "must specify `media' before `instance'");
|
|
|
|
type = IFM_TYPE(media_current);
|
|
subtype = IFM_SUBTYPE(media_current);
|
|
options = IFM_OPTIONS(media_current);
|
|
|
|
inst = atoi(val);
|
|
if (inst < 0 || inst > IFM_INST_MAX)
|
|
errx(1, "invalid media instance: %s", val);
|
|
|
|
media_current = IFM_MAKEWORD(type, subtype, options, inst);
|
|
|
|
/* Media will be set after other processing is complete. */
|
|
}
|
|
|
|
struct ifmedia_description ifm_type_descriptions[] =
|
|
IFM_TYPE_DESCRIPTIONS;
|
|
|
|
struct ifmedia_description ifm_subtype_descriptions[] =
|
|
IFM_SUBTYPE_DESCRIPTIONS;
|
|
|
|
struct ifmedia_description ifm_option_descriptions[] =
|
|
IFM_OPTION_DESCRIPTIONS;
|
|
|
|
const char *
|
|
get_media_type_string(mword)
|
|
int mword;
|
|
{
|
|
struct ifmedia_description *desc;
|
|
|
|
for (desc = ifm_type_descriptions; desc->ifmt_string != NULL;
|
|
desc++) {
|
|
if (IFM_TYPE(mword) == desc->ifmt_word)
|
|
return (desc->ifmt_string);
|
|
}
|
|
return ("<unknown type>");
|
|
}
|
|
|
|
const char *
|
|
get_media_subtype_string(mword)
|
|
int mword;
|
|
{
|
|
struct ifmedia_description *desc;
|
|
|
|
for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
|
|
desc++) {
|
|
if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
|
|
IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
|
|
return (desc->ifmt_string);
|
|
}
|
|
return ("<unknown subtype>");
|
|
}
|
|
|
|
int
|
|
get_media_subtype(type, val)
|
|
int type;
|
|
const char *val;
|
|
{
|
|
int rval;
|
|
|
|
rval = lookup_media_word(ifm_subtype_descriptions, type, val);
|
|
if (rval == -1)
|
|
errx(1, "unknown %s media subtype: %s",
|
|
get_media_type_string(type), val);
|
|
|
|
return (rval);
|
|
}
|
|
|
|
int
|
|
get_media_options(type, val)
|
|
int type;
|
|
const char *val;
|
|
{
|
|
char *optlist, *str;
|
|
int option, rval = 0;
|
|
|
|
/* We muck with the string, so copy it. */
|
|
optlist = strdup(val);
|
|
if (optlist == NULL)
|
|
err(1, "strdup");
|
|
str = optlist;
|
|
|
|
/*
|
|
* Look up the options in the user-provided comma-separated list.
|
|
*/
|
|
for (; (str = strtok(str, ",")) != NULL; str = NULL) {
|
|
option = lookup_media_word(ifm_option_descriptions, type, str);
|
|
if (option == -1)
|
|
errx(1, "unknown %s media option: %s",
|
|
get_media_type_string(type), str);
|
|
rval |= IFM_OPTIONS(option);
|
|
}
|
|
|
|
free(optlist);
|
|
return (rval);
|
|
}
|
|
|
|
int
|
|
lookup_media_word(desc, type, val)
|
|
struct ifmedia_description *desc;
|
|
int type;
|
|
const char *val;
|
|
{
|
|
|
|
for (; desc->ifmt_string != NULL; desc++) {
|
|
if (IFM_TYPE_MATCH(desc->ifmt_word, type) &&
|
|
strcasecmp(desc->ifmt_string, val) == 0)
|
|
return (desc->ifmt_word);
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
void
|
|
print_media_word(ifmw, print_type, as_syntax)
|
|
int ifmw, print_type, as_syntax;
|
|
{
|
|
struct ifmedia_description *desc;
|
|
int seen_option = 0;
|
|
|
|
if (print_type)
|
|
printf("%s ", get_media_type_string(ifmw));
|
|
printf("%s%s", as_syntax ? "media " : "",
|
|
get_media_subtype_string(ifmw));
|
|
|
|
/* Find options. */
|
|
for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
|
|
desc++) {
|
|
if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) &&
|
|
(ifmw & IFM_OPTIONS(desc->ifmt_word)) != 0 &&
|
|
(seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) {
|
|
if (seen_option == 0)
|
|
printf(" %s", as_syntax ? "mediaopt " : "");
|
|
printf("%s%s", seen_option ? "," : "",
|
|
desc->ifmt_string);
|
|
seen_option |= IFM_OPTIONS(desc->ifmt_word);
|
|
}
|
|
}
|
|
if (IFM_INST(ifmw) != 0)
|
|
printf(" instance %d", IFM_INST(ifmw));
|
|
}
|
|
|
|
int carrier()
|
|
{
|
|
struct ifmediareq ifmr;
|
|
|
|
(void) memset(&ifmr, 0, sizeof(ifmr));
|
|
(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
|
|
|
|
if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
|
|
/*
|
|
* Interface doesn't support SIOC{G,S}IFMEDIA;
|
|
* assume ok.
|
|
*/
|
|
return 0;
|
|
}
|
|
if ((ifmr.ifm_status & IFM_AVALID) == 0) {
|
|
/*
|
|
* Interface doesn't report media-valid status.
|
|
* assume ok.
|
|
*/
|
|
return 0;
|
|
}
|
|
/* otherwise, return ok for active, not-ok if not active. */
|
|
return !(ifmr.ifm_status & IFM_ACTIVE);
|
|
}
|
|
|
|
|
|
#define IFFBITS \
|
|
"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
|
|
\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
|
|
|
|
#define IFCAPBITS \
|
|
"\020\1IP4CSUM\2TCP4CSUM\3UDP4CSUM\4TCP6CSUM\5UDP6CSUM"
|
|
|
|
const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST;
|
|
|
|
const struct ifmedia_status_description ifm_status_descriptions[] =
|
|
IFM_STATUS_DESCRIPTIONS;
|
|
|
|
/*
|
|
* Print the status of the interface. If an address family was
|
|
* specified, show it and it only; otherwise, show them all.
|
|
*/
|
|
void
|
|
status(ap, alen)
|
|
const u_int8_t *ap;
|
|
int alen;
|
|
{
|
|
struct afswtch *p = afp;
|
|
struct ifmediareq ifmr;
|
|
int *media_list, i;
|
|
|
|
printf("%s: ", name);
|
|
printb("flags", flags, IFFBITS);
|
|
if (metric)
|
|
printf(" metric %d", metric);
|
|
if (mtu)
|
|
printf(" mtu %d", mtu);
|
|
putchar('\n');
|
|
|
|
if (g_ifcr.ifcr_capabilities) {
|
|
putchar('\t');
|
|
printb("capabilities", g_ifcr.ifcr_capabilities, IFCAPBITS);
|
|
putchar('\n');
|
|
|
|
putchar('\t');
|
|
printb("enabled", g_ifcr.ifcr_capenable, IFCAPBITS);
|
|
putchar('\n');
|
|
}
|
|
|
|
ieee80211_status();
|
|
vlan_status();
|
|
tunnel_status();
|
|
|
|
if (ap && alen > 0) {
|
|
printf("\taddress:");
|
|
for (i = 0; i < alen; i++, ap++)
|
|
printf("%c%02x", i > 0 ? ':' : ' ', *ap);
|
|
putchar('\n');
|
|
}
|
|
|
|
(void) memset(&ifmr, 0, sizeof(ifmr));
|
|
(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
|
|
|
|
if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
|
|
/*
|
|
* Interface doesn't support SIOC{G,S}IFMEDIA.
|
|
*/
|
|
goto proto_status;
|
|
}
|
|
|
|
if (ifmr.ifm_count == 0) {
|
|
warnx("%s: no media types?", name);
|
|
goto proto_status;
|
|
}
|
|
|
|
media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
|
|
if (media_list == NULL)
|
|
err(1, "malloc");
|
|
ifmr.ifm_ulist = media_list;
|
|
|
|
if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
|
|
err(1, "SIOCGIFMEDIA");
|
|
|
|
printf("\tmedia: ");
|
|
print_media_word(ifmr.ifm_current, 1, 0);
|
|
if (ifmr.ifm_active != ifmr.ifm_current) {
|
|
putchar(' ');
|
|
putchar('(');
|
|
print_media_word(ifmr.ifm_active, 0, 0);
|
|
putchar(')');
|
|
}
|
|
putchar('\n');
|
|
|
|
if (ifmr.ifm_status & IFM_STATUS_VALID) {
|
|
const struct ifmedia_status_description *ifms;
|
|
int bitno, found = 0;
|
|
|
|
printf("\tstatus: ");
|
|
for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) {
|
|
for (ifms = ifm_status_descriptions;
|
|
ifms->ifms_valid != 0; ifms++) {
|
|
if (ifms->ifms_type !=
|
|
IFM_TYPE(ifmr.ifm_current) ||
|
|
ifms->ifms_valid !=
|
|
ifm_status_valid_list[bitno])
|
|
continue;
|
|
printf("%s%s", found ? ", " : "",
|
|
IFM_STATUS_DESC(ifms, ifmr.ifm_status));
|
|
found = 1;
|
|
|
|
/*
|
|
* For each valid indicator bit, there's
|
|
* only one entry for each media type, so
|
|
* terminate the inner loop now.
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found == 0)
|
|
printf("unknown");
|
|
putchar('\n');
|
|
}
|
|
|
|
if (mflag) {
|
|
int type, printed_type;
|
|
|
|
for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) {
|
|
for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) {
|
|
if (IFM_TYPE(media_list[i]) == type) {
|
|
if (printed_type == 0) {
|
|
printf("\tsupported %s media:\n",
|
|
get_media_type_string(type));
|
|
printed_type = 1;
|
|
}
|
|
printf("\t\t");
|
|
print_media_word(media_list[i], 0, 1);
|
|
printf("\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
free(media_list);
|
|
|
|
proto_status:
|
|
if ((p = afp) != NULL) {
|
|
(*p->af_status)(1);
|
|
} else for (p = afs; p->af_name; p++) {
|
|
ifr.ifr_addr.sa_family = p->af_af;
|
|
(*p->af_status)(0);
|
|
}
|
|
}
|
|
|
|
void
|
|
tunnel_status()
|
|
{
|
|
char psrcaddr[NI_MAXHOST];
|
|
char pdstaddr[NI_MAXHOST];
|
|
const char *ver = "";
|
|
#ifdef NI_WITHSCOPEID
|
|
const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
|
|
#else
|
|
const int niflag = NI_NUMERICHOST;
|
|
#endif
|
|
struct if_laddrreq req;
|
|
|
|
psrcaddr[0] = pdstaddr[0] = '\0';
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
strncpy(req.iflr_name, name, IFNAMSIZ);
|
|
if (ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&req) < 0)
|
|
return;
|
|
#ifdef INET6
|
|
if (req.addr.ss_family == AF_INET6)
|
|
in6_fillscopeid((struct sockaddr_in6 *)&req.addr);
|
|
#endif
|
|
getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len,
|
|
psrcaddr, sizeof(psrcaddr), 0, 0, niflag);
|
|
#ifdef INET6
|
|
if (req.addr.ss_family == AF_INET6)
|
|
ver = "6";
|
|
#endif
|
|
|
|
#ifdef INET6
|
|
if (req.dstaddr.ss_family == AF_INET6)
|
|
in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr);
|
|
#endif
|
|
getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len,
|
|
pdstaddr, sizeof(pdstaddr), 0, 0, niflag);
|
|
|
|
printf("\ttunnel inet%s %s --> %s\n", ver, psrcaddr, pdstaddr);
|
|
}
|
|
|
|
void
|
|
vlan_status()
|
|
{
|
|
struct vlanreq vlr;
|
|
|
|
if (strncmp(ifr.ifr_name, "vlan", 4) != 0 ||
|
|
!isdigit(ifr.ifr_name[4]))
|
|
return;
|
|
|
|
memset(&vlr, 0, sizeof(vlr));
|
|
ifr.ifr_data = (caddr_t)&vlr;
|
|
|
|
if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
|
|
return;
|
|
|
|
if (vlr.vlr_tag || vlr.vlr_parent[0] != '\0')
|
|
printf("\tvlan: %d parent: %s\n",
|
|
vlr.vlr_tag, vlr.vlr_parent[0] == '\0' ?
|
|
"<none>" : vlr.vlr_parent);
|
|
}
|
|
|
|
void
|
|
in_alias(creq)
|
|
struct ifreq *creq;
|
|
{
|
|
struct sockaddr_in *sin;
|
|
int alias;
|
|
|
|
if (lflag)
|
|
return;
|
|
|
|
alias = 1;
|
|
|
|
/* Get the non-alias address for this interface. */
|
|
getsock(AF_INET);
|
|
if (s < 0) {
|
|
if (errno == EPROTONOSUPPORT)
|
|
return;
|
|
err(1, "socket");
|
|
}
|
|
(void) memset(&ifr, 0, sizeof(ifr));
|
|
(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
|
|
if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
|
|
return;
|
|
} else
|
|
warn("SIOCGIFADDR");
|
|
}
|
|
/* If creq and ifr are the same address, this is not an alias. */
|
|
if (memcmp(&ifr.ifr_addr, &creq->ifr_addr,
|
|
sizeof(creq->ifr_addr)) == 0)
|
|
alias = 0;
|
|
(void) memset(&addreq, 0, sizeof(addreq));
|
|
(void) strncpy(addreq.ifra_name, name, sizeof(addreq.ifra_name));
|
|
addreq.ifra_addr = creq->ifr_addr;
|
|
if (ioctl(s, SIOCGIFALIAS, (caddr_t)&addreq) < 0) {
|
|
if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
|
|
return;
|
|
} else
|
|
warn("SIOCGIFALIAS");
|
|
}
|
|
|
|
sin = (struct sockaddr_in *)&addreq.ifra_addr;
|
|
printf("\tinet %s%s", alias ? "alias " : "", inet_ntoa(sin->sin_addr));
|
|
|
|
if (flags & IFF_POINTOPOINT) {
|
|
sin = (struct sockaddr_in *)&addreq.ifra_dstaddr;
|
|
printf(" -> %s", inet_ntoa(sin->sin_addr));
|
|
}
|
|
|
|
sin = (struct sockaddr_in *)&addreq.ifra_mask;
|
|
printf(" netmask 0x%x", ntohl(sin->sin_addr.s_addr));
|
|
|
|
if (flags & IFF_BROADCAST) {
|
|
sin = (struct sockaddr_in *)&addreq.ifra_broadaddr;
|
|
printf(" broadcast %s", inet_ntoa(sin->sin_addr));
|
|
}
|
|
printf("\n");
|
|
}
|
|
|
|
void
|
|
in_status(force)
|
|
int force;
|
|
{
|
|
struct ifaddrs *ifap, *ifa;
|
|
struct ifreq ifr;
|
|
|
|
if (getifaddrs(&ifap) != 0)
|
|
err(1, "getifaddrs");
|
|
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
|
if (strcmp(name, ifa->ifa_name) != 0)
|
|
continue;
|
|
if (ifa->ifa_addr->sa_family != AF_INET)
|
|
continue;
|
|
if (sizeof(ifr.ifr_addr) < ifa->ifa_addr->sa_len)
|
|
continue;
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
|
|
memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
|
|
in_alias(&ifr);
|
|
}
|
|
freeifaddrs(ifap);
|
|
}
|
|
|
|
void
|
|
setifprefixlen(addr, d)
|
|
const char *addr;
|
|
int d;
|
|
{
|
|
if (*afp->af_getprefix)
|
|
(*afp->af_getprefix)(addr, MASK);
|
|
explicit_prefix = 1;
|
|
}
|
|
|
|
#ifdef INET6
|
|
void
|
|
in6_fillscopeid(sin6)
|
|
struct sockaddr_in6 *sin6;
|
|
{
|
|
#if defined(__KAME__) && defined(KAME_SCOPEID)
|
|
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
|
|
sin6->sin6_scope_id =
|
|
ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
|
|
sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* XXX not really an alias */
|
|
void
|
|
in6_alias(creq)
|
|
struct in6_ifreq *creq;
|
|
{
|
|
struct sockaddr_in6 *sin6;
|
|
char hbuf[NI_MAXHOST];
|
|
u_int32_t scopeid;
|
|
#ifdef NI_WITHSCOPEID
|
|
const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID;
|
|
#else
|
|
const int niflag = NI_NUMERICHOST;
|
|
#endif
|
|
|
|
/* Get the non-alias address for this interface. */
|
|
getsock(AF_INET6);
|
|
if (s < 0) {
|
|
if (errno == EPROTONOSUPPORT)
|
|
return;
|
|
err(1, "socket");
|
|
}
|
|
|
|
sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
|
|
|
|
in6_fillscopeid(sin6);
|
|
scopeid = sin6->sin6_scope_id;
|
|
if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
|
|
hbuf, sizeof(hbuf), NULL, 0, niflag))
|
|
strncpy(hbuf, "", sizeof(hbuf)); /* some message? */
|
|
printf("\tinet6 %s", hbuf);
|
|
|
|
if (flags & IFF_POINTOPOINT) {
|
|
(void) memset(&ifr6, 0, sizeof(ifr6));
|
|
(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
|
|
ifr6.ifr_addr = creq->ifr_addr;
|
|
if (ioctl(s, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) < 0) {
|
|
if (errno != EADDRNOTAVAIL)
|
|
warn("SIOCGIFDSTADDR_IN6");
|
|
(void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
|
|
ifr6.ifr_addr.sin6_family = AF_INET6;
|
|
ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
|
|
}
|
|
sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
|
|
in6_fillscopeid(sin6);
|
|
hbuf[0] = '\0';
|
|
if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
|
|
hbuf, sizeof(hbuf), NULL, 0, niflag))
|
|
strncpy(hbuf, "", sizeof(hbuf)); /* some message? */
|
|
printf(" -> %s", hbuf);
|
|
}
|
|
|
|
(void) memset(&ifr6, 0, sizeof(ifr6));
|
|
(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
|
|
ifr6.ifr_addr = creq->ifr_addr;
|
|
if (ioctl(s, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) < 0) {
|
|
if (errno != EADDRNOTAVAIL)
|
|
warn("SIOCGIFNETMASK_IN6");
|
|
} else {
|
|
sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
|
|
printf(" prefixlen %d", prefix(&sin6->sin6_addr,
|
|
sizeof(struct in6_addr)));
|
|
}
|
|
|
|
(void) memset(&ifr6, 0, sizeof(ifr6));
|
|
(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
|
|
ifr6.ifr_addr = creq->ifr_addr;
|
|
if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) < 0) {
|
|
if (errno != EADDRNOTAVAIL)
|
|
warn("SIOCGIFAFLAG_IN6");
|
|
} else {
|
|
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
|
|
printf(" anycast");
|
|
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
|
|
printf(" tentative");
|
|
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
|
|
printf(" duplicated");
|
|
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
|
|
printf(" detached");
|
|
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
|
|
printf(" deprecated");
|
|
}
|
|
|
|
if (scopeid)
|
|
printf(" scopeid 0x%x", scopeid);
|
|
|
|
if (Lflag) {
|
|
struct in6_addrlifetime *lifetime;
|
|
(void) memset(&ifr6, 0, sizeof(ifr6));
|
|
(void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
|
|
ifr6.ifr_addr = creq->ifr_addr;
|
|
lifetime = &ifr6.ifr_ifru.ifru_lifetime;
|
|
if (ioctl(s, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) < 0) {
|
|
if (errno != EADDRNOTAVAIL)
|
|
warn("SIOCGIFALIFETIME_IN6");
|
|
} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
|
|
time_t t = time(NULL);
|
|
printf(" pltime ");
|
|
if (lifetime->ia6t_preferred) {
|
|
printf("%s", lifetime->ia6t_preferred < t
|
|
? "0"
|
|
: sec2str(lifetime->ia6t_preferred - t));
|
|
} else
|
|
printf("infty");
|
|
|
|
printf(" vltime ");
|
|
if (lifetime->ia6t_expire) {
|
|
printf("%s", lifetime->ia6t_expire < t
|
|
? "0"
|
|
: sec2str(lifetime->ia6t_expire - t));
|
|
} else
|
|
printf("infty");
|
|
}
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
void
|
|
in6_status(force)
|
|
int force;
|
|
{
|
|
struct ifaddrs *ifap, *ifa;
|
|
struct in6_ifreq ifr;
|
|
|
|
if (getifaddrs(&ifap) != 0)
|
|
err(1, "getifaddrs");
|
|
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
|
if (strcmp(name, ifa->ifa_name) != 0)
|
|
continue;
|
|
if (ifa->ifa_addr->sa_family != AF_INET6)
|
|
continue;
|
|
if (sizeof(ifr.ifr_addr) < ifa->ifa_addr->sa_len)
|
|
continue;
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
|
|
memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
|
|
in6_alias(&ifr);
|
|
}
|
|
freeifaddrs(ifap);
|
|
}
|
|
#endif /*INET6*/
|
|
|
|
#ifndef INET_ONLY
|
|
|
|
void
|
|
at_status(force)
|
|
int force;
|
|
{
|
|
struct sockaddr_at *sat, null_sat;
|
|
struct netrange *nr;
|
|
|
|
getsock(AF_APPLETALK);
|
|
if (s < 0) {
|
|
if (errno == EPROTONOSUPPORT)
|
|
return;
|
|
err(1, "socket");
|
|
}
|
|
(void) memset(&ifr, 0, sizeof(ifr));
|
|
(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
|
|
if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
|
|
if (!force)
|
|
return;
|
|
(void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
|
|
} else
|
|
warn("SIOCGIFADDR");
|
|
}
|
|
(void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
|
|
sat = (struct sockaddr_at *)&ifr.ifr_addr;
|
|
|
|
(void) memset(&null_sat, 0, sizeof(null_sat));
|
|
|
|
nr = (struct netrange *) &sat->sat_zero;
|
|
printf("\tatalk %d.%d range %d-%d phase %d",
|
|
ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
|
|
ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
|
|
if (flags & IFF_POINTOPOINT) {
|
|
if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
|
|
if (errno == EADDRNOTAVAIL)
|
|
(void) memset(&ifr.ifr_addr, 0,
|
|
sizeof(ifr.ifr_addr));
|
|
else
|
|
warn("SIOCGIFDSTADDR");
|
|
}
|
|
(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
|
|
sat = (struct sockaddr_at *)&ifr.ifr_dstaddr;
|
|
if (!sat)
|
|
sat = &null_sat;
|
|
printf("--> %d.%d",
|
|
ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
|
|
}
|
|
if (flags & IFF_BROADCAST) {
|
|
/* note RTAX_BRD overlap with IFF_POINTOPOINT */
|
|
sat = (struct sockaddr_at *)&ifr.ifr_broadaddr;
|
|
if (sat)
|
|
printf(" broadcast %d.%d", ntohs(sat->sat_addr.s_net),
|
|
sat->sat_addr.s_node);
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
void
|
|
xns_status(force)
|
|
int force;
|
|
{
|
|
struct sockaddr_ns *sns;
|
|
|
|
getsock(AF_NS);
|
|
if (s < 0) {
|
|
if (errno == EPROTONOSUPPORT)
|
|
return;
|
|
err(1, "socket");
|
|
}
|
|
(void) memset(&ifr, 0, sizeof(ifr));
|
|
(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
|
|
if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
|
|
if (!force)
|
|
return;
|
|
memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
|
|
} else
|
|
warn("SIOCGIFADDR");
|
|
}
|
|
(void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
|
|
sns = (struct sockaddr_ns *)&ifr.ifr_addr;
|
|
printf("\tns %s ", ns_ntoa(sns->sns_addr));
|
|
if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
|
|
if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
|
|
if (errno == EADDRNOTAVAIL)
|
|
memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
|
|
else
|
|
warn("SIOCGIFDSTADDR");
|
|
}
|
|
(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
|
|
sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
|
|
printf("--> %s ", ns_ntoa(sns->sns_addr));
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
void
|
|
iso_status(force)
|
|
int force;
|
|
{
|
|
struct sockaddr_iso *siso;
|
|
struct iso_ifreq ifr;
|
|
|
|
getsock(AF_ISO);
|
|
if (s < 0) {
|
|
if (errno == EPROTONOSUPPORT)
|
|
return;
|
|
err(1, "socket");
|
|
}
|
|
(void) memset(&ifr, 0, sizeof(ifr));
|
|
(void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
|
|
if (ioctl(s, SIOCGIFADDR_ISO, (caddr_t)&ifr) < 0) {
|
|
if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
|
|
if (!force)
|
|
return;
|
|
(void) memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
|
|
} else
|
|
warn("SIOCGIFADDR_ISO");
|
|
}
|
|
(void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
|
|
siso = &ifr.ifr_Addr;
|
|
printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
|
|
if (ioctl(s, SIOCGIFNETMASK_ISO, (caddr_t)&ifr) < 0) {
|
|
if (errno == EADDRNOTAVAIL)
|
|
memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
|
|
else
|
|
warn("SIOCGIFNETMASK_ISO");
|
|
} else {
|
|
if (siso->siso_len > offsetof(struct sockaddr_iso, siso_addr))
|
|
siso->siso_addr.isoa_len = siso->siso_len
|
|
- offsetof(struct sockaddr_iso, siso_addr);
|
|
printf("\n\t\tnetmask %s ", iso_ntoa(&siso->siso_addr));
|
|
}
|
|
if (flags & IFF_POINTOPOINT) {
|
|
if (ioctl(s, SIOCGIFDSTADDR_ISO, (caddr_t)&ifr) < 0) {
|
|
if (errno == EADDRNOTAVAIL)
|
|
memset(&ifr.ifr_Addr, 0, sizeof(ifr.ifr_Addr));
|
|
else
|
|
warn("SIOCGIFDSTADDR_ISO");
|
|
}
|
|
(void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
|
|
siso = &ifr.ifr_Addr;
|
|
printf("--> %s ", iso_ntoa(&siso->siso_addr));
|
|
}
|
|
putchar('\n');
|
|
}
|
|
|
|
#endif /* INET_ONLY */
|
|
|
|
#define SIN(x) ((struct sockaddr_in *) &(x))
|
|
struct sockaddr_in *sintab[] = {
|
|
SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
|
|
SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
|
|
|
|
void
|
|
in_getaddr(s, which)
|
|
const char *s;
|
|
int which;
|
|
{
|
|
struct sockaddr_in *sin = sintab[which];
|
|
struct hostent *hp;
|
|
struct netent *np;
|
|
|
|
sin->sin_len = sizeof(*sin);
|
|
if (which != MASK)
|
|
sin->sin_family = AF_INET;
|
|
|
|
if (which == ADDR) {
|
|
char *p = NULL;
|
|
if ((p = strrchr(s, '/')) != NULL) {
|
|
*p = '\0';
|
|
in_getprefix(p + 1, MASK);
|
|
}
|
|
}
|
|
|
|
if (inet_aton(s, &sin->sin_addr) == 0) {
|
|
if ((hp = gethostbyname(s)) != NULL)
|
|
(void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
|
|
else if ((np = getnetbyname(s)) != NULL)
|
|
sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
|
|
else
|
|
errx(1, "%s: bad value", s);
|
|
}
|
|
}
|
|
|
|
void
|
|
in_getprefix(plen, which)
|
|
const char *plen;
|
|
int which;
|
|
{
|
|
register struct sockaddr_in *sin = sintab[which];
|
|
register u_char *cp;
|
|
int len = strtol(plen, (char **)NULL, 10);
|
|
|
|
if ((len < 0) || (len > 32))
|
|
errx(1, "%s: bad value", plen);
|
|
sin->sin_len = sizeof(*sin);
|
|
if (which != MASK)
|
|
sin->sin_family = AF_INET;
|
|
if ((len == 0) || (len == 32)) {
|
|
memset(&sin->sin_addr, 0xff, sizeof(struct in_addr));
|
|
return;
|
|
}
|
|
memset((void *)&sin->sin_addr, 0x00, sizeof(sin->sin_addr));
|
|
for (cp = (u_char *)&sin->sin_addr; len > 7; len -= 8)
|
|
*cp++ = 0xff;
|
|
*cp = 0xff << (8 - len);
|
|
}
|
|
|
|
/*
|
|
* Print a value a la the %b format of the kernel's printf
|
|
*/
|
|
void
|
|
printb(s, v, bits)
|
|
const char *s;
|
|
unsigned short v;
|
|
const char *bits;
|
|
{
|
|
int i, any = 0;
|
|
char c;
|
|
|
|
if (bits && *bits == 8)
|
|
printf("%s=%o", s, v);
|
|
else
|
|
printf("%s=%x", s, v);
|
|
bits++;
|
|
if (bits) {
|
|
putchar('<');
|
|
while ((i = *bits++) != 0) {
|
|
if (v & (1 << (i-1))) {
|
|
if (any)
|
|
putchar(',');
|
|
any = 1;
|
|
for (; (c = *bits) > 32; bits++)
|
|
putchar(c);
|
|
} else
|
|
for (; *bits > 32; bits++)
|
|
;
|
|
}
|
|
putchar('>');
|
|
}
|
|
}
|
|
|
|
#ifdef INET6
|
|
#define SIN6(x) ((struct sockaddr_in6 *) &(x))
|
|
struct sockaddr_in6 *sin6tab[] = {
|
|
SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
|
|
SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
|
|
|
|
void
|
|
in6_getaddr(s, which)
|
|
const char *s;
|
|
int which;
|
|
{
|
|
#if defined(__KAME__) && defined(KAME_SCOPEID)
|
|
struct sockaddr_in6 *sin6 = sin6tab[which];
|
|
struct addrinfo hints, *res;
|
|
int error;
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = AF_INET6;
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
#if 0 /* in_getaddr() allows FQDN */
|
|
hints.ai_flags = AI_NUMERICHOST;
|
|
#endif
|
|
error = getaddrinfo(s, "0", &hints, &res);
|
|
if (error)
|
|
errx(1, "%s: %s", s, gai_strerror(error));
|
|
if (res->ai_next)
|
|
errx(1, "%s: resolved to multiple hosts", s);
|
|
if (res->ai_addrlen != sizeof(struct sockaddr_in6))
|
|
errx(1, "%s: bad value", s);
|
|
memcpy(sin6, res->ai_addr, res->ai_addrlen);
|
|
freeaddrinfo(res);
|
|
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && sin6->sin6_scope_id) {
|
|
*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
|
|
htons(sin6->sin6_scope_id);
|
|
sin6->sin6_scope_id = 0;
|
|
}
|
|
#else
|
|
struct sockaddr_in6 *sin = sin6tab[which];
|
|
|
|
sin->sin6_len = sizeof(*sin);
|
|
if (which != MASK)
|
|
sin->sin6_family = AF_INET6;
|
|
|
|
if (which == ADDR) {
|
|
char *p = NULL;
|
|
if((p = strrchr(s, '/')) != NULL) {
|
|
*p = '\0';
|
|
in6_getprefix(p + 1, MASK);
|
|
explicit_prefix = 1;
|
|
}
|
|
}
|
|
|
|
if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
|
|
errx(1, "%s: bad value", s);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
in6_getprefix(plen, which)
|
|
const char *plen;
|
|
int which;
|
|
{
|
|
register struct sockaddr_in6 *sin = sin6tab[which];
|
|
register u_char *cp;
|
|
int len = strtol(plen, (char **)NULL, 10);
|
|
|
|
if ((len < 0) || (len > 128))
|
|
errx(1, "%s: bad value", plen);
|
|
sin->sin6_len = sizeof(*sin);
|
|
if (which != MASK)
|
|
sin->sin6_family = AF_INET6;
|
|
if ((len == 0) || (len == 128)) {
|
|
memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
|
|
return;
|
|
}
|
|
memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
|
|
for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
|
|
*cp++ = 0xff;
|
|
*cp = 0xff << (8 - len);
|
|
}
|
|
|
|
int
|
|
prefix(val, size)
|
|
void *val;
|
|
int size;
|
|
{
|
|
register u_char *name = (u_char *)val;
|
|
register int byte, bit, plen = 0;
|
|
|
|
for (byte = 0; byte < size; byte++, plen += 8)
|
|
if (name[byte] != 0xff)
|
|
break;
|
|
if (byte == size)
|
|
return (plen);
|
|
for (bit = 7; bit != 0; bit--, plen++)
|
|
if (!(name[byte] & (1 << bit)))
|
|
break;
|
|
for (; bit != 0; bit--)
|
|
if (name[byte] & (1 << bit))
|
|
return(0);
|
|
byte++;
|
|
for (; byte < size; byte++)
|
|
if (name[byte])
|
|
return(0);
|
|
return (plen);
|
|
}
|
|
#endif /*INET6*/
|
|
|
|
#ifndef INET_ONLY
|
|
void
|
|
at_getaddr(addr, which)
|
|
const char *addr;
|
|
int which;
|
|
{
|
|
struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr;
|
|
u_int net, node;
|
|
|
|
sat->sat_family = AF_APPLETALK;
|
|
sat->sat_len = sizeof(*sat);
|
|
if (which == MASK)
|
|
errx(1, "AppleTalk does not use netmasks\n");
|
|
if (sscanf(addr, "%u.%u", &net, &node) != 2
|
|
|| net == 0 || net > 0xffff || node == 0 || node > 0xfe)
|
|
errx(1, "%s: illegal address", addr);
|
|
sat->sat_addr.s_net = htons(net);
|
|
sat->sat_addr.s_node = node;
|
|
}
|
|
|
|
void
|
|
setatrange(range, d)
|
|
const char *range;
|
|
int d;
|
|
{
|
|
u_short first = 123, last = 123;
|
|
|
|
if (sscanf(range, "%hu-%hu", &first, &last) != 2
|
|
|| first == 0 || first > 0xffff
|
|
|| last == 0 || last > 0xffff || first > last)
|
|
errx(1, "%s: illegal net range: %u-%u", range, first, last);
|
|
at_nr.nr_firstnet = htons(first);
|
|
at_nr.nr_lastnet = htons(last);
|
|
}
|
|
|
|
void
|
|
setatphase(phase, d)
|
|
const char *phase;
|
|
int d;
|
|
{
|
|
if (!strcmp(phase, "1"))
|
|
at_nr.nr_phase = 1;
|
|
else if (!strcmp(phase, "2"))
|
|
at_nr.nr_phase = 2;
|
|
else
|
|
errx(1, "%s: illegal phase", phase);
|
|
}
|
|
|
|
void
|
|
checkatrange(sat)
|
|
struct sockaddr_at *sat;
|
|
{
|
|
if (at_nr.nr_phase == 0)
|
|
at_nr.nr_phase = 2; /* Default phase 2 */
|
|
if (at_nr.nr_firstnet == 0)
|
|
at_nr.nr_firstnet = /* Default range of one */
|
|
at_nr.nr_lastnet = sat->sat_addr.s_net;
|
|
printf("\tatalk %d.%d range %d-%d phase %d\n",
|
|
ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
|
|
ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase);
|
|
if ((u_short) ntohs(at_nr.nr_firstnet) >
|
|
(u_short) ntohs(sat->sat_addr.s_net)
|
|
|| (u_short) ntohs(at_nr.nr_lastnet) <
|
|
(u_short) ntohs(sat->sat_addr.s_net))
|
|
errx(1, "AppleTalk address is not in range");
|
|
*((struct netrange *) &sat->sat_zero) = at_nr;
|
|
}
|
|
|
|
#define SNS(x) ((struct sockaddr_ns *) &(x))
|
|
struct sockaddr_ns *snstab[] = {
|
|
SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
|
|
SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
|
|
|
|
void
|
|
xns_getaddr(addr, which)
|
|
const char *addr;
|
|
int which;
|
|
{
|
|
struct sockaddr_ns *sns = snstab[which];
|
|
|
|
sns->sns_family = AF_NS;
|
|
sns->sns_len = sizeof(*sns);
|
|
sns->sns_addr = ns_addr(addr);
|
|
if (which == MASK)
|
|
puts("Attempt to set XNS netmask will be ineffectual");
|
|
}
|
|
|
|
#define SISO(x) ((struct sockaddr_iso *) &(x))
|
|
struct sockaddr_iso *sisotab[] = {
|
|
SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr),
|
|
SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
|
|
|
|
void
|
|
iso_getaddr(addr, which)
|
|
const char *addr;
|
|
int which;
|
|
{
|
|
struct sockaddr_iso *siso = sisotab[which];
|
|
siso->siso_addr = *iso_addr(addr);
|
|
|
|
if (which == MASK) {
|
|
siso->siso_len = TSEL(siso) - (caddr_t)(siso);
|
|
siso->siso_nlen = 0;
|
|
} else {
|
|
siso->siso_len = sizeof(*siso);
|
|
siso->siso_family = AF_ISO;
|
|
}
|
|
}
|
|
|
|
void
|
|
setsnpaoffset(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
iso_addreq.ifra_snpaoffset = atoi(val);
|
|
}
|
|
|
|
void
|
|
setnsellength(val, d)
|
|
const char *val;
|
|
int d;
|
|
{
|
|
nsellength = atoi(val);
|
|
if (nsellength < 0)
|
|
errx(1, "Negative NSEL length is absurd");
|
|
if (afp == 0 || afp->af_af != AF_ISO)
|
|
errx(1, "Setting NSEL length valid only for iso");
|
|
}
|
|
|
|
void
|
|
fixnsel(s)
|
|
struct sockaddr_iso *s;
|
|
{
|
|
if (s->siso_family == 0)
|
|
return;
|
|
s->siso_tlen = nsellength;
|
|
}
|
|
|
|
void
|
|
adjust_nsellength()
|
|
{
|
|
fixnsel(sisotab[RIDADDR]);
|
|
fixnsel(sisotab[ADDR]);
|
|
fixnsel(sisotab[DSTADDR]);
|
|
}
|
|
|
|
#endif /* INET_ONLY */
|
|
|
|
void
|
|
usage()
|
|
{
|
|
const char *progname = getprogname();
|
|
|
|
fprintf(stderr,
|
|
"usage: %s [ -m ] "
|
|
#ifdef INET6
|
|
"[ -L ] "
|
|
#endif
|
|
"interface\n"
|
|
"\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n"
|
|
"\t\t[ alias | -alias ] ]\n"
|
|
"\t[ up ] [ down ] [ metric n ] [ mtu n ]\n"
|
|
"\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n"
|
|
"\t[ powersave | -powersave ] [ powersavesleep duration ]\n"
|
|
"\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n"
|
|
"\t[ arp | -arp ]\n"
|
|
"\t[ media type ] [ mediaopt opts ] [ -mediaopt opts ] "
|
|
"[ instance minst ]\n"
|
|
"\t[ vlan n vlanif i ]\n"
|
|
"\t[ anycast | -anycast ] [ deprecated | -deprecated ]\n"
|
|
"\t[ tentative | -tentative ] [ pltime n ] [ vltime n ]\n"
|
|
"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
|
|
" %s -a [ -m ] [ -d ] [ -u ] [ af ]\n"
|
|
" %s -l [ -b ] [ -d ] [ -u ] [ -s ]\n"
|
|
" %s -C\n"
|
|
" %s interface create\n"
|
|
" %s interface destroy\n",
|
|
progname, progname, progname, progname, progname, progname);
|
|
exit(1);
|
|
}
|
|
|
|
#ifdef INET6
|
|
char *
|
|
sec2str(total)
|
|
time_t total;
|
|
{
|
|
static char result[256];
|
|
int days, hours, mins, secs;
|
|
int first = 1;
|
|
char *p = result;
|
|
|
|
if (0) { /*XXX*/
|
|
days = total / 3600 / 24;
|
|
hours = (total / 3600) % 24;
|
|
mins = (total / 60) % 60;
|
|
secs = total % 60;
|
|
|
|
if (days) {
|
|
first = 0;
|
|
p += sprintf(p, "%dd", days);
|
|
}
|
|
if (!first || hours) {
|
|
first = 0;
|
|
p += sprintf(p, "%dh", hours);
|
|
}
|
|
if (!first || mins) {
|
|
first = 0;
|
|
p += sprintf(p, "%dm", mins);
|
|
}
|
|
sprintf(p, "%ds", secs);
|
|
} else
|
|
sprintf(p, "%lu", (u_long)total);
|
|
|
|
return(result);
|
|
}
|
|
#endif
|