ifconfig.c revision 155050
150276Speter/* 250276Speter * Copyright (c) 1983, 1993 3174993Srafan * The Regents of the University of California. All rights reserved. 450276Speter * 550276Speter * Redistribution and use in source and binary forms, with or without 650276Speter * modification, are permitted provided that the following conditions 750276Speter * are met: 850276Speter * 1. Redistributions of source code must retain the above copyright 950276Speter * notice, this list of conditions and the following disclaimer. 1050276Speter * 2. Redistributions in binary form must reproduce the above copyright 1150276Speter * notice, this list of conditions and the following disclaimer in the 1250276Speter * documentation and/or other materials provided with the distribution. 1350276Speter * 4. Neither the name of the University nor the names of its contributors 1450276Speter * may be used to endorse or promote products derived from this software 1550276Speter * without specific prior written permission. 1650276Speter * 1750276Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1850276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1950276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2050276Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2150276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2250276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2350276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2450276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2550276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2650276Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2750276Speter * SUCH DAMAGE. 2850276Speter */ 2950276Speter 30174993Srafan#ifndef lint 3150276Speterstatic const char copyright[] = 3250276Speter"@(#) Copyright (c) 1983, 1993\n\ 3350276Speter The Regents of the University of California. All rights reserved.\n"; 3450276Speter#endif /* not lint */ 3550276Speter 3650276Speter#ifndef lint 37174993Srafan#if 0 3850276Speterstatic char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; 39174993Srafan#endif 4050276Speterstatic const char rcsid[] = 41174993Srafan "$FreeBSD: head/sbin/ifconfig/ifconfig.c 155050 2006-01-30 13:37:34Z yar $"; 4250276Speter#endif /* not lint */ 43174993Srafan 4450276Speter#include <sys/param.h> 45174993Srafan#include <sys/ioctl.h> 4650276Speter#include <sys/socket.h> 47174993Srafan#include <sys/sysctl.h> 4850276Speter#include <sys/time.h> 49174993Srafan#include <sys/module.h> 5050276Speter#include <sys/linker.h> 51174993Srafan 5250276Speter#include <net/ethernet.h> 5350276Speter#include <net/if.h> 5450276Speter#include <net/if_var.h> 5550276Speter#include <net/if_dl.h> 56166124Srafan#include <net/if_types.h> 5750276Speter#include <net/route.h> 5850276Speter 5950276Speter/* IP */ 6050276Speter#include <netinet/in.h> 61166124Srafan#include <netinet/in_var.h> 6250276Speter#include <arpa/inet.h> 6350276Speter#include <netdb.h> 6450276Speter 6550276Speter#include <ctype.h> 66166124Srafan#include <err.h> 6750276Speter#include <errno.h> 6850276Speter#include <fcntl.h> 6950276Speter#include <stdio.h> 70166124Srafan#include <stdlib.h> 7150276Speter#include <string.h> 7250276Speter#include <unistd.h> 7350276Speter 7450276Speter#include "ifconfig.h" 7550276Speter 7650276Speter/* 7750276Speter * Since "struct ifreq" is composed of various union members, callers 7850276Speter * should pay special attention to interprete the value. 79166124Srafan * (.e.g. little/big endian difference in the structure.) 8050276Speter */ 8150276Speterstruct ifreq ifr; 82166124Srafan 8350276Speterchar name[IFNAMSIZ]; 8450276Speterint flags; 8550276Speterint setaddr; 8650276Speterint setipdst; 8750276Speterint setmask; 8850276Speterint doalias; 8950276Speterint clearaddr; 9050276Speterint newaddr = 1; 9150276Speterint verbose; 9250276Speter 9350276Speterint supmedia = 0; 9450276Speterint printkeys = 0; /* Print keying material for interfaces. */ 9550276Speterint printname = 0; /* Print the name of the created interface. */ 9650276Speter 9750276Speterstatic int ifconfig(int argc, char *const *argv, const struct afswtch *afp); 9850276Speterstatic void status(const struct afswtch *afp, int addrcount, 9950276Speter struct sockaddr_dl *sdl, struct if_msghdr *ifm, 10050276Speter struct ifa_msghdr *ifam); 101static void tunnel_status(int s); 102static void usage(void); 103 104static struct afswtch *af_getbyname(const char *name); 105static struct afswtch *af_getbyfamily(int af); 106static void af_other_status(int); 107 108static struct option *opts = NULL; 109 110void 111opt_register(struct option *p) 112{ 113 p->next = opts; 114 opts = p; 115} 116 117static void 118usage(void) 119{ 120 char options[1024]; 121 struct option *p; 122 123 /* XXX not right but close enough for now */ 124 options[0] = '\0'; 125 for (p = opts; p != NULL; p = p->next) { 126 strlcat(options, p->opt_usage, sizeof(options)); 127 strlcat(options, " ", sizeof(options)); 128 } 129 130 fprintf(stderr, 131 "usage: ifconfig %sinterface address_family [address [dest_address]]\n" 132 " [parameters]\n" 133 " ifconfig interface create\n" 134 " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n" 135 " ifconfig -l [-d] [-u] [address_family]\n" 136 " ifconfig %s[-d] [-m] [-u] [-v]\n", 137 options, options, options); 138 exit(1); 139} 140 141int 142main(int argc, char *argv[]) 143{ 144 int c, all, namesonly, downonly, uponly; 145 int need_nl = 0, count = 0; 146 const struct afswtch *afp = NULL; 147 int addrcount, ifindex; 148 struct if_msghdr *ifm, *nextifm; 149 struct ifa_msghdr *ifam; 150 struct sockaddr_dl *sdl; 151 char *buf, *lim, *next; 152 size_t needed; 153 int mib[6]; 154 char options[1024]; 155 struct option *p; 156 157 all = downonly = uponly = namesonly = verbose = 0; 158 159 /* Parse leading line options */ 160 strlcpy(options, "adklmuv", sizeof(options)); 161 for (p = opts; p != NULL; p = p->next) 162 strlcat(options, p->opt, sizeof(options)); 163 while ((c = getopt(argc, argv, options)) != -1) { 164 switch (c) { 165 case 'a': /* scan all interfaces */ 166 all++; 167 break; 168 case 'd': /* restrict scan to "down" interfaces */ 169 downonly++; 170 break; 171 case 'k': 172 printkeys++; 173 break; 174 case 'l': /* scan interface names only */ 175 namesonly++; 176 break; 177 case 'm': /* show media choices in status */ 178 supmedia = 1; 179 break; 180 case 'u': /* restrict scan to "up" interfaces */ 181 uponly++; 182 break; 183 case 'v': 184 verbose++; 185 break; 186 default: 187 for (p = opts; p != NULL; p = p->next) 188 if (p->opt[0] == c) { 189 p->cb(optarg); 190 break; 191 } 192 if (p == NULL) 193 usage(); 194 break; 195 } 196 } 197 argc -= optind; 198 argv += optind; 199 200 /* -l cannot be used with -a or -m */ 201 if (namesonly && (all || supmedia)) 202 usage(); 203 204 /* nonsense.. */ 205 if (uponly && downonly) 206 usage(); 207 208 /* no arguments is equivalent to '-a' */ 209 if (!namesonly && argc < 1) 210 all = 1; 211 212 /* -a and -l allow an address family arg to limit the output */ 213 if (all || namesonly) { 214 if (argc > 1) 215 usage(); 216 217 ifindex = 0; 218 if (argc == 1) { 219 afp = af_getbyname(*argv); 220 if (afp == NULL) 221 usage(); 222 if (afp->af_name != NULL) 223 argc--, argv++; 224 /* leave with afp non-zero */ 225 } 226 } else { 227 /* not listing, need an argument */ 228 if (argc < 1) 229 usage(); 230 231 strncpy(name, *argv, sizeof(name)); 232 argc--, argv++; 233 234 /* check and maybe load support for this interface */ 235 ifmaybeload(name); 236 237 /* 238 * NOTE: We must special-case the `create' command right 239 * here as we would otherwise fail when trying to find 240 * the interface. 241 */ 242 if (argc > 0 && (strcmp(argv[0], "create") == 0 || 243 strcmp(argv[0], "plumb") == 0)) { 244 clone_create(); 245 argc--, argv++; 246 if (argc == 0) 247 goto end; 248 } 249 ifindex = if_nametoindex(name); 250 if (ifindex == 0) 251 errx(1, "interface %s does not exist", name); 252 } 253 254 /* Check for address family */ 255 if (argc > 0) { 256 afp = af_getbyname(*argv); 257 if (afp != NULL) 258 argc--, argv++; 259 } 260 261retry: 262 mib[0] = CTL_NET; 263 mib[1] = PF_ROUTE; 264 mib[2] = 0; 265 mib[3] = 0; /* address family */ 266 mib[4] = NET_RT_IFLIST; 267 mib[5] = ifindex; /* interface index */ 268 269 /* if particular family specified, only ask about it */ 270 if (afp != NULL) 271 mib[3] = afp->af_af; 272 273 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 274 errx(1, "iflist-sysctl-estimate"); 275 if ((buf = malloc(needed)) == NULL) 276 errx(1, "malloc"); 277 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 278 if (errno == ENOMEM && count++ < 10) { 279 warnx("Routing table grew, retrying"); 280 free(buf); 281 sleep(1); 282 goto retry; 283 } 284 errx(1, "actual retrieval of interface table"); 285 } 286 lim = buf + needed; 287 288 next = buf; 289 while (next < lim) { 290 291 ifm = (struct if_msghdr *)next; 292 293 if (ifm->ifm_type == RTM_IFINFO) { 294 if (ifm->ifm_data.ifi_datalen == 0) 295 ifm->ifm_data.ifi_datalen = sizeof(struct if_data); 296 sdl = (struct sockaddr_dl *)((char *)ifm + sizeof(struct if_msghdr) - 297 sizeof(struct if_data) + ifm->ifm_data.ifi_datalen); 298 flags = ifm->ifm_flags; 299 } else { 300 fprintf(stderr, "out of sync parsing NET_RT_IFLIST\n"); 301 fprintf(stderr, "expected %d, got %d\n", RTM_IFINFO, 302 ifm->ifm_type); 303 fprintf(stderr, "msglen = %d\n", ifm->ifm_msglen); 304 fprintf(stderr, "buf:%p, next:%p, lim:%p\n", buf, next, 305 lim); 306 exit (1); 307 } 308 309 next += ifm->ifm_msglen; 310 ifam = NULL; 311 addrcount = 0; 312 while (next < lim) { 313 314 nextifm = (struct if_msghdr *)next; 315 316 if (nextifm->ifm_type != RTM_NEWADDR) 317 break; 318 319 if (ifam == NULL) 320 ifam = (struct ifa_msghdr *)nextifm; 321 322 addrcount++; 323 next += nextifm->ifm_msglen; 324 } 325 memcpy(name, sdl->sdl_data, 326 sizeof(name) < sdl->sdl_nlen ? 327 sizeof(name)-1 : sdl->sdl_nlen); 328 name[sizeof(name) < sdl->sdl_nlen ? 329 sizeof(name)-1 : sdl->sdl_nlen] = '\0'; 330 331 if (all || namesonly) { 332 if (uponly) 333 if ((flags & IFF_UP) == 0) 334 continue; /* not up */ 335 if (downonly) 336 if (flags & IFF_UP) 337 continue; /* not down */ 338 if (namesonly) { 339 if (afp == NULL || afp->af_af != AF_LINK || 340 sdl->sdl_type == IFT_ETHER) { 341 if (need_nl) 342 putchar(' '); 343 fputs(name, stdout); 344 need_nl++; 345 } 346 continue; 347 } 348 } 349 350 if (argc > 0) 351 ifconfig(argc, argv, afp); 352 else 353 status(afp, addrcount, sdl, ifm, ifam); 354 } 355 free(buf); 356 357 if (namesonly && need_nl > 0) 358 putchar('\n'); 359end: 360 if (printname) 361 printf("%s\n", name); 362 363 exit (0); 364} 365 366static struct afswtch *afs = NULL; 367 368void 369af_register(struct afswtch *p) 370{ 371 p->af_next = afs; 372 afs = p; 373} 374 375static struct afswtch * 376af_getbyname(const char *name) 377{ 378 struct afswtch *afp; 379 380 for (afp = afs; afp != NULL; afp = afp->af_next) 381 if (strcmp(afp->af_name, name) == 0) 382 return afp; 383 return NULL; 384} 385 386static struct afswtch * 387af_getbyfamily(int af) 388{ 389 struct afswtch *afp; 390 391 for (afp = afs; afp != NULL; afp = afp->af_next) 392 if (afp->af_af == af) 393 return afp; 394 return NULL; 395} 396 397static void 398af_other_status(int s) 399{ 400 struct afswtch *afp; 401 uint8_t afmask[howmany(AF_MAX, NBBY)]; 402 403 memset(afmask, 0, sizeof(afmask)); 404 for (afp = afs; afp != NULL; afp = afp->af_next) { 405 if (afp->af_other_status == NULL) 406 continue; 407 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) 408 continue; 409 afp->af_other_status(s); 410 setbit(afmask, afp->af_af); 411 } 412} 413 414static void 415af_all_tunnel_status(int s) 416{ 417 struct afswtch *afp; 418 uint8_t afmask[howmany(AF_MAX, NBBY)]; 419 420 memset(afmask, 0, sizeof(afmask)); 421 for (afp = afs; afp != NULL; afp = afp->af_next) { 422 if (afp->af_status_tunnel == NULL) 423 continue; 424 if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af)) 425 continue; 426 afp->af_status_tunnel(s); 427 setbit(afmask, afp->af_af); 428 } 429} 430 431static struct cmd *cmds = NULL; 432 433void 434cmd_register(struct cmd *p) 435{ 436 p->c_next = cmds; 437 cmds = p; 438} 439 440static const struct cmd * 441cmd_lookup(const char *name) 442{ 443#define N(a) (sizeof(a)/sizeof(a[0])) 444 const struct cmd *p; 445 446 for (p = cmds; p != NULL; p = p->c_next) 447 if (strcmp(name, p->c_name) == 0) 448 return p; 449 return NULL; 450#undef N 451} 452 453struct callback { 454 callback_func *cb_func; 455 void *cb_arg; 456 struct callback *cb_next; 457}; 458static struct callback *callbacks = NULL; 459 460void 461callback_register(callback_func *func, void *arg) 462{ 463 struct callback *cb; 464 465 cb = malloc(sizeof(struct callback)); 466 if (cb == NULL) 467 errx(1, "unable to allocate memory for callback"); 468 cb->cb_func = func; 469 cb->cb_arg = arg; 470 cb->cb_next = callbacks; 471 callbacks = cb; 472} 473 474/* specially-handled commands */ 475static void setifaddr(const char *, int, int, const struct afswtch *); 476static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr); 477 478static void setifdstaddr(const char *, int, int, const struct afswtch *); 479static const struct cmd setifdstaddr_cmd = 480 DEF_CMD("ifdstaddr", 0, setifdstaddr); 481 482static int 483ifconfig(int argc, char *const *argv, const struct afswtch *afp) 484{ 485 struct callback *cb; 486 int s; 487 488 if (afp == NULL) 489 afp = af_getbyname("inet"); 490 ifr.ifr_addr.sa_family = 491 afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ? 492 AF_INET : afp->af_af; 493 strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); 494 495 if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) 496 err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family); 497 498 while (argc > 0) { 499 const struct cmd *p; 500 501 p = cmd_lookup(*argv); 502 if (p == NULL) { 503 /* 504 * Not a recognized command, choose between setting 505 * the interface address and the dst address. 506 */ 507 p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd); 508 } 509 if (p->c_u.c_func || p->c_u.c_func2) { 510 if (p->c_parameter == NEXTARG) { 511 if (argv[1] == NULL) 512 errx(1, "'%s' requires argument", 513 p->c_name); 514 p->c_u.c_func(argv[1], 0, s, afp); 515 argc--, argv++; 516 } else if (p->c_parameter == OPTARG) { 517 p->c_u.c_func(argv[1], 0, s, afp); 518 if (argv[1] != NULL) 519 argc--, argv++; 520 } else if (p->c_parameter == NEXTARG2) { 521 if (argc < 3) 522 errx(1, "'%s' requires 2 arguments", 523 p->c_name); 524 p->c_u.c_func2(argv[1], argv[2], s, afp); 525 argc -= 2, argv += 2; 526 } else 527 p->c_u.c_func(*argv, p->c_parameter, s, afp); 528 } 529 argc--, argv++; 530 } 531 532 /* 533 * Do any post argument processing required by the address family. 534 */ 535 if (afp->af_postproc != NULL) 536 afp->af_postproc(s, afp); 537 /* 538 * Do deferred callbacks registered while processing 539 * command-line arguments. 540 */ 541 for (cb = callbacks; cb != NULL; cb = cb->cb_next) 542 cb->cb_func(s, cb->cb_arg); 543 /* 544 * Do deferred operations. 545 */ 546 if (clearaddr) { 547 if (afp->af_ridreq == NULL || afp->af_difaddr == 0) { 548 warnx("interface %s cannot change %s addresses!", 549 name, afp->af_name); 550 clearaddr = 0; 551 } 552 } 553 if (clearaddr) { 554 int ret; 555 strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name); 556 ret = ioctl(s, afp->af_difaddr, afp->af_ridreq); 557 if (ret < 0) { 558 if (errno == EADDRNOTAVAIL && (doalias >= 0)) { 559 /* means no previous address for interface */ 560 } else 561 Perror("ioctl (SIOCDIFADDR)"); 562 } 563 } 564 if (newaddr) { 565 if (afp->af_addreq == NULL || afp->af_aifaddr == 0) { 566 warnx("interface %s cannot change %s addresses!", 567 name, afp->af_name); 568 newaddr = 0; 569 } 570 } 571 if (newaddr && (setaddr || setmask)) { 572 strncpy(afp->af_addreq, name, sizeof ifr.ifr_name); 573 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) 574 Perror("ioctl (SIOCAIFADDR)"); 575 } 576 577 close(s); 578 return(0); 579} 580 581/*ARGSUSED*/ 582static void 583setifaddr(const char *addr, int param, int s, const struct afswtch *afp) 584{ 585 if (afp->af_getaddr == NULL) 586 return; 587 /* 588 * Delay the ioctl to set the interface addr until flags are all set. 589 * The address interpretation may depend on the flags, 590 * and the flags may change when the address is set. 591 */ 592 setaddr++; 593 if (doalias == 0 && afp->af_af != AF_LINK) 594 clearaddr = 1; 595 afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR)); 596} 597 598static void 599settunnel(const char *src, const char *dst, int s, const struct afswtch *afp) 600{ 601 struct addrinfo *srcres, *dstres; 602 int ecode; 603 604 if (afp->af_settunnel == NULL) { 605 warn("address family %s does not support tunnel setup", 606 afp->af_name); 607 return; 608 } 609 610 if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0) 611 errx(1, "error in parsing address string: %s", 612 gai_strerror(ecode)); 613 614 if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) 615 errx(1, "error in parsing address string: %s", 616 gai_strerror(ecode)); 617 618 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) 619 errx(1, 620 "source and destination address families do not match"); 621 622 afp->af_settunnel(s, srcres, dstres); 623 624 freeaddrinfo(srcres); 625 freeaddrinfo(dstres); 626} 627 628/* ARGSUSED */ 629static void 630deletetunnel(const char *vname, int param, int s, const struct afswtch *afp) 631{ 632 633 if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0) 634 err(1, "SIOCDIFPHYADDR"); 635} 636 637static void 638setifnetmask(const char *addr, int dummy __unused, int s, 639 const struct afswtch *afp) 640{ 641 if (afp->af_getaddr != NULL) { 642 setmask++; 643 afp->af_getaddr(addr, MASK); 644 } 645} 646 647static void 648setifbroadaddr(const char *addr, int dummy __unused, int s, 649 const struct afswtch *afp) 650{ 651 if (afp->af_getaddr != NULL) 652 afp->af_getaddr(addr, DSTADDR); 653} 654 655static void 656setifipdst(const char *addr, int dummy __unused, int s, 657 const struct afswtch *afp) 658{ 659 const struct afswtch *inet; 660 661 inet = af_getbyname("inet"); 662 if (inet == NULL) 663 return; 664 inet->af_getaddr(addr, DSTADDR); 665 setipdst++; 666 clearaddr = 0; 667 newaddr = 0; 668} 669 670static void 671notealias(const char *addr, int param, int s, const struct afswtch *afp) 672{ 673#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) 674 if (setaddr && doalias == 0 && param < 0) 675 if (afp->af_addreq != NULL && afp->af_ridreq != NULL) 676 bcopy((caddr_t)rqtosa(af_addreq), 677 (caddr_t)rqtosa(af_ridreq), 678 rqtosa(af_addreq)->sa_len); 679 doalias = param; 680 if (param < 0) { 681 clearaddr = 1; 682 newaddr = 0; 683 } else 684 clearaddr = 0; 685#undef rqtosa 686} 687 688/*ARGSUSED*/ 689static void 690setifdstaddr(const char *addr, int param __unused, int s, 691 const struct afswtch *afp) 692{ 693 if (afp->af_getaddr != NULL) 694 afp->af_getaddr(addr, DSTADDR); 695} 696 697/* 698 * Note: doing an SIOCIGIFFLAGS scribbles on the union portion 699 * of the ifreq structure, which may confuse other parts of ifconfig. 700 * Make a private copy so we can avoid that. 701 */ 702static void 703setifflags(const char *vname, int value, int s, const struct afswtch *afp) 704{ 705 struct ifreq my_ifr; 706 707 bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq)); 708 709 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) { 710 Perror("ioctl (SIOCGIFFLAGS)"); 711 exit(1); 712 } 713 strncpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name)); 714 flags = (my_ifr.ifr_flags & 0xffff) | (my_ifr.ifr_flagshigh << 16); 715 716 if (value < 0) { 717 value = -value; 718 flags &= ~value; 719 } else 720 flags |= value; 721 my_ifr.ifr_flags = flags & 0xffff; 722 my_ifr.ifr_flagshigh = flags >> 16; 723 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0) 724 Perror(vname); 725} 726 727void 728setifcap(const char *vname, int value, int s, const struct afswtch *afp) 729{ 730 731 if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) { 732 Perror("ioctl (SIOCGIFCAP)"); 733 exit(1); 734 } 735 flags = ifr.ifr_curcap; 736 if (value < 0) { 737 value = -value; 738 flags &= ~value; 739 } else 740 flags |= value; 741 ifr.ifr_reqcap = flags; 742 if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0) 743 Perror(vname); 744} 745 746static void 747setifmetric(const char *val, int dummy __unused, int s, 748 const struct afswtch *afp) 749{ 750 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 751 ifr.ifr_metric = atoi(val); 752 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) 753 warn("ioctl (set metric)"); 754} 755 756static void 757setifmtu(const char *val, int dummy __unused, int s, 758 const struct afswtch *afp) 759{ 760 strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 761 ifr.ifr_mtu = atoi(val); 762 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) 763 warn("ioctl (set mtu)"); 764} 765 766static void 767setifname(const char *val, int dummy __unused, int s, 768 const struct afswtch *afp) 769{ 770 char *newname; 771 772 newname = strdup(val); 773 if (newname == NULL) { 774 warn("no memory to set ifname"); 775 return; 776 } 777 ifr.ifr_data = newname; 778 if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) { 779 warn("ioctl (set name)"); 780 free(newname); 781 return; 782 } 783 strlcpy(name, newname, sizeof(name)); 784 free(newname); 785 786 /* 787 * Even if we just created the interface, we don't need to print 788 * its name because we just nailed it down separately. 789 */ 790 printname = 0; 791} 792 793/* 794 * Expand the compacted form of addresses as returned via the 795 * configuration read via sysctl(). 796 */ 797static void 798rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo) 799{ 800 struct sockaddr *sa; 801 int i; 802 803 memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); 804 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { 805 if ((rtinfo->rti_addrs & (1 << i)) == 0) 806 continue; 807 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; 808 cp += SA_SIZE(sa); 809 } 810} 811 812#define IFFBITS \ 813"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \ 814"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ 815"\20MULTICAST\21POLLING\22PPROMISC\23MONITOR\24STATICARP\25NEEDSGIANT" 816 817#define IFCAPBITS \ 818"\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" 819 820/* 821 * Print the status of the interface. If an address family was 822 * specified, show only it; otherwise, show them all. 823 */ 824static void 825status(const struct afswtch *afp, int addrcount, struct sockaddr_dl *sdl, 826 struct if_msghdr *ifm, struct ifa_msghdr *ifam) 827{ 828 struct rt_addrinfo info; 829 int allfamilies, s; 830 struct ifstat ifs; 831 832 if (afp == NULL) { 833 allfamilies = 1; 834 afp = af_getbyname("inet"); 835 } else 836 allfamilies = 0; 837 838 ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af; 839 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 840 841 s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); 842 if (s < 0) 843 err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family); 844 845 printf("%s: ", name); 846 printb("flags", flags, IFFBITS); 847 if (ifm->ifm_data.ifi_metric) 848 printf(" metric %ld", ifm->ifm_data.ifi_metric); 849 if (ifm->ifm_data.ifi_mtu) 850 printf(" mtu %ld", ifm->ifm_data.ifi_mtu); 851 putchar('\n'); 852 853 if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) { 854 if (ifr.ifr_curcap != 0) { 855 printb("\toptions", ifr.ifr_curcap, IFCAPBITS); 856 putchar('\n'); 857 } 858 if (supmedia && ifr.ifr_reqcap != 0) { 859 printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS); 860 putchar('\n'); 861 } 862 } 863 864 tunnel_status(s); 865 866 while (addrcount > 0) { 867 info.rti_addrs = ifam->ifam_addrs; 868 /* Expand the compacted addresses */ 869 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, 870 &info); 871 872 if (allfamilies) { 873 const struct afswtch *p; 874 p = af_getbyfamily(info.rti_info[RTAX_IFA]->sa_family); 875 if (p != NULL && p->af_status != NULL) 876 p->af_status(s, &info); 877 } else if (afp->af_af == info.rti_info[RTAX_IFA]->sa_family) 878 afp->af_status(s, &info); 879 addrcount--; 880 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen); 881 } 882 if (allfamilies || afp->af_af == AF_LINK) { 883 const struct afswtch *lafp; 884 885 /* 886 * Hack; the link level address is received separately 887 * from the routing information so any address is not 888 * handled above. Cobble together an entry and invoke 889 * the status method specially. 890 */ 891 lafp = af_getbyname("lladdr"); 892 if (lafp != NULL) { 893 info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl; 894 lafp->af_status(s, &info); 895 } 896 } 897 if (allfamilies) 898 af_other_status(s); 899 else if (afp->af_other_status != NULL) 900 afp->af_other_status(s); 901 902 strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name); 903 if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) 904 printf("%s", ifs.ascii); 905 906 close(s); 907 return; 908} 909 910static void 911tunnel_status(int s) 912{ 913 af_all_tunnel_status(s); 914} 915 916void 917Perror(const char *cmd) 918{ 919 switch (errno) { 920 921 case ENXIO: 922 errx(1, "%s: no such interface", cmd); 923 break; 924 925 case EPERM: 926 errx(1, "%s: permission denied", cmd); 927 break; 928 929 default: 930 err(1, "%s", cmd); 931 } 932} 933 934/* 935 * Print a value a la the %b format of the kernel's printf 936 */ 937void 938printb(const char *s, unsigned v, const char *bits) 939{ 940 int i, any = 0; 941 char c; 942 943 if (bits && *bits == 8) 944 printf("%s=%o", s, v); 945 else 946 printf("%s=%x", s, v); 947 bits++; 948 if (bits) { 949 putchar('<'); 950 while ((i = *bits++) != '\0') { 951 if (v & (1 << (i-1))) { 952 if (any) 953 putchar(','); 954 any = 1; 955 for (; (c = *bits) > 32; bits++) 956 putchar(c); 957 } else 958 for (; *bits > 32; bits++) 959 ; 960 } 961 putchar('>'); 962 } 963} 964 965void 966ifmaybeload(char *name) 967{ 968 struct module_stat mstat; 969 int fileid, modid; 970 char ifkind[35], *cp, *dp; 971 972 /* turn interface and unit into module name */ 973 strcpy(ifkind, "if_"); 974 for (cp = name, dp = ifkind + 3; 975 (*cp != 0) && !isdigit(*cp); cp++, dp++) 976 *dp = *cp; 977 *dp = 0; 978 979 /* scan files in kernel */ 980 mstat.version = sizeof(struct module_stat); 981 for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) { 982 /* scan modules in file */ 983 for (modid = kldfirstmod(fileid); modid > 0; 984 modid = modfnext(modid)) { 985 if (modstat(modid, &mstat) < 0) 986 continue; 987 /* strip bus name if present */ 988 if ((cp = strchr(mstat.name, '/')) != NULL) { 989 cp++; 990 } else { 991 cp = mstat.name; 992 } 993 /* already loaded? */ 994 if (strncmp(name, cp, strlen(cp)) == 0 || 995 strncmp(ifkind, cp, strlen(cp)) == 0) 996 return; 997 } 998 } 999 1000 /* not present, we should try to load it */ 1001 kldload(ifkind); 1002} 1003 1004static struct cmd basic_cmds[] = { 1005 DEF_CMD("up", IFF_UP, setifflags), 1006 DEF_CMD("down", -IFF_UP, setifflags), 1007 DEF_CMD("arp", -IFF_NOARP, setifflags), 1008 DEF_CMD("-arp", IFF_NOARP, setifflags), 1009 DEF_CMD("debug", IFF_DEBUG, setifflags), 1010 DEF_CMD("-debug", -IFF_DEBUG, setifflags), 1011 DEF_CMD("promisc", IFF_PPROMISC, setifflags), 1012 DEF_CMD("-promisc", -IFF_PPROMISC, setifflags), 1013 DEF_CMD("add", IFF_UP, notealias), 1014 DEF_CMD("alias", IFF_UP, notealias), 1015 DEF_CMD("-alias", -IFF_UP, notealias), 1016 DEF_CMD("delete", -IFF_UP, notealias), 1017 DEF_CMD("remove", -IFF_UP, notealias), 1018#ifdef notdef 1019#define EN_SWABIPS 0x1000 1020 DEF_CMD("swabips", EN_SWABIPS, setifflags), 1021 DEF_CMD("-swabips", -EN_SWABIPS, setifflags), 1022#endif 1023 DEF_CMD_ARG("netmask", setifnetmask), 1024 DEF_CMD_ARG("metric", setifmetric), 1025 DEF_CMD_ARG("broadcast", setifbroadaddr), 1026 DEF_CMD_ARG("ipdst", setifipdst), 1027 DEF_CMD_ARG2("tunnel", settunnel), 1028 DEF_CMD("-tunnel", 0, deletetunnel), 1029 DEF_CMD("deletetunnel", 0, deletetunnel), 1030 DEF_CMD("link0", IFF_LINK0, setifflags), 1031 DEF_CMD("-link0", -IFF_LINK0, setifflags), 1032 DEF_CMD("link1", IFF_LINK1, setifflags), 1033 DEF_CMD("-link1", -IFF_LINK1, setifflags), 1034 DEF_CMD("link2", IFF_LINK2, setifflags), 1035 DEF_CMD("-link2", -IFF_LINK2, setifflags), 1036 DEF_CMD("monitor", IFF_MONITOR, setifflags), 1037 DEF_CMD("-monitor", -IFF_MONITOR, setifflags), 1038 DEF_CMD("staticarp", IFF_STATICARP, setifflags), 1039 DEF_CMD("-staticarp", -IFF_STATICARP, setifflags), 1040 DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap), 1041 DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap), 1042 DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap), 1043 DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap), 1044 DEF_CMD("netcons", IFCAP_NETCONS, setifcap), 1045 DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap), 1046 DEF_CMD("polling", IFCAP_POLLING, setifcap), 1047 DEF_CMD("-polling", -IFCAP_POLLING, setifcap), 1048 DEF_CMD("normal", -IFF_LINK0, setifflags), 1049 DEF_CMD("compress", IFF_LINK0, setifflags), 1050 DEF_CMD("noicmp", IFF_LINK1, setifflags), 1051 DEF_CMD_ARG("mtu", setifmtu), 1052 DEF_CMD_ARG("name", setifname), 1053}; 1054 1055static __constructor void 1056ifconfig_ctor(void) 1057{ 1058#define N(a) (sizeof(a) / sizeof(a[0])) 1059 int i; 1060 1061 for (i = 0; i < N(basic_cmds); i++) 1062 cmd_register(&basic_cmds[i]); 1063#undef N 1064} 1065