1 /* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-4-Clause
5 *
6 * Copyright (c) 1997 Jason R. Thorpe.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project
20 * by Jason R. Thorpe.
21 * 4. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 /*
38 * Copyright (c) 1983, 1993
39 * The Regents of the University of California. All rights reserved.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66 #include <sys/param.h>
67 #include <sys/ioctl.h>
68 #include <sys/socket.h>
69 #include <sys/sysctl.h>
70 #include <sys/time.h>
71
72 #include <net/if.h>
73 #include <net/if_dl.h>
74 #include <net/if_types.h>
75 #include <net/if_media.h>
76 #include <net/route.h>
77
78 #include <ctype.h>
79 #include <err.h>
80 #include <errno.h>
81 #include <fcntl.h>
82 #include <stdbool.h>
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <unistd.h>
87
88 #include <libifconfig.h>
89
90 #include "ifconfig.h"
91
92 static void domediaopt(const char *, bool, int);
93 static ifmedia_t get_media_subtype(ifmedia_t, const char *);
94 static ifmedia_t get_media_mode(ifmedia_t, const char *);
95 static ifmedia_t get_media_options(ifmedia_t, const char *);
96 static void print_media(ifmedia_t, bool);
97 static void print_media_ifconfig(ifmedia_t);
98
99 static void
media_status(int s)100 media_status(int s)
101 {
102 struct ifmediareq *ifmr;
103
104 if (ifconfig_media_get_mediareq(lifh, name, &ifmr) == -1)
105 return;
106
107 if (ifmr->ifm_count == 0) {
108 warnx("%s: no media types?", name);
109 goto free;
110 }
111
112 printf("\tmedia: ");
113 print_media(ifmr->ifm_current, true);
114 if (ifmr->ifm_active != ifmr->ifm_current) {
115 putchar(' ');
116 putchar('(');
117 print_media(ifmr->ifm_active, false);
118 putchar(')');
119 }
120
121 putchar('\n');
122
123 if (ifmr->ifm_status & IFM_AVALID) {
124 struct ifdownreason ifdr;
125 const char *status;
126
127 status = ifconfig_media_get_status(ifmr);
128 printf("\tstatus: %s", status);
129 if (strcmp(status, "no carrier") == 0 &&
130 ifconfig_media_get_downreason(lifh, name, &ifdr) == 0) {
131 switch (ifdr.ifdr_reason) {
132 case IFDR_REASON_MSG:
133 printf(" (%s)", ifdr.ifdr_msg);
134 break;
135 case IFDR_REASON_VENDOR:
136 printf(" (vendor code %d)",
137 ifdr.ifdr_vendor);
138 break;
139 default:
140 break;
141 }
142 }
143 putchar('\n');
144 }
145
146 if (supmedia) {
147 printf("\tsupported media:\n");
148 for (size_t i = 0; i < ifmr->ifm_count; ++i) {
149 printf("\t\t");
150 print_media_ifconfig(ifmr->ifm_ulist[i]);
151 putchar('\n');
152 }
153 }
154 free:
155 free(ifmr);
156 }
157
158 struct ifmediareq *
ifmedia_getstate(void)159 ifmedia_getstate(void)
160 {
161 static struct ifmediareq *ifmr = NULL;
162
163 if (ifmr != NULL)
164 return (ifmr);
165
166 if (ifconfig_media_get_mediareq(lifh, name, &ifmr) == -1)
167 errc(1, ifconfig_err_errno(lifh),
168 "%s: ifconfig_media_get_mediareq", name);
169
170 if (ifmr->ifm_count == 0)
171 errx(1, "%s: no media types?", name);
172
173 return (ifmr);
174 }
175
176 static void
setifmediacallback(int s,void * arg)177 setifmediacallback(int s, void *arg)
178 {
179 struct ifmediareq *ifmr = (struct ifmediareq *)arg;
180 static bool did_it = false;
181
182 if (!did_it) {
183 ifr.ifr_media = ifmr->ifm_current;
184 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
185 err(1, "SIOCSIFMEDIA (media)");
186 free(ifmr);
187 did_it = true;
188 }
189 }
190
191 static void
setmedia(const char * val,int d,int s,const struct afswtch * afp)192 setmedia(const char *val, int d, int s, const struct afswtch *afp)
193 {
194 struct ifmediareq *ifmr;
195 int subtype;
196
197 ifmr = ifmedia_getstate();
198
199 /*
200 * We are primarily concerned with the top-level type.
201 * However, "current" may be only IFM_NONE, so we just look
202 * for the top-level type in the first "supported type"
203 * entry.
204 *
205 * (I'm assuming that all supported media types for a given
206 * interface will be the same top-level type..)
207 */
208 subtype = get_media_subtype(ifmr->ifm_ulist[0], val);
209
210 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
211 ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) |
212 IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
213
214 ifmr->ifm_current = ifr.ifr_media;
215 callback_register(setifmediacallback, (void *)ifmr);
216 }
217
218 static void
setmediaopt(const char * val,int d,int s,const struct afswtch * afp)219 setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
220 {
221
222 domediaopt(val, false, s);
223 }
224
225 static void
unsetmediaopt(const char * val,int d,int s,const struct afswtch * afp)226 unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
227 {
228
229 domediaopt(val, true, s);
230 }
231
232 static void
domediaopt(const char * val,bool clear,int s)233 domediaopt(const char *val, bool clear, int s)
234 {
235 struct ifmediareq *ifmr;
236 ifmedia_t options;
237
238 ifmr = ifmedia_getstate();
239
240 options = get_media_options(ifmr->ifm_ulist[0], val);
241
242 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
243 ifr.ifr_media = ifmr->ifm_current;
244 if (clear)
245 ifr.ifr_media &= ~options;
246 else {
247 if (options & IFM_HDX) {
248 ifr.ifr_media &= ~IFM_FDX;
249 options &= ~IFM_HDX;
250 }
251 ifr.ifr_media |= options;
252 }
253 ifmr->ifm_current = ifr.ifr_media;
254 callback_register(setifmediacallback, (void *)ifmr);
255 }
256
257 static void
setmediainst(const char * val,int d,int s,const struct afswtch * afp)258 setmediainst(const char *val, int d, int s, const struct afswtch *afp)
259 {
260 struct ifmediareq *ifmr;
261 int inst;
262
263 ifmr = ifmedia_getstate();
264
265 inst = atoi(val);
266 if (inst < 0 || inst > (int)IFM_INST_MAX)
267 errx(1, "invalid media instance: %s", val);
268
269 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
270 ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
271
272 ifmr->ifm_current = ifr.ifr_media;
273 callback_register(setifmediacallback, (void *)ifmr);
274 }
275
276 static void
setmediamode(const char * val,int d,int s,const struct afswtch * afp)277 setmediamode(const char *val, int d, int s, const struct afswtch *afp)
278 {
279 struct ifmediareq *ifmr;
280 int mode;
281
282 ifmr = ifmedia_getstate();
283
284 mode = get_media_mode(ifmr->ifm_ulist[0], val);
285
286 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
287 ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
288
289 ifmr->ifm_current = ifr.ifr_media;
290 callback_register(setifmediacallback, (void *)ifmr);
291 }
292
293 static ifmedia_t
get_media_subtype(ifmedia_t media,const char * val)294 get_media_subtype(ifmedia_t media, const char *val)
295 {
296 ifmedia_t subtype;
297
298 subtype = ifconfig_media_lookup_subtype(media, val);
299 if (subtype != INVALID_IFMEDIA)
300 return (subtype);
301 switch (errno) {
302 case EINVAL:
303 errx(EXIT_FAILURE, "unknown media type 0x%x", media);
304 case ENOENT:
305 errx(EXIT_FAILURE, "unknown media subtype: %s", val);
306 default:
307 err(EXIT_FAILURE, "ifconfig_media_lookup_subtype");
308 }
309 /*NOTREACHED*/
310 }
311
312 static ifmedia_t
get_media_mode(ifmedia_t media,const char * val)313 get_media_mode(ifmedia_t media, const char *val)
314 {
315 ifmedia_t mode;
316
317 mode = ifconfig_media_lookup_mode(media, val);
318 if (mode != INVALID_IFMEDIA)
319 return (mode);
320 switch (errno) {
321 case EINVAL:
322 errx(EXIT_FAILURE, "unknown media type 0x%x", media);
323 case ENOENT:
324 return (INVALID_IFMEDIA);
325 default:
326 err(EXIT_FAILURE, "ifconfig_media_lookup_subtype");
327 }
328 /*NOTREACHED*/
329 }
330
331 static ifmedia_t
get_media_options(ifmedia_t media,const char * val)332 get_media_options(ifmedia_t media, const char *val)
333 {
334 ifmedia_t *options;
335 const char **optnames;
336 char *opts, *opt;
337 size_t nopts;
338 int rval;
339
340 /*
341 * We muck with the string, so copy it.
342 */
343 opts = strdup(val);
344 if (opts == NULL)
345 err(EXIT_FAILURE, "strdup");
346
347 /*
348 * Split the comma-delimited list into separate strings.
349 */
350 nopts = 0;
351 for (opt = opts; (opt = strtok(opt, ",")) != NULL; opt = NULL)
352 ++nopts;
353 if (nopts == 0) {
354 free(opts);
355 return (0);
356 }
357 optnames = calloc(nopts, sizeof(*optnames));
358 if (optnames == NULL)
359 err(EXIT_FAILURE, "calloc");
360 opt = opts;
361 for (size_t i = 0; i < nopts; ++i) {
362 optnames[i] = opt;
363 opt = strchr(opt, '\0') + 1;
364 }
365
366 /*
367 * Look up the options in the user-provided list.
368 */
369 options = ifconfig_media_lookup_options(media, optnames, nopts);
370 if (options == NULL)
371 err(EXIT_FAILURE, "ifconfig_media_lookup_options");
372 rval = 0;
373 for (size_t i = 0; i < nopts; ++i) {
374 if (options[i] == INVALID_IFMEDIA)
375 errx(EXIT_FAILURE, "unknown option: %s", optnames[i]);
376 rval |= options[i];
377 }
378 free(options);
379 free(optnames);
380 free(opts);
381 return (rval);
382 }
383
384 static void
print_media(ifmedia_t media,bool print_toptype)385 print_media(ifmedia_t media, bool print_toptype)
386 {
387 const char *val, **options;
388
389 val = ifconfig_media_get_type(media);
390 if (val == NULL) {
391 printf("<unknown type>");
392 return;
393 } else if (print_toptype) {
394 printf("%s", val);
395 }
396
397 val = ifconfig_media_get_subtype(media);
398 if (val == NULL) {
399 printf("<unknown subtype>");
400 return;
401 }
402
403 if (print_toptype)
404 putchar(' ');
405
406 printf("%s", val);
407
408 if (print_toptype) {
409 val = ifconfig_media_get_mode(media);
410 if (val != NULL && strcasecmp("autoselect", val) != 0)
411 printf(" mode %s", val);
412 }
413
414 options = ifconfig_media_get_options(media);
415 if (options != NULL && options[0] != NULL) {
416 printf(" <%s", options[0]);
417 for (size_t i = 1; options[i] != NULL; ++i)
418 printf(",%s", options[i]);
419 printf(">");
420 }
421 free(options);
422
423 if (print_toptype && IFM_INST(media) != 0)
424 printf(" instance %d", IFM_INST(media));
425 }
426
427 static void
print_media_ifconfig(ifmedia_t media)428 print_media_ifconfig(ifmedia_t media)
429 {
430 const char *val, **options;
431
432 val = ifconfig_media_get_type(media);
433 if (val == NULL) {
434 printf("<unknown type>");
435 return;
436 }
437
438 /*
439 * Don't print the top-level type; it's not like we can
440 * change it, or anything.
441 */
442
443 val = ifconfig_media_get_subtype(media);
444 if (val == NULL) {
445 printf("<unknown subtype>");
446 return;
447 }
448
449 printf("media %s", val);
450
451 val = ifconfig_media_get_mode(media);
452 if (val != NULL)
453 printf(" mode %s", val);
454
455 options = ifconfig_media_get_options(media);
456 if (options != NULL && options[0] != NULL) {
457 printf(" mediaopt %s", options[0]);
458 for (size_t i = 1; options[i] != NULL; ++i)
459 printf(",%s", options[i]);
460 }
461 free(options);
462
463 if (IFM_INST(media) != 0)
464 printf(" instance %d", IFM_INST(media));
465 }
466
467 /**********************************************************************
468 * ...until here.
469 **********************************************************************/
470
471 static struct cmd media_cmds[] = {
472 DEF_CMD_ARG("media", setmedia),
473 DEF_CMD_ARG("mode", setmediamode),
474 DEF_CMD_ARG("mediaopt", setmediaopt),
475 DEF_CMD_ARG("-mediaopt",unsetmediaopt),
476 DEF_CMD_ARG("inst", setmediainst),
477 DEF_CMD_ARG("instance", setmediainst),
478 };
479 static struct afswtch af_media = {
480 .af_name = "af_media",
481 .af_af = AF_UNSPEC,
482 .af_other_status = media_status,
483 };
484
485 static __constructor void
ifmedia_ctor(void)486 ifmedia_ctor(void)
487 {
488 size_t i;
489
490 for (i = 0; i < nitems(media_cmds); i++)
491 cmd_register(&media_cmds[i]);
492 af_register(&af_media);
493 }
494