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