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