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