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