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