ifmedia.c revision 30459
1/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
2/*	$Id: ifmedia.c,v 1.3 1997/05/10 17:14:53 peter Exp $ */
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_var.h>
77#include <net/if_dl.h>
78#include <net/if_types.h>
79#include <net/if_media.h>
80#include <net/route.h>
81
82#include <ctype.h>
83#include <err.h>
84#include <errno.h>
85#include <fcntl.h>
86#include <stdio.h>
87#include <stdlib.h>
88#include <string.h>
89#include <unistd.h>
90
91#include "ifconfig.h"
92
93static void	domediaopt __P((const char *, int, int));
94static int	get_media_subtype __P((int, const char *));
95static int	get_media_options __P((int, const char *));
96static int	lookup_media_word __P((struct ifmedia_description *, const char *));
97static void	print_media_word __P((int));
98
99void
100media_status(s, info)
101	int s;
102	struct rt_addrinfo *info __unused;
103{
104	struct ifmediareq ifmr;
105	int *media_list, i;
106
107	(void) memset(&ifmr, 0, sizeof(ifmr));
108	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
109
110	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
111		/*
112		 * Interface doesn't support SIOC{G,S}IFMEDIA.
113		 */
114		return;
115	}
116
117	if (ifmr.ifm_count == 0) {
118		warnx("%s: no media types?", name);
119		return;
120	}
121
122	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
123	if (media_list == NULL)
124		err(1, "malloc");
125	ifmr.ifm_ulist = media_list;
126
127	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
128		err(1, "SIOCGIFMEDIA");
129
130	printf("\tmedia: ");
131	print_media_word(ifmr.ifm_current);
132	if (ifmr.ifm_active != ifmr.ifm_current) {
133		putchar(' ');
134		putchar('(');
135		print_media_word(ifmr.ifm_active);
136		putchar(')');
137	}
138
139	if (ifmr.ifm_status & IFM_AVALID) {
140		printf(" status: ");
141		switch (IFM_TYPE(ifmr.ifm_active)) {
142		case IFM_ETHER:
143			if (ifmr.ifm_status & IFM_ACTIVE)
144				printf("active");
145			else
146				printf("no carrier");
147			break;
148
149		case IFM_FDDI:
150		case IFM_TOKEN:
151			if (ifmr.ifm_status & IFM_ACTIVE)
152				printf("inserted");
153			else
154				printf("no ring");
155			break;
156		}
157	}
158
159	putchar('\n');
160
161	if (ifmr.ifm_count > 0) {
162		printf("\tsupported media:");
163		for (i = 0; i < ifmr.ifm_count; i++) {
164			putchar(' ');
165			print_media_word(media_list[i]);
166		}
167		putchar('\n');
168	}
169
170	free(media_list);
171}
172
173void
174setmedia(val, d, s, afp)
175	const char *val;
176	int d;
177	int s;
178	const struct afswtch *afp;
179{
180	struct ifmediareq ifmr;
181	int first_type, subtype;
182
183	(void) memset(&ifmr, 0, sizeof(ifmr));
184	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
185
186	ifmr.ifm_count = 1;
187	ifmr.ifm_ulist = &first_type;
188	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
189		/*
190		 * If we get E2BIG, the kernel is telling us
191		 * that there are more, so we can ignore it.
192		 */
193		if (errno != E2BIG)
194			err(1, "SIOCGIFMEDIA");
195	}
196
197	if (ifmr.ifm_count == 0)
198		errx(1, "%s: no media types?", name);
199
200	/*
201	 * We are primarily concerned with the top-level type.
202	 * However, "current" may be only IFM_NONE, so we just look
203	 * for the top-level type in the first "supported type"
204	 * entry.
205	 *
206	 * (I'm assuming that all supported media types for a given
207	 * interface will be the same top-level type..)
208	 */
209	subtype = get_media_subtype(IFM_TYPE(first_type), val);
210
211	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
212	ifr.ifr_media = (ifmr.ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
213	    IFM_TYPE(first_type) | subtype;
214
215	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
216		err(1, "SIOCSIFMEDIA");
217}
218
219void
220setmediaopt(val, d, s, afp)
221	const char *val;
222	int d;
223	int s;
224	const struct afswtch *afp;
225{
226
227	domediaopt(val, 0, s);
228}
229
230void
231unsetmediaopt(val, d, s, afp)
232	const char *val;
233	int d;
234	int s;
235	const struct afswtch *afp;
236{
237
238	domediaopt(val, 1, s);
239}
240
241static void
242domediaopt(val, clear, s)
243	const char *val;
244	int clear;
245	int s;
246{
247	struct ifmediareq ifmr;
248	int *mwords, options;
249
250	(void) memset(&ifmr, 0, sizeof(ifmr));
251	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
252
253	/*
254	 * We must go through the motions of reading all
255	 * supported media because we need to know both
256	 * the current media type and the top-level type.
257	 */
258
259	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
260		err(1, "SIOCGIFMEDIA");
261
262	if (ifmr.ifm_count == 0)
263		errx(1, "%s: no media types?", name);
264
265	mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
266	if (mwords == NULL)
267		err(1, "malloc");
268
269	ifmr.ifm_ulist = mwords;
270	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
271		err(1, "SIOCGIFMEDIA");
272
273	options = get_media_options(IFM_TYPE(mwords[0]), val);
274
275	free(mwords);
276
277	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
278	ifr.ifr_media = ifmr.ifm_current;
279	if (clear)
280		ifr.ifr_media &= ~options;
281	else
282		ifr.ifr_media |= options;
283
284	if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
285		err(1, "SIOCSIFMEDIA");
286}
287
288/**********************************************************************
289 * A good chunk of this is duplicated from sys/net/ifmedia.c
290 **********************************************************************/
291
292static struct ifmedia_description ifm_type_descriptions[] =
293    IFM_TYPE_DESCRIPTIONS;
294
295static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
296    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
297
298static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
299    IFM_SUBTYPE_ETHERNET_ALIASES;
300
301static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
302    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
303
304static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
305    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
306
307static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
308    IFM_SUBTYPE_TOKENRING_ALIASES;
309
310static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
311    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
312
313static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
314    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
315
316static struct ifmedia_description ifm_subtype_fddi_aliases[] =
317    IFM_SUBTYPE_FDDI_ALIASES;
318
319static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
320    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
321
322static struct ifmedia_description ifm_subtype_shared_descriptions[] =
323    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
324
325static struct ifmedia_description ifm_subtype_shared_aliases[] =
326    IFM_SUBTYPE_SHARED_ALIASES;
327
328static struct ifmedia_description ifm_shared_option_descriptions[] =
329    IFM_SHARED_OPTION_DESCRIPTIONS;
330
331struct ifmedia_type_to_subtype {
332	struct {
333		struct ifmedia_description *desc;
334		int alias;
335	} subtypes[5];
336	struct {
337		struct ifmedia_description *desc;
338		int alias;
339	} options[3];
340};
341
342/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
343static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
344	{
345		{
346			{ &ifm_subtype_shared_descriptions[0], 0 },
347			{ &ifm_subtype_shared_aliases[0], 1 },
348			{ &ifm_subtype_ethernet_descriptions[0], 0 },
349			{ &ifm_subtype_ethernet_aliases[0], 1 },
350			{ NULL, 0 },
351		},
352		{
353			{ &ifm_shared_option_descriptions[0], 0 },
354			{ &ifm_subtype_ethernet_option_descriptions[0], 1 },
355			{ NULL, 0 },
356		},
357	},
358	{
359		{
360			{ &ifm_subtype_shared_descriptions[0], 0 },
361			{ &ifm_subtype_shared_aliases[0], 1 },
362			{ &ifm_subtype_tokenring_descriptions[0], 0 },
363			{ &ifm_subtype_tokenring_aliases[0], 1 },
364			{ NULL, 0 },
365		},
366		{
367			{ &ifm_shared_option_descriptions[0], 0 },
368			{ &ifm_subtype_tokenring_option_descriptions[0], 1 },
369			{ NULL, 0 },
370		},
371	},
372	{
373		{
374			{ &ifm_subtype_shared_descriptions[0], 0 },
375			{ &ifm_subtype_shared_aliases[0], 1 },
376			{ &ifm_subtype_fddi_descriptions[0], 0 },
377			{ &ifm_subtype_fddi_aliases[0], 1 },
378			{ NULL, 0 },
379		},
380		{
381			{ &ifm_shared_option_descriptions[0], 0 },
382			{ &ifm_subtype_fddi_option_descriptions[0], 1 },
383			{ NULL, 0 },
384		},
385	},
386};
387
388static int
389get_media_subtype(type, val)
390	int type;
391	const char *val;
392{
393	struct ifmedia_description *desc;
394	struct ifmedia_type_to_subtype *ttos;
395	int rval, i;
396
397	/* Find the top-level interface type. */
398	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
399	    desc->ifmt_string != NULL; desc++, ttos++)
400		if (type == desc->ifmt_word)
401			break;
402	if (desc->ifmt_string == NULL)
403		errx(1, "unknown media type 0x%x", type);
404
405	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
406		rval = lookup_media_word(ttos->subtypes[i].desc, val);
407		if (rval != -1)
408			return (rval);
409	}
410	errx(1, "unknown media subtype: %s", val);
411	/* NOTREACHED */
412}
413
414static int
415get_media_options(type, val)
416	int type;
417	const char *val;
418{
419	struct ifmedia_description *desc;
420	struct ifmedia_type_to_subtype *ttos;
421	char *optlist, *optptr;
422	int option = 0, i, rval = 0;
423
424	/* We muck with the string, so copy it. */
425	optlist = strdup(val);
426	if (optlist == NULL)
427		err(1, "strdup");
428
429	/* Find the top-level interface type. */
430	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
431	    desc->ifmt_string != NULL; desc++, ttos++)
432		if (type == desc->ifmt_word)
433			break;
434	if (desc->ifmt_string == NULL)
435		errx(1, "unknown media type 0x%x", type);
436
437	/*
438	 * Look up the options in the user-provided comma-separated
439	 * list.
440	 */
441	optptr = optlist;
442	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
443		for (i = 0; ttos->options[i].desc != NULL; i++) {
444			option = lookup_media_word(ttos->options[i].desc, optptr);
445			if (option != -1)
446				break;
447		}
448		if (option == 0)
449			errx(1, "unknown option: %s", optptr);
450		rval |= option;
451	}
452
453	free(optlist);
454	return (rval);
455}
456
457static int
458lookup_media_word(desc, val)
459	struct ifmedia_description *desc;
460	const char *val;
461{
462
463	for (; desc->ifmt_string != NULL; desc++)
464		if (strcasecmp(desc->ifmt_string, val) == 0)
465			return (desc->ifmt_word);
466
467	return (-1);
468}
469
470static void
471print_media_word(ifmw)
472	int ifmw;
473{
474	struct ifmedia_description *desc;
475	struct ifmedia_type_to_subtype *ttos;
476	int seen_option = 0, i;
477
478	/* Find the top-level interface type. */
479	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
480	    desc->ifmt_string != NULL; desc++, ttos++)
481		if (IFM_TYPE(ifmw) == desc->ifmt_word)
482			break;
483	if (desc->ifmt_string == NULL) {
484		printf("<unknown type>");
485		return;
486	}
487
488	/*
489	 * Don't print the top-level type; it's not like we can
490	 * change it, or anything.
491	 */
492
493	/* Find subtype. */
494	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
495		if (ttos->subtypes[i].alias)
496			continue;
497		for (desc = ttos->subtypes[i].desc;
498		    desc->ifmt_string != NULL; desc++) {
499			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
500				goto got_subtype;
501		}
502	}
503
504	/* Falling to here means unknown subtype. */
505	printf("<unknown subtype>");
506	return;
507
508 got_subtype:
509	printf("%s", desc->ifmt_string);
510
511	/* Find options. */
512	for (i = 0; ttos->options[i].desc != NULL; i++) {
513		if (ttos->options[i].alias)
514			continue;
515		for (desc = ttos->options[i].desc;
516		    desc->ifmt_string != NULL; desc++) {
517			if (ifmw & desc->ifmt_word) {
518				if (seen_option == 0)
519					printf(" <");
520				printf("%s%s", seen_option++ ? "," : "",
521				    desc->ifmt_string);
522			}
523		}
524	}
525	printf("%s", seen_option ? ">" : "");
526}
527
528/**********************************************************************
529 * ...until here.
530 **********************************************************************/
531