ifmedia.c revision 77385
1/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
2/* $FreeBSD: head/sbin/ifconfig/ifmedia.c 77385 2001-05-29 09:13:44Z phk $ */
3
4/*
5 * Copyright (c) 1997 Jason R. Thorpe.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *      This product includes software developed for the NetBSD Project
19 *	by Jason R. Thorpe.
20 * 4. The name of the author may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36/*
37 * Copyright (c) 1983, 1993
38 *	The Regents of the University of California.  All rights reserved.
39 *
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
42 * are met:
43 * 1. Redistributions of source code must retain the above copyright
44 *    notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 *    notice, this list of conditions and the following disclaimer in the
47 *    documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 *    must display the following acknowledgement:
50 *	This product includes software developed by the University of
51 *	California, Berkeley and its contributors.
52 * 4. Neither the name of the University nor the names of its contributors
53 *    may be used to endorse or promote products derived from this software
54 *    without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 */
68
69#include <sys/param.h>
70#include <sys/ioctl.h>
71#include <sys/socket.h>
72#include <sys/sysctl.h>
73#include <sys/time.h>
74
75#include <net/if.h>
76#include <net/if_dl.h>
77#include <net/if_types.h>
78#include <net/if_media.h>
79#include <net/route.h>
80
81#include <ctype.h>
82#include <err.h>
83#include <errno.h>
84#include <fcntl.h>
85#include <stdio.h>
86#include <stdlib.h>
87#include <string.h>
88#include <unistd.h>
89
90#include "ifconfig.h"
91
92static void	domediaopt __P((const char *, int, int));
93static int	get_media_subtype __P((int, const char *));
94static int	get_media_options __P((int, const char *));
95static int	lookup_media_word __P((struct ifmedia_description *, const char *));
96static void	print_media_word __P((int, int));
97static void	print_media_word_ifconfig __P((int));
98
99static struct ifmedia_description *get_toptype_desc __P((int));
100static struct ifmedia_type_to_subtype *get_toptype_ttos __P((int));
101static struct ifmedia_description *get_subtype_desc __P((int,
102    struct ifmedia_type_to_subtype *ttos));
103
104void
105media_status(s, info)
106	int s;
107	struct rt_addrinfo *info __unused;
108{
109	struct ifmediareq ifmr;
110	int *media_list, i;
111
112	(void) memset(&ifmr, 0, sizeof(ifmr));
113	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
114
115	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
116		/*
117		 * Interface doesn't support SIOC{G,S}IFMEDIA.
118		 */
119		return;
120	}
121
122	if (ifmr.ifm_count == 0) {
123		warnx("%s: no media types?", name);
124		return;
125	}
126
127	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
128	if (media_list == NULL)
129		err(1, "malloc");
130	ifmr.ifm_ulist = media_list;
131
132	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
133		err(1, "SIOCGIFMEDIA");
134
135	printf("\tmedia: ");
136	print_media_word(ifmr.ifm_current, 1);
137	if (ifmr.ifm_active != ifmr.ifm_current) {
138		putchar(' ');
139		putchar('(');
140		print_media_word(ifmr.ifm_active, 0);
141		putchar(')');
142	}
143
144	putchar('\n');
145
146	if (ifmr.ifm_status & IFM_AVALID) {
147		printf("\tstatus: ");
148		switch (IFM_TYPE(ifmr.ifm_active)) {
149		case IFM_ETHER:
150			if (ifmr.ifm_status & IFM_ACTIVE)
151				printf("active");
152			else
153				printf("no carrier");
154			break;
155
156		case IFM_FDDI:
157		case IFM_TOKEN:
158			if (ifmr.ifm_status & IFM_ACTIVE)
159				printf("inserted");
160			else
161				printf("no ring");
162			break;
163		case IFM_IEEE80211:
164			/* XXX: Different value for adhoc? */
165			if (ifmr.ifm_status & IFM_ACTIVE)
166				printf("associated");
167			else
168				printf("no carrier");
169			break;
170		}
171	}
172
173	putchar('\n');
174
175	if (ifmr.ifm_count > 0 && supmedia) {
176		printf("\tsupported media:\n");
177		for (i = 0; i < ifmr.ifm_count; i++) {
178			printf("\t\t");
179			print_media_word_ifconfig(media_list[i]);
180			putchar('\n');
181		}
182	}
183
184	free(media_list);
185}
186
187void
188setmedia(val, d, s, afp)
189	const char *val;
190	int d;
191	int s;
192	const struct afswtch *afp;
193{
194	struct ifmediareq ifmr;
195	int first_type, subtype;
196
197	(void) memset(&ifmr, 0, sizeof(ifmr));
198	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
199
200	ifmr.ifm_count = 1;
201	ifmr.ifm_ulist = &first_type;
202	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
203		/*
204		 * If we get E2BIG, the kernel is telling us
205		 * that there are more, so we can ignore it.
206		 */
207		if (errno != E2BIG)
208			err(1, "SIOCGIFMEDIA");
209	}
210
211	if (ifmr.ifm_count == 0)
212		errx(1, "%s: no media types?", name);
213
214	/*
215	 * We are primarily concerned with the top-level type.
216	 * However, "current" may be only IFM_NONE, so we just look
217	 * for the top-level type in the first "supported type"
218	 * entry.
219	 *
220	 * (I'm assuming that all supported media types for a given
221	 * interface will be the same top-level type..)
222	 */
223	subtype = get_media_subtype(IFM_TYPE(first_type), val);
224
225	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
226	ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
227	    IFM_TYPE(first_type) | subtype;
228
229	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
230		err(1, "SIOCSIFMEDIA");
231}
232
233void
234setmediaopt(val, d, s, afp)
235	const char *val;
236	int d;
237	int s;
238	const struct afswtch *afp;
239{
240
241	domediaopt(val, 0, s);
242}
243
244void
245unsetmediaopt(val, d, s, afp)
246	const char *val;
247	int d;
248	int s;
249	const struct afswtch *afp;
250{
251
252	domediaopt(val, 1, s);
253}
254
255static void
256domediaopt(val, clear, s)
257	const char *val;
258	int clear;
259	int s;
260{
261	struct ifmediareq ifmr;
262	int *mwords, options;
263
264	(void) memset(&ifmr, 0, sizeof(ifmr));
265	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
266
267	/*
268	 * We must go through the motions of reading all
269	 * supported media because we need to know both
270	 * the current media type and the top-level type.
271	 */
272
273	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
274		err(1, "SIOCGIFMEDIA");
275
276	if (ifmr.ifm_count == 0)
277		errx(1, "%s: no media types?", name);
278
279	mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
280	if (mwords == NULL)
281		err(1, "malloc");
282
283	ifmr.ifm_ulist = mwords;
284	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
285		err(1, "SIOCGIFMEDIA");
286
287	options = get_media_options(IFM_TYPE(mwords[0]), val);
288
289	free(mwords);
290
291	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
292	ifr.ifr_media = ifmr.ifm_current;
293	if (clear)
294		ifr.ifr_media &= ~options;
295	else
296		ifr.ifr_media |= options;
297
298	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
299		err(1, "SIOCSIFMEDIA");
300}
301
302/**********************************************************************
303 * A good chunk of this is duplicated from sys/net/ifmedia.c
304 **********************************************************************/
305
306static struct ifmedia_description ifm_type_descriptions[] =
307    IFM_TYPE_DESCRIPTIONS;
308
309static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
310    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
311
312static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
313    IFM_SUBTYPE_ETHERNET_ALIASES;
314
315static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
316    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
317
318static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
319    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
320
321static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
322    IFM_SUBTYPE_TOKENRING_ALIASES;
323
324static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
325    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
326
327static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
328    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
329
330static struct ifmedia_description ifm_subtype_fddi_aliases[] =
331    IFM_SUBTYPE_FDDI_ALIASES;
332
333static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
334    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
335
336static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
337    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
338
339static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
340    IFM_SUBTYPE_IEEE80211_ALIASES;
341
342static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
343    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
344
345static struct ifmedia_description ifm_subtype_shared_descriptions[] =
346    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
347
348static struct ifmedia_description ifm_subtype_shared_aliases[] =
349    IFM_SUBTYPE_SHARED_ALIASES;
350
351static struct ifmedia_description ifm_shared_option_descriptions[] =
352    IFM_SHARED_OPTION_DESCRIPTIONS;
353
354struct ifmedia_type_to_subtype {
355	struct {
356		struct ifmedia_description *desc;
357		int alias;
358	} subtypes[5];
359	struct {
360		struct ifmedia_description *desc;
361		int alias;
362	} options[3];
363};
364
365/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
366static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
367	{
368		{
369			{ &ifm_subtype_shared_descriptions[0], 0 },
370			{ &ifm_subtype_shared_aliases[0], 1 },
371			{ &ifm_subtype_ethernet_descriptions[0], 0 },
372			{ &ifm_subtype_ethernet_aliases[0], 1 },
373			{ NULL, 0 },
374		},
375		{
376			{ &ifm_shared_option_descriptions[0], 0 },
377			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
378			{ NULL, 0 },
379		},
380	},
381	{
382		{
383			{ &ifm_subtype_shared_descriptions[0], 0 },
384			{ &ifm_subtype_shared_aliases[0], 1 },
385			{ &ifm_subtype_tokenring_descriptions[0], 0 },
386			{ &ifm_subtype_tokenring_aliases[0], 1 },
387			{ NULL, 0 },
388		},
389		{
390			{ &ifm_shared_option_descriptions[0], 0 },
391			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
392			{ NULL, 0 },
393		},
394	},
395	{
396		{
397			{ &ifm_subtype_shared_descriptions[0], 0 },
398			{ &ifm_subtype_shared_aliases[0], 1 },
399			{ &ifm_subtype_fddi_descriptions[0], 0 },
400			{ &ifm_subtype_fddi_aliases[0], 1 },
401			{ NULL, 0 },
402		},
403		{
404			{ &ifm_shared_option_descriptions[0], 0 },
405			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
406			{ NULL, 0 },
407		},
408	},
409	{
410		{
411			{ &ifm_subtype_shared_descriptions[0], 0 },
412			{ &ifm_subtype_shared_aliases[0], 1 },
413			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
414			{ &ifm_subtype_ieee80211_aliases[0], 1 },
415			{ NULL, 0 },
416		},
417		{
418			{ &ifm_shared_option_descriptions[0], 0 },
419			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
420			{ NULL, 0 },
421		},
422	},
423};
424
425static int
426get_media_subtype(type, val)
427	int type;
428	const char *val;
429{
430	struct ifmedia_description *desc;
431	struct ifmedia_type_to_subtype *ttos;
432	int rval, i;
433
434	/* Find the top-level interface type. */
435	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
436	    desc->ifmt_string != NULL; desc++, ttos++)
437		if (type == desc->ifmt_word)
438			break;
439	if (desc->ifmt_string == NULL)
440		errx(1, "unknown media type 0x%x", type);
441
442	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
443		rval = lookup_media_word(ttos->subtypes[i].desc, val);
444		if (rval != -1)
445			return (rval);
446	}
447	errx(1, "unknown media subtype: %s", val);
448	/* NOTREACHED */
449}
450
451static int
452get_media_options(type, val)
453	int type;
454	const char *val;
455{
456	struct ifmedia_description *desc;
457	struct ifmedia_type_to_subtype *ttos;
458	char *optlist, *optptr;
459	int option = 0, i, rval = 0;
460
461	/* We muck with the string, so copy it. */
462	optlist = strdup(val);
463	if (optlist == NULL)
464		err(1, "strdup");
465
466	/* Find the top-level interface type. */
467	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
468	    desc->ifmt_string != NULL; desc++, ttos++)
469		if (type == desc->ifmt_word)
470			break;
471	if (desc->ifmt_string == NULL)
472		errx(1, "unknown media type 0x%x", type);
473
474	/*
475	 * Look up the options in the user-provided comma-separated
476	 * list.
477	 */
478	optptr = optlist;
479	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
480		for (i = 0; ttos->options[i].desc != NULL; i++) {
481			option = lookup_media_word(ttos->options[i].desc, optptr);
482			if (option != -1)
483				break;
484		}
485		if (option == 0)
486			errx(1, "unknown option: %s", optptr);
487		rval |= option;
488	}
489
490	free(optlist);
491	return (rval);
492}
493
494static int
495lookup_media_word(desc, val)
496	struct ifmedia_description *desc;
497	const char *val;
498{
499
500	for (; desc->ifmt_string != NULL; desc++)
501		if (strcasecmp(desc->ifmt_string, val) == 0)
502			return (desc->ifmt_word);
503
504	return (-1);
505}
506
507static struct ifmedia_description *get_toptype_desc(ifmw)
508	int ifmw;
509{
510	struct ifmedia_description *desc;
511
512	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
513		if (IFM_TYPE(ifmw) == desc->ifmt_word)
514			break;
515
516	return desc;
517}
518
519static struct ifmedia_type_to_subtype *get_toptype_ttos(ifmw)
520	int ifmw;
521{
522	struct ifmedia_description *desc;
523	struct ifmedia_type_to_subtype *ttos;
524
525	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
526	    desc->ifmt_string != NULL; desc++, ttos++)
527		if (IFM_TYPE(ifmw) == desc->ifmt_word)
528			break;
529
530	return ttos;
531}
532
533static struct ifmedia_description *get_subtype_desc(ifmw, ttos)
534	int ifmw;
535	struct ifmedia_type_to_subtype *ttos;
536{
537	int i;
538	struct ifmedia_description *desc;
539
540	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
541		if (ttos->subtypes[i].alias)
542			continue;
543		for (desc = ttos->subtypes[i].desc;
544		    desc->ifmt_string != NULL; desc++) {
545			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
546				return desc;
547		}
548	}
549
550	return NULL;
551}
552
553static void
554print_media_word(ifmw, print_toptype)
555	int ifmw;
556	int print_toptype;
557{
558	struct ifmedia_description *desc;
559	struct ifmedia_type_to_subtype *ttos;
560	int seen_option = 0, i;
561
562	/* Find the top-level interface type. */
563	desc = get_toptype_desc(ifmw);
564	ttos = get_toptype_ttos(ifmw);
565	if (desc->ifmt_string == NULL) {
566		printf("<unknown type>");
567		return;
568	} else if (print_toptype) {
569		printf("%s", desc->ifmt_string);
570	}
571
572	/*
573	 * Don't print the top-level type; it's not like we can
574	 * change it, or anything.
575	 */
576
577	/* Find subtype. */
578	desc = get_subtype_desc(ifmw, ttos);
579	if (desc != NULL)
580		goto got_subtype;
581
582	/* Falling to here means unknown subtype. */
583	printf("<unknown subtype>");
584	return;
585
586 got_subtype:
587	if (print_toptype)
588		putchar(' ');
589
590	printf("%s", desc->ifmt_string);
591
592	/* Find options. */
593	for (i = 0; ttos->options[i].desc != NULL; i++) {
594		if (ttos->options[i].alias)
595			continue;
596		for (desc = ttos->options[i].desc;
597		    desc->ifmt_string != NULL; desc++) {
598			if (ifmw & desc->ifmt_word) {
599				if (seen_option == 0)
600					printf(" <");
601				printf("%s%s", seen_option++ ? "," : "",
602				    desc->ifmt_string);
603			}
604		}
605	}
606	printf("%s", seen_option ? ">" : "");
607}
608
609static void
610print_media_word_ifconfig(ifmw)
611	int ifmw;
612{
613	struct ifmedia_description *desc;
614	struct ifmedia_type_to_subtype *ttos;
615	int i;
616
617	/* Find the top-level interface type. */
618	desc = get_toptype_desc(ifmw);
619	ttos = get_toptype_ttos(ifmw);
620	if (desc->ifmt_string == NULL) {
621		printf("<unknown type>");
622		return;
623	}
624
625	/*
626	 * Don't print the top-level type; it's not like we can
627	 * change it, or anything.
628	 */
629
630	/* Find subtype. */
631	desc = get_subtype_desc(ifmw, ttos);
632	if (desc != NULL)
633		goto got_subtype;
634
635	/* Falling to here means unknown subtype. */
636	printf("<unknown subtype>");
637	return;
638
639 got_subtype:
640	printf("media %s", desc->ifmt_string);
641
642	/* Find options. */
643	for (i = 0; ttos->options[i].desc != NULL; i++) {
644		if (ttos->options[i].alias)
645			continue;
646		for (desc = ttos->options[i].desc;
647		    desc->ifmt_string != NULL; desc++) {
648			if (ifmw & desc->ifmt_word) {
649				printf(" mediaopt %s", desc->ifmt_string);
650			}
651		}
652	}
653}
654
655/**********************************************************************
656 * ...until here.
657 **********************************************************************/
658