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(if_ctx *, const char *, bool);
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(if_ctx * ctx)100 media_status(if_ctx *ctx)
101 {
102 struct ifmediareq *ifmr;
103
104 if (ifconfig_media_get_mediareq(lifh, ctx->ifname, &ifmr) == -1)
105 return;
106
107 if (ifmr->ifm_count == 0) {
108 warnx("%s: no media types?", ctx->ifname);
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, ctx->ifname, &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 (ctx->args->supmedia) {
147 printf("\tsupported media:\n");
148 for (int 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(if_ctx * ctx)159 ifmedia_getstate(if_ctx *ctx)
160 {
161 static struct ifmediareq *ifmr = NULL;
162
163 if (ifmr != NULL)
164 return (ifmr);
165
166 if (ifconfig_media_get_mediareq(lifh, ctx->ifname, &ifmr) == -1)
167 errc(1, ifconfig_err_errno(lifh),
168 "%s: ifconfig_media_get_mediareq", ctx->ifname);
169
170 if (ifmr->ifm_count == 0)
171 errx(1, "%s: no media types?", ctx->ifname);
172
173 return (ifmr);
174 }
175
176 static void
setifmediacallback(if_ctx * ctx,void * arg)177 setifmediacallback(if_ctx *ctx, void *arg)
178 {
179 struct ifmediareq *ifmr = (struct ifmediareq *)arg;
180 static bool did_it = false;
181 struct ifreq ifr = {};
182
183 if (!did_it) {
184 ifr.ifr_media = ifmr->ifm_current;
185 if (ioctl_ctx_ifr(ctx, SIOCSIFMEDIA, &ifr) < 0)
186 err(1, "SIOCSIFMEDIA (media)");
187 free(ifmr);
188 did_it = true;
189 }
190 }
191
192 static void
setmedia(if_ctx * ctx,const char * val,int d __unused)193 setmedia(if_ctx *ctx, const char *val, int d __unused)
194 {
195 struct ifmediareq *ifmr;
196 int subtype;
197
198 ifmr = ifmedia_getstate(ctx);
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(ifmr->ifm_ulist[0], val);
210
211 ifmr->ifm_current = (ifmr->ifm_current & IFM_IMASK) |
212 IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
213
214 callback_register(setifmediacallback, (void *)ifmr);
215 }
216
217 static void
setmediaopt(if_ctx * ctx,const char * val,int d __unused)218 setmediaopt(if_ctx *ctx, const char *val, int d __unused)
219 {
220
221 domediaopt(ctx, val, false);
222 }
223
224 static void
unsetmediaopt(if_ctx * ctx,const char * val,int d __unused)225 unsetmediaopt(if_ctx *ctx, const char *val, int d __unused)
226 {
227
228 domediaopt(ctx, val, true);
229 }
230
231 static void
domediaopt(if_ctx * ctx,const char * val,bool clear)232 domediaopt(if_ctx *ctx, const char *val, bool clear)
233 {
234 struct ifmediareq *ifmr;
235 ifmedia_t options;
236
237 ifmr = ifmedia_getstate(ctx);
238
239 options = get_media_options(ifmr->ifm_ulist[0], val);
240
241 if (clear)
242 ifmr->ifm_current &= ~options;
243 else {
244 if (options & IFM_HDX) {
245 ifmr->ifm_current &= ~IFM_FDX;
246 options &= ~IFM_HDX;
247 }
248 ifmr->ifm_current |= options;
249 }
250 callback_register(setifmediacallback, (void *)ifmr);
251 }
252
253 static void
setmediainst(if_ctx * ctx,const char * val,int d __unused)254 setmediainst(if_ctx *ctx, const char *val, int d __unused)
255 {
256 struct ifmediareq *ifmr;
257 int inst;
258
259 ifmr = ifmedia_getstate(ctx);
260
261 inst = atoi(val);
262 if (inst < 0 || inst > (int)IFM_INST_MAX)
263 errx(1, "invalid media instance: %s", val);
264
265 ifmr->ifm_current = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
266
267 callback_register(setifmediacallback, (void *)ifmr);
268 }
269
270 static void
setmediamode(if_ctx * ctx,const char * val,int d __unused)271 setmediamode(if_ctx *ctx, const char *val, int d __unused)
272 {
273 struct ifmediareq *ifmr;
274 int mode;
275
276 ifmr = ifmedia_getstate(ctx);
277
278 mode = get_media_mode(ifmr->ifm_ulist[0], val);
279
280 ifmr->ifm_current = (ifmr->ifm_current & ~IFM_MMASK) | mode;
281
282 callback_register(setifmediacallback, (void *)ifmr);
283 }
284
285 static ifmedia_t
get_media_subtype(ifmedia_t media,const char * val)286 get_media_subtype(ifmedia_t media, const char *val)
287 {
288 ifmedia_t subtype;
289
290 subtype = ifconfig_media_lookup_subtype(media, val);
291 if (subtype != INVALID_IFMEDIA)
292 return (subtype);
293 switch (errno) {
294 case EINVAL:
295 errx(EXIT_FAILURE, "unknown media type 0x%x", media);
296 case ENOENT:
297 errx(EXIT_FAILURE, "unknown media subtype: %s", val);
298 default:
299 err(EXIT_FAILURE, "ifconfig_media_lookup_subtype");
300 }
301 /*NOTREACHED*/
302 }
303
304 static ifmedia_t
get_media_mode(ifmedia_t media,const char * val)305 get_media_mode(ifmedia_t media, const char *val)
306 {
307 ifmedia_t mode;
308
309 mode = ifconfig_media_lookup_mode(media, val);
310 if (mode != INVALID_IFMEDIA)
311 return (mode);
312 switch (errno) {
313 case EINVAL:
314 errx(EXIT_FAILURE, "unknown media type 0x%x", media);
315 case ENOENT:
316 return (INVALID_IFMEDIA);
317 default:
318 err(EXIT_FAILURE, "ifconfig_media_lookup_subtype");
319 }
320 /*NOTREACHED*/
321 }
322
323 static ifmedia_t
get_media_options(ifmedia_t media,const char * val)324 get_media_options(ifmedia_t media, const char *val)
325 {
326 ifmedia_t *options;
327 const char **optnames;
328 char *opts, *opt;
329 size_t nopts;
330 int rval;
331
332 /*
333 * We muck with the string, so copy it.
334 */
335 opts = strdup(val);
336 if (opts == NULL)
337 err(EXIT_FAILURE, "strdup");
338
339 /*
340 * Split the comma-delimited list into separate strings.
341 */
342 nopts = 0;
343 for (opt = opts; (opt = strtok(opt, ",")) != NULL; opt = NULL)
344 ++nopts;
345 if (nopts == 0) {
346 free(opts);
347 return (0);
348 }
349 optnames = calloc(nopts, sizeof(*optnames));
350 if (optnames == NULL)
351 err(EXIT_FAILURE, "calloc");
352 opt = opts;
353 for (size_t i = 0; i < nopts; ++i) {
354 optnames[i] = opt;
355 opt = strchr(opt, '\0') + 1;
356 }
357
358 /*
359 * Look up the options in the user-provided list.
360 */
361 options = ifconfig_media_lookup_options(media, optnames, nopts);
362 if (options == NULL)
363 err(EXIT_FAILURE, "ifconfig_media_lookup_options");
364 rval = 0;
365 for (size_t i = 0; i < nopts; ++i) {
366 if (options[i] == INVALID_IFMEDIA)
367 errx(EXIT_FAILURE, "unknown option: %s", optnames[i]);
368 rval |= options[i];
369 }
370 free(options);
371 free(optnames);
372 free(opts);
373 return (rval);
374 }
375
376 static void
print_media(ifmedia_t media,bool print_toptype)377 print_media(ifmedia_t media, bool print_toptype)
378 {
379 const char *val, **options;
380
381 val = ifconfig_media_get_type(media);
382 if (val == NULL) {
383 printf("<unknown type>");
384 return;
385 } else if (print_toptype) {
386 printf("%s", val);
387 }
388
389 val = ifconfig_media_get_subtype(media);
390 if (val == NULL) {
391 printf("<unknown subtype>");
392 return;
393 }
394
395 if (print_toptype)
396 putchar(' ');
397
398 printf("%s", val);
399
400 if (print_toptype) {
401 val = ifconfig_media_get_mode(media);
402 if (val != NULL && strcasecmp("autoselect", val) != 0)
403 printf(" mode %s", val);
404 }
405
406 options = ifconfig_media_get_options(media);
407 if (options != NULL && options[0] != NULL) {
408 printf(" <%s", options[0]);
409 for (size_t i = 1; options[i] != NULL; ++i)
410 printf(",%s", options[i]);
411 printf(">");
412 }
413 free(options);
414
415 if (print_toptype && IFM_INST(media) != 0)
416 printf(" instance %d", IFM_INST(media));
417 }
418
419 static void
print_media_ifconfig(ifmedia_t media)420 print_media_ifconfig(ifmedia_t media)
421 {
422 const char *val, **options;
423
424 val = ifconfig_media_get_type(media);
425 if (val == NULL) {
426 printf("<unknown type>");
427 return;
428 }
429
430 /*
431 * Don't print the top-level type; it's not like we can
432 * change it, or anything.
433 */
434
435 val = ifconfig_media_get_subtype(media);
436 if (val == NULL) {
437 printf("<unknown subtype>");
438 return;
439 }
440
441 printf("media %s", val);
442
443 val = ifconfig_media_get_mode(media);
444 if (val != NULL)
445 printf(" mode %s", val);
446
447 options = ifconfig_media_get_options(media);
448 if (options != NULL && options[0] != NULL) {
449 printf(" mediaopt %s", options[0]);
450 for (size_t i = 1; options[i] != NULL; ++i)
451 printf(",%s", options[i]);
452 }
453 free(options);
454
455 if (IFM_INST(media) != 0)
456 printf(" instance %d", IFM_INST(media));
457 }
458
459 /**********************************************************************
460 * ...until here.
461 **********************************************************************/
462
463 static struct cmd media_cmds[] = {
464 DEF_CMD_ARG("media", setmedia),
465 DEF_CMD_ARG("mode", setmediamode),
466 DEF_CMD_ARG("mediaopt", setmediaopt),
467 DEF_CMD_ARG("-mediaopt",unsetmediaopt),
468 DEF_CMD_ARG("inst", setmediainst),
469 DEF_CMD_ARG("instance", setmediainst),
470 };
471 static struct afswtch af_media = {
472 .af_name = "af_media",
473 .af_af = AF_UNSPEC,
474 .af_other_status = media_status,
475 };
476
477 static __constructor void
ifmedia_ctor(void)478 ifmedia_ctor(void)
479 {
480 for (size_t i = 0; i < nitems(media_cmds); i++)
481 cmd_register(&media_cmds[i]);
482 af_register(&af_media);
483 }
484