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