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