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