1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2013 by Delphix. All rights reserved. 24 * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>. 25 */ 26 27 /* 28 * This file contains functions for address management such as creating 29 * an address, deleting an address, enabling an address, disabling an 30 * address, bringing an address down or up, setting/getting properties 31 * on an address object and listing address information 32 * for all addresses in active as well as persistent configuration. 33 */ 34 #include <sys/types.h> 35 #include <sys/socket.h> 36 #include <sys/param.h> 37 #include <netdb.h> 38 #include <inet/ip.h> 39 #include <string.h> 40 #include <strings.h> 41 #include <assert.h> 42 #include <sys/sockio.h> 43 #include <errno.h> 44 #include <unistd.h> 45 #include <stropts.h> 46 #include <zone.h> 47 #include <netinet/in.h> 48 #include <arpa/inet.h> 49 #include <fcntl.h> 50 #include <ctype.h> 51 #include <dhcpagent_util.h> 52 #include <dhcpagent_ipc.h> 53 #include <dhcp_inittab.h> 54 #include <dhcp_symbol.h> 55 #include <ipadm_ndpd.h> 56 #include <libdladm.h> 57 #include <libdllink.h> 58 #include <libdliptun.h> 59 #include <ifaddrs.h> 60 #include "libipadm_impl.h" 61 62 #define SIN6(a) ((struct sockaddr_in6 *)a) 63 #define SIN(a) ((struct sockaddr_in *)a) 64 65 static ipadm_status_t i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t, 66 uint32_t); 67 static ipadm_status_t i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t, 68 uint32_t); 69 static ipadm_status_t i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t, 70 boolean_t); 71 static ipadm_status_t i_ipadm_refresh_dhcp(ipadm_addrobj_t); 72 static ipadm_status_t i_ipadm_get_db_addr(ipadm_handle_t, const char *, 73 const char *, nvlist_t **); 74 static ipadm_status_t i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t, 75 int *); 76 static ipadm_status_t i_ipadm_dhcp_status(ipadm_addrobj_t addr, 77 dhcp_status_t *status, int *dhcperror); 78 static ipadm_status_t i_ipadm_validate_create_addr(ipadm_handle_t, 79 ipadm_addrobj_t, uint32_t); 80 static ipadm_status_t i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *, 81 uint32_t); 82 static ipadm_status_t i_ipadm_get_default_prefixlen(struct sockaddr_storage *, 83 uint32_t *); 84 static ipadm_status_t i_ipadm_get_static_addr_db(ipadm_handle_t, 85 ipadm_addrobj_t); 86 static boolean_t i_ipadm_is_user_aobjname_valid(const char *); 87 static ipadm_prop_desc_t *i_ipadm_get_addrprop_desc(const char *pname); 88 89 /* 90 * Callback functions to retrieve property values from the kernel. These 91 * functions, when required, translate the values from the kernel to a format 92 * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values 93 * for a given property. 94 */ 95 static ipadm_pd_getf_t i_ipadm_get_prefixlen, i_ipadm_get_addr_flag, 96 i_ipadm_get_zone, i_ipadm_get_broadcast, 97 i_ipadm_get_primary, i_ipadm_get_reqhost; 98 99 /* 100 * Callback functions to set property values. These functions translate the 101 * values to a format suitable for kernel consumption, allocate the necessary 102 * ioctl buffers and then invoke ioctl(); or in the case of reqhost, get the 103 * collaborating agent to set the value. 104 */ 105 static ipadm_pd_setf_t i_ipadm_set_prefixlen, i_ipadm_set_addr_flag, 106 i_ipadm_set_zone, i_ipadm_set_reqhost; 107 108 static ipadm_status_t i_ipadm_set_aobj_addrprop(ipadm_handle_t iph, 109 ipadm_addrobj_t ipaddr, uint_t flags, const char *propname); 110 111 /* address properties description table */ 112 ipadm_prop_desc_t ipadm_addrprop_table[] = { 113 { "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 114 NULL, NULL, i_ipadm_get_broadcast }, 115 116 { "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 117 i_ipadm_set_addr_flag, i_ipadm_get_onoff, 118 i_ipadm_get_addr_flag }, 119 120 { IPADM_NVP_PREFIXLEN, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 121 i_ipadm_set_prefixlen, i_ipadm_get_prefixlen, 122 i_ipadm_get_prefixlen }, 123 124 /* 125 * primary is read-only because there is no operation to un-set 126 * DHCP_IF_PRIMARY in dhcpagent except to delete-addr and then 127 * re-create-addr. 128 */ 129 { "primary", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 130 NULL, NULL, i_ipadm_get_primary }, 131 132 { "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 133 i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag }, 134 135 { IPADM_NVP_REQHOST, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 136 i_ipadm_set_reqhost, NULL, i_ipadm_get_reqhost }, 137 138 { "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 139 i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag }, 140 141 { "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0, 142 i_ipadm_set_zone, NULL, i_ipadm_get_zone }, 143 144 { NULL, NULL, 0, 0, 0, NULL, NULL, NULL } 145 }; 146 147 static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR, 148 MOD_PROTO_NONE, 0, NULL, NULL, NULL }; 149 150 /* 151 * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and 152 * `ipadm_atype' fields of the given `ipaddr'. 153 */ 154 void 155 i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname, 156 const char *aobjname, ipadm_addr_type_t atype) 157 { 158 bzero(ipaddr, sizeof (struct ipadm_addrobj_s)); 159 (void) strlcpy(ipaddr->ipadm_ifname, ifname, 160 sizeof (ipaddr->ipadm_ifname)); 161 (void) strlcpy(ipaddr->ipadm_aobjname, aobjname, 162 sizeof (ipaddr->ipadm_aobjname)); 163 ipaddr->ipadm_atype = atype; 164 } 165 166 /* 167 * Determine the permission of the property depending on whether it has a 168 * set() and/or get() callback functions. 169 */ 170 static ipadm_status_t 171 i_ipadm_pd2permstr(ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize) 172 { 173 uint_t perm; 174 size_t nbytes; 175 176 perm = 0; 177 if (pdp->ipd_set != NULL) 178 perm |= MOD_PROP_PERM_WRITE; 179 if (pdp->ipd_get != NULL) 180 perm |= MOD_PROP_PERM_READ; 181 182 nbytes = snprintf(buf, *bufsize, "%c%c", 183 ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-', 184 ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-'); 185 186 if (nbytes >= *bufsize) { 187 /* insufficient buffer space */ 188 *bufsize = nbytes + 1; 189 return (IPADM_NO_BUFS); 190 } 191 return (IPADM_SUCCESS); 192 } 193 194 /* 195 * Given an addrobj with `ipadm_aobjname' filled in, i_ipadm_get_addrobj() 196 * retrieves the information necessary for any operation on the object, 197 * such as delete-addr, enable-addr, disable-addr, up-addr, down-addr, 198 * refresh-addr, get-addrprop or set-addrprop. The information include 199 * the logical interface number, address type, address family, 200 * the interface id (if the address type is IPADM_ADDR_IPV6_ADDRCONF) and 201 * the ipadm_flags that indicate if the address is present in 202 * active configuration or persistent configuration or both. If the address 203 * is not found, IPADM_NOTSUP is returned. 204 */ 205 ipadm_status_t 206 i_ipadm_get_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr) 207 { 208 ipmgmt_aobjop_arg_t larg; 209 ipmgmt_aobjop_rval_t rval, *rvalp; 210 int err = 0; 211 212 /* populate the door_call argument structure */ 213 larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ; 214 (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname, 215 sizeof (larg.ia_aobjname)); 216 217 rvalp = &rval; 218 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp, 219 sizeof (rval), B_FALSE); 220 if (err != 0) 221 return (ipadm_errno2status(err)); 222 (void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname, 223 sizeof (ipaddr->ipadm_ifname)); 224 ipaddr->ipadm_lifnum = rval.ir_lnum; 225 ipaddr->ipadm_atype = rval.ir_atype; 226 ipaddr->ipadm_af = rval.ir_family; 227 ipaddr->ipadm_flags = rval.ir_flags; 228 switch (rval.ir_atype) { 229 case IPADM_ADDR_IPV6_ADDRCONF: 230 ipaddr->ipadm_intfid = rval.ipmgmt_ir_intfid; 231 break; 232 case IPADM_ADDR_DHCP: 233 if (strlcpy(ipaddr->ipadm_reqhost, rval.ipmgmt_ir_reqhost, 234 sizeof (ipaddr->ipadm_reqhost)) >= 235 sizeof (ipaddr->ipadm_reqhost)) { 236 /* 237 * shouldn't get here as the buffers are defined 238 * with same length, MAX_NAME_LEN 239 */ 240 return (IPADM_FAILURE); 241 } 242 break; 243 default: 244 break; 245 } 246 247 return (IPADM_SUCCESS); 248 } 249 250 /* 251 * Retrieves the static address (IPv4 or IPv6) for the given address object 252 * in `ipaddr' from persistent DB. 253 */ 254 static ipadm_status_t 255 i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr) 256 { 257 ipadm_status_t status; 258 nvlist_t *onvl; 259 nvlist_t *anvl = NULL; 260 nvlist_t *nvladdr; 261 nvpair_t *nvp; 262 char *name; 263 char *aobjname = ipaddr->ipadm_aobjname; 264 char *sname; 265 sa_family_t af = AF_UNSPEC; 266 267 /* 268 * Get the address line in the nvlist `onvl' from ipmgmtd daemon. 269 */ 270 status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl); 271 if (status != IPADM_SUCCESS) 272 return (status); 273 /* 274 * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR 275 * or the IPADM_NVP_IPV6ADDR name-value pair. 276 */ 277 for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL; 278 nvp = nvlist_next_nvpair(onvl, NULL)) { 279 if (nvpair_value_nvlist(nvp, &anvl) != 0) 280 continue; 281 if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) || 282 nvlist_exists(anvl, IPADM_NVP_IPV6ADDR)) 283 break; 284 } 285 if (nvp == NULL) 286 goto fail; 287 for (nvp = nvlist_next_nvpair(anvl, NULL); 288 nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) { 289 name = nvpair_name(nvp); 290 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) { 291 af = AF_INET; 292 break; 293 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) { 294 af = AF_INET6; 295 break; 296 } 297 } 298 assert(af != AF_UNSPEC); 299 if (nvpair_value_nvlist(nvp, &nvladdr) != 0 || 300 nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 || 301 ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) { 302 goto fail; 303 } 304 nvlist_free(onvl); 305 return (IPADM_SUCCESS); 306 fail: 307 nvlist_free(onvl); 308 return (IPADM_NOTFOUND); 309 } 310 311 /* 312 * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function 313 * fills in the address objname, the address type and the ipadm_flags. 314 */ 315 ipadm_status_t 316 i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj) 317 { 318 ipmgmt_aobjop_arg_t larg; 319 ipmgmt_aobjop_rval_t rval, *rvalp; 320 int err; 321 322 larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ; 323 (void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname, 324 sizeof (larg.ia_ifname)); 325 larg.ia_lnum = addrobj->ipadm_lifnum; 326 larg.ia_family = addrobj->ipadm_af; 327 328 rvalp = &rval; 329 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp, 330 sizeof (rval), B_FALSE); 331 if (err != 0) 332 return (ipadm_errno2status(err)); 333 (void) strlcpy(addrobj->ipadm_aobjname, rval.ir_aobjname, 334 sizeof (addrobj->ipadm_aobjname)); 335 addrobj->ipadm_atype = rval.ir_atype; 336 addrobj->ipadm_flags = rval.ir_flags; 337 338 return (IPADM_SUCCESS); 339 } 340 341 /* 342 * Adds an addrobj to ipmgmtd daemon's aobjmap (active configuration). 343 * with the given name and logical interface number. 344 * This API is called by in.ndpd to add addrobjs when new prefixes or 345 * dhcpv6 addresses are configured. 346 */ 347 ipadm_status_t 348 ipadm_add_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af, 349 const char *aobjname, ipadm_addr_type_t atype, int lnum) 350 { 351 ipmgmt_aobjop_arg_t larg; 352 int err; 353 354 larg.ia_cmd = IPMGMT_CMD_ADDROBJ_ADD; 355 (void) strlcpy(larg.ia_ifname, ifname, sizeof (larg.ia_ifname)); 356 (void) strlcpy(larg.ia_aobjname, aobjname, sizeof (larg.ia_aobjname)); 357 larg.ia_atype = atype; 358 larg.ia_lnum = lnum; 359 larg.ia_family = af; 360 err = ipadm_door_call(iph, &larg, sizeof (larg), NULL, 0, B_FALSE); 361 return (ipadm_errno2status(err)); 362 } 363 364 /* 365 * Deletes an address object with given name and logical number from ipmgmtd 366 * daemon's aobjmap (active configuration). This API is called by in.ndpd to 367 * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are 368 * removed. 369 */ 370 ipadm_status_t 371 ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af, 372 const char *aobjname, ipadm_addr_type_t atype, int lnum) 373 { 374 struct ipadm_addrobj_s aobj; 375 376 i_ipadm_init_addr(&aobj, ifname, aobjname, atype); 377 aobj.ipadm_af = af; 378 aobj.ipadm_lifnum = lnum; 379 return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE)); 380 } 381 382 /* 383 * Gets all the addresses from active configuration and populates the 384 * address information in `addrinfo'. 385 */ 386 static ipadm_status_t 387 i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname, 388 ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags) 389 { 390 ipadm_status_t status; 391 struct ifaddrs *ifap, *ifa; 392 ipadm_addr_info_t *curr, *prev = NULL; 393 struct ifaddrs *cifaddr; 394 struct lifreq lifr; 395 int sock; 396 uint64_t flags; 397 char cifname[LIFNAMSIZ]; 398 struct sockaddr_in6 *sin6; 399 struct ipadm_addrobj_s ipaddr; 400 char *sep; 401 int lnum; 402 403 retry: 404 *addrinfo = NULL; 405 406 /* Get all the configured addresses */ 407 if (getallifaddrs(AF_UNSPEC, &ifa, lifc_flags) < 0) 408 return (ipadm_errno2status(errno)); 409 /* Return if there is nothing to process. */ 410 if (ifa == NULL) 411 return (IPADM_SUCCESS); 412 bzero(&lifr, sizeof (lifr)); 413 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) { 414 struct sockaddr_storage data; 415 416 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname)); 417 lnum = 0; 418 if ((sep = strrchr(cifname, ':')) != NULL) { 419 *sep++ = '\0'; 420 lnum = atoi(sep); 421 } 422 if (ifname != NULL && strcmp(cifname, ifname) != 0) 423 continue; 424 if (!(ipadm_flags & IPADM_OPT_ZEROADDR) && 425 sockaddrunspec(ifap->ifa_addr) && 426 !(ifap->ifa_flags & IFF_DHCPRUNNING)) 427 continue; 428 429 /* Allocate and populate the current node in the list. */ 430 if ((curr = calloc(1, sizeof (ipadm_addr_info_t))) == NULL) 431 goto fail; 432 433 /* Link to the list in `addrinfo'. */ 434 if (prev != NULL) 435 prev->ia_ifa.ifa_next = &curr->ia_ifa; 436 else 437 *addrinfo = curr; 438 prev = curr; 439 440 cifaddr = &curr->ia_ifa; 441 if ((cifaddr->ifa_name = strdup(ifap->ifa_name)) == NULL) 442 goto fail; 443 cifaddr->ifa_flags = ifap->ifa_flags; 444 cifaddr->ifa_addr = malloc(sizeof (struct sockaddr_storage)); 445 if (cifaddr->ifa_addr == NULL) 446 goto fail; 447 (void) memcpy(cifaddr->ifa_addr, ifap->ifa_addr, 448 sizeof (struct sockaddr_storage)); 449 cifaddr->ifa_netmask = malloc(sizeof (struct sockaddr_storage)); 450 if (cifaddr->ifa_netmask == NULL) 451 goto fail; 452 (void) memcpy(cifaddr->ifa_netmask, ifap->ifa_netmask, 453 sizeof (struct sockaddr_storage)); 454 if (ifap->ifa_flags & IFF_POINTOPOINT) { 455 cifaddr->ifa_dstaddr = malloc( 456 sizeof (struct sockaddr_storage)); 457 if (cifaddr->ifa_dstaddr == NULL) 458 goto fail; 459 (void) memcpy(cifaddr->ifa_dstaddr, ifap->ifa_dstaddr, 460 sizeof (struct sockaddr_storage)); 461 } else if (ifap->ifa_flags & IFF_BROADCAST) { 462 cifaddr->ifa_broadaddr = malloc( 463 sizeof (struct sockaddr_storage)); 464 if (cifaddr->ifa_broadaddr == NULL) 465 goto fail; 466 (void) memcpy(cifaddr->ifa_broadaddr, 467 ifap->ifa_broadaddr, 468 sizeof (struct sockaddr_storage)); 469 } 470 /* Get the addrobj name stored for this logical interface. */ 471 ipaddr.ipadm_aobjname[0] = '\0'; 472 (void) strlcpy(ipaddr.ipadm_ifname, cifname, 473 sizeof (ipaddr.ipadm_ifname)); 474 ipaddr.ipadm_lifnum = lnum; 475 ipaddr.ipadm_af = ifap->ifa_addr->sa_family; 476 status = i_ipadm_get_lif2addrobj(iph, &ipaddr); 477 478 /* 479 * Find address type from ifa_flags, if we could not get it 480 * from daemon. 481 */ 482 (void) memcpy(&data, ifap->ifa_addr, 483 sizeof (struct sockaddr_in6)); 484 sin6 = SIN6(&data); 485 flags = ifap->ifa_flags; 486 if (status == IPADM_SUCCESS) { 487 (void) strlcpy(curr->ia_aobjname, ipaddr.ipadm_aobjname, 488 sizeof (curr->ia_aobjname)); 489 curr->ia_atype = ipaddr.ipadm_atype; 490 } else if ((flags & IFF_DHCPRUNNING) && (!(flags & IFF_IPV6) || 491 !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) { 492 curr->ia_atype = IPADM_ADDR_DHCP; 493 } else if (flags & IFF_ADDRCONF) { 494 curr->ia_atype = IPADM_ADDR_IPV6_ADDRCONF; 495 } else { 496 curr->ia_atype = IPADM_ADDR_STATIC; 497 } 498 /* 499 * Populate the flags for the active configuration from the 500 * `ifa_flags'. 501 */ 502 if (!(flags & IFF_UP)) { 503 if (flags & IFF_DUPLICATE) 504 curr->ia_state = IFA_DUPLICATE; 505 else 506 curr->ia_state = IFA_DOWN; 507 } else { 508 curr->ia_cflags |= IA_UP; 509 if (flags & IFF_RUNNING) { 510 (void) strlcpy(lifr.lifr_name, ifap->ifa_name, 511 sizeof (lifr.lifr_name)); 512 sock = (ifap->ifa_addr->sa_family == AF_INET) ? 513 iph->iph_sock : iph->iph_sock6; 514 if (ioctl(sock, SIOCGLIFDADSTATE, 515 (caddr_t)&lifr) < 0) { 516 if (errno == ENXIO) { 517 freeifaddrs(ifa); 518 ipadm_free_addr_info(*addrinfo); 519 goto retry; 520 } 521 goto fail; 522 } 523 if (lifr.lifr_dadstate == DAD_IN_PROGRESS) 524 curr->ia_state = IFA_TENTATIVE; 525 else 526 curr->ia_state = IFA_OK; 527 } else { 528 curr->ia_state = IFA_INACCESSIBLE; 529 } 530 } 531 if (flags & IFF_UNNUMBERED) 532 curr->ia_cflags |= IA_UNNUMBERED; 533 if (flags & IFF_PRIVATE) 534 curr->ia_cflags |= IA_PRIVATE; 535 if (flags & IFF_TEMPORARY) 536 curr->ia_cflags |= IA_TEMPORARY; 537 if (flags & IFF_DEPRECATED) 538 curr->ia_cflags |= IA_DEPRECATED; 539 540 } 541 542 freeifaddrs(ifa); 543 return (IPADM_SUCCESS); 544 545 fail: 546 /* On error, cleanup everything and return. */ 547 ipadm_free_addr_info(*addrinfo); 548 *addrinfo = NULL; 549 freeifaddrs(ifa); 550 return (ipadm_errno2status(errno)); 551 } 552 553 /* 554 * From the given `name', i_ipadm_name2atype() deduces the address type 555 * and address family. If the `name' implies an address, it returns B_TRUE. 556 * Else, returns B_FALSE and leaves the output parameters unchanged. 557 */ 558 boolean_t 559 i_ipadm_name2atype(const char *name, sa_family_t *af, ipadm_addr_type_t *type) 560 { 561 boolean_t is_addr = B_TRUE; 562 563 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) { 564 *af = AF_INET; 565 *type = IPADM_ADDR_STATIC; 566 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) { 567 *af = AF_INET6; 568 *type = IPADM_ADDR_STATIC; 569 } else if (strcmp(name, IPADM_NVP_DHCP) == 0) { 570 *af = AF_INET; 571 *type = IPADM_ADDR_DHCP; 572 } else if (strcmp(name, IPADM_NVP_INTFID) == 0) { 573 *af = AF_INET6; 574 *type = IPADM_ADDR_IPV6_ADDRCONF; 575 } else { 576 is_addr = B_FALSE; 577 } 578 579 return (is_addr); 580 } 581 582 /* 583 * Parses the given nvlist `nvl' for an address or an address property. 584 * The input nvlist must contain either an address or an address property. 585 * `ainfo' is an input as well as output parameter. When an address or an 586 * address property is found, `ainfo' is updated with the information found. 587 * Some of the fields may be already filled in by the calling function. 588 * 589 * The fields that will be filled/updated by this function are `ia_pflags', 590 * `ia_sname' and `ia_dname'. Values for `ia_pflags' are obtained if the `nvl' 591 * contains an address property. `ia_sname', `ia_dname', and `ia_pflags' are 592 * obtained if `nvl' contains an address. 593 */ 594 static ipadm_status_t 595 i_ipadm_nvl2ainfo_common(nvlist_t *nvl, ipadm_addr_info_t *ainfo) 596 { 597 nvlist_t *nvladdr; 598 char *name; 599 char *propstr = NULL; 600 char *sname, *dname; 601 nvpair_t *nvp; 602 sa_family_t af; 603 ipadm_addr_type_t atype; 604 boolean_t is_addr = B_FALSE; 605 int err; 606 607 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 608 nvp = nvlist_next_nvpair(nvl, nvp)) { 609 name = nvpair_name(nvp); 610 if (i_ipadm_name2atype(name, &af, &atype)) { 611 err = nvpair_value_nvlist(nvp, &nvladdr); 612 is_addr = B_TRUE; 613 } else if (IPADM_PRIV_NVP(name)) { 614 continue; 615 } else { 616 err = nvpair_value_string(nvp, &propstr); 617 } 618 if (err != 0) 619 return (ipadm_errno2status(err)); 620 } 621 622 if (is_addr) { 623 /* 624 * We got an address from the nvlist `nvl'. 625 * Parse `nvladdr' and populate relevant information 626 * in `ainfo'. 627 */ 628 switch (atype) { 629 case IPADM_ADDR_STATIC: 630 if (strcmp(name, "up") == 0 && 631 strcmp(propstr, "yes") == 0) { 632 ainfo->ia_pflags |= IA_UP; 633 } 634 /* 635 * For static addresses, we need to get the hostnames. 636 */ 637 err = nvlist_lookup_string(nvladdr, 638 IPADM_NVP_IPADDRHNAME, &sname); 639 if (err != 0) 640 return (ipadm_errno2status(err)); 641 (void) strlcpy(ainfo->ia_sname, sname, 642 sizeof (ainfo->ia_sname)); 643 err = nvlist_lookup_string(nvladdr, 644 IPADM_NVP_IPDADDRHNAME, &dname); 645 if (err == 0) { 646 (void) strlcpy(ainfo->ia_dname, dname, 647 sizeof (ainfo->ia_dname)); 648 } 649 break; 650 case IPADM_ADDR_DHCP: 651 case IPADM_ADDR_IPV6_ADDRCONF: 652 /* 653 * dhcp and addrconf address objects are always 654 * marked up when re-enabled. 655 */ 656 ainfo->ia_pflags |= IA_UP; 657 break; 658 default: 659 return (IPADM_FAILURE); 660 } 661 } else { 662 /* 663 * We got an address property from `nvl'. Parse the 664 * name and the property value. Update the `ainfo->ia_pflags' 665 * for the flags. 666 */ 667 if (strcmp(name, "deprecated") == 0) { 668 if (strcmp(propstr, IPADM_ONSTR) == 0) 669 ainfo->ia_pflags |= IA_DEPRECATED; 670 } else if (strcmp(name, "private") == 0) { 671 if (strcmp(propstr, IPADM_ONSTR) == 0) 672 ainfo->ia_pflags |= IA_PRIVATE; 673 } 674 } 675 676 return (IPADM_SUCCESS); 677 } 678 679 /* 680 * Parses the given nvlist `nvl' for an address or an address property. 681 * The input nvlist must contain either an address or an address property. 682 * `ainfo' is an input as well as output parameter. When an address or an 683 * address property is found, `ainfo' is updated with the information found. 684 * Some of the fields may be already filled in by the calling function, 685 * because of previous calls to i_ipadm_nvl2ainfo_active(). 686 * 687 * Since the address object in `nvl' is also in the active configuration, the 688 * fields that will be filled/updated by this function are `ia_pflags', 689 * `ia_sname' and `ia_dname'. 690 * 691 * If this function returns an error, the calling function will take 692 * care of freeing the fields in `ainfo'. 693 */ 694 static ipadm_status_t 695 i_ipadm_nvl2ainfo_active(nvlist_t *nvl, ipadm_addr_info_t *ainfo) 696 { 697 return (i_ipadm_nvl2ainfo_common(nvl, ainfo)); 698 } 699 700 /* 701 * Parses the given nvlist `nvl' for an address or an address property. 702 * The input nvlist must contain either an address or an address property. 703 * `ainfo' is an input as well as output parameter. When an address or an 704 * address property is found, `ainfo' is updated with the information found. 705 * Some of the fields may be already filled in by the calling function, 706 * because of previous calls to i_ipadm_nvl2ainfo_persist(). 707 * 708 * All the relevant fields in `ainfo' will be filled by this function based 709 * on what we find in `nvl'. 710 * 711 * If this function returns an error, the calling function will take 712 * care of freeing the fields in `ainfo'. 713 */ 714 static ipadm_status_t 715 i_ipadm_nvl2ainfo_persist(nvlist_t *nvl, ipadm_addr_info_t *ainfo) 716 { 717 nvlist_t *nvladdr; 718 struct ifaddrs *ifa; 719 char *name; 720 char *ifname = NULL; 721 char *aobjname = NULL; 722 char *propstr = NULL; 723 nvpair_t *nvp; 724 sa_family_t af; 725 ipadm_addr_type_t atype; 726 boolean_t is_addr = B_FALSE; 727 size_t size = sizeof (struct sockaddr_storage); 728 uint32_t plen = 0; 729 int err; 730 ipadm_status_t status; 731 732 status = i_ipadm_nvl2ainfo_common(nvl, ainfo); 733 if (status != IPADM_SUCCESS) 734 return (status); 735 736 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 737 nvp = nvlist_next_nvpair(nvl, nvp)) { 738 name = nvpair_name(nvp); 739 if (strcmp(name, IPADM_NVP_IFNAME) == 0) { 740 err = nvpair_value_string(nvp, &ifname); 741 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) { 742 err = nvpair_value_string(nvp, &aobjname); 743 } else if (i_ipadm_name2atype(name, &af, &atype)) { 744 err = nvpair_value_nvlist(nvp, &nvladdr); 745 is_addr = B_TRUE; 746 } else { 747 err = nvpair_value_string(nvp, &propstr); 748 } 749 if (err != 0) 750 return (ipadm_errno2status(err)); 751 } 752 753 ifa = &ainfo->ia_ifa; 754 (void) strlcpy(ainfo->ia_aobjname, aobjname, 755 sizeof (ainfo->ia_aobjname)); 756 if (ifa->ifa_name == NULL && (ifa->ifa_name = strdup(ifname)) == NULL) 757 return (IPADM_NO_MEMORY); 758 if (is_addr) { 759 struct sockaddr_in6 data; 760 761 /* 762 * We got an address from the nvlist `nvl'. 763 * Parse `nvladdr' and populate `ifa->ifa_addr'. 764 */ 765 ainfo->ia_atype = atype; 766 if ((ifa->ifa_addr = calloc(1, size)) == NULL) 767 return (IPADM_NO_MEMORY); 768 switch (atype) { 769 case IPADM_ADDR_STATIC: 770 ifa->ifa_addr->sa_family = af; 771 break; 772 case IPADM_ADDR_DHCP: 773 ifa->ifa_addr->sa_family = AF_INET; 774 break; 775 case IPADM_ADDR_IPV6_ADDRCONF: 776 data.sin6_family = AF_INET6; 777 if (i_ipadm_nvl2in6_addr(nvladdr, IPADM_NVP_IPNUMADDR, 778 &data.sin6_addr) != IPADM_SUCCESS) 779 return (IPADM_NO_MEMORY); 780 err = nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN, 781 &plen); 782 if (err != 0) 783 return (ipadm_errno2status(err)); 784 if ((ifa->ifa_netmask = malloc(size)) == NULL) 785 return (IPADM_NO_MEMORY); 786 if ((err = plen2mask(plen, af, ifa->ifa_netmask)) != 0) 787 return (ipadm_errno2status(err)); 788 (void) memcpy(ifa->ifa_addr, &data, sizeof (data)); 789 break; 790 default: 791 return (IPADM_FAILURE); 792 } 793 } else { 794 if (strcmp(name, "prefixlen") == 0) { 795 /* 796 * If a prefixlen was found, update the 797 * `ainfo->ia_ifa.ifa_netmask'. 798 */ 799 800 if ((ifa->ifa_netmask = malloc(size)) == NULL) 801 return (IPADM_NO_MEMORY); 802 /* 803 * Address property lines always follow the address 804 * line itself in the persistent db. We must have 805 * found a valid `ainfo->ia_ifa.ifa_addr' by now. 806 */ 807 assert(ifa->ifa_addr != NULL); 808 err = plen2mask(atoi(propstr), ifa->ifa_addr->sa_family, 809 ifa->ifa_netmask); 810 if (err != 0) 811 return (ipadm_errno2status(err)); 812 } 813 } 814 815 return (IPADM_SUCCESS); 816 } 817 818 /* 819 * Retrieves all addresses from active config and appends to it the 820 * addresses that are found only in persistent config. In addition, 821 * it updates the persistent fields for each address from information 822 * found in persistent config. The output parameter `addrinfo' contains 823 * complete information regarding all addresses in active as well as 824 * persistent config. 825 */ 826 static ipadm_status_t 827 i_ipadm_get_all_addr_info(ipadm_handle_t iph, const char *ifname, 828 ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags) 829 { 830 nvlist_t *nvladdr = NULL; 831 nvlist_t *onvl = NULL; 832 nvpair_t *nvp; 833 ipadm_status_t status; 834 ipadm_addr_info_t *ainfo = NULL; 835 ipadm_addr_info_t *curr; 836 ipadm_addr_info_t *last = NULL; 837 char *aobjname; 838 839 /* Get all addresses from active config. */ 840 status = i_ipadm_active_addr_info(iph, ifname, &ainfo, ipadm_flags, 841 lifc_flags); 842 if (status != IPADM_SUCCESS) 843 goto fail; 844 845 /* Get all addresses from persistent config. */ 846 status = i_ipadm_get_db_addr(iph, ifname, NULL, &onvl); 847 /* 848 * If no address was found in persistent config, just 849 * return what we found in active config. 850 */ 851 if (status == IPADM_NOTFOUND) { 852 /* 853 * If nothing was found neither active nor persistent 854 * config, this means that the interface does not exist, 855 * if one was provided in `ifname'. 856 */ 857 if (ainfo == NULL && ifname != NULL) 858 return (IPADM_ENXIO); 859 *addrinfo = ainfo; 860 return (IPADM_SUCCESS); 861 } 862 /* In case of any other error, cleanup and return. */ 863 if (status != IPADM_SUCCESS) 864 goto fail; 865 /* we append to make sure, loopback addresses are first */ 866 if (ainfo != NULL) { 867 for (curr = ainfo; IA_NEXT(curr) != NULL; curr = IA_NEXT(curr)) 868 ; 869 last = curr; 870 } 871 872 /* 873 * `onvl' will contain all the address lines from the db. Each line 874 * could contain the address itself or an address property. Addresses 875 * and address properties are found in separate lines. 876 * 877 * If an address A was found in active, we will already have `ainfo', 878 * and it is present in persistent configuration as well, we need to 879 * update `ainfo' with persistent information (`ia_pflags). 880 * For each address B found only in persistent configuration, 881 * append the address to the list with the address info for B from 882 * `onvl'. 883 */ 884 for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL; 885 nvp = nvlist_next_nvpair(onvl, nvp)) { 886 if (nvpair_value_nvlist(nvp, &nvladdr) != 0) 887 continue; 888 if (nvlist_lookup_string(nvladdr, IPADM_NVP_AOBJNAME, 889 &aobjname) != 0) 890 continue; 891 for (curr = ainfo; curr != NULL; curr = IA_NEXT(curr)) { 892 if (strcmp(curr->ia_aobjname, aobjname) == 0) 893 break; 894 } 895 if (curr == NULL) { 896 /* 897 * We did not find this address object in `ainfo'. 898 * This means that the address object exists only 899 * in the persistent configuration. Get its 900 * details and append to `ainfo'. 901 */ 902 curr = calloc(1, sizeof (ipadm_addr_info_t)); 903 if (curr == NULL) 904 goto fail; 905 curr->ia_state = IFA_DISABLED; 906 if (last != NULL) 907 last->ia_ifa.ifa_next = &curr->ia_ifa; 908 else 909 ainfo = curr; 910 last = curr; 911 } 912 /* 913 * Fill relevant fields of `curr' from the persistent info 914 * in `nvladdr'. Call the appropriate function based on the 915 * `ia_state' value. 916 */ 917 if (curr->ia_state == IFA_DISABLED) 918 status = i_ipadm_nvl2ainfo_persist(nvladdr, curr); 919 else 920 status = i_ipadm_nvl2ainfo_active(nvladdr, curr); 921 if (status != IPADM_SUCCESS) 922 goto fail; 923 } 924 *addrinfo = ainfo; 925 nvlist_free(onvl); 926 return (status); 927 fail: 928 /* On error, cleanup and return. */ 929 nvlist_free(onvl); 930 ipadm_free_addr_info(ainfo); 931 *addrinfo = NULL; 932 return (status); 933 } 934 935 /* 936 * Callback function that sets the property `prefixlen' on the address 937 * object in `arg' to the value in `pval'. 938 */ 939 /* ARGSUSED */ 940 static ipadm_status_t 941 i_ipadm_set_prefixlen(ipadm_handle_t iph, const void *arg, 942 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags) 943 { 944 struct sockaddr_storage netmask; 945 struct lifreq lifr; 946 int err, s; 947 unsigned long prefixlen, abits; 948 char *end; 949 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 950 951 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP) 952 return (IPADM_NOTSUP); 953 954 errno = 0; 955 prefixlen = strtoul(pval, &end, 10); 956 if (errno != 0 || *end != '\0') 957 return (IPADM_INVALID_ARG); 958 959 abits = (af == AF_INET ? IP_ABITS : IPV6_ABITS); 960 if (prefixlen == 0 || prefixlen == (abits - 1)) 961 return (IPADM_INVALID_ARG); 962 963 if ((err = plen2mask(prefixlen, af, (struct sockaddr *)&netmask)) != 0) 964 return (ipadm_errno2status(err)); 965 966 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 967 968 bzero(&lifr, sizeof (lifr)); 969 i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name, 970 sizeof (lifr.lifr_name)); 971 (void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask)); 972 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) 973 return (ipadm_errno2status(errno)); 974 975 /* now, change the broadcast address to reflect the prefixlen */ 976 if (af == AF_INET) { 977 /* 978 * get the interface address and set it, this should reset 979 * the broadcast address. 980 */ 981 (void) ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr); 982 (void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr); 983 } 984 985 return (IPADM_SUCCESS); 986 } 987 988 989 /* 990 * Callback function that sets the given value `pval' to one of the 991 * properties among `deprecated', `private', and `transmit' as defined in 992 * `pdp', on the address object in `arg'. 993 */ 994 /* ARGSUSED */ 995 static ipadm_status_t 996 i_ipadm_set_addr_flag(ipadm_handle_t iph, const void *arg, 997 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags) 998 { 999 char lifname[LIFNAMSIZ]; 1000 uint64_t on_flags = 0, off_flags = 0; 1001 boolean_t on; 1002 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 1003 1004 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP && 1005 strcmp(pdp->ipd_name, "deprecated") == 0) 1006 return (IPADM_NOTSUP); 1007 1008 if (strcmp(pval, IPADM_ONSTR) == 0) 1009 on = B_TRUE; 1010 else if (strcmp(pval, IPADM_OFFSTR) == 0) 1011 on = B_FALSE; 1012 else 1013 return (IPADM_INVALID_ARG); 1014 1015 if (strcmp(pdp->ipd_name, "private") == 0) { 1016 if (on) 1017 on_flags = IFF_PRIVATE; 1018 else 1019 off_flags = IFF_PRIVATE; 1020 } else if (strcmp(pdp->ipd_name, "transmit") == 0) { 1021 if (on) 1022 off_flags = IFF_NOXMIT; 1023 else 1024 on_flags = IFF_NOXMIT; 1025 } else if (strcmp(pdp->ipd_name, "deprecated") == 0) { 1026 if (on) 1027 on_flags = IFF_DEPRECATED; 1028 else 1029 off_flags = IFF_DEPRECATED; 1030 } else { 1031 return (IPADM_PROP_UNKNOWN); 1032 } 1033 1034 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 1035 return (i_ipadm_set_flags(iph, lifname, af, on_flags, off_flags)); 1036 } 1037 1038 /* 1039 * Callback function that sets the property `zone' on the address 1040 * object in `arg' to the value in `pval'. 1041 */ 1042 /* ARGSUSED */ 1043 static ipadm_status_t 1044 i_ipadm_set_zone(ipadm_handle_t iph, const void *arg, 1045 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags) 1046 { 1047 struct lifreq lifr; 1048 zoneid_t zoneid; 1049 int s; 1050 1051 /* 1052 * To modify the zone assignment such that it persists across 1053 * reboots, zonecfg(1M) must be used. 1054 */ 1055 if (flags & IPADM_OPT_PERSIST) { 1056 return (IPADM_NOTSUP); 1057 } else if (flags & IPADM_OPT_ACTIVE) { 1058 /* put logical interface into all zones */ 1059 if (strcmp(pval, "all-zones") == 0) { 1060 zoneid = ALL_ZONES; 1061 } else { 1062 /* zone must be ready or running */ 1063 if ((zoneid = getzoneidbyname(pval)) == -1) 1064 return (ipadm_errno2status(errno)); 1065 } 1066 } else { 1067 return (IPADM_INVALID_ARG); 1068 } 1069 1070 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 1071 bzero(&lifr, sizeof (lifr)); 1072 i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name, 1073 sizeof (lifr.lifr_name)); 1074 lifr.lifr_zoneid = zoneid; 1075 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0) 1076 return (ipadm_errno2status(errno)); 1077 1078 return (IPADM_SUCCESS); 1079 } 1080 1081 /* 1082 * Callback function that sets the property `reqhost' on the address 1083 * object in `arg' to the value in `pval'. 1084 */ 1085 /* ARGSUSED */ 1086 static ipadm_status_t 1087 i_ipadm_set_reqhost(ipadm_handle_t iph, const void *arg, 1088 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags) 1089 { 1090 ipadm_status_t status; 1091 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 1092 1093 if (ipaddr->ipadm_atype != IPADM_ADDR_DHCP) 1094 return (IPADM_NOTSUP); 1095 1096 /* 1097 * If requested to set reqhost just from active config but the 1098 * address is not in active config, return error. 1099 */ 1100 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE) && 1101 (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) { 1102 return (IPADM_NOTFOUND); 1103 } 1104 1105 status = ipadm_set_reqhost(ipaddr, pval); 1106 if (status != IPADM_SUCCESS) 1107 return (status); 1108 1109 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) { 1110 status = i_ipadm_refresh_dhcp(ipaddr); 1111 1112 /* 1113 * We do not report a problem for IPADM_DHCP_IPC_TIMEOUT since 1114 * it is only a soft error to indicate the caller that the 1115 * lease might be renewed after the function returns. 1116 */ 1117 if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT) 1118 return (status); 1119 } 1120 1121 status = i_ipadm_set_aobj_addrprop(iph, ipaddr, flags, 1122 IPADM_NVP_REQHOST); 1123 return (status); 1124 } 1125 1126 /* 1127 * Used by address object property callback functions that need to do a 1128 * two-stage update because the addrprop is cached on the address object. 1129 */ 1130 static ipadm_status_t 1131 i_ipadm_set_aobj_addrprop(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, 1132 uint_t flags, const char *propname) 1133 { 1134 ipadm_status_t status; 1135 uint32_t two_stage_flags; 1136 1137 /* 1138 * Send the updated address object information to ipmgmtd, since the 1139 * cached version of an addrprop resides on an aobjmap, but do 1140 * not change the ACTIVE/PERSIST state of the aobjmap. Instead, request 1141 * a two-stage, SET_PROPS update with ACTIVE/PERSIST as the first stage 1142 * per the existing aobjmap flags and a second stage encoded in 1143 * IPADM_OPT_PERSIST_PROPS. 1144 */ 1145 two_stage_flags = (flags | IPADM_OPT_SET_PROPS) 1146 & ~(IPADM_OPT_ACTIVE | IPADM_OPT_PERSIST); 1147 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) 1148 two_stage_flags |= IPADM_OPT_ACTIVE; 1149 if (ipaddr->ipadm_flags & IPMGMT_PERSIST) 1150 two_stage_flags |= IPADM_OPT_PERSIST; 1151 if (flags & IPADM_OPT_PERSIST) 1152 two_stage_flags |= IPADM_OPT_PERSIST_PROPS; 1153 1154 status = i_ipadm_addr_persist(iph, ipaddr, B_FALSE, two_stage_flags, 1155 propname); 1156 return (status); 1157 } 1158 1159 /* 1160 * Callback function that gets the property `broadcast' for the address 1161 * object in `arg'. 1162 */ 1163 /* ARGSUSED */ 1164 static ipadm_status_t 1165 i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg, 1166 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 1167 uint_t valtype) 1168 { 1169 struct sockaddr_in *sin; 1170 struct lifreq lifr; 1171 char lifname[LIFNAMSIZ]; 1172 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 1173 ipadm_status_t status; 1174 size_t nbytes = 0; 1175 uint64_t ifflags = 0; 1176 1177 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 1178 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) { 1179 status = i_ipadm_get_flags(iph, lifname, af, &ifflags); 1180 if (status != IPADM_SUCCESS) 1181 return (status); 1182 if (!(ifflags & IFF_BROADCAST)) { 1183 buf[0] = '\0'; 1184 return (IPADM_SUCCESS); 1185 } 1186 } 1187 1188 switch (valtype) { 1189 case MOD_PROP_DEFAULT: { 1190 struct sockaddr_storage mask; 1191 struct in_addr broadaddr; 1192 uint_t plen; 1193 in_addr_t addr, maddr; 1194 char val[MAXPROPVALLEN]; 1195 uint_t valsz = MAXPROPVALLEN; 1196 ipadm_status_t status; 1197 int err; 1198 struct sockaddr_in *sin; 1199 1200 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) { 1201 /* 1202 * Since the address is unknown we cannot 1203 * obtain default prefixlen 1204 */ 1205 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP || 1206 ipaddr->ipadm_af == AF_INET6) { 1207 buf[0] = '\0'; 1208 return (IPADM_SUCCESS); 1209 } 1210 /* 1211 * For the static address, we get the address from the 1212 * persistent db. 1213 */ 1214 status = i_ipadm_get_static_addr_db(iph, ipaddr); 1215 if (status != IPADM_SUCCESS) 1216 return (status); 1217 sin = SIN(&ipaddr->ipadm_static_addr); 1218 addr = sin->sin_addr.s_addr; 1219 } else { 1220 /* 1221 * If the address object is active, we retrieve the 1222 * address from kernel. 1223 */ 1224 bzero(&lifr, sizeof (lifr)); 1225 (void) strlcpy(lifr.lifr_name, lifname, 1226 sizeof (lifr.lifr_name)); 1227 if (ioctl(iph->iph_sock, SIOCGLIFADDR, 1228 (caddr_t)&lifr) < 0) 1229 return (ipadm_errno2status(errno)); 1230 1231 addr = (SIN(&lifr.lifr_addr))->sin_addr.s_addr; 1232 } 1233 /* 1234 * For default broadcast address, get the address and the 1235 * default prefixlen for that address and then compute the 1236 * broadcast address. 1237 */ 1238 status = i_ipadm_get_prefixlen(iph, arg, NULL, val, &valsz, af, 1239 MOD_PROP_DEFAULT); 1240 if (status != IPADM_SUCCESS) 1241 return (status); 1242 1243 plen = atoi(val); 1244 if ((err = plen2mask(plen, AF_INET, 1245 (struct sockaddr *)&mask)) != 0) 1246 return (ipadm_errno2status(err)); 1247 maddr = (SIN(&mask))->sin_addr.s_addr; 1248 broadaddr.s_addr = (addr & maddr) | ~maddr; 1249 nbytes = snprintf(buf, *bufsize, "%s", inet_ntoa(broadaddr)); 1250 break; 1251 } 1252 case MOD_PROP_ACTIVE: 1253 bzero(&lifr, sizeof (lifr)); 1254 (void) strlcpy(lifr.lifr_name, lifname, 1255 sizeof (lifr.lifr_name)); 1256 if (ioctl(iph->iph_sock, SIOCGLIFBRDADDR, 1257 (caddr_t)&lifr) < 0) { 1258 return (ipadm_errno2status(errno)); 1259 } else { 1260 sin = SIN(&lifr.lifr_addr); 1261 nbytes = snprintf(buf, *bufsize, "%s", 1262 inet_ntoa(sin->sin_addr)); 1263 } 1264 break; 1265 default: 1266 return (IPADM_INVALID_ARG); 1267 } 1268 if (nbytes >= *bufsize) { 1269 /* insufficient buffer space */ 1270 *bufsize = nbytes + 1; 1271 return (IPADM_NO_BUFS); 1272 } 1273 return (IPADM_SUCCESS); 1274 } 1275 1276 /* 1277 * Callback function that retrieves the value of the property `prefixlen' 1278 * for the address object in `arg'. 1279 */ 1280 /* ARGSUSED */ 1281 static ipadm_status_t 1282 i_ipadm_get_prefixlen(ipadm_handle_t iph, const void *arg, 1283 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 1284 uint_t valtype) 1285 { 1286 struct lifreq lifr; 1287 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 1288 char lifname[LIFNAMSIZ]; 1289 int s; 1290 uint32_t prefixlen; 1291 size_t nbytes; 1292 ipadm_status_t status; 1293 uint64_t lifflags; 1294 1295 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 1296 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) { 1297 status = i_ipadm_get_flags(iph, lifname, af, &lifflags); 1298 if (status != IPADM_SUCCESS) { 1299 return (status); 1300 } else if (lifflags & IFF_POINTOPOINT) { 1301 buf[0] = '\0'; 1302 return (status); 1303 } 1304 } 1305 1306 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 1307 bzero(&lifr, sizeof (lifr)); 1308 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name)); 1309 switch (valtype) { 1310 case MOD_PROP_POSSIBLE: 1311 if (af == AF_INET) 1312 nbytes = snprintf(buf, *bufsize, "1-30,32"); 1313 else 1314 nbytes = snprintf(buf, *bufsize, "1-126,128"); 1315 break; 1316 case MOD_PROP_DEFAULT: 1317 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) { 1318 /* 1319 * For static addresses, we retrieve the address 1320 * from kernel if it is active. 1321 */ 1322 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0) 1323 return (ipadm_errno2status(errno)); 1324 status = i_ipadm_get_default_prefixlen( 1325 &lifr.lifr_addr, &prefixlen); 1326 if (status != IPADM_SUCCESS) 1327 return (status); 1328 } else if ((ipaddr->ipadm_flags & IPMGMT_PERSIST) && 1329 ipaddr->ipadm_atype == IPADM_ADDR_DHCP) { 1330 /* 1331 * Since the address is unknown we cannot 1332 * obtain default prefixlen 1333 */ 1334 buf[0] = '\0'; 1335 return (IPADM_SUCCESS); 1336 } else { 1337 /* 1338 * If not in active config, we use the address 1339 * from persistent store. 1340 */ 1341 status = i_ipadm_get_static_addr_db(iph, ipaddr); 1342 if (status != IPADM_SUCCESS) 1343 return (status); 1344 status = i_ipadm_get_default_prefixlen( 1345 &ipaddr->ipadm_static_addr, &prefixlen); 1346 if (status != IPADM_SUCCESS) 1347 return (status); 1348 } 1349 nbytes = snprintf(buf, *bufsize, "%u", prefixlen); 1350 break; 1351 case MOD_PROP_ACTIVE: 1352 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0) 1353 return (ipadm_errno2status(errno)); 1354 prefixlen = lifr.lifr_addrlen; 1355 nbytes = snprintf(buf, *bufsize, "%u", prefixlen); 1356 break; 1357 default: 1358 return (IPADM_INVALID_ARG); 1359 } 1360 if (nbytes >= *bufsize) { 1361 /* insufficient buffer space */ 1362 *bufsize = nbytes + 1; 1363 return (IPADM_NO_BUFS); 1364 } 1365 return (IPADM_SUCCESS); 1366 } 1367 1368 /* 1369 * Callback function that retrieves the value of one of the properties 1370 * among `deprecated', `private', and `transmit' for the address object 1371 * in `arg'. 1372 */ 1373 /* ARGSUSED */ 1374 static ipadm_status_t 1375 i_ipadm_get_addr_flag(ipadm_handle_t iph, const void *arg, 1376 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 1377 uint_t valtype) 1378 { 1379 boolean_t on = B_FALSE; 1380 char lifname[LIFNAMSIZ]; 1381 ipadm_status_t status = IPADM_SUCCESS; 1382 uint64_t ifflags; 1383 size_t nbytes; 1384 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 1385 1386 switch (valtype) { 1387 case MOD_PROP_DEFAULT: 1388 if (strcmp(pdp->ipd_name, "private") == 0 || 1389 strcmp(pdp->ipd_name, "deprecated") == 0) { 1390 on = B_FALSE; 1391 } else if (strcmp(pdp->ipd_name, "transmit") == 0) { 1392 on = B_TRUE; 1393 } else { 1394 return (IPADM_PROP_UNKNOWN); 1395 } 1396 break; 1397 case MOD_PROP_ACTIVE: 1398 /* 1399 * If the address is present in active configuration, we 1400 * retrieve it from kernel to get the property value. 1401 * Else, there is no value to return. 1402 */ 1403 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 1404 status = i_ipadm_get_flags(iph, lifname, af, &ifflags); 1405 if (status != IPADM_SUCCESS) 1406 return (status); 1407 if (strcmp(pdp->ipd_name, "private") == 0) 1408 on = (ifflags & IFF_PRIVATE); 1409 else if (strcmp(pdp->ipd_name, "transmit") == 0) 1410 on = !(ifflags & IFF_NOXMIT); 1411 else if (strcmp(pdp->ipd_name, "deprecated") == 0) 1412 on = (ifflags & IFF_DEPRECATED); 1413 break; 1414 default: 1415 return (IPADM_INVALID_ARG); 1416 } 1417 nbytes = snprintf(buf, *bufsize, "%s", 1418 (on ? IPADM_ONSTR : IPADM_OFFSTR)); 1419 if (nbytes >= *bufsize) { 1420 /* insufficient buffer space */ 1421 *bufsize = nbytes + 1; 1422 status = IPADM_NO_BUFS; 1423 } 1424 1425 return (status); 1426 } 1427 1428 /* 1429 * Callback function that retrieves the value of the property `zone' 1430 * for the address object in `arg'. 1431 */ 1432 /* ARGSUSED */ 1433 static ipadm_status_t 1434 i_ipadm_get_zone(ipadm_handle_t iph, const void *arg, 1435 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 1436 uint_t valtype) 1437 { 1438 struct lifreq lifr; 1439 char zone_name[ZONENAME_MAX]; 1440 int s; 1441 size_t nbytes = 0; 1442 1443 if (iph->iph_zoneid != GLOBAL_ZONEID) { 1444 buf[0] = '\0'; 1445 return (IPADM_SUCCESS); 1446 } 1447 1448 /* 1449 * we are in global zone. See if the lifname is assigned to shared-ip 1450 * zone or global zone. 1451 */ 1452 switch (valtype) { 1453 case MOD_PROP_DEFAULT: 1454 if (getzonenamebyid(GLOBAL_ZONEID, zone_name, 1455 sizeof (zone_name)) > 0) 1456 nbytes = snprintf(buf, *bufsize, "%s", zone_name); 1457 else 1458 return (ipadm_errno2status(errno)); 1459 break; 1460 case MOD_PROP_ACTIVE: 1461 bzero(&lifr, sizeof (lifr)); 1462 i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name, 1463 sizeof (lifr.lifr_name)); 1464 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 1465 1466 if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) == -1) 1467 return (ipadm_errno2status(errno)); 1468 1469 if (lifr.lifr_zoneid == ALL_ZONES) { 1470 nbytes = snprintf(buf, *bufsize, "%s", "all-zones"); 1471 } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name, 1472 sizeof (zone_name)) < 0) { 1473 return (ipadm_errno2status(errno)); 1474 } else { 1475 nbytes = snprintf(buf, *bufsize, "%s", zone_name); 1476 } 1477 break; 1478 default: 1479 return (IPADM_INVALID_ARG); 1480 } 1481 if (nbytes >= *bufsize) { 1482 /* insufficient buffer space */ 1483 *bufsize = nbytes + 1; 1484 return (IPADM_NO_BUFS); 1485 } 1486 1487 return (IPADM_SUCCESS); 1488 } 1489 1490 /* 1491 * Callback function that retrieves the value of the property `primary' 1492 * for the address object in `arg'. 1493 */ 1494 /* ARGSUSED */ 1495 static ipadm_status_t 1496 i_ipadm_get_primary(ipadm_handle_t iph, const void *arg, 1497 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 1498 uint_t valtype) 1499 { 1500 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 1501 const char *onoff = ""; 1502 size_t nbytes; 1503 1504 switch (valtype) { 1505 case MOD_PROP_DEFAULT: 1506 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP) 1507 onoff = IPADM_OFFSTR; 1508 break; 1509 case MOD_PROP_ACTIVE: 1510 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP) { 1511 dhcp_status_t dhcp_status; 1512 ipadm_status_t ipc_status; 1513 int error; 1514 1515 ipc_status = i_ipadm_dhcp_status(ipaddr, &dhcp_status, 1516 &error); 1517 if (ipc_status != IPADM_SUCCESS && 1518 ipc_status != IPADM_NOTFOUND) 1519 return (ipc_status); 1520 1521 onoff = dhcp_status.if_dflags & DHCP_IF_PRIMARY ? 1522 IPADM_ONSTR : IPADM_OFFSTR; 1523 } 1524 break; 1525 default: 1526 return (IPADM_INVALID_ARG); 1527 } 1528 1529 nbytes = strlcpy(buf, onoff, *bufsize); 1530 if (nbytes >= *bufsize) { 1531 /* insufficient buffer space */ 1532 *bufsize = nbytes + 1; 1533 return (IPADM_NO_BUFS); 1534 } 1535 1536 return (IPADM_SUCCESS); 1537 } 1538 1539 /* 1540 * Callback function that retrieves the value of the property `reqhost' 1541 * for the address object in `arg'. 1542 */ 1543 /* ARGSUSED */ 1544 static ipadm_status_t 1545 i_ipadm_get_reqhost(ipadm_handle_t iph, const void *arg, 1546 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af, 1547 uint_t valtype) 1548 { 1549 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg; 1550 const char *reqhost = ""; 1551 size_t nbytes; 1552 1553 switch (valtype) { 1554 case MOD_PROP_DEFAULT: 1555 break; 1556 case MOD_PROP_ACTIVE: 1557 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP) 1558 reqhost = ipaddr->ipadm_reqhost; 1559 break; 1560 default: 1561 return (IPADM_INVALID_ARG); 1562 } 1563 1564 nbytes = strlcpy(buf, reqhost, *bufsize); 1565 if (nbytes >= *bufsize) { 1566 /* insufficient buffer space */ 1567 *bufsize = nbytes + 1; 1568 return (IPADM_NO_BUFS); 1569 } 1570 1571 return (IPADM_SUCCESS); 1572 } 1573 1574 static ipadm_prop_desc_t * 1575 i_ipadm_get_addrprop_desc(const char *pname) 1576 { 1577 int i; 1578 1579 for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) { 1580 if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 || 1581 (ipadm_addrprop_table[i].ipd_old_name != NULL && 1582 strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0)) 1583 return (&ipadm_addrprop_table[i]); 1584 } 1585 return (NULL); 1586 } 1587 1588 /* 1589 * Gets the value of the given address property `pname' for the address 1590 * object with name `aobjname'. 1591 */ 1592 ipadm_status_t 1593 ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf, 1594 uint_t *bufsize, const char *aobjname, uint_t valtype) 1595 { 1596 struct ipadm_addrobj_s ipaddr; 1597 ipadm_status_t status = IPADM_SUCCESS; 1598 sa_family_t af; 1599 ipadm_prop_desc_t *pdp = NULL; 1600 1601 if (iph == NULL || pname == NULL || buf == NULL || 1602 bufsize == NULL || *bufsize == 0 || aobjname == NULL) { 1603 return (IPADM_INVALID_ARG); 1604 } 1605 1606 /* find the property in the property description table */ 1607 if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL) 1608 return (IPADM_PROP_UNKNOWN); 1609 1610 /* 1611 * For the given aobjname, get the addrobj it represents and 1612 * retrieve the property value for that object. 1613 */ 1614 i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE); 1615 if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS) 1616 return (status); 1617 1618 if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF) 1619 return (IPADM_NOTSUP); 1620 af = ipaddr.ipadm_af; 1621 1622 /* 1623 * Call the appropriate callback function to based on the field 1624 * that was asked for. 1625 */ 1626 switch (valtype) { 1627 case IPADM_OPT_PERM: 1628 status = i_ipadm_pd2permstr(pdp, buf, bufsize); 1629 break; 1630 case IPADM_OPT_ACTIVE: 1631 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) { 1632 buf[0] = '\0'; 1633 } else { 1634 status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize, 1635 af, MOD_PROP_ACTIVE); 1636 } 1637 break; 1638 case IPADM_OPT_DEFAULT: 1639 status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize, 1640 af, MOD_PROP_DEFAULT); 1641 break; 1642 case IPADM_OPT_POSSIBLE: 1643 if (pdp->ipd_get_range != NULL) { 1644 status = pdp->ipd_get_range(iph, &ipaddr, pdp, buf, 1645 bufsize, af, MOD_PROP_POSSIBLE); 1646 break; 1647 } 1648 buf[0] = '\0'; 1649 break; 1650 case IPADM_OPT_PERSIST: 1651 status = i_ipadm_get_persist_propval(iph, pdp, buf, bufsize, 1652 &ipaddr); 1653 break; 1654 default: 1655 status = IPADM_INVALID_ARG; 1656 break; 1657 } 1658 1659 return (status); 1660 } 1661 1662 /* 1663 * Sets the value of the given address property `pname' to `pval' for the 1664 * address object with name `aobjname'. 1665 */ 1666 ipadm_status_t 1667 ipadm_set_addrprop(ipadm_handle_t iph, const char *pname, 1668 const char *pval, const char *aobjname, uint_t pflags) 1669 { 1670 struct ipadm_addrobj_s ipaddr; 1671 sa_family_t af; 1672 ipadm_prop_desc_t *pdp = NULL; 1673 char defbuf[MAXPROPVALLEN]; 1674 uint_t defbufsize = MAXPROPVALLEN; 1675 boolean_t reset = (pflags & IPADM_OPT_DEFAULT); 1676 ipadm_status_t status = IPADM_SUCCESS; 1677 1678 /* Check for solaris.network.interface.config authorization */ 1679 if (!ipadm_check_auth()) 1680 return (IPADM_EAUTH); 1681 1682 if (iph == NULL || pname == NULL || aobjname == NULL || pflags == 0 || 1683 pflags == IPADM_OPT_PERSIST || 1684 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT)) || 1685 (!reset && pval == NULL)) { 1686 return (IPADM_INVALID_ARG); 1687 } 1688 1689 /* find the property in the property description table */ 1690 if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL) 1691 return (IPADM_PROP_UNKNOWN); 1692 1693 if (pdp->ipd_set == NULL || (reset && pdp->ipd_get == NULL)) 1694 return (IPADM_NOTSUP); 1695 1696 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) && 1697 (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) { 1698 return (IPADM_INVALID_ARG); 1699 } 1700 1701 /* 1702 * For the given aobjname, get the addrobj it represents and 1703 * set the property value for that object. 1704 */ 1705 i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE); 1706 if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS) 1707 return (status); 1708 1709 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) 1710 return (IPADM_OP_DISABLE_OBJ); 1711 1712 /* Persistent operation not allowed on a temporary object. */ 1713 if ((pflags & IPADM_OPT_PERSIST) && 1714 !(ipaddr.ipadm_flags & IPMGMT_PERSIST)) 1715 return (IPADM_TEMPORARY_OBJ); 1716 1717 /* 1718 * Currently, setting an address property on an address object of type 1719 * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves 1720 * in.ndpd retrieving the address properties from ipmgmtd for given 1721 * address object and then setting them on auto-configured addresses, 1722 * whenever in.ndpd gets a new prefix. This will be supported in 1723 * future releases. 1724 */ 1725 if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF) 1726 return (IPADM_NOTSUP); 1727 1728 /* 1729 * Setting an address property on an address object that is 1730 * not present in active configuration is not supported. 1731 */ 1732 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) 1733 return (IPADM_NOTSUP); 1734 1735 af = ipaddr.ipadm_af; 1736 if (reset) { 1737 /* 1738 * If we were asked to reset the value, we need to fetch 1739 * the default value and set the default value. 1740 */ 1741 status = pdp->ipd_get(iph, &ipaddr, pdp, defbuf, &defbufsize, 1742 af, MOD_PROP_DEFAULT); 1743 if (status != IPADM_SUCCESS) 1744 return (status); 1745 pval = defbuf; 1746 } 1747 /* set the user provided or default property value */ 1748 status = pdp->ipd_set(iph, &ipaddr, pdp, pval, af, pflags); 1749 if (status != IPADM_SUCCESS) 1750 return (status); 1751 1752 /* 1753 * If IPADM_OPT_PERSIST was set in `flags', we need to store 1754 * property and its value in persistent DB. 1755 */ 1756 if (pflags & IPADM_OPT_PERSIST) { 1757 status = i_ipadm_persist_propval(iph, pdp, pval, &ipaddr, 1758 pflags); 1759 } 1760 1761 return (status); 1762 } 1763 1764 /* 1765 * Remove the address specified by the address object in `addr' 1766 * from kernel. If the address is on a non-zero logical interface, we do a 1767 * SIOCLIFREMOVEIF, otherwise we set the address to INADDR_ANY for IPv4 or 1768 * :: for IPv6. 1769 */ 1770 ipadm_status_t 1771 i_ipadm_delete_addr(ipadm_handle_t iph, ipadm_addrobj_t addr) 1772 { 1773 struct lifreq lifr; 1774 int sock; 1775 ipadm_status_t status; 1776 1777 bzero(&lifr, sizeof (lifr)); 1778 i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name)); 1779 sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : iph->iph_sock6); 1780 if (addr->ipadm_lifnum == 0) { 1781 /* 1782 * Fake the deletion of the 0'th address by 1783 * clearing IFF_UP and setting it to as 0.0.0.0 or ::. 1784 */ 1785 status = i_ipadm_set_flags(iph, addr->ipadm_ifname, 1786 addr->ipadm_af, 0, IFF_UP); 1787 if (status != IPADM_SUCCESS) 1788 return (status); 1789 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr)); 1790 lifr.lifr_addr.ss_family = addr->ipadm_af; 1791 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) 1792 return (ipadm_errno2status(errno)); 1793 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) 1794 return (ipadm_errno2status(errno)); 1795 } else if (ioctl(sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) { 1796 return (ipadm_errno2status(errno)); 1797 } 1798 1799 return (IPADM_SUCCESS); 1800 } 1801 1802 /* 1803 * Extracts the IPv6 address from the nvlist in `nvl'. 1804 */ 1805 ipadm_status_t 1806 i_ipadm_nvl2in6_addr(nvlist_t *nvl, char *addr_type, in6_addr_t *in6_addr) 1807 { 1808 uint8_t *addr6; 1809 uint_t n; 1810 1811 if (nvlist_lookup_uint8_array(nvl, addr_type, &addr6, &n) != 0) 1812 return (IPADM_NOTFOUND); 1813 assert(n == 16); 1814 bcopy(addr6, in6_addr->s6_addr, n); 1815 return (IPADM_SUCCESS); 1816 } 1817 1818 /* 1819 * Used to validate the given addrobj name string. Length of `aobjname' 1820 * cannot exceed IPADM_AOBJ_USTRSIZ. `aobjname' should start with an 1821 * alphabetic character and it can only contain alphanumeric characters. 1822 */ 1823 static boolean_t 1824 i_ipadm_is_user_aobjname_valid(const char *aobjname) 1825 { 1826 const char *cp; 1827 1828 if (aobjname == NULL || strlen(aobjname) >= IPADM_AOBJ_USTRSIZ || 1829 !isalpha(*aobjname)) { 1830 return (B_FALSE); 1831 } 1832 for (cp = aobjname + 1; *cp && isalnum(*cp); cp++) 1833 ; 1834 return (*cp == '\0'); 1835 } 1836 1837 /* 1838 * Computes the prefixlen for the given `addr' based on the netmask found using 1839 * the order specified in /etc/nsswitch.conf. If not found, then the 1840 * prefixlen is computed using the Classful subnetting semantics defined 1841 * in RFC 791 for IPv4 and RFC 4291 for IPv6. 1842 */ 1843 static ipadm_status_t 1844 i_ipadm_get_default_prefixlen(struct sockaddr_storage *addr, uint32_t *plen) 1845 { 1846 sa_family_t af = addr->ss_family; 1847 struct sockaddr_storage mask; 1848 struct sockaddr_in *m = (struct sockaddr_in *)&mask; 1849 struct sockaddr_in6 *sin6; 1850 struct sockaddr_in *sin; 1851 struct in_addr ia; 1852 uint32_t prefixlen = 0; 1853 1854 switch (af) { 1855 case AF_INET: 1856 sin = SIN(addr); 1857 ia.s_addr = ntohl(sin->sin_addr.s_addr); 1858 get_netmask4(&ia, &m->sin_addr); 1859 m->sin_addr.s_addr = htonl(m->sin_addr.s_addr); 1860 m->sin_family = AF_INET; 1861 prefixlen = mask2plen((struct sockaddr *)&mask); 1862 break; 1863 case AF_INET6: 1864 sin6 = SIN6(addr); 1865 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 1866 prefixlen = 10; 1867 else 1868 prefixlen = 64; 1869 break; 1870 default: 1871 return (IPADM_INVALID_ARG); 1872 } 1873 *plen = prefixlen; 1874 return (IPADM_SUCCESS); 1875 } 1876 1877 ipadm_status_t 1878 i_ipadm_resolve_addr(const char *name, sa_family_t af, 1879 struct sockaddr_storage *ss) 1880 { 1881 struct addrinfo hints, *ai; 1882 int rc; 1883 struct sockaddr_in6 *sin6; 1884 struct sockaddr_in *sin; 1885 boolean_t is_mapped; 1886 1887 (void) memset(&hints, 0, sizeof (hints)); 1888 hints.ai_family = af; 1889 hints.ai_flags = (AI_ALL | AI_V4MAPPED); 1890 rc = getaddrinfo(name, NULL, &hints, &ai); 1891 if (rc != 0) { 1892 if (rc == EAI_NONAME) 1893 return (IPADM_BAD_ADDR); 1894 else 1895 return (IPADM_FAILURE); 1896 } 1897 if (ai->ai_next != NULL) { 1898 /* maps to more than one hostname */ 1899 freeaddrinfo(ai); 1900 return (IPADM_BAD_HOSTNAME); 1901 } 1902 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1903 is_mapped = IN6_IS_ADDR_V4MAPPED(&(SIN6(ai->ai_addr))->sin6_addr); 1904 if (is_mapped) { 1905 sin = SIN(ss); 1906 sin->sin_family = AF_INET; 1907 /* LINTED E_BAD_PTR_CAST_ALIGN */ 1908 IN6_V4MAPPED_TO_INADDR(&(SIN6(ai->ai_addr))->sin6_addr, 1909 &sin->sin_addr); 1910 } else { 1911 sin6 = SIN6(ss); 1912 sin6->sin6_family = AF_INET6; 1913 bcopy(ai->ai_addr, sin6, sizeof (*sin6)); 1914 } 1915 freeaddrinfo(ai); 1916 return (IPADM_SUCCESS); 1917 } 1918 1919 /* 1920 * This takes a static address string <addr>[/<mask>] or a hostname 1921 * and maps it to a single numeric IP address, consulting DNS if 1922 * hostname was provided. If a specific address family was requested, 1923 * an error is returned if the given hostname does not map to an address 1924 * of the given family. Note that this function returns failure 1925 * if the name maps to more than one IP address. 1926 */ 1927 ipadm_status_t 1928 ipadm_set_addr(ipadm_addrobj_t ipaddr, const char *astr, sa_family_t af) 1929 { 1930 char *prefixlenstr; 1931 uint32_t prefixlen = 0; 1932 char *endp; 1933 /* 1934 * We use (NI_MAXHOST + 5) because the longest possible 1935 * astr will have (NI_MAXHOST + '/' + {a maximum of 32 for IPv4 1936 * or a maximum of 128 for IPv6 + '\0') chars 1937 */ 1938 char addrstr[NI_MAXHOST + 5]; 1939 ipadm_status_t status; 1940 1941 (void) snprintf(addrstr, sizeof (addrstr), "%s", astr); 1942 if ((prefixlenstr = strchr(addrstr, '/')) != NULL) { 1943 *prefixlenstr++ = '\0'; 1944 errno = 0; 1945 prefixlen = strtoul(prefixlenstr, &endp, 10); 1946 if (errno != 0 || *endp != '\0') 1947 return (IPADM_INVALID_ARG); 1948 if ((af == AF_INET && prefixlen > IP_ABITS) || 1949 (af == AF_INET6 && prefixlen > IPV6_ABITS)) 1950 return (IPADM_INVALID_ARG); 1951 } 1952 1953 status = i_ipadm_resolve_addr(addrstr, af, &ipaddr->ipadm_static_addr); 1954 if (status == IPADM_SUCCESS) { 1955 (void) strlcpy(ipaddr->ipadm_static_aname, addrstr, 1956 sizeof (ipaddr->ipadm_static_aname)); 1957 ipaddr->ipadm_af = ipaddr->ipadm_static_addr.ss_family; 1958 ipaddr->ipadm_static_prefixlen = prefixlen; 1959 } 1960 return (status); 1961 } 1962 1963 /* 1964 * Gets the static source address from the address object in `ipaddr'. 1965 * Memory for `addr' should be already allocated by the caller. 1966 */ 1967 ipadm_status_t 1968 ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr) 1969 { 1970 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC || 1971 addr == NULL) { 1972 return (IPADM_INVALID_ARG); 1973 } 1974 *addr = ipaddr->ipadm_static_addr; 1975 1976 return (IPADM_SUCCESS); 1977 } 1978 1979 /* 1980 * Set up tunnel destination address in ipaddr by contacting DNS. 1981 * The function works similar to ipadm_set_addr(). 1982 * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned 1983 * if dst_addr resolves to more than one address. The caller has to verify 1984 * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family 1985 */ 1986 ipadm_status_t 1987 ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af) 1988 { 1989 ipadm_status_t status; 1990 1991 /* mask lengths are not meaningful for point-to-point interfaces. */ 1992 if (strchr(daddrstr, '/') != NULL) 1993 return (IPADM_BAD_ADDR); 1994 1995 status = i_ipadm_resolve_addr(daddrstr, af, 1996 &ipaddr->ipadm_static_dst_addr); 1997 if (status == IPADM_SUCCESS) { 1998 (void) strlcpy(ipaddr->ipadm_static_dname, daddrstr, 1999 sizeof (ipaddr->ipadm_static_dname)); 2000 } 2001 return (status); 2002 } 2003 2004 /* 2005 * Sets the interface ID in the address object `ipaddr' with the address 2006 * in the string `interface_id'. This interface ID will be used when 2007 * ipadm_create_addr() is called with `ipaddr' with address type 2008 * set to IPADM_ADDR_IPV6_ADDRCONF. 2009 */ 2010 ipadm_status_t 2011 ipadm_set_interface_id(ipadm_addrobj_t ipaddr, const char *interface_id) 2012 { 2013 struct sockaddr_in6 *sin6; 2014 char *end; 2015 char *cp; 2016 uint32_t prefixlen; 2017 char addrstr[INET6_ADDRSTRLEN + 1]; 2018 2019 if (ipaddr == NULL || interface_id == NULL || 2020 ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF) 2021 return (IPADM_INVALID_ARG); 2022 2023 (void) strlcpy(addrstr, interface_id, sizeof (addrstr)); 2024 if ((cp = strchr(addrstr, '/')) == NULL) 2025 return (IPADM_INVALID_ARG); 2026 *cp++ = '\0'; 2027 sin6 = &ipaddr->ipadm_intfid; 2028 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) == 1) { 2029 errno = 0; 2030 prefixlen = strtoul(cp, &end, 10); 2031 if (errno != 0 || *end != '\0' || prefixlen > IPV6_ABITS) 2032 return (IPADM_INVALID_ARG); 2033 sin6->sin6_family = AF_INET6; 2034 ipaddr->ipadm_intfidlen = prefixlen; 2035 return (IPADM_SUCCESS); 2036 } 2037 return (IPADM_INVALID_ARG); 2038 } 2039 2040 /* 2041 * Sets the value for the field `ipadm_stateless' in address object `ipaddr'. 2042 */ 2043 ipadm_status_t 2044 ipadm_set_stateless(ipadm_addrobj_t ipaddr, boolean_t stateless) 2045 { 2046 if (ipaddr == NULL || 2047 ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF) 2048 return (IPADM_INVALID_ARG); 2049 ipaddr->ipadm_stateless = stateless; 2050 2051 return (IPADM_SUCCESS); 2052 } 2053 2054 /* 2055 * Sets the value for the field `ipadm_stateful' in address object `ipaddr'. 2056 */ 2057 ipadm_status_t 2058 ipadm_set_stateful(ipadm_addrobj_t ipaddr, boolean_t stateful) 2059 { 2060 if (ipaddr == NULL || 2061 ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF) 2062 return (IPADM_INVALID_ARG); 2063 ipaddr->ipadm_stateful = stateful; 2064 2065 return (IPADM_SUCCESS); 2066 } 2067 2068 /* 2069 * Sets the dhcp parameter `ipadm_primary' in the address object `ipaddr'. 2070 * The field is used during the address creation with address 2071 * type IPADM_ADDR_DHCP. It specifies if the interface should be set 2072 * as a primary interface for getting dhcp global options from the DHCP server. 2073 */ 2074 ipadm_status_t 2075 ipadm_set_primary(ipadm_addrobj_t ipaddr, boolean_t primary) 2076 { 2077 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP) 2078 return (IPADM_INVALID_ARG); 2079 ipaddr->ipadm_primary = primary; 2080 2081 return (IPADM_SUCCESS); 2082 } 2083 2084 /* 2085 * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'. 2086 * This field is used during the address creation with address type 2087 * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr() 2088 * should wait before returning while the dhcp address is being acquired 2089 * by the dhcpagent. 2090 * Possible values: 2091 * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns. 2092 * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning. 2093 * - <integer> : Wait the specified number of seconds before returning. 2094 */ 2095 ipadm_status_t 2096 ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait) 2097 { 2098 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP) 2099 return (IPADM_INVALID_ARG); 2100 ipaddr->ipadm_wait = wait; 2101 return (IPADM_SUCCESS); 2102 } 2103 2104 /* 2105 * Sets the dhcp parameter `ipadm_reqhost' in the address object `ipaddr', 2106 * but validate any non-nil value using ipadm_is_valid_hostname() and also 2107 * check length. 2108 */ 2109 ipadm_status_t 2110 ipadm_set_reqhost(ipadm_addrobj_t ipaddr, const char *reqhost) 2111 { 2112 const size_t HNLEN = sizeof (ipaddr->ipadm_reqhost); 2113 2114 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP) 2115 return (IPADM_INVALID_ARG); 2116 2117 if (ipadm_is_nil_hostname(reqhost)) 2118 *ipaddr->ipadm_reqhost = '\0'; 2119 else if (!ipadm_is_valid_hostname(reqhost)) 2120 return (IPADM_INVALID_ARG); 2121 else if (strlcpy(ipaddr->ipadm_reqhost, reqhost, HNLEN) >= HNLEN) 2122 return (IPADM_INVALID_ARG); 2123 return (IPADM_SUCCESS); 2124 } 2125 2126 /* 2127 * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'. 2128 * If the `aobjname' already exists in the daemon's `aobjmap' then 2129 * IPADM_ADDROBJ_EXISTS will be returned. 2130 * 2131 * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the 2132 * daemon will generate an `aobjname' for the given `ipaddr'. 2133 */ 2134 ipadm_status_t 2135 i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr) 2136 { 2137 ipmgmt_aobjop_arg_t larg; 2138 ipmgmt_aobjop_rval_t rval, *rvalp; 2139 int err; 2140 2141 bzero(&larg, sizeof (larg)); 2142 larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD; 2143 (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname, 2144 sizeof (larg.ia_aobjname)); 2145 (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname, 2146 sizeof (larg.ia_ifname)); 2147 larg.ia_family = ipaddr->ipadm_af; 2148 larg.ia_atype = ipaddr->ipadm_atype; 2149 2150 rvalp = &rval; 2151 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp, 2152 sizeof (rval), B_FALSE); 2153 if (err == 0 && ipaddr->ipadm_aobjname[0] == '\0') { 2154 /* copy the daemon generated `aobjname' into `ipadddr' */ 2155 (void) strlcpy(ipaddr->ipadm_aobjname, rval.ir_aobjname, 2156 sizeof (ipaddr->ipadm_aobjname)); 2157 } 2158 if (err == EEXIST) 2159 return (IPADM_ADDROBJ_EXISTS); 2160 return (ipadm_errno2status(err)); 2161 } 2162 2163 /* 2164 * Sets the logical interface number in the ipmgmtd's memory map for the 2165 * address object `ipaddr'. If another address object has the same 2166 * logical interface number, IPADM_ADDROBJ_EXISTS is returned. 2167 */ 2168 ipadm_status_t 2169 i_ipadm_setlifnum_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr) 2170 { 2171 ipmgmt_aobjop_arg_t larg; 2172 ipmgmt_retval_t rval, *rvalp; 2173 int err; 2174 2175 if (iph->iph_flags & IPH_IPMGMTD) 2176 return (IPADM_SUCCESS); 2177 2178 bzero(&larg, sizeof (larg)); 2179 larg.ia_cmd = IPMGMT_CMD_ADDROBJ_SETLIFNUM; 2180 (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname, 2181 sizeof (larg.ia_aobjname)); 2182 larg.ia_lnum = ipaddr->ipadm_lifnum; 2183 (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname, 2184 sizeof (larg.ia_ifname)); 2185 larg.ia_family = ipaddr->ipadm_af; 2186 2187 rvalp = &rval; 2188 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp, 2189 sizeof (rval), B_FALSE); 2190 if (err == EEXIST) 2191 return (IPADM_ADDROBJ_EXISTS); 2192 return (ipadm_errno2status(err)); 2193 } 2194 2195 /* 2196 * Creates the IPv4 or IPv6 address in the nvlist `nvl' on the interface 2197 * `ifname'. If a hostname is present, it is resolved before the address 2198 * is created. 2199 */ 2200 ipadm_status_t 2201 i_ipadm_enable_static(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl, 2202 sa_family_t af) 2203 { 2204 char *prefixlenstr = NULL; 2205 char *upstr = NULL; 2206 char *sname = NULL, *dname = NULL; 2207 struct ipadm_addrobj_s ipaddr; 2208 char *aobjname = NULL; 2209 nvlist_t *nvaddr = NULL; 2210 nvpair_t *nvp; 2211 char *cidraddr; 2212 char *name; 2213 ipadm_status_t status; 2214 int err = 0; 2215 uint32_t flags = IPADM_OPT_ACTIVE; 2216 2217 /* retrieve the address information */ 2218 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 2219 nvp = nvlist_next_nvpair(nvl, nvp)) { 2220 name = nvpair_name(nvp); 2221 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0 || 2222 strcmp(name, IPADM_NVP_IPV6ADDR) == 0) { 2223 err = nvpair_value_nvlist(nvp, &nvaddr); 2224 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) { 2225 err = nvpair_value_string(nvp, &aobjname); 2226 } else if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) { 2227 err = nvpair_value_string(nvp, &prefixlenstr); 2228 } else if (strcmp(name, "up") == 0) { 2229 err = nvpair_value_string(nvp, &upstr); 2230 } 2231 if (err != 0) 2232 return (ipadm_errno2status(err)); 2233 } 2234 for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL; 2235 nvp = nvlist_next_nvpair(nvaddr, nvp)) { 2236 name = nvpair_name(nvp); 2237 if (strcmp(name, IPADM_NVP_IPADDRHNAME) == 0) 2238 err = nvpair_value_string(nvp, &sname); 2239 else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0) 2240 err = nvpair_value_string(nvp, &dname); 2241 if (err != 0) 2242 return (ipadm_errno2status(err)); 2243 } 2244 2245 if (strcmp(upstr, "yes") == 0) 2246 flags |= IPADM_OPT_UP; 2247 2248 /* build the address object from the above information */ 2249 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC); 2250 if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) { 2251 if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1) 2252 return (IPADM_NO_MEMORY); 2253 status = ipadm_set_addr(&ipaddr, cidraddr, af); 2254 free(cidraddr); 2255 } else { 2256 status = ipadm_set_addr(&ipaddr, sname, af); 2257 } 2258 if (status != IPADM_SUCCESS) 2259 return (status); 2260 2261 if (dname != NULL) { 2262 status = ipadm_set_dst_addr(&ipaddr, dname, af); 2263 if (status != IPADM_SUCCESS) 2264 return (status); 2265 } 2266 return (i_ipadm_create_addr(iph, &ipaddr, flags)); 2267 } 2268 2269 /* 2270 * Creates a dhcp address on the interface `ifname' based on the 2271 * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'. 2272 */ 2273 ipadm_status_t 2274 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl) 2275 { 2276 int32_t wait = IPADM_DHCP_WAIT_DEFAULT; 2277 boolean_t primary = B_FALSE; 2278 nvlist_t *nvdhcp = NULL; 2279 nvpair_t *nvp; 2280 char *name; 2281 struct ipadm_addrobj_s ipaddr; 2282 char *aobjname = NULL, *reqhost = NULL; 2283 int err = 0; 2284 ipadm_status_t ipadm_err = IPADM_SUCCESS; 2285 2286 /* Extract the dhcp parameters */ 2287 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 2288 nvp = nvlist_next_nvpair(nvl, nvp)) { 2289 name = nvpair_name(nvp); 2290 if (strcmp(name, IPADM_NVP_DHCP) == 0) 2291 err = nvpair_value_nvlist(nvp, &nvdhcp); 2292 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) 2293 err = nvpair_value_string(nvp, &aobjname); 2294 else if (strcmp(name, IPADM_NVP_REQHOST) == 0) 2295 err = nvpair_value_string(nvp, &reqhost); 2296 if (err != 0) 2297 return (ipadm_errno2status(err)); 2298 } 2299 for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL; 2300 nvp = nvlist_next_nvpair(nvdhcp, nvp)) { 2301 name = nvpair_name(nvp); 2302 if (strcmp(name, IPADM_NVP_WAIT) == 0) 2303 err = nvpair_value_int32(nvp, &wait); 2304 else if (strcmp(name, IPADM_NVP_PRIMARY) == 0) 2305 err = nvpair_value_boolean_value(nvp, &primary); 2306 if (err != 0) 2307 return (ipadm_errno2status(err)); 2308 } 2309 2310 /* Build the address object */ 2311 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP); 2312 ipaddr.ipadm_primary = primary; 2313 if (iph->iph_flags & IPH_INIT) 2314 ipaddr.ipadm_wait = 0; 2315 else 2316 ipaddr.ipadm_wait = wait; 2317 ipadm_err = ipadm_set_reqhost(&ipaddr, reqhost); 2318 if (ipadm_err != IPADM_SUCCESS) 2319 return (ipadm_err); 2320 ipaddr.ipadm_af = AF_INET; 2321 return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE)); 2322 } 2323 2324 /* 2325 * Creates auto-configured addresses on the interface `ifname' based on 2326 * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'. 2327 */ 2328 ipadm_status_t 2329 i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl) 2330 { 2331 struct ipadm_addrobj_s ipaddr; 2332 char *stateful = NULL, *stateless = NULL; 2333 uint_t n; 2334 uint8_t *addr6 = NULL; 2335 uint32_t intfidlen = 0; 2336 char *aobjname; 2337 nvlist_t *nvaddr; 2338 nvpair_t *nvp; 2339 char *name; 2340 int err = 0; 2341 2342 /* Extract the parameters */ 2343 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 2344 nvp = nvlist_next_nvpair(nvl, nvp)) { 2345 name = nvpair_name(nvp); 2346 if (strcmp(name, IPADM_NVP_INTFID) == 0) 2347 err = nvpair_value_nvlist(nvp, &nvaddr); 2348 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) 2349 err = nvpair_value_string(nvp, &aobjname); 2350 if (err != 0) 2351 return (ipadm_errno2status(err)); 2352 } 2353 for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL; 2354 nvp = nvlist_next_nvpair(nvaddr, nvp)) { 2355 name = nvpair_name(nvp); 2356 if (strcmp(name, IPADM_NVP_IPNUMADDR) == 0) 2357 err = nvpair_value_uint8_array(nvp, &addr6, &n); 2358 if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) 2359 err = nvpair_value_uint32(nvp, &intfidlen); 2360 else if (strcmp(name, IPADM_NVP_STATELESS) == 0) 2361 err = nvpair_value_string(nvp, &stateless); 2362 else if (strcmp(name, IPADM_NVP_STATEFUL) == 0) 2363 err = nvpair_value_string(nvp, &stateful); 2364 if (err != 0) 2365 return (ipadm_errno2status(err)); 2366 } 2367 /* Build the address object. */ 2368 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_IPV6_ADDRCONF); 2369 if (intfidlen > 0) { 2370 ipaddr.ipadm_intfidlen = intfidlen; 2371 bcopy(addr6, &ipaddr.ipadm_intfid.sin6_addr.s6_addr, n); 2372 } 2373 ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0); 2374 ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0); 2375 return (i_ipadm_create_ipv6addrs(iph, &ipaddr, IPADM_OPT_ACTIVE)); 2376 } 2377 2378 /* 2379 * Allocates `ipadm_addrobj_t' and populates the relevant member fields based on 2380 * the provided `type'. `aobjname' represents the address object name, which 2381 * is of the form `<ifname>/<addressname>'. 2382 * 2383 * The caller has to minimally provide <ifname>. If <addressname> is not 2384 * provided, then a default one will be generated by the API. 2385 */ 2386 ipadm_status_t 2387 ipadm_create_addrobj(ipadm_addr_type_t type, const char *aobjname, 2388 ipadm_addrobj_t *ipaddr) 2389 { 2390 ipadm_addrobj_t newaddr; 2391 ipadm_status_t status; 2392 char *aname, *cp; 2393 char ifname[IPADM_AOBJSIZ]; 2394 ifspec_t ifsp; 2395 2396 if (ipaddr == NULL) 2397 return (IPADM_INVALID_ARG); 2398 *ipaddr = NULL; 2399 2400 if (aobjname == NULL || aobjname[0] == '\0') 2401 return (IPADM_INVALID_ARG); 2402 2403 if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) 2404 return (IPADM_INVALID_ARG); 2405 2406 if ((aname = strchr(ifname, '/')) != NULL) 2407 *aname++ = '\0'; 2408 2409 /* Check if the interface name is valid. */ 2410 if (!ifparse_ifspec(ifname, &ifsp)) 2411 return (IPADM_INVALID_ARG); 2412 2413 /* Check if the given addrobj name is valid. */ 2414 if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname)) 2415 return (IPADM_INVALID_ARG); 2416 2417 if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL) 2418 return (IPADM_NO_MEMORY); 2419 2420 /* 2421 * If the ifname has logical interface number, extract it and assign 2422 * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do 2423 * this today. We will check for the validity later in 2424 * i_ipadm_validate_create_addr(). 2425 */ 2426 if (ifsp.ifsp_lunvalid) { 2427 newaddr->ipadm_lifnum = ifsp.ifsp_lun; 2428 cp = strchr(ifname, IPADM_LOGICAL_SEP); 2429 *cp = '\0'; 2430 } 2431 (void) strlcpy(newaddr->ipadm_ifname, ifname, 2432 sizeof (newaddr->ipadm_ifname)); 2433 2434 if (aname != NULL) { 2435 (void) snprintf(newaddr->ipadm_aobjname, 2436 sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname); 2437 } 2438 2439 switch (type) { 2440 case IPADM_ADDR_IPV6_ADDRCONF: 2441 newaddr->ipadm_intfidlen = 0; 2442 newaddr->ipadm_stateful = B_TRUE; 2443 newaddr->ipadm_stateless = B_TRUE; 2444 newaddr->ipadm_af = AF_INET6; 2445 break; 2446 2447 case IPADM_ADDR_DHCP: 2448 newaddr->ipadm_primary = B_FALSE; 2449 newaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT; 2450 newaddr->ipadm_af = AF_INET; 2451 break; 2452 2453 case IPADM_ADDR_STATIC: 2454 newaddr->ipadm_af = AF_UNSPEC; 2455 newaddr->ipadm_static_prefixlen = 0; 2456 break; 2457 2458 default: 2459 status = IPADM_INVALID_ARG; 2460 goto fail; 2461 } 2462 newaddr->ipadm_atype = type; 2463 *ipaddr = newaddr; 2464 return (IPADM_SUCCESS); 2465 fail: 2466 free(newaddr); 2467 return (status); 2468 } 2469 2470 /* 2471 * Returns `aobjname' from the address object in `ipaddr'. 2472 */ 2473 ipadm_status_t 2474 ipadm_get_aobjname(const ipadm_addrobj_t ipaddr, char *aobjname, size_t len) 2475 { 2476 if (ipaddr == NULL || aobjname == NULL) 2477 return (IPADM_INVALID_ARG); 2478 if (strlcpy(aobjname, ipaddr->ipadm_aobjname, len) >= len) 2479 return (IPADM_INVALID_ARG); 2480 2481 return (IPADM_SUCCESS); 2482 } 2483 2484 /* 2485 * Frees the address object in `ipaddr'. 2486 */ 2487 void 2488 ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr) 2489 { 2490 free(ipaddr); 2491 } 2492 2493 /* 2494 * Retrieves the logical interface name from `ipaddr' and stores the 2495 * string in `lifname'. 2496 */ 2497 void 2498 i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr, char *lifname, int lifnamesize) 2499 { 2500 if (ipaddr->ipadm_lifnum != 0) { 2501 (void) snprintf(lifname, lifnamesize, "%s:%d", 2502 ipaddr->ipadm_ifname, ipaddr->ipadm_lifnum); 2503 } else { 2504 (void) snprintf(lifname, lifnamesize, "%s", 2505 ipaddr->ipadm_ifname); 2506 } 2507 } 2508 2509 /* 2510 * Checks if a non-zero static address is present on the 0th logical interface 2511 * of the given IPv4 or IPv6 physical interface. For an IPv4 interface, it 2512 * also checks if the interface is under DHCP control. If the condition is true, 2513 * the output argument `exists' will be set to B_TRUE. Otherwise, `exists' 2514 * is set to B_FALSE. 2515 * 2516 * Note that *exists will not be initialized if an error is encountered. 2517 */ 2518 static ipadm_status_t 2519 i_ipadm_addr_exists_on_if(ipadm_handle_t iph, const char *ifname, 2520 sa_family_t af, boolean_t *exists) 2521 { 2522 struct lifreq lifr; 2523 int sock; 2524 2525 /* For IPH_LEGACY, a new logical interface will never be added. */ 2526 if (iph->iph_flags & IPH_LEGACY) { 2527 *exists = B_FALSE; 2528 return (IPADM_SUCCESS); 2529 } 2530 bzero(&lifr, sizeof (lifr)); 2531 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name)); 2532 if (af == AF_INET) { 2533 sock = iph->iph_sock; 2534 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) 2535 return (ipadm_errno2status(errno)); 2536 if (lifr.lifr_flags & IFF_DHCPRUNNING) { 2537 *exists = B_TRUE; 2538 return (IPADM_SUCCESS); 2539 } 2540 } else { 2541 sock = iph->iph_sock6; 2542 } 2543 if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0) 2544 return (ipadm_errno2status(errno)); 2545 *exists = !sockaddrunspec((struct sockaddr *)&lifr.lifr_addr); 2546 2547 return (IPADM_SUCCESS); 2548 } 2549 2550 /* 2551 * Adds a new logical interface in the kernel for interface 2552 * `addr->ipadm_ifname', if there is a non-zero address on the 0th 2553 * logical interface or if the 0th logical interface is under DHCP 2554 * control. On success, it sets the lifnum in the address object `addr'. 2555 */ 2556 ipadm_status_t 2557 i_ipadm_do_addif(ipadm_handle_t iph, ipadm_addrobj_t addr) 2558 { 2559 ipadm_status_t status; 2560 boolean_t addif; 2561 struct lifreq lifr; 2562 int sock; 2563 2564 addr->ipadm_lifnum = 0; 2565 status = i_ipadm_addr_exists_on_if(iph, addr->ipadm_ifname, 2566 addr->ipadm_af, &addif); 2567 if (status != IPADM_SUCCESS) 2568 return (status); 2569 if (addif) { 2570 /* 2571 * If there is an address on 0th logical interface, 2572 * add a new logical interface. 2573 */ 2574 bzero(&lifr, sizeof (lifr)); 2575 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname, 2576 sizeof (lifr.lifr_name)); 2577 sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : 2578 iph->iph_sock6); 2579 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0) 2580 return (ipadm_errno2status(errno)); 2581 addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name); 2582 } 2583 return (IPADM_SUCCESS); 2584 } 2585 2586 /* 2587 * Reads all the address lines from the persistent DB into the nvlist `onvl', 2588 * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided, 2589 * it returns all the addresses for the given interface `ifname'. 2590 * If an `aobjname' is specified, then the address line corresponding to 2591 * that name will be returned. 2592 */ 2593 static ipadm_status_t 2594 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname, 2595 const char *aobjname, nvlist_t **onvl) 2596 { 2597 ipmgmt_getaddr_arg_t garg; 2598 ipmgmt_get_rval_t *rvalp; 2599 int err; 2600 size_t nvlsize; 2601 char *nvlbuf; 2602 2603 /* Populate the door_call argument structure */ 2604 bzero(&garg, sizeof (garg)); 2605 garg.ia_cmd = IPMGMT_CMD_GETADDR; 2606 if (aobjname != NULL) 2607 (void) strlcpy(garg.ia_aobjname, aobjname, 2608 sizeof (garg.ia_aobjname)); 2609 if (ifname != NULL) 2610 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname)); 2611 2612 rvalp = malloc(sizeof (ipmgmt_get_rval_t)); 2613 err = ipadm_door_call(iph, &garg, sizeof (garg), (void **)&rvalp, 2614 sizeof (*rvalp), B_TRUE); 2615 if (err == 0) { 2616 nvlsize = rvalp->ir_nvlsize; 2617 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t); 2618 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE); 2619 } 2620 free(rvalp); 2621 return (ipadm_errno2status(err)); 2622 } 2623 2624 /* 2625 * Adds the IP address contained in the 'ipaddr' argument to the physical 2626 * interface represented by 'ifname' after doing the required validation. 2627 * If the interface does not exist, it is created before the address is 2628 * added. 2629 * 2630 * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE 2631 * and a default addrobj name will be generated. Input `addr->ipadm_aobjname', 2632 * if provided, will be ignored and replaced with the newly generated name. 2633 * The interface name provided has to be a logical interface name that 2634 * already exists. No new logical interface will be added in this function. 2635 * 2636 * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces 2637 * are plumbed (if they haven't been already). Otherwise, just the interface 2638 * specified in `addr' is plumbed. 2639 */ 2640 ipadm_status_t 2641 ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags) 2642 { 2643 ipadm_status_t status; 2644 sa_family_t af; 2645 sa_family_t daf; 2646 sa_family_t other_af; 2647 boolean_t created_af = B_FALSE; 2648 boolean_t created_other_af = B_FALSE; 2649 ipadm_addr_type_t type; 2650 char *ifname = addr->ipadm_ifname; 2651 boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 2652 boolean_t aobjfound; 2653 boolean_t is_6to4; 2654 struct lifreq lifr; 2655 uint64_t ifflags; 2656 boolean_t is_boot = (iph->iph_flags & IPH_IPMGMTD); 2657 2658 /* check for solaris.network.interface.config authorization */ 2659 if (!ipadm_check_auth()) 2660 return (IPADM_EAUTH); 2661 2662 /* Validate the addrobj. This also fills in addr->ipadm_ifname. */ 2663 status = i_ipadm_validate_create_addr(iph, addr, flags); 2664 if (status != IPADM_SUCCESS) 2665 return (status); 2666 2667 /* 2668 * For Legacy case, check if an addrobj already exists for the 2669 * given logical interface name. If one does not exist, 2670 * a default name will be generated and added to the daemon's 2671 * aobjmap. 2672 */ 2673 if (legacy) { 2674 struct ipadm_addrobj_s ipaddr; 2675 2676 ipaddr = *addr; 2677 status = i_ipadm_get_lif2addrobj(iph, &ipaddr); 2678 if (status == IPADM_SUCCESS) { 2679 aobjfound = B_TRUE; 2680 /* 2681 * With IPH_LEGACY, modifying an address that is not 2682 * a static address will return with an error. 2683 */ 2684 if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC) 2685 return (IPADM_NOTSUP); 2686 /* 2687 * we found the addrobj in daemon, copy over the 2688 * aobjname to `addr'. 2689 */ 2690 (void) strlcpy(addr->ipadm_aobjname, 2691 ipaddr.ipadm_aobjname, IPADM_AOBJSIZ); 2692 } else if (status == IPADM_NOTFOUND) { 2693 aobjfound = B_FALSE; 2694 } else { 2695 return (status); 2696 } 2697 } 2698 2699 af = addr->ipadm_af; 2700 /* 2701 * Create a placeholder for this address object in the daemon. 2702 * Skip this step if we are booting a zone (and therefore being called 2703 * from ipmgmtd itself), and, for IPH_LEGACY case if the 2704 * addrobj already exists. 2705 * 2706 * Note that the placeholder is not needed in the NGZ boot case, 2707 * when zoneadmd has itself applied the "allowed-ips" property to clamp 2708 * down any interface configuration, so the namespace for the interface 2709 * is fully controlled by the GZ. 2710 */ 2711 if (!is_boot && (!legacy || !aobjfound)) { 2712 status = i_ipadm_lookupadd_addrobj(iph, addr); 2713 if (status != IPADM_SUCCESS) 2714 return (status); 2715 } 2716 2717 is_6to4 = i_ipadm_is_6to4(iph, ifname); 2718 /* Plumb the IP interfaces if necessary */ 2719 status = i_ipadm_create_if(iph, ifname, af, flags); 2720 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) { 2721 (void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE); 2722 return (status); 2723 } 2724 if (status == IPADM_SUCCESS) 2725 created_af = B_TRUE; 2726 if (!is_6to4 && !legacy && (flags & IPADM_OPT_V46)) { 2727 other_af = (af == AF_INET ? AF_INET6 : AF_INET); 2728 status = i_ipadm_create_if(iph, ifname, other_af, flags); 2729 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) { 2730 (void) i_ipadm_delete_if(iph, ifname, af, flags); 2731 return (status); 2732 } 2733 if (status == IPADM_SUCCESS) 2734 created_other_af = B_TRUE; 2735 } 2736 2737 /* 2738 * Some input validation based on the interface flags: 2739 * 1. in non-global zones, make sure that we are not persistently 2740 * creating addresses on interfaces that are acquiring 2741 * address from the global zone. 2742 * 2. Validate static addresses for IFF_POINTOPOINT interfaces. 2743 */ 2744 if (addr->ipadm_atype == IPADM_ADDR_STATIC) { 2745 status = i_ipadm_get_flags(iph, ifname, af, &ifflags); 2746 if (status != IPADM_SUCCESS) 2747 goto fail; 2748 2749 if (iph->iph_zoneid != GLOBAL_ZONEID && 2750 (ifflags & IFF_L3PROTECT) && (flags & IPADM_OPT_PERSIST)) { 2751 status = IPADM_GZ_PERM; 2752 goto fail; 2753 } 2754 daf = addr->ipadm_static_dst_addr.ss_family; 2755 if (ifflags & IFF_POINTOPOINT) { 2756 if (is_6to4) { 2757 if (af != AF_INET6 || daf != AF_UNSPEC) { 2758 status = IPADM_INVALID_ARG; 2759 goto fail; 2760 } 2761 } else { 2762 if (daf != af) { 2763 status = IPADM_INVALID_ARG; 2764 goto fail; 2765 } 2766 /* Check for a valid dst address. */ 2767 if (!legacy && sockaddrunspec( 2768 (struct sockaddr *) 2769 &addr->ipadm_static_dst_addr)) { 2770 status = IPADM_BAD_ADDR; 2771 goto fail; 2772 } 2773 } 2774 } else { 2775 /* 2776 * Disallow setting of dstaddr when the link is not 2777 * a point-to-point link. 2778 */ 2779 if (daf != AF_UNSPEC) 2780 return (IPADM_INVALID_ARG); 2781 } 2782 } 2783 2784 /* 2785 * For 6to4 interfaces, kernel configures a default link-local 2786 * address. We need to replace it, if the caller has provided 2787 * an address that is different from the default link-local. 2788 */ 2789 if (status == IPADM_SUCCESS && is_6to4) { 2790 bzero(&lifr, sizeof (lifr)); 2791 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname, 2792 sizeof (lifr.lifr_name)); 2793 if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) { 2794 status = ipadm_errno2status(errno); 2795 goto fail; 2796 } 2797 if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr)) 2798 return (IPADM_SUCCESS); 2799 } 2800 2801 /* Create the address. */ 2802 type = addr->ipadm_atype; 2803 switch (type) { 2804 case IPADM_ADDR_STATIC: 2805 status = i_ipadm_create_addr(iph, addr, flags); 2806 break; 2807 case IPADM_ADDR_DHCP: 2808 status = i_ipadm_create_dhcp(iph, addr, flags); 2809 break; 2810 case IPADM_ADDR_IPV6_ADDRCONF: 2811 status = i_ipadm_create_ipv6addrs(iph, addr, flags); 2812 break; 2813 default: 2814 status = IPADM_INVALID_ARG; 2815 break; 2816 } 2817 2818 /* 2819 * If address was not created successfully, unplumb the interface 2820 * if it was plumbed implicitly in this function and remove the 2821 * addrobj created by the ipmgmtd daemon as a placeholder. 2822 * If IPH_LEGACY is set, then remove the addrobj only if it was 2823 * created in this function. 2824 */ 2825 fail: 2826 if (status != IPADM_DHCP_IPC_TIMEOUT && 2827 status != IPADM_SUCCESS) { 2828 if (!legacy) { 2829 if (created_af || created_other_af) { 2830 if (created_af) { 2831 (void) i_ipadm_delete_if(iph, ifname, 2832 af, flags); 2833 } 2834 if (created_other_af) { 2835 (void) i_ipadm_delete_if(iph, ifname, 2836 other_af, flags); 2837 } 2838 } else { 2839 (void) i_ipadm_delete_addrobj(iph, addr, flags); 2840 } 2841 } else if (!aobjfound) { 2842 (void) i_ipadm_delete_addrobj(iph, addr, flags); 2843 } 2844 } 2845 2846 return (status); 2847 } 2848 2849 /* 2850 * Creates the static address in `ipaddr' in kernel. After successfully 2851 * creating it, it updates the ipmgmtd daemon's aobjmap with the logical 2852 * interface information. 2853 */ 2854 static ipadm_status_t 2855 i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags) 2856 { 2857 struct lifreq lifr; 2858 ipadm_status_t status = IPADM_SUCCESS; 2859 int sock; 2860 struct sockaddr_storage m, *mask = &m; 2861 const struct sockaddr_storage *addr = &ipaddr->ipadm_static_addr; 2862 const struct sockaddr_storage *daddr = &ipaddr->ipadm_static_dst_addr; 2863 sa_family_t af; 2864 boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 2865 struct ipadm_addrobj_s legacy_addr; 2866 boolean_t default_prefixlen = B_FALSE; 2867 boolean_t is_boot; 2868 2869 is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0); 2870 af = ipaddr->ipadm_af; 2871 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6); 2872 2873 /* If prefixlen was not provided, get default prefixlen */ 2874 if (ipaddr->ipadm_static_prefixlen == 0) { 2875 /* prefixlen was not provided, get default prefixlen */ 2876 status = i_ipadm_get_default_prefixlen( 2877 &ipaddr->ipadm_static_addr, 2878 &ipaddr->ipadm_static_prefixlen); 2879 if (status != IPADM_SUCCESS) 2880 return (status); 2881 default_prefixlen = B_TRUE; 2882 } 2883 (void) plen2mask(ipaddr->ipadm_static_prefixlen, af, 2884 (struct sockaddr *)mask); 2885 2886 /* 2887 * Create a new logical interface if needed; otherwise, just 2888 * use the 0th logical interface. 2889 */ 2890 retry: 2891 if (!(iph->iph_flags & IPH_LEGACY)) { 2892 status = i_ipadm_do_addif(iph, ipaddr); 2893 if (status != IPADM_SUCCESS) 2894 return (status); 2895 /* 2896 * We don't have to set the lifnum for IPH_INIT case, because 2897 * there is no placeholder created for the address object in 2898 * this case. For IPH_LEGACY, we don't do this because the 2899 * lifnum is given by the caller and it will be set in the 2900 * end while we call the i_ipadm_addr_persist(). 2901 */ 2902 if (!(iph->iph_flags & IPH_INIT)) { 2903 status = i_ipadm_setlifnum_addrobj(iph, ipaddr); 2904 if (status == IPADM_ADDROBJ_EXISTS) 2905 goto retry; 2906 if (status != IPADM_SUCCESS) 2907 return (status); 2908 } 2909 } 2910 i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name, 2911 sizeof (lifr.lifr_name)); 2912 lifr.lifr_addr = *mask; 2913 if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) { 2914 status = ipadm_errno2status(errno); 2915 goto ret; 2916 } 2917 lifr.lifr_addr = *addr; 2918 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) { 2919 status = ipadm_errno2status(errno); 2920 goto ret; 2921 } 2922 /* Set the destination address, if one is given. */ 2923 if (daddr->ss_family != AF_UNSPEC) { 2924 lifr.lifr_addr = *daddr; 2925 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) { 2926 status = ipadm_errno2status(errno); 2927 goto ret; 2928 } 2929 } 2930 2931 if (flags & IPADM_OPT_UP) { 2932 status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0); 2933 2934 /* 2935 * IPADM_DAD_FOUND is a soft-error for create-addr. 2936 * No need to tear down the address. 2937 */ 2938 if (status == IPADM_DAD_FOUND) 2939 status = IPADM_SUCCESS; 2940 } 2941 2942 if (status == IPADM_SUCCESS && !is_boot) { 2943 /* 2944 * For IPH_LEGACY, we might be modifying the address on 2945 * an address object that already exists e.g. by doing 2946 * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>" 2947 * So, we need to store the object only if it does not 2948 * already exist in ipmgmtd. 2949 */ 2950 if (legacy) { 2951 bzero(&legacy_addr, sizeof (legacy_addr)); 2952 (void) strlcpy(legacy_addr.ipadm_aobjname, 2953 ipaddr->ipadm_aobjname, 2954 sizeof (legacy_addr.ipadm_aobjname)); 2955 status = i_ipadm_get_addrobj(iph, &legacy_addr); 2956 if (status == IPADM_SUCCESS && 2957 legacy_addr.ipadm_lifnum >= 0) { 2958 return (status); 2959 } 2960 } 2961 status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen, 2962 flags, NULL); 2963 } 2964 ret: 2965 if (status != IPADM_SUCCESS && !legacy) 2966 (void) i_ipadm_delete_addr(iph, ipaddr); 2967 return (status); 2968 } 2969 2970 /* 2971 * Removes the address object identified by `aobjname' from both active and 2972 * persistent configuration. The address object will be removed from only 2973 * active configuration if IPH_LEGACY is set in `iph->iph_flags'. 2974 * 2975 * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address 2976 * in the address object will be removed from the physical interface. 2977 * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies 2978 * whether the lease should be released. If IPADM_OPT_RELEASE is not 2979 * specified, the lease will be dropped. This option is not supported 2980 * for other address types. 2981 * 2982 * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and 2983 * all the autoconfigured addresses will be removed. 2984 * Finally, the address object is also removed from ipmgmtd's aobjmap and from 2985 * the persistent DB. 2986 */ 2987 ipadm_status_t 2988 ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags) 2989 { 2990 ipadm_status_t status; 2991 struct ipadm_addrobj_s ipaddr; 2992 boolean_t release = ((flags & IPADM_OPT_RELEASE) != 0); 2993 2994 /* check for solaris.network.interface.config authorization */ 2995 if (!ipadm_check_auth()) 2996 return (IPADM_EAUTH); 2997 2998 /* validate input */ 2999 if (flags == 0 || ((flags & IPADM_OPT_PERSIST) && 3000 !(flags & IPADM_OPT_ACTIVE)) || 3001 (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_RELEASE))) { 3002 return (IPADM_INVALID_ARG); 3003 } 3004 bzero(&ipaddr, sizeof (ipaddr)); 3005 if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname, 3006 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) { 3007 return (IPADM_INVALID_ARG); 3008 } 3009 3010 /* Retrieve the address object information from ipmgmtd. */ 3011 status = i_ipadm_get_addrobj(iph, &ipaddr); 3012 if (status != IPADM_SUCCESS) 3013 return (status); 3014 3015 if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP) 3016 return (IPADM_NOTSUP); 3017 /* 3018 * If requested to delete just from active config but the address 3019 * is not in active config, return error. 3020 */ 3021 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) && 3022 (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) { 3023 return (IPADM_NOTFOUND); 3024 } 3025 3026 /* 3027 * If address is present in active config, remove it from 3028 * kernel. 3029 */ 3030 if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) { 3031 switch (ipaddr.ipadm_atype) { 3032 case IPADM_ADDR_STATIC: 3033 status = i_ipadm_delete_addr(iph, &ipaddr); 3034 break; 3035 case IPADM_ADDR_DHCP: 3036 status = i_ipadm_delete_dhcp(iph, &ipaddr, release); 3037 break; 3038 case IPADM_ADDR_IPV6_ADDRCONF: 3039 status = i_ipadm_delete_ipv6addrs(iph, &ipaddr); 3040 break; 3041 default: 3042 /* 3043 * This is the case of address object name residing in 3044 * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall 3045 * through and delete that address object. 3046 */ 3047 break; 3048 } 3049 3050 /* 3051 * If the address was previously deleted from the active 3052 * config, we will get a IPADM_ENXIO from kernel. 3053 * We will still proceed and purge the address information 3054 * in the DB. 3055 */ 3056 if (status == IPADM_ENXIO) 3057 status = IPADM_SUCCESS; 3058 else if (status != IPADM_SUCCESS) 3059 return (status); 3060 } 3061 3062 if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) && 3063 (flags & IPADM_OPT_PERSIST)) { 3064 flags &= ~IPADM_OPT_PERSIST; 3065 } 3066 status = i_ipadm_delete_addrobj(iph, &ipaddr, flags); 3067 if (status == IPADM_NOTFOUND) 3068 return (status); 3069 return (IPADM_SUCCESS); 3070 } 3071 3072 /* 3073 * Starts the dhcpagent and sends it the message DHCP_START to start 3074 * configuring a dhcp address on the given interface in `addr'. 3075 * After making the dhcpagent request, it also updates the 3076 * address object information in ipmgmtd's aobjmap and creates an 3077 * entry in persistent DB if IPADM_OPT_PERSIST is set in `flags'. 3078 */ 3079 static ipadm_status_t 3080 i_ipadm_create_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags) 3081 { 3082 ipadm_status_t status; 3083 ipadm_status_t dh_status; 3084 3085 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) 3086 return (IPADM_DHCP_START_ERROR); 3087 /* 3088 * Create a new logical interface if needed; otherwise, just 3089 * use the 0th logical interface. 3090 */ 3091 retry: 3092 status = i_ipadm_do_addif(iph, addr); 3093 if (status != IPADM_SUCCESS) 3094 return (status); 3095 /* 3096 * We don't have to set the lifnum for IPH_INIT case, because 3097 * there is no placeholder created for the address object in this 3098 * case. 3099 */ 3100 if (!(iph->iph_flags & IPH_INIT)) { 3101 status = i_ipadm_setlifnum_addrobj(iph, addr); 3102 if (status == IPADM_ADDROBJ_EXISTS) 3103 goto retry; 3104 if (status != IPADM_SUCCESS) 3105 return (status); 3106 } 3107 /* Send DHCP_START to the dhcpagent. */ 3108 status = i_ipadm_op_dhcp(addr, DHCP_START, NULL); 3109 /* 3110 * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT 3111 * since it is only a soft error to indicate the caller that the lease 3112 * might be required after the function returns. 3113 */ 3114 if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT) 3115 goto fail; 3116 dh_status = status; 3117 3118 /* Persist the address object information in ipmgmtd. */ 3119 status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags, NULL); 3120 if (status != IPADM_SUCCESS) 3121 goto fail; 3122 3123 return (dh_status); 3124 fail: 3125 /* In case of error, delete the dhcp address */ 3126 (void) i_ipadm_delete_dhcp(iph, addr, B_TRUE); 3127 return (status); 3128 } 3129 3130 /* 3131 * Releases/drops the dhcp lease on the logical interface in the address 3132 * object `addr'. If `release' is set to B_FALSE, the lease will be dropped. 3133 */ 3134 static ipadm_status_t 3135 i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release) 3136 { 3137 ipadm_status_t status; 3138 int dherr; 3139 3140 /* Send DHCP_RELEASE or DHCP_DROP to the dhcpagent */ 3141 if (release) { 3142 status = i_ipadm_op_dhcp(addr, DHCP_RELEASE, &dherr); 3143 /* 3144 * If no lease was obtained on the object, we should 3145 * drop the dhcp control on the interface. 3146 */ 3147 if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) 3148 status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL); 3149 } else { 3150 status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL); 3151 } 3152 if (status != IPADM_SUCCESS) 3153 return (status); 3154 3155 /* Delete the logical interface */ 3156 if (addr->ipadm_lifnum != 0) { 3157 struct lifreq lifr; 3158 3159 bzero(&lifr, sizeof (lifr)); 3160 i_ipadm_addrobj2lifname(addr, lifr.lifr_name, 3161 sizeof (lifr.lifr_name)); 3162 if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) 3163 return (ipadm_errno2status(errno)); 3164 } 3165 3166 return (IPADM_SUCCESS); 3167 } 3168 3169 /* 3170 * Communicates with the dhcpagent to send a dhcp message of type `type'. 3171 * It returns the dhcp error in `dhcperror' if a non-null pointer is provided 3172 * in `dhcperror'. 3173 */ 3174 static ipadm_status_t 3175 i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror) 3176 { 3177 dhcp_ipc_request_t *request; 3178 dhcp_ipc_reply_t *reply = NULL; 3179 dhcp_symbol_t *entry = NULL; 3180 dhcp_data_type_t dtype = DHCP_TYPE_NONE; 3181 void *d4o = NULL; 3182 uint16_t d4olen = 0; 3183 char ifname[LIFNAMSIZ]; 3184 int error; 3185 int dhcp_timeout; 3186 3187 /* Construct a message to the dhcpagent. */ 3188 bzero(&ifname, sizeof (ifname)); 3189 i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname)); 3190 if (addr->ipadm_primary) 3191 type |= DHCP_PRIMARY; 3192 3193 /* Set up a CD_HOSTNAME option, if applicable, to send through IPC */ 3194 switch (DHCP_IPC_CMD(type)) { 3195 case DHCP_START: 3196 case DHCP_EXTEND: 3197 if (addr->ipadm_af == AF_INET && addr->ipadm_reqhost != NULL && 3198 *addr->ipadm_reqhost != '\0') { 3199 entry = inittab_getbycode(ITAB_CAT_STANDARD, 3200 ITAB_CONS_INFO, CD_HOSTNAME); 3201 if (entry == NULL) { 3202 return (IPADM_FAILURE); 3203 } else { 3204 d4o = inittab_encode(entry, addr->ipadm_reqhost, 3205 &d4olen, B_FALSE); 3206 free(entry); 3207 entry = NULL; 3208 if (d4o == NULL) 3209 return (IPADM_FAILURE); 3210 dtype = DHCP_TYPE_OPTION; 3211 } 3212 } 3213 break; 3214 default: 3215 break; 3216 } 3217 3218 request = dhcp_ipc_alloc_request(type, ifname, d4o, d4olen, dtype); 3219 if (request == NULL) { 3220 free(d4o); 3221 return (IPADM_NO_MEMORY); 3222 } 3223 3224 if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER) 3225 dhcp_timeout = DHCP_IPC_WAIT_FOREVER; 3226 else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT) 3227 dhcp_timeout = DHCP_IPC_WAIT_DEFAULT; 3228 else 3229 dhcp_timeout = addr->ipadm_wait; 3230 /* Send the message to dhcpagent. */ 3231 error = dhcp_ipc_make_request(request, &reply, dhcp_timeout); 3232 free(request); 3233 free(d4o); 3234 if (error == 0) { 3235 error = reply->return_code; 3236 free(reply); 3237 } 3238 if (error != 0) { 3239 if (dhcperror != NULL) 3240 *dhcperror = error; 3241 if (error != DHCP_IPC_E_TIMEOUT) 3242 return (IPADM_DHCP_IPC_ERROR); 3243 else if (dhcp_timeout != 0) 3244 return (IPADM_DHCP_IPC_TIMEOUT); 3245 } 3246 3247 return (IPADM_SUCCESS); 3248 } 3249 3250 /* 3251 * Communicates with the dhcpagent to send a dhcp message of type 3252 * DHCP_STATUS, and copy on success into the `status' instance owned by the 3253 * caller. It returns any dhcp error in `dhcperror' if a non-null pointer 3254 * is provided. 3255 */ 3256 static ipadm_status_t 3257 i_ipadm_dhcp_status(ipadm_addrobj_t addr, dhcp_status_t *status, 3258 int *dhcperror) 3259 { 3260 dhcp_ipc_type_t type = DHCP_STATUS; 3261 dhcp_ipc_request_t *request; 3262 dhcp_ipc_reply_t *reply; 3263 dhcp_status_t *private_status; 3264 size_t reply_size; 3265 int error; 3266 3267 if (addr->ipadm_af == AF_INET6) 3268 type |= DHCP_V6; 3269 3270 request = dhcp_ipc_alloc_request(type, addr->ipadm_ifname, NULL, 0, 3271 DHCP_TYPE_NONE); 3272 if (request == NULL) 3273 return (IPADM_NO_MEMORY); 3274 3275 error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT); 3276 free(request); 3277 if (error != 0) { 3278 if (dhcperror != NULL) 3279 *dhcperror = error; 3280 return (error != DHCP_IPC_E_TIMEOUT ? IPADM_DHCP_IPC_ERROR 3281 : IPADM_DHCP_IPC_TIMEOUT); 3282 } 3283 3284 error = reply->return_code; 3285 if (error == DHCP_IPC_E_UNKIF) { 3286 free(reply); 3287 bzero(status, sizeof (dhcp_status_t)); 3288 return (IPADM_NOTFOUND); 3289 } 3290 3291 private_status = dhcp_ipc_get_data(reply, &reply_size, NULL); 3292 if (reply_size < DHCP_STATUS_VER1_SIZE) { 3293 free(reply); 3294 return (IPADM_DHCP_IPC_ERROR); 3295 } 3296 3297 /* 3298 * Copy the status out of the memory allocated by this function into 3299 * memory owned by the caller. 3300 */ 3301 *status = *private_status; 3302 free(reply); 3303 return (IPADM_SUCCESS); 3304 } 3305 3306 /* 3307 * Returns the IP addresses of the specified interface in both the 3308 * active and the persistent configuration. If no 3309 * interface is specified, it returns all non-zero IP addresses 3310 * configured on all interfaces in active and persistent 3311 * configurations. 3312 * `addrinfo' will contain addresses that are 3313 * (1) in both active and persistent configuration (created persistently) 3314 * (2) only in active configuration (created temporarily) 3315 * (3) only in persistent configuration (disabled addresses) 3316 * 3317 * Address list that is returned by this function must be freed 3318 * using the ipadm_freeaddr_info() function. 3319 */ 3320 ipadm_status_t 3321 ipadm_addr_info(ipadm_handle_t iph, const char *ifname, 3322 ipadm_addr_info_t **addrinfo, uint32_t flags, int64_t lifc_flags) 3323 { 3324 ifspec_t ifsp; 3325 3326 if (addrinfo == NULL || iph == NULL) 3327 return (IPADM_INVALID_ARG); 3328 if (ifname != NULL && 3329 (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) { 3330 return (IPADM_INVALID_ARG); 3331 } 3332 return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo, 3333 flags, lifc_flags)); 3334 } 3335 3336 /* 3337 * Frees the structure allocated by ipadm_addr_info(). 3338 */ 3339 void 3340 ipadm_free_addr_info(ipadm_addr_info_t *ainfo) 3341 { 3342 freeifaddrs((struct ifaddrs *)ainfo); 3343 } 3344 3345 /* 3346 * Makes a door call to ipmgmtd to update its `aobjmap' with the address 3347 * object in `ipaddr'. This door call also can update the persistent DB to 3348 * remember address object to be recreated on next reboot or on an 3349 * ipadm_enable_addr()/ipadm_enable_if() call. 3350 */ 3351 ipadm_status_t 3352 i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr, 3353 boolean_t default_prefixlen, uint32_t flags, const char *propname) 3354 { 3355 char *aname = ipaddr->ipadm_aobjname; 3356 nvlist_t *nvl; 3357 int err = 0; 3358 ipadm_status_t status; 3359 uint_t pflags = 0; 3360 3361 /* 3362 * Construct the nvl to send to the door. 3363 */ 3364 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 3365 return (IPADM_NO_MEMORY); 3366 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME, 3367 ipaddr->ipadm_ifname)) != 0 || 3368 (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 || 3369 (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM, 3370 ipaddr->ipadm_lifnum)) != 0) { 3371 status = ipadm_errno2status(err); 3372 goto ret; 3373 } 3374 switch (ipaddr->ipadm_atype) { 3375 case IPADM_ADDR_STATIC: 3376 status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr); 3377 if (status != IPADM_SUCCESS) 3378 goto ret; 3379 if (flags & IPADM_OPT_UP) 3380 err = nvlist_add_string(nvl, "up", "yes"); 3381 else 3382 err = nvlist_add_string(nvl, "up", "no"); 3383 status = ipadm_errno2status(err); 3384 break; 3385 case IPADM_ADDR_DHCP: 3386 status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary, 3387 ipaddr->ipadm_wait); 3388 if (status != IPADM_SUCCESS) 3389 goto ret; 3390 3391 /* 3392 * For purposes of updating the ipmgmtd cached representation of 3393 * reqhost (ipmgmt_am_reqhost), include a value here in `nvl', 3394 * but the value is actually fully persisted as a separate 3395 * i_ipadm_persist_propval below. 3396 */ 3397 err = nvlist_add_string(nvl, IPADM_NVP_REQHOST, 3398 ipaddr->ipadm_reqhost); 3399 status = ipadm_errno2status(err); 3400 break; 3401 case IPADM_ADDR_IPV6_ADDRCONF: 3402 status = i_ipadm_add_intfid2nvl(nvl, ipaddr); 3403 break; 3404 } 3405 if (status != IPADM_SUCCESS) 3406 goto ret; 3407 3408 if (iph->iph_flags & IPH_INIT) { 3409 /* 3410 * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and 3411 * IPMGMT_PERSIST on the address object in its `aobjmap'. 3412 * For the callers ipadm_enable_if() and ipadm_enable_addr(), 3413 * IPADM_OPT_PERSIST is not set in their flags. They send 3414 * IPH_INIT in iph_flags, so that the address object will be 3415 * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST. 3416 */ 3417 pflags |= IPMGMT_INIT; 3418 } else { 3419 if (flags & IPADM_OPT_ACTIVE) 3420 pflags |= IPMGMT_ACTIVE; 3421 if (flags & IPADM_OPT_PERSIST) 3422 pflags |= IPMGMT_PERSIST; 3423 if (flags & IPADM_OPT_SET_PROPS) 3424 pflags |= IPMGMT_PROPS_ONLY; 3425 } 3426 status = i_ipadm_addr_persist_nvl(iph, nvl, pflags); 3427 3428 if (flags & IPADM_OPT_SET_PROPS) { 3429 /* 3430 * Set PERSIST per IPADM_OPT_PROPS_PERSIST, and then un-set the 3431 * SET_PROPS bits. 3432 */ 3433 flags |= IPADM_OPT_ACTIVE; 3434 if (flags & IPADM_OPT_PERSIST_PROPS) 3435 flags |= IPADM_OPT_PERSIST; 3436 else 3437 flags &= ~IPADM_OPT_PERSIST; 3438 flags &= ~(IPADM_OPT_SET_PROPS | IPADM_OPT_PERSIST_PROPS); 3439 } 3440 3441 if (status == IPADM_SUCCESS && (flags & IPADM_OPT_PERSIST)) { 3442 char pbuf[MAXPROPVALLEN], *pval = NULL; 3443 ipadm_prop_desc_t *pdp = NULL; 3444 3445 /* 3446 * addprop properties are stored on separate lines in the DB and 3447 * not along with the address itself. Call the function that 3448 * persists address properties. 3449 */ 3450 3451 switch (ipaddr->ipadm_atype) { 3452 case IPADM_ADDR_STATIC: 3453 if (!default_prefixlen && (propname == NULL || 3454 strcmp(propname, IPADM_NVP_PREFIXLEN) == 0)) { 3455 pdp = i_ipadm_get_addrprop_desc( 3456 IPADM_NVP_PREFIXLEN); 3457 (void) snprintf(pbuf, sizeof (pbuf), "%u", 3458 ipaddr->ipadm_static_prefixlen); 3459 pval = pbuf; 3460 } 3461 break; 3462 case IPADM_ADDR_DHCP: 3463 if (propname == NULL || 3464 strcmp(propname, IPADM_NVP_REQHOST) == 0) { 3465 pdp = i_ipadm_get_addrprop_desc( 3466 IPADM_NVP_REQHOST); 3467 pval = ipaddr->ipadm_reqhost; 3468 } 3469 break; 3470 default: 3471 break; 3472 } 3473 3474 if (pval != NULL) { 3475 assert(pdp != NULL); 3476 status = i_ipadm_persist_propval(iph, pdp, pval, 3477 ipaddr, flags); 3478 } 3479 } 3480 3481 ret: 3482 nvlist_free(nvl); 3483 return (status); 3484 } 3485 3486 /* 3487 * Makes the door call to ipmgmtd to store the address object in the 3488 * nvlist `nvl'. 3489 */ 3490 static ipadm_status_t 3491 i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags) 3492 { 3493 char *buf = NULL, *nvlbuf = NULL; 3494 size_t nvlsize, bufsize; 3495 ipmgmt_setaddr_arg_t *sargp; 3496 int err; 3497 3498 err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0); 3499 if (err != 0) 3500 return (ipadm_errno2status(err)); 3501 bufsize = sizeof (*sargp) + nvlsize; 3502 buf = calloc(1, bufsize); 3503 sargp = (void *)buf; 3504 sargp->ia_cmd = IPMGMT_CMD_SETADDR; 3505 sargp->ia_flags = flags; 3506 sargp->ia_nvlsize = nvlsize; 3507 (void) bcopy(nvlbuf, buf + sizeof (*sargp), nvlsize); 3508 err = ipadm_door_call(iph, buf, bufsize, NULL, 0, B_FALSE); 3509 free(buf); 3510 free(nvlbuf); 3511 return (ipadm_errno2status(err)); 3512 } 3513 3514 /* 3515 * Makes a door call to ipmgmtd to remove the address object in `ipaddr' 3516 * from its `aobjmap'. This door call also removes the address object and all 3517 * its properties from the persistent DB if IPADM_OPT_PERSIST is set in 3518 * `flags', so that the object will not be recreated on next reboot or on an 3519 * ipadm_enable_addr()/ipadm_enable_if() call. 3520 */ 3521 ipadm_status_t 3522 i_ipadm_delete_addrobj(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr, 3523 uint32_t flags) 3524 { 3525 ipmgmt_addr_arg_t arg; 3526 int err; 3527 3528 arg.ia_cmd = IPMGMT_CMD_RESETADDR; 3529 arg.ia_flags = 0; 3530 if (flags & IPADM_OPT_ACTIVE) 3531 arg.ia_flags |= IPMGMT_ACTIVE; 3532 if (flags & IPADM_OPT_PERSIST) 3533 arg.ia_flags |= IPMGMT_PERSIST; 3534 (void) strlcpy(arg.ia_aobjname, ipaddr->ipadm_aobjname, 3535 sizeof (arg.ia_aobjname)); 3536 arg.ia_lnum = ipaddr->ipadm_lifnum; 3537 err = ipadm_door_call(iph, &arg, sizeof (arg), NULL, 0, B_FALSE); 3538 return (ipadm_errno2status(err)); 3539 } 3540 3541 /* 3542 * Checks if the caller is authorized for the up/down operation. 3543 * Retrieves the address object corresponding to `aobjname' from ipmgmtd 3544 * and retrieves the address flags for that object from kernel. 3545 * The arguments `ipaddr' and `ifflags' must be allocated by the caller. 3546 */ 3547 static ipadm_status_t 3548 i_ipadm_updown_common(ipadm_handle_t iph, const char *aobjname, 3549 ipadm_addrobj_t ipaddr, uint32_t ipadm_flags, uint64_t *ifflags) 3550 { 3551 ipadm_status_t status; 3552 char lifname[LIFNAMSIZ]; 3553 3554 /* check for solaris.network.interface.config authorization */ 3555 if (!ipadm_check_auth()) 3556 return (IPADM_EAUTH); 3557 3558 /* validate input */ 3559 if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname, 3560 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) { 3561 return (IPADM_INVALID_ARG); 3562 } 3563 3564 /* Retrieve the address object information. */ 3565 status = i_ipadm_get_addrobj(iph, ipaddr); 3566 if (status != IPADM_SUCCESS) 3567 return (status); 3568 3569 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) 3570 return (IPADM_OP_DISABLE_OBJ); 3571 if ((ipadm_flags & IPADM_OPT_PERSIST) && 3572 !(ipaddr->ipadm_flags & IPMGMT_PERSIST)) 3573 return (IPADM_TEMPORARY_OBJ); 3574 if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF || 3575 (ipaddr->ipadm_atype == IPADM_ADDR_DHCP && 3576 (ipadm_flags & IPADM_OPT_PERSIST))) 3577 return (IPADM_NOTSUP); 3578 3579 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname)); 3580 return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags)); 3581 } 3582 3583 /* 3584 * Marks the address in the address object `aobjname' up. This operation is 3585 * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF. 3586 * For an address object of type IPADM_ADDR_DHCP, this operation can 3587 * only be temporary and no updates will be made to the persistent DB. 3588 */ 3589 ipadm_status_t 3590 ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags) 3591 { 3592 struct ipadm_addrobj_s ipaddr; 3593 ipadm_status_t status; 3594 uint64_t flags; 3595 char lifname[LIFNAMSIZ]; 3596 3597 status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags, 3598 &flags); 3599 if (status != IPADM_SUCCESS) 3600 return (status); 3601 if (flags & IFF_UP) 3602 goto persist; 3603 /* 3604 * If the address is already a duplicate, then refresh-addr 3605 * should be used to mark it up. 3606 */ 3607 if (flags & IFF_DUPLICATE) 3608 return (IPADM_DAD_FOUND); 3609 3610 i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname)); 3611 status = i_ipadm_set_flags(iph, lifname, ipaddr.ipadm_af, IFF_UP, 0); 3612 if (status != IPADM_SUCCESS) 3613 return (status); 3614 3615 persist: 3616 /* Update persistent DB. */ 3617 if (ipadm_flags & IPADM_OPT_PERSIST) { 3618 status = i_ipadm_persist_propval(iph, &up_addrprop, 3619 "yes", &ipaddr, 0); 3620 } 3621 3622 return (status); 3623 } 3624 3625 /* 3626 * Marks the address in the address object `aobjname' down. This operation is 3627 * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF. 3628 * For an address object of type IPADM_ADDR_DHCP, this operation can 3629 * only be temporary and no updates will be made to the persistent DB. 3630 */ 3631 ipadm_status_t 3632 ipadm_down_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags) 3633 { 3634 struct ipadm_addrobj_s ipaddr; 3635 ipadm_status_t status; 3636 struct lifreq lifr; 3637 uint64_t flags; 3638 3639 status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags, 3640 &flags); 3641 if (status != IPADM_SUCCESS) 3642 return (status); 3643 i_ipadm_addrobj2lifname(&ipaddr, lifr.lifr_name, 3644 sizeof (lifr.lifr_name)); 3645 if (flags & IFF_UP) { 3646 status = i_ipadm_set_flags(iph, lifr.lifr_name, 3647 ipaddr.ipadm_af, 0, IFF_UP); 3648 if (status != IPADM_SUCCESS) 3649 return (status); 3650 } else if (flags & IFF_DUPLICATE) { 3651 /* 3652 * Clear the IFF_DUPLICATE flag. 3653 */ 3654 if (ioctl(iph->iph_sock, SIOCGLIFADDR, &lifr) < 0) 3655 return (ipadm_errno2status(errno)); 3656 if (ioctl(iph->iph_sock, SIOCSLIFADDR, &lifr) < 0) 3657 return (ipadm_errno2status(errno)); 3658 } 3659 3660 /* Update persistent DB */ 3661 if (ipadm_flags & IPADM_OPT_PERSIST) { 3662 status = i_ipadm_persist_propval(iph, &up_addrprop, 3663 "no", &ipaddr, 0); 3664 } 3665 3666 return (status); 3667 } 3668 3669 /* 3670 * Refreshes the address in the address object `aobjname'. If the address object 3671 * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If 3672 * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the 3673 * dhcpagent for this static address. If the address object is of type 3674 * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent. 3675 * If a dhcp address has not yet been acquired, a DHCP_START is sent to the 3676 * dhcpagent. This operation is not supported for an address object of 3677 * type IPADM_ADDR_IPV6_ADDRCONF. 3678 */ 3679 ipadm_status_t 3680 ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname, 3681 uint32_t ipadm_flags) 3682 { 3683 ipadm_status_t status = IPADM_SUCCESS; 3684 uint64_t flags; 3685 struct ipadm_addrobj_s ipaddr; 3686 sa_family_t af; 3687 char lifname[LIFNAMSIZ]; 3688 boolean_t inform = 3689 ((ipadm_flags & IPADM_OPT_INFORM) != 0); 3690 3691 /* check for solaris.network.interface.config authorization */ 3692 if (!ipadm_check_auth()) 3693 return (IPADM_EAUTH); 3694 3695 bzero(&ipaddr, sizeof (ipaddr)); 3696 /* validate input */ 3697 if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname, 3698 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) { 3699 return (IPADM_INVALID_ARG); 3700 } 3701 3702 /* Retrieve the address object information. */ 3703 status = i_ipadm_get_addrobj(iph, &ipaddr); 3704 if (status != IPADM_SUCCESS) 3705 return (status); 3706 3707 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) 3708 return (IPADM_OP_DISABLE_OBJ); 3709 3710 if (i_ipadm_is_vni(ipaddr.ipadm_ifname)) 3711 return (IPADM_NOTSUP); 3712 if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC) 3713 return (IPADM_INVALID_ARG); 3714 af = ipaddr.ipadm_af; 3715 if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) { 3716 i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname)); 3717 status = i_ipadm_get_flags(iph, lifname, af, &flags); 3718 if (status != IPADM_SUCCESS) 3719 return (status); 3720 if (inform) { 3721 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1) 3722 return (IPADM_DHCP_START_ERROR); 3723 3724 ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT; 3725 return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL)); 3726 } 3727 if (!(flags & IFF_DUPLICATE)) 3728 return (IPADM_SUCCESS); 3729 status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0); 3730 } else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) { 3731 status = i_ipadm_refresh_dhcp(&ipaddr); 3732 } else { 3733 status = IPADM_NOTSUP; 3734 } 3735 return (status); 3736 } 3737 3738 /* 3739 * This is called from ipadm_refresh_addr() and i_ipadm_set_reqhost() to 3740 * send a DHCP_EXTEND message and possibly a DHCP_START message 3741 * to the dhcpagent. 3742 */ 3743 static ipadm_status_t 3744 i_ipadm_refresh_dhcp(ipadm_addrobj_t ipaddr) 3745 { 3746 ipadm_status_t status; 3747 int dherr; 3748 3749 status = i_ipadm_op_dhcp(ipaddr, DHCP_EXTEND, &dherr); 3750 /* 3751 * Restart the dhcp address negotiation with server if no 3752 * address has been acquired yet. 3753 */ 3754 if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) { 3755 ipaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT; 3756 status = i_ipadm_op_dhcp(ipaddr, DHCP_START, NULL); 3757 } 3758 3759 return (status); 3760 } 3761 3762 /* 3763 * This is called from ipadm_create_addr() to validate the address parameters. 3764 * It does the following steps: 3765 * 1. Validates the interface name. 3766 * 2. Verifies that the interface is not an IPMP meta-interface or an 3767 * underlying interface. 3768 * 3. In case of a persistent operation, verifies that the interface 3769 * is persistent. Returns error if interface is not enabled but 3770 * is in persistent config. 3771 * 4. Verifies that the destination address is not set or the address type is 3772 * not DHCP or ADDRCONF when the interface is a loopback interface. 3773 * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface 3774 * has IFF_VRRP interface flag set. 3775 */ 3776 static ipadm_status_t 3777 i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, 3778 uint32_t flags) 3779 { 3780 sa_family_t af; 3781 sa_family_t other_af; 3782 char *ifname; 3783 ipadm_status_t status; 3784 boolean_t legacy = (iph->iph_flags & IPH_LEGACY); 3785 boolean_t islo, isvni; 3786 uint64_t ifflags = 0; 3787 boolean_t p_exists; 3788 boolean_t af_exists, other_af_exists, a_exists; 3789 3790 if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST || 3791 (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) { 3792 return (IPADM_INVALID_ARG); 3793 } 3794 3795 if (ipaddr->ipadm_af == AF_UNSPEC) 3796 return (IPADM_BAD_ADDR); 3797 3798 if (!legacy && ipaddr->ipadm_lifnum != 0) 3799 return (IPADM_INVALID_ARG); 3800 3801 if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC) 3802 return (IPADM_NOTSUP); 3803 3804 ifname = ipaddr->ipadm_ifname; 3805 3806 if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname)) 3807 return (IPADM_NOTSUP); 3808 3809 af = ipaddr->ipadm_af; 3810 af_exists = ipadm_if_enabled(iph, ifname, af); 3811 /* 3812 * For legacy case, interfaces are not implicitly plumbed. We need to 3813 * check if the interface exists in the active configuration. 3814 */ 3815 if (legacy && !af_exists) 3816 return (IPADM_ENXIO); 3817 3818 other_af = (af == AF_INET ? AF_INET6 : AF_INET); 3819 other_af_exists = ipadm_if_enabled(iph, ifname, other_af); 3820 /* 3821 * Check if one of the v4 or the v6 interfaces exists in the 3822 * active configuration. An interface is considered disabled only 3823 * if both v4 and v6 are not active. 3824 */ 3825 a_exists = (af_exists || other_af_exists); 3826 3827 /* Check if interface exists in the persistent configuration. */ 3828 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists); 3829 if (status != IPADM_SUCCESS) 3830 return (status); 3831 if (!a_exists && p_exists) 3832 return (IPADM_OP_DISABLE_OBJ); 3833 if ((flags & IPADM_OPT_PERSIST) && a_exists && !p_exists) { 3834 /* 3835 * If address has to be created persistently, 3836 * and the interface does not exist in the persistent 3837 * store but in active config, fail. 3838 */ 3839 return (IPADM_TEMPORARY_OBJ); 3840 } 3841 if (af_exists) { 3842 status = i_ipadm_get_flags(iph, ifname, af, &ifflags); 3843 if (status != IPADM_SUCCESS) 3844 return (status); 3845 } 3846 3847 /* Perform validation steps (4) and (5) */ 3848 islo = i_ipadm_is_loopback(ifname); 3849 isvni = i_ipadm_is_vni(ifname); 3850 switch (ipaddr->ipadm_atype) { 3851 case IPADM_ADDR_STATIC: 3852 if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0') 3853 return (IPADM_INVALID_ARG); 3854 /* Check for a valid src address */ 3855 if (!legacy && sockaddrunspec( 3856 (struct sockaddr *)&ipaddr->ipadm_static_addr)) 3857 return (IPADM_BAD_ADDR); 3858 break; 3859 case IPADM_ADDR_DHCP: 3860 if (islo || (ifflags & IFF_VRRP)) 3861 return (IPADM_NOTSUP); 3862 break; 3863 case IPADM_ADDR_IPV6_ADDRCONF: 3864 if (islo || (ifflags & IFF_VRRP) || 3865 i_ipadm_is_6to4(iph, ifname)) { 3866 return (IPADM_NOTSUP); 3867 } 3868 break; 3869 default: 3870 return (IPADM_INVALID_ARG); 3871 } 3872 3873 return (IPADM_SUCCESS); 3874 } 3875 3876 ipadm_status_t 3877 i_ipadm_merge_addrprops_from_nvl(nvlist_t *invl, nvlist_t *onvl, 3878 const char *aobjname) 3879 { 3880 const char * const ADDRPROPS[] = 3881 { IPADM_NVP_PREFIXLEN, IPADM_NVP_REQHOST }; 3882 const size_t ADDRPROPSLEN = 3883 sizeof (ADDRPROPS) / sizeof (*ADDRPROPS); 3884 nvpair_t *nvp, *propnvp; 3885 nvlist_t *tnvl; 3886 char *aname; 3887 const char *propname; 3888 size_t i; 3889 int err; 3890 3891 for (i = 0; i < ADDRPROPSLEN; ++i) { 3892 propname = ADDRPROPS[i]; 3893 3894 for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL; 3895 nvp = nvlist_next_nvpair(invl, nvp)) { 3896 if (nvpair_value_nvlist(nvp, &tnvl) == 0 && 3897 nvlist_exists(tnvl, propname) && 3898 nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME, 3899 &aname) == 0 && strcmp(aname, aobjname) == 0) { 3900 3901 /* 3902 * property named `propname' exists for given 3903 * aobj 3904 */ 3905 (void) nvlist_lookup_nvpair(tnvl, propname, 3906 &propnvp); 3907 err = nvlist_add_nvpair(onvl, propnvp); 3908 if (err == 0) { 3909 err = nvlist_remove(invl, 3910 nvpair_name(nvp), nvpair_type(nvp)); 3911 } 3912 if (err != 0) 3913 return (ipadm_errno2status(err)); 3914 break; 3915 } 3916 } 3917 } 3918 return (IPADM_SUCCESS); 3919 } 3920 3921 /* 3922 * Re-enables the address object `aobjname' based on the saved 3923 * configuration for `aobjname'. 3924 */ 3925 ipadm_status_t 3926 ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags) 3927 { 3928 nvlist_t *addrnvl, *nvl; 3929 nvpair_t *nvp; 3930 ipadm_status_t status; 3931 struct ipadm_addrobj_s ipaddr; 3932 3933 /* check for solaris.network.interface.config authorization */ 3934 if (!ipadm_check_auth()) 3935 return (IPADM_EAUTH); 3936 3937 /* validate input */ 3938 if (flags & IPADM_OPT_PERSIST) 3939 return (IPADM_NOTSUP); 3940 if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname, 3941 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) { 3942 return (IPADM_INVALID_ARG); 3943 } 3944 3945 /* Retrieve the address object information. */ 3946 status = i_ipadm_get_addrobj(iph, &ipaddr); 3947 if (status != IPADM_SUCCESS) 3948 return (status); 3949 if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) 3950 return (IPADM_ADDROBJ_EXISTS); 3951 3952 status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl); 3953 if (status != IPADM_SUCCESS) 3954 return (status); 3955 3956 assert(addrnvl != NULL); 3957 3958 for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL; 3959 nvp = nvlist_next_nvpair(addrnvl, nvp)) { 3960 if (nvpair_value_nvlist(nvp, &nvl) != 0) 3961 continue; 3962 3963 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) || 3964 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) || 3965 nvlist_exists(nvl, IPADM_NVP_DHCP)) { 3966 status = i_ipadm_merge_addrprops_from_nvl(addrnvl, nvl, 3967 aobjname); 3968 if (status != IPADM_SUCCESS) 3969 continue; 3970 } 3971 iph->iph_flags |= IPH_INIT; 3972 status = i_ipadm_init_addrobj(iph, nvl); 3973 iph->iph_flags &= ~IPH_INIT; 3974 if (status != IPADM_SUCCESS) 3975 break; 3976 } 3977 3978 nvlist_free(addrnvl); 3979 return (status); 3980 } 3981 3982 /* 3983 * Disables the address object in `aobjname' from the active configuration. 3984 * Error code return values follow the model in ipadm_delete_addr(). 3985 */ 3986 ipadm_status_t 3987 ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags) 3988 { 3989 /* validate input */ 3990 if (flags & IPADM_OPT_PERSIST) 3991 return (IPADM_NOTSUP); 3992 3993 return (ipadm_delete_addr(iph, aobjname, IPADM_OPT_ACTIVE)); 3994 } 3995