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