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