ifconfig.c revision 1.141
1/* $NetBSD: ifconfig.c,v 1.141 2004/03/01 00:11:33 perry Exp $ */ 2 3/*- 4 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40/* 41 * Copyright (c) 1983, 1993 42 * The Regents of the University of California. All rights reserved. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 */ 68 69#include <sys/cdefs.h> 70#ifndef lint 71__COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\ 72 The Regents of the University of California. All rights reserved.\n"); 73#endif /* not lint */ 74 75#ifndef lint 76#if 0 77static char sccsid[] = "@(#)ifconfig.c 8.2 (Berkeley) 2/16/94"; 78#else 79__RCSID("$NetBSD: ifconfig.c,v 1.141 2004/03/01 00:11:33 perry Exp $"); 80#endif 81#endif /* not lint */ 82 83#include <sys/param.h> 84#include <sys/socket.h> 85#include <sys/ioctl.h> 86 87#include <net/if.h> 88#include <net/if_dl.h> 89#include <net/if_media.h> 90#include <net/if_ether.h> 91#include <net80211/ieee80211.h> 92#include <net80211/ieee80211_ioctl.h> 93#include <net/if_vlanvar.h> 94#include <netinet/in.h> 95#include <netinet/in_var.h> 96#ifdef INET6 97#include <netinet6/nd6.h> 98#endif 99#include <arpa/inet.h> 100 101#include <netatalk/at.h> 102 103#define NSIP 104#include <netns/ns.h> 105#include <netns/ns_if.h> 106#include <netdb.h> 107 108#define EON 109#include <netiso/iso.h> 110#include <netiso/iso_var.h> 111#include <sys/protosw.h> 112 113#include <ctype.h> 114#include <err.h> 115#include <errno.h> 116#include <stddef.h> 117#include <stdio.h> 118#include <stdlib.h> 119#include <string.h> 120#include <unistd.h> 121#include <ifaddrs.h> 122#include <util.h> 123 124struct ifreq ifr, ridreq; 125struct ifaliasreq addreq __attribute__((aligned(4))); 126struct in_aliasreq in_addreq; 127#ifdef INET6 128struct in6_ifreq ifr6; 129struct in6_ifreq in6_ridreq; 130struct in6_aliasreq in6_addreq; 131#endif 132struct iso_ifreq iso_ridreq; 133struct iso_aliasreq iso_addreq; 134struct sockaddr_in netmask; 135struct netrange at_nr; /* AppleTalk net range */ 136 137char name[30]; 138u_short flags; 139int setaddr, setipdst, doalias; 140u_long metric, mtu; 141int clearaddr, s; 142int newaddr = -1; 143int conflicting = 0; 144int nsellength = 1; 145int af; 146int aflag, bflag, Cflag, dflag, lflag, mflag, sflag, uflag, vflag, zflag; 147#ifdef INET6 148int Lflag; 149#endif 150int reset_if_flags; 151int explicit_prefix = 0; 152u_int vlan_tag = (u_int)-1; 153 154struct ifcapreq g_ifcr; 155int g_ifcr_updated; 156 157void notealias __P((const char *, int)); 158void notrailers __P((const char *, int)); 159void setifaddr __P((const char *, int)); 160void setifdstaddr __P((const char *, int)); 161void setifflags __P((const char *, int)); 162void setifcaps __P((const char *, int)); 163void setifbroadaddr __P((const char *, int)); 164void setifipdst __P((const char *, int)); 165void setifmetric __P((const char *, int)); 166void setifmtu __P((const char *, int)); 167void setifnwid __P((const char *, int)); 168void setifnwkey __P((const char *, int)); 169void setifbssid __P((const char *, int)); 170void setifchan __P((const char *, int)); 171void setifpowersave __P((const char *, int)); 172void setifpowersavesleep __P((const char *, int)); 173void setifnetmask __P((const char *, int)); 174void setifprefixlen __P((const char *, int)); 175void setnsellength __P((const char *, int)); 176void setsnpaoffset __P((const char *, int)); 177void setatrange __P((const char *, int)); 178void setatphase __P((const char *, int)); 179void settunnel __P((const char *, const char *)); 180void deletetunnel __P((const char *, int)); 181#ifdef INET6 182void setia6flags __P((const char *, int)); 183void setia6pltime __P((const char *, int)); 184void setia6vltime __P((const char *, int)); 185void setia6lifetime __P((const char *, const char *)); 186void setia6eui64 __P((const char *, int)); 187#endif 188void checkatrange __P ((struct sockaddr_at *)); 189void setmedia __P((const char *, int)); 190void setmediamode __P((const char *, int)); 191void setmediaopt __P((const char *, int)); 192void unsetmediaopt __P((const char *, int)); 193void setmediainst __P((const char *, int)); 194void clone_create __P((const char *, int)); 195void clone_destroy __P((const char *, int)); 196void fixnsel __P((struct sockaddr_iso *)); 197void setvlan __P((const char *, int)); 198void setvlanif __P((const char *, int)); 199void unsetvlanif __P((const char *, int)); 200int main __P((int, char *[])); 201 202/* 203 * Media stuff. Whenever a media command is first performed, the 204 * currently select media is grabbed for this interface. If `media' 205 * is given, the current media word is modifed. `mediaopt' commands 206 * only modify the set and clear words. They then operate on the 207 * current media word later. 208 */ 209int media_current; 210int mediaopt_set; 211int mediaopt_clear; 212 213int actions; /* Actions performed */ 214 215#define A_MEDIA 0x0001 /* media command */ 216#define A_MEDIAOPTSET 0x0002 /* mediaopt command */ 217#define A_MEDIAOPTCLR 0x0004 /* -mediaopt command */ 218#define A_MEDIAOPT (A_MEDIAOPTSET|A_MEDIAOPTCLR) 219#define A_MEDIAINST 0x0008 /* instance or inst command */ 220#define A_MEDIAMODE 0x0010 /* mode command */ 221 222#define NEXTARG 0xffffff 223#define NEXTARG2 0xfffffe 224 225const struct cmd { 226 const char *c_name; 227 int c_parameter; /* NEXTARG means next argv */ 228 int c_action; /* defered action */ 229 void (*c_func) __P((const char *, int)); 230 void (*c_func2) __P((const char *, const char *)); 231} cmds[] = { 232 { "up", IFF_UP, 0, setifflags } , 233 { "down", -IFF_UP, 0, setifflags }, 234 { "trailers", -1, 0, notrailers }, 235 { "-trailers", 1, 0, notrailers }, 236 { "arp", -IFF_NOARP, 0, setifflags }, 237 { "-arp", IFF_NOARP, 0, setifflags }, 238 { "debug", IFF_DEBUG, 0, setifflags }, 239 { "-debug", -IFF_DEBUG, 0, setifflags }, 240 { "alias", IFF_UP, 0, notealias }, 241 { "-alias", -IFF_UP, 0, notealias }, 242 { "delete", -IFF_UP, 0, notealias }, 243#ifdef notdef 244#define EN_SWABIPS 0x1000 245 { "swabips", EN_SWABIPS, 0, setifflags }, 246 { "-swabips", -EN_SWABIPS, 0, setifflags }, 247#endif 248 { "netmask", NEXTARG, 0, setifnetmask }, 249 { "metric", NEXTARG, 0, setifmetric }, 250 { "mtu", NEXTARG, 0, setifmtu }, 251 { "bssid", NEXTARG, 0, setifbssid }, 252 { "-bssid", -1, 0, setifbssid }, 253 { "chan", NEXTARG, 0, setifchan }, 254 { "-chan", -1, 0, setifchan }, 255 { "ssid", NEXTARG, 0, setifnwid }, 256 { "nwid", NEXTARG, 0, setifnwid }, 257 { "nwkey", NEXTARG, 0, setifnwkey }, 258 { "-nwkey", -1, 0, setifnwkey }, 259 { "powersave", 1, 0, setifpowersave }, 260 { "-powersave", 0, 0, setifpowersave }, 261 { "powersavesleep", NEXTARG, 0, setifpowersavesleep }, 262 { "broadcast", NEXTARG, 0, setifbroadaddr }, 263 { "ipdst", NEXTARG, 0, setifipdst }, 264 { "prefixlen", NEXTARG, 0, setifprefixlen}, 265#ifdef INET6 266 { "anycast", IN6_IFF_ANYCAST, 0, setia6flags }, 267 { "-anycast", -IN6_IFF_ANYCAST, 0, setia6flags }, 268 { "tentative", IN6_IFF_TENTATIVE, 0, setia6flags }, 269 { "-tentative", -IN6_IFF_TENTATIVE, 0, setia6flags }, 270 { "deprecated", IN6_IFF_DEPRECATED, 0, setia6flags }, 271 { "-deprecated", -IN6_IFF_DEPRECATED, 0, setia6flags }, 272 { "pltime", NEXTARG, 0, setia6pltime }, 273 { "vltime", NEXTARG, 0, setia6vltime }, 274 { "eui64", 0, 0, setia6eui64 }, 275#endif /*INET6*/ 276#ifndef INET_ONLY 277 { "range", NEXTARG, 0, setatrange }, 278 { "phase", NEXTARG, 0, setatphase }, 279 { "snpaoffset", NEXTARG, 0, setsnpaoffset }, 280 { "nsellength", NEXTARG, 0, setnsellength }, 281#endif /* INET_ONLY */ 282 { "tunnel", NEXTARG2, 0, NULL, 283 settunnel } , 284 { "deletetunnel", 0, 0, deletetunnel }, 285 { "vlan", NEXTARG, 0, setvlan } , 286 { "vlanif", NEXTARG, 0, setvlanif } , 287 { "-vlanif", 0, 0, unsetvlanif } , 288#if 0 289 /* XXX `create' special-cased below */ 290 { "create", 0, 0, clone_create } , 291#endif 292 { "destroy", 0, 0, clone_destroy } , 293 { "link0", IFF_LINK0, 0, setifflags } , 294 { "-link0", -IFF_LINK0, 0, setifflags } , 295 { "link1", IFF_LINK1, 0, setifflags } , 296 { "-link1", -IFF_LINK1, 0, setifflags } , 297 { "link2", IFF_LINK2, 0, setifflags } , 298 { "-link2", -IFF_LINK2, 0, setifflags } , 299 { "media", NEXTARG, A_MEDIA, setmedia }, 300 { "mediaopt", NEXTARG, A_MEDIAOPTSET, setmediaopt }, 301 { "-mediaopt", NEXTARG, A_MEDIAOPTCLR, unsetmediaopt }, 302 { "mode", NEXTARG, A_MEDIAMODE, setmediamode }, 303 { "instance", NEXTARG, A_MEDIAINST, setmediainst }, 304 { "inst", NEXTARG, A_MEDIAINST, setmediainst }, 305 { "ip4csum", IFCAP_CSUM_IPv4,0, setifcaps }, 306 { "-ip4csum", -IFCAP_CSUM_IPv4,0, setifcaps }, 307 { "tcp4csum", IFCAP_CSUM_TCPv4,0, setifcaps }, 308 { "-tcp4csum", -IFCAP_CSUM_TCPv4,0, setifcaps }, 309 { "udp4csum", IFCAP_CSUM_UDPv4,0, setifcaps }, 310 { "-udp4csum", -IFCAP_CSUM_UDPv4,0, setifcaps }, 311 { "tcp6csum", IFCAP_CSUM_TCPv6,0, setifcaps }, 312 { "-tcp6csum", -IFCAP_CSUM_TCPv6,0, setifcaps }, 313 { "udp6csum", IFCAP_CSUM_UDPv6,0, setifcaps }, 314 { "-udp6csum", -IFCAP_CSUM_UDPv6,0, setifcaps }, 315 { "tcp4csum-rx",IFCAP_CSUM_TCPv4_Rx,0, setifcaps }, 316 { "-tcp4csum-rx",-IFCAP_CSUM_TCPv4_Rx,0, setifcaps }, 317 { "udp4csum-rx",IFCAP_CSUM_UDPv4_Rx,0, setifcaps }, 318 { "-udp4csum-rx",-IFCAP_CSUM_UDPv4_Rx,0, setifcaps }, 319 { 0, 0, 0, setifaddr }, 320 { 0, 0, 0, setifdstaddr }, 321}; 322 323void adjust_nsellength __P((void)); 324int getinfo __P((struct ifreq *)); 325int carrier __P((void)); 326void getsock __P((int)); 327void printall __P((const char *)); 328void list_cloners __P((void)); 329int prefix __P((void *, int)); 330void status __P((const struct sockaddr_dl *)); 331void usage __P((void)); 332const char *get_string __P((const char *, const char *, u_int8_t *, int *)); 333void print_string __P((const u_int8_t *, int)); 334char *sec2str __P((time_t)); 335 336const char *get_media_type_string __P((int)); 337const char *get_media_subtype_string __P((int)); 338int get_media_mode __P((int, const char *)); 339int get_media_subtype __P((int, const char *)); 340int get_media_options __P((int, const char *)); 341int lookup_media_word __P((struct ifmedia_description *, int, 342 const char *)); 343void print_media_word __P((int, int, int)); 344void process_media_commands __P((void)); 345void init_current_media __P((void)); 346 347/* 348 * XNS support liberally adapted from code written at the University of 349 * Maryland principally by James O'Toole and Chris Torek. 350 */ 351void in_alias __P((struct ifreq *)); 352void in_status __P((int)); 353void in_getaddr __P((const char *, int)); 354void in_getprefix __P((const char *, int)); 355#ifdef INET6 356void in6_fillscopeid __P((struct sockaddr_in6 *sin6)); 357void in6_alias __P((struct in6_ifreq *)); 358void in6_status __P((int)); 359void in6_getaddr __P((const char *, int)); 360void in6_getprefix __P((const char *, int)); 361#endif 362void at_status __P((int)); 363void at_getaddr __P((const char *, int)); 364void xns_status __P((int)); 365void xns_getaddr __P((const char *, int)); 366void iso_status __P((int)); 367void iso_getaddr __P((const char *, int)); 368 369void ieee80211_status __P((void)); 370void tunnel_status __P((void)); 371void vlan_status __P((void)); 372 373/* Known address families */ 374struct afswtch { 375 const char *af_name; 376 short af_af; 377 void (*af_status) __P((int)); 378 void (*af_getaddr) __P((const char *, int)); 379 void (*af_getprefix) __P((const char *, int)); 380 u_long af_difaddr; 381 u_long af_aifaddr; 382 u_long af_gifaddr; 383 caddr_t af_ridreq; 384 caddr_t af_addreq; 385} afs[] = { 386#define C(x) ((caddr_t) &x) 387 { "inet", AF_INET, in_status, in_getaddr, in_getprefix, 388 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, C(ridreq), C(in_addreq) }, 389#ifdef INET6 390 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_getprefix, 391 SIOCDIFADDR_IN6, SIOCAIFADDR_IN6, 392 /* 393 * Deleting the first address before setting new one is 394 * not prefered way in this protocol. 395 */ 396 0, 397 C(in6_ridreq), C(in6_addreq) }, 398#endif 399#ifndef INET_ONLY /* small version, for boot media */ 400 { "atalk", AF_APPLETALK, at_status, at_getaddr, NULL, 401 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, C(addreq), C(addreq) }, 402 { "ns", AF_NS, xns_status, xns_getaddr, NULL, 403 SIOCDIFADDR, SIOCAIFADDR, SIOCGIFADDR, C(ridreq), C(addreq) }, 404 { "iso", AF_ISO, iso_status, iso_getaddr, NULL, 405 SIOCDIFADDR_ISO, SIOCAIFADDR_ISO, SIOCGIFADDR_ISO, 406 C(iso_ridreq), C(iso_addreq) }, 407#endif /* INET_ONLY */ 408 { 0, 0, 0, 0 } 409}; 410 411struct afswtch *afp; /*the address family being set or asked about*/ 412 413struct afswtch *lookup_af __P((const char *)); 414 415int 416main(argc, argv) 417 int argc; 418 char *argv[]; 419{ 420 struct ifreq ifreq; 421 int ch; 422 423 /* Parse command-line options */ 424 aflag = mflag = vflag = zflag = 0; 425 while ((ch = getopt(argc, argv, "AabCdlmsuvz" 426#ifdef INET6 427 "L" 428#endif 429 )) != -1) { 430 switch (ch) { 431 case 'A': 432 warnx("-A is deprecated"); 433 break; 434 435 case 'a': 436 aflag = 1; 437 break; 438 439 case 'b': 440 bflag = 1; 441 break; 442 443 case 'C': 444 Cflag = 1; 445 break; 446 447 case 'd': 448 dflag = 1; 449 break; 450 451#ifdef INET6 452 case 'L': 453 Lflag = 1; 454 break; 455#endif 456 457 case 'l': 458 lflag = 1; 459 break; 460 461 case 'm': 462 mflag = 1; 463 break; 464 465 case 's': 466 sflag = 1; 467 break; 468 469 case 'u': 470 uflag = 1; 471 break; 472 473 case 'v': 474 vflag = 1; 475 break; 476 477 case 'z': 478 zflag = 1; 479 break; 480 481 482 default: 483 usage(); 484 /* NOTREACHED */ 485 } 486 } 487 argc -= optind; 488 argv += optind; 489 490 /* 491 * -l means "list all interfaces", and is mutally exclusive with 492 * all other flags/commands. 493 * 494 * -C means "list all names of cloners", and it mutually exclusive 495 * with all other flags/commands. 496 * 497 * -a means "print status of all interfaces". 498 */ 499 if ((lflag || Cflag) && (aflag || mflag || vflag || argc || zflag)) 500 usage(); 501#ifdef INET6 502 if ((lflag || Cflag) && Lflag) 503 usage(); 504#endif 505 if (lflag && Cflag) 506 usage(); 507 if (Cflag) { 508 if (argc) 509 usage(); 510 list_cloners(); 511 exit(0); 512 } 513 if (aflag || lflag) { 514 if (argc > 1) 515 usage(); 516 else if (argc == 1) { 517 afp = lookup_af(argv[0]); 518 if (afp == NULL) 519 usage(); 520 } 521 if (afp) 522 af = ifr.ifr_addr.sa_family = afp->af_af; 523 else 524 af = ifr.ifr_addr.sa_family = afs[0].af_af; 525 printall(NULL); 526 exit(0); 527 } 528 529 /* Make sure there's an interface name. */ 530 if (argc < 1) 531 usage(); 532 if (strlcpy(name, argv[0], sizeof(name)) >= sizeof(name)) 533 errx(1, "interface name '%s' too long", argv[0]); 534 argc--; argv++; 535 536 /* 537 * NOTE: We must special-case the `create' command right 538 * here as we would otherwise fail in getinfo(). 539 */ 540 if (argc > 0 && strcmp(argv[0], "create") == 0) { 541 clone_create(argv[0], 0); 542 argc--, argv++; 543 if (argc == 0) 544 exit(0); 545 } 546 547 /* Check for address family. */ 548 afp = NULL; 549 if (argc > 0) { 550 afp = lookup_af(argv[0]); 551 if (afp != NULL) { 552 argv++; 553 argc--; 554 } 555 } 556 557 /* Initialize af, just for use in getinfo(). */ 558 if (afp == NULL) 559 af = afs->af_af; 560 else 561 af = afp->af_af; 562 563 /* Get information about the interface. */ 564 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 565 if (getinfo(&ifr) < 0) 566 exit(1); 567 568 if (sflag) { 569 if (argc != 0) 570 usage(); 571 else 572 exit(carrier()); 573 } 574 575 /* No more arguments means interface status. */ 576 if (argc == 0) { 577 printall(name); 578 exit(0); 579 } 580 581 /* The following operations assume inet family as the default. */ 582 if (afp == NULL) 583 afp = afs; 584 af = ifr.ifr_addr.sa_family = afp->af_af; 585 586#ifdef INET6 587 /* initialization */ 588 in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; 589 in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; 590#endif 591 592 /* Process commands. */ 593 while (argc > 0) { 594 const struct cmd *p; 595 596 for (p = cmds; p->c_name; p++) 597 if (strcmp(argv[0], p->c_name) == 0) 598 break; 599 if (p->c_name == 0 && setaddr) { 600 if ((flags & IFF_POINTOPOINT) == 0) { 601 errx(EXIT_FAILURE, 602 "can't set destination address %s", 603 "on non-point-to-point link"); 604 } 605 p++; /* got src, do dst */ 606 } 607 if (p->c_func != NULL || p->c_func2 != NULL) { 608 if (p->c_parameter == NEXTARG) { 609 if (argc < 2) 610 errx(EXIT_FAILURE, 611 "'%s' requires argument", 612 p->c_name); 613 (*p->c_func)(argv[1], 0); 614 argc--, argv++; 615 } else if (p->c_parameter == NEXTARG2) { 616 if (argc < 3) 617 errx(EXIT_FAILURE, 618 "'%s' requires 2 arguments", 619 p->c_name); 620 (*p->c_func2)(argv[1], argv[2]); 621 argc -= 2, argv += 2; 622 } else 623 (*p->c_func)(argv[0], p->c_parameter); 624 actions |= p->c_action; 625 } 626 argc--, argv++; 627 } 628 629 /* 630 * See if multiple alias, -alias, or delete commands were 631 * specified. More than one constitutes an invalid command line 632 */ 633 634 if (conflicting > 1) 635 err(EXIT_FAILURE, 636 "Only one use of alias, -alias or delete is valid."); 637 638 /* Process any media commands that may have been issued. */ 639 process_media_commands(); 640 641 if (af == AF_INET6 && explicit_prefix == 0) { 642 /* 643 * Aggregatable address architecture defines all prefixes 644 * are 64. So, it is convenient to set prefixlen to 64 if 645 * it is not specified. 646 */ 647 setifprefixlen("64", 0); 648 /* in6_getprefix("64", MASK) if MASK is available here... */ 649 } 650 651#ifndef INET_ONLY 652 if (af == AF_ISO) 653 adjust_nsellength(); 654 655 if (af == AF_APPLETALK) 656 checkatrange((struct sockaddr_at *) &addreq.ifra_addr); 657 658 if (setipdst && af==AF_NS) { 659 struct nsip_req rq; 660 int size = sizeof(rq); 661 662 rq.rq_ns = addreq.ifra_addr; 663 rq.rq_ip = addreq.ifra_dstaddr; 664 665 if (setsockopt(s, 0, SO_NSIP_ROUTE, &rq, size) < 0) 666 warn("encapsulation routing"); 667 } 668 669#endif /* INET_ONLY */ 670 671 if (clearaddr) { 672 (void) strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name); 673 if (ioctl(s, afp->af_difaddr, afp->af_ridreq) == -1) 674 err(EXIT_FAILURE, "SIOCDIFADDR"); 675 } 676 if (newaddr > 0) { 677 (void) strncpy(afp->af_addreq, name, sizeof ifr.ifr_name); 678 if (ioctl(s, afp->af_aifaddr, afp->af_addreq) == -1) 679 warn("SIOCAIFADDR"); 680 } 681 682 if (g_ifcr_updated) { 683 (void) strncpy(g_ifcr.ifcr_name, name, 684 sizeof(g_ifcr.ifcr_name)); 685 if (ioctl(s, SIOCSIFCAP, (caddr_t) &g_ifcr) == -1) 686 err(EXIT_FAILURE, "SIOCSIFCAP"); 687 } 688 689 if (reset_if_flags) { 690 (void) strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name)); 691 ifreq.ifr_flags = flags; 692 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) == -1) 693 err(EXIT_FAILURE, "SIOCSIFFLAGS"); 694 } 695 exit(0); 696} 697 698struct afswtch * 699lookup_af(cp) 700 const char *cp; 701{ 702 struct afswtch *a; 703 704 for (a = afs; a->af_name != NULL; a++) 705 if (strcmp(a->af_name, cp) == 0) 706 return (a); 707 return (NULL); 708} 709 710void 711getsock(naf) 712 int naf; 713{ 714 static int oaf = -1; 715 716 if (oaf == naf) 717 return; 718 if (oaf != -1) 719 close(s); 720 s = socket(naf, SOCK_DGRAM, 0); 721 if (s < 0) 722 oaf = -1; 723 else 724 oaf = naf; 725} 726 727int 728getinfo(giifr) 729 struct ifreq *giifr; 730{ 731 732 getsock(af); 733 if (s < 0) 734 err(EXIT_FAILURE, "socket"); 735 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)giifr) == -1) { 736 warn("SIOCGIFFLAGS %s", giifr->ifr_name); 737 return (-1); 738 } 739 flags = giifr->ifr_flags; 740 if (ioctl(s, SIOCGIFMETRIC, (caddr_t)giifr) == -1) { 741 warn("SIOCGIFMETRIC %s", giifr->ifr_name); 742 metric = 0; 743 } else 744 metric = giifr->ifr_metric; 745 if (ioctl(s, SIOCGIFMTU, (caddr_t)giifr) == -1) 746 mtu = 0; 747 else 748 mtu = giifr->ifr_mtu; 749 750 memset(&g_ifcr, 0, sizeof(g_ifcr)); 751 strcpy(g_ifcr.ifcr_name, giifr->ifr_name); 752 (void) ioctl(s, SIOCGIFCAP, (caddr_t) &g_ifcr); 753 754 return (0); 755} 756 757void 758printall(ifname) 759 const char *ifname; 760{ 761 struct ifaddrs *ifap, *ifa; 762 struct ifreq paifr; 763 const struct sockaddr_dl *sdl = NULL; 764 int idx; 765 char *p; 766 767 if (getifaddrs(&ifap) != 0) 768 err(EXIT_FAILURE, "getifaddrs"); 769 p = NULL; 770 idx = 0; 771 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 772 memset(&paifr, 0, sizeof(paifr)); 773 strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name)); 774 if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) { 775 memcpy(&paifr.ifr_addr, ifa->ifa_addr, 776 ifa->ifa_addr->sa_len); 777 } 778 779 if (ifname && strcmp(ifname, ifa->ifa_name) != 0) 780 continue; 781 if (ifa->ifa_addr->sa_family == AF_LINK) 782 sdl = (const struct sockaddr_dl *) ifa->ifa_addr; 783 if (p && strcmp(p, ifa->ifa_name) == 0) 784 continue; 785 if (strlcpy(name, ifa->ifa_name, sizeof(name)) >= sizeof(name)) 786 continue; 787 p = ifa->ifa_name; 788 789 if (getinfo(&paifr) < 0) 790 continue; 791 if (bflag && (ifa->ifa_flags & IFF_BROADCAST) == 0) 792 continue; 793 if (dflag && (ifa->ifa_flags & IFF_UP) != 0) 794 continue; 795 if (uflag && (ifa->ifa_flags & IFF_UP) == 0) 796 continue; 797 798 if (sflag && carrier()) 799 continue; 800 idx++; 801 /* 802 * Are we just listing the interfaces? 803 */ 804 if (lflag) { 805 if (idx > 1) 806 putchar(' '); 807 fputs(name, stdout); 808 continue; 809 } 810 811 status(sdl); 812 sdl = NULL; 813 } 814 if (lflag) 815 putchar('\n'); 816 freeifaddrs(ifap); 817} 818 819void 820list_cloners(void) 821{ 822 struct if_clonereq ifcr; 823 char *cp, *buf; 824 int idx; 825 826 memset(&ifcr, 0, sizeof(ifcr)); 827 828 getsock(AF_INET); 829 830 if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 831 err(EXIT_FAILURE, "SIOCIFGCLONERS for count"); 832 833 buf = malloc(ifcr.ifcr_total * IFNAMSIZ); 834 if (buf == NULL) 835 err(EXIT_FAILURE, "unable to allocate cloner name buffer"); 836 837 ifcr.ifcr_count = ifcr.ifcr_total; 838 ifcr.ifcr_buffer = buf; 839 840 if (ioctl(s, SIOCIFGCLONERS, &ifcr) == -1) 841 err(EXIT_FAILURE, "SIOCIFGCLONERS for names"); 842 843 /* 844 * In case some disappeared in the mean time, clamp it down. 845 */ 846 if (ifcr.ifcr_count > ifcr.ifcr_total) 847 ifcr.ifcr_count = ifcr.ifcr_total; 848 849 for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { 850 if (idx > 0) 851 putchar(' '); 852 printf("%s", cp); 853 } 854 855 putchar('\n'); 856 free(buf); 857 return; 858} 859 860/*ARGSUSED*/ 861void 862clone_create(addr, param) 863 const char *addr; 864 int param; 865{ 866 867 /* We're called early... */ 868 getsock(AF_INET); 869 870 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 871 if (ioctl(s, SIOCIFCREATE, &ifr) == -1) 872 err(EXIT_FAILURE, "SIOCIFCREATE"); 873} 874 875/*ARGSUSED*/ 876void 877clone_destroy(addr, param) 878 const char *addr; 879 int param; 880{ 881 882 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 883 if (ioctl(s, SIOCIFDESTROY, &ifr) == -1) 884 err(EXIT_FAILURE, "SIOCIFDESTROY"); 885} 886 887#define RIDADDR 0 888#define ADDR 1 889#define MASK 2 890#define DSTADDR 3 891 892/*ARGSUSED*/ 893void 894setifaddr(addr, param) 895 const char *addr; 896 int param; 897{ 898 struct ifreq *siifr; /* XXX */ 899 900 /* 901 * Delay the ioctl to set the interface addr until flags are all set. 902 * The address interpretation may depend on the flags, 903 * and the flags may change when the address is set. 904 */ 905 setaddr++; 906 if (newaddr == -1) 907 newaddr = 1; 908 if (doalias == 0 && afp->af_gifaddr != 0) { 909 siifr = (struct ifreq *)afp->af_ridreq; 910 (void) strncpy(siifr->ifr_name, name, sizeof(siifr->ifr_name)); 911 siifr->ifr_addr.sa_family = afp->af_af; 912 if (ioctl(s, afp->af_gifaddr, afp->af_ridreq) == 0) 913 clearaddr = 1; 914 else if (errno == EADDRNOTAVAIL) 915 /* No address was assigned yet. */ 916 ; 917 else 918 err(EXIT_FAILURE, "SIOCGIFADDR"); 919 } 920 921 (*afp->af_getaddr)(addr, (doalias >= 0 ? ADDR : RIDADDR)); 922} 923 924void 925settunnel(src, dst) 926 const char *src, *dst; 927{ 928 struct addrinfo hints, *srcres, *dstres; 929 int ecode; 930 struct if_laddrreq req; 931 932 memset(&hints, 0, sizeof(hints)); 933 hints.ai_family = afp->af_af; 934 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 935 936 if ((ecode = getaddrinfo(src, NULL, &hints, &srcres)) != 0) 937 errx(EXIT_FAILURE, "error in parsing address string: %s", 938 gai_strerror(ecode)); 939 940 if ((ecode = getaddrinfo(dst, NULL, &hints, &dstres)) != 0) 941 errx(EXIT_FAILURE, "error in parsing address string: %s", 942 gai_strerror(ecode)); 943 944 if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family) 945 errx(EXIT_FAILURE, 946 "source and destination address families do not match"); 947 948 if (srcres->ai_addrlen > sizeof(req.addr) || 949 dstres->ai_addrlen > sizeof(req.dstaddr)) 950 errx(EXIT_FAILURE, "invalid sockaddr"); 951 952 memset(&req, 0, sizeof(req)); 953 strncpy(req.iflr_name, name, sizeof(req.iflr_name)); 954 memcpy(&req.addr, srcres->ai_addr, srcres->ai_addrlen); 955 memcpy(&req.dstaddr, dstres->ai_addr, dstres->ai_addrlen); 956 957#ifdef INET6 958 if (req.addr.ss_family == AF_INET6) { 959 struct sockaddr_in6 *s6, *d; 960 961 s6 = (struct sockaddr_in6 *)&req.addr; 962 d = (struct sockaddr_in6 *)&req.dstaddr; 963 if (s6->sin6_scope_id != d->sin6_scope_id) { 964 errx(EXIT_FAILURE, "scope mismatch"); 965 /* NOTREACHED */ 966 } 967#ifdef __KAME__ 968 /* embed scopeid */ 969 if (s6->sin6_scope_id && 970 (IN6_IS_ADDR_LINKLOCAL(&s6->sin6_addr) || 971 IN6_IS_ADDR_MC_LINKLOCAL(&s6->sin6_addr))) { 972 *(u_int16_t *)&s6->sin6_addr.s6_addr[2] = 973 htons(s6->sin6_scope_id); 974 } 975 if (d->sin6_scope_id && 976 (IN6_IS_ADDR_LINKLOCAL(&d->sin6_addr) || 977 IN6_IS_ADDR_MC_LINKLOCAL(&d->sin6_addr))) { 978 *(u_int16_t *)&d->sin6_addr.s6_addr[2] = 979 htons(d->sin6_scope_id); 980 } 981#endif 982 } 983#endif 984 985 if (ioctl(s, SIOCSLIFPHYADDR, &req) == -1) 986 warn("SIOCSLIFPHYADDR"); 987 988 freeaddrinfo(srcres); 989 freeaddrinfo(dstres); 990} 991 992/* ARGSUSED */ 993void 994deletetunnel(vname, param) 995 const char *vname; 996 int param; 997{ 998 999 if (ioctl(s, SIOCDIFPHYADDR, &ifr) == -1) 1000 err(EXIT_FAILURE, "SIOCDIFPHYADDR"); 1001} 1002 1003void setvlan(val, d) 1004 const char *val; 1005 int d; 1006{ 1007 struct vlanreq vlr; 1008 1009 if (strncmp(ifr.ifr_name, "vlan", 4) != 0 || 1010 !isdigit(ifr.ifr_name[4])) 1011 errx(EXIT_FAILURE, 1012 "``vlan'' valid only with vlan(4) interfaces"); 1013 1014 vlan_tag = atoi(val); 1015 1016 memset(&vlr, 0, sizeof(vlr)); 1017 ifr.ifr_data = (caddr_t)&vlr; 1018 1019 if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) 1020 err(EXIT_FAILURE, "SIOCGETVLAN"); 1021 1022 vlr.vlr_tag = vlan_tag; 1023 1024 if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) 1025 err(EXIT_FAILURE, "SIOCSETVLAN"); 1026} 1027 1028void setvlanif(val, d) 1029 const char *val; 1030 int d; 1031{ 1032 struct vlanreq vlr; 1033 1034 if (strncmp(ifr.ifr_name, "vlan", 4) != 0 || 1035 !isdigit(ifr.ifr_name[4])) 1036 errx(EXIT_FAILURE, 1037 "``vlanif'' valid only with vlan(4) interfaces"); 1038 1039 if (vlan_tag == (u_int)-1) 1040 errx(EXIT_FAILURE, 1041 "must specify both ``vlan'' and ``vlanif''"); 1042 1043 memset(&vlr, 0, sizeof(vlr)); 1044 ifr.ifr_data = (caddr_t)&vlr; 1045 1046 if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) 1047 err(EXIT_FAILURE, "SIOCGETVLAN"); 1048 1049 strlcpy(vlr.vlr_parent, val, sizeof(vlr.vlr_parent)); 1050 vlr.vlr_tag = vlan_tag; 1051 1052 if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) 1053 err(EXIT_FAILURE, "SIOCSETVLAN"); 1054} 1055 1056void unsetvlanif(val, d) 1057 const char *val; 1058 int d; 1059{ 1060 struct vlanreq vlr; 1061 1062 if (strncmp(ifr.ifr_name, "vlan", 4) != 0 || 1063 !isdigit(ifr.ifr_name[4])) 1064 errx(EXIT_FAILURE, 1065 "``vlanif'' valid only with vlan(4) interfaces"); 1066 1067 memset(&vlr, 0, sizeof(vlr)); 1068 ifr.ifr_data = (caddr_t)&vlr; 1069 1070 if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) 1071 err(EXIT_FAILURE, "SIOCGETVLAN"); 1072 1073 vlr.vlr_parent[0] = '\0'; 1074 vlr.vlr_tag = 0; 1075 1076 if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1) 1077 err(EXIT_FAILURE, "SIOCSETVLAN"); 1078} 1079 1080void 1081setifnetmask(addr, d) 1082 const char *addr; 1083 int d; 1084{ 1085 (*afp->af_getaddr)(addr, MASK); 1086} 1087 1088void 1089setifbroadaddr(addr, d) 1090 const char *addr; 1091 int d; 1092{ 1093 (*afp->af_getaddr)(addr, DSTADDR); 1094} 1095 1096void 1097setifipdst(addr, d) 1098 const char *addr; 1099 int d; 1100{ 1101 in_getaddr(addr, DSTADDR); 1102 setipdst++; 1103 clearaddr = 0; 1104 newaddr = 0; 1105} 1106 1107#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) 1108/*ARGSUSED*/ 1109void 1110notealias(addr, param) 1111 const char *addr; 1112 int param; 1113{ 1114 if (setaddr && doalias == 0 && param < 0) 1115 (void) memcpy(rqtosa(af_ridreq), rqtosa(af_addreq), 1116 rqtosa(af_addreq)->sa_len); 1117 doalias = param; 1118 if (param < 0) { 1119 clearaddr = 1; 1120 newaddr = 0; 1121 conflicting++; 1122 } else { 1123 clearaddr = 0; 1124 conflicting++; 1125 } 1126} 1127 1128/*ARGSUSED*/ 1129void 1130notrailers(vname, value) 1131 const char *vname; 1132 int value; 1133{ 1134 puts("Note: trailers are no longer sent, but always received"); 1135} 1136 1137/*ARGSUSED*/ 1138void 1139setifdstaddr(addr, param) 1140 const char *addr; 1141 int param; 1142{ 1143 (*afp->af_getaddr)(addr, DSTADDR); 1144} 1145 1146void 1147setifflags(vname, value) 1148 const char *vname; 1149 int value; 1150{ 1151 struct ifreq ifreq; 1152 1153 (void) strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name)); 1154 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifreq) == -1) 1155 err(EXIT_FAILURE, "SIOCGIFFLAGS"); 1156 flags = ifreq.ifr_flags; 1157 1158 if (value < 0) { 1159 value = -value; 1160 flags &= ~value; 1161 } else 1162 flags |= value; 1163 ifreq.ifr_flags = flags; 1164 if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifreq) == -1) 1165 err(EXIT_FAILURE, "SIOCSIFFLAGS"); 1166 1167 reset_if_flags = 1; 1168} 1169 1170void 1171setifcaps(vname, value) 1172 const char *vname; 1173 int value; 1174{ 1175 1176 if (value < 0) { 1177 value = -value; 1178 g_ifcr.ifcr_capenable &= ~value; 1179 } else 1180 g_ifcr.ifcr_capenable |= value; 1181 1182 g_ifcr_updated = 1; 1183} 1184 1185#ifdef INET6 1186void 1187setia6flags(vname, value) 1188 const char *vname; 1189 int value; 1190{ 1191 1192 if (value < 0) { 1193 value = -value; 1194 in6_addreq.ifra_flags &= ~value; 1195 } else 1196 in6_addreq.ifra_flags |= value; 1197} 1198 1199void 1200setia6pltime(val, d) 1201 const char *val; 1202 int d; 1203{ 1204 1205 setia6lifetime("pltime", val); 1206} 1207 1208void 1209setia6vltime(val, d) 1210 const char *val; 1211 int d; 1212{ 1213 1214 setia6lifetime("vltime", val); 1215} 1216 1217void 1218setia6lifetime(cmd, val) 1219 const char *cmd; 1220 const char *val; 1221{ 1222 time_t newval, t; 1223 char *ep; 1224 1225 t = time(NULL); 1226 newval = (time_t)strtoul(val, &ep, 0); 1227 if (val == ep) 1228 errx(EXIT_FAILURE, "invalid %s", cmd); 1229 if (afp->af_af != AF_INET6) 1230 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd); 1231 if (strcmp(cmd, "vltime") == 0) { 1232 in6_addreq.ifra_lifetime.ia6t_expire = t + newval; 1233 in6_addreq.ifra_lifetime.ia6t_vltime = newval; 1234 } else if (strcmp(cmd, "pltime") == 0) { 1235 in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; 1236 in6_addreq.ifra_lifetime.ia6t_pltime = newval; 1237 } 1238} 1239 1240void 1241setia6eui64(cmd, val) 1242 const char *cmd; 1243 int val; 1244{ 1245 struct ifaddrs *ifap, *ifa; 1246 const struct sockaddr_in6 *sin6 = NULL; 1247 const struct in6_addr *lladdr = NULL; 1248 struct in6_addr *in6; 1249 1250 if (afp->af_af != AF_INET6) 1251 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd); 1252 in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr; 1253 if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0) 1254 errx(EXIT_FAILURE, "interface index is already filled"); 1255 if (getifaddrs(&ifap) != 0) 1256 err(EXIT_FAILURE, "getifaddrs"); 1257 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 1258 if (ifa->ifa_addr->sa_family == AF_INET6 && 1259 strcmp(ifa->ifa_name, name) == 0) { 1260 sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr; 1261 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 1262 lladdr = &sin6->sin6_addr; 1263 break; 1264 } 1265 } 1266 } 1267 if (!lladdr) 1268 errx(EXIT_FAILURE, "could not determine link local address"); 1269 1270 memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8); 1271 1272 freeifaddrs(ifap); 1273} 1274#endif 1275 1276void 1277setifmetric(val, d) 1278 const char *val; 1279 int d; 1280{ 1281 char *ep = NULL; 1282 1283 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 1284 ifr.ifr_metric = strtoul(val, &ep, 10); 1285 if (!ep || *ep) 1286 errx(EXIT_FAILURE, "%s: invalid metric", val); 1287 if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) == -1) 1288 warn("SIOCSIFMETRIC"); 1289} 1290 1291void 1292setifmtu(val, d) 1293 const char *val; 1294 int d; 1295{ 1296 char *ep = NULL; 1297 1298 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1299 ifr.ifr_mtu = strtoul(val, &ep, 10); 1300 if (!ep || *ep) 1301 errx(EXIT_FAILURE, "%s: invalid mtu", val); 1302 if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) == -1) 1303 warn("SIOCSIFMTU"); 1304} 1305 1306const char * 1307get_string(val, sep, buf, lenp) 1308 const char *val, *sep; 1309 u_int8_t *buf; 1310 int *lenp; 1311{ 1312 int len; 1313 int hexstr; 1314 u_int8_t *p; 1315 1316 len = *lenp; 1317 p = buf; 1318 hexstr = (val[0] == '0' && tolower((u_char)val[1]) == 'x'); 1319 if (hexstr) 1320 val += 2; 1321 for (;;) { 1322 if (*val == '\0') 1323 break; 1324 if (sep != NULL && strchr(sep, *val) != NULL) { 1325 val++; 1326 break; 1327 } 1328 if (hexstr) { 1329 if (!isxdigit((u_char)val[0]) || 1330 !isxdigit((u_char)val[1])) { 1331 warnx("bad hexadecimal digits"); 1332 return NULL; 1333 } 1334 } 1335 if (p > buf + len) { 1336 if (hexstr) 1337 warnx("hexadecimal digits too long"); 1338 else 1339 warnx("strings too long"); 1340 return NULL; 1341 } 1342 if (hexstr) { 1343#define tohex(x) (isdigit(x) ? (x) - '0' : tolower(x) - 'a' + 10) 1344 *p++ = (tohex((u_char)val[0]) << 4) | 1345 tohex((u_char)val[1]); 1346#undef tohex 1347 val += 2; 1348 } else 1349 *p++ = *val++; 1350 } 1351 len = p - buf; 1352 if (len < *lenp) 1353 memset(p, 0, *lenp - len); 1354 *lenp = len; 1355 return val; 1356} 1357 1358void 1359print_string(buf, len) 1360 const u_int8_t *buf; 1361 int len; 1362{ 1363 int i; 1364 int hasspc; 1365 1366 i = 0; 1367 hasspc = 0; 1368 if (len < 2 || buf[0] != '0' || tolower(buf[1]) != 'x') { 1369 for (; i < len; i++) { 1370 if (!isprint(buf[i])) 1371 break; 1372 if (isspace(buf[i])) 1373 hasspc++; 1374 } 1375 } 1376 if (i == len) { 1377 if (hasspc || len == 0) 1378 printf("\"%.*s\"", len, buf); 1379 else 1380 printf("%.*s", len, buf); 1381 } else { 1382 printf("0x"); 1383 for (i = 0; i < len; i++) 1384 printf("%02x", buf[i]); 1385 } 1386} 1387 1388void 1389setifnwid(val, d) 1390 const char *val; 1391 int d; 1392{ 1393 struct ieee80211_nwid nwid; 1394 int len; 1395 1396 len = sizeof(nwid.i_nwid); 1397 if (get_string(val, NULL, nwid.i_nwid, &len) == NULL) 1398 return; 1399 nwid.i_len = len; 1400 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1401 ifr.ifr_data = (caddr_t)&nwid; 1402 if (ioctl(s, SIOCS80211NWID, (caddr_t)&ifr) == -1) 1403 warn("SIOCS80211NWID"); 1404} 1405 1406void 1407setifbssid(val, d) 1408 const char *val; 1409 int d; 1410{ 1411 struct ieee80211_bssid bssid; 1412 struct ether_addr *ea; 1413 1414 if (d != 0) { 1415 /* no BSSID is especially desired */ 1416 memset(&bssid.i_bssid, 0, sizeof(bssid.i_bssid)); 1417 } else { 1418 ea = ether_aton(val); 1419 if (ea == NULL) { 1420 warnx("malformed BSSID: %s", val); 1421 return; 1422 } 1423 memcpy(&bssid.i_bssid, ea->ether_addr_octet, 1424 sizeof(bssid.i_bssid)); 1425 } 1426 (void)strncpy(bssid.i_name, name, sizeof(bssid.i_name)); 1427 if (ioctl(s, SIOCS80211BSSID, (caddr_t)&bssid) == -1) 1428 warn("SIOCS80211BSSID"); 1429} 1430 1431void 1432setifchan(val, d) 1433 const char *val; 1434 int d; 1435{ 1436 struct ieee80211chanreq channel; 1437 int chan; 1438 1439 if (d != 0) 1440 chan = IEEE80211_CHAN_ANY; 1441 else { 1442 chan = atoi(val); 1443 if (chan < 0 || chan > 0xffff) { 1444 warnx("invalid channel: %s", val); 1445 return; 1446 } 1447 } 1448 1449 (void)strncpy(channel.i_name, name, sizeof(channel.i_name)); 1450 channel.i_channel = (u_int16_t) chan; 1451 if (ioctl(s, SIOCS80211CHANNEL, (caddr_t)&channel) == -1) 1452 warn("SIOCS80211CHANNEL"); 1453} 1454 1455void 1456setifnwkey(val, d) 1457 const char *val; 1458 int d; 1459{ 1460 struct ieee80211_nwkey nwkey; 1461 int i; 1462 u_int8_t keybuf[IEEE80211_WEP_NKID][16]; 1463 1464 nwkey.i_wepon = IEEE80211_NWKEY_WEP; 1465 nwkey.i_defkid = 1; 1466 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 1467 nwkey.i_key[i].i_keylen = sizeof(keybuf[i]); 1468 nwkey.i_key[i].i_keydat = keybuf[i]; 1469 } 1470 if (d != 0) { 1471 /* disable WEP encryption */ 1472 nwkey.i_wepon = 0; 1473 i = 0; 1474 } else if (strcasecmp("persist", val) == 0) { 1475 /* use all values from persistent memory */ 1476 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST; 1477 nwkey.i_defkid = 0; 1478 for (i = 0; i < IEEE80211_WEP_NKID; i++) 1479 nwkey.i_key[i].i_keylen = -1; 1480 } else if (strncasecmp("persist:", val, 8) == 0) { 1481 val += 8; 1482 /* program keys in persistent memory */ 1483 nwkey.i_wepon |= IEEE80211_NWKEY_PERSIST; 1484 goto set_nwkey; 1485 } else { 1486 set_nwkey: 1487 if (isdigit(val[0]) && val[1] == ':') { 1488 /* specifying a full set of four keys */ 1489 nwkey.i_defkid = val[0] - '0'; 1490 val += 2; 1491 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 1492 val = get_string(val, ",", keybuf[i], 1493 &nwkey.i_key[i].i_keylen); 1494 if (val == NULL) 1495 return; 1496 } 1497 if (*val != '\0') { 1498 warnx("SIOCS80211NWKEY: too many keys."); 1499 return; 1500 } 1501 } else { 1502 val = get_string(val, NULL, keybuf[0], 1503 &nwkey.i_key[0].i_keylen); 1504 if (val == NULL) 1505 return; 1506 i = 1; 1507 } 1508 } 1509 for (; i < IEEE80211_WEP_NKID; i++) 1510 nwkey.i_key[i].i_keylen = 0; 1511 (void)strncpy(nwkey.i_name, name, sizeof(nwkey.i_name)); 1512 if (ioctl(s, SIOCS80211NWKEY, (caddr_t)&nwkey) == -1) 1513 warn("SIOCS80211NWKEY"); 1514} 1515 1516void 1517setifpowersave(val, d) 1518 const char *val; 1519 int d; 1520{ 1521 struct ieee80211_power power; 1522 1523 (void)strncpy(power.i_name, name, sizeof(power.i_name)); 1524 if (ioctl(s, SIOCG80211POWER, (caddr_t)&power) == -1) { 1525 warn("SIOCG80211POWER"); 1526 return; 1527 } 1528 1529 power.i_enabled = d; 1530 if (ioctl(s, SIOCS80211POWER, (caddr_t)&power) == -1) 1531 warn("SIOCS80211POWER"); 1532} 1533 1534void 1535setifpowersavesleep(val, d) 1536 const char *val; 1537 int d; 1538{ 1539 struct ieee80211_power power; 1540 1541 (void)strncpy(power.i_name, name, sizeof(power.i_name)); 1542 if (ioctl(s, SIOCG80211POWER, (caddr_t)&power) == -1) { 1543 warn("SIOCG80211POWER"); 1544 return; 1545 } 1546 1547 power.i_maxsleep = atoi(val); 1548 if (ioctl(s, SIOCS80211POWER, (caddr_t)&power) == -1) 1549 warn("SIOCS80211POWER"); 1550} 1551 1552void 1553ieee80211_status() 1554{ 1555 int i, nwkey_verbose; 1556 struct ieee80211_nwid nwid; 1557 struct ieee80211_nwkey nwkey; 1558 struct ieee80211_power power; 1559 u_int8_t keybuf[IEEE80211_WEP_NKID][16]; 1560 struct ieee80211_bssid bssid; 1561 struct ieee80211chanreq channel; 1562 struct ether_addr ea; 1563 static const u_int8_t zero_macaddr[IEEE80211_ADDR_LEN]; 1564 1565 memset(&ifr, 0, sizeof(ifr)); 1566 ifr.ifr_data = (caddr_t)&nwid; 1567 (void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1568 if (ioctl(s, SIOCG80211NWID, (caddr_t)&ifr) == -1) 1569 return; 1570 if (nwid.i_len > IEEE80211_NWID_LEN) { 1571 warnx("SIOCG80211NWID: wrong length of nwid (%d)", nwid.i_len); 1572 return; 1573 } 1574 printf("\tssid "); 1575 print_string(nwid.i_nwid, nwid.i_len); 1576 memset(&nwkey, 0, sizeof(nwkey)); 1577 (void)strncpy(nwkey.i_name, name, sizeof(nwkey.i_name)); 1578 /* show nwkey only when WEP is enabled */ 1579 if (ioctl(s, SIOCG80211NWKEY, (caddr_t)&nwkey) == -1 || 1580 nwkey.i_wepon == 0) { 1581 printf("\n"); 1582 goto skip_wep; 1583 } 1584 1585 printf(" nwkey "); 1586 /* try to retrieve WEP keys */ 1587 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 1588 nwkey.i_key[i].i_keydat = keybuf[i]; 1589 nwkey.i_key[i].i_keylen = sizeof(keybuf[i]); 1590 } 1591 if (ioctl(s, SIOCG80211NWKEY, (caddr_t)&nwkey) == -1) { 1592 printf("*****"); 1593 } else { 1594 nwkey_verbose = 0; 1595 /* check to see non default key or multiple keys defined */ 1596 if (nwkey.i_defkid != 1) { 1597 nwkey_verbose = 1; 1598 } else { 1599 for (i = 1; i < IEEE80211_WEP_NKID; i++) { 1600 if (nwkey.i_key[i].i_keylen != 0) { 1601 nwkey_verbose = 1; 1602 break; 1603 } 1604 } 1605 } 1606 /* check extra ambiguity with keywords */ 1607 if (!nwkey_verbose) { 1608 if (nwkey.i_key[0].i_keylen >= 2 && 1609 isdigit(nwkey.i_key[0].i_keydat[0]) && 1610 nwkey.i_key[0].i_keydat[1] == ':') 1611 nwkey_verbose = 1; 1612 else if (nwkey.i_key[0].i_keylen >= 7 && 1613 strncasecmp("persist", nwkey.i_key[0].i_keydat, 7) 1614 == 0) 1615 nwkey_verbose = 1; 1616 } 1617 if (nwkey_verbose) 1618 printf("%d:", nwkey.i_defkid); 1619 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 1620 if (i > 0) 1621 printf(","); 1622 if (nwkey.i_key[i].i_keylen < 0) 1623 printf("persist"); 1624 else 1625 print_string(nwkey.i_key[i].i_keydat, 1626 nwkey.i_key[i].i_keylen); 1627 if (!nwkey_verbose) 1628 break; 1629 } 1630 } 1631 printf("\n"); 1632 1633 skip_wep: 1634 (void)strncpy(power.i_name, name, sizeof(power.i_name)); 1635 if (ioctl(s, SIOCG80211POWER, &power) == -1) 1636 goto skip_power; 1637 printf("\tpowersave "); 1638 if (power.i_enabled) 1639 printf("on (%dms sleep)", power.i_maxsleep); 1640 else 1641 printf("off"); 1642 printf("\n"); 1643 1644 skip_power: 1645 (void)strncpy(bssid.i_name, name, sizeof(bssid.i_name)); 1646 if (ioctl(s, SIOCG80211BSSID, &bssid) == -1) 1647 return; 1648 (void)strncpy(channel.i_name, name, sizeof(channel.i_name)); 1649 if (ioctl(s, SIOCG80211CHANNEL, &channel) == -1) 1650 return; 1651 if (memcmp(bssid.i_bssid, zero_macaddr, IEEE80211_ADDR_LEN) == 0) { 1652 if (channel.i_channel != (u_int16_t)-1) 1653 printf("\tchan %d\n", channel.i_channel); 1654 } else { 1655 memcpy(ea.ether_addr_octet, bssid.i_bssid, 1656 sizeof(ea.ether_addr_octet)); 1657 printf("\tbssid %s", ether_ntoa(&ea)); 1658 if (channel.i_channel != IEEE80211_CHAN_ANY) 1659 printf(" chan %d", channel.i_channel); 1660 printf("\n"); 1661 } 1662} 1663 1664void 1665init_current_media() 1666{ 1667 struct ifmediareq ifmr; 1668 1669 /* 1670 * If we have not yet done so, grab the currently-selected 1671 * media. 1672 */ 1673 if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) { 1674 (void) memset(&ifmr, 0, sizeof(ifmr)); 1675 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 1676 1677 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { 1678 /* 1679 * If we get E2BIG, the kernel is telling us 1680 * that there are more, so we can ignore it. 1681 */ 1682 if (errno != E2BIG) 1683 err(EXIT_FAILURE, "SGIOCGIFMEDIA"); 1684 } 1685 1686 media_current = ifmr.ifm_current; 1687 } 1688 1689 /* Sanity. */ 1690 if (IFM_TYPE(media_current) == 0) 1691 errx(EXIT_FAILURE, "%s: no link type?", name); 1692} 1693 1694void 1695process_media_commands() 1696{ 1697 1698 if ((actions & (A_MEDIA|A_MEDIAOPT|A_MEDIAMODE)) == 0) { 1699 /* Nothing to do. */ 1700 return; 1701 } 1702 1703 /* 1704 * Media already set up, and commands sanity-checked. Set/clear 1705 * any options, and we're ready to go. 1706 */ 1707 media_current |= mediaopt_set; 1708 media_current &= ~mediaopt_clear; 1709 1710 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1711 ifr.ifr_media = media_current; 1712 1713 if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) == -1) 1714 err(EXIT_FAILURE, "SIOCSIFMEDIA"); 1715} 1716 1717void 1718setmedia(val, d) 1719 const char *val; 1720 int d; 1721{ 1722 int type, subtype, inst; 1723 1724 init_current_media(); 1725 1726 /* Only one media command may be given. */ 1727 if (actions & A_MEDIA) 1728 errx(EXIT_FAILURE, "only one `media' command may be issued"); 1729 1730 /* Must not come after mode commands */ 1731 if (actions & A_MEDIAMODE) 1732 errx(EXIT_FAILURE, 1733 "may not issue `media' after `mode' commands"); 1734 1735 /* Must not come after mediaopt commands */ 1736 if (actions & A_MEDIAOPT) 1737 errx(EXIT_FAILURE, 1738 "may not issue `media' after `mediaopt' commands"); 1739 1740 /* 1741 * No need to check if `instance' has been issued; setmediainst() 1742 * craps out if `media' has not been specified. 1743 */ 1744 1745 type = IFM_TYPE(media_current); 1746 inst = IFM_INST(media_current); 1747 1748 /* Look up the subtype. */ 1749 subtype = get_media_subtype(type, val); 1750 1751 /* Build the new current media word. */ 1752 media_current = IFM_MAKEWORD(type, subtype, 0, inst); 1753 1754 /* Media will be set after other processing is complete. */ 1755} 1756 1757void 1758setmediaopt(val, d) 1759 const char *val; 1760 int d; 1761{ 1762 1763 init_current_media(); 1764 1765 /* Can only issue `mediaopt' once. */ 1766 if (actions & A_MEDIAOPTSET) 1767 errx(EXIT_FAILURE, "only one `mediaopt' command may be issued"); 1768 1769 /* Can't issue `mediaopt' if `instance' has already been issued. */ 1770 if (actions & A_MEDIAINST) 1771 errx(EXIT_FAILURE, "may not issue `mediaopt' after `instance'"); 1772 1773 mediaopt_set = get_media_options(IFM_TYPE(media_current), val); 1774 1775 /* Media will be set after other processing is complete. */ 1776} 1777 1778void 1779unsetmediaopt(val, d) 1780 const char *val; 1781 int d; 1782{ 1783 1784 init_current_media(); 1785 1786 /* Can only issue `-mediaopt' once. */ 1787 if (actions & A_MEDIAOPTCLR) 1788 errx(EXIT_FAILURE, 1789 "only one `-mediaopt' command may be issued"); 1790 1791 /* May not issue `media' and `-mediaopt'. */ 1792 if (actions & A_MEDIA) 1793 errx(EXIT_FAILURE, 1794 "may not issue both `media' and `-mediaopt'"); 1795 1796 /* 1797 * No need to check for A_MEDIAINST, since the test for A_MEDIA 1798 * implicitly checks for A_MEDIAINST. 1799 */ 1800 1801 mediaopt_clear = get_media_options(IFM_TYPE(media_current), val); 1802 1803 /* Media will be set after other processing is complete. */ 1804} 1805 1806void 1807setmediainst(val, d) 1808 const char *val; 1809 int d; 1810{ 1811 int type, subtype, options, inst; 1812 1813 init_current_media(); 1814 1815 /* Can only issue `instance' once. */ 1816 if (actions & A_MEDIAINST) 1817 errx(EXIT_FAILURE, "only one `instance' command may be issued"); 1818 1819 /* Must have already specified `media' */ 1820 if ((actions & A_MEDIA) == 0) 1821 errx(EXIT_FAILURE, "must specify `media' before `instance'"); 1822 1823 type = IFM_TYPE(media_current); 1824 subtype = IFM_SUBTYPE(media_current); 1825 options = IFM_OPTIONS(media_current); 1826 1827 inst = atoi(val); 1828 if (inst < 0 || inst > IFM_INST_MAX) 1829 errx(EXIT_FAILURE, "invalid media instance: %s", val); 1830 1831 media_current = IFM_MAKEWORD(type, subtype, options, inst); 1832 1833 /* Media will be set after other processing is complete. */ 1834} 1835 1836void 1837setmediamode(val, d) 1838 const char *val; 1839 int d; 1840{ 1841 int type, subtype, options, inst, mode; 1842 1843 init_current_media(); 1844 1845 /* Can only issue `mode' once. */ 1846 if (actions & A_MEDIAMODE) 1847 errx(EXIT_FAILURE, "only one `mode' command may be issued"); 1848 1849 type = IFM_TYPE(media_current); 1850 subtype = IFM_SUBTYPE(media_current); 1851 options = IFM_OPTIONS(media_current); 1852 inst = IFM_INST(media_current); 1853 1854 if ((mode = get_media_mode(type, val)) == -1) 1855 errx(EXIT_FAILURE, "invalid media mode: %s", val); 1856 1857 media_current = IFM_MAKEWORD(type, subtype, options, inst) | mode; 1858 1859 /* Media will be set after other processing is complete. */ 1860} 1861 1862struct ifmedia_description ifm_mode_descriptions[] = 1863 IFM_MODE_DESCRIPTIONS; 1864 1865struct ifmedia_description ifm_type_descriptions[] = 1866 IFM_TYPE_DESCRIPTIONS; 1867 1868struct ifmedia_description ifm_subtype_descriptions[] = 1869 IFM_SUBTYPE_DESCRIPTIONS; 1870 1871struct ifmedia_description ifm_option_descriptions[] = 1872 IFM_OPTION_DESCRIPTIONS; 1873 1874const char * 1875get_media_type_string(mword) 1876 int mword; 1877{ 1878 struct ifmedia_description *desc; 1879 1880 for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; 1881 desc++) { 1882 if (IFM_TYPE(mword) == desc->ifmt_word) 1883 return (desc->ifmt_string); 1884 } 1885 return ("<unknown type>"); 1886} 1887 1888const char * 1889get_media_subtype_string(mword) 1890 int mword; 1891{ 1892 struct ifmedia_description *desc; 1893 1894 for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL; 1895 desc++) { 1896 if (IFM_TYPE_MATCH(desc->ifmt_word, mword) && 1897 IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword)) 1898 return (desc->ifmt_string); 1899 } 1900 return ("<unknown subtype>"); 1901} 1902 1903int 1904get_media_mode(type, val) 1905 int type; 1906 const char *val; 1907{ 1908 int rval; 1909 1910 rval = lookup_media_word(ifm_mode_descriptions, type, val); 1911 if (rval == -1) 1912 errx(EXIT_FAILURE, "unknown %s media mode: %s", 1913 get_media_type_string(type), val); 1914 1915 return (rval); 1916} 1917 1918int 1919get_media_subtype(type, val) 1920 int type; 1921 const char *val; 1922{ 1923 int rval; 1924 1925 rval = lookup_media_word(ifm_subtype_descriptions, type, val); 1926 if (rval == -1) 1927 errx(EXIT_FAILURE, "unknown %s media subtype: %s", 1928 get_media_type_string(type), val); 1929 1930 return (rval); 1931} 1932 1933int 1934get_media_options(type, val) 1935 int type; 1936 const char *val; 1937{ 1938 char *optlist, *str; 1939 int option, rval = 0; 1940 1941 /* We muck with the string, so copy it. */ 1942 optlist = strdup(val); 1943 if (optlist == NULL) 1944 err(EXIT_FAILURE, "strdup"); 1945 str = optlist; 1946 1947 /* 1948 * Look up the options in the user-provided comma-separated list. 1949 */ 1950 for (; (str = strtok(str, ",")) != NULL; str = NULL) { 1951 option = lookup_media_word(ifm_option_descriptions, type, str); 1952 if (option == -1) 1953 errx(EXIT_FAILURE, "unknown %s media option: %s", 1954 get_media_type_string(type), str); 1955 rval |= IFM_OPTIONS(option); 1956 } 1957 1958 free(optlist); 1959 return (rval); 1960} 1961 1962int 1963lookup_media_word(desc, type, val) 1964 struct ifmedia_description *desc; 1965 int type; 1966 const char *val; 1967{ 1968 1969 for (; desc->ifmt_string != NULL; desc++) { 1970 if (IFM_TYPE_MATCH(desc->ifmt_word, type) && 1971 strcasecmp(desc->ifmt_string, val) == 0) 1972 return (desc->ifmt_word); 1973 } 1974 return (-1); 1975} 1976 1977void 1978print_media_word(ifmw, print_type, as_syntax) 1979 int ifmw, print_type, as_syntax; 1980{ 1981 struct ifmedia_description *desc; 1982 int seen_option = 0; 1983 1984 if (print_type) 1985 printf("%s ", get_media_type_string(ifmw)); 1986 printf("%s%s", as_syntax ? "media " : "", 1987 get_media_subtype_string(ifmw)); 1988 1989 /* Find mode. */ 1990 if (IFM_MODE(ifmw) != 0) { 1991 for (desc = ifm_mode_descriptions; desc->ifmt_string != NULL; 1992 desc++) { 1993 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) && 1994 IFM_MODE(ifmw) == IFM_MODE(desc->ifmt_word)) { 1995 printf(" mode %s", desc->ifmt_string); 1996 break; 1997 } 1998 } 1999 } 2000 2001 /* Find options. */ 2002 for (desc = ifm_option_descriptions; desc->ifmt_string != NULL; 2003 desc++) { 2004 if (IFM_TYPE_MATCH(desc->ifmt_word, ifmw) && 2005 (ifmw & IFM_OPTIONS(desc->ifmt_word)) != 0 && 2006 (seen_option & IFM_OPTIONS(desc->ifmt_word)) == 0) { 2007 if (seen_option == 0) 2008 printf(" %s", as_syntax ? "mediaopt " : ""); 2009 printf("%s%s", seen_option ? "," : "", 2010 desc->ifmt_string); 2011 seen_option |= IFM_OPTIONS(desc->ifmt_word); 2012 } 2013 } 2014 if (IFM_INST(ifmw) != 0) 2015 printf(" instance %d", IFM_INST(ifmw)); 2016} 2017 2018int carrier() 2019{ 2020 struct ifmediareq ifmr; 2021 2022 (void) memset(&ifmr, 0, sizeof(ifmr)); 2023 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 2024 2025 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { 2026 /* 2027 * Interface doesn't support SIOC{G,S}IFMEDIA; 2028 * assume ok. 2029 */ 2030 return 0; 2031 } 2032 if ((ifmr.ifm_status & IFM_AVALID) == 0) { 2033 /* 2034 * Interface doesn't report media-valid status. 2035 * assume ok. 2036 */ 2037 return 0; 2038 } 2039 /* otherwise, return ok for active, not-ok if not active. */ 2040 return !(ifmr.ifm_status & IFM_ACTIVE); 2041} 2042 2043 2044#define IFFBITS \ 2045"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\ 2046\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST" 2047 2048#define IFCAPBITS \ 2049"\020\1IP4CSUM\2TCP4CSUM\3UDP4CSUM\4TCP6CSUM\5UDP6CSUM\6TCP4CSUM_Rx\7UDP4CSUM_Rx" 2050 2051const int ifm_status_valid_list[] = IFM_STATUS_VALID_LIST; 2052 2053const struct ifmedia_status_description ifm_status_descriptions[] = 2054 IFM_STATUS_DESCRIPTIONS; 2055 2056/* 2057 * Print the status of the interface. If an address family was 2058 * specified, show it and it only; otherwise, show them all. 2059 */ 2060void 2061status(sdl) 2062 const struct sockaddr_dl *sdl; 2063{ 2064 struct afswtch *p = afp; 2065 struct ifmediareq ifmr; 2066 struct ifdatareq ifdr; 2067 int *media_list, i; 2068 char hbuf[NI_MAXHOST]; 2069 char fbuf[BUFSIZ]; 2070 2071 (void)snprintb(fbuf, sizeof(fbuf), IFFBITS, flags); 2072 printf("%s: flags=%s", name, &fbuf[2]); 2073 if (metric) 2074 printf(" metric %lu", metric); 2075 if (mtu) 2076 printf(" mtu %lu", mtu); 2077 putchar('\n'); 2078 2079 if (g_ifcr.ifcr_capabilities) { 2080 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS, 2081 g_ifcr.ifcr_capabilities); 2082 printf("\tcapabilities=%s\n", &fbuf[2]); 2083 (void)snprintb(fbuf, sizeof(fbuf), IFCAPBITS, 2084 g_ifcr.ifcr_capenable); 2085 printf("\tenabled=%s\n", &fbuf[2]); 2086 } 2087 2088 ieee80211_status(); 2089 vlan_status(); 2090 tunnel_status(); 2091 2092 if (sdl != NULL && 2093 getnameinfo((struct sockaddr *)sdl, sdl->sdl_len, 2094 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0 && 2095 hbuf[0] != '\0') 2096 printf("\taddress: %s\n", hbuf); 2097 2098 (void) memset(&ifmr, 0, sizeof(ifmr)); 2099 (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); 2100 2101 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) { 2102 /* 2103 * Interface doesn't support SIOC{G,S}IFMEDIA. 2104 */ 2105 goto iface_stats; 2106 } 2107 2108 if (ifmr.ifm_count == 0) { 2109 warnx("%s: no media types?", name); 2110 goto iface_stats; 2111 } 2112 2113 media_list = (int *)malloc(ifmr.ifm_count * sizeof(int)); 2114 if (media_list == NULL) 2115 err(EXIT_FAILURE, "malloc"); 2116 ifmr.ifm_ulist = media_list; 2117 2118 if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) == -1) 2119 err(EXIT_FAILURE, "SIOCGIFMEDIA"); 2120 2121 printf("\tmedia: "); 2122 print_media_word(ifmr.ifm_current, 1, 0); 2123 if (ifmr.ifm_active != ifmr.ifm_current) { 2124 putchar(' '); 2125 putchar('('); 2126 print_media_word(ifmr.ifm_active, 0, 0); 2127 putchar(')'); 2128 } 2129 putchar('\n'); 2130 2131 if (ifmr.ifm_status & IFM_STATUS_VALID) { 2132 const struct ifmedia_status_description *ifms; 2133 int bitno, found = 0; 2134 2135 printf("\tstatus: "); 2136 for (bitno = 0; ifm_status_valid_list[bitno] != 0; bitno++) { 2137 for (ifms = ifm_status_descriptions; 2138 ifms->ifms_valid != 0; ifms++) { 2139 if (ifms->ifms_type != 2140 IFM_TYPE(ifmr.ifm_current) || 2141 ifms->ifms_valid != 2142 ifm_status_valid_list[bitno]) 2143 continue; 2144 printf("%s%s", found ? ", " : "", 2145 IFM_STATUS_DESC(ifms, ifmr.ifm_status)); 2146 found = 1; 2147 2148 /* 2149 * For each valid indicator bit, there's 2150 * only one entry for each media type, so 2151 * terminate the inner loop now. 2152 */ 2153 break; 2154 } 2155 } 2156 2157 if (found == 0) 2158 printf("unknown"); 2159 putchar('\n'); 2160 } 2161 2162 if (mflag) { 2163 int type, printed_type; 2164 2165 for (type = IFM_NMIN; type <= IFM_NMAX; type += IFM_NMIN) { 2166 for (i = 0, printed_type = 0; i < ifmr.ifm_count; i++) { 2167 if (IFM_TYPE(media_list[i]) == type) { 2168 if (printed_type == 0) { 2169 printf("\tsupported %s media:\n", 2170 get_media_type_string(type)); 2171 printed_type = 1; 2172 } 2173 printf("\t\t"); 2174 print_media_word(media_list[i], 0, 1); 2175 printf("\n"); 2176 } 2177 } 2178 } 2179 } 2180 2181 free(media_list); 2182 2183 iface_stats: 2184 if (!vflag && !zflag) 2185 goto proto_status; 2186 2187 (void) strncpy(ifdr.ifdr_name, name, sizeof(ifdr.ifdr_name)); 2188 2189 if (ioctl(s, zflag ? SIOCZIFDATA:SIOCGIFDATA, (caddr_t)&ifdr) == -1) { 2190 err(EXIT_FAILURE, zflag ? "SIOCZIFDATA" : "SIOCGIFDATA"); 2191 } else { 2192 struct if_data * const ifi = &ifdr.ifdr_data; 2193#define PLURAL(n) ((n) == 1 ? "" : "s") 2194 printf("\tinput: %llu packet%s, %llu byte%s", 2195 (unsigned long long) ifi->ifi_ipackets, 2196 PLURAL(ifi->ifi_ipackets), 2197 (unsigned long long) ifi->ifi_ibytes, 2198 PLURAL(ifi->ifi_ibytes)); 2199 if (ifi->ifi_imcasts) 2200 printf(", %llu multicast%s", 2201 (unsigned long long) ifi->ifi_imcasts, 2202 PLURAL(ifi->ifi_imcasts)); 2203 if (ifi->ifi_ierrors) 2204 printf(", %llu error%s", 2205 (unsigned long long) ifi->ifi_ierrors, 2206 PLURAL(ifi->ifi_ierrors)); 2207 if (ifi->ifi_iqdrops) 2208 printf(", %llu queue drop%s", 2209 (unsigned long long) ifi->ifi_iqdrops, 2210 PLURAL(ifi->ifi_iqdrops)); 2211 if (ifi->ifi_noproto) 2212 printf(", %llu unknown protocol", 2213 (unsigned long long) ifi->ifi_noproto); 2214 printf("\n\toutput: %llu packet%s, %llu byte%s", 2215 (unsigned long long) ifi->ifi_opackets, 2216 PLURAL(ifi->ifi_opackets), 2217 (unsigned long long) ifi->ifi_obytes, 2218 PLURAL(ifi->ifi_obytes)); 2219 if (ifi->ifi_omcasts) 2220 printf(", %llu multicast%s", 2221 (unsigned long long) ifi->ifi_omcasts, 2222 PLURAL(ifi->ifi_omcasts)); 2223 if (ifi->ifi_oerrors) 2224 printf(", %llu error%s", 2225 (unsigned long long) ifi->ifi_oerrors, 2226 PLURAL(ifi->ifi_oerrors)); 2227 if (ifi->ifi_collisions) 2228 printf(", %llu collision%s", 2229 (unsigned long long) ifi->ifi_collisions, 2230 PLURAL(ifi->ifi_collisions)); 2231 printf("\n"); 2232#undef PLURAL 2233 } 2234 2235 proto_status: 2236 if ((p = afp) != NULL) { 2237 (*p->af_status)(1); 2238 } else for (p = afs; p->af_name; p++) { 2239 ifr.ifr_addr.sa_family = p->af_af; 2240 (*p->af_status)(0); 2241 } 2242} 2243 2244void 2245tunnel_status() 2246{ 2247 char psrcaddr[NI_MAXHOST]; 2248 char pdstaddr[NI_MAXHOST]; 2249 const char *ver = ""; 2250#ifdef NI_WITHSCOPEID 2251 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; 2252#else 2253 const int niflag = NI_NUMERICHOST; 2254#endif 2255 struct if_laddrreq req; 2256 2257 psrcaddr[0] = pdstaddr[0] = '\0'; 2258 2259 memset(&req, 0, sizeof(req)); 2260 strncpy(req.iflr_name, name, IFNAMSIZ); 2261 if (ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&req) == -1) 2262 return; 2263#ifdef INET6 2264 if (req.addr.ss_family == AF_INET6) 2265 in6_fillscopeid((struct sockaddr_in6 *)&req.addr); 2266#endif 2267 getnameinfo((struct sockaddr *)&req.addr, req.addr.ss_len, 2268 psrcaddr, sizeof(psrcaddr), 0, 0, niflag); 2269#ifdef INET6 2270 if (req.addr.ss_family == AF_INET6) 2271 ver = "6"; 2272#endif 2273 2274#ifdef INET6 2275 if (req.dstaddr.ss_family == AF_INET6) 2276 in6_fillscopeid((struct sockaddr_in6 *)&req.dstaddr); 2277#endif 2278 getnameinfo((struct sockaddr *)&req.dstaddr, req.dstaddr.ss_len, 2279 pdstaddr, sizeof(pdstaddr), 0, 0, niflag); 2280 2281 printf("\ttunnel inet%s %s --> %s\n", ver, psrcaddr, pdstaddr); 2282} 2283 2284void 2285vlan_status() 2286{ 2287 struct vlanreq vlr; 2288 2289 if (strncmp(ifr.ifr_name, "vlan", 4) != 0 || 2290 !isdigit(ifr.ifr_name[4])) 2291 return; 2292 2293 memset(&vlr, 0, sizeof(vlr)); 2294 ifr.ifr_data = (caddr_t)&vlr; 2295 2296 if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1) 2297 return; 2298 2299 if (vlr.vlr_tag || vlr.vlr_parent[0] != '\0') 2300 printf("\tvlan: %d parent: %s\n", 2301 vlr.vlr_tag, vlr.vlr_parent[0] == '\0' ? 2302 "<none>" : vlr.vlr_parent); 2303} 2304 2305void 2306in_alias(creq) 2307 struct ifreq *creq; 2308{ 2309 struct sockaddr_in *iasin; 2310 int alias; 2311 2312 if (lflag) 2313 return; 2314 2315 alias = 1; 2316 2317 /* Get the non-alias address for this interface. */ 2318 getsock(AF_INET); 2319 if (s < 0) { 2320 if (errno == EPROTONOSUPPORT) 2321 return; 2322 err(EXIT_FAILURE, "socket"); 2323 } 2324 (void) memset(&ifr, 0, sizeof(ifr)); 2325 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 2326 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) == -1) { 2327 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) { 2328 return; 2329 } else 2330 warn("SIOCGIFADDR"); 2331 } 2332 /* If creq and ifr are the same address, this is not an alias. */ 2333 if (memcmp(&ifr.ifr_addr, &creq->ifr_addr, 2334 sizeof(creq->ifr_addr)) == 0) 2335 alias = 0; 2336 (void) memset(&in_addreq, 0, sizeof(in_addreq)); 2337 (void) strncpy(in_addreq.ifra_name, name, sizeof(in_addreq.ifra_name)); 2338 memcpy(&in_addreq.ifra_addr, &creq->ifr_addr, 2339 sizeof(in_addreq.ifra_addr)); 2340 if (ioctl(s, SIOCGIFALIAS, (caddr_t)&in_addreq) == -1) { 2341 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) { 2342 return; 2343 } else 2344 warn("SIOCGIFALIAS"); 2345 } 2346 2347 iasin = &in_addreq.ifra_addr; 2348 printf("\tinet %s%s", alias ? "alias " : "", inet_ntoa(iasin->sin_addr)); 2349 2350 if (flags & IFF_POINTOPOINT) { 2351 iasin = &in_addreq.ifra_dstaddr; 2352 printf(" -> %s", inet_ntoa(iasin->sin_addr)); 2353 } 2354 2355 iasin = &in_addreq.ifra_mask; 2356 printf(" netmask 0x%x", ntohl(iasin->sin_addr.s_addr)); 2357 2358 if (flags & IFF_BROADCAST) { 2359 iasin = &in_addreq.ifra_broadaddr; 2360 printf(" broadcast %s", inet_ntoa(iasin->sin_addr)); 2361 } 2362 printf("\n"); 2363} 2364 2365void 2366in_status(force) 2367 int force; 2368{ 2369 struct ifaddrs *ifap, *ifa; 2370 struct ifreq isifr; 2371 2372 if (getifaddrs(&ifap) != 0) 2373 err(EXIT_FAILURE, "getifaddrs"); 2374 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 2375 if (strcmp(name, ifa->ifa_name) != 0) 2376 continue; 2377 if (ifa->ifa_addr->sa_family != AF_INET) 2378 continue; 2379 if (sizeof(isifr.ifr_addr) < ifa->ifa_addr->sa_len) 2380 continue; 2381 2382 memset(&isifr, 0, sizeof(isifr)); 2383 strncpy(isifr.ifr_name, ifa->ifa_name, sizeof(isifr.ifr_name)); 2384 memcpy(&isifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len); 2385 in_alias(&isifr); 2386 } 2387 freeifaddrs(ifap); 2388} 2389 2390void 2391setifprefixlen(addr, d) 2392 const char *addr; 2393 int d; 2394{ 2395 if (*afp->af_getprefix) 2396 (*afp->af_getprefix)(addr, MASK); 2397 explicit_prefix = 1; 2398} 2399 2400#ifdef INET6 2401void 2402in6_fillscopeid(sin6) 2403 struct sockaddr_in6 *sin6; 2404{ 2405#if defined(__KAME__) && defined(KAME_SCOPEID) 2406 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { 2407 sin6->sin6_scope_id = 2408 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); 2409 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; 2410 } 2411#endif 2412} 2413 2414/* XXX not really an alias */ 2415void 2416in6_alias(creq) 2417 struct in6_ifreq *creq; 2418{ 2419 struct sockaddr_in6 *sin6; 2420 char hbuf[NI_MAXHOST]; 2421 u_int32_t scopeid; 2422#ifdef NI_WITHSCOPEID 2423 const int niflag = NI_NUMERICHOST | NI_WITHSCOPEID; 2424#else 2425 const int niflag = NI_NUMERICHOST; 2426#endif 2427 2428 /* Get the non-alias address for this interface. */ 2429 getsock(AF_INET6); 2430 if (s < 0) { 2431 if (errno == EPROTONOSUPPORT) 2432 return; 2433 err(EXIT_FAILURE, "socket"); 2434 } 2435 2436 sin6 = (struct sockaddr_in6 *)&creq->ifr_addr; 2437 2438 in6_fillscopeid(sin6); 2439 scopeid = sin6->sin6_scope_id; 2440 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, 2441 hbuf, sizeof(hbuf), NULL, 0, niflag)) 2442 strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */ 2443 printf("\tinet6 %s", hbuf); 2444 2445 if (flags & IFF_POINTOPOINT) { 2446 (void) memset(&ifr6, 0, sizeof(ifr6)); 2447 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 2448 ifr6.ifr_addr = creq->ifr_addr; 2449 if (ioctl(s, SIOCGIFDSTADDR_IN6, (caddr_t)&ifr6) == -1) { 2450 if (errno != EADDRNOTAVAIL) 2451 warn("SIOCGIFDSTADDR_IN6"); 2452 (void) memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr)); 2453 ifr6.ifr_addr.sin6_family = AF_INET6; 2454 ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6); 2455 } 2456 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr; 2457 in6_fillscopeid(sin6); 2458 hbuf[0] = '\0'; 2459 if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len, 2460 hbuf, sizeof(hbuf), NULL, 0, niflag)) 2461 strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */ 2462 printf(" -> %s", hbuf); 2463 } 2464 2465 (void) memset(&ifr6, 0, sizeof(ifr6)); 2466 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 2467 ifr6.ifr_addr = creq->ifr_addr; 2468 if (ioctl(s, SIOCGIFNETMASK_IN6, (caddr_t)&ifr6) == -1) { 2469 if (errno != EADDRNOTAVAIL) 2470 warn("SIOCGIFNETMASK_IN6"); 2471 } else { 2472 sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr; 2473 printf(" prefixlen %d", prefix(&sin6->sin6_addr, 2474 sizeof(struct in6_addr))); 2475 } 2476 2477 (void) memset(&ifr6, 0, sizeof(ifr6)); 2478 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 2479 ifr6.ifr_addr = creq->ifr_addr; 2480 if (ioctl(s, SIOCGIFAFLAG_IN6, (caddr_t)&ifr6) == -1) { 2481 if (errno != EADDRNOTAVAIL) 2482 warn("SIOCGIFAFLAG_IN6"); 2483 } else { 2484 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST) 2485 printf(" anycast"); 2486 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE) 2487 printf(" tentative"); 2488 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED) 2489 printf(" duplicated"); 2490 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED) 2491 printf(" detached"); 2492 if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED) 2493 printf(" deprecated"); 2494 } 2495 2496 if (scopeid) 2497 printf(" scopeid 0x%x", scopeid); 2498 2499 if (Lflag) { 2500 struct in6_addrlifetime *lifetime; 2501 (void) memset(&ifr6, 0, sizeof(ifr6)); 2502 (void) strncpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name)); 2503 ifr6.ifr_addr = creq->ifr_addr; 2504 lifetime = &ifr6.ifr_ifru.ifru_lifetime; 2505 if (ioctl(s, SIOCGIFALIFETIME_IN6, (caddr_t)&ifr6) == -1) { 2506 if (errno != EADDRNOTAVAIL) 2507 warn("SIOCGIFALIFETIME_IN6"); 2508 } else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) { 2509 time_t t = time(NULL); 2510 printf(" pltime "); 2511 if (lifetime->ia6t_preferred) { 2512 printf("%s", lifetime->ia6t_preferred < t 2513 ? "0" 2514 : sec2str(lifetime->ia6t_preferred - t)); 2515 } else 2516 printf("infty"); 2517 2518 printf(" vltime "); 2519 if (lifetime->ia6t_expire) { 2520 printf("%s", lifetime->ia6t_expire < t 2521 ? "0" 2522 : sec2str(lifetime->ia6t_expire - t)); 2523 } else 2524 printf("infty"); 2525 } 2526 } 2527 2528 printf("\n"); 2529} 2530 2531void 2532in6_status(force) 2533 int force; 2534{ 2535 struct ifaddrs *ifap, *ifa; 2536 struct in6_ifreq isifr; 2537 2538 if (getifaddrs(&ifap) != 0) 2539 err(EXIT_FAILURE, "getifaddrs"); 2540 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 2541 if (strcmp(name, ifa->ifa_name) != 0) 2542 continue; 2543 if (ifa->ifa_addr->sa_family != AF_INET6) 2544 continue; 2545 if (sizeof(isifr.ifr_addr) < ifa->ifa_addr->sa_len) 2546 continue; 2547 2548 memset(&isifr, 0, sizeof(isifr)); 2549 strncpy(isifr.ifr_name, ifa->ifa_name, sizeof(isifr.ifr_name)); 2550 memcpy(&isifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len); 2551 in6_alias(&isifr); 2552 } 2553 freeifaddrs(ifap); 2554} 2555#endif /*INET6*/ 2556 2557#ifndef INET_ONLY 2558 2559void 2560at_status(force) 2561 int force; 2562{ 2563 struct sockaddr_at *sat, null_sat; 2564 struct netrange *nr; 2565 2566 getsock(AF_APPLETALK); 2567 if (s < 0) { 2568 if (errno == EPROTONOSUPPORT) 2569 return; 2570 err(EXIT_FAILURE, "socket"); 2571 } 2572 (void) memset(&ifr, 0, sizeof(ifr)); 2573 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 2574 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) == -1) { 2575 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) { 2576 if (!force) 2577 return; 2578 (void) memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 2579 } else 2580 warn("SIOCGIFADDR"); 2581 } 2582 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); 2583 sat = (struct sockaddr_at *)&ifr.ifr_addr; 2584 2585 (void) memset(&null_sat, 0, sizeof(null_sat)); 2586 2587 nr = (struct netrange *) &sat->sat_zero; 2588 printf("\tatalk %d.%d range %d-%d phase %d", 2589 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, 2590 ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase); 2591 if (flags & IFF_POINTOPOINT) { 2592 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) == -1) { 2593 if (errno == EADDRNOTAVAIL) 2594 (void) memset(&ifr.ifr_addr, 0, 2595 sizeof(ifr.ifr_addr)); 2596 else 2597 warn("SIOCGIFDSTADDR"); 2598 } 2599 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 2600 sat = (struct sockaddr_at *)&ifr.ifr_dstaddr; 2601 if (!sat) 2602 sat = &null_sat; 2603 printf("--> %d.%d", 2604 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node); 2605 } 2606 if (flags & IFF_BROADCAST) { 2607 /* note RTAX_BRD overlap with IFF_POINTOPOINT */ 2608 sat = (struct sockaddr_at *)&ifr.ifr_broadaddr; 2609 if (sat) 2610 printf(" broadcast %d.%d", ntohs(sat->sat_addr.s_net), 2611 sat->sat_addr.s_node); 2612 } 2613 putchar('\n'); 2614} 2615 2616void 2617xns_status(force) 2618 int force; 2619{ 2620 struct sockaddr_ns *sns; 2621 2622 getsock(AF_NS); 2623 if (s < 0) { 2624 if (errno == EPROTONOSUPPORT) 2625 return; 2626 err(EXIT_FAILURE, "socket"); 2627 } 2628 (void) memset(&ifr, 0, sizeof(ifr)); 2629 (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 2630 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) == -1) { 2631 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) { 2632 if (!force) 2633 return; 2634 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 2635 } else 2636 warn("SIOCGIFADDR"); 2637 } 2638 (void) strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); 2639 sns = (struct sockaddr_ns *)&ifr.ifr_addr; 2640 printf("\tns %s ", ns_ntoa(sns->sns_addr)); 2641 if (flags & IFF_POINTOPOINT) { /* by W. Nesheim@Cornell */ 2642 if (ioctl(s, SIOCGIFDSTADDR, (caddr_t)&ifr) == -1) { 2643 if (errno == EADDRNOTAVAIL) 2644 memset(&ifr.ifr_addr, 0, sizeof(ifr.ifr_addr)); 2645 else 2646 warn("SIOCGIFDSTADDR"); 2647 } 2648 (void) strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); 2649 sns = (struct sockaddr_ns *)&ifr.ifr_dstaddr; 2650 printf("--> %s ", ns_ntoa(sns->sns_addr)); 2651 } 2652 putchar('\n'); 2653} 2654 2655void 2656iso_status(force) 2657 int force; 2658{ 2659 struct sockaddr_iso *siso; 2660 struct iso_ifreq isoifr; 2661 2662 getsock(AF_ISO); 2663 if (s < 0) { 2664 if (errno == EPROTONOSUPPORT) 2665 return; 2666 err(EXIT_FAILURE, "socket"); 2667 } 2668 (void) memset(&isoifr, 0, sizeof(isoifr)); 2669 (void) strncpy(isoifr.ifr_name, name, sizeof(isoifr.ifr_name)); 2670 if (ioctl(s, SIOCGIFADDR_ISO, (caddr_t)&isoifr) == -1) { 2671 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT) { 2672 if (!force) 2673 return; 2674 (void) memset(&isoifr.ifr_Addr, 0, 2675 sizeof(isoifr.ifr_Addr)); 2676 } else 2677 warn("SIOCGIFADDR_ISO"); 2678 } 2679 (void) strncpy(isoifr.ifr_name, name, sizeof isoifr.ifr_name); 2680 siso = &isoifr.ifr_Addr; 2681 printf("\tiso %s ", iso_ntoa(&siso->siso_addr)); 2682 if (ioctl(s, SIOCGIFNETMASK_ISO, (caddr_t)&isoifr) == -1) { 2683 if (errno == EADDRNOTAVAIL) 2684 memset(&isoifr.ifr_Addr, 0, sizeof(isoifr.ifr_Addr)); 2685 else 2686 warn("SIOCGIFNETMASK_ISO"); 2687 } else { 2688 if (siso->siso_len > offsetof(struct sockaddr_iso, siso_addr)) 2689 siso->siso_addr.isoa_len = siso->siso_len 2690 - offsetof(struct sockaddr_iso, siso_addr); 2691 printf("\n\t\tnetmask %s ", iso_ntoa(&siso->siso_addr)); 2692 } 2693 if (flags & IFF_POINTOPOINT) { 2694 if (ioctl(s, SIOCGIFDSTADDR_ISO, (caddr_t)&isoifr) == -1) { 2695 if (errno == EADDRNOTAVAIL) 2696 memset(&isoifr.ifr_Addr, 0, 2697 sizeof(isoifr.ifr_Addr)); 2698 else 2699 warn("SIOCGIFDSTADDR_ISO"); 2700 } 2701 (void) strncpy(isoifr.ifr_name, name, sizeof (isoifr.ifr_name)); 2702 siso = &isoifr.ifr_Addr; 2703 printf("--> %s ", iso_ntoa(&siso->siso_addr)); 2704 } 2705 putchar('\n'); 2706} 2707 2708#endif /* INET_ONLY */ 2709 2710#define SIN(x) ((struct sockaddr_in *) &(x)) 2711struct sockaddr_in *sintab[] = { 2712SIN(ridreq.ifr_addr), SIN(in_addreq.ifra_addr), 2713SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)}; 2714 2715void 2716in_getaddr(str, which) 2717 const char *str; 2718 int which; 2719{ 2720 struct sockaddr_in *gasin = sintab[which]; 2721 struct hostent *hp; 2722 struct netent *np; 2723 2724 gasin->sin_len = sizeof(*gasin); 2725 if (which != MASK) 2726 gasin->sin_family = AF_INET; 2727 2728 if (which == ADDR) { 2729 char *p = NULL; 2730 if ((p = strrchr(str, '/')) != NULL) { 2731 *p = '\0'; 2732 in_getprefix(p + 1, MASK); 2733 } 2734 } 2735 2736 if (inet_aton(str, &gasin->sin_addr) == 0) { 2737 if ((hp = gethostbyname(str)) != NULL) 2738 (void) memcpy(&gasin->sin_addr, hp->h_addr, hp->h_length); 2739 else if ((np = getnetbyname(str)) != NULL) 2740 gasin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 2741 else 2742 errx(EXIT_FAILURE, "%s: bad value", str); 2743 } 2744} 2745 2746void 2747in_getprefix(plen, which) 2748 const char *plen; 2749 int which; 2750{ 2751 register struct sockaddr_in *igsin = sintab[which]; 2752 register u_char *cp; 2753 int len = strtol(plen, (char **)NULL, 10); 2754 2755 if ((len < 0) || (len > 32)) 2756 errx(EXIT_FAILURE, "%s: bad value", plen); 2757 igsin->sin_len = sizeof(*igsin); 2758 if (which != MASK) 2759 igsin->sin_family = AF_INET; 2760 if ((len == 0) || (len == 32)) { 2761 memset(&igsin->sin_addr, 0xff, sizeof(struct in_addr)); 2762 return; 2763 } 2764 memset((void *)&igsin->sin_addr, 0x00, sizeof(igsin->sin_addr)); 2765 for (cp = (u_char *)&igsin->sin_addr; len > 7; len -= 8) 2766 *cp++ = 0xff; 2767 if (len) 2768 *cp = 0xff << (8 - len); 2769} 2770 2771#ifdef INET6 2772#define SIN6(x) ((struct sockaddr_in6 *) &(x)) 2773struct sockaddr_in6 *sin6tab[] = { 2774SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr), 2775SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)}; 2776 2777void 2778in6_getaddr(str, which) 2779 const char *str; 2780 int which; 2781{ 2782#if defined(__KAME__) && defined(KAME_SCOPEID) 2783 struct sockaddr_in6 *sin6 = sin6tab[which]; 2784 struct addrinfo hints, *res; 2785 int error; 2786 char *slash = NULL; 2787 2788 if (which == ADDR) { 2789 if ((slash = strrchr(str, '/')) != NULL) 2790 *slash = '\0'; 2791 } 2792 2793 memset(&hints, 0, sizeof(hints)); 2794 hints.ai_family = AF_INET6; 2795 hints.ai_socktype = SOCK_DGRAM; 2796#if 0 /* in_getaddr() allows FQDN */ 2797 hints.ai_flags = AI_NUMERICHOST; 2798#endif 2799 error = getaddrinfo(str, "0", &hints, &res); 2800 if (error && slash) { 2801 /* try again treating the '/' as part of the name */ 2802 *slash = '/'; 2803 slash = NULL; 2804 error = getaddrinfo(str, "0", &hints, &res); 2805 } 2806 if (error) 2807 errx(EXIT_FAILURE, "%s: %s", str, gai_strerror(error)); 2808 if (res->ai_next) 2809 errx(EXIT_FAILURE, "%s: resolved to multiple addresses", str); 2810 if (res->ai_addrlen != sizeof(struct sockaddr_in6)) 2811 errx(EXIT_FAILURE, "%s: bad value", str); 2812 memcpy(sin6, res->ai_addr, res->ai_addrlen); 2813 freeaddrinfo(res); 2814 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && sin6->sin6_scope_id) { 2815 *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] = 2816 htons(sin6->sin6_scope_id); 2817 sin6->sin6_scope_id = 0; 2818 } 2819 if (slash) { 2820 in6_getprefix(slash + 1, MASK); 2821 explicit_prefix = 1; 2822 } 2823#else 2824 struct sockaddr_in6 *gasin = sin6tab[which]; 2825 2826 gasin->sin6_len = sizeof(*gasin); 2827 if (which != MASK) 2828 gasin->sin6_family = AF_INET6; 2829 2830 if (which == ADDR) { 2831 char *p = NULL; 2832 if((p = strrchr(str, '/')) != NULL) { 2833 *p = '\0'; 2834 in6_getprefix(p + 1, MASK); 2835 explicit_prefix = 1; 2836 } 2837 } 2838 2839 if (inet_pton(AF_INET6, str, &gasin->sin6_addr) != 1) 2840 errx(EXIT_FAILURE, "%s: bad value", str); 2841#endif 2842} 2843 2844void 2845in6_getprefix(plen, which) 2846 const char *plen; 2847 int which; 2848{ 2849 register struct sockaddr_in6 *gpsin = sin6tab[which]; 2850 register u_char *cp; 2851 int len = strtol(plen, (char **)NULL, 10); 2852 2853 if ((len < 0) || (len > 128)) 2854 errx(EXIT_FAILURE, "%s: bad value", plen); 2855 gpsin->sin6_len = sizeof(*gpsin); 2856 if (which != MASK) 2857 gpsin->sin6_family = AF_INET6; 2858 if ((len == 0) || (len == 128)) { 2859 memset(&gpsin->sin6_addr, 0xff, sizeof(struct in6_addr)); 2860 return; 2861 } 2862 memset((void *)&gpsin->sin6_addr, 0x00, sizeof(gpsin->sin6_addr)); 2863 for (cp = (u_char *)&gpsin->sin6_addr; len > 7; len -= 8) 2864 *cp++ = 0xff; 2865 if (len) 2866 *cp = 0xff << (8 - len); 2867} 2868 2869int 2870prefix(val, size) 2871 void *val; 2872 int size; 2873{ 2874 register u_char *pname = (u_char *)val; 2875 register int byte, bit, plen = 0; 2876 2877 for (byte = 0; byte < size; byte++, plen += 8) 2878 if (pname[byte] != 0xff) 2879 break; 2880 if (byte == size) 2881 return (plen); 2882 for (bit = 7; bit != 0; bit--, plen++) 2883 if (!(pname[byte] & (1 << bit))) 2884 break; 2885 for (; bit != 0; bit--) 2886 if (pname[byte] & (1 << bit)) 2887 return(0); 2888 byte++; 2889 for (; byte < size; byte++) 2890 if (pname[byte]) 2891 return(0); 2892 return (plen); 2893} 2894#endif /*INET6*/ 2895 2896#ifndef INET_ONLY 2897void 2898at_getaddr(addr, which) 2899 const char *addr; 2900 int which; 2901{ 2902 struct sockaddr_at *sat = (struct sockaddr_at *) &addreq.ifra_addr; 2903 u_int net, node; 2904 2905 sat->sat_family = AF_APPLETALK; 2906 sat->sat_len = sizeof(*sat); 2907 if (which == MASK) 2908 errx(EXIT_FAILURE, "AppleTalk does not use netmasks"); 2909 if (sscanf(addr, "%u.%u", &net, &node) != 2 2910 || net == 0 || net > 0xffff || node == 0 || node > 0xfe) 2911 errx(EXIT_FAILURE, "%s: illegal address", addr); 2912 sat->sat_addr.s_net = htons(net); 2913 sat->sat_addr.s_node = node; 2914} 2915 2916void 2917setatrange(range, d) 2918 const char *range; 2919 int d; 2920{ 2921 u_short first = 123, last = 123; 2922 2923 if (sscanf(range, "%hu-%hu", &first, &last) != 2 2924 || first == 0 /* || first > 0xffff */ 2925 || last == 0 /* || last > 0xffff */ || first > last) 2926 errx(EXIT_FAILURE, "%s: illegal net range: %u-%u", range, 2927 first, last); 2928 at_nr.nr_firstnet = htons(first); 2929 at_nr.nr_lastnet = htons(last); 2930} 2931 2932void 2933setatphase(phase, d) 2934 const char *phase; 2935 int d; 2936{ 2937 if (!strcmp(phase, "1")) 2938 at_nr.nr_phase = 1; 2939 else if (!strcmp(phase, "2")) 2940 at_nr.nr_phase = 2; 2941 else 2942 errx(EXIT_FAILURE, "%s: illegal phase", phase); 2943} 2944 2945void 2946checkatrange(sat) 2947 struct sockaddr_at *sat; 2948{ 2949 if (at_nr.nr_phase == 0) 2950 at_nr.nr_phase = 2; /* Default phase 2 */ 2951 if (at_nr.nr_firstnet == 0) 2952 at_nr.nr_firstnet = /* Default range of one */ 2953 at_nr.nr_lastnet = sat->sat_addr.s_net; 2954 printf("\tatalk %d.%d range %d-%d phase %d\n", 2955 ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node, 2956 ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet), at_nr.nr_phase); 2957 if ((u_short) ntohs(at_nr.nr_firstnet) > 2958 (u_short) ntohs(sat->sat_addr.s_net) 2959 || (u_short) ntohs(at_nr.nr_lastnet) < 2960 (u_short) ntohs(sat->sat_addr.s_net)) 2961 errx(EXIT_FAILURE, "AppleTalk address is not in range"); 2962 *((struct netrange *) &sat->sat_zero) = at_nr; 2963} 2964 2965#define SNS(x) ((struct sockaddr_ns *) &(x)) 2966struct sockaddr_ns *snstab[] = { 2967SNS(ridreq.ifr_addr), SNS(addreq.ifra_addr), 2968SNS(addreq.ifra_mask), SNS(addreq.ifra_broadaddr)}; 2969 2970void 2971xns_getaddr(addr, which) 2972 const char *addr; 2973 int which; 2974{ 2975 struct sockaddr_ns *sns = snstab[which]; 2976 2977 sns->sns_family = AF_NS; 2978 sns->sns_len = sizeof(*sns); 2979 sns->sns_addr = ns_addr(addr); 2980 if (which == MASK) 2981 puts("Attempt to set XNS netmask will be ineffectual"); 2982} 2983 2984#define SISO(x) ((struct sockaddr_iso *) &(x)) 2985struct sockaddr_iso *sisotab[] = { 2986SISO(iso_ridreq.ifr_Addr), SISO(iso_addreq.ifra_addr), 2987SISO(iso_addreq.ifra_mask), SISO(iso_addreq.ifra_dstaddr)}; 2988 2989void 2990iso_getaddr(addr, which) 2991 const char *addr; 2992 int which; 2993{ 2994 struct sockaddr_iso *siso = sisotab[which]; 2995 siso->siso_addr = *iso_addr(addr); 2996 2997 if (which == MASK) { 2998 siso->siso_len = TSEL(siso) - (caddr_t)(siso); 2999 siso->siso_nlen = 0; 3000 } else { 3001 siso->siso_len = sizeof(*siso); 3002 siso->siso_family = AF_ISO; 3003 } 3004} 3005 3006void 3007setsnpaoffset(val, d) 3008 const char *val; 3009 int d; 3010{ 3011 iso_addreq.ifra_snpaoffset = atoi(val); 3012} 3013 3014void 3015setnsellength(val, d) 3016 const char *val; 3017 int d; 3018{ 3019 nsellength = atoi(val); 3020 if (nsellength < 0) 3021 errx(EXIT_FAILURE, "Negative NSEL length is absurd"); 3022 if (afp == 0 || afp->af_af != AF_ISO) 3023 errx(EXIT_FAILURE, "Setting NSEL length valid only for iso"); 3024} 3025 3026void 3027fixnsel(siso) 3028 struct sockaddr_iso *siso; 3029{ 3030 if (siso->siso_family == 0) 3031 return; 3032 siso->siso_tlen = nsellength; 3033} 3034 3035void 3036adjust_nsellength() 3037{ 3038 fixnsel(sisotab[RIDADDR]); 3039 fixnsel(sisotab[ADDR]); 3040 fixnsel(sisotab[DSTADDR]); 3041} 3042 3043#endif /* INET_ONLY */ 3044 3045void 3046usage() 3047{ 3048 const char *progname = getprogname(); 3049 3050 fprintf(stderr, 3051 "usage: %s [-m] [-v] [-z] " 3052#ifdef INET6 3053 "[-L] " 3054#endif 3055 "interface\n" 3056 "\t[ af [ address [ dest_addr ] ] [ netmask mask ] [ prefixlen n ]\n" 3057 "\t\t[ alias | -alias ] ]\n" 3058 "\t[ up ] [ down ] [ metric n ] [ mtu n ]\n" 3059 "\t[ nwid network_id ] [ nwkey network_key | -nwkey ]\n" 3060 "\t[ powersave | -powersave ] [ powersavesleep duration ]\n" 3061 "\t[ [ af ] tunnel src_addr dest_addr ] [ deletetunnel ]\n" 3062 "\t[ arp | -arp ]\n" 3063 "\t[ media type ] [ mediaopt opts ] [ -mediaopt opts ] " 3064 "[ instance minst ]\n" 3065 "\t[ vlan n vlanif i ]\n" 3066 "\t[ anycast | -anycast ] [ deprecated | -deprecated ]\n" 3067 "\t[ tentative | -tentative ] [ pltime n ] [ vltime n ] [ eui64 ]\n" 3068 "\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n" 3069 " %s -a [-b] [-m] [-d] [-u] [-v] [-z] [ af ]\n" 3070 " %s -l [-b] [-d] [-u] [-s]\n" 3071 " %s -C\n" 3072 " %s interface create\n" 3073 " %s interface destroy\n", 3074 progname, progname, progname, progname, progname, progname); 3075 exit(1); 3076} 3077 3078#ifdef INET6 3079char * 3080sec2str(total) 3081 time_t total; 3082{ 3083 static char result[256]; 3084 int days, hours, mins, secs; 3085 int first = 1; 3086 char *p = result; 3087 char *end = &result[sizeof(result)]; 3088 int n; 3089 3090 if (0) { /*XXX*/ 3091 days = total / 3600 / 24; 3092 hours = (total / 3600) % 24; 3093 mins = (total / 60) % 60; 3094 secs = total % 60; 3095 3096 if (days) { 3097 first = 0; 3098 n = snprintf(p, end - p, "%dd", days); 3099 if (n < 0 || n >= end - p) 3100 return(result); 3101 p += n; 3102 } 3103 if (!first || hours) { 3104 first = 0; 3105 n = snprintf(p, end - p, "%dh", hours); 3106 if (n < 0 || n >= end - p) 3107 return(result); 3108 p += n; 3109 } 3110 if (!first || mins) { 3111 first = 0; 3112 n = snprintf(p, end - p, "%dm", mins); 3113 if (n < 0 || n >= end - p) 3114 return(result); 3115 p += n; 3116 } 3117 snprintf(p, end - p, "%ds", secs); 3118 } else 3119 snprintf(p, end - p, "%lu", (u_long)total); 3120 3121 return(result); 3122} 3123#endif 3124