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