ifmedia.c revision 85853
1/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
2/* $FreeBSD: head/sbin/ifconfig/ifmedia.c 85853 2001-11-02 02:20:21Z yar $ */
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		putchar('\n');
172	}
173
174	if (ifmr.ifm_count > 0 && supmedia) {
175		printf("\tsupported media:\n");
176		for (i = 0; i < ifmr.ifm_count; i++) {
177			printf("\t\t");
178			print_media_word_ifconfig(media_list[i]);
179			putchar('\n');
180		}
181	}
182
183	free(media_list);
184}
185
186void
187setmedia(val, d, s, afp)
188	const char *val;
189	int d;
190	int s;
191	const struct afswtch *afp;
192{
193	struct ifmediareq ifmr;
194	int first_type, subtype;
195
196	(void) memset(&ifmr, 0, sizeof(ifmr));
197	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
198
199	ifmr.ifm_count = 1;
200	ifmr.ifm_ulist = &first_type;
201	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
202		/*
203		 * If we get E2BIG, the kernel is telling us
204		 * that there are more, so we can ignore it.
205		 */
206		if (errno != E2BIG)
207			err(1, "SIOCGIFMEDIA");
208	}
209
210	if (ifmr.ifm_count == 0)
211		errx(1, "%s: no media types?", name);
212
213	/*
214	 * We are primarily concerned with the top-level type.
215	 * However, "current" may be only IFM_NONE, so we just look
216	 * for the top-level type in the first "supported type"
217	 * entry.
218	 *
219	 * (I'm assuming that all supported media types for a given
220	 * interface will be the same top-level type..)
221	 */
222	subtype = get_media_subtype(IFM_TYPE(first_type), val);
223
224	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
225	ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
226	    IFM_TYPE(first_type) | subtype;
227
228	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
229		err(1, "SIOCSIFMEDIA");
230}
231
232void
233setmediaopt(val, d, s, afp)
234	const char *val;
235	int d;
236	int s;
237	const struct afswtch *afp;
238{
239
240	domediaopt(val, 0, s);
241}
242
243void
244unsetmediaopt(val, d, s, afp)
245	const char *val;
246	int d;
247	int s;
248	const struct afswtch *afp;
249{
250
251	domediaopt(val, 1, s);
252}
253
254static void
255domediaopt(val, clear, s)
256	const char *val;
257	int clear;
258	int s;
259{
260	struct ifmediareq ifmr;
261	int *mwords, options;
262
263	(void) memset(&ifmr, 0, sizeof(ifmr));
264	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
265
266	/*
267	 * We must go through the motions of reading all
268	 * supported media because we need to know both
269	 * the current media type and the top-level type.
270	 */
271
272	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
273		err(1, "SIOCGIFMEDIA");
274
275	if (ifmr.ifm_count == 0)
276		errx(1, "%s: no media types?", name);
277
278	mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
279	if (mwords == NULL)
280		err(1, "malloc");
281
282	ifmr.ifm_ulist = mwords;
283	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
284		err(1, "SIOCGIFMEDIA");
285
286	options = get_media_options(IFM_TYPE(mwords[0]), val);
287
288	free(mwords);
289
290	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
291	ifr.ifr_media = ifmr.ifm_current;
292	if (clear)
293		ifr.ifr_media &= ~options;
294	else
295		ifr.ifr_media |= options;
296
297	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
298		err(1, "SIOCSIFMEDIA");
299}
300
301/**********************************************************************
302 * A good chunk of this is duplicated from sys/net/ifmedia.c
303 **********************************************************************/
304
305static struct ifmedia_description ifm_type_descriptions[] =
306    IFM_TYPE_DESCRIPTIONS;
307
308static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
309    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
310
311static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
312    IFM_SUBTYPE_ETHERNET_ALIASES;
313
314static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
315    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
316
317static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
318    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
319
320static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
321    IFM_SUBTYPE_TOKENRING_ALIASES;
322
323static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
324    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
325
326static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
327    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
328
329static struct ifmedia_description ifm_subtype_fddi_aliases[] =
330    IFM_SUBTYPE_FDDI_ALIASES;
331
332static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
333    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
334
335static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
336    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
337
338static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
339    IFM_SUBTYPE_IEEE80211_ALIASES;
340
341static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
342    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
343
344static struct ifmedia_description ifm_subtype_shared_descriptions[] =
345    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
346
347static struct ifmedia_description ifm_subtype_shared_aliases[] =
348    IFM_SUBTYPE_SHARED_ALIASES;
349
350static struct ifmedia_description ifm_shared_option_descriptions[] =
351    IFM_SHARED_OPTION_DESCRIPTIONS;
352
353struct ifmedia_type_to_subtype {
354	struct {
355		struct ifmedia_description *desc;
356		int alias;
357	} subtypes[5];
358	struct {
359		struct ifmedia_description *desc;
360		int alias;
361	} options[3];
362};
363
364/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
365static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
366	{
367		{
368			{ &ifm_subtype_shared_descriptions[0], 0 },
369			{ &ifm_subtype_shared_aliases[0], 1 },
370			{ &ifm_subtype_ethernet_descriptions[0], 0 },
371			{ &ifm_subtype_ethernet_aliases[0], 1 },
372			{ NULL, 0 },
373		},
374		{
375			{ &ifm_shared_option_descriptions[0], 0 },
376			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
377			{ NULL, 0 },
378		},
379	},
380	{
381		{
382			{ &ifm_subtype_shared_descriptions[0], 0 },
383			{ &ifm_subtype_shared_aliases[0], 1 },
384			{ &ifm_subtype_tokenring_descriptions[0], 0 },
385			{ &ifm_subtype_tokenring_aliases[0], 1 },
386			{ NULL, 0 },
387		},
388		{
389			{ &ifm_shared_option_descriptions[0], 0 },
390			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
391			{ NULL, 0 },
392		},
393	},
394	{
395		{
396			{ &ifm_subtype_shared_descriptions[0], 0 },
397			{ &ifm_subtype_shared_aliases[0], 1 },
398			{ &ifm_subtype_fddi_descriptions[0], 0 },
399			{ &ifm_subtype_fddi_aliases[0], 1 },
400			{ NULL, 0 },
401		},
402		{
403			{ &ifm_shared_option_descriptions[0], 0 },
404			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
405			{ NULL, 0 },
406		},
407	},
408	{
409		{
410			{ &ifm_subtype_shared_descriptions[0], 0 },
411			{ &ifm_subtype_shared_aliases[0], 1 },
412			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
413			{ &ifm_subtype_ieee80211_aliases[0], 1 },
414			{ NULL, 0 },
415		},
416		{
417			{ &ifm_shared_option_descriptions[0], 0 },
418			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
419			{ NULL, 0 },
420		},
421	},
422};
423
424static int
425get_media_subtype(type, val)
426	int type;
427	const char *val;
428{
429	struct ifmedia_description *desc;
430	struct ifmedia_type_to_subtype *ttos;
431	int rval, i;
432
433	/* Find the top-level interface type. */
434	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
435	    desc->ifmt_string != NULL; desc++, ttos++)
436		if (type == desc->ifmt_word)
437			break;
438	if (desc->ifmt_string == NULL)
439		errx(1, "unknown media type 0x%x", type);
440
441	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
442		rval = lookup_media_word(ttos->subtypes[i].desc, val);
443		if (rval != -1)
444			return (rval);
445	}
446	errx(1, "unknown media subtype: %s", val);
447	/* NOTREACHED */
448}
449
450static int
451get_media_options(type, val)
452	int type;
453	const char *val;
454{
455	struct ifmedia_description *desc;
456	struct ifmedia_type_to_subtype *ttos;
457	char *optlist, *optptr;
458	int option = 0, i, rval = 0;
459
460	/* We muck with the string, so copy it. */
461	optlist = strdup(val);
462	if (optlist == NULL)
463		err(1, "strdup");
464
465	/* Find the top-level interface type. */
466	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
467	    desc->ifmt_string != NULL; desc++, ttos++)
468		if (type == desc->ifmt_word)
469			break;
470	if (desc->ifmt_string == NULL)
471		errx(1, "unknown media type 0x%x", type);
472
473	/*
474	 * Look up the options in the user-provided comma-separated
475	 * list.
476	 */
477	optptr = optlist;
478	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
479		for (i = 0; ttos->options[i].desc != NULL; i++) {
480			option = lookup_media_word(ttos->options[i].desc, optptr);
481			if (option != -1)
482				break;
483		}
484		if (option == 0)
485			errx(1, "unknown option: %s", optptr);
486		rval |= option;
487	}
488
489	free(optlist);
490	return (rval);
491}
492
493static int
494lookup_media_word(desc, val)
495	struct ifmedia_description *desc;
496	const char *val;
497{
498
499	for (; desc->ifmt_string != NULL; desc++)
500		if (strcasecmp(desc->ifmt_string, val) == 0)
501			return (desc->ifmt_word);
502
503	return (-1);
504}
505
506static struct ifmedia_description *get_toptype_desc(ifmw)
507	int ifmw;
508{
509	struct ifmedia_description *desc;
510
511	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
512		if (IFM_TYPE(ifmw) == desc->ifmt_word)
513			break;
514
515	return desc;
516}
517
518static struct ifmedia_type_to_subtype *get_toptype_ttos(ifmw)
519	int ifmw;
520{
521	struct ifmedia_description *desc;
522	struct ifmedia_type_to_subtype *ttos;
523
524	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
525	    desc->ifmt_string != NULL; desc++, ttos++)
526		if (IFM_TYPE(ifmw) == desc->ifmt_word)
527			break;
528
529	return ttos;
530}
531
532static struct ifmedia_description *get_subtype_desc(ifmw, ttos)
533	int ifmw;
534	struct ifmedia_type_to_subtype *ttos;
535{
536	int i;
537	struct ifmedia_description *desc;
538
539	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
540		if (ttos->subtypes[i].alias)
541			continue;
542		for (desc = ttos->subtypes[i].desc;
543		    desc->ifmt_string != NULL; desc++) {
544			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
545				return desc;
546		}
547	}
548
549	return NULL;
550}
551
552static void
553print_media_word(ifmw, print_toptype)
554	int ifmw;
555	int print_toptype;
556{
557	struct ifmedia_description *desc;
558	struct ifmedia_type_to_subtype *ttos;
559	int seen_option = 0, i;
560
561	/* Find the top-level interface type. */
562	desc = get_toptype_desc(ifmw);
563	ttos = get_toptype_ttos(ifmw);
564	if (desc->ifmt_string == NULL) {
565		printf("<unknown type>");
566		return;
567	} else if (print_toptype) {
568		printf("%s", desc->ifmt_string);
569	}
570
571	/*
572	 * Don't print the top-level type; it's not like we can
573	 * change it, or anything.
574	 */
575
576	/* Find subtype. */
577	desc = get_subtype_desc(ifmw, ttos);
578	if (desc != NULL)
579		goto got_subtype;
580
581	/* Falling to here means unknown subtype. */
582	printf("<unknown subtype>");
583	return;
584
585 got_subtype:
586	if (print_toptype)
587		putchar(' ');
588
589	printf("%s", desc->ifmt_string);
590
591	/* Find options. */
592	for (i = 0; ttos->options[i].desc != NULL; i++) {
593		if (ttos->options[i].alias)
594			continue;
595		for (desc = ttos->options[i].desc;
596		    desc->ifmt_string != NULL; desc++) {
597			if (ifmw & desc->ifmt_word) {
598				if (seen_option == 0)
599					printf(" <");
600				printf("%s%s", seen_option++ ? "," : "",
601				    desc->ifmt_string);
602			}
603		}
604	}
605	printf("%s", seen_option ? ">" : "");
606}
607
608static void
609print_media_word_ifconfig(ifmw)
610	int ifmw;
611{
612	struct ifmedia_description *desc;
613	struct ifmedia_type_to_subtype *ttos;
614	int i;
615
616	/* Find the top-level interface type. */
617	desc = get_toptype_desc(ifmw);
618	ttos = get_toptype_ttos(ifmw);
619	if (desc->ifmt_string == NULL) {
620		printf("<unknown type>");
621		return;
622	}
623
624	/*
625	 * Don't print the top-level type; it's not like we can
626	 * change it, or anything.
627	 */
628
629	/* Find subtype. */
630	desc = get_subtype_desc(ifmw, ttos);
631	if (desc != NULL)
632		goto got_subtype;
633
634	/* Falling to here means unknown subtype. */
635	printf("<unknown subtype>");
636	return;
637
638 got_subtype:
639	printf("media %s", desc->ifmt_string);
640
641	/* Find options. */
642	for (i = 0; ttos->options[i].desc != NULL; i++) {
643		if (ttos->options[i].alias)
644			continue;
645		for (desc = ttos->options[i].desc;
646		    desc->ifmt_string != NULL; desc++) {
647			if (ifmw & desc->ifmt_word) {
648				printf(" mediaopt %s", desc->ifmt_string);
649			}
650		}
651	}
652}
653
654/**********************************************************************
655 * ...until here.
656 **********************************************************************/
657