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 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 * 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 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 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 218 setmediaopt(if_ctx *ctx, const char *val, int d __unused) 219 { 220 221 domediaopt(ctx, val, false); 222 } 223 224 static void 225 unsetmediaopt(if_ctx *ctx, const char *val, int d __unused) 226 { 227 228 domediaopt(ctx, val, true); 229 } 230 231 static void 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 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 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 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 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 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 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 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 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