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