ifconfig.c revision 1.27
1/*	$NetBSD: ifconfig.c,v 1.27 1997/03/18 05:04:50 thorpej Exp $	*/
2
3/*
4 * Copyright (c) 1997 Jason R. Thorpe.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *      This product includes software developed for the NetBSD Project
18 *	by Jason R. Thorpe.
19 * 4. The name of the author may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35/*
36 * Copyright (c) 1983, 1993
37 *	The Regents of the University of California.  All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 *    notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 *    notice, this list of conditions and the following disclaimer in the
46 *    documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 *    must display the following acknowledgement:
49 *	This product includes software developed by the University of
50 *	California, Berkeley and its contributors.
51 * 4. Neither the name of the University nor the names of its contributors
52 *    may be used to endorse or promote products derived from this software
53 *    without specific prior written permission.
54 *
55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 * SUCH DAMAGE.
66 */
67
68#ifndef lint
69static char copyright[] =
70"@(#) Copyright (c) 1983, 1993\n\
71	The Regents of the University of California.  All rights reserved.\n";
72#endif /* not lint */
73
74#ifndef lint
75#if 0
76static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
77#else
78static char rcsid[] = "$NetBSD: ifconfig.c,v 1.27 1997/03/18 05:04:50 thorpej Exp $";
79#endif
80#endif /* not lint */
81
82#include <sys/param.h>
83#include <sys/socket.h>
84#include <sys/ioctl.h>
85
86#include <net/if.h>
87#include <net/if_media.h>
88#include <netinet/in.h>
89#include <arpa/inet.h>
90
91#define	NSIP
92#include <netns/ns.h>
93#include <netns/ns_if.h>
94#include <netdb.h>
95
96#define EON
97#include <netiso/iso.h>
98#include <netiso/iso_var.h>
99#include <sys/protosw.h>
100
101#include <ctype.h>
102#include <err.h>
103#include <errno.h>
104#include <stdio.h>
105#include <stdlib.h>
106#include <string.h>
107#include <unistd.h>
108
109struct	ifreq		ifr, ridreq;
110struct	ifaliasreq	addreq;
111struct	iso_aliasreq	iso_addreq;
112struct	sockaddr_in	netmask;
113char	name[30];
114int	flags, metric, setaddr, setipdst, doalias;
115int	clearaddr, s;
116int	newaddr = 1;
117int	nsellength = 1;
118int	af;
119int	mflag;
120
121void 	notealias __P((char *, int));
122void 	notrailers __P((char *, int));
123void 	setifaddr __P((char *, int));
124void 	setifdstaddr __P((char *, int));
125void 	setifflags __P((char *, int));
126void 	setifbroadaddr __P((char *));
127void 	setifipdst __P((char *));
128void 	setifmetric __P((char *));
129void 	setifnetmask __P((char *));
130void 	setnsellength __P((char *));
131void 	setsnpaoffset __P((char *));
132void	setmedia __P((char *));
133void	setmediaopt __P((char *));
134void	unsetmediaopt __P((char *));
135
136#define	NEXTARG		0xffffff
137
138struct	cmd {
139	char	*c_name;
140	int	c_parameter;		/* NEXTARG means next argv */
141	void	(*c_func)();
142} cmds[] = {
143	{ "up",		IFF_UP,		setifflags } ,
144	{ "down",	-IFF_UP,	setifflags },
145	{ "trailers",	-1,		notrailers },
146	{ "-trailers",	1,		notrailers },
147	{ "arp",	-IFF_NOARP,	setifflags },
148	{ "-arp",	IFF_NOARP,	setifflags },
149	{ "debug",	IFF_DEBUG,	setifflags },
150	{ "-debug",	-IFF_DEBUG,	setifflags },
151	{ "alias",	IFF_UP,		notealias },
152	{ "-alias",	-IFF_UP,	notealias },
153	{ "delete",	-IFF_UP,	notealias },
154#ifdef notdef
155#define	EN_SWABIPS	0x1000
156	{ "swabips",	EN_SWABIPS,	setifflags },
157	{ "-swabips",	-EN_SWABIPS,	setifflags },
158#endif
159	{ "netmask",	NEXTARG,	setifnetmask },
160	{ "metric",	NEXTARG,	setifmetric },
161	{ "broadcast",	NEXTARG,	setifbroadaddr },
162	{ "ipdst",	NEXTARG,	setifipdst },
163#ifndef INET_ONLY
164	{ "snpaoffset",	NEXTARG,	setsnpaoffset },
165	{ "nsellength",	NEXTARG,	setnsellength },
166#endif	/* INET_ONLY */
167	{ "link0",	IFF_LINK0,	setifflags } ,
168	{ "-link0",	-IFF_LINK0,	setifflags } ,
169	{ "link1",	IFF_LINK1,	setifflags } ,
170	{ "-link1",	-IFF_LINK1,	setifflags } ,
171	{ "link2",	IFF_LINK2,	setifflags } ,
172	{ "-link2",	-IFF_LINK2,	setifflags } ,
173	{ "media",	NEXTARG,	setmedia },
174	{ "mediaopt",	NEXTARG,	setmediaopt },
175	{ "-mediaopt",	NEXTARG,	unsetmediaopt },
176	{ 0,		0,		setifaddr },
177	{ 0,		0,		setifdstaddr },
178};
179
180void 	adjust_nsellength();
181int	getinfo __P((struct ifreq *));
182void	getsock __P((int));
183void	printall __P((void));
184void 	printb __P((char *, unsigned short, char *));
185void 	status();
186void 	usage();
187
188void	domediaopt __P((char *, int));
189int	get_media_subtype __P((int, char *));
190int	get_media_options __P((int, char *));
191int	lookup_media_word __P((struct ifmedia_description *, char *));
192void	print_media_word __P((int));
193
194/*
195 * XNS support liberally adapted from code written at the University of
196 * Maryland principally by James O'Toole and Chris Torek.
197 */
198void	in_status __P((int));
199void 	in_getaddr __P((char *, int));
200void 	xns_status __P((int));
201void 	xns_getaddr __P((char *, int));
202void 	iso_status __P((int));
203void 	iso_getaddr __P((char *, int));
204
205/* Known address families */
206struct afswtch {
207	char *af_name;
208	short af_af;
209	void (*af_status)();
210	void (*af_getaddr)();
211	u_long af_difaddr;
212	u_long af_aifaddr;
213	caddr_t af_ridreq;
214	caddr_t af_addreq;
215} afs[] = {
216#define C(x) ((caddr_t) &x)
217	{ "inet", AF_INET, in_status, in_getaddr,
218	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
219#ifndef INET_ONLY	/* small version, for boot media */
220	{ "ns", AF_NS, xns_status, xns_getaddr,
221	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(addreq) },
222	{ "iso", AF_ISO, iso_status, iso_getaddr,
223	     SIOCDIFADDR, SIOCAIFADDR, C(ridreq), C(iso_addreq) },
224#endif	/* INET_ONLY */
225	{ 0,	0,	    0,		0 }
226};
227
228struct afswtch *afp;	/*the address family being set or asked about*/
229
230struct afswtch *lookup_af __P((const char *));
231
232int
233main(argc, argv)
234	int argc;
235	char *argv[];
236{
237	extern int optind;
238	int ch, aflag;
239
240	/* Parse command-line options */
241	aflag = mflag = 0;
242	while ((ch = getopt(argc, argv, "am")) != -1) {
243		switch (ch) {
244		case 'a':
245			aflag = 1;
246			break;
247
248		case 'm':
249			mflag = 1;
250			break;
251
252		default:
253			usage();
254			/* NOTREACHED */
255		}
256	}
257	argc -= optind;
258	argv += optind;
259
260	/* -a means print all interfaces */
261	if (aflag) {
262		if (argc > 1)
263			usage();
264		else if (argc == 1) {
265			afp = lookup_af(argv[0]);
266			if (afp == NULL)
267				usage();
268		} else
269			afp = afs;
270		af = ifr.ifr_addr.sa_family = afp->af_af;
271
272		printall();
273		exit(0);
274	}
275
276	/* Make sure there's an interface name. */
277	if (argc < 1)
278		usage();
279	strncpy(name, argv[0], sizeof(name));
280	argc--; argv++;
281
282	/* Check for address family. */
283	afp = NULL;
284	if (argc > 0) {
285		afp = lookup_af(argv[0]);
286		if (afp != NULL) {
287			argv++;
288			argc--;
289		}
290	}
291
292	if (afp == NULL)
293		afp = afs;
294	af = ifr.ifr_addr.sa_family = afp->af_af;
295
296	/* Get information about the interface. */
297	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
298	if (getinfo(&ifr) < 0)
299		exit(1);
300
301	/* No more arguments means interface status. */
302	if (argc == 0) {
303		status();
304		exit(0);
305	}
306
307	/* Process commands. */
308	while (argc > 0) {
309		register struct cmd *p;
310
311		for (p = cmds; p->c_name; p++)
312			if (strcmp(argv[0], p->c_name) == 0)
313				break;
314		if (p->c_name == 0 && setaddr)
315			p++;	/* got src, do dst */
316		if (p->c_func) {
317			if (p->c_parameter == NEXTARG) {
318				if (argc < 2)
319					errx(1, "'%s' requires argument",
320					    p->c_name);
321				(*p->c_func)(argv[1]);
322				argc--, argv++;
323			} else
324				(*p->c_func)(argv[0], p->c_parameter);
325		}
326		argc--, argv++;
327	}
328
329#ifndef INET_ONLY
330
331	if (af == AF_ISO)
332		adjust_nsellength();
333	if (setipdst && af==AF_NS) {
334		struct nsip_req rq;
335		int size = sizeof(rq);
336
337		rq.rq_ns = addreq.ifra_addr;
338		rq.rq_ip = addreq.ifra_dstaddr;
339
340		if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0)
341			warn("encapsulation routing");
342	}
343
344#endif	/* INET_ONLY */
345
346	if (clearaddr) {
347		int ret;
348		strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
349		if ((ret = ioctl(s, afp->af_difaddr, afp->af_ridreq)) < 0) {
350			if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
351				/* means no previous address for interface */
352			} else
353				warn("SIOCDIFADDR");
354		}
355	}
356	if (newaddr) {
357		strncpy(afp->af_addreq, name, sizeof ifr.ifr_name);
358		if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
359			warn("SIOCAIFADDR");
360	}
361	exit(0);
362}
363
364struct afswtch *
365lookup_af(cp)
366	const char *cp;
367{
368	struct afswtch *a;
369
370	for (a = afs; a->af_name != NULL; a++)
371		if (strcmp(a->af_name, cp) == 0)
372			return (a);
373	return (NULL);
374}
375
376void
377getsock(naf)
378	int naf;
379{
380	static int oaf = -1;
381
382	if (oaf == naf)
383		return;
384	if (oaf != -1)
385		close(s);
386	s = socket(naf, SOCK_DGRAM, 0);
387	if (s < 0)
388		oaf = -1;
389	else
390		oaf = naf;
391}
392
393int
394getinfo(ifr)
395	struct ifreq *ifr;
396{
397
398	getsock(af);
399	if (s < 0)
400		err(1, "socket");
401	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
402		warn("SIOCGIFFLAGS");
403		return (-1);
404	}
405	flags = ifr->ifr_flags;
406	if (ioctl(s, SIOCGIFMETRIC, (caddr_t)ifr) < 0) {
407		warn("SIOCGIFMETRIC");
408		metric = 0;
409	} else
410		metric = ifr->ifr_metric;
411	return (0);
412}
413
414void
415printall()
416{
417	char inbuf[8192];
418	struct ifconf ifc;
419	struct ifreq ifreq, *ifr;
420	int i;
421
422	ifc.ifc_len = sizeof(inbuf);
423	ifc.ifc_buf = inbuf;
424	getsock(af);
425	if (s < 0)
426		err(1, "socket");
427	if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
428		err(1, "SIOCGIFCONF");
429	ifr = ifc.ifc_req;
430	ifreq.ifr_name[0] = '\0';
431	for (i = 0; i < ifc.ifc_len; ) {
432		ifr = (struct ifreq *)((caddr_t)ifc.ifc_req + i);
433		i += sizeof(ifr->ifr_name) +
434			(ifr->ifr_addr.sa_len > sizeof(struct sockaddr)
435				? ifr->ifr_addr.sa_len
436				: sizeof(struct sockaddr));
437		if (!strncmp(ifreq.ifr_name, ifr->ifr_name,
438			     sizeof(ifr->ifr_name)))
439			continue;
440		strncpy(name, ifr->ifr_name, sizeof(ifr->ifr_name));
441		ifreq = *ifr;
442		if (getinfo(&ifreq) < 0)
443			continue;
444		status();
445	}
446}
447
448#define RIDADDR 0
449#define ADDR	1
450#define MASK	2
451#define DSTADDR	3
452
453/*ARGSUSED*/
454void
455setifaddr(addr, param)
456	char *addr;
457	int param;
458{
459	/*
460	 * Delay the ioctl to set the interface addr until flags are all set.
461	 * The address interpretation may depend on the flags,
462	 * and the flags may change when the address is set.
463	 */
464	setaddr++;
465	if (doalias == 0)
466		clearaddr = 1;
467	(*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR));
468}
469
470void
471setifnetmask(addr)
472	char *addr;
473{
474	(*afp->af_getaddr)(addr, MASK);
475}
476
477void
478setifbroadaddr(addr)
479	char *addr;
480{
481	(*afp->af_getaddr)(addr, DSTADDR);
482}
483
484void
485setifipdst(addr)
486	char *addr;
487{
488	in_getaddr(addr, DSTADDR);
489	setipdst++;
490	clearaddr = 0;
491	newaddr = 0;
492}
493
494#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
495/*ARGSUSED*/
496void
497notealias(addr, param)
498	char *addr;
499	int param;
500{
501	if (setaddr && doalias == 0 && param < 0)
502		memcpy(rqtosa(af_ridreq),
503		       rqtosa(af_addreq),
504		       rqtosa(af_addreq)->sa_len);
505	doalias = param;
506	if (param < 0) {
507		clearaddr = 1;
508		newaddr = 0;
509	} else
510		clearaddr = 0;
511}
512
513/*ARGSUSED*/
514void
515notrailers(vname, value)
516	char *vname;
517	int value;
518{
519	printf("Note: trailers are no longer sent, but always received\n");
520}
521
522/*ARGSUSED*/
523void
524setifdstaddr(addr, param)
525	char *addr;
526	int param;
527{
528	(*afp->af_getaddr)(addr, DSTADDR);
529}
530
531void
532setifflags(vname, value)
533	char *vname;
534	int value;
535{
536 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0)
537		err(1, "SIOCGIFFLAGS");
538	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
539 	flags = ifr.ifr_flags;
540
541	if (value < 0) {
542		value = -value;
543		flags &= ~value;
544	} else
545		flags |= value;
546	ifr.ifr_flags = flags;
547	if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0)
548		err(1, "SIOCSIFFLAGS");
549}
550
551void
552setifmetric(val)
553	char *val;
554{
555	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
556	ifr.ifr_metric = atoi(val);
557	if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
558		warn("SIOCSIFMETRIC");
559}
560
561void
562setmedia(val)
563	char *val;
564{
565	struct ifmediareq ifmr;
566	int first_type, subtype;
567
568	memset(&ifmr, 0, sizeof(ifmr));
569	strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
570
571	ifmr.ifm_count = 1;
572	ifmr.ifm_ulist = &first_type;
573	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
574		/*
575		 * If we get E2BIG, the kernel is telling us
576		 * that there are more, so we can ignore it.
577		 */
578		if (errno != E2BIG)
579			err(1, "SIOCGIFMEDIA");
580	}
581
582	if (ifmr.ifm_count == 0)
583		errx(1, "%s: no media types?", name);
584
585	/*
586	 * We are primarily concerned with the top-level type.
587	 * However, "current" may be only IFM_NONE, so we just look
588	 * for the top-level type in the first "supported type"
589	 * entry.
590	 *
591	 * (I'm assuming that all supported media types for a given
592	 * interface will be the same top-level type..)
593	 */
594	subtype = get_media_subtype(IFM_TYPE(first_type), val);
595
596	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
597	ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
598	    IFM_TYPE(first_type) | subtype;
599
600	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
601		err(1, "SIOCSIFMEDIA");
602}
603
604void
605setmediaopt(val)
606	char *val;
607{
608
609	domediaopt(val, 0);
610}
611
612void
613unsetmediaopt(val)
614	char *val;
615{
616
617	domediaopt(val, 1);
618}
619
620void
621domediaopt(val, clear)
622	char *val;
623	int clear;
624{
625	struct ifmediareq ifmr;
626	int *mwords, options;
627
628	memset(&ifmr, 0, sizeof(ifmr));
629	strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
630
631	/*
632	 * We must go through the motions of reading all
633	 * supported media because we need to know both
634	 * the current media type and the top-level type.
635	 */
636
637	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
638		err(1, "SIOCGIFMEDIA");
639
640	if (ifmr.ifm_count == 0)
641		errx(1, "%s: no media types?", name);
642
643	mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
644	if (mwords == NULL)
645		err(1, "malloc");
646
647	ifmr.ifm_ulist = mwords;
648	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
649		err(1, "SIOCGIFMEDIA");
650
651	options = get_media_options(IFM_TYPE(mwords[0]), val);
652
653	free(mwords);
654
655	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
656	ifr.ifr_media = ifmr.ifm_current;
657	if (clear)
658		ifr.ifr_media &= ~options;
659	else
660		ifr.ifr_media |= options;
661
662	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
663		err(1, "SIOCSIFMEDIA");
664}
665
666/**********************************************************************
667 * A good chunk of this is duplicated from sys/net/ifmedia.c
668 **********************************************************************/
669
670struct ifmedia_description ifm_type_descriptions[] =
671    IFM_TYPE_DESCRIPTIONS;
672
673struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
674    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
675
676struct ifmedia_description ifm_subtype_ethernet_aliases[] =
677    IFM_SUBTYPE_ETHERNET_ALIASES;
678
679struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
680    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
681
682struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
683    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
684
685struct ifmedia_description ifm_subtype_tokenring_aliases[] =
686    IFM_SUBTYPE_TOKENRING_ALIASES;
687
688struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
689    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
690
691struct ifmedia_description ifm_subtype_fddi_descriptions[] =
692    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
693
694struct ifmedia_description ifm_subtype_fddi_aliases[] =
695    IFM_SUBTYPE_FDDI_ALIASES;
696
697struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
698    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
699
700struct ifmedia_description ifm_subtype_shared_descriptions[] =
701    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
702
703struct ifmedia_description ifm_subtype_shared_aliases[] =
704    IFM_SUBTYPE_SHARED_ALIASES;
705
706struct ifmedia_description ifm_shared_option_descriptions[] =
707    IFM_SHARED_OPTION_DESCRIPTIONS;
708
709struct ifmedia_type_to_subtype {
710	struct {
711		struct ifmedia_description *desc;
712		int alias;
713	} subtypes[5];
714	struct {
715		struct ifmedia_description *desc;
716		int alias;
717	} options[3];
718};
719
720/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
721struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
722	{
723		{
724			{ &ifm_subtype_shared_descriptions[0], 0 },
725			{ &ifm_subtype_shared_aliases[0], 1 },
726			{ &ifm_subtype_ethernet_descriptions[0], 0 },
727			{ &ifm_subtype_ethernet_aliases[0], 1 },
728			{ NULL, 0 },
729		},
730		{
731			{ &ifm_shared_option_descriptions[0], 0 },
732			{ &ifm_subtype_ethernet_option_descriptions[0], 1 },
733			{ NULL, 0 },
734		},
735	},
736	{
737		{
738			{ &ifm_subtype_shared_descriptions[0], 0 },
739			{ &ifm_subtype_shared_aliases[0], 1 },
740			{ &ifm_subtype_tokenring_descriptions[0], 0 },
741			{ &ifm_subtype_tokenring_aliases[0], 1 },
742			{ NULL, 0 },
743		},
744		{
745			{ &ifm_shared_option_descriptions[0], 0 },
746			{ &ifm_subtype_tokenring_option_descriptions[0], 1 },
747			{ NULL, 0 },
748		},
749	},
750	{
751		{
752			{ &ifm_subtype_shared_descriptions[0], 0 },
753			{ &ifm_subtype_shared_aliases[0], 1 },
754			{ &ifm_subtype_fddi_descriptions[0], 0 },
755			{ &ifm_subtype_fddi_aliases[0], 1 },
756			{ NULL, 0 },
757		},
758		{
759			{ &ifm_shared_option_descriptions[0], 0 },
760			{ &ifm_subtype_fddi_option_descriptions[0], 1 },
761			{ NULL, 0 },
762		},
763	},
764};
765
766int
767get_media_subtype(type, val)
768	int type;
769	char *val;
770{
771	struct ifmedia_description *desc;
772	struct ifmedia_type_to_subtype *ttos;
773	int rval, i;
774
775	/* Find the top-level interface type. */
776	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
777	    desc->ifmt_string != NULL; desc++, ttos++)
778		if (type == desc->ifmt_word)
779			break;
780	if (desc->ifmt_string == NULL)
781		errx(1, "unknown media type 0x%x", type);
782
783	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
784		rval = lookup_media_word(ttos->subtypes[i].desc, val);
785		if (rval != -1)
786			return (rval);
787	}
788	errx(1, "unknown media subtype: %s", val);
789	/* NOTREACHED */
790}
791
792int
793get_media_options(type, val)
794	int type;
795	char *val;
796{
797	struct ifmedia_description *desc;
798	struct ifmedia_type_to_subtype *ttos;
799	char *optlist;
800	int option, i, rval = 0;
801
802	/* We muck with the string, so copy it. */
803	optlist = strdup(val);
804	if (optlist == NULL)
805		err(1, "strdup");
806	val = optlist;
807
808	/* Find the top-level interface type. */
809	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
810	    desc->ifmt_string != NULL; desc++, ttos++)
811		if (type == desc->ifmt_word)
812			break;
813	if (desc->ifmt_string == NULL)
814		errx(1, "unknown media type 0x%x", type);
815
816	/*
817	 * Look up the options in the user-provided comma-separated
818	 * list.
819	 */
820	for (; (val = strtok(val, ",")) != NULL; val = NULL) {
821		for (i = 0; ttos->options[i].desc != NULL; i++) {
822			option = lookup_media_word(ttos->options[i].desc, val);
823			if (option != -1)
824				break;
825		}
826		if (option == 0)
827			errx(1, "unknown option: %s", val);
828		rval |= option;
829	}
830
831	free(optlist);
832	return (rval);
833}
834
835int
836lookup_media_word(desc, val)
837	struct ifmedia_description *desc;
838	char *val;
839{
840
841	for (; desc->ifmt_string != NULL; desc++)
842		if (strcasecmp(desc->ifmt_string, val) == 0)
843			return (desc->ifmt_word);
844
845	return (-1);
846}
847
848void
849print_media_word(ifmw)
850	int ifmw;
851{
852	struct ifmedia_description *desc;
853	struct ifmedia_type_to_subtype *ttos;
854	int seen_option = 0, i;
855
856	/* Find the top-level interface type. */
857	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
858	    desc->ifmt_string != NULL; desc++, ttos++)
859		if (IFM_TYPE(ifmw) == desc->ifmt_word)
860			break;
861	if (desc->ifmt_string == NULL) {
862		printf("<unknown type>");
863		return;
864	}
865
866	/*
867	 * Don't print the top-level type; it's not like we can
868	 * change it, or anything.
869	 */
870
871	/* Find subtype. */
872	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
873		if (ttos->subtypes[i].alias)
874			continue;
875		for (desc = ttos->subtypes[i].desc;
876		    desc->ifmt_string != NULL; desc++) {
877			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
878				goto got_subtype;
879		}
880	}
881
882	/* Falling to here means unknown subtype. */
883	printf("<unknown subtype>");
884	return;
885
886 got_subtype:
887	printf("%s", desc->ifmt_string);
888
889	/* Find options. */
890	for (i = 0; ttos->options[i].desc != NULL; i++) {
891		if (ttos->options[i].alias)
892			continue;
893		for (desc = ttos->options[i].desc;
894		    desc->ifmt_string != NULL; desc++) {
895			if (ifmw & desc->ifmt_word) {
896				if (seen_option == 0)
897					printf(" <");
898				printf("%s%s", seen_option++ ? "," : "",
899				    desc->ifmt_string);
900			}
901		}
902	}
903	printf("%s", seen_option ? ">" : "");
904}
905
906/**********************************************************************
907 * ...until here.
908 **********************************************************************/
909
910#define	IFFBITS \
911"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\
912\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST"
913
914/*
915 * Print the status of the interface.  If an address family was
916 * specified, show it and it only; otherwise, show them all.
917 */
918void
919status()
920{
921	register struct afswtch *p = afp;
922	struct ifmediareq ifmr;
923	int *media_list, i;
924
925	printf("%s: ", name);
926	printb("flags", flags, IFFBITS);
927	if (metric)
928		printf(" metric %d", metric);
929	putchar('\n');
930
931	memset(&ifmr, 0, sizeof(ifmr));
932	strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
933
934	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
935		/*
936		 * Interface doesn't support SIOC{G,S}IFMEDIA.
937		 */
938		goto proto_status;
939	}
940
941	if (ifmr.ifm_count == 0) {
942		warnx("%s: no media types?", ifr.ifr_name);
943		goto proto_status;
944	}
945
946	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
947	if (media_list == NULL)
948		err(1, "malloc");
949	ifmr.ifm_ulist = media_list;
950
951	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
952		err(1, "SIOCGIFMEDIA");
953
954	printf("\tmedia: ");
955	print_media_word(ifmr.ifm_current);
956	if (ifmr.ifm_active != ifmr.ifm_current) {
957		putchar('(');
958		print_media_word(ifmr.ifm_current);
959		putchar(')');
960	}
961
962	if (ifmr.ifm_status & IFM_AVALID) {
963		printf(" status: ");
964		switch (IFM_TYPE(ifmr.ifm_active)) {
965		case IFM_ETHER:
966			if (ifmr.ifm_status & IFM_ACTIVE)
967				printf("active");
968			else
969				printf("no carrier");
970			break;
971
972		case IFM_FDDI:
973		case IFM_TOKEN:
974			if (ifmr.ifm_status & IFM_ACTIVE)
975				printf("inserted");
976			else
977				printf("no ring");
978			break;
979		}
980	}
981
982	putchar('\n');
983
984	if (mflag) {
985		printf("\tsupported media:");
986		for (i = 0; i < ifmr.ifm_count; i++) {
987			putchar(' ');
988			print_media_word(media_list[i]);
989		}
990		putchar('\n');
991	}
992
993	free(media_list);
994
995 proto_status:
996	if ((p = afp) != NULL) {
997		(*p->af_status)(1);
998	} else for (p = afs; p->af_name; p++) {
999		ifr.ifr_addr.sa_family = p->af_af;
1000		(*p->af_status)(0);
1001	}
1002}
1003
1004void
1005in_status(force)
1006	int force;
1007{
1008	struct sockaddr_in *sin;
1009	char *inet_ntoa();
1010
1011	getsock(AF_INET);
1012	if (s < 0) {
1013		if (errno == EPROTONOSUPPORT)
1014			return;
1015		err(1, "socket");
1016	}
1017	memset(&ifr, 0, sizeof(ifr));
1018	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1019	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1020		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1021			if (!force)
1022				return;
1023			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1024		} else
1025			warn("SIOCGIFADDR");
1026	}
1027	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1028	sin = (struct sockaddr_in *)&ifr.ifr_addr;
1029	printf("\tinet %s ", inet_ntoa(sin->sin_addr));
1030	strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1031	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1032		if (errno != EADDRNOTAVAIL)
1033			warn("SIOCGIFNETMASK");
1034		memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1035	} else
1036		netmask.sin_addr =
1037		    ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
1038	if (flags & IFF_POINTOPOINT) {
1039		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1040			if (errno == EADDRNOTAVAIL)
1041			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1042			else
1043			    warn("SIOCGIFDSTADDR");
1044		}
1045		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1046		sin = (struct sockaddr_in *)&ifr.ifr_dstaddr;
1047		printf("--> %s ", inet_ntoa(sin->sin_addr));
1048	}
1049	printf("netmask 0x%x ", ntohl(netmask.sin_addr.s_addr));
1050	if (flags & IFF_BROADCAST) {
1051		if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
1052			if (errno == EADDRNOTAVAIL)
1053			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1054			else
1055			    warn("SIOCGIFBRDADDR");
1056		}
1057		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1058		sin = (struct sockaddr_in *)&ifr.ifr_addr;
1059		if (sin->sin_addr.s_addr != 0)
1060			printf("broadcast %s", inet_ntoa(sin->sin_addr));
1061	}
1062	putchar('\n');
1063}
1064
1065#ifndef INET_ONLY
1066
1067void
1068xns_status(force)
1069	int force;
1070{
1071	struct sockaddr_ns *sns;
1072
1073	getsock(AF_NS);
1074	if (s < 0) {
1075		if (errno == EPROTONOSUPPORT)
1076			return;
1077		err(1, "socket");
1078	}
1079	memset(&ifr, 0, sizeof(ifr));
1080	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1081	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1082		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1083			if (!force)
1084				return;
1085			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1086		} else
1087			warn("SIOCGIFADDR");
1088	}
1089	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1090	sns = (struct sockaddr_ns *)&ifr.ifr_addr;
1091	printf("\tns %s ", ns_ntoa(sns->sns_addr));
1092	if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */
1093		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1094			if (errno == EADDRNOTAVAIL)
1095			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1096			else
1097			    warn("SIOCGIFDSTADDR");
1098		}
1099		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1100		sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr;
1101		printf("--> %s ", ns_ntoa(sns->sns_addr));
1102	}
1103	putchar('\n');
1104}
1105
1106void
1107iso_status(force)
1108	int force;
1109{
1110	struct sockaddr_iso *siso;
1111
1112	getsock(AF_ISO);
1113	if (s < 0) {
1114		if (errno == EPROTONOSUPPORT)
1115			return;
1116		err(1, "socket");
1117	}
1118	memset(&ifr, 0, sizeof(ifr));
1119	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1120	if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
1121		if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) {
1122			if (!force)
1123				return;
1124			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1125		} else
1126			warn("SIOCGIFADDR");
1127	}
1128	strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
1129	siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1130	printf("\tiso %s ", iso_ntoa(&siso->siso_addr));
1131	if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
1132		if (errno == EADDRNOTAVAIL)
1133			memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1134		else
1135			warn("SIOCGIFNETMASK");
1136	} else {
1137		printf(" netmask %s ", iso_ntoa(&siso->siso_addr));
1138	}
1139	if (flags & IFF_POINTOPOINT) {
1140		if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) < 0) {
1141			if (errno == EADDRNOTAVAIL)
1142			    memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr));
1143			else
1144			    warn("SIOCGIFDSTADDR");
1145		}
1146		strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
1147		siso = (struct sockaddr_iso *)&ifr.ifr_addr;
1148		printf("--> %s ", iso_ntoa(&siso->siso_addr));
1149	}
1150	putchar('\n');
1151}
1152
1153#endif	/* INET_ONLY */
1154
1155struct	in_addr inet_makeaddr();
1156
1157#define SIN(x) ((struct sockaddr_in *) &(x))
1158struct sockaddr_in *sintab[] = {
1159SIN(ridreq.ifr_addr), SIN(addreq.ifra_addr),
1160SIN(addreq.ifra_mask), SIN(addreq.ifra_broadaddr)};
1161
1162void
1163in_getaddr(s, which)
1164	char *s;
1165	int which;
1166{
1167	register struct sockaddr_in *sin = sintab[which];
1168	struct hostent *hp;
1169	struct netent *np;
1170
1171	sin->sin_len = sizeof(*sin);
1172	if (which != MASK)
1173		sin->sin_family = AF_INET;
1174
1175	if (inet_aton(s, &sin->sin_addr) == 0) {
1176		if (hp = gethostbyname(s))
1177			memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
1178		else if (np = getnetbyname(s))
1179			sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
1180		else
1181			errx(1, "%s: bad value", s);
1182	}
1183}
1184
1185/*
1186 * Print a value a la the %b format of the kernel's printf
1187 */
1188void
1189printb(s, v, bits)
1190	char *s;
1191	register char *bits;
1192	register unsigned short v;
1193{
1194	register int i, any = 0;
1195	register char c;
1196
1197	if (bits && *bits == 8)
1198		printf("%s=%o", s, v);
1199	else
1200		printf("%s=%x", s, v);
1201	bits++;
1202	if (bits) {
1203		putchar('<');
1204		while (i = *bits++) {
1205			if (v & (1 << (i-1))) {
1206				if (any)
1207					putchar(',');
1208				any = 1;
1209				for (; (c = *bits) > 32; bits++)
1210					putchar(c);
1211			} else
1212				for (; *bits > 32; bits++)
1213					;
1214		}
1215		putchar('>');
1216	}
1217}
1218
1219#ifndef INET_ONLY
1220
1221#define SNS(x) ((struct sockaddr_ns *) &(x))
1222struct sockaddr_ns *snstab[] = {
1223SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr),
1224SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)};
1225
1226void
1227xns_getaddr(addr, which)
1228	char *addr;
1229	int which;
1230{
1231	struct sockaddr_ns *sns = snstab[which];
1232	struct ns_addr ns_addr();
1233
1234	sns->sns_family = AF_NS;
1235	sns->sns_len = sizeof(*sns);
1236	sns->sns_addr = ns_addr(addr);
1237	if (which == MASK)
1238		printf("Attempt to set XNS netmask will be ineffectual\n");
1239}
1240
1241#define SISO(x) ((struct sockaddr_iso *) &(x))
1242struct sockaddr_iso *sisotab[] = {
1243SISO(ridreq.ifr_addr), SISO(iso_addreq.ifra_addr),
1244SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)};
1245
1246void
1247iso_getaddr(addr, which)
1248	char *addr;
1249	int which;
1250{
1251	register struct sockaddr_iso *siso = sisotab[which];
1252	struct iso_addr *iso_addr();
1253	siso->siso_addr = *iso_addr(addr);
1254
1255	if (which == MASK) {
1256		siso->siso_len = TSEL(siso) - (caddr_t)(siso);
1257		siso->siso_nlen = 0;
1258	} else {
1259		siso->siso_len = sizeof(*siso);
1260		siso->siso_family = AF_ISO;
1261	}
1262}
1263
1264void
1265setsnpaoffset(val)
1266	char *val;
1267{
1268	iso_addreq.ifra_snpaoffset = atoi(val);
1269}
1270
1271void
1272setnsellength(val)
1273	char *val;
1274{
1275	nsellength = atoi(val);
1276	if (nsellength < 0)
1277		errx(1, "Negative NSEL length is absurd");
1278	if (afp == 0 || afp->af_af != AF_ISO)
1279		errx(1, "Setting NSEL length valid only for iso");
1280}
1281
1282void
1283fixnsel(s)
1284	register struct sockaddr_iso *s;
1285{
1286	if (s->siso_family == 0)
1287		return;
1288	s->siso_tlen = nsellength;
1289}
1290
1291void
1292adjust_nsellength()
1293{
1294	fixnsel(sisotab[RIDADDR]);
1295	fixnsel(sisotab[ADDR]);
1296	fixnsel(sisotab[DSTADDR]);
1297}
1298
1299#endif	/* INET_ONLY */
1300
1301void
1302usage()
1303{
1304	fprintf(stderr, "usage: ifconfig [ -m ] interface\n%s%s%s%s%s%s%s%s%s",
1305		"\t[ af [ address [ dest_addr ] ] [ up ] [ down ] ",
1306		"[ netmask mask ] ]\n",
1307		"\t[ metric n ]\n",
1308		"\t[ arp | -arp ]\n",
1309		"\t[ media mtype ]\n",
1310		"\t[ mediaopt mopts ]\n",
1311		"\t[ -mediaopt mopts ]\n",
1312		"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n",
1313		"       ifconfig -a [ -m ] [ af ]\n");
1314	exit(1);
1315}
1316