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