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