freebsd-skq/sbin/ifconfig/ifconfig.c
Garrett Wollman ee9a463848 Use a dynamically-sized buffer for SIOCGIFCONF so that `ifconfig -a'
actually retrieves all the information no matter how many interfaces
there are.  (Probably there are other utilities which need similar
modification.)

Submitted by:	Andrew Webster <awebster@dataradio.com>
1995-12-07 19:21:53 +00:00

949 lines
23 KiB
C

/*
* 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.
*/
/*
* 951109 - Andrew@pubnix.net - Changed to iterative buffer growing mechanism
* for ifconfig -a so all interfaces are queried.
*
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94";
#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 <netinet/in.h>
#include <netinet/in_var.h>
#include <arpa/inet.h>
#include <netdb.h>
#define IPXIP
#define IPTUNNEL
#include <netipx/ipx.h>
#include <netipx/ipx_if.h>
#define NSIP
#include <netns/ns.h>
#include <netns/ns_if.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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <nlist.h>
#include <kvm.h>
#include <fcntl.h>
struct ifreq ifr, ridreq;
struct ifaliasreq addreq;
struct iso_ifreq iso_ridreq;
struct iso_aliasreq iso_addreq;
struct sockaddr_in netmask;
char name[30];
int flags;
int metric;
int mtu;
int nsellength = 1;
int setaddr;
int setipdst;
int doalias;
int clearaddr;
int newaddr = 1;
int s;
kvm_t *kvmd;
extern int errno;
int setifflags(), setifaddr(), setifdstaddr(), setifnetmask();
int setifmetric(), setifmtu(), setifbroadaddr(), setifipdst();
int notealias(), setsnpaoffset(), setnsellength(), notrailers();
#define NEXTARG 0xffffff
struct cmd {
char *c_name;
int c_parameter; /* NEXTARG means next argv */
int (*c_func)();
} cmds[] = {
{ "up", IFF_UP, setifflags } ,
{ "down", -IFF_UP, setifflags },
{ "trailers", -1, notrailers },
{ "-trailers", 1, notrailers },
{ "arp", -IFF_NOARP, setifflags },
{ "-arp", IFF_NOARP, setifflags },
{ "debug", IFF_DEBUG, setifflags },
{ "-debug", -IFF_DEBUG, setifflags },
{ "alias", IFF_UP, notealias },
{ "-alias", -IFF_UP, notealias },
{ "delete", -IFF_UP, notealias },
#ifdef notdef
#define EN_SWABIPS 0x1000
{ "swabips", EN_SWABIPS, setifflags },
{ "-swabips", -EN_SWABIPS, setifflags },
#endif
{ "netmask", NEXTARG, setifnetmask },
{ "metric", NEXTARG, setifmetric },
{ "broadcast", NEXTARG, setifbroadaddr },
{ "ipdst", NEXTARG, setifipdst },
{ "snpaoffset", NEXTARG, setsnpaoffset },
{ "nsellength", NEXTARG, setnsellength },
{ "link0", IFF_LINK0, setifflags },
{ "-link0", -IFF_LINK0, setifflags },
{ "link1", IFF_LINK1, setifflags },
{ "-link1", -IFF_LINK1, setifflags },
{ "link2", IFF_LINK2, setifflags },
{ "-link2", -IFF_LINK2, setifflags },
{ "normal", -IFF_LINK0, setifflags },
{ "compress", IFF_LINK0, setifflags },
{ "noicmp", IFF_LINK1, setifflags },
{ "mtu", NEXTARG, setifmtu },
{ 0, 0, setifaddr },
{ 0, 0, setifdstaddr },
};
/*
* XNS support liberally adapted from code written at the University of
* Maryland principally by James O'Toole and Chris Torek.
*/
int in_status(), in_getaddr();
int ipx_status(), ipx_getaddr();
int xns_status(), xns_getaddr();
int iso_status(), iso_getaddr();
int ether_status();
/* Known address families */
struct afswtch {
char *af_name;
short af_af;
int (*af_status)();
int (*af_getaddr)();
int af_difaddr;
int af_aifaddr;
caddr_t af_ridreq;
caddr_t af_addreq;
} afs[] = {
#define C(x) ((caddr_t) &x)
{ "inet", AF_INET, in_status, in_getaddr,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
{ "ipx", AF_IPX, ipx_status, ipx_getaddr,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
{ "ns", AF_NS, xns_status, xns_getaddr,
SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
{ "iso", AF_ISO, iso_status, iso_getaddr,
SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, C(iso_ridreq), C(iso_addreq) },
{ "ether", AF_INET, ether_status, NULL },
{ 0, 0, 0, 0 }
};
struct afswtch *afp; /*the address family being set or asked about*/
main(argc, argv)
int argc;
char *argv[];
{
int af = AF_INET;
register struct afswtch *rafp;
if (argc < 2) {
fprintf(stderr, "usage: ifconfig interface\n%s%s%s%s%s%s",
"\t[ af [ address [ dest_addr ] ] [ up ] [ down ]",
"[ netmask mask ] ]\n",
"\t[ metric n ]\n",
"\t[ mtu n ]\n",
"\t[ arp | -arp ]\n",
"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ] \n");
exit(1);
}
argc--, argv++;
strncpy(name, *argv, sizeof(name));
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
argc--, argv++;
if (argc > 0) {
for (afp = rafp = afs; rafp->af_name; rafp++)
if (strcmp(rafp->af_name, *argv) == 0) {
afp = rafp; argc--; argv++;
break;
}
rafp = afp;
af = ifr.ifr_addr.sa_family = rafp->af_af;
}
s = socket(af, SOCK_DGRAM, 0);
if (s < 0) {
perror("ifconfig: socket");
exit(1);
}
if (strstr(name, "-a")) {
char *buffer;
struct ifconf ifc;
struct ifreq *ifptr, *end;
int ifflags, selectflag = -1;
int oldbufsize, bufsize = sizeof(struct ifreq);
if (strstr(name, "-au"))
selectflag = 1;
if (strstr(name, "-ad"))
selectflag = 0;
buffer = malloc(bufsize); /* allocate first buffer */
ifc.ifc_len = bufsize; /* Initial setting */
/*
* Itterate through here until we don't get any more data
*/
do {
oldbufsize = ifc.ifc_len;
bufsize += 1+sizeof(struct ifreq);
buffer = realloc((void *)buffer, bufsize);
ifc.ifc_len = bufsize;
ifc.ifc_buf = buffer;
if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) {
perror("ifconfig (SIOCGIFCONF)");
exit (1);
}
} while (ifc.ifc_len > oldbufsize);
ifflags = ifc.ifc_req->ifr_flags;
end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
ifptr = ifc.ifc_req;
while (ifptr < end) {
sprintf(ifr.ifr_name,"%s",ifptr->ifr_name);
sprintf(name,"%s",ifptr->ifr_name);
close(s);
if ((s = socket(af, SOCK_DGRAM, 0)) < 0) {
perror("ifconfig: socket");
exit(1);
}
if (ifptr->ifr_flags == ifflags)
ifconfig(argc,argv,af,rafp,selectflag);
if(ifptr->ifr_addr.sa_len) /* Dohw! */
ifptr = (struct ifreq *) ((caddr_t) ifptr +
ifptr->ifr_addr.sa_len -
sizeof(struct sockaddr));
ifptr++;
}
free(buffer);
} else
ifconfig(argc,argv,af,rafp, -1);
exit (0);
}
ifconfig(argc,argv,af,rafp,flag)
int argc;
char *argv[];
int af;
struct afswtch *rafp;
int flag;
{
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
Perror("ioctl (SIOCGIFFLAGS)");
exit(1);
}
switch(flag) {
case 0:
if (ifr.ifr_flags & IFF_UP)
return(0);
break;
case 1:
if (!(ifr.ifr_flags & IFF_UP))
return(0);
break;
case -1:
default:
break;
}
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
flags = ifr.ifr_flags;
if (ioctl(s, SIOCGIFMETRIC, (caddr_t)&ifr) < 0)
perror("ioctl (SIOCGIFMETRIC)");
else
metric = ifr.ifr_metric;
if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0)
perror("ioctl (SIOCGIFMTU)");
else
mtu = ifr.ifr_mtu;
if (argc == 0) {
status();
return(0);
}
while (argc > 0) {
register struct cmd *p;
for (p = cmds; p->c_name; p++)
if (strcmp(*argv, p->c_name) == 0)
break;
if (p->c_name == 0 && setaddr)
p++; /* got src, do dst */
if (p->c_func) {
if (p->c_parameter == NEXTARG) {
if (argv[1] == NULL)
errx(1, "'%s' requires argument",
p->c_name);
(*p->c_func)(argv[1]);
argc--, argv++;
} else
(*p->c_func)(*argv, p->c_parameter);
}
argc--, argv++;
}
if (af == AF_ISO)
adjust_nsellength();
if (setipdst && af==AF_IPX) {
struct ipxip_req rq;
int size = sizeof(rq);
rq.rq_ipx = addreq.ifra_addr;
rq.rq_ip = addreq.ifra_dstaddr;
if (setsockopt(s, 0, SO_IPXIP_ROUTE, &rq, size) < 0)
Perror("Encapsulation Routing");
}
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)
Perror("Encapsulation Routing");
}
if (clearaddr) {
int ret;
strncpy(rafp->af_ridreq, name, sizeof ifr.ifr_name);
if ((ret = ioctl(s, rafp->af_difaddr, rafp->af_ridreq)) < 0) {
if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
/* means no previous address for interface */
} else
Perror("ioctl (SIOCDIFADDR)");
}
}
if (newaddr) {
strncpy(rafp->af_addreq, name, sizeof ifr.ifr_name);
if (ioctl(s, rafp->af_aifaddr, rafp->af_addreq) < 0)
Perror("ioctl (SIOCAIFADDR)");
}
return(0);
}
#define RIDADDR 0
#define ADDR 1
#define MASK 2
#define DSTADDR 3
/*ARGSUSED*/
setifaddr(addr, param)
char *addr;
short param;
{
/*
* 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 (doalias == 0)
clearaddr = 1;
(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
}
setifnetmask(addr)
char *addr;
{
(*afp->af_getaddr)(addr, MASK);
}
setifbroadaddr(addr)
char *addr;
{
(*afp->af_getaddr)(addr, DSTADDR);
}
setifipdst(addr)
char *addr;
{
in_getaddr(addr, DSTADDR);
setipdst++;
clearaddr = 0;
newaddr = 0;
}
#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
/*ARGSUSED*/
notealias(addr, param)
char *addr;
{
if (setaddr && doalias == 0 && param < 0)
bcopy((caddr_t)rqtosa(af_addreq),
(caddr_t)rqtosa(af_ridreq),
rqtosa(af_addreq)->sa_len);
doalias = param;
if (param < 0) {
clearaddr = 1;
newaddr = 0;
} else
clearaddr = 0;
}
/*ARGSUSED*/
notrailers(vname, value)
char *vname;
int value;
{
printf("Note: trailers are no longer sent, but always received\n");
}
/*ARGSUSED*/
setifdstaddr(addr, param)
char *addr;
int param;
{
(*afp->af_getaddr)(addr, DSTADDR);
}
setifflags(vname, value)
char *vname;
short value;
{
if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
Perror("ioctl (SIOCGIFFLAGS)");
exit(1);
}
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
flags = ifr.ifr_flags;
if (value < 0) {
value = -value;
flags &= ~value;
} else
flags |= value;
ifr.ifr_flags = flags;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
Perror(vname);
}
setifmetric(val)
char *val;
{
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_metric = atoi(val);
if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
perror("ioctl (set metric)");
}
setifmtu(val)
char *val;
{
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_mtu = atoi(val);
if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
perror("ioctl (set mtu)");
}
setsnpaoffset(val)
char *val;
{
iso_addreq.ifra_snpaoffset = atoi(val);
}
#define IFFBITS \
"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
/*
* Print the status of the interface. If an address family was
* specified, show it and it only; otherwise, show them all.
*/
status()
{
register struct afswtch *p = afp;
short af = ifr.ifr_addr.sa_family;
printf("%s: ", name);
printb("flags", flags, IFFBITS);
if (metric)
printf(" metric %d", metric);
if (mtu)
printf(" mtu %d", mtu);
putchar('\n');
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);
}
}
in_status(force)
int force;
{
struct sockaddr_in *sin;
char *inet_ntoa();
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;
bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
} else
perror("ioctl (SIOCGIFADDR)");
}
sin = (struct sockaddr_in *)&ifr.ifr_addr;
printf("\tinet %s ", inet_ntoa(sin->sin_addr));
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
if (errno != EADDRNOTAVAIL)
perror("ioctl (SIOCGIFNETMASK)");
bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
} else
netmask.sin_addr =
((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
if (flags & IFF_POINTOPOINT) {
if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
if (errno == EADDRNOTAVAIL)
bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
else
perror("ioctl (SIOCGIFDSTADDR)");
}
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
printf("--> %s ", inet_ntoa(sin->sin_addr));
}
printf("netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
if (flags & IFF_BROADCAST) {
if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
if (errno == EADDRNOTAVAIL)
bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
else
perror("ioctl (SIOCGIFADDR)");
}
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
sin = (struct sockaddr_in *)&ifr.ifr_addr;
if (sin->sin_addr.s_addr != 0)
printf("broadcast %s", inet_ntoa(sin->sin_addr));
}
putchar('\n');
}
ipx_status(force)
int force;
{
struct sockaddr_ipx *sipx;
close(s);
s = socket(AF_IPX, SOCK_DGRAM, 0);
if (s < 0) {
if (errno == EPROTONOSUPPORT)
return;
perror("ifconfig: socket");
exit(1);
}
if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
if (!force)
return;
bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
} else
perror("ioctl (SIOCGIFADDR)");
}
strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
sipx = (struct sockaddr_ipx *)&ifr.ifr_addr;
printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
if (errno == EADDRNOTAVAIL)
bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
else
Perror("ioctl (SIOCGIFDSTADDR)");
}
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
sipx = (struct sockaddr_ipx *)&ifr.ifr_dstaddr;
printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
}
putchar('\n');
}
xns_status(force)
int force;
{
struct sockaddr_ns *sns;
close(s);
s = socket(AF_NS, SOCK_DGRAM, 0);
if (s < 0) {
if (errno == EPROTONOSUPPORT)
return;
perror("ifconfig: socket");
exit(1);
}
if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
if (!force)
return;
bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
} else
perror("ioctl (SIOCGIFADDR)");
}
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)
bzero((char *)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
else
Perror("ioctl (SIOCGIFDSTADDR)");
}
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');
}
iso_status(force)
int force;
{
struct sockaddr_iso *siso;
struct iso_ifreq ifr;
close(s);
s = socket(AF_ISO, SOCK_DGRAM, 0);
if (s < 0) {
if (errno == EPROTONOSUPPORT)
return;
perror("ifconfig: socket");
exit(1);
}
bzero((caddr_t)&ifr, sizeof(ifr));
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;
bzero((char *)&ifr.ifr_Addr, sizeof(ifr.ifr_Addr));
} else {
perror("ioctl (SIOCGIFADDR_ISO)");
exit(1);
}
}
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)
perror("ioctl (SIOCGIFNETMASK_ISO)");
} else {
printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
}
if (flags & IFF_POINTOPOINT) {
if (ioctl(s, SIOCGIFDSTADDR_ISO, (caddr_t)&ifr) < 0) {
if (errno == EADDRNOTAVAIL)
bzero((char *)&ifr.ifr_Addr, sizeof(ifr.ifr_Addr));
else
Perror("ioctl (SIOCGIFDSTADDR_ISO)");
}
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
siso = &ifr.ifr_Addr;
printf("--> %s ", iso_ntoa(&siso->siso_addr));
}
putchar('\n');
}
kread(addr, buf, size)
u_long addr;
char *buf;
int size;
{
if (kvm_read(kvmd, addr, buf, size) != size)
return (-1);
return (0);
}
/* Unashamedly stolen from netstat -- maybe someday we can us sysctl() */
ether_status()
{
struct nlist nl[] = { { "_ifnet" } , "" };
u_long addr, addr2;
struct ifnet ifnet;
union {
struct ifaddr ifa;
struct in_ifaddr in;
struct ns_ifaddr ns;
struct iso_ifaddr iso;
} ifaddr;
char *cp;
struct sockaddr *sa;
struct sockaddr_dl *sdl;
int n,m;
char ifacename[IFNAMSIZ];
/*
* If we fail here it probably means we don't have permission to
* read /dev/kmem. Best to just silently bail out. If we have
* an error *after* we succeed in opening /dev/kmem, then we
* should report it.
*/
if ((kvmd = kvm_open(NULL,NULL,NULL,O_RDONLY,NULL)) == NULL)
return;
if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
perror("ifconfig: kvm_nlist()");
return;
}
if (kread(nl[0].n_value, (char *)&addr, sizeof(addr))) {
perror("_ifnet");
return;
}
addr2 = 0;
while (addr || addr2) {
if (addr2 == 0) {
if (kread(addr, (char *)&ifnet, sizeof ifnet) ||
kread((u_long)ifnet.if_name, ifacename, IFNAMSIZ)){
perror("ifconfig: kvm_read()");
return;
}
addr = (u_long)ifnet.if_next;
addr2 = (u_long)ifnet.if_addrlist;
}
if (kread(addr2, (char *)&ifaddr, sizeof ifaddr)) {
addr2 = 0;
continue;
}
sprintf(ifacename,"%s%d",ifacename, ifnet.if_unit);
if (!strncmp(name, ifacename, strlen(name))) {
#define CP(x) ((char *)(x))
cp = (CP(ifaddr.ifa.ifa_addr) - CP(addr2)) +
CP(&ifaddr); sa = (struct sockaddr *)cp;
if (sa->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *)sa;
cp = (char *)LLADDR(sdl);
if ((n = sdl->sdl_alen) > 0) {
printf ("\tether ");
while (--n >= 0)
m += printf("%02x%c",
*cp++ & 0xff,
n > 0 ? ':' : ' ');
putchar('\n');
}
break;
}
}
addr2 = (u_long)ifaddr.ifa.ifa_next;
}
kvm_close(kvmd);
}
Perror(cmd)
char *cmd;
{
extern int errno;
switch (errno) {
case ENXIO:
errx(1, "%s: no such interface", cmd);
break;
case EPERM:
errx(1, "%s: permission denied", cmd);
break;
default:
err(1, "%s", cmd);
}
}
struct in_addr inet_makeaddr();
#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)};
in_getaddr(s, which)
char *s;
{
register struct sockaddr_in *sin = sintab[which];
struct hostent *hp;
struct netent *np;
int val;
sin->sin_len = sizeof(*sin);
if (which != MASK)
sin->sin_family = AF_INET;
if (inet_aton(s, &sin->sin_addr))
;
else if (hp = gethostbyname(s))
bcopy(hp->h_addr, (char *)&sin->sin_addr, hp->h_length);
else if (np = getnetbyname(s))
sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
else
errx(1, "%s: bad value", s);
}
/*
* Print a value a la the %b format of the kernel's printf
*/
printb(s, v, bits)
char *s;
register char *bits;
register unsigned short v;
{
register int i, any = 0;
register char c;
if (bits && *bits == 8)
printf("%s=%o", s, v);
else
printf("%s=%x", s, v);
bits++;
if (bits) {
putchar('<');
while (i = *bits++) {
if (v & (1 << (i-1))) {
if (any)
putchar(',');
any = 1;
for (; (c = *bits) > 32; bits++)
putchar(c);
} else
for (; *bits > 32; bits++)
;
}
putchar('>');
}
}
#define SIPX(x) ((struct sockaddr_ipx *) &(x))
struct sockaddr_ipx *sipxtab[] = {
SIPX(ridreq.ifr_addr), SIPX(addreq.ifra_addr),
SIPX(addreq.ifra_mask), SIPX(addreq.ifra_broadaddr)};
ipx_getaddr(addr, which)
char *addr;
{
struct sockaddr_ipx *sipx = sipxtab[which];
struct ipx_addr ipx_addr();
sipx->sipx_family = AF_IPX;
sipx->sipx_len = sizeof(*sipx);
sipx->sipx_addr = ipx_addr(addr);
if (which == MASK)
printf("Attempt to set IPX netmask will be ineffectual\n");
}
#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)};
xns_getaddr(addr, which)
char *addr;
{
struct sockaddr_ns *sns = snstab[which];
struct ns_addr ns_addr();
sns->sns_family = AF_NS;
sns->sns_len = sizeof(*sns);
sns->sns_addr = ns_addr(addr);
if (which == MASK)
printf("Attempt to set XNS netmask will be ineffectual\n");
}
#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)};
iso_getaddr(addr, which)
char *addr;
{
register struct sockaddr_iso *siso = sisotab[which];
struct iso_addr *iso_addr();
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;
}
}
setnsellength(val)
char *val;
{
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");
}
fixnsel(s)
register struct sockaddr_iso *s;
{
if (s->siso_family == 0)
return;
s->siso_tlen = nsellength;
}
adjust_nsellength()
{
fixnsel(sisotab[RIDADDR]);
fixnsel(sisotab[ADDR]);
fixnsel(sisotab[DSTADDR]);
}