]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ifconfig/ifmedia.c
fortune: update mailing list search url
[FreeBSD/FreeBSD.git] / sbin / ifconfig / ifmedia.c
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }