diff --git a/sbin/ifconfig/ifmedia.c b/sbin/ifconfig/ifmedia.c index 66eb40254889..aacf34a13248 100644 --- a/sbin/ifconfig/ifmedia.c +++ b/sbin/ifconfig/ifmedia.c @@ -1,491 +1,494 @@ /* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */ /* $FreeBSD$ */ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 1997 Jason R. Thorpe. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project * by Jason R. Thorpe. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ifconfig.h" static void domediaopt(const char *, bool, int); static ifmedia_t get_media_subtype(ifmedia_t, const char *); static ifmedia_t get_media_mode(ifmedia_t, const char *); static ifmedia_t get_media_options(ifmedia_t, const char *); static void print_media(ifmedia_t, bool); static void print_media_ifconfig(ifmedia_t); static void media_status(int s) { struct ifmediareq *ifmr; if (ifconfig_media_get_mediareq(lifh, name, &ifmr) == -1) return; if (ifmr->ifm_count == 0) { warnx("%s: no media types?", name); goto free; } printf("\tmedia: "); print_media(ifmr->ifm_current, true); if (ifmr->ifm_active != ifmr->ifm_current) { putchar(' '); putchar('('); print_media(ifmr->ifm_active, false); putchar(')'); } putchar('\n'); if (ifmr->ifm_status & IFM_AVALID) { struct ifdownreason ifdr; const char *status; status = ifconfig_media_get_status(ifmr); printf("\tstatus: %s", status); if (strcmp(status, "no carrier") == 0 && ifconfig_media_get_downreason(lifh, name, &ifdr) == 0) { switch (ifdr.ifdr_reason) { case IFDR_REASON_MSG: printf(" (%s)", ifdr.ifdr_msg); break; case IFDR_REASON_VENDOR: printf(" (vendor code %d)", ifdr.ifdr_vendor); break; default: break; } } putchar('\n'); } if (supmedia) { printf("\tsupported media:\n"); for (size_t i = 0; i < ifmr->ifm_count; ++i) { printf("\t\t"); print_media_ifconfig(ifmr->ifm_ulist[i]); putchar('\n'); } } free: free(ifmr); } struct ifmediareq * ifmedia_getstate(void) { - static struct ifmediareq *ifmr; + static struct ifmediareq *ifmr = NULL; + + if (ifmr != NULL) + return (ifmr); if (ifconfig_media_get_mediareq(lifh, name, &ifmr) == -1) errc(1, ifconfig_err_errno(lifh), "%s: ifconfig_media_get_mediareq", name); if (ifmr->ifm_count == 0) errx(1, "%s: no media types?", name); return (ifmr); } static void setifmediacallback(int s, void *arg) { struct ifmediareq *ifmr = (struct ifmediareq *)arg; static bool did_it = false; if (!did_it) { ifr.ifr_media = ifmr->ifm_current; if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) err(1, "SIOCSIFMEDIA (media)"); free(ifmr); did_it = true; } } static void setmedia(const char *val, int d, int s, const struct afswtch *afp) { struct ifmediareq *ifmr; int subtype; ifmr = ifmedia_getstate(); /* * We are primarily concerned with the top-level type. * However, "current" may be only IFM_NONE, so we just look * for the top-level type in the first "supported type" * entry. * * (I'm assuming that all supported media types for a given * interface will be the same top-level type..) */ subtype = get_media_subtype(ifmr->ifm_ulist[0], val); strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) | IFM_TYPE(ifmr->ifm_ulist[0]) | subtype; ifmr->ifm_current = ifr.ifr_media; callback_register(setifmediacallback, (void *)ifmr); } static void setmediaopt(const char *val, int d, int s, const struct afswtch *afp) { domediaopt(val, false, s); } static void unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp) { domediaopt(val, true, s); } static void domediaopt(const char *val, bool clear, int s) { struct ifmediareq *ifmr; ifmedia_t options; ifmr = ifmedia_getstate(); options = get_media_options(ifmr->ifm_ulist[0], val); strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_media = ifmr->ifm_current; if (clear) ifr.ifr_media &= ~options; else { if (options & IFM_HDX) { ifr.ifr_media &= ~IFM_FDX; options &= ~IFM_HDX; } ifr.ifr_media |= options; } ifmr->ifm_current = ifr.ifr_media; callback_register(setifmediacallback, (void *)ifmr); } static void setmediainst(const char *val, int d, int s, const struct afswtch *afp) { struct ifmediareq *ifmr; int inst; ifmr = ifmedia_getstate(); inst = atoi(val); if (inst < 0 || inst > (int)IFM_INST_MAX) errx(1, "invalid media instance: %s", val); strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT; ifmr->ifm_current = ifr.ifr_media; callback_register(setifmediacallback, (void *)ifmr); } static void setmediamode(const char *val, int d, int s, const struct afswtch *afp) { struct ifmediareq *ifmr; int mode; ifmr = ifmedia_getstate(); mode = get_media_mode(ifmr->ifm_ulist[0], val); strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode; ifmr->ifm_current = ifr.ifr_media; callback_register(setifmediacallback, (void *)ifmr); } static ifmedia_t get_media_subtype(ifmedia_t media, const char *val) { ifmedia_t subtype; subtype = ifconfig_media_lookup_subtype(media, val); if (subtype != INVALID_IFMEDIA) return (subtype); switch (errno) { case EINVAL: errx(EXIT_FAILURE, "unknown media type 0x%x", media); case ENOENT: errx(EXIT_FAILURE, "unknown media subtype: %s", val); default: err(EXIT_FAILURE, "ifconfig_media_lookup_subtype"); } /*NOTREACHED*/ } static ifmedia_t get_media_mode(ifmedia_t media, const char *val) { ifmedia_t mode; mode = ifconfig_media_lookup_mode(media, val); if (mode != INVALID_IFMEDIA) return (mode); switch (errno) { case EINVAL: errx(EXIT_FAILURE, "unknown media type 0x%x", media); case ENOENT: return (INVALID_IFMEDIA); default: err(EXIT_FAILURE, "ifconfig_media_lookup_subtype"); } /*NOTREACHED*/ } static ifmedia_t get_media_options(ifmedia_t media, const char *val) { ifmedia_t *options; const char **optnames; char *opts, *opt; size_t nopts; int rval; /* * We muck with the string, so copy it. */ opts = strdup(val); if (opts == NULL) err(EXIT_FAILURE, "strdup"); /* * Split the comma-delimited list into separate strings. */ nopts = 0; for (opt = opts; (opt = strtok(opt, ",")) != NULL; opt = NULL) ++nopts; if (nopts == 0) { free(opts); return (0); } optnames = calloc(nopts, sizeof(*optnames)); if (optnames == NULL) err(EXIT_FAILURE, "calloc"); opt = opts; for (size_t i = 0; i < nopts; ++i) { optnames[i] = opt; opt = strchr(opt, '\0') + 1; } /* * Look up the options in the user-provided list. */ options = ifconfig_media_lookup_options(media, optnames, nopts); if (options == NULL) err(EXIT_FAILURE, "ifconfig_media_lookup_options"); rval = 0; for (size_t i = 0; i < nopts; ++i) { if (options[i] == INVALID_IFMEDIA) errx(EXIT_FAILURE, "unknown option: %s", optnames[i]); rval |= options[i]; } free(options); free(optnames); free(opts); return (rval); } static void print_media(ifmedia_t media, bool print_toptype) { const char *val, **options; val = ifconfig_media_get_type(media); if (val == NULL) { printf(""); return; } else if (print_toptype) { printf("%s", val); } val = ifconfig_media_get_subtype(media); if (val == NULL) { printf(""); return; } if (print_toptype) putchar(' '); printf("%s", val); if (print_toptype) { val = ifconfig_media_get_mode(media); if (val != NULL && strcasecmp("autoselect", val) != 0) printf(" mode %s", val); } options = ifconfig_media_get_options(media); if (options != NULL && options[0] != NULL) { printf(" <%s", options[0]); for (size_t i = 1; options[i] != NULL; ++i) printf(",%s", options[i]); printf(">"); } free(options); if (print_toptype && IFM_INST(media) != 0) printf(" instance %d", IFM_INST(media)); } static void print_media_ifconfig(ifmedia_t media) { const char *val, **options; val = ifconfig_media_get_type(media); if (val == NULL) { printf(""); return; } /* * Don't print the top-level type; it's not like we can * change it, or anything. */ val = ifconfig_media_get_subtype(media); if (val == NULL) { printf(""); return; } printf("media %s", val); val = ifconfig_media_get_mode(media); if (val != NULL) printf(" mode %s", val); options = ifconfig_media_get_options(media); if (options != NULL && options[0] != NULL) { printf(" mediaopt %s", options[0]); for (size_t i = 1; options[i] != NULL; ++i) printf(",%s", options[i]); } free(options); if (IFM_INST(media) != 0) printf(" instance %d", IFM_INST(media)); } /********************************************************************** * ...until here. **********************************************************************/ static struct cmd media_cmds[] = { DEF_CMD_ARG("media", setmedia), DEF_CMD_ARG("mode", setmediamode), DEF_CMD_ARG("mediaopt", setmediaopt), DEF_CMD_ARG("-mediaopt",unsetmediaopt), DEF_CMD_ARG("inst", setmediainst), DEF_CMD_ARG("instance", setmediainst), }; static struct afswtch af_media = { .af_name = "af_media", .af_af = AF_UNSPEC, .af_other_status = media_status, }; static __constructor void ifmedia_ctor(void) { size_t i; for (i = 0; i < nitems(media_cmds); i++) cmd_register(&media_cmds[i]); af_register(&af_media); }