1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 /* 6 * Copyright (c) 1983 Regents of the University of California. 7 * All rights reserved. The Berkeley software License Agreement 8 * specifies the terms and conditions for redistribution. 9 */ 10 11 #pragma ident "%Z%%M% %I% %E% SMI" 12 13 #include "defs.h" 14 #include "strings.h" 15 #include "ifconfig.h" 16 #include <compat.h> 17 18 #include <sys/dlpi.h> 19 #include <libdlpi.h> 20 21 #define LOOPBACK_IF "lo0" 22 23 #define NONE_STR "none" 24 25 #ifndef ARP_MOD_NAME 26 #define ARP_MOD_NAME "arp" 27 #endif 28 29 #ifndef IP_DEV_NAME 30 #define IP_DEV_NAME "/dev/ip" 31 #endif 32 33 #ifndef IP_MOD_NAME 34 #define IP_MOD_NAME "ip" 35 #endif 36 37 #ifndef IP6_DEV_NAME 38 #define IP6_DEV_NAME "/dev/ip6" 39 #endif 40 41 #ifndef UDP_DEV_NAME 42 #define UDP_DEV_NAME "/dev/udp" 43 #endif 44 45 #ifndef UDP6_DEV_NAME 46 #define UDP6_DEV_NAME "/dev/udp6" 47 #endif 48 49 #define ADDRBITS_V4 32 /* number of bits in IPv4 address */ 50 #define ADDRBITS_V6 128 /* number of bits in IPv6 address */ 51 52 #define AF_FUNC_STATUS 1 /* af_status func reports status */ 53 #define AF_FUNC_CONFIGINFO 2 /* af_status func reports configinfo */ 54 55 typedef struct if_flags { 56 uint64_t iff_value; 57 char *iff_name; 58 } if_flags_t; 59 60 static if_flags_t if_flags_tbl[] = { 61 { IFF_UP, "UP" }, 62 { IFF_BROADCAST, "BROADCAST" }, 63 { IFF_DEBUG, "DEBUG" }, 64 { IFF_LOOPBACK, "LOOPBACK" }, 65 { IFF_POINTOPOINT, "POINTOPOINT" }, 66 { IFF_NOTRAILERS, "NOTRAILERS" }, 67 { IFF_RUNNING, "RUNNING" }, 68 { IFF_NOARP, "NOARP" }, 69 { IFF_PROMISC, "PROMISC" }, 70 { IFF_ALLMULTI, "ALLMULTI" }, 71 { IFF_INTELLIGENT, "INTELLIGENT" }, 72 { IFF_MULTICAST, "MULTICAST" }, 73 { IFF_MULTI_BCAST, "MULTI_BCAST" }, 74 { IFF_UNNUMBERED, "UNNUMBERED" }, 75 { IFF_DHCPRUNNING, "DHCP" }, 76 { IFF_PRIVATE, "PRIVATE" }, 77 { IFF_NOXMIT, "NOXMIT" }, 78 { IFF_NOLOCAL, "NOLOCAL" }, 79 { IFF_DEPRECATED, "DEPRECATED" }, 80 { IFF_ADDRCONF, "ADDRCONF" }, 81 { IFF_ROUTER, "ROUTER" }, 82 { IFF_NONUD, "NONUD" }, 83 { IFF_ANYCAST, "ANYCAST" }, 84 { IFF_NORTEXCH, "NORTEXCH" }, 85 { IFF_IPV4, "IPv4" }, 86 { IFF_IPV6, "IPv6" }, 87 { IFF_MIPRUNNING, "MIP" }, 88 { IFF_NOFAILOVER, "NOFAILOVER" }, 89 { IFF_FAILED, "FAILED" }, 90 { IFF_STANDBY, "STANDBY" }, 91 { IFF_INACTIVE, "INACTIVE" }, 92 { IFF_OFFLINE, "OFFLINE" }, 93 { IFF_XRESOLV, "XRESOLV" }, 94 { IFF_COS_ENABLED, "CoS" }, 95 { IFF_PREFERRED, "PREFERRED" }, 96 { IFF_TEMPORARY, "TEMPORARY" }, 97 { IFF_FIXEDMTU, "FIXEDMTU" }, 98 { IFF_VIRTUAL, "VIRTUAL"} 99 }; 100 101 static struct lifreq lifr; 102 /* current interface name a praticular function is accessing */ 103 static char name[LIFNAMSIZ]; 104 /* foreach interface saved name */ 105 static char origname[LIFNAMSIZ]; 106 static char savedname[LIFNAMSIZ]; /* For addif */ 107 static int setaddr; 108 static char partname[LIFNAMSIZ]; 109 110 uid_t euid; 111 112 /* 113 * Make sure the algorithm variables hold more than the sizeof an algorithm 114 * in PF_KEY. (For now, more than a uint8_t.) The NO_***_?ALG indicates that 115 * there was no algorithm requested, and in the ipsec_req that service should 116 * be disabled. (E.g. if ah_aalg remains NO_AH_AALG, then AH will be 117 * disabled on that tunnel.) 118 */ 119 #define NO_AH_AALG 256 120 #define NO_ESP_AALG 256 121 #define NO_ESP_EALG 256 122 123 /* 124 * iface_t 125 * used by setifether to create a list of interfaces to mark 126 * down-up when changing the ethernet address of an interface 127 */ 128 typedef struct iface { 129 struct lifreq lifr; 130 struct iface *next; /* pointer to the next list element */ 131 } iface_t; 132 133 static iface_t *logifs = NULL; /* list of logical interfaces */ 134 static iface_t *phyif = NULL; /* physical interface */ 135 136 int s; 137 int af = AF_INET; /* default address family */ 138 int debug = 0; 139 int all = 0; /* setifdhcp() needs to know this */ 140 int verbose = 0; 141 int v4compat = 0; /* Compatible printing format */ 142 boolean_t partial = _B_FALSE; 143 144 /* 145 * Function prototypes for command functions. 146 */ 147 static int addif(char *arg, int64_t param); 148 static int inetplumb(char *arg, int64_t param); 149 static int inetunplumb(char *arg, int64_t param); 150 static int removeif(char *arg, int64_t param); 151 static int setdebugflag(char *arg, int64_t param); 152 static int setifaddr(char *arg, int64_t param); 153 static int setifbroadaddr(char *arg, int64_t param); 154 static int setifdstaddr(char *arg, int64_t param); 155 static int setifether(char *arg, int64_t param); 156 static int setifflags(char *arg, int64_t param); 157 static int setifindex(char *arg, int64_t param); 158 static int setifmetric(char *arg, int64_t param); 159 static int setifmtu(char *arg, int64_t param); 160 static int setifnetmask(char *arg, int64_t param); 161 static int setifprefixlen(char *arg, int64_t param); 162 static int setifrevarp(char *arg, int64_t param); 163 static int setifsubnet(char *arg, int64_t param); 164 static int setiftdst(char *arg, int64_t param); 165 static int setiftoken(char *arg, int64_t param); 166 static int setiftsrc(char *arg, int64_t param); 167 static int setverboseflag(char *arg, int64_t param); 168 static int set_tun_ah_alg(char *arg, int64_t param); 169 static int set_tun_esp_auth_alg(char *arg, int64_t param); 170 static int set_tun_esp_encr_alg(char *arg, int64_t param); 171 static int modlist(char *arg, int64_t param); 172 static int modinsert(char *arg, int64_t param); 173 static int modremove(char *arg, int64_t param); 174 static int setifgroupname(char *arg, int64_t param); 175 static int configinfo(char *arg, int64_t param); 176 static void print_config_flags(uint64_t flags); 177 static void print_flags(uint64_t flags); 178 static void print_ifether(char *ifname); 179 static int set_tun_encap_limit(char *arg, int64_t param); 180 static int clr_tun_encap_limit(char *arg, int64_t param); 181 static int set_tun_hop_limit(char *arg, int64_t param); 182 static int setzone(char *arg, int64_t param); 183 static int setifsrc(char *arg, int64_t param); 184 185 #ifdef DEBUG 186 static int setnd(char *arg, int64_t param); 187 static int delnd(char *arg, int64_t param); 188 static int getnd(char *arg, int64_t param); 189 #endif /* DEBUG */ 190 191 /* 192 * Address family specific function prototypes. 193 */ 194 static void in_getaddr(char *s, struct sockaddr *saddr, int *plenp); 195 static void in_status(int force, uint64_t flags); 196 static void in_configinfo(int force, uint64_t flags); 197 static void in6_getaddr(char *s, struct sockaddr *saddr, int *plenp); 198 static void in6_status(int force, uint64_t flags); 199 static void in6_configinfo(int force, uint64_t flags); 200 201 /* 202 * Misc support functions 203 */ 204 static int devfs_entry(di_node_t node, di_minor_t minor, void *arg); 205 static void foreachinterface(void (*func)(), int argc, char *argv[], 206 int af, int64_t onflags, int64_t offflags, 207 int64_t lifc_flags); 208 static void ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp); 209 static int ifdad(char *ifname, struct sockaddr_in6 *laddr); 210 static boolean_t in_getmask(struct sockaddr_in *saddr); 211 static int in_getprefixlen(char *addr, boolean_t slash, int plen); 212 static boolean_t in_prefixlentomask(int prefixlen, int maxlen, 213 uchar_t *mask); 214 static int settaddr(char *, int (*)(icfg_handle_t, 215 const struct sockaddr *, socklen_t)); 216 static void status(void); 217 static void ifstatus(const char *); 218 static void usage(void); 219 static int strioctl(int s, int cmd, char *buf, int buflen); 220 static int setifdhcp(const char *caller, const char *ifname, 221 int argc, char *argv[]); 222 static int ip_domux2fd(int *, int *, int *, int *); 223 static int ip_plink(int, int, int, int); 224 static int modop(char *arg, char op); 225 static int get_lun(char *); 226 static void selectifs(int argc, char *argv[], int af, 227 struct lifreq *lifrp); 228 static int updownifs(iface_t *ifs, int up); 229 230 #define max(a, b) ((a) < (b) ? (b) : (a)) 231 232 /* 233 * DHCP_EXIT_IF_FAILURE indicates that the operation failed, but if there 234 * are more interfaces to act on (i.e., ifconfig was invoked with -a), keep 235 * on going rather than exit with an error. 236 */ 237 238 #define DHCP_EXIT_IF_FAILURE -1 239 #define DHCP_IPC_MAX_WAIT 15 /* max seconds to wait to start agent */ 240 241 #define NEXTARG 0xffffff /* command takes an argument */ 242 #define OPTARG 0xfffffe /* command takes an optional argument */ 243 #define AF_ANY (-1) 244 245 /* Refer to the comments in ifconfig() on the netmask "hack" */ 246 #define NETMASK_CMD "netmask" 247 struct sockaddr_storage g_netmask; 248 boolean_t g_netmask_set = _B_FALSE; 249 250 struct cmd { 251 char *c_name; 252 int64_t c_parameter; /* NEXTARG means next argv */ 253 int (*c_func)(char *, int64_t); 254 int c_abortonfail; /* don't continue parsing args */ 255 /* for the current interface */ 256 int c_af; /* address family restrictions */ 257 } cmds[] = { 258 { "up", IFF_UP, setifflags, 0, AF_ANY }, 259 { "down", -IFF_UP, setifflags, 0, AF_ANY }, 260 { "trailers", -IFF_NOTRAILERS, setifflags, 0, AF_ANY }, 261 { "-trailers", IFF_NOTRAILERS, setifflags, 0, AF_ANY }, 262 { "arp", -IFF_NOARP, setifflags, 0, AF_INET }, 263 { "-arp", IFF_NOARP, setifflags, 0, AF_INET }, 264 { "router", IFF_ROUTER, setifflags, 0, AF_ANY }, 265 { "-router", -IFF_ROUTER, setifflags, 0, AF_ANY }, 266 { "private", IFF_PRIVATE, setifflags, 0, AF_ANY }, 267 { "-private", -IFF_PRIVATE, setifflags, 0, AF_ANY }, 268 { "xmit", -IFF_NOXMIT, setifflags, 0, AF_ANY }, 269 { "-xmit", IFF_NOXMIT, setifflags, 0, AF_ANY }, 270 { "-nud", IFF_NONUD, setifflags, 0, AF_INET6 }, 271 { "nud", -IFF_NONUD, setifflags, 0, AF_INET6 }, 272 { "anycast", IFF_ANYCAST, setifflags, 0, AF_ANY }, 273 { "-anycast", -IFF_ANYCAST, setifflags, 0, AF_ANY }, 274 { "local", -IFF_NOLOCAL, setifflags, 0, AF_ANY }, 275 { "-local", IFF_NOLOCAL, setifflags, 0, AF_ANY }, 276 { "deprecated", IFF_DEPRECATED, setifflags, 0, AF_ANY }, 277 { "-deprecated", -IFF_DEPRECATED, setifflags, 0, AF_ANY }, 278 { "preferred", IFF_PREFERRED, setifflags, 0, AF_INET6 }, 279 { "-preferred", -IFF_PREFERRED, setifflags, 0, AF_INET6 }, 280 { "debug", 0, setdebugflag, 0, AF_ANY }, 281 { "verbose", 0, setverboseflag, 0, AF_ANY }, 282 { NETMASK_CMD, NEXTARG, setifnetmask, 0, AF_INET }, 283 { "metric", NEXTARG, setifmetric, 0, AF_ANY }, 284 { "mtu", NEXTARG, setifmtu, 0, AF_ANY }, 285 { "index", NEXTARG, setifindex, 0, AF_ANY }, 286 { "broadcast", NEXTARG, setifbroadaddr, 0, AF_INET }, 287 { "auto-revarp", 0, setifrevarp, 1, AF_INET }, 288 { "plumb", 0, inetplumb, 1, AF_ANY }, 289 { "unplumb", 0, inetunplumb, 0, AF_ANY }, 290 { "subnet", NEXTARG, setifsubnet, 0, AF_ANY }, 291 { "token", NEXTARG, setiftoken, 0, AF_INET6 }, 292 { "tsrc", NEXTARG, setiftsrc, 0, AF_ANY }, 293 { "tdst", NEXTARG, setiftdst, 0, AF_ANY }, 294 { "encr_auth_algs", NEXTARG, set_tun_esp_auth_alg, 0, AF_ANY }, 295 { "encr_algs", NEXTARG, set_tun_esp_encr_alg, 0, AF_ANY }, 296 { "auth_algs", NEXTARG, set_tun_ah_alg, 0, AF_ANY }, 297 { "addif", NEXTARG, addif, 1, AF_ANY }, 298 { "removeif", NEXTARG, removeif, 1, AF_ANY }, 299 { "modlist", 0, modlist, 1, AF_ANY }, 300 { "modinsert", NEXTARG, modinsert, 1, AF_ANY }, 301 { "modremove", NEXTARG, modremove, 1, AF_ANY }, 302 { "failover", -IFF_NOFAILOVER, setifflags, 1, AF_ANY }, 303 { "-failover", IFF_NOFAILOVER, setifflags, 1, AF_ANY }, 304 { "standby", IFF_STANDBY, setifflags, 1, AF_ANY }, 305 { "-standby", -IFF_STANDBY, setifflags, 1, AF_ANY }, 306 { "failed", IFF_FAILED, setifflags, 1, AF_ANY }, 307 { "-failed", -IFF_FAILED, setifflags, 1, AF_ANY }, 308 { "group", NEXTARG, setifgroupname, 1, AF_ANY }, 309 { "configinfo", 0, configinfo, 1, AF_ANY }, 310 { "encaplimit", NEXTARG, set_tun_encap_limit, 0, 311 AF_ANY }, 312 { "-encaplimit", 0, clr_tun_encap_limit, 0, 313 AF_ANY }, 314 { "thoplimit", NEXTARG, set_tun_hop_limit, 0, 315 AF_ANY }, 316 #ifdef DEBUG 317 { "getnd", NEXTARG, getnd, 0, AF_INET6 }, 318 { "setnd", NEXTARG, setnd, 0, AF_INET6 }, 319 { "delnd", NEXTARG, delnd, 0, AF_INET6 }, 320 #endif 321 /* XXX for testing SIOCT* ioctls. Remove */ 322 { "set", NEXTARG, setifaddr, 0, AF_ANY }, 323 { "destination", NEXTARG, setifdstaddr, 0, AF_ANY }, 324 { "zone", NEXTARG, setzone, 0, AF_ANY }, 325 { "-zone", 0, setzone, 0, AF_ANY }, 326 { "ether", OPTARG, setifether, 0, AF_ANY }, 327 { "usesrc", NEXTARG, setifsrc, 0, AF_ANY }, 328 { 0, 0, setifaddr, 0, AF_ANY }, 329 { 0, 0, setifdstaddr, 0, AF_ANY }, 330 { 0, 0, 0, 0, 0 }, 331 }; 332 333 334 typedef struct if_config_cmd { 335 uint64_t iff_flag; 336 char *iff_name; 337 } if_config_cmd_t; 338 339 static if_config_cmd_t if_config_cmd_tbl[] = { 340 { IFF_UP, "up" }, 341 { IFF_NOTRAILERS, "-trailers" }, 342 { IFF_PRIVATE, "private" }, 343 { IFF_NOXMIT, "-xmit" }, 344 { IFF_ANYCAST, "anycast" }, 345 { IFF_NOLOCAL, "-local" }, 346 { IFF_DEPRECATED, "deprecated" }, 347 { IFF_NOFAILOVER, "-failover" }, 348 { IFF_STANDBY, "standby" }, 349 { IFF_FAILED, "failed" }, 350 { IFF_PREFERRED, "preferred" }, 351 { 0, 0 }, 352 }; 353 354 typedef struct ni { 355 char ni_name[LIFNAMSIZ]; 356 struct ni *ni_next; 357 } ni_t; 358 359 static ni_t *ni_list = NULL; 360 static int num_ni = 0; 361 362 /* End defines and structure definitions for ifconfig -a plumb */ 363 364 /* Known address families */ 365 struct afswtch { 366 char *af_name; 367 short af_af; 368 void (*af_status)(); 369 void (*af_getaddr)(); 370 void (*af_configinfo)(); 371 } afs[] = { 372 { "inet", AF_INET, in_status, in_getaddr, in_configinfo }, 373 { "inet6", AF_INET6, in6_status, in6_getaddr, in6_configinfo }, 374 { 0, 0, 0, 0, 0 } 375 }; 376 377 #define SOCKET_AF(af) (((af) == AF_UNSPEC) ? AF_INET : (af)) 378 379 struct afswtch *afp; /* the address family being set or asked about */ 380 381 int 382 main(int argc, char *argv[]) 383 { 384 /* Include IFF_NOXMIT, IFF_TEMPORARY and all zone interfaces */ 385 int64_t lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES; 386 char *default_ip_str; 387 388 if (argc < 2) { 389 usage(); 390 exit(1); 391 } 392 argc--, argv++; 393 if (strlen(*argv) > sizeof (name) - 1) { 394 (void) fprintf(stderr, "%s: interface name too long\n", *argv); 395 exit(1); 396 } 397 (void) strncpy(name, *argv, sizeof (name)); 398 name[sizeof (name) - 1] = '\0'; 399 (void) strncpy(origname, name, sizeof (origname)); /* For addif */ 400 euid = geteuid(); 401 default_ip_str = NULL; 402 v4compat = get_compat_flag(&default_ip_str); 403 if (v4compat == DEFAULT_PROT_BAD_VALUE) { 404 (void) fprintf(stderr, 405 "ifconfig: %s: Bad value for %s in %s\n", default_ip_str, 406 DEFAULT_IP, INET_DEFAULT_FILE); 407 free(default_ip_str); 408 exit(2); 409 } 410 free(default_ip_str); 411 argc--, argv++; 412 if (argc > 0) { 413 struct afswtch *myafp; 414 415 for (myafp = afp = afs; myafp->af_name; myafp++) { 416 if (strcmp(myafp->af_name, *argv) == 0) { 417 afp = myafp; argc--; argv++; 418 break; 419 } 420 } 421 af = lifr.lifr_addr.ss_family = afp->af_af; 422 if (af == AF_INET6) { 423 v4compat = 0; 424 } 425 } 426 427 s = socket(SOCKET_AF(af), SOCK_DGRAM, 0); 428 if (s < 0) { 429 Perror0_exit("socket"); 430 } 431 432 /* 433 * Special interface names is any combination of these flags. 434 * Note that due to the ifconfig syntax they have to be combined 435 * as a single '-' option. 436 * -a All interfaces 437 * -u "up" interfaces 438 * -d "down" interfaces 439 * -D Interfaces not controlled by DHCP 440 * -4 IPv4 interfaces 441 * -6 IPv6 interfaces 442 * -X Turn on debug (not documented) 443 * -v Turn on verbose 444 * -Z Only interfaces in caller's zone 445 */ 446 447 if (name[0] == '-') { 448 /* One or more options */ 449 int64_t onflags = 0; 450 int64_t offflags = 0; 451 int c; 452 char *av[2] = { "ifconfig", name }; 453 454 while ((c = getopt(2, av, "audDXZ46v")) != -1) { 455 switch ((char)c) { 456 case 'a': 457 all = 1; 458 break; 459 case 'u': 460 onflags |= IFF_UP; 461 break; 462 case 'd': 463 offflags |= IFF_UP; 464 break; 465 case 'D': 466 offflags |= IFF_DHCPRUNNING; 467 break; 468 case 'X': 469 debug += 3; 470 break; 471 case 'Z': 472 lifc_flags &= ~LIFC_ALLZONES; 473 break; 474 case '4': 475 /* 476 * -4 is not a compatable flag, therefore 477 * we assume they want v4compat turned off 478 */ 479 v4compat = 0; 480 onflags |= IFF_IPV4; 481 break; 482 case '6': 483 /* 484 * If they want IPv6, well then we'll assume 485 * they don't want IPv4 compat 486 */ 487 v4compat = 0; 488 onflags |= IFF_IPV6; 489 break; 490 case 'v': 491 verbose = 1; 492 break; 493 case '?': 494 usage(); 495 exit(1); 496 } 497 } 498 if (!all) { 499 (void) fprintf(stderr, 500 "ifconfig: %s: no such interface\n", 501 name); 502 exit(1); 503 } 504 foreachinterface(ifconfig, argc, argv, af, onflags, offflags, 505 lifc_flags); 506 } else { 507 ifconfig(argc, argv, af, (struct lifreq *)NULL); 508 } 509 return (0); 510 } 511 512 /* 513 * For each interface, call (*func)(argc, argv, af, lifrp). 514 * Only call function if onflags and offflags are set or clear, respectively, 515 * in the interfaces flags field. 516 */ 517 static void 518 foreachinterface(void (*func)(), int argc, char *argv[], int af, 519 int64_t onflags, int64_t offflags, int64_t lifc_flags) 520 { 521 int n; 522 char *buf; 523 struct lifnum lifn; 524 struct lifconf lifc; 525 struct lifreq *lifrp; 526 struct lifreq lifrl; /* Local lifreq struct */ 527 int numifs; 528 unsigned bufsize; 529 ni_t *nip; 530 int plumball = 0; 531 int save_af = af; 532 533 /* 534 * Special case: 535 * ifconfig -a plumb should find all network interfaces 536 * in the machine by traversing the devinfo tree. 537 * Also, there is no need to SIOCGLIF* ioctls, since 538 * those interfaces have already been plumbed 539 */ 540 if (argc > 0 && (strcmp(*argv, "plumb") == 0)) { 541 /* 542 * Look through the kernel's devinfo tree for 543 * network devices 544 */ 545 di_node_t root; 546 547 /* 548 * DINFOCACHE is equivalent to DINFOSUBTREE | DINFOMINOR | 549 * DINFOPROP | DINFOFORCE. 550 */ 551 if ((root = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 552 (void) fprintf(stderr, "ifconfig: di_init failed;" 553 " check the devinfo driver.\n"); 554 exit(1); 555 } 556 557 (void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, NULL, 558 devfs_entry); 559 di_fini(root); 560 561 /* 562 * Now, translate the linked list into 563 * a struct lifreq buffer 564 */ 565 bufsize = num_ni * sizeof (struct lifreq); 566 if ((buf = malloc(bufsize)) == NULL) 567 Perror0_exit("foreachinterface: malloc failed"); 568 569 lifc.lifc_family = AF_UNSPEC; 570 lifc.lifc_flags = lifc_flags; 571 lifc.lifc_len = bufsize; 572 lifc.lifc_buf = buf; 573 574 for (n = 0, lifrp = lifc.lifc_req; n < num_ni; n++, lifrp++) { 575 nip = ni_list; 576 (void) strncpy(lifrp->lifr_name, nip->ni_name, 577 sizeof (lifr.lifr_name)); 578 ni_list = nip->ni_next; 579 free(nip); 580 } 581 582 plumball = 1; 583 } else { 584 lifn.lifn_family = AF_UNSPEC; 585 lifn.lifn_flags = lifc_flags; 586 if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) { 587 Perror0_exit("Could not determine number" 588 " of interfaces"); 589 } 590 numifs = lifn.lifn_count; 591 if (debug) 592 (void) printf("ifconfig: %d interfaces\n", numifs); 593 594 bufsize = numifs * sizeof (struct lifreq); 595 if ((buf = malloc(bufsize)) == NULL) { 596 Perror0("out of memory\n"); 597 (void) close(s); 598 return; 599 } 600 601 lifc.lifc_family = AF_UNSPEC; 602 lifc.lifc_flags = lifc_flags; 603 lifc.lifc_len = bufsize; 604 lifc.lifc_buf = buf; 605 606 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { 607 Perror0("SIOCGLIFCONF"); 608 (void) close(s); 609 free(buf); 610 return; 611 } 612 } 613 614 lifrp = lifc.lifc_req; 615 for (n = lifc.lifc_len / sizeof (struct lifreq); n > 0; n--, lifrp++) { 616 617 if (!plumball) { 618 /* 619 * We must close and recreate the socket each time 620 * since we don't know what type of socket it is now 621 * (each status function may change it). 622 */ 623 624 (void) close(s); 625 626 af = lifrp->lifr_addr.ss_family; 627 s = socket(SOCKET_AF(af), SOCK_DGRAM, 0); 628 if (s == -1) { 629 /* 630 * Perror0() assumes the name to be in the 631 * globally defined lifreq structure. 632 */ 633 (void) strncpy(lifr.lifr_name, 634 lifrp->lifr_name, sizeof (lifr.lifr_name)); 635 Perror0_exit("socket"); 636 } 637 } 638 639 /* 640 * Only service interfaces that match the on and off 641 * flags masks. 642 */ 643 if (onflags || offflags) { 644 (void) memset(&lifrl, 0, sizeof (lifrl)); 645 (void) strncpy(lifrl.lifr_name, lifrp->lifr_name, 646 sizeof (lifrl.lifr_name)); 647 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) { 648 /* 649 * Perror0() assumes the name to be in the 650 * globally defined lifreq structure. 651 */ 652 (void) strncpy(lifr.lifr_name, 653 lifrp->lifr_name, sizeof (lifr.lifr_name)); 654 Perror0_exit("foreachinterface: SIOCGLIFFLAGS"); 655 } 656 if ((lifrl.lifr_flags & onflags) != onflags) 657 continue; 658 if ((~lifrl.lifr_flags & offflags) != offflags) 659 continue; 660 } 661 662 if (!plumball) { 663 (void) strncpy(lifrl.lifr_name, lifrp->lifr_name, 664 sizeof (lifrl.lifr_name)); 665 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifrl) < 0) { 666 /* 667 * Perror0() assumes the name to be in the 668 * globally defined lifreq structure. 669 */ 670 (void) strncpy(lifr.lifr_name, 671 lifrp->lifr_name, sizeof (lifr.lifr_name)); 672 Perror0("foreachinterface: SIOCGLIFADDR"); 673 continue; 674 } 675 if (lifrl.lifr_addr.ss_family != af) { 676 /* Switch address family */ 677 af = lifrl.lifr_addr.ss_family; 678 (void) close(s); 679 680 s = socket(SOCKET_AF(af), SOCK_DGRAM, 0); 681 if (s == -1) { 682 /* 683 * Perror0() assumes the name to be in 684 * the globally defined lifreq 685 * structure. 686 */ 687 (void) strncpy(lifr.lifr_name, 688 lifrp->lifr_name, 689 sizeof (lifr.lifr_name)); 690 Perror0_exit("socket"); 691 } 692 } 693 } 694 695 /* 696 * Reset global state 697 * setaddr: Used by parser to tear apart source and dest 698 * name and origname contain the name of the 'current' 699 * interface. 700 */ 701 setaddr = 0; 702 (void) strncpy(name, lifrp->lifr_name, sizeof (name)); 703 (void) strncpy(origname, name, sizeof (origname)); 704 705 if (partial) { 706 if (debug) 707 (void) fprintf(stderr, 708 "checking partial %s against %s\n", 709 partname, name); 710 if (strncmp(name, partname, strlen(partname))) 711 continue; 712 } 713 (*func)(argc, argv, save_af, lifrp); 714 /* the func could have overwritten origname, so restore */ 715 (void) strncpy(name, origname, sizeof (name)); 716 } 717 free(buf); 718 } 719 720 static void 721 tun_reality_check(void) 722 { 723 struct iftun_req treq; 724 ipsec_req_t *ipsr; 725 726 (void) strncpy(treq.ifta_lifr_name, name, sizeof (treq.ifta_lifr_name)); 727 if (strchr(name, ':') != NULL) { 728 /* Return, we don't need to check. */ 729 return; 730 } 731 if (ioctl(s, SIOCGTUNPARAM, (caddr_t)&treq) < 0 || 732 (treq.ifta_flags & IFTUN_SECURITY) == 0) { 733 /* 734 * Either not a tunnel (the SIOCGTUNPARAM fails on 735 * non-tunnels), or the security flag is not set. Either 736 * way, return. 737 */ 738 return; 739 } 740 741 ipsr = (ipsec_req_t *)&treq.ifta_secinfo; 742 743 if (ipsr->ipsr_esp_req != 0 && 744 ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE && 745 ipsr->ipsr_ah_req == 0) 746 (void) fprintf(stderr, "ifconfig: WARNING - tunnel with " 747 "only ESP and potentially no authentication.\n"); 748 } 749 750 /* 751 * for the specified interface call (*func)(argc, argv, af, lifrp). 752 */ 753 754 static void 755 ifconfig(int argc, char *argv[], int af, struct lifreq *lifrp) 756 { 757 static boolean_t scan_netmask = _B_FALSE; 758 int ret; 759 760 if (argc == 0) { 761 status(); 762 return; 763 } 764 765 if (strcmp(*argv, "auto-dhcp") == 0 || strcmp(*argv, "dhcp") == 0) { 766 if (af == AF_INET) { 767 768 /* 769 * some errors are ignored in the case where 770 * more than one interface is being operated on. 771 */ 772 ret = setifdhcp("ifconfig", name, argc, argv); 773 if (ret == DHCP_EXIT_IF_FAILURE) { 774 if (!all) 775 exit(DHCP_EXIT_FAILURE); 776 } else if (ret != DHCP_EXIT_SUCCESS) 777 exit(ret); 778 } else 779 (void) fprintf(stderr, "ifconfig: dhcp not supported " 780 "for inet6\n"); 781 return; 782 } 783 784 /* 785 * The following is a "hack" to get around the existing interface 786 * setting mechanism. Currently, each interface attribute, 787 * such as address, netmask, broadcast, ... is set separately. But 788 * sometimes two or more attributes must be set together. For 789 * example, setting an address without a netmask does not make sense. 790 * Yet they can be set separately for IPv4 address using the current 791 * ifconfig(1M) syntax. The kernel then "infers" the correct netmask 792 * using the deprecated "IP address classes." This is simply not 793 * correct. 794 * 795 * The "hack" below is to go thru the whole command list looking for 796 * the netmask command first. Then use this netmask to set the 797 * address. This does not provide an extensible way to accommodate 798 * future need for setting more than one attributes together. 799 * 800 * ifconfig(1M) is too overloaded and the code is so convoluted 801 * that it is "safer" not to re-architect the code to fix the above 802 * issue, hence this "hack." We may be better off to have a new 803 * command with better syntax for configuring network interface 804 * parameters... 805 */ 806 if (!scan_netmask && afp->af_af == AF_INET) { 807 int largc; 808 char **largv; 809 810 /* Only go thru the command list once to find the netmask. */ 811 scan_netmask = _B_TRUE; 812 813 /* 814 * Currently, if multiple netmask commands are specified, the 815 * last one will be used as the final netmask. So we need 816 * to scan the whole list to preserve this behavior. 817 */ 818 for (largc = argc, largv = argv; largc > 0; largc--, largv++) { 819 if (strcmp(*largv, NETMASK_CMD) == 0) { 820 if (--largc == 0) 821 break; 822 largv++; 823 if (strcmp(*largv, "+") == 0) { 824 if (in_getmask((struct sockaddr_in *) 825 &g_netmask)) { 826 g_netmask_set = _B_TRUE; 827 } 828 } else { 829 in_getaddr(*largv, (struct sockaddr *) 830 &g_netmask, NULL); 831 g_netmask_set = _B_TRUE; 832 } 833 /* Continue the scan. */ 834 } 835 } 836 } 837 838 while (argc > 0) { 839 struct cmd *p; 840 boolean_t found_cmd; 841 842 if (debug) 843 (void) printf("ifconfig: argv %s\n", *argv); 844 845 found_cmd = _B_FALSE; 846 for (p = cmds; p->c_func; p++) { 847 if (p->c_name) { 848 if (strcmp(*argv, p->c_name) == 0) { 849 /* 850 * indicate that the command was 851 * found and check to see if 852 * the address family is valid 853 */ 854 found_cmd = _B_TRUE; 855 if (p->c_af == AF_ANY || 856 af == p->c_af) 857 break; 858 } 859 } else { 860 if (p->c_af == AF_ANY || 861 af == p->c_af) 862 break; 863 } 864 } 865 /* 866 * If we found the keyword, but the address family 867 * did not match spit out an error 868 */ 869 if (found_cmd && p->c_name == 0) { 870 (void) fprintf(stderr, "ifconfig: Operation %s not" 871 " supported for %s\n", *argv, afp->af_name); 872 exit(1); 873 } 874 /* 875 * else (no keyword found), we assume it's an address 876 * of some sort 877 */ 878 if (p->c_name == 0 && setaddr) 879 p++; /* got src, do dst */ 880 if (p->c_func) { 881 if (p->c_af == AF_INET6) { 882 v4compat = 0; 883 } 884 if (p->c_parameter == NEXTARG || 885 p->c_parameter == OPTARG) { 886 argc--, argv++; 887 if (argc == 0 && p->c_parameter == NEXTARG) { 888 (void) fprintf(stderr, 889 "ifconfig: no argument for %s\n", 890 p->c_name); 891 exit(1); 892 } 893 } 894 /* 895 * Call the function if: 896 * 897 * there's no address family 898 * restriction 899 * OR 900 * we don't know the address yet 901 * (because we were called from 902 * main) 903 * OR 904 * there is a restriction AND 905 * the address families match 906 */ 907 if ((p->c_af == AF_ANY) || 908 (lifrp == (struct lifreq *)NULL) || 909 (lifrp->lifr_addr.ss_family == p->c_af)) { 910 ret = (*p->c_func)(*argv, p->c_parameter); 911 /* 912 * If c_func failed and we should 913 * abort processing for this 914 * interface on failure, return 915 * now rather than going on to 916 * process other commands for 917 * the same interface. 918 */ 919 if (ret != 0 && p->c_abortonfail) 920 return; 921 } 922 } 923 argc--, argv++; 924 } 925 926 /* Check to see if there's a security hole in the tunnel setup. */ 927 tun_reality_check(); 928 } 929 930 /* ARGSUSED */ 931 static int 932 setdebugflag(char *val, int64_t arg) 933 { 934 debug++; 935 return (0); 936 } 937 938 /* ARGSUSED */ 939 static int 940 setverboseflag(char *val, int64_t arg) 941 { 942 verbose++; 943 return (0); 944 } 945 946 /* 947 * Set the interface address. Handles <addr>, <addr>/<n> as well as /<n> 948 * syntax for setting the address, the address plus netmask, and just 949 * the netmask respectively. 950 */ 951 /* ARGSUSED */ 952 static int 953 setifaddr(char *addr, int64_t param) 954 { 955 int prefixlen = 0; 956 struct sockaddr_storage laddr; 957 struct sockaddr_storage netmask; 958 struct sockaddr_in6 *sin6; 959 struct sockaddr_in *sin; 960 struct sockaddr_storage sav_netmask; 961 962 if (addr[0] == '/') 963 return (setifprefixlen(addr, 0)); 964 965 (*afp->af_getaddr)(addr, (struct sockaddr *)&laddr, &prefixlen); 966 967 (void) memset(&netmask, 0, sizeof (netmask)); 968 netmask.ss_family = afp->af_af; 969 switch (prefixlen) { 970 case NO_PREFIX: 971 /* Nothing there - ok */ 972 break; 973 case BAD_ADDR: 974 (void) fprintf(stderr, "ifconfig: Bad prefix length in %s\n", 975 addr); 976 exit(1); 977 default: 978 if (afp->af_af == AF_INET6) { 979 sin6 = (struct sockaddr_in6 *)&netmask; 980 if (!in_prefixlentomask(prefixlen, ADDRBITS_V6, 981 (uchar_t *)&sin6->sin6_addr)) { 982 (void) fprintf(stderr, "ifconfig: " 983 "Bad prefix length: %d\n", 984 prefixlen); 985 exit(1); 986 } 987 } else { 988 sin = (struct sockaddr_in *)&netmask; 989 if (!in_prefixlentomask(prefixlen, ADDRBITS_V4, 990 (uchar_t *)&sin->sin_addr)) { 991 (void) fprintf(stderr, "ifconfig: " 992 "Bad prefix length: %d\n", 993 prefixlen); 994 exit(1); 995 } 996 } 997 /* 998 * Just in case of funny setting of both prefix and netmask, 999 * prefix should override the netmask command. 1000 */ 1001 g_netmask_set = _B_FALSE; 1002 break; 1003 } 1004 /* Tell parser that an address was set */ 1005 setaddr++; 1006 /* save copy of netmask to restore in case of error */ 1007 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1008 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) 1009 Perror0_exit("SIOCGLIFNETMASK"); 1010 sav_netmask = lifr.lifr_addr; 1011 1012 /* 1013 * Catch set of address for AF_INET6 to perform 1014 * duplicate address detection. Check that the interface is 1015 * up. 1016 */ 1017 if (afp->af_af == AF_INET6) { 1018 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 1019 Perror0_exit("ifsetaddr: SIOCGLIFFLAGS"); 1020 } 1021 if (lifr.lifr_flags & IFF_UP) { 1022 if (debug) 1023 (void) printf( 1024 "setifaddr: Calling ifdad flags %llx\n", 1025 lifr.lifr_flags); 1026 if (ifdad(name, (struct sockaddr_in6 *)&laddr) == -1) 1027 exit(3); 1028 } 1029 } 1030 1031 /* 1032 * If setting the address and not the mask, clear any existing mask 1033 * and the kernel will then assign the default (netmask has been set 1034 * to 0 in this case). If setting both (either by using a prefix or 1035 * using the netmask command), set the mask first, so the address will 1036 * be interpreted correctly. 1037 */ 1038 lifr.lifr_addr = g_netmask_set ? g_netmask : netmask; 1039 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 1040 Perror0_exit("SIOCSLIFNETMASK"); 1041 1042 if (debug) { 1043 char abuf[INET6_ADDRSTRLEN]; 1044 void *addr = (afp->af_af == AF_INET) ? 1045 (void *)&((struct sockaddr_in *)&laddr)->sin_addr : 1046 (void *)&((struct sockaddr_in6 *)&laddr)->sin6_addr; 1047 1048 (void) printf("Setting %s af %d addr %s\n", 1049 lifr.lifr_name, afp->af_af, 1050 inet_ntop(afp->af_af, addr, abuf, sizeof (abuf))); 1051 } 1052 lifr.lifr_addr = laddr; 1053 lifr.lifr_addr.ss_family = afp->af_af; 1054 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) { 1055 /* 1056 * Restore the netmask 1057 */ 1058 int saverr = errno; 1059 1060 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1061 lifr.lifr_addr = sav_netmask; 1062 (void) ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr); 1063 errno = saverr; 1064 Perror0_exit("SIOCSLIFADDR"); 1065 } 1066 1067 return (0); 1068 } 1069 1070 /* 1071 * The following functions are stolen from the ipseckey(1m) program. 1072 * Perhaps they should be somewhere common, but for now, we just maintain 1073 * two versions. We do this because of the different semantics for which 1074 * algorithms we select ("requested" for ifconfig vs. "actual" for key). 1075 */ 1076 1077 static ulong_t 1078 parsenum(char *num) 1079 { 1080 ulong_t rc; 1081 char *end = NULL; 1082 1083 errno = 0; 1084 rc = strtoul(num, &end, 0); 1085 if (errno != 0 || end == num || *end != '\0') { 1086 rc = (ulong_t)-1; 1087 } 1088 1089 return (rc); 1090 } 1091 1092 /* 1093 * Parse and reverse parse possible algorithm values, include numbers. 1094 * Mostly stolen from ipseckey.c. See the comments above parsenum() for why 1095 * this isn't common to ipseckey.c. 1096 * 1097 * NOTE: Static buffer in this function for the return value. Since ifconfig 1098 * isn't multithreaded, this isn't a huge problem. 1099 */ 1100 1101 #define NBUF_SIZE 20 /* Enough to print a large integer. */ 1102 1103 static char * 1104 rparsealg(uint8_t alg_value, int proto_num) 1105 { 1106 struct ipsecalgent *alg; 1107 static char numprint[128]; /* Enough to hold an algorithm name. */ 1108 1109 /* Special-case 0 to return "<any-none>" */ 1110 if (alg_value == 0) 1111 return ("<any-none>"); 1112 1113 alg = getipsecalgbynum(alg_value, proto_num, NULL); 1114 if (alg != NULL) { 1115 (void) strlcpy(numprint, alg->a_names[0], sizeof (numprint)); 1116 freeipsecalgent(alg); 1117 } else { 1118 (void) snprintf(numprint, sizeof (numprint), "%d", alg_value); 1119 } 1120 1121 return (numprint); 1122 } 1123 1124 static uint_t 1125 parsealg(char *algname, int proto_num) 1126 { 1127 struct ipsecalgent *alg; 1128 ulong_t invalue; 1129 1130 if (algname == NULL) { 1131 (void) fprintf(stderr, "ifconfig: Unexpected end of command " 1132 "line.\n"); 1133 exit(1); 1134 } 1135 1136 /* 1137 * Special-case "none". Use strcasecmp because its length is 1138 * bound. 1139 */ 1140 if (strcasecmp("none", algname) == 0) { 1141 return ((proto_num == IPSEC_PROTO_ESP) ? 1142 NO_ESP_EALG : NO_ESP_AALG); 1143 } 1144 1145 alg = getipsecalgbyname(algname, proto_num, NULL); 1146 if (alg != NULL) { 1147 invalue = alg->a_alg_num; 1148 freeipsecalgent(alg); 1149 return ((uint_t)invalue); 1150 } 1151 1152 /* 1153 * Since algorithms can be loaded during kernel run-time, check for 1154 * numeric algorithm values too. 1155 */ 1156 invalue = parsenum(algname); 1157 if ((invalue & (ulong_t)0xff) == invalue) 1158 return ((uint_t)invalue); 1159 1160 (void) fprintf(stderr, "ifconfig: %s algorithm type %s unknown.\n", 1161 (proto_num == IPSEC_PROTO_ESP) ? 1162 "Encryption" : "Authentication", algname); 1163 exit(1); 1164 /* NOTREACHED */ 1165 } 1166 1167 /* 1168 * Actual ifconfig functions to set tunnel security properties. 1169 */ 1170 1171 enum ipsec_alg_type { ESP_ENCR_ALG = 1, ESP_AUTH_ALG, AH_AUTH_ALG }; 1172 1173 boolean_t first_set_tun = _B_TRUE; 1174 boolean_t encr_alg_set = _B_FALSE; 1175 1176 static int 1177 set_tun_algs(int which_alg, int alg) 1178 { 1179 struct iftun_req treq; 1180 ipsec_req_t *ipsr; 1181 1182 (void) strncpy(treq.ifta_lifr_name, name, sizeof (treq.ifta_lifr_name)); 1183 if (strchr(name, ':') != NULL) { 1184 errno = EPERM; 1185 Perror0_exit("Tunnel params on logical interfaces"); 1186 } 1187 if (ioctl(s, SIOCGTUNPARAM, (caddr_t)&treq) < 0) { 1188 if (errno == EOPNOTSUPP || errno == EINVAL) 1189 Perror0_exit("Not a tunnel"); 1190 else Perror0_exit("SIOCGTUNPARAM"); 1191 } 1192 1193 ipsr = (ipsec_req_t *)&treq.ifta_secinfo; 1194 1195 if (treq.ifta_vers != IFTUN_VERSION) { 1196 (void) fprintf(stderr, 1197 "Kernel tunnel secinfo version mismatch.\n"); 1198 exit(1); 1199 } 1200 1201 /* 1202 * If I'm just starting off this ifconfig, I want a clean slate, 1203 * otherwise, I've captured the current tunnel security settings. 1204 * In the case of continuation, I merely add to the settings. 1205 */ 1206 if (first_set_tun) { 1207 first_set_tun = _B_FALSE; 1208 (void) memset(ipsr, 0, sizeof (*ipsr)); 1209 } 1210 1211 treq.ifta_flags = IFTUN_SECURITY; 1212 1213 switch (which_alg) { 1214 case ESP_ENCR_ALG: 1215 if (alg == NO_ESP_EALG) { 1216 if (ipsr->ipsr_esp_auth_alg == SADB_AALG_NONE) 1217 ipsr->ipsr_esp_req = 0; 1218 ipsr->ipsr_esp_alg = SADB_EALG_NONE; 1219 } else { 1220 encr_alg_set = _B_TRUE; 1221 ipsr->ipsr_esp_req = 1222 IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE; 1223 ipsr->ipsr_esp_alg = alg; 1224 } 1225 break; 1226 case ESP_AUTH_ALG: 1227 if (alg == NO_ESP_AALG) { 1228 if (ipsr->ipsr_esp_alg == SADB_EALG_NONE || 1229 ipsr->ipsr_esp_alg == SADB_EALG_NULL) 1230 ipsr->ipsr_esp_req = 0; 1231 ipsr->ipsr_esp_auth_alg = SADB_AALG_NONE; 1232 } else { 1233 ipsr->ipsr_esp_req = 1234 IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE; 1235 ipsr->ipsr_esp_auth_alg = alg; 1236 1237 /* Let the user specify NULL encryption implicitly. */ 1238 if (ipsr->ipsr_esp_alg == SADB_EALG_NONE && 1239 !encr_alg_set) 1240 ipsr->ipsr_esp_alg = SADB_EALG_NULL; 1241 } 1242 break; 1243 case AH_AUTH_ALG: 1244 if (alg == NO_AH_AALG) { 1245 ipsr->ipsr_ah_req = 0; 1246 ipsr->ipsr_auth_alg = SADB_AALG_NONE; 1247 } else { 1248 ipsr->ipsr_ah_req = 1249 IPSEC_PREF_REQUIRED | IPSEC_PREF_UNIQUE; 1250 ipsr->ipsr_auth_alg = alg; 1251 } 1252 break; 1253 /* Will never hit DEFAULT */ 1254 } 1255 1256 if (ioctl(s, SIOCSTUNPARAM, (caddr_t)&treq) < 0) { 1257 Perror2_exit("set tunnel security properties", 1258 treq.ifta_lifr_name); 1259 } 1260 1261 return (0); 1262 } 1263 1264 /* ARGSUSED */ 1265 static int 1266 set_tun_esp_encr_alg(char *addr, int64_t param) 1267 { 1268 return (set_tun_algs(ESP_ENCR_ALG, 1269 parsealg(addr, IPSEC_PROTO_ESP))); 1270 } 1271 1272 /* ARGSUSED */ 1273 static int 1274 set_tun_esp_auth_alg(char *addr, int64_t param) 1275 { 1276 return (set_tun_algs(ESP_AUTH_ALG, 1277 parsealg(addr, IPSEC_PROTO_AH))); 1278 } 1279 1280 /* ARGSUSED */ 1281 static int 1282 set_tun_ah_alg(char *addr, int64_t param) 1283 { 1284 return (set_tun_algs(AH_AUTH_ALG, 1285 parsealg(addr, IPSEC_PROTO_AH))); 1286 } 1287 1288 /* ARGSUSED */ 1289 static int 1290 setifrevarp(char *arg, int64_t param) 1291 { 1292 struct sockaddr_in laddr; 1293 1294 if (afp->af_af == AF_INET6) { 1295 (void) fprintf(stderr, 1296 "ifconfig: revarp not possible on IPv6 interface %s\n", 1297 name); 1298 exit(1); 1299 } 1300 if (doifrevarp(name, &laddr)) { 1301 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1302 laddr.sin_family = AF_INET; 1303 (void) memcpy(&lifr.lifr_addr, &laddr, sizeof (laddr)); 1304 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 1305 Perror0_exit("SIOCSLIFADDR"); 1306 } 1307 return (0); 1308 } 1309 1310 /* ARGSUSED */ 1311 static int 1312 setifsubnet(char *addr, int64_t param) 1313 { 1314 int prefixlen = 0; 1315 struct sockaddr_storage subnet; 1316 1317 (*afp->af_getaddr)(addr, &subnet, &prefixlen); 1318 1319 switch (prefixlen) { 1320 case NO_PREFIX: 1321 (void) fprintf(stderr, 1322 "ifconfig: Missing prefix length in subnet %s\n", addr); 1323 exit(1); 1324 /* NOTREACHED */ 1325 case BAD_ADDR: 1326 (void) fprintf(stderr, 1327 "ifconfig: Bad prefix length in %s\n", addr); 1328 exit(1); 1329 default: 1330 break; 1331 } 1332 1333 lifr.lifr_addr = subnet; 1334 lifr.lifr_addrlen = prefixlen; 1335 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1336 if (ioctl(s, SIOCSLIFSUBNET, (caddr_t)&lifr) < 0) 1337 Perror0_exit("SIOCSLIFSUBNET"); 1338 1339 return (0); 1340 } 1341 1342 /* ARGSUSED */ 1343 static int 1344 setifnetmask(char *addr, int64_t param) 1345 { 1346 struct sockaddr_in netmask; 1347 1348 assert(afp->af_af != AF_INET6); 1349 1350 if (strcmp(addr, "+") == 0) { 1351 if (in_getmask(&netmask) == 0) 1352 return (0); 1353 } else { 1354 in_getaddr(addr, (struct sockaddr *)&netmask, NULL); 1355 } 1356 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1357 (void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask)); 1358 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 1359 Perror0_exit("SIOCSLIFNETMASK"); 1360 return (0); 1361 } 1362 1363 /* 1364 * Parse '/<n>' as a netmask. 1365 */ 1366 /* ARGSUSED */ 1367 static int 1368 setifprefixlen(char *addr, int64_t param) 1369 { 1370 int prefixlen; 1371 int af = afp->af_af; 1372 1373 prefixlen = in_getprefixlen(addr, _B_TRUE, 1374 (af == AF_INET) ? ADDRBITS_V4 : ADDRBITS_V6); 1375 if (prefixlen < 0) { 1376 (void) fprintf(stderr, 1377 "ifconfig: Bad prefix length in %s\n", addr); 1378 exit(1); 1379 } 1380 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 1381 lifr.lifr_addr.ss_family = af; 1382 if (af == AF_INET6) { 1383 struct sockaddr_in6 *sin6; 1384 1385 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 1386 if (!in_prefixlentomask(prefixlen, ADDRBITS_V6, 1387 (uchar_t *)&sin6->sin6_addr)) { 1388 (void) fprintf(stderr, "ifconfig: " 1389 "Bad prefix length: %d\n", 1390 prefixlen); 1391 exit(1); 1392 } 1393 } else if (af == AF_INET) { 1394 struct sockaddr_in *sin; 1395 1396 sin = (struct sockaddr_in *)&lifr.lifr_addr; 1397 if (!in_prefixlentomask(prefixlen, ADDRBITS_V4, 1398 (uchar_t *)&sin->sin_addr)) { 1399 (void) fprintf(stderr, "ifconfig: " 1400 "Bad prefix length: %d\n", 1401 prefixlen); 1402 exit(1); 1403 } 1404 } else { 1405 (void) fprintf(stderr, "ifconfig: setting prefix only supported" 1406 " for address family inet or inet6\n"); 1407 exit(1); 1408 } 1409 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1410 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 1411 Perror0_exit("SIOCSLIFNETMASK"); 1412 return (0); 1413 } 1414 1415 /* ARGSUSED */ 1416 static int 1417 setifbroadaddr(char *addr, int64_t param) 1418 { 1419 struct sockaddr_in broadaddr; 1420 1421 assert(afp->af_af != AF_INET6); 1422 1423 if (strcmp(addr, "+") == 0) { 1424 /* 1425 * This doesn't set the broadcast address at all. Rather, it 1426 * gets, then sets the interface's address, relying on the fact 1427 * that resetting the address will reset the broadcast address. 1428 */ 1429 (void) strncpy(lifr.lifr_name, name, 1430 sizeof (lifr.lifr_name)); 1431 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 1432 if (errno != EADDRNOTAVAIL) 1433 Perror0_exit("SIOCGLIFADDR"); 1434 return (0); 1435 } 1436 if (ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 1437 Perror0_exit("SIOCGLIFADDR"); 1438 1439 return (0); 1440 } 1441 in_getaddr(addr, (struct sockaddr *)&broadaddr, NULL); 1442 1443 (void) memcpy(&lifr.lifr_addr, &broadaddr, sizeof (broadaddr)); 1444 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1445 if (ioctl(s, SIOCSLIFBRDADDR, (caddr_t)&lifr) < 0) 1446 Perror0_exit("SIOCSLIFBRDADDR"); 1447 return (0); 1448 } 1449 1450 /* 1451 * set interface destination address 1452 */ 1453 /* ARGSUSED */ 1454 static int 1455 setifdstaddr(char *addr, int64_t param) 1456 { 1457 (*afp->af_getaddr)(addr, (struct sockaddr *)&lifr.lifr_addr, NULL); 1458 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1459 if (ioctl(s, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) 1460 Perror0_exit("setifdstaddr: SIOCSLIFDSTADDR"); 1461 return (0); 1462 } 1463 1464 /* ARGSUSED */ 1465 static int 1466 setifflags(char *val, int64_t value) 1467 { 1468 int phyintlen, origphyintlen; 1469 1470 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1471 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) 1472 Perror0_exit("setifflags: SIOCGLIFFLAGS"); 1473 1474 if (value == IFF_NOFAILOVER) { 1475 /* 1476 * Fail if '-failover' is set after a prior addif created the 1477 * alias on a different interface. This can happen when the 1478 * interface is part of an IPMP group. 1479 */ 1480 phyintlen = strcspn(name, ":"); 1481 origphyintlen = strcspn(origname, ":"); 1482 if (phyintlen != origphyintlen || 1483 strncmp(name, origname, phyintlen) != 0) { 1484 (void) fprintf(stderr, "ifconfig: can't set -failover " 1485 "on failed/standby/offlined interface %s\n", 1486 origname); 1487 exit(1); 1488 } 1489 } 1490 1491 /* 1492 * Catch "up" transition for AF_INET6 to perform duplicate address 1493 * detection. ifdad checks if an address has been set. 1494 */ 1495 if (afp->af_af == AF_INET6 && !(lifr.lifr_flags & IFF_UP) && 1496 value == IFF_UP) { 1497 if (debug) 1498 (void) printf( 1499 "setifaddr:Calling ifdad flags %llx value 0x%llx\n", 1500 lifr.lifr_flags, value); 1501 if (ifdad(name, NULL) == -1) 1502 exit(1); 1503 } 1504 1505 if (value < 0) { 1506 value = -value; 1507 lifr.lifr_flags &= ~value; 1508 } else 1509 lifr.lifr_flags |= value; 1510 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1511 if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) { 1512 Perror0_exit("setifflags: SIOCSLIFFLAGS"); 1513 } 1514 return (0); 1515 } 1516 1517 /* ARGSUSED */ 1518 static int 1519 setifmetric(char *val, int64_t param) 1520 { 1521 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1522 lifr.lifr_metric = atoi(val); 1523 if (ioctl(s, SIOCSLIFMETRIC, (caddr_t)&lifr) < 0) 1524 Perror0_exit("setifmetric: SIOCSLIFMETRIC"); 1525 return (0); 1526 } 1527 1528 /* ARGSUSED */ 1529 static int 1530 setifmtu(char *val, int64_t param) 1531 { 1532 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1533 lifr.lifr_mtu = atoi(val); 1534 if (ioctl(s, SIOCSLIFMTU, (caddr_t)&lifr) < 0) 1535 Perror0_exit("setifmtu: SIOCSLIFMTU"); 1536 return (0); 1537 } 1538 1539 /* ARGSUSED */ 1540 static int 1541 setifindex(char *val, int64_t param) 1542 { 1543 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1544 lifr.lifr_index = atoi(val); 1545 if (ioctl(s, SIOCSLIFINDEX, (caddr_t)&lifr) < 0) 1546 Perror0_exit("setifindex: SIOCSLIFINDEX"); 1547 return (0); 1548 } 1549 1550 /* ARGSUSED */ 1551 static int 1552 setifether(char *addr, int64_t param) 1553 { 1554 uchar_t *ea; 1555 iface_t *current; 1556 int maclen; 1557 1558 if (addr == NULL) { 1559 ifstatus(name); 1560 print_ifether(name); 1561 return (0); 1562 } 1563 1564 phyif = NULL; 1565 logifs = NULL; 1566 1567 /* 1568 * if the IP interface in the arguments is a logical 1569 * interface, exit with an error now. 1570 */ 1571 if (strchr(name, ':') != NULL) { 1572 (void) fprintf(stderr, "ifconfig: cannot change" 1573 " ethernet address of a logical interface\n"); 1574 exit(1); 1575 } 1576 1577 ea = _link_aton(addr, &maclen); 1578 if (ea == NULL) { 1579 if (maclen == -1) 1580 (void) fprintf(stderr, 1581 "ifconfig: %s: bad address\n", addr); 1582 else 1583 (void) fprintf(stderr, "ifconfig: malloc() failed\n"); 1584 exit(1); 1585 } 1586 1587 (void) strncpy(savedname, name, sizeof (savedname)); 1588 1589 /* 1590 * Call selectifs only for the IP interfaces that are ipv4. 1591 * offflags == IFF_IPV6 because you should not change the 1592 * Ethernet address of an ipv6 interface 1593 */ 1594 foreachinterface(selectifs, 0, (char **)NULL, 0, 0, IFF_IPV6, 0); 1595 1596 /* If physical interface not found, exit now */ 1597 if (phyif == NULL) { 1598 (void) fprintf(stderr, 1599 "ifconfig: interface %s not found\n", savedname); 1600 exit(1); 1601 } 1602 1603 /* Restore */ 1604 (void) strncpy(name, savedname, sizeof (name)); 1605 (void) strncpy(origname, savedname, sizeof (origname)); 1606 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1607 1608 /* 1609 * close and reopen the socket 1610 * we don't know which type of socket we have now 1611 */ 1612 (void) close(s); 1613 s = socket(SOCKET_AF(AF_UNSPEC), SOCK_DGRAM, 0); 1614 if (s < 0) { 1615 Perror0_exit("socket"); 1616 } 1617 1618 /* 1619 * mark down the logical interfaces first, 1620 * and then the physical interface 1621 */ 1622 if (updownifs(logifs, 0) < 0 || updownifs(phyif, 0) < 0) { 1623 Perror0_exit("mark down interface failed"); 1624 } 1625 1626 /* 1627 * Change the physical address 1628 */ 1629 if (dlpi_set_address(savedname, ea, maclen) == -1) { 1630 (void) fprintf(stderr, 1631 "ifconfig: failed setting mac address on %s\n", 1632 savedname); 1633 } 1634 1635 /* 1636 * if any interfaces were marked down before changing the 1637 * ethernet address, put them up again. 1638 * First the physical interface, then the logical ones. 1639 */ 1640 if (updownifs(phyif, 1) < 0 || updownifs(logifs, 1) < 0) { 1641 Perror0_exit("mark down interface failed"); 1642 } 1643 1644 /* Free the memory allocated by selectifs */ 1645 free(phyif); 1646 for (current = logifs; current != NULL; current = logifs) { 1647 logifs = logifs->next; 1648 free(current); 1649 } 1650 1651 return (0); 1652 } 1653 1654 /* 1655 * Print an interface's Ethernet address, if it has one. 1656 */ 1657 static void 1658 print_ifether(char *ifname) 1659 { 1660 int protocol; 1661 icfg_if_t interface; 1662 icfg_handle_t handle; 1663 int fd; 1664 1665 /* 1666 * Loopback interfaces and tunnels can't have MAC addresses, 1667 * so filter them out first. 1668 */ 1669 if (strcmp(ifname, LOOPBACK_IF) == 0) 1670 return; 1671 1672 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1673 1674 fd = socket(AF_INET, SOCK_DGRAM, 0); 1675 if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1676 /* 1677 * It's possible the interface is only configured for 1678 * IPv6; check again with AF_INET6. 1679 */ 1680 (void) close(fd); 1681 fd = socket(AF_INET6, SOCK_DGRAM, 0); 1682 if (fd == -1 || ioctl(fd, SIOCGLIFFLAGS, &lifr) == -1) { 1683 (void) close(fd); 1684 return; 1685 } 1686 } 1687 (void) close(fd); 1688 1689 /* Virtual interfaces don't have MAC addresses */ 1690 if (lifr.lifr_flags & IFF_VIRTUAL) 1691 return; 1692 1693 /* 1694 * We must be careful to set if_protocol based on the current 1695 * properties of the interface. For instance, if "ip.tun0" is 1696 * configured only as an IPv6 tunnel, then if_protocol must be 1697 * set to AF_INET6 or icfg_get_tunnel_lower() will fail and 1698 * we will falsely conclude that it's not a tunnel. 1699 */ 1700 interface.if_protocol = AF_INET; 1701 if (lifr.lifr_flags & IFF_IPV6) 1702 interface.if_protocol = AF_INET6; 1703 1704 (void) strncpy(interface.if_name, ifname, sizeof (interface.if_name)); 1705 1706 if (icfg_open(&handle, &interface) == ICFG_SUCCESS) { 1707 if (icfg_get_tunnel_lower(handle, &protocol) == ICFG_SUCCESS) { 1708 /* Tunnel op succeeded -- it's a tunnel so skip */ 1709 icfg_close(handle); 1710 return; 1711 } 1712 icfg_close(handle); 1713 } 1714 1715 dlpi_print_address(ifname); 1716 } 1717 1718 /* 1719 * static void selectifs(int argc, char *argv[], int af, struct lifreq *rp) 1720 * 1721 * Called inside setifether() to create a list of interfaces to 1722 * mark down/up when changing the Ethernet address. 1723 * If the current interface is the physical interface passed 1724 * as an argument to ifconfig, update phyif. 1725 * If the current interface is a logical interface associated 1726 * to the physical interface, add it to the logifs list. 1727 */ 1728 /* ARGSUSED */ 1729 static void 1730 selectifs(int argc, char *argv[], int af, struct lifreq *rp) 1731 { 1732 char *colonp; 1733 int length; 1734 iface_t *current; 1735 1736 /* 1737 * savedname= name of the IP interface to which you want to 1738 * change ethernet address 1739 * name= name of the current IP interface 1740 */ 1741 colonp = strchr(name, ':'); 1742 if (colonp == NULL) 1743 length = max(strlen(savedname), strlen(name)); 1744 else 1745 length = max(strlen(savedname), colonp - name); 1746 if (strncmp(savedname, name, length) == 0) { 1747 (void) strcpy(lifr.lifr_name, name); 1748 if (ioctl(s, SIOCGLIFFLAGS, &lifr) < 0) { 1749 Perror0("selectifs: SIOCGLIFFLAGS"); 1750 return; 1751 } 1752 1753 if ((current = malloc(sizeof (iface_t))) == NULL) { 1754 Perror0_exit("selectifs: malloc failed\n"); 1755 } 1756 1757 if (colonp == NULL) { 1758 /* this is the physical interface */ 1759 phyif = current; 1760 bcopy(&lifr, &phyif->lifr, sizeof (struct lifreq)); 1761 phyif->next = NULL; 1762 } else { 1763 /* this is a logical interface */ 1764 bcopy(&lifr, ¤t->lifr, sizeof (struct lifreq)); 1765 current->next = logifs; 1766 logifs = current; 1767 } 1768 } 1769 } 1770 1771 /* 1772 * static int updownifs(iface_t *ifs, int up) 1773 * 1774 * It takes in input a list of IP interfaces (ifs) 1775 * and a flag (up). 1776 * It marks each interface in the list down (up = 0) 1777 * or up (up > 0). This is done ONLY if the IP 1778 * interface was originally up. 1779 * 1780 * Return values: 1781 * 0 = everything OK 1782 * -1 = problem 1783 */ 1784 static int 1785 updownifs(iface_t *ifs, int up) 1786 { 1787 iface_t *current; 1788 int ret = 0; 1789 int save_errno; 1790 char savename[LIFNAMSIZ]; 1791 uint64_t orig_flags; 1792 1793 for (current = ifs; current != NULL; current = current->next) { 1794 if (current->lifr.lifr_flags & IFF_UP) { 1795 orig_flags = current->lifr.lifr_flags; 1796 if (!up) 1797 current->lifr.lifr_flags &= ~IFF_UP; 1798 if (ioctl(s, SIOCSLIFFLAGS, ¤t->lifr) < 0) { 1799 save_errno = errno; 1800 (void) strcpy(savename, 1801 current->lifr.lifr_name); 1802 ret = -1; 1803 } 1804 if (!up) /* restore the original flags */ 1805 current->lifr.lifr_flags = orig_flags; 1806 } 1807 } 1808 1809 if (ret == -1) { 1810 (void) strcpy(lifr.lifr_name, savename); 1811 errno = save_errno; 1812 } 1813 return (ret); 1814 } 1815 1816 /* 1817 * Create the next unused logical interface using the original name 1818 * and assign the address (and mask if '/<n>' is part of the address). 1819 * Use the new logical interface for subsequent subcommands by updating 1820 * the name variable. 1821 * 1822 * This allows syntax like: 1823 * ifconfig le0 addif 109.106.86.130 netmask + up \ 1824 * addif 109.106.86.131 netmask + up 1825 */ 1826 /* ARGSUSED */ 1827 static int 1828 addif(char *str, int64_t param) 1829 { 1830 int prefixlen = 0; 1831 struct sockaddr_storage laddr; 1832 struct sockaddr_storage mask; 1833 1834 (void) strncpy(name, origname, sizeof (name)); 1835 1836 if (strchr(name, ':') != NULL) { 1837 (void) fprintf(stderr, 1838 "ifconfig: addif: bad physical interface name %s\n", 1839 name); 1840 exit(1); 1841 } 1842 1843 /* 1844 * clear so parser will interpret next address as source followed 1845 * by possible dest 1846 */ 1847 setaddr = 0; 1848 (*afp->af_getaddr)(str, (struct sockaddr *)&laddr, &prefixlen); 1849 1850 switch (prefixlen) { 1851 case NO_PREFIX: 1852 /* Nothing there - ok */ 1853 break; 1854 case BAD_ADDR: 1855 (void) fprintf(stderr, 1856 "ifconfig: Bad prefix length in %s\n", str); 1857 exit(1); 1858 default: 1859 (void) memset(&mask, 0, sizeof (mask)); 1860 mask.ss_family = afp->af_af; 1861 if (afp->af_af == AF_INET6) { 1862 struct sockaddr_in6 *sin6; 1863 sin6 = (struct sockaddr_in6 *)&mask; 1864 if (!in_prefixlentomask(prefixlen, ADDRBITS_V6, 1865 (uchar_t *)&sin6->sin6_addr)) { 1866 (void) fprintf(stderr, "ifconfig: " 1867 "Bad prefix length: %d\n", 1868 prefixlen); 1869 exit(1); 1870 } 1871 } else { 1872 struct sockaddr_in *sin; 1873 1874 sin = (struct sockaddr_in *)&mask; 1875 if (!in_prefixlentomask(prefixlen, ADDRBITS_V4, 1876 (uchar_t *)&sin->sin_addr)) { 1877 (void) fprintf(stderr, "ifconfig: " 1878 "Bad prefix length: %d\n", 1879 prefixlen); 1880 exit(1); 1881 } 1882 } 1883 break; 1884 } 1885 1886 /* Set the address and then the mask (if there was one) */ 1887 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1888 lifr.lifr_addr = laddr; 1889 1890 /* Note: no need to do DAD here since the interface isn't up yet. */ 1891 1892 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) 1893 Perror0_exit("addif: SIOCLIFADDIF"); 1894 1895 (void) printf("Created new logical interface %s\n", 1896 lifr.lifr_name); 1897 (void) strncpy(name, lifr.lifr_name, sizeof (name)); 1898 1899 if (prefixlen >= 0) { 1900 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1901 lifr.lifr_addr = mask; 1902 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 1903 Perror0_exit("addif: SIOCSLIFNETMASK"); 1904 } 1905 /* 1906 * let parser know we got a source. 1907 * Next address, if given, should be dest 1908 */ 1909 setaddr++; 1910 return (0); 1911 } 1912 1913 /* 1914 * Remove a logical interface based on its IP address. Unlike addif 1915 * there is no '/<n>' here. 1916 * Verifies that the interface is down before it is removed. 1917 */ 1918 /* ARGSUSED */ 1919 static int 1920 removeif(char *str, int64_t param) 1921 { 1922 struct sockaddr_storage laddr; 1923 1924 if (strchr(name, ':') != NULL) { 1925 (void) fprintf(stderr, 1926 "ifconfig: removeif: bad physical interface name %s\n", 1927 name); 1928 exit(1); 1929 } 1930 1931 (*afp->af_getaddr)(str, &laddr, NULL); 1932 lifr.lifr_addr = laddr; 1933 1934 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 1935 if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { 1936 if (errno == EBUSY) { 1937 /* This can only happen if ipif_id = 0 */ 1938 (void) fprintf(stderr, 1939 "ifconfig: removeif: can't remove interface: %s\n", 1940 name); 1941 exit(1); 1942 } 1943 Perror0_exit("removeif: SIOCLIFREMOVEIF"); 1944 } 1945 return (0); 1946 } 1947 1948 /* 1949 * If laddr is non-NULL it is used - otherwise we use the address on 1950 * the interface. 1951 */ 1952 /* ARGSUSED */ 1953 static int 1954 ifdad(char *ifname, struct sockaddr_in6 *laddr) 1955 { 1956 struct sockaddr_in6 testaddr; 1957 struct lifreq lifr2; /* Avoid overriting lifr */ 1958 1959 if (debug) 1960 (void) printf("ifdad(%s)\n", ifname); 1961 1962 assert(afp->af_af == AF_INET6); 1963 1964 /* 1965 * Check the address assigned to the interface. 1966 * Skip the check if IFF_NOLOCAL, IFF_NONUD, IFF_ANYCAST, or 1967 * IFF_LOOPBACK. 1968 * Note that IFF_NONUD turns of both NUD and DAD. 1969 */ 1970 (void) strncpy(lifr2.lifr_name, ifname, 1971 sizeof (lifr2.lifr_name)); 1972 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr2) < 0) { 1973 Perror0_exit("ifdad: SIOCGLIFFLAGS"); 1974 } 1975 if (lifr2.lifr_flags & (IFF_NOLOCAL|IFF_LOOPBACK|IFF_NONUD|IFF_ANYCAST)) 1976 return (0); 1977 1978 if (laddr != NULL) { 1979 testaddr = *laddr; 1980 } else { 1981 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr2) < 0) { 1982 Perror0_exit("ifdad: SIOCGLIFADDR"); 1983 } 1984 testaddr = *(struct sockaddr_in6 *)&lifr2.lifr_addr; 1985 } 1986 1987 if (IN6_IS_ADDR_UNSPECIFIED(&testaddr.sin6_addr)) 1988 return (0); 1989 1990 if (do_dad(name, &testaddr) != 0) 1991 return (-1); 1992 else 1993 return (0); 1994 } 1995 1996 /* 1997 * Set the address token for IPv6. 1998 */ 1999 /* ARGSUSED */ 2000 static int 2001 setiftoken(char *addr, int64_t param) 2002 { 2003 int prefixlen = 0; 2004 struct sockaddr_in6 token; 2005 2006 in6_getaddr(addr, (struct sockaddr *)&token, &prefixlen); 2007 switch (prefixlen) { 2008 case NO_PREFIX: 2009 (void) fprintf(stderr, 2010 "ifconfig: Missing prefix length in subnet %s\n", addr); 2011 exit(1); 2012 /* NOTREACHED */ 2013 case BAD_ADDR: 2014 (void) fprintf(stderr, 2015 "ifconfig: Bad prefix length in %s\n", addr); 2016 exit(1); 2017 default: 2018 break; 2019 } 2020 (void) memcpy(&lifr.lifr_addr, &token, sizeof (token)); 2021 lifr.lifr_addrlen = prefixlen; 2022 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2023 if (ioctl(s, SIOCSLIFTOKEN, (caddr_t)&lifr) < 0) { 2024 Perror0_exit("setiftoken: SIOCSLIFTOKEN"); 2025 } 2026 return (0); 2027 } 2028 2029 /* 2030 * Return value: 0 on success, -1 on failure. 2031 */ 2032 static int 2033 connect_to_mpathd(int family) 2034 { 2035 int s; 2036 struct sockaddr_storage ss; 2037 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 2038 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 2039 struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT; 2040 int addrlen; 2041 int ret; 2042 int on; 2043 2044 s = socket(family, SOCK_STREAM, 0); 2045 if (s < 0) { 2046 Perror0_exit("connect_to_mpathd: socket"); 2047 } 2048 (void) bzero((char *)&ss, sizeof (ss)); 2049 ss.ss_family = family; 2050 /* 2051 * Need to bind to a privileged port. For non-root, this 2052 * will fail. in.mpathd verifies that only commands coming 2053 * from privileged ports succeed so that ordinary users 2054 * can't connect and start talking to in.mpathd 2055 */ 2056 on = 1; 2057 if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on, 2058 sizeof (on)) < 0) { 2059 Perror0_exit("connect_to_mpathd: setsockopt"); 2060 } 2061 switch (family) { 2062 case AF_INET: 2063 sin->sin_port = 0; 2064 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 2065 addrlen = sizeof (struct sockaddr_in); 2066 break; 2067 case AF_INET6: 2068 sin6->sin6_port = 0; 2069 sin6->sin6_addr = loopback_addr; 2070 addrlen = sizeof (struct sockaddr_in6); 2071 break; 2072 } 2073 ret = bind(s, (struct sockaddr *)&ss, addrlen); 2074 if (ret != 0) { 2075 (void) close(s); 2076 return (-1); 2077 } 2078 2079 switch (family) { 2080 case AF_INET: 2081 sin->sin_port = htons(MPATHD_PORT); 2082 break; 2083 case AF_INET6: 2084 sin6->sin6_port = htons(MPATHD_PORT); 2085 break; 2086 } 2087 ret = connect(s, (struct sockaddr *)&ss, addrlen); 2088 (void) close(s); 2089 return (ret); 2090 } 2091 2092 /* ARGSUSED */ 2093 static int 2094 setifgroupname(char *grpname, int64_t param) 2095 { 2096 if (debug) { 2097 (void) printf("Setting groupname %s on interface %s\n", 2098 grpname, name); 2099 } 2100 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2101 (void) strncpy(lifr.lifr_groupname, grpname, 2102 sizeof (lifr.lifr_groupname)); 2103 if (ioctl(s, SIOCSLIFGROUPNAME, (caddr_t)&lifr) < 0) { 2104 Perror0_exit("setifgroupname: SIOCSLIFGROUPNAME"); 2105 } 2106 2107 /* 2108 * If the SUNW_NO_MPATHD environment variable is set then don't 2109 * bother starting up in.mpathd. See PSARC/2002/249 for the 2110 * depressing details on this bit of stupidity. 2111 */ 2112 if (getenv("SUNW_NO_MPATHD") != NULL) { 2113 return (0); 2114 } 2115 2116 /* 2117 * Try to connect to in.mpathd using IPv4. If we succeed, 2118 * we conclude that in.mpathd is running, and quit. 2119 */ 2120 if (connect_to_mpathd(AF_INET) == 0) { 2121 /* connect succeeded, mpathd is already running */ 2122 return (0); 2123 } 2124 /* 2125 * Try to connect to in.mpathd using IPv6. If we succeed, 2126 * we conclude that in.mpathd is running, and quit. 2127 */ 2128 if (connect_to_mpathd(AF_INET6) == 0) { 2129 /* connect succeeded, mpathd is already running */ 2130 return (0); 2131 } 2132 2133 /* 2134 * in.mpathd may not be running. Start it now. If it is already 2135 * running, in.mpathd will take care of handling multiple incarnations 2136 * of itself. ifconfig only tries to optimize performance by not 2137 * starting another incarnation of in.mpathd. 2138 */ 2139 switch (fork()) { 2140 2141 case -1: 2142 Perror0_exit("setifgroupname: fork"); 2143 /* NOTREACHED */ 2144 case 0: 2145 (void) execl(MPATHD_PATH, MPATHD_PATH, NULL); 2146 _exit(1); 2147 /* NOTREACHED */ 2148 default: 2149 return (0); 2150 } 2151 } 2152 2153 2154 /* 2155 * To list all the modules above a given network interface. 2156 */ 2157 /* ARGSUSED */ 2158 static int 2159 modlist(char *null, int64_t param) 2160 { 2161 int muxfd; 2162 int ipfd_lowstr; 2163 int arpfd_lowstr; 2164 int num_mods; 2165 int i; 2166 struct str_list strlist; 2167 int orig_arpid; 2168 2169 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2170 if (ip_domux2fd(&muxfd, &ipfd_lowstr, &arpfd_lowstr, 2171 &orig_arpid) < 0) { 2172 return (-1); 2173 } 2174 if ((num_mods = ioctl(ipfd_lowstr, I_LIST, NULL)) < 0) { 2175 Perror0("cannot I_LIST to get the number of modules"); 2176 } else { 2177 if (debug > 0) { 2178 (void) printf("Listing (%d) modules above %s\n", 2179 num_mods, name); 2180 } 2181 2182 strlist.sl_nmods = num_mods; 2183 strlist.sl_modlist = malloc(sizeof (struct str_mlist) * 2184 num_mods); 2185 if (strlist.sl_modlist == NULL) { 2186 Perror0("cannot malloc"); 2187 } else { 2188 if (ioctl(ipfd_lowstr, I_LIST, (caddr_t)&strlist) < 0) { 2189 Perror0("cannot I_LIST for module names"); 2190 } else { 2191 for (i = 0; i < strlist.sl_nmods; i++) { 2192 (void) printf("%d %s\n", i, 2193 strlist.sl_modlist[i].l_name); 2194 } 2195 } 2196 free(strlist.sl_modlist); 2197 } 2198 } 2199 return (ip_plink(muxfd, ipfd_lowstr, arpfd_lowstr, orig_arpid)); 2200 } 2201 2202 #define MODINSERT_OP 'i' 2203 #define MODREMOVE_OP 'r' 2204 2205 /* 2206 * To insert a module to the stream of the interface. It is just a 2207 * wrapper. The real function is modop(). 2208 */ 2209 /* ARGSUSED */ 2210 static int 2211 modinsert(char *arg, int64_t param) 2212 { 2213 return (modop(arg, MODINSERT_OP)); 2214 } 2215 2216 /* 2217 * To remove a module from the stream of the interface. It is just a 2218 * wrapper. The real function is modop(). 2219 */ 2220 /* ARGSUSED */ 2221 static int 2222 modremove(char *arg, int64_t param) 2223 { 2224 return (modop(arg, MODREMOVE_OP)); 2225 } 2226 2227 /* 2228 * Open a stream on /dev/udp, pop off all undesired modules (note that 2229 * the user may have configured autopush to add modules above or below 2230 * udp), and push the arp module onto raw IP. 2231 */ 2232 static int 2233 open_arp_on_udp(char *udp_dev_name) 2234 { 2235 int fd; 2236 boolean_t popped; 2237 2238 if ((fd = open(udp_dev_name, O_RDWR)) == -1) { 2239 Perror2("open", udp_dev_name); 2240 return (-1); 2241 } 2242 errno = 0; 2243 popped = _B_FALSE; 2244 while (ioctl(fd, I_POP, 0) != -1) 2245 popped = _B_TRUE; 2246 if (!popped) { 2247 Perror2("cannot pop", udp_dev_name); 2248 } else if (errno != EINVAL) { 2249 Perror2("pop", udp_dev_name); 2250 } else if (ioctl(fd, I_PUSH, ARP_MOD_NAME) == -1) { 2251 Perror2("arp PUSH", udp_dev_name); 2252 } else { 2253 return (fd); 2254 } 2255 (void) close(fd); 2256 return (-1); 2257 } 2258 2259 /* 2260 * Helper function for mod*() functions. It gets a fd to the lower IP 2261 * stream and I_PUNLINK's the lower stream. It also initializes the 2262 * global variable lifr. 2263 * 2264 * Param: 2265 * int *udp_fd: (referenced) fd to /dev/udp (upper IP stream). 2266 * int *fd: (referenced) fd to the lower IP stream. 2267 * 2268 * Return: 2269 * -1 if operation fails, 0 otherwise. 2270 * 2271 * Please see the big block comment above plumb_one_device() 2272 * for the logic of the PLINK/PUNLINK 2273 */ 2274 static int 2275 ip_domux2fd(int *muxfd, int *ipfd_lowstr, int *arpfd_lowstr, int *orig_arpid) 2276 { 2277 int ip_fd; 2278 uint64_t flags; 2279 char *udp_dev_name; 2280 char *ip_dev_name; 2281 2282 *orig_arpid = 0; 2283 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2284 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2285 Perror0_exit("status: SIOCGLIFFLAGS"); 2286 } 2287 flags = lifr.lifr_flags; 2288 if (flags & IFF_IPV4) { 2289 udp_dev_name = UDP_DEV_NAME; 2290 ip_dev_name = IP_DEV_NAME; 2291 } else if (flags & IFF_IPV6) { 2292 udp_dev_name = UDP6_DEV_NAME; 2293 ip_dev_name = IP6_DEV_NAME; 2294 } else { 2295 return (-1); 2296 } 2297 2298 if ((ip_fd = open(ip_dev_name, O_RDWR)) < 0) { 2299 Perror2("open", ip_dev_name); 2300 return (-1); 2301 } 2302 if (ioctl(ip_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 2303 Perror2("SIOCGLIFMUXID", ip_dev_name); 2304 return (-1); 2305 } 2306 if (debug > 0) { 2307 (void) printf("ARP_muxid %d IP_muxid %d\n", 2308 lifr.lifr_arp_muxid, lifr.lifr_ip_muxid); 2309 } 2310 2311 if ((*muxfd = open_arp_on_udp(udp_dev_name)) == -1) 2312 return (-1); 2313 2314 if (lifr.lifr_arp_muxid != 0) { 2315 if ((*arpfd_lowstr = ioctl(*muxfd, _I_MUXID2FD, 2316 lifr.lifr_arp_muxid)) < 0) { 2317 if ((errno == EINVAL) && 2318 (flags & (IFF_NOARP | IFF_IPV6))) { 2319 /* 2320 * Some plumbing utilities set the muxid to 2321 * -1 or some invalid value to signify that 2322 * there is no arp stream. Set the muxid to 0 2323 * before trying to unplumb the IP stream. 2324 * IP does not allow the IP stream to be 2325 * unplumbed if it sees a non-null arp muxid, 2326 * for consistency of IP-ARP streams. 2327 */ 2328 *orig_arpid = lifr.lifr_arp_muxid; 2329 lifr.lifr_arp_muxid = 0; 2330 (void) ioctl(*muxfd, SIOCSLIFMUXID, 2331 (caddr_t)&lifr); 2332 *arpfd_lowstr = -1; 2333 } else { 2334 Perror0("_I_MUXID2FD"); 2335 return (-1); 2336 } 2337 } else if (ioctl(*muxfd, I_PUNLINK, 2338 lifr.lifr_arp_muxid) < 0) { 2339 Perror2("I_PUNLINK", udp_dev_name); 2340 return (-1); 2341 } 2342 } else { 2343 *arpfd_lowstr = -1; 2344 } 2345 2346 if ((*ipfd_lowstr = ioctl(*muxfd, _I_MUXID2FD, 2347 lifr.lifr_ip_muxid)) < 0) { 2348 Perror0("_I_MUXID2FD"); 2349 /* Undo any changes we made */ 2350 if (*orig_arpid != 0) { 2351 lifr.lifr_arp_muxid = *orig_arpid; 2352 (void) ioctl(*muxfd, SIOCSLIFMUXID, (caddr_t)&lifr); 2353 } 2354 return (-1); 2355 } 2356 if (ioctl(*muxfd, I_PUNLINK, lifr.lifr_ip_muxid) < 0) { 2357 Perror2("I_PUNLINK", udp_dev_name); 2358 /* Undo any changes we made */ 2359 if (*orig_arpid != 0) { 2360 lifr.lifr_arp_muxid = *orig_arpid; 2361 (void) ioctl(*muxfd, SIOCSLIFMUXID, (caddr_t)&lifr); 2362 } 2363 return (-1); 2364 } 2365 return (0); 2366 } 2367 2368 /* 2369 * Helper function for mod*() functions. It I_PLINK's back the upper and 2370 * lower IP streams. Note that this function must be called after 2371 * ip_domux2fd(). In ip_domux2fd(), the global variable lifr is initialized 2372 * and ip_plink() needs information in lifr. So ip_domux2fd() and ip_plink() 2373 * must be called in pairs. 2374 * 2375 * Param: 2376 * int udp_fd: fd to /dev/udp (upper IP stream). 2377 * int fd: fd to the lower IP stream. 2378 * 2379 * Return: 2380 * -1 if operation fails, 0 otherwise. 2381 * 2382 * Please see the big block comment above plumb_one_device() 2383 * for the logic of the PLINK/PUNLINK 2384 */ 2385 static int 2386 ip_plink(int muxfd, int ipfd_lowstr, int arpfd_lowstr, int orig_arpid) 2387 { 2388 int ip_muxid; 2389 2390 ip_muxid = ioctl(muxfd, I_PLINK, ipfd_lowstr); 2391 if (ip_muxid < 0) { 2392 Perror2("I_PLINK", UDP_DEV_NAME); 2393 return (-1); 2394 } 2395 2396 /* 2397 * If there is an arp stream, plink it. If there is no 2398 * arp stream, then it is possible that the plumbing 2399 * utility could have stored any value in the arp_muxid. 2400 * If so, restore it from orig_arpid. 2401 */ 2402 if (arpfd_lowstr != -1) { 2403 if (ioctl(muxfd, I_PLINK, arpfd_lowstr) < 0) { 2404 Perror2("I_PLINK", UDP_DEV_NAME); 2405 return (-1); 2406 } 2407 } else if (orig_arpid != 0) { 2408 /* Undo the changes we did in ip_domux2fd */ 2409 lifr.lifr_arp_muxid = orig_arpid; 2410 lifr.lifr_ip_muxid = ip_muxid; 2411 (void) ioctl(muxfd, SIOCSLIFMUXID, (caddr_t)&lifr); 2412 } 2413 2414 return (0); 2415 } 2416 2417 2418 /* 2419 * The names of other core TCP/IP stack modules which cannot be removed. 2420 */ 2421 #ifndef TUN_NAME 2422 #define TUN_NAME "tun" 2423 #endif 2424 2425 #ifndef ATUN_NAME 2426 #define ATUN_NAME "atun" 2427 #endif 2428 2429 #ifndef TUN6TO4_NAME 2430 #define TUN6TO4_NAME "6to4tun" 2431 #endif 2432 2433 /* 2434 * The real function to perform module insertion/removal. 2435 * 2436 * Param: 2437 * char *arg: the argument string module_name@position 2438 * char op: operation, either MODINSERT_OP or MODREMOVE_OP. 2439 * 2440 * Return: 2441 * Before doing ip_domux2fd(), this function calls exit(1) in case of 2442 * error. After ip_domux2fd() is done, it returns -1 for error, 0 2443 * otherwise. 2444 */ 2445 static int 2446 modop(char *arg, char op) 2447 { 2448 char *pos_p; 2449 int muxfd; 2450 int ipfd_lowstr; /* IP stream (lower stream of mux) to be plinked */ 2451 int arpfd_lowstr; /* ARP stream (lower stream of mux) to be plinked */ 2452 struct strmodconf mod; 2453 char *at_char = "@"; 2454 char *arg_str; 2455 int orig_arpid; 2456 2457 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2458 2459 /* Need to save the original string for -a option. */ 2460 if ((arg_str = malloc(strlen(arg) + 1)) == NULL) { 2461 Perror0("cannot malloc"); 2462 return (-1); 2463 } 2464 (void) strcpy(arg_str, arg); 2465 2466 if (*arg_str == *at_char) { 2467 (void) fprintf(stderr, 2468 "ifconfig: must supply a module name\n"); 2469 exit(1); 2470 } 2471 mod.mod_name = strtok(arg_str, at_char); 2472 if (strlen(mod.mod_name) > FMNAMESZ) { 2473 (void) fprintf(stderr, "ifconfig: module name too long: %s\n", 2474 mod.mod_name); 2475 exit(1); 2476 } 2477 2478 /* 2479 * Need to make sure that the core TCP/IP stack modules are not 2480 * removed. Otherwise, "bad" things can happen. If a module 2481 * is removed and inserted back, it loses its old state. But 2482 * the modules above it still have the old state. E.g. IP assumes 2483 * fast data path while tunnel after re-inserted assumes that it can 2484 * receive M_DATA only in fast data path for which it does not have 2485 * any state. This is a general caveat of _I_REMOVE/_I_INSERT. 2486 */ 2487 if (op == MODREMOVE_OP && 2488 (strcmp(mod.mod_name, ARP_MOD_NAME) == 0 || 2489 strcmp(mod.mod_name, IP_MOD_NAME) == 0 || 2490 strcmp(mod.mod_name, TUN_NAME) == 0 || 2491 strcmp(mod.mod_name, ATUN_NAME) == 0 || 2492 strcmp(mod.mod_name, TUN6TO4_NAME) == 0)) { 2493 (void) fprintf(stderr, "ifconfig: cannot remove %s\n", 2494 mod.mod_name); 2495 exit(1); 2496 } 2497 2498 if ((pos_p = strtok(NULL, at_char)) == NULL) { 2499 (void) fprintf(stderr, "ifconfig: must supply a position\n"); 2500 exit(1); 2501 } 2502 mod.pos = atoi(pos_p); 2503 2504 if (ip_domux2fd(&muxfd, &ipfd_lowstr, &arpfd_lowstr, 2505 &orig_arpid) < 0) { 2506 free(arg_str); 2507 return (-1); 2508 } 2509 switch (op) { 2510 case MODINSERT_OP: 2511 if (debug > 0) { 2512 (void) printf("Inserting module %s at %d\n", 2513 mod.mod_name, mod.pos); 2514 } 2515 if (ioctl(ipfd_lowstr, _I_INSERT, (caddr_t)&mod) < 0) { 2516 Perror2("fail to insert module", mod.mod_name); 2517 } 2518 break; 2519 case MODREMOVE_OP: 2520 if (debug > 0) { 2521 (void) printf("Removing module %s at %d\n", 2522 mod.mod_name, mod.pos); 2523 } 2524 if (ioctl(ipfd_lowstr, _I_REMOVE, (caddr_t)&mod) < 0) { 2525 Perror2("fail to remove module", mod.mod_name); 2526 } 2527 break; 2528 default: 2529 /* Should never get to here. */ 2530 (void) fprintf(stderr, "Unknown operation\n"); 2531 break; 2532 } 2533 free(arg_str); 2534 return (ip_plink(muxfd, ipfd_lowstr, arpfd_lowstr, orig_arpid)); 2535 } 2536 2537 #ifdef DEBUG 2538 2539 /* ARGSUSED */ 2540 static int 2541 getnd(char *addr, int64_t param) 2542 { 2543 struct sockaddr_in6 v6addr; 2544 char *str = NULL; 2545 2546 in6_getaddr(addr, &v6addr, NULL); 2547 (void) memcpy(&lifr.lifr_nd.lnr_addr, &v6addr, sizeof (v6addr)); 2548 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2549 if (ioctl(s, SIOCLIFGETND, (caddr_t)&lifr) < 0) { 2550 Perror0_exit("SIOCLIFGETND"); 2551 } 2552 str = _link_ntoa((const unsigned char *)lifr.lifr_nd.lnr_hdw_addr, 2553 str, lifr.lifr_nd.lnr_hdw_len, IFT_OTHER); 2554 if (str != NULL) { 2555 (void) printf("address %s", str); 2556 free(str); 2557 } 2558 (void) printf(" state %d/%d/%d flags %x\n", 2559 lifr.lifr_nd.lnr_state_create, 2560 lifr.lifr_nd.lnr_state_same_lla, 2561 lifr.lifr_nd.lnr_state_diff_lla, 2562 lifr.lifr_nd.lnr_flags); 2563 return (0); 2564 } 2565 2566 /* ARGSUSED */ 2567 static int 2568 delnd(char *addr, int64_t param) 2569 { 2570 struct sockaddr_in6 v6addr; 2571 2572 in6_getaddr(addr, &v6addr, NULL); 2573 (void) memcpy(&lifr.lifr_nd.lnr_addr, &v6addr, sizeof (v6addr)); 2574 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2575 2576 lifr.lifr_nd.lnr_state_create = ND_UNCHANGED; 2577 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 2578 lifr.lifr_nd.lnr_state_diff_lla = ND_UNCHANGED; 2579 lifr.lifr_nd.lnr_flags = 0; 2580 if (ioctl(s, SIOCLIFDELND, (caddr_t)&lifr) < 0) { 2581 Perror0_exit("SIOCLIFDELND"); 2582 } 2583 return (0); 2584 } 2585 2586 /* ARGSUSED */ 2587 static int 2588 setnd(char *addr, int64_t param) 2589 { 2590 struct sockaddr_in6 v6addr; 2591 2592 /* 2593 * XXX parse phyaddr? Need syntax to fit in one argv. 2594 * XXX <proto addr>/<phyaddr> ?? 2595 */ 2596 in6_getaddr(addr, &v6addr, NULL); 2597 (void) memcpy(&lifr.lifr_nd.lnr_addr, &v6addr, sizeof (v6addr)); 2598 (void) memset(lifr.lifr_nd.lnr_hdw_addr, 0x55, 2599 sizeof (lifr.lifr_nd.lnr_hdw_addr)); 2600 lifr.lifr_nd.lnr_hdw_len = 6; 2601 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2602 2603 lifr.lifr_nd.lnr_state_create = ND_STALE; 2604 lifr.lifr_nd.lnr_state_same_lla = ND_UNCHANGED; 2605 lifr.lifr_nd.lnr_state_diff_lla = ND_STALE; 2606 lifr.lifr_nd.lnr_flags = 0; 2607 2608 if (ioctl(s, SIOCLIFSETND, (caddr_t)&lifr) < 0) { 2609 Perror0_exit("SIOCLIFSETND"); 2610 } 2611 return (0); 2612 } 2613 #endif /* DEBUG */ 2614 2615 /* 2616 * Set tunnel source address 2617 */ 2618 /* ARGSUSED */ 2619 static int 2620 setiftsrc(char *addr, int64_t param) 2621 { 2622 return (settaddr(addr, icfg_set_tunnel_src)); 2623 } 2624 2625 /* 2626 * Set tunnel destination address 2627 */ 2628 /* ARGSUSED */ 2629 static int 2630 setiftdst(char *addr, int64_t param) 2631 { 2632 return (settaddr(addr, icfg_set_tunnel_dest)); 2633 } 2634 2635 /* 2636 * sets tunnels src|dst address. settaddr() expects the following: 2637 * addr: Points to a printable string containing the address to be 2638 * set, e.g. 129.153.128.110. 2639 * fn: Pointer to a libinetcfg routine that will do the actual work. 2640 * The only valid functions are icfg_set_tunnel_src and 2641 * icfg_set_tunnel_dest. 2642 */ 2643 static int 2644 settaddr(char *addr, 2645 int (*fn)(icfg_handle_t, const struct sockaddr *, socklen_t)) 2646 { 2647 icfg_handle_t handle; 2648 icfg_if_t interface; 2649 struct sockaddr_storage laddr; 2650 int lower; 2651 int rc; 2652 2653 if (strchr(name, ':') != NULL) { 2654 errno = EPERM; 2655 Perror0_exit("Tunnel params on logical interfaces"); 2656 } 2657 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2658 interface.if_protocol = SOCKET_AF(af); 2659 2660 /* Open interface. */ 2661 if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS) 2662 Perror0_exit((char *)icfg_errmsg(rc)); 2663 2664 rc = icfg_get_tunnel_lower(handle, &lower); 2665 if (rc != ICFG_SUCCESS) 2666 Perror0_exit((char *)icfg_errmsg(rc)); 2667 2668 if (lower == AF_INET) { 2669 in_getaddr(addr, (struct sockaddr *)&laddr, NULL); 2670 } else { 2671 in6_getaddr(addr, (struct sockaddr *)&laddr, NULL); 2672 } 2673 2674 /* Call fn to do the real work, and close the interface. */ 2675 rc = (*fn)(handle, (struct sockaddr *)&laddr, 2676 sizeof (struct sockaddr_storage)); 2677 icfg_close(handle); 2678 2679 if (rc != ICFG_SUCCESS) 2680 Perror0_exit((char *)icfg_errmsg(rc)); 2681 2682 return (0); 2683 } 2684 2685 /* Set tunnel encapsulation limit. */ 2686 /* ARGSUSED */ 2687 static int 2688 set_tun_encap_limit(char *arg, int64_t param) 2689 { 2690 short limit; 2691 icfg_if_t interface; 2692 icfg_handle_t handle; 2693 int rc; 2694 2695 if (strchr(name, ':') != NULL) { 2696 errno = EPERM; 2697 Perror0_exit("Tunnel params on logical interfaces"); 2698 } 2699 2700 if ((sscanf(arg, "%hd", &limit) != 1) || (limit < 0) || 2701 (limit > 255)) { 2702 errno = EINVAL; 2703 Perror0_exit("Invalid encapsulation limit"); 2704 } 2705 2706 /* Open interface for configuration. */ 2707 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2708 interface.if_protocol = SOCKET_AF(af); 2709 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2710 Perror0_exit("couldn't open interface"); 2711 2712 rc = icfg_set_tunnel_encaplimit(handle, (int)limit); 2713 icfg_close(handle); 2714 2715 if (rc != ICFG_SUCCESS) 2716 Perror0_exit("Could not configure tunnel encapsulation limit"); 2717 2718 return (0); 2719 } 2720 2721 /* Disable encapsulation limit. */ 2722 /* ARGSUSED */ 2723 static int 2724 clr_tun_encap_limit(char *arg, int64_t param) 2725 { 2726 icfg_if_t interface; 2727 icfg_handle_t handle; 2728 int rc; 2729 2730 if (strchr(name, ':') != NULL) { 2731 errno = EPERM; 2732 Perror0_exit("Tunnel params on logical interfaces"); 2733 } 2734 2735 /* Open interface for configuration. */ 2736 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2737 interface.if_protocol = SOCKET_AF(af); 2738 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2739 Perror0_exit("couldn't open interface"); 2740 2741 rc = icfg_set_tunnel_encaplimit(handle, -1); 2742 icfg_close(handle); 2743 2744 if (rc != ICFG_SUCCESS) 2745 Perror0_exit((char *)icfg_errmsg(rc)); 2746 2747 return (0); 2748 } 2749 2750 /* Set tunnel hop limit. */ 2751 /* ARGSUSED */ 2752 static int 2753 set_tun_hop_limit(char *arg, int64_t param) 2754 { 2755 unsigned short limit; 2756 icfg_if_t interface; 2757 icfg_handle_t handle; 2758 int rc; 2759 2760 if (strchr(name, ':') != NULL) { 2761 errno = EPERM; 2762 Perror0_exit("Tunnel params on logical interfaces"); 2763 } 2764 2765 /* 2766 * Check limit here since it's really only an 8-bit unsigned quantity. 2767 */ 2768 if ((sscanf(arg, "%hu", &limit) != 1) || (limit > 255)) { 2769 errno = EINVAL; 2770 Perror0_exit("Invalid hop limit"); 2771 } 2772 2773 /* Open interface for configuration. */ 2774 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 2775 interface.if_protocol = SOCKET_AF(af); 2776 if (icfg_open(&handle, &interface) != ICFG_SUCCESS) 2777 Perror0_exit("couldn't open interface"); 2778 2779 rc = icfg_set_tunnel_hoplimit(handle, (uint8_t)limit); 2780 icfg_close(handle); 2781 2782 if (rc != ICFG_SUCCESS) 2783 Perror0_exit("Could not configure tunnel hop limit"); 2784 2785 return (0); 2786 } 2787 2788 /* Set zone ID */ 2789 static int 2790 setzone(char *arg, int64_t param) 2791 { 2792 zoneid_t zoneid = GLOBAL_ZONEID; 2793 2794 if (param == NEXTARG) { 2795 /* zone must be active */ 2796 if ((zoneid = getzoneidbyname(arg)) == -1) { 2797 (void) fprintf(stderr, 2798 "ifconfig: unknown zone '%s'\n", arg); 2799 exit(1); 2800 } 2801 } 2802 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2803 lifr.lifr_zoneid = zoneid; 2804 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) == -1) 2805 Perror0_exit("SIOCSLIFZONE"); 2806 return (0); 2807 } 2808 2809 /* Set source address to use */ 2810 /* ARGSUSED */ 2811 static int 2812 setifsrc(char *arg, int64_t param) 2813 { 2814 uint_t ifindex = 0; 2815 int rval; 2816 2817 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2818 2819 /* 2820 * Argument can be either an interface name or "none". The latter means 2821 * that any previous selection is cleared. 2822 */ 2823 2824 rval = strcmp(arg, name); 2825 if (rval == 0) { 2826 (void) fprintf(stderr, 2827 "ifconfig: Cannot specify same interface for usesrc" 2828 " group\n"); 2829 exit(1); 2830 } 2831 2832 rval = strcmp(arg, NONE_STR); 2833 if (rval != 0) { 2834 if ((ifindex = if_nametoindex(arg)) == 0) { 2835 (void) strncpy(lifr.lifr_name, arg, LIFNAMSIZ); 2836 Perror0_exit("Could not get interface index"); 2837 } 2838 lifr.lifr_index = ifindex; 2839 } else { 2840 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) != 0) 2841 Perror0_exit("Not a valid usesrc consumer"); 2842 lifr.lifr_index = 0; 2843 } 2844 2845 if (debug) 2846 (void) printf("setifsrc: lifr_name %s, lifr_index %d\n", 2847 lifr.lifr_name, lifr.lifr_index); 2848 2849 if (ioctl(s, SIOCSLIFUSESRC, (caddr_t)&lifr) == -1) { 2850 if (rval == 0) 2851 Perror0_exit("Cannot reset usesrc group"); 2852 else 2853 Perror0_exit("Could not set source interface"); 2854 } 2855 2856 return (0); 2857 } 2858 2859 /* 2860 * Print the interface status line associated with `ifname' 2861 */ 2862 static void 2863 ifstatus(const char *ifname) 2864 { 2865 uint64_t flags; 2866 char if_usesrc_name[LIFNAMSIZ]; 2867 char *newbuf; 2868 int n, numifs, rval = 0; 2869 struct lifreq *lifrp; 2870 struct lifsrcof lifs; 2871 2872 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2873 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2874 Perror0_exit("status: SIOCGLIFFLAGS"); 2875 } 2876 flags = lifr.lifr_flags; 2877 2878 /* 2879 * In V4 compatibility mode, we don't print the IFF_IPV4 flag or 2880 * interfaces with IFF_IPV6 set. 2881 */ 2882 if (v4compat) { 2883 flags &= ~IFF_IPV4; 2884 if (flags & IFF_IPV6) 2885 return; 2886 } 2887 2888 (void) printf("%s: ", ifname); 2889 print_flags(flags); 2890 2891 (void) strncpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2892 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) { 2893 Perror0_exit("status: SIOCGLIFMETRIC"); 2894 } else { 2895 if (lifr.lifr_metric) 2896 (void) printf(" metric %d", lifr.lifr_metric); 2897 } 2898 if (ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) 2899 (void) printf(" mtu %d", lifr.lifr_metric); 2900 2901 /* don't print index or zone when in compatibility mode */ 2902 if (!v4compat) { 2903 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) 2904 (void) printf(" index %d", lifr.lifr_index); 2905 if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) >= 0 && 2906 lifr.lifr_zoneid != getzoneid()) { 2907 char zone_name[ZONENAME_MAX]; 2908 2909 if (getzonenamebyid(lifr.lifr_zoneid, zone_name, 2910 sizeof (zone_name)) < 0) { 2911 (void) printf("\n\tzone %d", lifr.lifr_zoneid); 2912 } else { 2913 (void) printf("\n\tzone %s", zone_name); 2914 } 2915 } 2916 } 2917 2918 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) { 2919 lifs.lifs_ifindex = lifr.lifr_index; 2920 2921 /* 2922 * Find the number of interfaces that use this interfaces' 2923 * address as a source address 2924 */ 2925 lifs.lifs_buf = NULL; 2926 lifs.lifs_maxlen = 0; 2927 for (;;) { 2928 /* The first pass will give the bufsize we need */ 2929 rval = ioctl(s, SIOCGLIFSRCOF, (char *)&lifs); 2930 if (rval < 0) { 2931 if (lifs.lifs_buf != NULL) { 2932 free(lifs.lifs_buf); 2933 lifs.lifs_buf = NULL; 2934 } 2935 lifs.lifs_len = 0; 2936 break; 2937 } 2938 if (lifs.lifs_len <= lifs.lifs_maxlen) 2939 break; 2940 /* Use kernel's size + a small margin to avoid loops */ 2941 lifs.lifs_maxlen = lifs.lifs_len + 2942 5 * sizeof (struct lifreq); 2943 /* For the first pass, realloc acts like malloc */ 2944 newbuf = realloc(lifs.lifs_buf, lifs.lifs_maxlen); 2945 if (newbuf == NULL) { 2946 if (lifs.lifs_buf != NULL) { 2947 free(lifs.lifs_buf); 2948 lifs.lifs_buf = NULL; 2949 } 2950 lifs.lifs_len = 0; 2951 break; 2952 } 2953 lifs.lifs_buf = newbuf; 2954 } 2955 2956 2957 numifs = lifs.lifs_len / sizeof (struct lifreq); 2958 if (numifs > 0) { 2959 lifrp = lifs.lifs_req; 2960 (void) printf("\n\tsrcof"); 2961 for (n = numifs; n > 0; n--, lifrp++) { 2962 (void) printf(" %s", lifrp->lifr_name); 2963 } 2964 } 2965 2966 if (lifs.lifs_buf != NULL) 2967 free(lifs.lifs_buf); 2968 } 2969 2970 /* Find the interface whose source address this interface uses */ 2971 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) { 2972 if (lifr.lifr_index != 0) { 2973 if (if_indextoname(lifr.lifr_index, 2974 if_usesrc_name) == NULL) { 2975 (void) printf("\n\tusesrc ifIndex %d", 2976 lifr.lifr_index); 2977 } else { 2978 (void) printf("\n\tusesrc %s", if_usesrc_name); 2979 } 2980 } 2981 } 2982 2983 (void) putchar('\n'); 2984 } 2985 2986 2987 /* 2988 * Print the status of the interface. If an address family was 2989 * specified, show it and it only; otherwise, show them all. 2990 */ 2991 static void 2992 status(void) 2993 { 2994 struct afswtch *p = afp; 2995 uint64_t flags; 2996 2997 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 2998 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 2999 Perror0_exit("status: SIOCGLIFFLAGS"); 3000 } 3001 3002 flags = lifr.lifr_flags; 3003 3004 /* 3005 * Only print the interface status if the address family matches 3006 * the interface family flag. 3007 */ 3008 if (p != NULL) { 3009 if (((p->af_af == AF_INET6) && (flags & IFF_IPV4)) || 3010 ((p->af_af == AF_INET) && (flags & IFF_IPV6))) 3011 return; 3012 } 3013 3014 /* 3015 * In V4 compatibility mode, don't print IFF_IPV6 interfaces. 3016 */ 3017 if (v4compat && (flags & IFF_IPV6)) 3018 return; 3019 3020 ifstatus(name); 3021 3022 if (p != NULL) { 3023 (*p->af_status)(1, flags); 3024 } else { 3025 for (p = afs; p->af_name; p++) { 3026 (void) close(s); 3027 s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0); 3028 /* set global af for use in p->af_status */ 3029 af = p->af_af; 3030 if (s == -1) { 3031 Perror0_exit("socket"); 3032 } 3033 (*p->af_status)(0, flags); 3034 } 3035 3036 /* 3037 * Historically, 'ether' has been an address family, 3038 * so print it here. 3039 */ 3040 print_ifether(name); 3041 } 3042 } 3043 3044 /* 3045 * Print the status of the interface in a format that can be used to 3046 * reconfigure the interface later. Code stolen from status() above. 3047 */ 3048 /* ARGSUSED */ 3049 static int 3050 configinfo(char *null, int64_t param) 3051 { 3052 struct afswtch *p = afp; 3053 uint64_t flags; 3054 char phydevname[LIFNAMSIZ]; 3055 char if_usesrc_name[LIFNAMSIZ]; 3056 char *cp; 3057 3058 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3059 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 3060 Perror0_exit("status: SIOCGLIFFLAGS"); 3061 } 3062 flags = lifr.lifr_flags; 3063 3064 if (debug) { 3065 (void) printf("configinfo: name %s flags 0x%llx af_af %d\n", 3066 name, flags, p != NULL ? p->af_af : -1); 3067 } 3068 3069 /* remove LIF component */ 3070 (void) strncpy(phydevname, name, sizeof (phydevname)); 3071 cp = strchr(phydevname, ':'); 3072 if (cp) { 3073 *cp = 0; 3074 } 3075 phydevname[sizeof (phydevname) - 1] = '\0'; 3076 3077 /* 3078 * if the interface is IPv4 3079 * if we have a IPv6 address family restriction return 3080 * so it won't print 3081 * if we are in IPv4 compatibility mode, clear out IFF_IPV4 3082 * so we don't print it. 3083 */ 3084 if (flags & IFF_IPV4) { 3085 if (p && p->af_af == AF_INET6) 3086 return (-1); 3087 if (v4compat) 3088 flags &= ~IFF_IPV4; 3089 3090 (void) printf("%s inet plumb", phydevname); 3091 } else if (flags & IFF_IPV6) { 3092 /* 3093 * else if the interface is IPv6 3094 * if we have a IPv4 address family restriction return 3095 * or we are in IPv4 compatibiltiy mode, return. 3096 */ 3097 if (p && p->af_af == AF_INET) 3098 return (-1); 3099 if (v4compat) 3100 return (-1); 3101 3102 (void) printf("%s inet6 plumb", phydevname); 3103 } 3104 3105 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3106 if (ioctl(s, SIOCGLIFMETRIC, (caddr_t)&lifr) < 0) { 3107 Perror0_exit("configinfo: SIOCGLIFMETRIC"); 3108 } else { 3109 if (lifr.lifr_metric) 3110 (void) printf(" metric %d ", lifr.lifr_metric); 3111 } 3112 if (((flags & (IFF_VIRTUAL|IFF_LOOPBACK)) != IFF_VIRTUAL) && 3113 ioctl(s, SIOCGLIFMTU, (caddr_t)&lifr) >= 0) 3114 (void) printf(" mtu %d", lifr.lifr_metric); 3115 3116 /* don't print index when in compatibility mode */ 3117 if (!v4compat) { 3118 if (ioctl(s, SIOCGLIFINDEX, (caddr_t)&lifr) >= 0) 3119 (void) printf(" index %d", lifr.lifr_index); 3120 } 3121 3122 if (ioctl(s, SIOCGLIFUSESRC, (caddr_t)&lifr) == 0) { 3123 if (lifr.lifr_index != 0) { 3124 if (if_indextoname(lifr.lifr_index, 3125 if_usesrc_name) != NULL) { 3126 (void) printf(" usesrc %s", if_usesrc_name); 3127 } 3128 } 3129 } 3130 3131 if (p != NULL) { 3132 (*p->af_configinfo)(1, flags); 3133 } else { 3134 for (p = afs; p->af_name; p++) { 3135 (void) close(s); 3136 s = socket(SOCKET_AF(p->af_af), SOCK_DGRAM, 0); 3137 /* set global af for use in p->af_configinfo */ 3138 af = p->af_af; 3139 if (s == -1) { 3140 Perror0_exit("socket"); 3141 } 3142 (*p->af_configinfo)(0, flags); 3143 } 3144 } 3145 3146 (void) printf("\n"); 3147 3148 return (0); 3149 } 3150 3151 static void 3152 print_tsec(struct iftun_req *tparams) 3153 { 3154 ipsec_req_t *ipsr; 3155 3156 (void) printf("\ttunnel security settings "); 3157 /* 3158 * Deal with versioning, for now just point 3159 * an ipsec_req_t at ifta_secinfo. If versions 3160 * change, something else will overlay ifta_secinfo. 3161 */ 3162 assert(tparams->ifta_vers == IFTUN_VERSION); 3163 3164 ipsr = (ipsec_req_t *)(&tparams->ifta_secinfo); 3165 if (ipsr->ipsr_ah_req & IPSEC_PREF_REQUIRED) { 3166 (void) printf("ah (%s) ", 3167 rparsealg(ipsr->ipsr_auth_alg, IPSEC_PROTO_AH)); 3168 } 3169 if (ipsr->ipsr_esp_req & IPSEC_PREF_REQUIRED) { 3170 (void) printf("esp (%s", 3171 rparsealg(ipsr->ipsr_esp_alg, IPSEC_PROTO_ESP)); 3172 (void) printf("/%s)", 3173 rparsealg(ipsr->ipsr_esp_auth_alg, IPSEC_PROTO_AH)); 3174 } 3175 (void) printf("\n"); 3176 } 3177 3178 static void 3179 tun_status(void) 3180 { 3181 icfg_if_t interface; 3182 int rc; 3183 icfg_handle_t handle; 3184 int protocol; 3185 char srcbuf[INET6_ADDRSTRLEN]; 3186 char dstbuf[INET6_ADDRSTRLEN]; 3187 boolean_t tabbed; 3188 uint8_t hoplimit; 3189 int16_t encaplimit; 3190 struct sockaddr_storage taddr; 3191 socklen_t socklen = sizeof (taddr); 3192 3193 (void) strncpy(interface.if_name, name, sizeof (interface.if_name)); 3194 interface.if_protocol = SOCKET_AF(af); 3195 if ((rc = icfg_open(&handle, &interface)) != ICFG_SUCCESS) 3196 Perror0_exit((char *)icfg_errmsg(rc)); 3197 3198 /* 3199 * only print tunnel info for lun 0. If ioctl fails, assume 3200 * we are not a tunnel 3201 */ 3202 if (strchr(name, ':') != NULL || 3203 icfg_get_tunnel_lower(handle, &protocol) != ICFG_SUCCESS) { 3204 icfg_close(handle); 3205 return; 3206 } 3207 3208 switch (protocol) { 3209 case AF_INET: 3210 (void) printf("\tinet"); 3211 break; 3212 case AF_INET6: 3213 (void) printf("\tinet6"); 3214 break; 3215 default: 3216 Perror0_exit("\ttunnel: Illegal lower stream\n\t"); 3217 break; 3218 } 3219 3220 rc = icfg_get_tunnel_src(handle, (struct sockaddr *)&taddr, &socklen); 3221 if (rc == ICFG_NOT_SET) { 3222 (void) strlcpy(srcbuf, (protocol == AF_INET) ? "0.0.0.0" : 3223 "::", sizeof (srcbuf)); 3224 } else if (rc != ICFG_SUCCESS) { 3225 Perror0_exit((char *)icfg_errmsg(rc)); 3226 } else { 3227 rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr, 3228 srcbuf, sizeof (srcbuf)); 3229 if (rc != ICFG_SUCCESS) { 3230 Perror0_exit((char *)icfg_errmsg(rc)); 3231 } 3232 } 3233 3234 (void) printf(" tunnel src %s ", srcbuf); 3235 3236 rc = icfg_get_tunnel_dest(handle, (struct sockaddr *)&taddr, &socklen); 3237 if (rc == ICFG_NOT_SET) { 3238 (void) printf("\n"); 3239 } else { 3240 rc = icfg_sockaddr_to_str(protocol, (struct sockaddr *)&taddr, 3241 dstbuf, sizeof (dstbuf)); 3242 if (rc != ICFG_SUCCESS) { 3243 Perror0_exit((char *)icfg_errmsg(rc)); 3244 } 3245 (void) printf("tunnel dst %s\n", dstbuf); 3246 } 3247 3248 if (handle->ifh_tunnel_params != NULL && 3249 (handle->ifh_tunnel_params->ifta_flags & IFTUN_SECURITY)) 3250 print_tsec(handle->ifh_tunnel_params); 3251 3252 /* 3253 * tabbed indicates tabbed and printed. Use it tell us whether 3254 * to tab and that we've printed something here, so we need a 3255 * newline 3256 */ 3257 tabbed = _B_FALSE; 3258 3259 if (icfg_get_tunnel_hoplimit(handle, &hoplimit) == ICFG_SUCCESS) { 3260 (void) printf("\ttunnel hop limit %d ", hoplimit); 3261 tabbed = _B_TRUE; 3262 } 3263 3264 if ((protocol == AF_INET6) && 3265 (icfg_get_tunnel_encaplimit(handle, &encaplimit) == 3266 ICFG_SUCCESS)) { 3267 if (!tabbed) { 3268 (void) printf("\t"); 3269 tabbed = _B_TRUE; 3270 } 3271 if (encaplimit >= 0) { 3272 (void) printf("tunnel encapsulation limit %d", 3273 encaplimit); 3274 } else { 3275 (void) printf("tunnel encapsulation limit disabled"); 3276 } 3277 } 3278 3279 if (tabbed) 3280 (void) printf("\n"); 3281 3282 icfg_close(handle); 3283 } 3284 3285 static void 3286 in_status(int force, uint64_t flags) 3287 { 3288 struct sockaddr_in *sin, *laddr; 3289 struct sockaddr_in netmask = { AF_INET }; 3290 3291 if (debug) 3292 (void) printf("in_status(%s) flags 0x%llx\n", name, flags); 3293 3294 /* only print status for IPv4 interfaces */ 3295 if (!(flags & IFF_IPV4)) 3296 return; 3297 3298 /* if the interface is a tunnel, print the tunnel status */ 3299 tun_status(); 3300 3301 if (!(flags & IFF_NOLOCAL)) { 3302 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3303 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3304 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3305 errno == ENXIO) { 3306 if (!force) 3307 return; 3308 (void) memset(&lifr.lifr_addr, 0, 3309 sizeof (lifr.lifr_addr)); 3310 } else 3311 Perror0_exit("in_status: SIOCGLIFADDR"); 3312 } 3313 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3314 (void) printf("\tinet %s ", inet_ntoa(sin->sin_addr)); 3315 laddr = sin; 3316 } else { 3317 (void) printf("\tinet "); 3318 } 3319 3320 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3321 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3322 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3323 errno == ENXIO) { 3324 if (!force) 3325 return; 3326 (void) memset(&lifr.lifr_addr, 0, 3327 sizeof (lifr.lifr_addr)); 3328 } else { 3329 Perror0_exit("in_status: SIOCGLIFSUBNET"); 3330 } 3331 } 3332 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3333 if ((flags & IFF_NOLOCAL) || 3334 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) { 3335 (void) printf("subnet %s/%d ", inet_ntoa(sin->sin_addr), 3336 lifr.lifr_addrlen); 3337 } 3338 if (sin->sin_family != AF_INET) { 3339 (void) printf("Wrong family: %d\n", sin->sin_family); 3340 } 3341 3342 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3343 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) { 3344 if (errno != EADDRNOTAVAIL) 3345 Perror0_exit("in_status: SIOCGLIFNETMASK"); 3346 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3347 } else 3348 netmask.sin_addr = 3349 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr; 3350 if (flags & IFF_POINTOPOINT) { 3351 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3352 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3353 if (errno == EADDRNOTAVAIL) 3354 (void) memset(&lifr.lifr_addr, 0, 3355 sizeof (lifr.lifr_addr)); 3356 else 3357 Perror0_exit("in_status: SIOCGLIFDSTADDR"); 3358 } 3359 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr; 3360 (void) printf("--> %s ", inet_ntoa(sin->sin_addr)); 3361 } 3362 (void) printf("netmask %x ", ntohl(netmask.sin_addr.s_addr)); 3363 if (flags & IFF_BROADCAST) { 3364 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3365 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) { 3366 if (errno == EADDRNOTAVAIL) 3367 (void) memset(&lifr.lifr_addr, 0, 3368 sizeof (lifr.lifr_addr)); 3369 else 3370 Perror0_exit("in_status: SIOCGLIFBRDADDR"); 3371 } 3372 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3373 if (sin->sin_addr.s_addr != 0) { 3374 (void) printf("broadcast %s", 3375 inet_ntoa(sin->sin_addr)); 3376 } 3377 } 3378 /* If there is a groupname, print it for lun 0 alone */ 3379 if (strchr(name, ':') == NULL) { 3380 (void) memset(lifr.lifr_groupname, 0, 3381 sizeof (lifr.lifr_groupname)); 3382 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3383 if (strlen(lifr.lifr_groupname) > 0) { 3384 (void) printf("\n\tgroupname %s", 3385 lifr.lifr_groupname); 3386 } 3387 } 3388 } 3389 (void) putchar('\n'); 3390 } 3391 3392 static void 3393 in6_status(int force, uint64_t flags) 3394 { 3395 char abuf[INET6_ADDRSTRLEN]; 3396 struct sockaddr_in6 *sin6, *laddr6; 3397 3398 if (debug) 3399 (void) printf("in6_status(%s) flags 0x%llx\n", name, flags); 3400 3401 if (!(flags & IFF_IPV6)) 3402 return; 3403 3404 /* if the interface is a tunnel, print the tunnel status */ 3405 tun_status(); 3406 3407 if (!(flags & IFF_NOLOCAL)) { 3408 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3409 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3410 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3411 errno == ENXIO) { 3412 if (!force) 3413 return; 3414 (void) memset(&lifr.lifr_addr, 0, 3415 sizeof (lifr.lifr_addr)); 3416 } else 3417 Perror0_exit("in_status6: SIOCGLIFADDR"); 3418 } 3419 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3420 (void) printf("\tinet6 %s/%d ", 3421 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3422 abuf, sizeof (abuf)), 3423 lifr.lifr_addrlen); 3424 laddr6 = sin6; 3425 } else { 3426 (void) printf("\tinet6 "); 3427 } 3428 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3429 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3430 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3431 errno == ENXIO) { 3432 if (!force) 3433 return; 3434 (void) memset(&lifr.lifr_addr, 0, 3435 sizeof (lifr.lifr_addr)); 3436 } else 3437 Perror0_exit("in_status6: SIOCGLIFSUBNET"); 3438 } 3439 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3440 if ((flags & IFF_NOLOCAL) || 3441 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) { 3442 (void) printf("subnet %s/%d ", 3443 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3444 abuf, sizeof (abuf)), 3445 lifr.lifr_addrlen); 3446 } 3447 if (sin6->sin6_family != AF_INET6) { 3448 (void) printf("Wrong family: %d\n", sin6->sin6_family); 3449 } 3450 if (flags & IFF_POINTOPOINT) { 3451 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3452 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3453 if (errno == EADDRNOTAVAIL) 3454 (void) memset(&lifr.lifr_addr, 0, 3455 sizeof (lifr.lifr_addr)); 3456 else 3457 Perror0_exit("in_status6: SIOCGLIFDSTADDR"); 3458 } 3459 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr; 3460 (void) printf("--> %s ", 3461 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3462 abuf, sizeof (abuf))); 3463 } 3464 if (verbose) { 3465 (void) putchar('\n'); 3466 (void) putchar('\t'); 3467 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3468 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) { 3469 if (errno == EADDRNOTAVAIL || errno == EINVAL) 3470 (void) memset(&lifr.lifr_addr, 0, 3471 sizeof (lifr.lifr_addr)); 3472 else 3473 Perror0_exit("in_status6: SIOCGLIFTOKEN"); 3474 } else { 3475 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3476 (void) printf("token %s/%d ", 3477 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3478 abuf, sizeof (abuf)), 3479 lifr.lifr_addrlen); 3480 } 3481 if (ioctl(s, SIOCGLIFLNKINFO, (caddr_t)&lifr) < 0) { 3482 if (errno != EINVAL) { 3483 Perror0_exit("in_status6: SIOCGLIFLNKINFO"); 3484 } 3485 } else { 3486 (void) printf("maxhops %u, reachtime %u ms, " 3487 "reachretrans %u ms, maxmtu %u ", 3488 lifr.lifr_ifinfo.lir_maxhops, 3489 lifr.lifr_ifinfo.lir_reachtime, 3490 lifr.lifr_ifinfo.lir_reachretrans, 3491 lifr.lifr_ifinfo.lir_maxmtu); 3492 } 3493 } 3494 /* If there is a groupname, print it for lun 0 alone */ 3495 if (strchr(name, ':') == NULL) { 3496 (void) memset(lifr.lifr_groupname, 0, 3497 sizeof (lifr.lifr_groupname)); 3498 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3499 if (strlen(lifr.lifr_groupname) > 0) { 3500 (void) printf("\n\tgroupname %s", 3501 lifr.lifr_groupname); 3502 } 3503 } 3504 } 3505 (void) putchar('\n'); 3506 } 3507 3508 static void 3509 in_configinfo(int force, uint64_t flags) 3510 { 3511 struct sockaddr_in *sin, *laddr; 3512 struct sockaddr_in netmask = { AF_INET }; 3513 3514 if (debug) 3515 (void) printf("in_configinfo(%s) flags 0x%llx\n", name, flags); 3516 3517 /* only configinfo info for IPv4 interfaces */ 3518 if (!(flags & IFF_IPV4)) 3519 return; 3520 3521 if (!(flags & IFF_NOLOCAL)) { 3522 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3523 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3524 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3525 errno == ENXIO) { 3526 if (!force) 3527 return; 3528 (void) memset(&lifr.lifr_addr, 0, 3529 sizeof (lifr.lifr_addr)); 3530 } else 3531 Perror0_exit("in_configinfo: SIOCGLIFADDR"); 3532 } 3533 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3534 if (get_lun(name) != 0) { 3535 (void) printf(" addif %s ", inet_ntoa(sin->sin_addr)); 3536 } else { 3537 (void) printf(" set %s ", inet_ntoa(sin->sin_addr)); 3538 } 3539 laddr = sin; 3540 } 3541 3542 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3543 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3544 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3545 errno == ENXIO) { 3546 if (!force) 3547 return; 3548 (void) memset(&lifr.lifr_addr, 0, 3549 sizeof (lifr.lifr_addr)); 3550 } else { 3551 Perror0_exit("in_configinfo: SIOCGLIFSUBNET"); 3552 } 3553 } 3554 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3555 3556 if ((flags & IFF_NOLOCAL) || 3557 sin->sin_addr.s_addr != laddr->sin_addr.s_addr) { 3558 (void) printf(" subnet %s/%d ", inet_ntoa(sin->sin_addr), 3559 lifr.lifr_addrlen); 3560 } 3561 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3562 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) { 3563 if (errno != EADDRNOTAVAIL) 3564 Perror0_exit("in_configinfo: SIOCGLIFNETMASK"); 3565 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3566 } else 3567 netmask.sin_addr = 3568 ((struct sockaddr_in *)&lifr.lifr_addr)->sin_addr; 3569 if (flags & IFF_POINTOPOINT) { 3570 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3571 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3572 if (errno == EADDRNOTAVAIL) 3573 (void) memset(&lifr.lifr_addr, 0, 3574 sizeof (lifr.lifr_addr)); 3575 else 3576 Perror0_exit("in_configinfo: SIOCGLIFDSTADDR"); 3577 } 3578 sin = (struct sockaddr_in *)&lifr.lifr_dstaddr; 3579 (void) printf(" destination %s ", inet_ntoa(sin->sin_addr)); 3580 } 3581 (void) printf(" netmask 0x%x ", ntohl(netmask.sin_addr.s_addr)); 3582 if (flags & IFF_BROADCAST) { 3583 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3584 if (ioctl(s, SIOCGLIFBRDADDR, (caddr_t)&lifr) < 0) { 3585 if (errno == EADDRNOTAVAIL) 3586 (void) memset(&lifr.lifr_addr, 0, 3587 sizeof (lifr.lifr_addr)); 3588 else 3589 Perror0_exit("in_configinfo: SIOCGLIFBRDADDR"); 3590 } 3591 sin = (struct sockaddr_in *)&lifr.lifr_addr; 3592 if (sin->sin_addr.s_addr != 0) { 3593 (void) printf(" broadcast %s ", 3594 inet_ntoa(sin->sin_addr)); 3595 } 3596 } 3597 3598 /* If there is a groupname, print it for lun 0 alone */ 3599 if (get_lun(name) == 0) { 3600 (void) memset(lifr.lifr_groupname, 0, 3601 sizeof (lifr.lifr_groupname)); 3602 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3603 if (strlen(lifr.lifr_groupname) > 0) { 3604 (void) printf(" group %s ", 3605 lifr.lifr_groupname); 3606 } 3607 } 3608 } 3609 3610 /* Print flags to configure */ 3611 print_config_flags(flags); 3612 3613 /* IFF_NOARP applies to AF_INET only */ 3614 if (flags & IFF_NOARP) { 3615 (void) printf("-arp "); 3616 } 3617 } 3618 3619 static void 3620 in6_configinfo(int force, uint64_t flags) 3621 { 3622 char abuf[INET6_ADDRSTRLEN]; 3623 struct sockaddr_in6 *sin6, *laddr6; 3624 3625 if (debug) 3626 (void) printf("in6_configinfo(%s) flags 0x%llx\n", name, 3627 flags); 3628 3629 if (!(flags & IFF_IPV6)) 3630 return; 3631 3632 if (!(flags & IFF_NOLOCAL)) { 3633 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3634 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 3635 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3636 errno == ENXIO) { 3637 if (!force) 3638 return; 3639 (void) memset(&lifr.lifr_addr, 0, 3640 sizeof (lifr.lifr_addr)); 3641 } else 3642 Perror0_exit("in6_configinfo: SIOCGLIFADDR"); 3643 } 3644 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3645 if (get_lun(name) != 0) { 3646 (void) printf(" addif %s/%d ", 3647 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3648 abuf, sizeof (abuf)), 3649 lifr.lifr_addrlen); 3650 } else { 3651 (void) printf(" set %s/%d ", 3652 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3653 abuf, sizeof (abuf)), 3654 lifr.lifr_addrlen); 3655 } 3656 laddr6 = sin6; 3657 } 3658 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3659 if (ioctl(s, SIOCGLIFSUBNET, (caddr_t)&lifr) < 0) { 3660 if (errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT || 3661 errno == ENXIO) { 3662 if (!force) 3663 return; 3664 (void) memset(&lifr.lifr_addr, 0, 3665 sizeof (lifr.lifr_addr)); 3666 } else 3667 Perror0_exit("in6_configinfo: SIOCGLIFSUBNET"); 3668 } 3669 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3670 if ((flags & IFF_NOLOCAL) || 3671 !IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &laddr6->sin6_addr)) { 3672 (void) printf(" subnet %s/%d ", 3673 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3674 abuf, sizeof (abuf)), 3675 lifr.lifr_addrlen); 3676 } 3677 3678 if (flags & IFF_POINTOPOINT) { 3679 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3680 if (ioctl(s, SIOCGLIFDSTADDR, (caddr_t)&lifr) < 0) { 3681 if (errno == EADDRNOTAVAIL) 3682 (void) memset(&lifr.lifr_addr, 0, 3683 sizeof (lifr.lifr_addr)); 3684 else 3685 Perror0_exit("in6_configinfo: SIOCGLIFDSTADDR"); 3686 } 3687 sin6 = (struct sockaddr_in6 *)&lifr.lifr_dstaddr; 3688 (void) printf(" destination %s ", 3689 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3690 abuf, sizeof (abuf))); 3691 } 3692 3693 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3694 if (ioctl(s, SIOCGLIFTOKEN, (caddr_t)&lifr) < 0) { 3695 if (errno == EADDRNOTAVAIL || errno == EINVAL) 3696 (void) memset(&lifr.lifr_addr, 0, 3697 sizeof (lifr.lifr_addr)); 3698 else 3699 Perror0_exit("in6_configinfo: SIOCGLIFTOKEN"); 3700 } else { 3701 sin6 = (struct sockaddr_in6 *)&lifr.lifr_addr; 3702 (void) printf(" token %s/%d ", 3703 inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, 3704 abuf, sizeof (abuf)), 3705 lifr.lifr_addrlen); 3706 } 3707 3708 /* If there is a groupname, print it for lun 0 alone */ 3709 if (get_lun(name) == 0) { 3710 (void) memset(lifr.lifr_groupname, 0, 3711 sizeof (lifr.lifr_groupname)); 3712 if (ioctl(s, SIOCGLIFGROUPNAME, (caddr_t)&lifr) >= 0) { 3713 if (strlen(lifr.lifr_groupname) > 0) { 3714 (void) printf(" group %s ", 3715 lifr.lifr_groupname); 3716 } 3717 } 3718 } 3719 3720 /* Print flags to configure */ 3721 print_config_flags(flags); 3722 3723 /* IFF_NONUD applies to AF_INET6 only */ 3724 if (flags & IFF_NONUD) { 3725 (void) printf("-nud "); 3726 } 3727 } 3728 3729 /* ARGSUSED */ 3730 static int 3731 get_lun(char *rsrc) 3732 { 3733 char resource[LIFNAMSIZ]; 3734 char *cp; 3735 3736 (void) strcpy(resource, rsrc); 3737 3738 /* remove LIF component */ 3739 cp = strchr(resource, ':'); 3740 if (cp) { 3741 cp++; 3742 return (atoi(cp)); 3743 } 3744 3745 return (0); 3746 } 3747 3748 /* 3749 * We need to plink both the arp-device stream and the arp-ip-device stream. 3750 * However the muxid is stored only in IP. Plumbing 2 streams individually 3751 * is not atomic, and if ifconfig is killed, the resulting plumbing can 3752 * be inconsistent. For eg. if only the arp stream is plumbed, we have lost 3753 * the muxid, and the half-baked plumbing can neither be unplumbed nor 3754 * replumbed, thus requiring a reboot. To avoid the above the following 3755 * scheme is used. 3756 * 3757 * Ifconfig asks IP to enforce atomicity of plumbing the arp and IP streams. 3758 * This is done by pushing arp on to the mux (/dev/udp). ARP adds some 3759 * extra information in the I_PLINK and I_PUNLINK ioctls to let IP know 3760 * that the plumbing/unplumbing has to be done atomically. Ifconfig plumbs 3761 * the IP stream first, and unplumbs it last. The kernel (IP) does not 3762 * allow IP stream to be unplumbed without unplumbing arp stream. Similarly 3763 * it does not allow arp stream to be plumbed before IP stream is plumbed. 3764 * There is no need to use SIOCSLIFMUXID, since the whole operation is atomic, 3765 * and IP uses the info in the I_PLINK message to get the muxid. 3766 * 3767 * a. STREAMS does not allow us to use /dev/ip itself as the mux. So we use 3768 * /dev/udp[6]. 3769 * b. SIOCGLIFMUXID returns the muxid corresponding to the V4 or V6 stream 3770 * depending on the open i.e. V4 vs V6 open. So we need to use /dev/udp 3771 * or /dev/udp6. 3772 * c. We need to push ARP in order to get the required kernel support for 3773 * atomic plumbings. The actual work done by ARP is explained in arp.c 3774 * Without pushing ARP, we will still be able to plumb/unplumb. But 3775 * it is not atomic, and is supported by the kernel for backward 3776 * compatibility for other utilities like atmifconfig etc. In this case 3777 * the utility must use SIOCSLIFMUXID. 3778 */ 3779 static void 3780 plumb_one_device(dlpi_if_attr_t *diap, int ip_fd, int af) 3781 { 3782 int arp_fd = -1; 3783 int arp_muxid = -1, ip_muxid; 3784 int mux_fd; 3785 char *udp_dev_name; 3786 dlpi_if_attr_t dia; 3787 3788 if (debug) 3789 (void) printf("plumb_one_device: ifname %s, ppa %d\n", 3790 diap->ifname, diap->ppa); 3791 3792 if (diap->style == DL_STYLE2 && dlpi_detach(ip_fd, -1) < 0) 3793 Perror0_exit("dlpi_detach"); 3794 3795 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) 3796 Perror2_exit("I_PUSH", IP_MOD_NAME); 3797 3798 /* 3799 * Push the ARP module onto the interface stream. IP uses 3800 * this to send resolution requests up to ARP. We need to 3801 * do this before the SLIFNAME ioctl is sent down because 3802 * the interface becomes publicly known as soon as the SLIFNAME 3803 * ioctl completes. Thus some other process trying to bring up 3804 * the interface after SLIFNAME but before we have pushed ARP 3805 * could hang. We pop the module again later if it is not needed. 3806 */ 3807 if (ioctl(ip_fd, I_PUSH, ARP_MOD_NAME) == -1) 3808 Perror2_exit("I_PUSH", ARP_MOD_NAME); 3809 3810 /* 3811 * Set IFF_IPV4/IFF_IPV6 flags. 3812 * At this point in time the kernel also allows an 3813 * override of the CANTCHANGE flags. 3814 */ 3815 3816 lifr.lifr_name[0] = '\0'; 3817 if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) 3818 Perror0_exit("plumb_one_device: SIOCGLIFFLAGS"); 3819 3820 /* Set the name string and the IFF_IPV* flag */ 3821 if (af == AF_INET6) { 3822 lifr.lifr_flags |= IFF_IPV6; 3823 lifr.lifr_flags &= ~(IFF_BROADCAST | IFF_IPV4); 3824 } else { 3825 lifr.lifr_flags |= IFF_IPV4; 3826 lifr.lifr_flags &= ~IFF_IPV6; 3827 } 3828 3829 /* record the device and module names as interface name */ 3830 lifr.lifr_ppa = diap->ppa; 3831 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3832 3833 /* set the interface name */ 3834 if (ioctl(ip_fd, SIOCSLIFNAME, (char *)&lifr) == -1) { 3835 if (errno != EEXIST) 3836 Perror0_exit("SIOCSLIFNAME for ip"); 3837 /* 3838 * This difference between the way we behave for EEXIST 3839 * and that with other errors exists to preserve legacy 3840 * behaviour. Earlier when foreachinterface() and matcif() 3841 * were doing the duplicate interface name checks, for 3842 * already existing interfaces, inetplumb() returned "0". 3843 * To preserve this behaviour, Perror0() and return are 3844 * called for EEXIST. 3845 */ 3846 Perror0("SIOCSLIFNAME for ip"); 3847 return; 3848 } 3849 3850 /* Get the full set of existing flags for this stream */ 3851 if (ioctl(ip_fd, SIOCGLIFFLAGS, (char *)&lifr) == -1) 3852 Perror0_exit("plumb_one_device: SIOCFLIFFLAGS"); 3853 3854 if (debug) { 3855 (void) printf("plumb_one_device: %s got flags: \n", 3856 lifr.lifr_name); 3857 print_flags(lifr.lifr_flags); 3858 (void) putchar('\n'); 3859 } 3860 3861 /* Check if arp is not actually needed */ 3862 if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) { 3863 if (ioctl(ip_fd, I_POP, 0) == -1) 3864 Perror2_exit("I_POP", ARP_MOD_NAME); 3865 } 3866 3867 /* 3868 * Open "/dev/udp" for use as a multiplexor to PLINK the 3869 * interface stream under. We use "/dev/udp" instead of "/dev/ip" 3870 * since STREAMS will not let you PLINK a driver under itself, 3871 * and "/dev/ip" is typically the driver at the bottom of 3872 * the stream for tunneling interfaces. 3873 */ 3874 if (af == AF_INET6) 3875 udp_dev_name = UDP6_DEV_NAME; 3876 else 3877 udp_dev_name = UDP_DEV_NAME; 3878 if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) 3879 exit(EXIT_FAILURE); 3880 3881 /* Check if arp is not needed */ 3882 if (lifr.lifr_flags & (IFF_NOARP|IFF_IPV6)) { 3883 /* 3884 * PLINK the interface stream so that ifconfig can exit 3885 * without tearing down the stream. 3886 */ 3887 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) { 3888 Perror0_exit("I_PLINK for ip"); 3889 } 3890 (void) close(mux_fd); 3891 return; 3892 } 3893 3894 /* 3895 * This interface does use ARP, so set up a separate stream 3896 * from the interface to ARP. 3897 * 3898 * Note: modules specified by the user are pushed 3899 * only on the interface stream, not on the ARP stream. 3900 */ 3901 3902 if (debug) 3903 (void) printf("plumb_one_device: ifname: %s\n", 3904 diap->ifname); 3905 arp_fd = dlpi_if_open(diap->ifname, &dia, _B_FALSE); 3906 3907 if (dia.style == DL_STYLE2 && dlpi_detach(arp_fd, -1) < 0) 3908 Perror0_exit("dlpi_detach"); 3909 3910 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) 3911 Perror2_exit("I_PUSH", ARP_MOD_NAME); 3912 3913 /* 3914 * Tell ARP the name and unit number for this interface. 3915 * Note that arp has no support for transparent ioctls. 3916 */ 3917 if (strioctl(arp_fd, SIOCSLIFNAME, (char *)&lifr, 3918 sizeof (lifr)) == -1) { 3919 if (errno != EEXIST) 3920 Perror0_exit("SIOCSLIFNAME for arp"); 3921 Perror0("SIOCSLIFNAME for arp"); 3922 (void) close(arp_fd); 3923 (void) close(mux_fd); 3924 return; 3925 } 3926 /* 3927 * PLINK the IP and ARP streams so that ifconfig can exit 3928 * without tearing down the stream. 3929 */ 3930 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) { 3931 Perror0_exit("I_PLINK for ip"); 3932 } 3933 if ((arp_muxid = ioctl(mux_fd, I_PLINK, arp_fd)) == -1) { 3934 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid); 3935 Perror0_exit("I_PLINK for arp"); 3936 } 3937 3938 if (debug) 3939 (void) printf("arp muxid = %d\n", arp_muxid); 3940 (void) close(arp_fd); 3941 (void) close(mux_fd); 3942 } 3943 3944 3945 /* 3946 * If this is a physical interface then remove it. 3947 * If it is a logical interface name use SIOCLIFREMOVEIF to 3948 * remove it. In both cases fail if it doesn't exist. 3949 */ 3950 /* ARGSUSED */ 3951 static int 3952 inetunplumb(char *arg, int64_t param) 3953 { 3954 int ip_muxid, arp_muxid; 3955 int mux_fd; 3956 char *udp_dev_name; 3957 char *strptr; 3958 uint64_t flags; 3959 boolean_t changed_arp_muxid = _B_FALSE; 3960 int save_errno; 3961 3962 strptr = strchr(name, ':'); 3963 if (strptr != NULL || strcmp(name, LOOPBACK_IF) == 0) { 3964 /* Can't unplumb logical interface zero */ 3965 if (strptr != NULL && strcmp(strptr, ":0") == 0) { 3966 (void) fprintf(stderr, "ifconfig: unplumb:" 3967 " Cannot unplumb %s: Invalid interface\n", name); 3968 exit(1); 3969 } 3970 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3971 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr)); 3972 3973 if (ioctl(s, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) 3974 Perror0_exit("unplumb: SIOCLIFREMOVEIF"); 3975 return (0); 3976 } 3977 3978 /* 3979 * We used /dev/udp or udp6 to set up the mux. So we have to use 3980 * the same now for PUNLINK also. 3981 */ 3982 if (afp->af_af == AF_INET6) 3983 udp_dev_name = UDP6_DEV_NAME; 3984 else 3985 udp_dev_name = UDP_DEV_NAME; 3986 3987 if ((mux_fd = open_arp_on_udp(udp_dev_name)) == -1) 3988 exit(EXIT_FAILURE); 3989 3990 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 3991 if (ioctl(mux_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) { 3992 Perror0_exit("unplumb: SIOCGLIFFLAGS"); 3993 } 3994 flags = lifr.lifr_flags; 3995 if (ioctl(mux_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) { 3996 Perror0_exit("unplumb: SIOCGLIFMUXID"); 3997 } 3998 arp_muxid = lifr.lifr_arp_muxid; 3999 ip_muxid = lifr.lifr_ip_muxid; 4000 /* 4001 * We don't have a good way of knowing whether the arp stream is 4002 * plumbed. We can't rely on IFF_NOARP because someone could 4003 * have turned it off later using "ifconfig xxx -arp". 4004 */ 4005 if (arp_muxid != 0) { 4006 if (debug) 4007 (void) printf("arp_muxid %d\n", arp_muxid); 4008 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) { 4009 if ((errno == EINVAL) && 4010 (flags & (IFF_NOARP | IFF_IPV6))) { 4011 /* 4012 * Some plumbing utilities set the muxid to 4013 * -1 or some invalid value to signify that 4014 * there is no arp stream. Set the muxid to 0 4015 * before trying to unplumb the IP stream. 4016 * IP does not allow the IP stream to be 4017 * unplumbed if it sees a non-null arp muxid, 4018 * for consistency of IP-ARP streams. 4019 */ 4020 lifr.lifr_arp_muxid = 0; 4021 (void) ioctl(mux_fd, SIOCSLIFMUXID, 4022 (caddr_t)&lifr); 4023 changed_arp_muxid = _B_TRUE; 4024 } else { 4025 Perror0("I_PUNLINK for arp"); 4026 } 4027 } 4028 } 4029 if (debug) 4030 (void) printf("ip_muxid %d\n", ip_muxid); 4031 4032 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) { 4033 if (changed_arp_muxid) { 4034 /* 4035 * Some error occurred, and we need to restore 4036 * everything back to what it was. 4037 */ 4038 save_errno = errno; 4039 lifr.lifr_arp_muxid = arp_muxid; 4040 lifr.lifr_ip_muxid = ip_muxid; 4041 (void) ioctl(mux_fd, SIOCSLIFMUXID, (caddr_t)&lifr); 4042 errno = save_errno; 4043 } 4044 Perror0_exit("I_PUNLINK for ip"); 4045 } 4046 (void) close(mux_fd); 4047 return (0); 4048 } 4049 4050 /* 4051 * If this is a physical interface then create it unless it is already 4052 * present. If it is a logical interface name use SIOCLIFADDIF to 4053 * create and (and fail it if already exists.) 4054 * As a special case send SIOCLIFADDIF for the loopback interface. This 4055 * is needed since there is no other notion of plumbing the loopback 4056 * interface. 4057 */ 4058 /* ARGSUSED */ 4059 static int 4060 inetplumb(char *arg, int64_t param) 4061 { 4062 char *strptr; 4063 int dev_fd; 4064 dlpi_if_attr_t dia; 4065 boolean_t islo; 4066 4067 strptr = strchr(name, ':'); 4068 islo = (strcmp(name, LOOPBACK_IF) == 0); 4069 4070 if (strptr != NULL || islo) { 4071 (void) memset(&lifr, 0, sizeof (lifr)); 4072 (void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4073 if (islo && ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) >= 0) { 4074 if (debug) { 4075 (void) fprintf(stderr, 4076 "ifconfig: %s already exists\n", name); 4077 } 4078 return (0); 4079 } 4080 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) { 4081 if (errno == EEXIST) { 4082 if (debug) { 4083 (void) fprintf(stderr, 4084 "ifconfig: %s already exists\n", 4085 name); 4086 } 4087 } else { 4088 Perror2_exit("plumb: SIOCLIFADDIF", name); 4089 } 4090 } 4091 /* 4092 * IP can create the new logical interface on a different 4093 * physical interface in the same IPMP group. Take the new 4094 * interface into account for further operations. 4095 */ 4096 (void) strncpy(name, lifr.lifr_name, sizeof (name)); 4097 return (0); 4098 } 4099 4100 if (debug) 4101 (void) printf("inetplumb: %s af %d\n", name, afp->af_af); 4102 4103 if ((dev_fd = dlpi_if_open(name, &dia, _B_FALSE)) < 0) { 4104 Perror2_exit("plumb", name); 4105 /* NOTREACHED */ 4106 } 4107 4108 plumb_one_device(&dia, dev_fd, afp->af_af); 4109 (void) close(dev_fd); 4110 return (0); 4111 } 4112 4113 void 4114 Perror0(char *cmd) 4115 { 4116 int save_errno; 4117 4118 save_errno = errno; 4119 (void) fprintf(stderr, "ifconfig: "); 4120 errno = save_errno; 4121 switch (errno) { 4122 4123 case ENXIO: 4124 (void) fprintf(stderr, "%s: %s: no such interface\n", 4125 cmd, lifr.lifr_name); 4126 break; 4127 4128 case EPERM: 4129 (void) fprintf(stderr, "%s: %s: permission denied\n", 4130 cmd, lifr.lifr_name); 4131 break; 4132 4133 case EEXIST: 4134 (void) fprintf(stderr, "%s: %s: already exists\n", 4135 cmd, lifr.lifr_name); 4136 break; 4137 4138 default: { 4139 char buf[BUFSIZ]; 4140 4141 (void) snprintf(buf, sizeof (buf), "%s: %s", 4142 cmd, lifr.lifr_name); 4143 perror(buf); 4144 } 4145 } 4146 } 4147 4148 void 4149 Perror0_exit(char *cmd) 4150 { 4151 Perror0(cmd); 4152 exit(1); 4153 /* NOTREACHED */ 4154 } 4155 4156 void 4157 Perror2(char *cmd, char *str) 4158 { 4159 int save_errno; 4160 4161 save_errno = errno; 4162 (void) fprintf(stderr, "ifconfig: "); 4163 errno = save_errno; 4164 switch (errno) { 4165 4166 case ENXIO: 4167 (void) fprintf(stderr, "%s: %s: no such interface\n", 4168 cmd, str); 4169 break; 4170 4171 case EPERM: 4172 (void) fprintf(stderr, "%s: %s: permission denied\n", 4173 cmd, str); 4174 break; 4175 4176 default: { 4177 char buf[BUFSIZ]; 4178 4179 (void) snprintf(buf, sizeof (buf), "%s: %s", cmd, str); 4180 perror(buf); 4181 } 4182 } 4183 } 4184 4185 /* 4186 * Print out error message (Perror2()) and exit 4187 */ 4188 void 4189 Perror2_exit(char *cmd, char *str) 4190 { 4191 Perror2(cmd, str); 4192 exit(1); 4193 /* NOTREACHED */ 4194 } 4195 4196 /* 4197 * If the last argument is non-NULL allow a <addr>/<n> syntax and 4198 * pass out <n> in *plenp. 4199 * If <n> doesn't parse return BAD_ADDR as *plenp. 4200 * If no /<n> is present return NO_PREFIX as *plenp. 4201 */ 4202 static void 4203 in_getaddr(char *s, struct sockaddr *saddr, int *plenp) 4204 { 4205 struct sockaddr_in *sin = (struct sockaddr_in *)saddr; 4206 struct hostent *hp; 4207 struct netent *np; 4208 char str[BUFSIZ]; 4209 int error_num; 4210 4211 (void) strncpy(str, s, sizeof (str)); 4212 4213 /* 4214 * Look for '/'<n> is plenp 4215 */ 4216 if (plenp != NULL) { 4217 char *cp; 4218 4219 *plenp = in_getprefixlen(str, _B_TRUE, ADDRBITS_V4); 4220 if (*plenp == BAD_ADDR) 4221 return; 4222 cp = strchr(str, '/'); 4223 if (cp != NULL) 4224 *cp = '\0'; 4225 } else if (strchr(str, '/') != NULL) { 4226 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str); 4227 exit(1); 4228 } 4229 4230 (void) memset(sin, 0, sizeof (*sin)); 4231 4232 /* 4233 * Try to catch attempts to set the broadcast address to all 1's. 4234 */ 4235 if (strcmp(str, "255.255.255.255") == 0 || 4236 (strtoul(str, (char **)NULL, 0) == 0xffffffffUL)) { 4237 sin->sin_family = AF_INET; 4238 sin->sin_addr.s_addr = 0xffffffff; 4239 return; 4240 } 4241 4242 hp = getipnodebyname(str, AF_INET, 0, &error_num); 4243 if (hp) { 4244 sin->sin_family = hp->h_addrtype; 4245 (void) memcpy(&sin->sin_addr, hp->h_addr, hp->h_length); 4246 freehostent(hp); 4247 return; 4248 } 4249 np = getnetbyname(str); 4250 if (np) { 4251 sin->sin_family = np->n_addrtype; 4252 sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); 4253 return; 4254 } 4255 if (error_num == TRY_AGAIN) { 4256 (void) fprintf(stderr, "ifconfig: %s: bad address " 4257 "(try again later)\n", s); 4258 } else { 4259 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s); 4260 } 4261 exit(1); 4262 } 4263 4264 /* 4265 * If the last argument is non-NULL allow a <addr>/<n> syntax and 4266 * pass out <n> in *plenp. 4267 * If <n> doesn't parse return BAD_ADDR as *plenp. 4268 * If no /<n> is present return NO_PREFIX as *plenp. 4269 */ 4270 static void 4271 in6_getaddr(char *s, struct sockaddr *saddr, int *plenp) 4272 { 4273 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)saddr; 4274 struct hostent *hp; 4275 char str[BUFSIZ]; 4276 int error_num; 4277 4278 (void) strncpy(str, s, sizeof (str)); 4279 4280 /* 4281 * Look for '/'<n> is plenp 4282 */ 4283 if (plenp != NULL) { 4284 char *cp; 4285 4286 *plenp = in_getprefixlen(str, _B_TRUE, ADDRBITS_V6); 4287 if (*plenp == BAD_ADDR) 4288 return; 4289 cp = strchr(str, '/'); 4290 if (cp != NULL) 4291 *cp = '\0'; 4292 } else if (strchr(str, '/') != NULL) { 4293 (void) fprintf(stderr, "ifconfig: %s: unexpected '/'\n", str); 4294 exit(1); 4295 } 4296 4297 (void) memset(sin6, 0, sizeof (*sin6)); 4298 4299 hp = getipnodebyname(str, AF_INET6, 0, &error_num); 4300 if (hp) { 4301 sin6->sin6_family = hp->h_addrtype; 4302 (void) memcpy(&sin6->sin6_addr, hp->h_addr, hp->h_length); 4303 freehostent(hp); 4304 return; 4305 } 4306 if (error_num == TRY_AGAIN) { 4307 (void) fprintf(stderr, "ifconfig: %s: bad address " 4308 "(try again later)\n", s); 4309 } else { 4310 (void) fprintf(stderr, "ifconfig: %s: bad address\n", s); 4311 } 4312 exit(1); 4313 } 4314 4315 /* 4316 * If "slash" is zero this parses the whole string as 4317 * an integer. With "slash" non zero it parses the tail part as an integer. 4318 * 4319 * If it is not a valid integer this returns BAD_ADDR. 4320 * If there is /<n> present this returns NO_PREFIX. 4321 */ 4322 static int 4323 in_getprefixlen(char *addr, boolean_t slash, int max_plen) 4324 { 4325 int prefixlen; 4326 char *str, *end; 4327 4328 if (slash) { 4329 str = strchr(addr, '/'); 4330 if (str == NULL) 4331 return (NO_PREFIX); 4332 str++; 4333 } else 4334 str = addr; 4335 4336 prefixlen = strtol(str, &end, 10); 4337 if (prefixlen < 0) 4338 return (BAD_ADDR); 4339 if (str == end) 4340 return (BAD_ADDR); 4341 if (max_plen != 0 && max_plen < prefixlen) 4342 return (BAD_ADDR); 4343 return (prefixlen); 4344 } 4345 4346 /* 4347 * Convert a prefix length to a mask. 4348 * Returns 1 if ok. 0 otherwise. 4349 * Assumes the mask array is zero'ed by the caller. 4350 */ 4351 static boolean_t 4352 in_prefixlentomask(int prefixlen, int maxlen, uchar_t *mask) 4353 { 4354 if (prefixlen < 0 || prefixlen > maxlen) 4355 return (0); 4356 4357 while (prefixlen > 0) { 4358 if (prefixlen >= 8) { 4359 *mask++ = 0xFF; 4360 prefixlen -= 8; 4361 continue; 4362 } 4363 *mask |= 1 << (8 - prefixlen); 4364 prefixlen--; 4365 } 4366 return (1); 4367 } 4368 4369 static void 4370 print_flags(uint64_t flags) 4371 { 4372 boolean_t first = _B_TRUE; 4373 int cnt, i; 4374 4375 (void) printf("flags=%llx", flags); 4376 cnt = sizeof (if_flags_tbl) / sizeof (if_flags_t); 4377 for (i = 0; i < cnt; i++) { 4378 if (flags & if_flags_tbl[i].iff_value) { 4379 if (first) { 4380 (void) printf("<"); 4381 first = _B_FALSE; 4382 } else { 4383 /* 4384 * It has to be here and not with the 4385 * printf below because for the last one, 4386 * we don't want a comma before the ">". 4387 */ 4388 (void) printf(","); 4389 } 4390 (void) printf("%s", if_flags_tbl[i].iff_name); 4391 } 4392 } 4393 if (!first) 4394 (void) printf(">"); 4395 } 4396 4397 static void 4398 print_config_flags(uint64_t flags) 4399 { 4400 int cnt, i; 4401 4402 cnt = sizeof (if_config_cmd_tbl) / sizeof (if_config_cmd_t); 4403 for (i = 0; i < cnt; i++) { 4404 if (flags & if_config_cmd_tbl[i].iff_flag) { 4405 (void) printf("%s ", if_config_cmd_tbl[i].iff_name); 4406 } 4407 } 4408 } 4409 4410 /* 4411 * Look in the NIS for the network mask. 4412 * returns true if we found one to set. 4413 */ 4414 static boolean_t 4415 in_getmask(struct sockaddr_in *saddr) 4416 { 4417 struct sockaddr_in ifaddr; 4418 4419 /* 4420 * Read the address from the interface 4421 */ 4422 (void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name)); 4423 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) { 4424 if (errno != EADDRNOTAVAIL) 4425 (void) fprintf(stderr, "Need net number for mask\n"); 4426 return (_B_FALSE); 4427 } 4428 ifaddr = *((struct sockaddr_in *)&lifr.lifr_addr); 4429 if (getnetmaskbyaddr(ifaddr.sin_addr, &saddr->sin_addr) == 0) { 4430 saddr->sin_family = AF_INET; 4431 (void) printf("Setting netmask of %s to %s\n", name, 4432 inet_ntoa(saddr->sin_addr)); 4433 return (_B_TRUE); 4434 } 4435 return (_B_FALSE); 4436 } 4437 4438 static int 4439 strioctl(int s, int cmd, char *buf, int buflen) 4440 { 4441 struct strioctl ioc; 4442 4443 (void) memset(&ioc, 0, sizeof (ioc)); 4444 ioc.ic_cmd = cmd; 4445 ioc.ic_timout = 0; 4446 ioc.ic_len = buflen; 4447 ioc.ic_dp = buf; 4448 return (ioctl(s, I_STR, (char *)&ioc)); 4449 } 4450 4451 static void 4452 add_ni(char *name) 4453 { 4454 ni_t **pp; 4455 ni_t *p; 4456 4457 for (pp = &ni_list; (p = *pp) != NULL; pp = &(p->ni_next)) { 4458 if (strcmp(p->ni_name, name) == 0) { 4459 if (debug > 2) 4460 (void) fprintf(stderr, "'%s' is a duplicate\n", 4461 name); 4462 return; 4463 } 4464 } 4465 4466 if (debug > 2) 4467 (void) fprintf(stderr, "adding '%s'\n", 4468 name); 4469 4470 if ((p = malloc(sizeof (ni_t))) == NULL) 4471 return; 4472 4473 (void) strlcpy(p->ni_name, name, sizeof (p->ni_name)); 4474 p->ni_next = NULL; 4475 4476 *pp = p; 4477 num_ni++; 4478 } 4479 4480 /* ARGSUSED2 */ 4481 static int 4482 devfs_entry(di_node_t node, di_minor_t minor, void *arg) 4483 { 4484 char *provider; 4485 int fd; 4486 uint_t ppa; 4487 dl_info_ack_t dlia; 4488 char ifname[LIFNAMSIZ]; 4489 4490 provider = di_minor_name(minor); 4491 4492 if (strlen(provider) > LIFNAMSIZ) 4493 return (DI_WALK_CONTINUE); 4494 4495 if (debug > 2) 4496 fprintf(stderr, "provider = %s\n", provider); 4497 4498 if ((fd = dlpi_open(provider)) < 0) 4499 return (DI_WALK_CONTINUE); 4500 4501 if (debug > 2) 4502 fprintf(stderr, "getting DL_INFO_ACK\n"); 4503 4504 if (dlpi_info(fd, -1, &dlia, NULL, NULL, NULL, NULL, NULL, NULL) < 0) 4505 goto done; 4506 4507 if (dlia.dl_provider_style == DL_STYLE1) { 4508 if (debug > 2) 4509 fprintf(stderr, "provider is DL_STYLE1\n"); 4510 add_ni(provider); 4511 goto done; 4512 } 4513 4514 if (debug > 2) 4515 fprintf(stderr, "provider is DL_STYLE2\n"); 4516 4517 if (di_minor_type(minor) != DDM_ALIAS) { 4518 if (debug > 2) 4519 (void) fprintf(stderr, 4520 "non-alias node, ignoring\n"); 4521 goto done; 4522 } 4523 4524 if (debug > 2) 4525 (void) fprintf(stderr, 4526 "alias node, using instance\n"); 4527 ppa = di_instance(node); 4528 4529 if (dlpi_attach(fd, -1, ppa) < 0) { 4530 if (debug > 2) 4531 (void) fprintf(stderr, 4532 "non-existent PPA, ignoring\n"); 4533 goto done; 4534 } 4535 4536 (void) snprintf(ifname, LIFNAMSIZ, "%s%d", provider, ppa); 4537 add_ni(ifname); 4538 4539 done: 4540 (void) dlpi_close(fd); 4541 return (DI_WALK_CONTINUE); 4542 } 4543 4544 /* 4545 * dhcp-related routines 4546 */ 4547 4548 static int 4549 setifdhcp(const char *caller, const char *ifname, int argc, char *argv[]) 4550 { 4551 dhcp_ipc_request_t *request; 4552 dhcp_ipc_reply_t *reply = NULL; 4553 int timeout = DHCP_IPC_WAIT_DEFAULT; 4554 dhcp_ipc_type_t type = DHCP_START; 4555 int error; 4556 boolean_t is_primary = _B_FALSE; 4557 boolean_t started = _B_FALSE; 4558 4559 for (argv++; --argc > 0; argv++) { 4560 4561 if (strcmp(*argv, "primary") == 0) { 4562 is_primary = _B_TRUE; 4563 continue; 4564 } 4565 4566 if (strcmp(*argv, "wait") == 0) { 4567 if (--argc <= 0) { 4568 usage(); 4569 return (DHCP_EXIT_BADARGS); 4570 } 4571 argv++; 4572 4573 if (strcmp(*argv, "forever") == 0) { 4574 timeout = DHCP_IPC_WAIT_FOREVER; 4575 continue; 4576 } 4577 4578 if (sscanf(*argv, "%d", &timeout) != 1) { 4579 usage(); 4580 return (DHCP_EXIT_BADARGS); 4581 } 4582 4583 if (timeout < 0) { 4584 usage(); 4585 return (DHCP_EXIT_BADARGS); 4586 } 4587 continue; 4588 } 4589 4590 type = dhcp_string_to_request(*argv); 4591 if (type == -1) { 4592 usage(); 4593 return (DHCP_EXIT_BADARGS); 4594 } 4595 } 4596 4597 /* 4598 * Only try to start agent on start or inform; in all other cases it 4599 * has to already be running for anything to make sense. 4600 */ 4601 if (type == DHCP_START || type == DHCP_INFORM) { 4602 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) { 4603 (void) fprintf(stderr, "%s: unable to start %s\n", 4604 caller, DHCP_AGENT_PATH); 4605 return (DHCP_EXIT_FAILURE); 4606 } 4607 started = _B_TRUE; 4608 } 4609 4610 if (is_primary) 4611 type = type | DHCP_PRIMARY; 4612 4613 request = dhcp_ipc_alloc_request(type, ifname, NULL, 0, DHCP_TYPE_NONE); 4614 if (request == NULL) { 4615 (void) fprintf(stderr, "%s: out of memory\n", caller); 4616 return (DHCP_EXIT_SYSTEM); 4617 } 4618 4619 error = dhcp_ipc_make_request(request, &reply, timeout); 4620 if (error != 0) { 4621 free(request); 4622 /* 4623 * Re-map connect error to not under control if we didn't try a 4624 * start operation, as this has to be true and results in a 4625 * clearer message, not to mention preserving compatibility 4626 * with the days when we always started dhcpagent for every 4627 * request. 4628 */ 4629 if (error == DHCP_IPC_E_CONNECT && !started) 4630 error = DHCP_IPC_E_UNKIF; 4631 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname, 4632 dhcp_ipc_strerror(error)); 4633 return (DHCP_EXIT_FAILURE); 4634 } 4635 4636 error = reply->return_code; 4637 if (error != 0) { 4638 free(request); 4639 free(reply); 4640 4641 if (error == DHCP_IPC_E_TIMEOUT && timeout == 0) 4642 return (DHCP_EXIT_SUCCESS); 4643 4644 (void) fprintf(stderr, "%s: %s: %s\n", caller, ifname, 4645 dhcp_ipc_strerror(error)); 4646 4647 if (error == DHCP_IPC_E_TIMEOUT) 4648 return (DHCP_EXIT_TIMEOUT); 4649 else 4650 return (DHCP_EXIT_IF_FAILURE); 4651 } 4652 4653 if (DHCP_IPC_CMD(type) == DHCP_STATUS) { 4654 (void) printf("%s", dhcp_status_hdr_string()); 4655 (void) printf("%s", dhcp_status_reply_to_string(reply)); 4656 } 4657 4658 free(request); 4659 free(reply); 4660 return (DHCP_EXIT_SUCCESS); 4661 } 4662 4663 static void 4664 usage(void) 4665 { 4666 (void) fprintf(stderr, 4667 "usage: ifconfig <interface> | -a[ 4 | 6 | D ][ u | d ][ Z ]\n"); 4668 4669 (void) fprintf(stderr, "%s", 4670 "\t[ <addr_family> ]\n" 4671 "\t[ <address>[/<prefix_length>] [ <dest_address> ] ]\n" 4672 "\t[ set [ <address>][/<prefix_length>] ]" 4673 " [ <address>/<prefix_length>] ]\n" 4674 "\t[ destination <dest_address> ]\n" 4675 "\t[ addif <address>[/<prefix_length>]" 4676 " [ <dest_address> ] ]\n" 4677 "\t[ removeif <address>[/<prefix_length>] ]\n" 4678 "\t[ arp | -arp ]\n" 4679 "\t[ auto-revarp ]\n" 4680 "\t[ broadcast <broad_addr> ]\n" 4681 "\t[ index <if_index> ]\n" 4682 "\t[ metric <n> ] [ mtu <n> ]\n" 4683 "\t[ netmask <mask> ]\n" 4684 "\t[ plumb ] [ unplumb ]\n" 4685 "\t[ preferred | -preferred ]\n" 4686 "\t[ private | -private ]\n" 4687 "\t[ local | -local ]\n" 4688 "\t[ router | -router ]\n" 4689 "\t[ subnet <subnet_address>]\n" 4690 "\t[ trailers | -trailers ]\n" 4691 "\t[ token <address>/<prefix_length> ]\n" 4692 "\t[ tsrc <tunnel_src_address> ]\n" 4693 "\t[ tdst <tunnel_dest_address> ]\n" 4694 "\t[ auth_algs <tunnel_AH_authentication_algorithm> ]\n" 4695 "\t[ encr_algs <tunnel_ESP_encryption_algorithm> ]\n" 4696 "\t[ encr_auth_algs <tunnel_ESP_authentication_algorithm> ]\n" 4697 "\t[ up ] [ down ]\n" 4698 "\t[ xmit | -xmit ]\n" 4699 "\t[ modlist ]\n" 4700 "\t[ modinsert <module_name@position> ]\n" 4701 "\t[ modremove <module_name@position> ]\n" 4702 "\t[ group <groupname>] | [ group \"\"]\n" 4703 "\t[ deprecated | -deprecated ]\n" 4704 "\t[ standby | -standby ]\n" 4705 "\t[ failover | -failover ]\n" 4706 "\t[ zone <zonename> | -zone ]\n" 4707 "\t[ usesrc <interface> ]\n"); 4708 4709 (void) fprintf(stderr, "or\n"); 4710 (void) fprintf(stderr, 4711 "\tifconfig <interface> | -a[ 4 | 6 | D ] [ u | d ]\n"); 4712 4713 (void) fprintf(stderr, "%s", "\tauto-dhcp | dhcp\n" 4714 "\t[ wait <time> | forever ]\n\t[ primary ]\n" 4715 "\tstart | drop | ping | release | status | inform\n"); 4716 } 4717