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