Merge branch 'merges' of git://repo.or.cz/unleashed into merges
[unleashed.git] / usr / src / lib / libipadm / common / ipadm_addr.c
blob635cf194026472309e952dfbead4d3852a6cb362
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.
24 * Copyright (c) 2016-2017, Chris Fraire <cfraire@me.com>.
28 * This file contains functions for address management such as creating
29 * an address, deleting an address, enabling an address, disabling an
30 * address, bringing an address down or up, setting/getting properties
31 * on an address object and listing address information
32 * for all addresses in active as well as persistent configuration.
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/param.h>
37 #include <netdb.h>
38 #include <inet/ip.h>
39 #include <string.h>
40 #include <strings.h>
41 #include <assert.h>
42 #include <sys/sockio.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <stropts.h>
46 #include <zone.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <fcntl.h>
50 #include <ctype.h>
51 #include <dhcpagent_util.h>
52 #include <dhcpagent_ipc.h>
53 #include <dhcp_inittab.h>
54 #include <dhcp_symbol.h>
55 #include <ipadm_ndpd.h>
56 #include <libdladm.h>
57 #include <libdllink.h>
58 #include <libdliptun.h>
59 #include <ifaddrs.h>
60 #include "libipadm_impl.h"
62 #define SIN6(a) ((struct sockaddr_in6 *)a)
63 #define SIN(a) ((struct sockaddr_in *)a)
65 static ipadm_status_t i_ipadm_create_addr(ipadm_handle_t, ipadm_addrobj_t,
66 uint32_t);
67 static ipadm_status_t i_ipadm_create_dhcp(ipadm_handle_t, ipadm_addrobj_t,
68 uint32_t);
69 static ipadm_status_t i_ipadm_delete_dhcp(ipadm_handle_t, ipadm_addrobj_t,
70 boolean_t);
71 static ipadm_status_t i_ipadm_refresh_dhcp(ipadm_addrobj_t);
72 static ipadm_status_t i_ipadm_get_db_addr(ipadm_handle_t, const char *,
73 const char *, nvlist_t **);
74 static ipadm_status_t i_ipadm_op_dhcp(ipadm_addrobj_t, dhcp_ipc_type_t,
75 int *);
76 static ipadm_status_t i_ipadm_dhcp_status(ipadm_addrobj_t addr,
77 dhcp_status_t *status, int *dhcperror);
78 static ipadm_status_t i_ipadm_validate_create_addr(ipadm_handle_t,
79 ipadm_addrobj_t, uint32_t);
80 static ipadm_status_t i_ipadm_addr_persist_nvl(ipadm_handle_t, nvlist_t *,
81 uint32_t);
82 static ipadm_status_t i_ipadm_get_default_prefixlen(struct sockaddr_storage *,
83 uint32_t *);
84 static ipadm_status_t i_ipadm_get_static_addr_db(ipadm_handle_t,
85 ipadm_addrobj_t);
86 static boolean_t i_ipadm_is_user_aobjname_valid(const char *);
87 static ipadm_prop_desc_t *i_ipadm_get_addrprop_desc(const char *pname);
90 * Callback functions to retrieve property values from the kernel. These
91 * functions, when required, translate the values from the kernel to a format
92 * suitable for printing. They also retrieve DEFAULT, PERM and POSSIBLE values
93 * for a given property.
95 static ipadm_pd_getf_t i_ipadm_get_prefixlen, i_ipadm_get_addr_flag,
96 i_ipadm_get_zone, i_ipadm_get_broadcast,
97 i_ipadm_get_primary, i_ipadm_get_reqhost;
100 * Callback functions to set property values. These functions translate the
101 * values to a format suitable for kernel consumption, allocate the necessary
102 * ioctl buffers and then invoke ioctl(); or in the case of reqhost, get the
103 * collaborating agent to set the value.
105 static ipadm_pd_setf_t i_ipadm_set_prefixlen, i_ipadm_set_addr_flag,
106 i_ipadm_set_zone, i_ipadm_set_reqhost;
108 static ipadm_status_t i_ipadm_set_aobj_addrprop(ipadm_handle_t iph,
109 ipadm_addrobj_t ipaddr, uint_t flags, const char *propname);
111 /* address properties description table */
112 ipadm_prop_desc_t ipadm_addrprop_table[] = {
113 { "broadcast", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
114 NULL, NULL, i_ipadm_get_broadcast },
116 { "deprecated", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
117 i_ipadm_set_addr_flag, i_ipadm_get_onoff,
118 i_ipadm_get_addr_flag },
120 { IPADM_NVP_PREFIXLEN, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
121 i_ipadm_set_prefixlen, i_ipadm_get_prefixlen,
122 i_ipadm_get_prefixlen },
125 * primary is read-only because there is no operation to un-set
126 * DHCP_IF_PRIMARY in dhcpagent except to delete-addr and then
127 * re-create-addr.
129 { "primary", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
130 NULL, NULL, i_ipadm_get_primary },
132 { "private", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
133 i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
135 { IPADM_NVP_REQHOST, NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
136 i_ipadm_set_reqhost, NULL, i_ipadm_get_reqhost },
138 { "transmit", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
139 i_ipadm_set_addr_flag, i_ipadm_get_onoff, i_ipadm_get_addr_flag },
141 { "zone", NULL, IPADMPROP_CLASS_ADDR, MOD_PROTO_NONE, 0,
142 i_ipadm_set_zone, NULL, i_ipadm_get_zone },
144 { NULL, NULL, 0, 0, 0, NULL, NULL, NULL }
147 static ipadm_prop_desc_t up_addrprop = { "up", NULL, IPADMPROP_CLASS_ADDR,
148 MOD_PROTO_NONE, 0, NULL, NULL, NULL };
151 * Helper function that initializes the `ipadm_ifname', `ipadm_aobjname', and
152 * `ipadm_atype' fields of the given `ipaddr'.
154 void
155 i_ipadm_init_addr(ipadm_addrobj_t ipaddr, const char *ifname,
156 const char *aobjname, ipadm_addr_type_t atype)
158 bzero(ipaddr, sizeof (struct ipadm_addrobj_s));
159 (void) strlcpy(ipaddr->ipadm_ifname, ifname,
160 sizeof (ipaddr->ipadm_ifname));
161 (void) strlcpy(ipaddr->ipadm_aobjname, aobjname,
162 sizeof (ipaddr->ipadm_aobjname));
163 ipaddr->ipadm_atype = atype;
167 * Determine the permission of the property depending on whether it has a
168 * set() and/or get() callback functions.
170 static ipadm_status_t
171 i_ipadm_pd2permstr(ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize)
173 uint_t perm;
174 size_t nbytes;
176 perm = 0;
177 if (pdp->ipd_set != NULL)
178 perm |= MOD_PROP_PERM_WRITE;
179 if (pdp->ipd_get != NULL)
180 perm |= MOD_PROP_PERM_READ;
182 nbytes = snprintf(buf, *bufsize, "%c%c",
183 ((perm & MOD_PROP_PERM_READ) != 0) ? 'r' : '-',
184 ((perm & MOD_PROP_PERM_WRITE) != 0) ? 'w' : '-');
186 if (nbytes >= *bufsize) {
187 /* insufficient buffer space */
188 *bufsize = nbytes + 1;
189 return (IPADM_NO_BUFS);
191 return (IPADM_SUCCESS);
195 * Given an addrobj with `ipadm_aobjname' filled in, i_ipadm_get_addrobj()
196 * retrieves the information necessary for any operation on the object,
197 * such as delete-addr, enable-addr, disable-addr, up-addr, down-addr,
198 * refresh-addr, get-addrprop or set-addrprop. The information include
199 * the logical interface number, address type, address family,
200 * the interface id (if the address type is IPADM_ADDR_IPV6_ADDRCONF) and
201 * the ipadm_flags that indicate if the address is present in
202 * active configuration or persistent configuration or both. If the address
203 * is not found, IPADM_NOTSUP is returned.
205 ipadm_status_t
206 i_ipadm_get_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
208 ipmgmt_aobjop_arg_t larg;
209 ipmgmt_aobjop_rval_t rval, *rvalp;
210 int err = 0;
212 /* populate the door_call argument structure */
213 larg.ia_cmd = IPMGMT_CMD_AOBJNAME2ADDROBJ;
214 (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
215 sizeof (larg.ia_aobjname));
217 rvalp = &rval;
218 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
219 sizeof (rval), B_FALSE);
220 if (err != 0)
221 return (ipadm_errno2status(err));
222 (void) strlcpy(ipaddr->ipadm_ifname, rval.ir_ifname,
223 sizeof (ipaddr->ipadm_ifname));
224 ipaddr->ipadm_lifnum = rval.ir_lnum;
225 ipaddr->ipadm_atype = rval.ir_atype;
226 ipaddr->ipadm_af = rval.ir_family;
227 ipaddr->ipadm_flags = rval.ir_flags;
228 switch (rval.ir_atype) {
229 case IPADM_ADDR_IPV6_ADDRCONF:
230 ipaddr->ipadm_intfid = rval.ipmgmt_ir_intfid;
231 break;
232 case IPADM_ADDR_DHCP:
233 if (strlcpy(ipaddr->ipadm_reqhost, rval.ipmgmt_ir_reqhost,
234 sizeof (ipaddr->ipadm_reqhost)) >=
235 sizeof (ipaddr->ipadm_reqhost)) {
237 * shouldn't get here as the buffers are defined
238 * with same length, MAX_NAME_LEN
240 return (IPADM_FAILURE);
242 break;
243 default:
244 break;
247 return (IPADM_SUCCESS);
251 * Retrieves the static address (IPv4 or IPv6) for the given address object
252 * in `ipaddr' from persistent DB.
254 static ipadm_status_t
255 i_ipadm_get_static_addr_db(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
257 ipadm_status_t status;
258 nvlist_t *onvl;
259 nvlist_t *anvl = NULL;
260 nvlist_t *nvladdr;
261 nvpair_t *nvp;
262 char *name;
263 char *aobjname = ipaddr->ipadm_aobjname;
264 char *sname;
265 sa_family_t af = AF_UNSPEC;
268 * Get the address line in the nvlist `onvl' from ipmgmtd daemon.
270 status = i_ipadm_get_db_addr(iph, NULL, aobjname, &onvl);
271 if (status != IPADM_SUCCESS)
272 return (status);
274 * Walk through the nvlist `onvl' to extract the IPADM_NVP_IPV4ADDR
275 * or the IPADM_NVP_IPV6ADDR name-value pair.
277 for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
278 nvp = nvlist_next_nvpair(onvl, NULL)) {
279 if (nvpair_value_nvlist(nvp, &anvl) != 0)
280 continue;
281 if (nvlist_exists(anvl, IPADM_NVP_IPV4ADDR) ||
282 nvlist_exists(anvl, IPADM_NVP_IPV6ADDR))
283 break;
285 if (nvp == NULL)
286 goto fail;
287 for (nvp = nvlist_next_nvpair(anvl, NULL);
288 nvp != NULL; nvp = nvlist_next_nvpair(anvl, nvp)) {
289 name = nvpair_name(nvp);
290 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
291 af = AF_INET;
292 break;
293 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
294 af = AF_INET6;
295 break;
298 assert(af != AF_UNSPEC);
299 if (nvpair_value_nvlist(nvp, &nvladdr) != 0 ||
300 nvlist_lookup_string(nvladdr, IPADM_NVP_IPADDRHNAME, &sname) != 0 ||
301 ipadm_set_addr(ipaddr, sname, af) != IPADM_SUCCESS) {
302 goto fail;
304 nvlist_free(onvl);
305 return (IPADM_SUCCESS);
306 fail:
307 nvlist_free(onvl);
308 return (IPADM_NOTFOUND);
312 * For the given `addrobj->ipadm_lifnum' and `addrobj->ipadm_af', this function
313 * fills in the address objname, the address type and the ipadm_flags.
315 ipadm_status_t
316 i_ipadm_get_lif2addrobj(ipadm_handle_t iph, ipadm_addrobj_t addrobj)
318 ipmgmt_aobjop_arg_t larg;
319 ipmgmt_aobjop_rval_t rval, *rvalp;
320 int err;
322 larg.ia_cmd = IPMGMT_CMD_LIF2ADDROBJ;
323 (void) strlcpy(larg.ia_ifname, addrobj->ipadm_ifname,
324 sizeof (larg.ia_ifname));
325 larg.ia_lnum = addrobj->ipadm_lifnum;
326 larg.ia_family = addrobj->ipadm_af;
328 rvalp = &rval;
329 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
330 sizeof (rval), B_FALSE);
331 if (err != 0)
332 return (ipadm_errno2status(err));
333 (void) strlcpy(addrobj->ipadm_aobjname, rval.ir_aobjname,
334 sizeof (addrobj->ipadm_aobjname));
335 addrobj->ipadm_atype = rval.ir_atype;
336 addrobj->ipadm_flags = rval.ir_flags;
338 return (IPADM_SUCCESS);
342 * Adds an addrobj to ipmgmtd daemon's aobjmap (active configuration).
343 * with the given name and logical interface number.
344 * This API is called by in.ndpd to add addrobjs when new prefixes or
345 * dhcpv6 addresses are configured.
347 ipadm_status_t
348 ipadm_add_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
349 const char *aobjname, ipadm_addr_type_t atype, int lnum)
351 ipmgmt_aobjop_arg_t larg;
352 int err;
354 larg.ia_cmd = IPMGMT_CMD_ADDROBJ_ADD;
355 (void) strlcpy(larg.ia_ifname, ifname, sizeof (larg.ia_ifname));
356 (void) strlcpy(larg.ia_aobjname, aobjname, sizeof (larg.ia_aobjname));
357 larg.ia_atype = atype;
358 larg.ia_lnum = lnum;
359 larg.ia_family = af;
360 err = ipadm_door_call(iph, &larg, sizeof (larg), NULL, 0, B_FALSE);
361 return (ipadm_errno2status(err));
365 * Deletes an address object with given name and logical number from ipmgmtd
366 * daemon's aobjmap (active configuration). This API is called by in.ndpd to
367 * remove addrobjs when auto-configured prefixes or dhcpv6 addresses are
368 * removed.
370 ipadm_status_t
371 ipadm_delete_aobjname(ipadm_handle_t iph, const char *ifname, sa_family_t af,
372 const char *aobjname, ipadm_addr_type_t atype, int lnum)
374 struct ipadm_addrobj_s aobj;
376 i_ipadm_init_addr(&aobj, ifname, aobjname, atype);
377 aobj.ipadm_af = af;
378 aobj.ipadm_lifnum = lnum;
379 return (i_ipadm_delete_addrobj(iph, &aobj, IPADM_OPT_ACTIVE));
383 * Gets all the addresses from active configuration and populates the
384 * address information in `addrinfo'.
386 static ipadm_status_t
387 i_ipadm_active_addr_info(ipadm_handle_t iph, const char *ifname,
388 ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
390 ipadm_status_t status;
391 struct ifaddrs *ifap, *ifa;
392 ipadm_addr_info_t *curr, *prev = NULL;
393 struct ifaddrs *cifaddr;
394 struct lifreq lifr;
395 int sock;
396 uint64_t flags;
397 char cifname[LIFNAMSIZ];
398 struct sockaddr_in6 *sin6;
399 struct ipadm_addrobj_s ipaddr;
400 char *sep;
401 int lnum;
403 retry:
404 *addrinfo = NULL;
406 /* Get all the configured addresses */
407 if (getallifaddrs(AF_UNSPEC, &ifa, lifc_flags) < 0)
408 return (ipadm_errno2status(errno));
409 /* Return if there is nothing to process. */
410 if (ifa == NULL)
411 return (IPADM_SUCCESS);
412 bzero(&lifr, sizeof (lifr));
413 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
414 struct sockaddr_storage data;
416 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
417 lnum = 0;
418 if ((sep = strrchr(cifname, ':')) != NULL) {
419 *sep++ = '\0';
420 lnum = atoi(sep);
422 if (ifname != NULL && strcmp(cifname, ifname) != 0)
423 continue;
424 if (!(ipadm_flags & IPADM_OPT_ZEROADDR) &&
425 sockaddrunspec(ifap->ifa_addr) &&
426 !(ifap->ifa_flags & IFF_DHCPRUNNING))
427 continue;
429 /* Allocate and populate the current node in the list. */
430 if ((curr = calloc(1, sizeof (ipadm_addr_info_t))) == NULL)
431 goto fail;
433 /* Link to the list in `addrinfo'. */
434 if (prev != NULL)
435 prev->ia_ifa.ifa_next = &curr->ia_ifa;
436 else
437 *addrinfo = curr;
438 prev = curr;
440 cifaddr = &curr->ia_ifa;
441 if ((cifaddr->ifa_name = strdup(ifap->ifa_name)) == NULL)
442 goto fail;
443 cifaddr->ifa_flags = ifap->ifa_flags;
444 cifaddr->ifa_addr = malloc(sizeof (struct sockaddr_storage));
445 if (cifaddr->ifa_addr == NULL)
446 goto fail;
447 (void) memcpy(cifaddr->ifa_addr, ifap->ifa_addr,
448 sizeof (struct sockaddr_storage));
449 cifaddr->ifa_netmask = malloc(sizeof (struct sockaddr_storage));
450 if (cifaddr->ifa_netmask == NULL)
451 goto fail;
452 (void) memcpy(cifaddr->ifa_netmask, ifap->ifa_netmask,
453 sizeof (struct sockaddr_storage));
454 if (ifap->ifa_flags & IFF_POINTOPOINT) {
455 cifaddr->ifa_dstaddr = malloc(
456 sizeof (struct sockaddr_storage));
457 if (cifaddr->ifa_dstaddr == NULL)
458 goto fail;
459 (void) memcpy(cifaddr->ifa_dstaddr, ifap->ifa_dstaddr,
460 sizeof (struct sockaddr_storage));
461 } else if (ifap->ifa_flags & IFF_BROADCAST) {
462 cifaddr->ifa_broadaddr = malloc(
463 sizeof (struct sockaddr_storage));
464 if (cifaddr->ifa_broadaddr == NULL)
465 goto fail;
466 (void) memcpy(cifaddr->ifa_broadaddr,
467 ifap->ifa_broadaddr,
468 sizeof (struct sockaddr_storage));
470 /* Get the addrobj name stored for this logical interface. */
471 ipaddr.ipadm_aobjname[0] = '\0';
472 (void) strlcpy(ipaddr.ipadm_ifname, cifname,
473 sizeof (ipaddr.ipadm_ifname));
474 ipaddr.ipadm_lifnum = lnum;
475 ipaddr.ipadm_af = ifap->ifa_addr->sa_family;
476 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
479 * Find address type from ifa_flags, if we could not get it
480 * from daemon.
482 (void) memcpy(&data, ifap->ifa_addr,
483 sizeof (struct sockaddr_in6));
484 sin6 = SIN6(&data);
485 flags = ifap->ifa_flags;
486 if (status == IPADM_SUCCESS) {
487 (void) strlcpy(curr->ia_aobjname, ipaddr.ipadm_aobjname,
488 sizeof (curr->ia_aobjname));
489 curr->ia_atype = ipaddr.ipadm_atype;
490 } else if ((flags & IFF_DHCPRUNNING) && (!(flags & IFF_IPV6) ||
491 !IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))) {
492 curr->ia_atype = IPADM_ADDR_DHCP;
493 } else if (flags & IFF_ADDRCONF) {
494 curr->ia_atype = IPADM_ADDR_IPV6_ADDRCONF;
495 } else {
496 curr->ia_atype = IPADM_ADDR_STATIC;
499 * Populate the flags for the active configuration from the
500 * `ifa_flags'.
502 if (!(flags & IFF_UP)) {
503 if (flags & IFF_DUPLICATE)
504 curr->ia_state = IFA_DUPLICATE;
505 else
506 curr->ia_state = IFA_DOWN;
507 } else {
508 curr->ia_cflags |= IA_UP;
509 if (flags & IFF_RUNNING) {
510 (void) strlcpy(lifr.lifr_name, ifap->ifa_name,
511 sizeof (lifr.lifr_name));
512 sock = (ifap->ifa_addr->sa_family == AF_INET) ?
513 iph->iph_sock : iph->iph_sock6;
514 if (ioctl(sock, SIOCGLIFDADSTATE,
515 (caddr_t)&lifr) < 0) {
516 if (errno == ENXIO) {
517 freeifaddrs(ifa);
518 ipadm_free_addr_info(*addrinfo);
519 goto retry;
521 goto fail;
523 if (lifr.lifr_dadstate == DAD_IN_PROGRESS)
524 curr->ia_state = IFA_TENTATIVE;
525 else
526 curr->ia_state = IFA_OK;
527 } else {
528 curr->ia_state = IFA_INACCESSIBLE;
531 if (flags & IFF_UNNUMBERED)
532 curr->ia_cflags |= IA_UNNUMBERED;
533 if (flags & IFF_PRIVATE)
534 curr->ia_cflags |= IA_PRIVATE;
535 if (flags & IFF_TEMPORARY)
536 curr->ia_cflags |= IA_TEMPORARY;
537 if (flags & IFF_DEPRECATED)
538 curr->ia_cflags |= IA_DEPRECATED;
542 freeifaddrs(ifa);
543 return (IPADM_SUCCESS);
545 fail:
546 /* On error, cleanup everything and return. */
547 ipadm_free_addr_info(*addrinfo);
548 *addrinfo = NULL;
549 freeifaddrs(ifa);
550 return (ipadm_errno2status(errno));
554 * From the given `name', i_ipadm_name2atype() deduces the address type
555 * and address family. If the `name' implies an address, it returns B_TRUE.
556 * Else, returns B_FALSE and leaves the output parameters unchanged.
558 boolean_t
559 i_ipadm_name2atype(const char *name, sa_family_t *af, ipadm_addr_type_t *type)
561 boolean_t is_addr = B_TRUE;
563 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0) {
564 *af = AF_INET;
565 *type = IPADM_ADDR_STATIC;
566 } else if (strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
567 *af = AF_INET6;
568 *type = IPADM_ADDR_STATIC;
569 } else if (strcmp(name, IPADM_NVP_DHCP) == 0) {
570 *af = AF_INET;
571 *type = IPADM_ADDR_DHCP;
572 } else if (strcmp(name, IPADM_NVP_INTFID) == 0) {
573 *af = AF_INET6;
574 *type = IPADM_ADDR_IPV6_ADDRCONF;
575 } else {
576 is_addr = B_FALSE;
579 return (is_addr);
583 * Parses the given nvlist `nvl' for an address or an address property.
584 * The input nvlist must contain either an address or an address property.
585 * `ainfo' is an input as well as output parameter. When an address or an
586 * address property is found, `ainfo' is updated with the information found.
587 * Some of the fields may be already filled in by the calling function.
589 * The fields that will be filled/updated by this function are `ia_pflags',
590 * `ia_sname' and `ia_dname'. Values for `ia_pflags' are obtained if the `nvl'
591 * contains an address property. `ia_sname', `ia_dname', and `ia_pflags' are
592 * obtained if `nvl' contains an address.
594 static ipadm_status_t
595 i_ipadm_nvl2ainfo_common(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
597 nvlist_t *nvladdr;
598 char *name;
599 char *propstr = NULL;
600 char *sname, *dname;
601 nvpair_t *nvp;
602 sa_family_t af;
603 ipadm_addr_type_t atype;
604 boolean_t is_addr = B_FALSE;
605 int err;
607 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
608 nvp = nvlist_next_nvpair(nvl, nvp)) {
609 name = nvpair_name(nvp);
610 if (i_ipadm_name2atype(name, &af, &atype)) {
611 err = nvpair_value_nvlist(nvp, &nvladdr);
612 is_addr = B_TRUE;
613 } else if (IPADM_PRIV_NVP(name)) {
614 continue;
615 } else {
616 err = nvpair_value_string(nvp, &propstr);
618 if (err != 0)
619 return (ipadm_errno2status(err));
622 if (is_addr) {
624 * We got an address from the nvlist `nvl'.
625 * Parse `nvladdr' and populate relevant information
626 * in `ainfo'.
628 switch (atype) {
629 case IPADM_ADDR_STATIC:
630 if (strcmp(name, "up") == 0 &&
631 strcmp(propstr, "yes") == 0) {
632 ainfo->ia_pflags |= IA_UP;
635 * For static addresses, we need to get the hostnames.
637 err = nvlist_lookup_string(nvladdr,
638 IPADM_NVP_IPADDRHNAME, &sname);
639 if (err != 0)
640 return (ipadm_errno2status(err));
641 (void) strlcpy(ainfo->ia_sname, sname,
642 sizeof (ainfo->ia_sname));
643 err = nvlist_lookup_string(nvladdr,
644 IPADM_NVP_IPDADDRHNAME, &dname);
645 if (err == 0) {
646 (void) strlcpy(ainfo->ia_dname, dname,
647 sizeof (ainfo->ia_dname));
649 break;
650 case IPADM_ADDR_DHCP:
651 case IPADM_ADDR_IPV6_ADDRCONF:
653 * dhcp and addrconf address objects are always
654 * marked up when re-enabled.
656 ainfo->ia_pflags |= IA_UP;
657 break;
658 default:
659 return (IPADM_FAILURE);
661 } else {
663 * We got an address property from `nvl'. Parse the
664 * name and the property value. Update the `ainfo->ia_pflags'
665 * for the flags.
667 if (strcmp(name, "deprecated") == 0) {
668 if (strcmp(propstr, IPADM_ONSTR) == 0)
669 ainfo->ia_pflags |= IA_DEPRECATED;
670 } else if (strcmp(name, "private") == 0) {
671 if (strcmp(propstr, IPADM_ONSTR) == 0)
672 ainfo->ia_pflags |= IA_PRIVATE;
676 return (IPADM_SUCCESS);
680 * Parses the given nvlist `nvl' for an address or an address property.
681 * The input nvlist must contain either an address or an address property.
682 * `ainfo' is an input as well as output parameter. When an address or an
683 * address property is found, `ainfo' is updated with the information found.
684 * Some of the fields may be already filled in by the calling function,
685 * because of previous calls to i_ipadm_nvl2ainfo_active().
687 * Since the address object in `nvl' is also in the active configuration, the
688 * fields that will be filled/updated by this function are `ia_pflags',
689 * `ia_sname' and `ia_dname'.
691 * If this function returns an error, the calling function will take
692 * care of freeing the fields in `ainfo'.
694 static ipadm_status_t
695 i_ipadm_nvl2ainfo_active(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
697 return (i_ipadm_nvl2ainfo_common(nvl, ainfo));
701 * Parses the given nvlist `nvl' for an address or an address property.
702 * The input nvlist must contain either an address or an address property.
703 * `ainfo' is an input as well as output parameter. When an address or an
704 * address property is found, `ainfo' is updated with the information found.
705 * Some of the fields may be already filled in by the calling function,
706 * because of previous calls to i_ipadm_nvl2ainfo_persist().
708 * All the relevant fields in `ainfo' will be filled by this function based
709 * on what we find in `nvl'.
711 * If this function returns an error, the calling function will take
712 * care of freeing the fields in `ainfo'.
714 static ipadm_status_t
715 i_ipadm_nvl2ainfo_persist(nvlist_t *nvl, ipadm_addr_info_t *ainfo)
717 nvlist_t *nvladdr;
718 struct ifaddrs *ifa;
719 char *name;
720 char *ifname = NULL;
721 char *aobjname = NULL;
722 char *propstr = NULL;
723 nvpair_t *nvp;
724 sa_family_t af;
725 ipadm_addr_type_t atype;
726 boolean_t is_addr = B_FALSE;
727 size_t size = sizeof (struct sockaddr_storage);
728 uint32_t plen = 0;
729 int err;
730 ipadm_status_t status;
732 status = i_ipadm_nvl2ainfo_common(nvl, ainfo);
733 if (status != IPADM_SUCCESS)
734 return (status);
736 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
737 nvp = nvlist_next_nvpair(nvl, nvp)) {
738 name = nvpair_name(nvp);
739 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
740 err = nvpair_value_string(nvp, &ifname);
741 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
742 err = nvpair_value_string(nvp, &aobjname);
743 } else if (i_ipadm_name2atype(name, &af, &atype)) {
744 err = nvpair_value_nvlist(nvp, &nvladdr);
745 is_addr = B_TRUE;
746 } else {
747 err = nvpair_value_string(nvp, &propstr);
749 if (err != 0)
750 return (ipadm_errno2status(err));
753 ifa = &ainfo->ia_ifa;
754 (void) strlcpy(ainfo->ia_aobjname, aobjname,
755 sizeof (ainfo->ia_aobjname));
756 if (ifa->ifa_name == NULL && (ifa->ifa_name = strdup(ifname)) == NULL)
757 return (IPADM_NO_MEMORY);
758 if (is_addr) {
759 struct sockaddr_in6 data;
762 * We got an address from the nvlist `nvl'.
763 * Parse `nvladdr' and populate `ifa->ifa_addr'.
765 ainfo->ia_atype = atype;
766 if ((ifa->ifa_addr = calloc(1, size)) == NULL)
767 return (IPADM_NO_MEMORY);
768 switch (atype) {
769 case IPADM_ADDR_STATIC:
770 ifa->ifa_addr->sa_family = af;
771 break;
772 case IPADM_ADDR_DHCP:
773 ifa->ifa_addr->sa_family = AF_INET;
774 break;
775 case IPADM_ADDR_IPV6_ADDRCONF:
776 data.sin6_family = AF_INET6;
777 if (i_ipadm_nvl2in6_addr(nvladdr, IPADM_NVP_IPNUMADDR,
778 &data.sin6_addr) != IPADM_SUCCESS)
779 return (IPADM_NO_MEMORY);
780 err = nvlist_lookup_uint32(nvladdr, IPADM_NVP_PREFIXLEN,
781 &plen);
782 if (err != 0)
783 return (ipadm_errno2status(err));
784 if ((ifa->ifa_netmask = malloc(size)) == NULL)
785 return (IPADM_NO_MEMORY);
786 if ((err = plen2mask(plen, af, ifa->ifa_netmask)) != 0)
787 return (ipadm_errno2status(err));
788 (void) memcpy(ifa->ifa_addr, &data, sizeof (data));
789 break;
790 default:
791 return (IPADM_FAILURE);
793 } else {
794 if (strcmp(name, "prefixlen") == 0) {
796 * If a prefixlen was found, update the
797 * `ainfo->ia_ifa.ifa_netmask'.
800 if ((ifa->ifa_netmask = malloc(size)) == NULL)
801 return (IPADM_NO_MEMORY);
803 * Address property lines always follow the address
804 * line itself in the persistent db. We must have
805 * found a valid `ainfo->ia_ifa.ifa_addr' by now.
807 assert(ifa->ifa_addr != NULL);
808 err = plen2mask(atoi(propstr), ifa->ifa_addr->sa_family,
809 ifa->ifa_netmask);
810 if (err != 0)
811 return (ipadm_errno2status(err));
815 return (IPADM_SUCCESS);
819 * Retrieves all addresses from active config and appends to it the
820 * addresses that are found only in persistent config. In addition,
821 * it updates the persistent fields for each address from information
822 * found in persistent config. The output parameter `addrinfo' contains
823 * complete information regarding all addresses in active as well as
824 * persistent config.
826 static ipadm_status_t
827 i_ipadm_get_all_addr_info(ipadm_handle_t iph, const char *ifname,
828 ipadm_addr_info_t **addrinfo, uint32_t ipadm_flags, int64_t lifc_flags)
830 nvlist_t *nvladdr = NULL;
831 nvlist_t *onvl = NULL;
832 nvpair_t *nvp;
833 ipadm_status_t status;
834 ipadm_addr_info_t *ainfo = NULL;
835 ipadm_addr_info_t *curr;
836 ipadm_addr_info_t *last = NULL;
837 char *aobjname;
839 /* Get all addresses from active config. */
840 status = i_ipadm_active_addr_info(iph, ifname, &ainfo, ipadm_flags,
841 lifc_flags);
842 if (status != IPADM_SUCCESS)
843 goto fail;
845 /* Get all addresses from persistent config. */
846 status = i_ipadm_get_db_addr(iph, ifname, NULL, &onvl);
848 * If no address was found in persistent config, just
849 * return what we found in active config.
851 if (status == IPADM_NOTFOUND) {
853 * If nothing was found neither active nor persistent
854 * config, this means that the interface does not exist,
855 * if one was provided in `ifname'.
857 if (ainfo == NULL && ifname != NULL)
858 return (IPADM_ENXIO);
859 *addrinfo = ainfo;
860 return (IPADM_SUCCESS);
862 /* In case of any other error, cleanup and return. */
863 if (status != IPADM_SUCCESS)
864 goto fail;
865 /* we append to make sure, loopback addresses are first */
866 if (ainfo != NULL) {
867 for (curr = ainfo; IA_NEXT(curr) != NULL; curr = IA_NEXT(curr))
869 last = curr;
873 * `onvl' will contain all the address lines from the db. Each line
874 * could contain the address itself or an address property. Addresses
875 * and address properties are found in separate lines.
877 * If an address A was found in active, we will already have `ainfo',
878 * and it is present in persistent configuration as well, we need to
879 * update `ainfo' with persistent information (`ia_pflags).
880 * For each address B found only in persistent configuration,
881 * append the address to the list with the address info for B from
882 * `onvl'.
884 for (nvp = nvlist_next_nvpair(onvl, NULL); nvp != NULL;
885 nvp = nvlist_next_nvpair(onvl, nvp)) {
886 if (nvpair_value_nvlist(nvp, &nvladdr) != 0)
887 continue;
888 if (nvlist_lookup_string(nvladdr, IPADM_NVP_AOBJNAME,
889 &aobjname) != 0)
890 continue;
891 for (curr = ainfo; curr != NULL; curr = IA_NEXT(curr)) {
892 if (strcmp(curr->ia_aobjname, aobjname) == 0)
893 break;
895 if (curr == NULL) {
897 * We did not find this address object in `ainfo'.
898 * This means that the address object exists only
899 * in the persistent configuration. Get its
900 * details and append to `ainfo'.
902 curr = calloc(1, sizeof (ipadm_addr_info_t));
903 if (curr == NULL)
904 goto fail;
905 curr->ia_state = IFA_DISABLED;
906 if (last != NULL)
907 last->ia_ifa.ifa_next = &curr->ia_ifa;
908 else
909 ainfo = curr;
910 last = curr;
913 * Fill relevant fields of `curr' from the persistent info
914 * in `nvladdr'. Call the appropriate function based on the
915 * `ia_state' value.
917 if (curr->ia_state == IFA_DISABLED)
918 status = i_ipadm_nvl2ainfo_persist(nvladdr, curr);
919 else
920 status = i_ipadm_nvl2ainfo_active(nvladdr, curr);
921 if (status != IPADM_SUCCESS)
922 goto fail;
924 *addrinfo = ainfo;
925 nvlist_free(onvl);
926 return (status);
927 fail:
928 /* On error, cleanup and return. */
929 nvlist_free(onvl);
930 ipadm_free_addr_info(ainfo);
931 *addrinfo = NULL;
932 return (status);
936 * Callback function that sets the property `prefixlen' on the address
937 * object in `arg' to the value in `pval'.
939 /* ARGSUSED */
940 static ipadm_status_t
941 i_ipadm_set_prefixlen(ipadm_handle_t iph, const void *arg,
942 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
944 struct sockaddr_storage netmask;
945 struct lifreq lifr;
946 int err, s;
947 unsigned long prefixlen, abits;
948 char *end;
949 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
951 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
952 return (IPADM_NOTSUP);
954 errno = 0;
955 prefixlen = strtoul(pval, &end, 10);
956 if (errno != 0 || *end != '\0')
957 return (IPADM_INVALID_ARG);
959 abits = (af == AF_INET ? IP_ABITS : IPV6_ABITS);
960 if (prefixlen == 0 || prefixlen == (abits - 1))
961 return (IPADM_INVALID_ARG);
963 if ((err = plen2mask(prefixlen, af, (struct sockaddr *)&netmask)) != 0)
964 return (ipadm_errno2status(err));
966 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
968 bzero(&lifr, sizeof (lifr));
969 i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
970 sizeof (lifr.lifr_name));
971 (void) memcpy(&lifr.lifr_addr, &netmask, sizeof (netmask));
972 if (ioctl(s, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0)
973 return (ipadm_errno2status(errno));
975 /* now, change the broadcast address to reflect the prefixlen */
976 if (af == AF_INET) {
978 * get the interface address and set it, this should reset
979 * the broadcast address.
981 (void) ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr);
982 (void) ioctl(s, SIOCSLIFADDR, (caddr_t)&lifr);
985 return (IPADM_SUCCESS);
990 * Callback function that sets the given value `pval' to one of the
991 * properties among `deprecated', `private', and `transmit' as defined in
992 * `pdp', on the address object in `arg'.
994 /* ARGSUSED */
995 static ipadm_status_t
996 i_ipadm_set_addr_flag(ipadm_handle_t iph, const void *arg,
997 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
999 char lifname[LIFNAMSIZ];
1000 uint64_t on_flags = 0, off_flags = 0;
1001 boolean_t on;
1002 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1004 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
1005 strcmp(pdp->ipd_name, "deprecated") == 0)
1006 return (IPADM_NOTSUP);
1008 if (strcmp(pval, IPADM_ONSTR) == 0)
1009 on = B_TRUE;
1010 else if (strcmp(pval, IPADM_OFFSTR) == 0)
1011 on = B_FALSE;
1012 else
1013 return (IPADM_INVALID_ARG);
1015 if (strcmp(pdp->ipd_name, "private") == 0) {
1016 if (on)
1017 on_flags = IFF_PRIVATE;
1018 else
1019 off_flags = IFF_PRIVATE;
1020 } else if (strcmp(pdp->ipd_name, "transmit") == 0) {
1021 if (on)
1022 off_flags = IFF_NOXMIT;
1023 else
1024 on_flags = IFF_NOXMIT;
1025 } else if (strcmp(pdp->ipd_name, "deprecated") == 0) {
1026 if (on)
1027 on_flags = IFF_DEPRECATED;
1028 else
1029 off_flags = IFF_DEPRECATED;
1030 } else {
1031 return (IPADM_PROP_UNKNOWN);
1034 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1035 return (i_ipadm_set_flags(iph, lifname, af, on_flags, off_flags));
1039 * Callback function that sets the property `zone' on the address
1040 * object in `arg' to the value in `pval'.
1042 /* ARGSUSED */
1043 static ipadm_status_t
1044 i_ipadm_set_zone(ipadm_handle_t iph, const void *arg,
1045 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
1047 struct lifreq lifr;
1048 zoneid_t zoneid;
1049 int s;
1052 * To modify the zone assignment such that it persists across
1053 * reboots, zonecfg(8) must be used.
1055 if (flags & IPADM_OPT_PERSIST) {
1056 return (IPADM_NOTSUP);
1057 } else if (flags & IPADM_OPT_ACTIVE) {
1058 /* put logical interface into all zones */
1059 if (strcmp(pval, "all-zones") == 0) {
1060 zoneid = ALL_ZONES;
1061 } else {
1062 /* zone must be ready or running */
1063 if ((zoneid = getzoneidbyname(pval)) == -1)
1064 return (ipadm_errno2status(errno));
1066 } else {
1067 return (IPADM_INVALID_ARG);
1070 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1071 bzero(&lifr, sizeof (lifr));
1072 i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1073 sizeof (lifr.lifr_name));
1074 lifr.lifr_zoneid = zoneid;
1075 if (ioctl(s, SIOCSLIFZONE, (caddr_t)&lifr) < 0)
1076 return (ipadm_errno2status(errno));
1078 return (IPADM_SUCCESS);
1082 * Callback function that sets the property `reqhost' on the address
1083 * object in `arg' to the value in `pval'.
1085 /* ARGSUSED */
1086 static ipadm_status_t
1087 i_ipadm_set_reqhost(ipadm_handle_t iph, const void *arg,
1088 ipadm_prop_desc_t *pdp, const void *pval, uint_t af, uint_t flags)
1090 ipadm_status_t status;
1091 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1093 if (ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
1094 return (IPADM_NOTSUP);
1097 * If requested to set reqhost just from active config but the
1098 * address is not in active config, return error.
1100 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE) &&
1101 (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
1102 return (IPADM_NOTFOUND);
1105 status = ipadm_set_reqhost(ipaddr, pval);
1106 if (status != IPADM_SUCCESS)
1107 return (status);
1109 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1110 status = i_ipadm_refresh_dhcp(ipaddr);
1113 * We do not report a problem for IPADM_DHCP_IPC_TIMEOUT since
1114 * it is only a soft error to indicate the caller that the
1115 * lease might be renewed after the function returns.
1117 if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
1118 return (status);
1121 status = i_ipadm_set_aobj_addrprop(iph, ipaddr, flags,
1122 IPADM_NVP_REQHOST);
1123 return (status);
1127 * Used by address object property callback functions that need to do a
1128 * two-stage update because the addrprop is cached on the address object.
1130 static ipadm_status_t
1131 i_ipadm_set_aobj_addrprop(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
1132 uint_t flags, const char *propname)
1134 ipadm_status_t status;
1135 uint32_t two_stage_flags;
1138 * Send the updated address object information to ipmgmtd, since the
1139 * cached version of an addrprop resides on an aobjmap, but do
1140 * not change the ACTIVE/PERSIST state of the aobjmap. Instead, request
1141 * a two-stage, SET_PROPS update with ACTIVE/PERSIST as the first stage
1142 * per the existing aobjmap flags and a second stage encoded in
1143 * IPADM_OPT_PERSIST_PROPS.
1145 two_stage_flags = (flags | IPADM_OPT_SET_PROPS)
1146 & ~(IPADM_OPT_ACTIVE | IPADM_OPT_PERSIST);
1147 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE)
1148 two_stage_flags |= IPADM_OPT_ACTIVE;
1149 if (ipaddr->ipadm_flags & IPMGMT_PERSIST)
1150 two_stage_flags |= IPADM_OPT_PERSIST;
1151 if (flags & IPADM_OPT_PERSIST)
1152 two_stage_flags |= IPADM_OPT_PERSIST_PROPS;
1154 status = i_ipadm_addr_persist(iph, ipaddr, B_FALSE, two_stage_flags,
1155 propname);
1156 return (status);
1160 * Callback function that gets the property `broadcast' for the address
1161 * object in `arg'.
1163 /* ARGSUSED */
1164 static ipadm_status_t
1165 i_ipadm_get_broadcast(ipadm_handle_t iph, const void *arg,
1166 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1167 uint_t valtype)
1169 struct sockaddr_in *sin;
1170 struct lifreq lifr;
1171 char lifname[LIFNAMSIZ];
1172 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1173 ipadm_status_t status;
1174 size_t nbytes = 0;
1175 uint64_t ifflags = 0;
1177 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1178 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1179 status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
1180 if (status != IPADM_SUCCESS)
1181 return (status);
1182 if (!(ifflags & IFF_BROADCAST)) {
1183 buf[0] = '\0';
1184 return (IPADM_SUCCESS);
1188 switch (valtype) {
1189 case MOD_PROP_DEFAULT: {
1190 struct sockaddr_storage mask;
1191 struct in_addr broadaddr;
1192 uint_t plen;
1193 in_addr_t addr, maddr;
1194 char val[MAXPROPVALLEN];
1195 uint_t valsz = MAXPROPVALLEN;
1196 ipadm_status_t status;
1197 int err;
1198 struct sockaddr_in *sin;
1200 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE)) {
1202 * Since the address is unknown we cannot
1203 * obtain default prefixlen
1205 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP ||
1206 ipaddr->ipadm_af == AF_INET6) {
1207 buf[0] = '\0';
1208 return (IPADM_SUCCESS);
1211 * For the static address, we get the address from the
1212 * persistent db.
1214 status = i_ipadm_get_static_addr_db(iph, ipaddr);
1215 if (status != IPADM_SUCCESS)
1216 return (status);
1217 sin = SIN(&ipaddr->ipadm_static_addr);
1218 addr = sin->sin_addr.s_addr;
1219 } else {
1221 * If the address object is active, we retrieve the
1222 * address from kernel.
1224 bzero(&lifr, sizeof (lifr));
1225 (void) strlcpy(lifr.lifr_name, lifname,
1226 sizeof (lifr.lifr_name));
1227 if (ioctl(iph->iph_sock, SIOCGLIFADDR,
1228 (caddr_t)&lifr) < 0)
1229 return (ipadm_errno2status(errno));
1231 addr = (SIN(&lifr.lifr_addr))->sin_addr.s_addr;
1234 * For default broadcast address, get the address and the
1235 * default prefixlen for that address and then compute the
1236 * broadcast address.
1238 status = i_ipadm_get_prefixlen(iph, arg, NULL, val, &valsz, af,
1239 MOD_PROP_DEFAULT);
1240 if (status != IPADM_SUCCESS)
1241 return (status);
1243 plen = atoi(val);
1244 if ((err = plen2mask(plen, AF_INET,
1245 (struct sockaddr *)&mask)) != 0)
1246 return (ipadm_errno2status(err));
1247 maddr = (SIN(&mask))->sin_addr.s_addr;
1248 broadaddr.s_addr = (addr & maddr) | ~maddr;
1249 nbytes = snprintf(buf, *bufsize, "%s", inet_ntoa(broadaddr));
1250 break;
1252 case MOD_PROP_ACTIVE:
1253 bzero(&lifr, sizeof (lifr));
1254 (void) strlcpy(lifr.lifr_name, lifname,
1255 sizeof (lifr.lifr_name));
1256 if (ioctl(iph->iph_sock, SIOCGLIFBRDADDR,
1257 (caddr_t)&lifr) < 0) {
1258 return (ipadm_errno2status(errno));
1259 } else {
1260 sin = SIN(&lifr.lifr_addr);
1261 nbytes = snprintf(buf, *bufsize, "%s",
1262 inet_ntoa(sin->sin_addr));
1264 break;
1265 default:
1266 return (IPADM_INVALID_ARG);
1268 if (nbytes >= *bufsize) {
1269 /* insufficient buffer space */
1270 *bufsize = nbytes + 1;
1271 return (IPADM_NO_BUFS);
1273 return (IPADM_SUCCESS);
1277 * Callback function that retrieves the value of the property `prefixlen'
1278 * for the address object in `arg'.
1280 /* ARGSUSED */
1281 static ipadm_status_t
1282 i_ipadm_get_prefixlen(ipadm_handle_t iph, const void *arg,
1283 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1284 uint_t valtype)
1286 struct lifreq lifr;
1287 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1288 char lifname[LIFNAMSIZ];
1289 int s;
1290 uint32_t prefixlen;
1291 size_t nbytes;
1292 ipadm_status_t status;
1293 uint64_t lifflags;
1295 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1296 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1297 status = i_ipadm_get_flags(iph, lifname, af, &lifflags);
1298 if (status != IPADM_SUCCESS) {
1299 return (status);
1300 } else if (lifflags & IFF_POINTOPOINT) {
1301 buf[0] = '\0';
1302 return (status);
1306 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1307 bzero(&lifr, sizeof (lifr));
1308 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
1309 switch (valtype) {
1310 case MOD_PROP_POSSIBLE:
1311 if (af == AF_INET)
1312 nbytes = snprintf(buf, *bufsize, "1-30,32");
1313 else
1314 nbytes = snprintf(buf, *bufsize, "1-126,128");
1315 break;
1316 case MOD_PROP_DEFAULT:
1317 if (ipaddr->ipadm_flags & IPMGMT_ACTIVE) {
1319 * For static addresses, we retrieve the address
1320 * from kernel if it is active.
1322 if (ioctl(s, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
1323 return (ipadm_errno2status(errno));
1324 status = i_ipadm_get_default_prefixlen(
1325 &lifr.lifr_addr, &prefixlen);
1326 if (status != IPADM_SUCCESS)
1327 return (status);
1328 } else if ((ipaddr->ipadm_flags & IPMGMT_PERSIST) &&
1329 ipaddr->ipadm_atype == IPADM_ADDR_DHCP) {
1331 * Since the address is unknown we cannot
1332 * obtain default prefixlen
1334 buf[0] = '\0';
1335 return (IPADM_SUCCESS);
1336 } else {
1338 * If not in active config, we use the address
1339 * from persistent store.
1341 status = i_ipadm_get_static_addr_db(iph, ipaddr);
1342 if (status != IPADM_SUCCESS)
1343 return (status);
1344 status = i_ipadm_get_default_prefixlen(
1345 &ipaddr->ipadm_static_addr, &prefixlen);
1346 if (status != IPADM_SUCCESS)
1347 return (status);
1349 nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
1350 break;
1351 case MOD_PROP_ACTIVE:
1352 if (ioctl(s, SIOCGLIFNETMASK, (caddr_t)&lifr) < 0)
1353 return (ipadm_errno2status(errno));
1354 prefixlen = lifr.lifr_addrlen;
1355 nbytes = snprintf(buf, *bufsize, "%u", prefixlen);
1356 break;
1357 default:
1358 return (IPADM_INVALID_ARG);
1360 if (nbytes >= *bufsize) {
1361 /* insufficient buffer space */
1362 *bufsize = nbytes + 1;
1363 return (IPADM_NO_BUFS);
1365 return (IPADM_SUCCESS);
1369 * Callback function that retrieves the value of one of the properties
1370 * among `deprecated', `private', and `transmit' for the address object
1371 * in `arg'.
1373 /* ARGSUSED */
1374 static ipadm_status_t
1375 i_ipadm_get_addr_flag(ipadm_handle_t iph, const void *arg,
1376 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1377 uint_t valtype)
1379 boolean_t on = B_FALSE;
1380 char lifname[LIFNAMSIZ];
1381 ipadm_status_t status = IPADM_SUCCESS;
1382 uint64_t ifflags;
1383 size_t nbytes;
1384 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1386 switch (valtype) {
1387 case MOD_PROP_DEFAULT:
1388 if (strcmp(pdp->ipd_name, "private") == 0 ||
1389 strcmp(pdp->ipd_name, "deprecated") == 0) {
1390 on = B_FALSE;
1391 } else if (strcmp(pdp->ipd_name, "transmit") == 0) {
1392 on = B_TRUE;
1393 } else {
1394 return (IPADM_PROP_UNKNOWN);
1396 break;
1397 case MOD_PROP_ACTIVE:
1399 * If the address is present in active configuration, we
1400 * retrieve it from kernel to get the property value.
1401 * Else, there is no value to return.
1403 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
1404 status = i_ipadm_get_flags(iph, lifname, af, &ifflags);
1405 if (status != IPADM_SUCCESS)
1406 return (status);
1407 if (strcmp(pdp->ipd_name, "private") == 0)
1408 on = (ifflags & IFF_PRIVATE);
1409 else if (strcmp(pdp->ipd_name, "transmit") == 0)
1410 on = !(ifflags & IFF_NOXMIT);
1411 else if (strcmp(pdp->ipd_name, "deprecated") == 0)
1412 on = (ifflags & IFF_DEPRECATED);
1413 break;
1414 default:
1415 return (IPADM_INVALID_ARG);
1417 nbytes = snprintf(buf, *bufsize, "%s",
1418 (on ? IPADM_ONSTR : IPADM_OFFSTR));
1419 if (nbytes >= *bufsize) {
1420 /* insufficient buffer space */
1421 *bufsize = nbytes + 1;
1422 status = IPADM_NO_BUFS;
1425 return (status);
1429 * Callback function that retrieves the value of the property `zone'
1430 * for the address object in `arg'.
1432 /* ARGSUSED */
1433 static ipadm_status_t
1434 i_ipadm_get_zone(ipadm_handle_t iph, const void *arg,
1435 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1436 uint_t valtype)
1438 struct lifreq lifr;
1439 char zone_name[ZONENAME_MAX];
1440 int s;
1441 size_t nbytes = 0;
1443 if (iph->iph_zoneid != GLOBAL_ZONEID) {
1444 buf[0] = '\0';
1445 return (IPADM_SUCCESS);
1449 * we are in global zone. See if the lifname is assigned to shared-ip
1450 * zone or global zone.
1452 switch (valtype) {
1453 case MOD_PROP_DEFAULT:
1454 if (getzonenamebyid(GLOBAL_ZONEID, zone_name,
1455 sizeof (zone_name)) > 0)
1456 nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1457 else
1458 return (ipadm_errno2status(errno));
1459 break;
1460 case MOD_PROP_ACTIVE:
1461 bzero(&lifr, sizeof (lifr));
1462 i_ipadm_addrobj2lifname((ipadm_addrobj_t)arg, lifr.lifr_name,
1463 sizeof (lifr.lifr_name));
1464 s = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1466 if (ioctl(s, SIOCGLIFZONE, (caddr_t)&lifr) == -1)
1467 return (ipadm_errno2status(errno));
1469 if (lifr.lifr_zoneid == ALL_ZONES) {
1470 nbytes = snprintf(buf, *bufsize, "%s", "all-zones");
1471 } else if (getzonenamebyid(lifr.lifr_zoneid, zone_name,
1472 sizeof (zone_name)) < 0) {
1473 return (ipadm_errno2status(errno));
1474 } else {
1475 nbytes = snprintf(buf, *bufsize, "%s", zone_name);
1477 break;
1478 default:
1479 return (IPADM_INVALID_ARG);
1481 if (nbytes >= *bufsize) {
1482 /* insufficient buffer space */
1483 *bufsize = nbytes + 1;
1484 return (IPADM_NO_BUFS);
1487 return (IPADM_SUCCESS);
1491 * Callback function that retrieves the value of the property `primary'
1492 * for the address object in `arg'.
1494 /* ARGSUSED */
1495 static ipadm_status_t
1496 i_ipadm_get_primary(ipadm_handle_t iph, const void *arg,
1497 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1498 uint_t valtype)
1500 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1501 const char *onoff = "";
1502 size_t nbytes;
1504 switch (valtype) {
1505 case MOD_PROP_DEFAULT:
1506 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
1507 onoff = IPADM_OFFSTR;
1508 break;
1509 case MOD_PROP_ACTIVE:
1510 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP) {
1511 dhcp_status_t dhcp_status;
1512 ipadm_status_t ipc_status;
1513 int error;
1515 ipc_status = i_ipadm_dhcp_status(ipaddr, &dhcp_status,
1516 &error);
1517 if (ipc_status != IPADM_SUCCESS &&
1518 ipc_status != IPADM_NOTFOUND)
1519 return (ipc_status);
1521 onoff = dhcp_status.if_dflags & DHCP_IF_PRIMARY ?
1522 IPADM_ONSTR : IPADM_OFFSTR;
1524 break;
1525 default:
1526 return (IPADM_INVALID_ARG);
1529 nbytes = strlcpy(buf, onoff, *bufsize);
1530 if (nbytes >= *bufsize) {
1531 /* insufficient buffer space */
1532 *bufsize = nbytes + 1;
1533 return (IPADM_NO_BUFS);
1536 return (IPADM_SUCCESS);
1540 * Callback function that retrieves the value of the property `reqhost'
1541 * for the address object in `arg'.
1543 /* ARGSUSED */
1544 static ipadm_status_t
1545 i_ipadm_get_reqhost(ipadm_handle_t iph, const void *arg,
1546 ipadm_prop_desc_t *pdp, char *buf, uint_t *bufsize, uint_t af,
1547 uint_t valtype)
1549 ipadm_addrobj_t ipaddr = (ipadm_addrobj_t)arg;
1550 const char *reqhost = "";
1551 size_t nbytes;
1553 switch (valtype) {
1554 case MOD_PROP_DEFAULT:
1555 break;
1556 case MOD_PROP_ACTIVE:
1557 if (ipaddr->ipadm_atype == IPADM_ADDR_DHCP)
1558 reqhost = ipaddr->ipadm_reqhost;
1559 break;
1560 default:
1561 return (IPADM_INVALID_ARG);
1564 nbytes = strlcpy(buf, reqhost, *bufsize);
1565 if (nbytes >= *bufsize) {
1566 /* insufficient buffer space */
1567 *bufsize = nbytes + 1;
1568 return (IPADM_NO_BUFS);
1571 return (IPADM_SUCCESS);
1574 static ipadm_prop_desc_t *
1575 i_ipadm_get_addrprop_desc(const char *pname)
1577 int i;
1579 for (i = 0; ipadm_addrprop_table[i].ipd_name != NULL; i++) {
1580 if (strcmp(pname, ipadm_addrprop_table[i].ipd_name) == 0 ||
1581 (ipadm_addrprop_table[i].ipd_old_name != NULL &&
1582 strcmp(pname, ipadm_addrprop_table[i].ipd_old_name) == 0))
1583 return (&ipadm_addrprop_table[i]);
1585 return (NULL);
1589 * Gets the value of the given address property `pname' for the address
1590 * object with name `aobjname'.
1592 ipadm_status_t
1593 ipadm_get_addrprop(ipadm_handle_t iph, const char *pname, char *buf,
1594 uint_t *bufsize, const char *aobjname, uint_t valtype)
1596 struct ipadm_addrobj_s ipaddr;
1597 ipadm_status_t status = IPADM_SUCCESS;
1598 sa_family_t af;
1599 ipadm_prop_desc_t *pdp = NULL;
1601 if (iph == NULL || pname == NULL || buf == NULL ||
1602 bufsize == NULL || *bufsize == 0 || aobjname == NULL) {
1603 return (IPADM_INVALID_ARG);
1606 /* find the property in the property description table */
1607 if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
1608 return (IPADM_PROP_UNKNOWN);
1611 * For the given aobjname, get the addrobj it represents and
1612 * retrieve the property value for that object.
1614 i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1615 if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1616 return (status);
1618 if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1619 return (IPADM_NOTSUP);
1620 af = ipaddr.ipadm_af;
1623 * Call the appropriate callback function to based on the field
1624 * that was asked for.
1626 switch (valtype) {
1627 case IPADM_OPT_PERM:
1628 status = i_ipadm_pd2permstr(pdp, buf, bufsize);
1629 break;
1630 case IPADM_OPT_ACTIVE:
1631 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE)) {
1632 buf[0] = '\0';
1633 } else {
1634 status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
1635 af, MOD_PROP_ACTIVE);
1637 break;
1638 case IPADM_OPT_DEFAULT:
1639 status = pdp->ipd_get(iph, &ipaddr, pdp, buf, bufsize,
1640 af, MOD_PROP_DEFAULT);
1641 break;
1642 case IPADM_OPT_POSSIBLE:
1643 if (pdp->ipd_get_range != NULL) {
1644 status = pdp->ipd_get_range(iph, &ipaddr, pdp, buf,
1645 bufsize, af, MOD_PROP_POSSIBLE);
1646 break;
1648 buf[0] = '\0';
1649 break;
1650 case IPADM_OPT_PERSIST:
1651 status = i_ipadm_get_persist_propval(iph, pdp, buf, bufsize,
1652 &ipaddr);
1653 break;
1654 default:
1655 status = IPADM_INVALID_ARG;
1656 break;
1659 return (status);
1663 * Sets the value of the given address property `pname' to `pval' for the
1664 * address object with name `aobjname'.
1666 ipadm_status_t
1667 ipadm_set_addrprop(ipadm_handle_t iph, const char *pname,
1668 const char *pval, const char *aobjname, uint_t pflags)
1670 struct ipadm_addrobj_s ipaddr;
1671 sa_family_t af;
1672 ipadm_prop_desc_t *pdp = NULL;
1673 char defbuf[MAXPROPVALLEN];
1674 uint_t defbufsize = MAXPROPVALLEN;
1675 boolean_t reset = (pflags & IPADM_OPT_DEFAULT);
1676 ipadm_status_t status = IPADM_SUCCESS;
1678 /* Check for solaris.network.interface.config authorization */
1679 if (!ipadm_check_auth())
1680 return (IPADM_EAUTH);
1682 if (iph == NULL || pname == NULL || aobjname == NULL || pflags == 0 ||
1683 pflags == IPADM_OPT_PERSIST ||
1684 (pflags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_DEFAULT)) ||
1685 (!reset && pval == NULL)) {
1686 return (IPADM_INVALID_ARG);
1689 /* find the property in the property description table */
1690 if ((pdp = i_ipadm_get_addrprop_desc(pname)) == NULL)
1691 return (IPADM_PROP_UNKNOWN);
1693 if (pdp->ipd_set == NULL || (reset && pdp->ipd_get == NULL))
1694 return (IPADM_NOTSUP);
1696 if (!(pdp->ipd_flags & IPADMPROP_MULVAL) &&
1697 (pflags & (IPADM_OPT_APPEND|IPADM_OPT_REMOVE))) {
1698 return (IPADM_INVALID_ARG);
1702 * For the given aobjname, get the addrobj it represents and
1703 * set the property value for that object.
1705 i_ipadm_init_addr(&ipaddr, "", aobjname, IPADM_ADDR_NONE);
1706 if ((status = i_ipadm_get_addrobj(iph, &ipaddr)) != IPADM_SUCCESS)
1707 return (status);
1709 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1710 return (IPADM_OP_DISABLE_OBJ);
1712 /* Persistent operation not allowed on a temporary object. */
1713 if ((pflags & IPADM_OPT_PERSIST) &&
1714 !(ipaddr.ipadm_flags & IPMGMT_PERSIST))
1715 return (IPADM_TEMPORARY_OBJ);
1718 * Currently, setting an address property on an address object of type
1719 * IPADM_ADDR_IPV6_ADDRCONF is not supported. Supporting it involves
1720 * in.ndpd retrieving the address properties from ipmgmtd for given
1721 * address object and then setting them on auto-configured addresses,
1722 * whenever in.ndpd gets a new prefix. This will be supported in
1723 * future releases.
1725 if (ipaddr.ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF)
1726 return (IPADM_NOTSUP);
1729 * Setting an address property on an address object that is
1730 * not present in active configuration is not supported.
1732 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
1733 return (IPADM_NOTSUP);
1735 af = ipaddr.ipadm_af;
1736 if (reset) {
1738 * If we were asked to reset the value, we need to fetch
1739 * the default value and set the default value.
1741 status = pdp->ipd_get(iph, &ipaddr, pdp, defbuf, &defbufsize,
1742 af, MOD_PROP_DEFAULT);
1743 if (status != IPADM_SUCCESS)
1744 return (status);
1745 pval = defbuf;
1747 /* set the user provided or default property value */
1748 status = pdp->ipd_set(iph, &ipaddr, pdp, pval, af, pflags);
1749 if (status != IPADM_SUCCESS)
1750 return (status);
1753 * If IPADM_OPT_PERSIST was set in `flags', we need to store
1754 * property and its value in persistent DB.
1756 if (pflags & IPADM_OPT_PERSIST) {
1757 status = i_ipadm_persist_propval(iph, pdp, pval, &ipaddr,
1758 pflags);
1761 return (status);
1765 * Remove the address specified by the address object in `addr'
1766 * from kernel. If the address is on a non-zero logical interface, we do a
1767 * SIOCLIFREMOVEIF, otherwise we set the address to INADDR_ANY for IPv4 or
1768 * :: for IPv6.
1770 ipadm_status_t
1771 i_ipadm_delete_addr(ipadm_handle_t iph, ipadm_addrobj_t addr)
1773 struct lifreq lifr;
1774 int sock;
1775 ipadm_status_t status;
1777 bzero(&lifr, sizeof (lifr));
1778 i_ipadm_addrobj2lifname(addr, lifr.lifr_name, sizeof (lifr.lifr_name));
1779 sock = (addr->ipadm_af == AF_INET ? iph->iph_sock : iph->iph_sock6);
1780 if (addr->ipadm_lifnum == 0) {
1782 * Fake the deletion of the 0'th address by
1783 * clearing IFF_UP and setting it to as 0.0.0.0 or ::.
1785 status = i_ipadm_set_flags(iph, addr->ipadm_ifname,
1786 addr->ipadm_af, 0, IFF_UP);
1787 if (status != IPADM_SUCCESS)
1788 return (status);
1789 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
1790 lifr.lifr_addr.ss_family = addr->ipadm_af;
1791 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
1792 return (ipadm_errno2status(errno));
1793 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0)
1794 return (ipadm_errno2status(errno));
1795 } else if (ioctl(sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
1796 return (ipadm_errno2status(errno));
1799 return (IPADM_SUCCESS);
1803 * Extracts the IPv6 address from the nvlist in `nvl'.
1805 ipadm_status_t
1806 i_ipadm_nvl2in6_addr(nvlist_t *nvl, char *addr_type, in6_addr_t *in6_addr)
1808 uint8_t *addr6;
1809 uint_t n;
1811 if (nvlist_lookup_uint8_array(nvl, addr_type, &addr6, &n) != 0)
1812 return (IPADM_NOTFOUND);
1813 assert(n == 16);
1814 bcopy(addr6, in6_addr->s6_addr, n);
1815 return (IPADM_SUCCESS);
1819 * Used to validate the given addrobj name string. Length of `aobjname'
1820 * cannot exceed IPADM_AOBJ_USTRSIZ. `aobjname' should start with an
1821 * alphabetic character and it can only contain alphanumeric characters.
1823 static boolean_t
1824 i_ipadm_is_user_aobjname_valid(const char *aobjname)
1826 const char *cp;
1828 if (aobjname == NULL || strlen(aobjname) >= IPADM_AOBJ_USTRSIZ ||
1829 !isalpha(*aobjname)) {
1830 return (B_FALSE);
1832 for (cp = aobjname + 1; *cp && isalnum(*cp); cp++)
1834 return (*cp == '\0');
1838 * Computes the prefixlen for the given `addr' based on the netmask found using
1839 * the order specified in /etc/nsswitch.conf. If not found, then the
1840 * prefixlen is computed using the Classful subnetting semantics defined
1841 * in RFC 791 for IPv4 and RFC 4291 for IPv6.
1843 static ipadm_status_t
1844 i_ipadm_get_default_prefixlen(struct sockaddr_storage *addr, uint32_t *plen)
1846 sa_family_t af = addr->ss_family;
1847 struct sockaddr_storage mask;
1848 struct sockaddr_in *m = (struct sockaddr_in *)&mask;
1849 struct sockaddr_in6 *sin6;
1850 struct sockaddr_in *sin;
1851 struct in_addr ia;
1852 uint32_t prefixlen = 0;
1854 switch (af) {
1855 case AF_INET:
1856 sin = SIN(addr);
1857 ia.s_addr = ntohl(sin->sin_addr.s_addr);
1858 get_netmask4(&ia, &m->sin_addr);
1859 m->sin_addr.s_addr = htonl(m->sin_addr.s_addr);
1860 m->sin_family = AF_INET;
1861 prefixlen = mask2plen((struct sockaddr *)&mask);
1862 break;
1863 case AF_INET6:
1864 sin6 = SIN6(addr);
1865 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
1866 prefixlen = 10;
1867 else
1868 prefixlen = 64;
1869 break;
1870 default:
1871 return (IPADM_INVALID_ARG);
1873 *plen = prefixlen;
1874 return (IPADM_SUCCESS);
1877 ipadm_status_t
1878 i_ipadm_resolve_addr(const char *name, sa_family_t af,
1879 struct sockaddr_storage *ss)
1881 struct addrinfo hints, *ai;
1882 int rc;
1883 struct sockaddr_in6 *sin6;
1884 struct sockaddr_in *sin;
1885 boolean_t is_mapped;
1887 (void) memset(&hints, 0, sizeof (hints));
1888 hints.ai_family = af;
1889 hints.ai_flags = (AI_ALL | AI_V4MAPPED);
1890 rc = getaddrinfo(name, NULL, &hints, &ai);
1891 if (rc != 0) {
1892 if (rc == EAI_NONAME)
1893 return (IPADM_BAD_ADDR);
1894 else
1895 return (IPADM_FAILURE);
1897 if (ai->ai_next != NULL) {
1898 /* maps to more than one hostname */
1899 freeaddrinfo(ai);
1900 return (IPADM_BAD_HOSTNAME);
1902 /* LINTED E_BAD_PTR_CAST_ALIGN */
1903 is_mapped = IN6_IS_ADDR_V4MAPPED(&(SIN6(ai->ai_addr))->sin6_addr);
1904 if (is_mapped) {
1905 sin = SIN(ss);
1906 sin->sin_family = AF_INET;
1907 /* LINTED E_BAD_PTR_CAST_ALIGN */
1908 IN6_V4MAPPED_TO_INADDR(&(SIN6(ai->ai_addr))->sin6_addr,
1909 &sin->sin_addr);
1910 } else {
1911 sin6 = SIN6(ss);
1912 sin6->sin6_family = AF_INET6;
1913 bcopy(ai->ai_addr, sin6, sizeof (*sin6));
1915 freeaddrinfo(ai);
1916 return (IPADM_SUCCESS);
1920 * This takes a static address string <addr>[/<mask>] or a hostname
1921 * and maps it to a single numeric IP address, consulting DNS if
1922 * hostname was provided. If a specific address family was requested,
1923 * an error is returned if the given hostname does not map to an address
1924 * of the given family. Note that this function returns failure
1925 * if the name maps to more than one IP address.
1927 ipadm_status_t
1928 ipadm_set_addr(ipadm_addrobj_t ipaddr, const char *astr, sa_family_t af)
1930 char *prefixlenstr;
1931 uint32_t prefixlen = 0;
1932 char *endp;
1934 * We use (NI_MAXHOST + 5) because the longest possible
1935 * astr will have (NI_MAXHOST + '/' + {a maximum of 32 for IPv4
1936 * or a maximum of 128 for IPv6 + '\0') chars
1938 char addrstr[NI_MAXHOST + 5];
1939 ipadm_status_t status;
1941 (void) snprintf(addrstr, sizeof (addrstr), "%s", astr);
1942 if ((prefixlenstr = strchr(addrstr, '/')) != NULL) {
1943 *prefixlenstr++ = '\0';
1944 errno = 0;
1945 prefixlen = strtoul(prefixlenstr, &endp, 10);
1946 if (errno != 0 || *endp != '\0')
1947 return (IPADM_INVALID_ARG);
1948 if ((af == AF_INET && prefixlen > IP_ABITS) ||
1949 (af == AF_INET6 && prefixlen > IPV6_ABITS))
1950 return (IPADM_INVALID_ARG);
1953 status = i_ipadm_resolve_addr(addrstr, af, &ipaddr->ipadm_static_addr);
1954 if (status == IPADM_SUCCESS) {
1955 (void) strlcpy(ipaddr->ipadm_static_aname, addrstr,
1956 sizeof (ipaddr->ipadm_static_aname));
1957 ipaddr->ipadm_af = ipaddr->ipadm_static_addr.ss_family;
1958 ipaddr->ipadm_static_prefixlen = prefixlen;
1960 return (status);
1964 * Gets the static source address from the address object in `ipaddr'.
1965 * Memory for `addr' should be already allocated by the caller.
1967 ipadm_status_t
1968 ipadm_get_addr(const ipadm_addrobj_t ipaddr, struct sockaddr_storage *addr)
1970 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_STATIC ||
1971 addr == NULL) {
1972 return (IPADM_INVALID_ARG);
1974 *addr = ipaddr->ipadm_static_addr;
1976 return (IPADM_SUCCESS);
1980 * Set up tunnel destination address in ipaddr by contacting DNS.
1981 * The function works similar to ipadm_set_addr().
1982 * The dst_addr must resolve to exactly one address. IPADM_BAD_ADDR is returned
1983 * if dst_addr resolves to more than one address. The caller has to verify
1984 * that ipadm_static_addr and ipadm_static_dst_addr have the same ss_family
1986 ipadm_status_t
1987 ipadm_set_dst_addr(ipadm_addrobj_t ipaddr, const char *daddrstr, sa_family_t af)
1989 ipadm_status_t status;
1991 /* mask lengths are not meaningful for point-to-point interfaces. */
1992 if (strchr(daddrstr, '/') != NULL)
1993 return (IPADM_BAD_ADDR);
1995 status = i_ipadm_resolve_addr(daddrstr, af,
1996 &ipaddr->ipadm_static_dst_addr);
1997 if (status == IPADM_SUCCESS) {
1998 (void) strlcpy(ipaddr->ipadm_static_dname, daddrstr,
1999 sizeof (ipaddr->ipadm_static_dname));
2001 return (status);
2005 * Sets the interface ID in the address object `ipaddr' with the address
2006 * in the string `interface_id'. This interface ID will be used when
2007 * ipadm_create_addr() is called with `ipaddr' with address type
2008 * set to IPADM_ADDR_IPV6_ADDRCONF.
2010 ipadm_status_t
2011 ipadm_set_interface_id(ipadm_addrobj_t ipaddr, const char *interface_id)
2013 struct sockaddr_in6 *sin6;
2014 char *end;
2015 char *cp;
2016 uint32_t prefixlen;
2017 char addrstr[INET6_ADDRSTRLEN + 1];
2019 if (ipaddr == NULL || interface_id == NULL ||
2020 ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
2021 return (IPADM_INVALID_ARG);
2023 (void) strlcpy(addrstr, interface_id, sizeof (addrstr));
2024 if ((cp = strchr(addrstr, '/')) == NULL)
2025 return (IPADM_INVALID_ARG);
2026 *cp++ = '\0';
2027 sin6 = &ipaddr->ipadm_intfid;
2028 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) == 1) {
2029 errno = 0;
2030 prefixlen = strtoul(cp, &end, 10);
2031 if (errno != 0 || *end != '\0' || prefixlen > IPV6_ABITS)
2032 return (IPADM_INVALID_ARG);
2033 sin6->sin6_family = AF_INET6;
2034 ipaddr->ipadm_intfidlen = prefixlen;
2035 return (IPADM_SUCCESS);
2037 return (IPADM_INVALID_ARG);
2041 * Sets the value for the field `ipadm_stateless' in address object `ipaddr'.
2043 ipadm_status_t
2044 ipadm_set_stateless(ipadm_addrobj_t ipaddr, boolean_t stateless)
2046 if (ipaddr == NULL ||
2047 ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
2048 return (IPADM_INVALID_ARG);
2049 ipaddr->ipadm_stateless = stateless;
2051 return (IPADM_SUCCESS);
2055 * Sets the value for the field `ipadm_stateful' in address object `ipaddr'.
2057 ipadm_status_t
2058 ipadm_set_stateful(ipadm_addrobj_t ipaddr, boolean_t stateful)
2060 if (ipaddr == NULL ||
2061 ipaddr->ipadm_atype != IPADM_ADDR_IPV6_ADDRCONF)
2062 return (IPADM_INVALID_ARG);
2063 ipaddr->ipadm_stateful = stateful;
2065 return (IPADM_SUCCESS);
2069 * Sets the dhcp parameter `ipadm_primary' in the address object `ipaddr'.
2070 * The field is used during the address creation with address
2071 * type IPADM_ADDR_DHCP. It specifies if the interface should be set
2072 * as a primary interface for getting dhcp global options from the DHCP server.
2074 ipadm_status_t
2075 ipadm_set_primary(ipadm_addrobj_t ipaddr, boolean_t primary)
2077 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2078 return (IPADM_INVALID_ARG);
2079 ipaddr->ipadm_primary = primary;
2081 return (IPADM_SUCCESS);
2085 * Sets the dhcp parameter `ipadm_wait' in the address object `ipaddr'.
2086 * This field is used during the address creation with address type
2087 * IPADM_ADDR_DHCP. It specifies how long the API ipadm_create_addr()
2088 * should wait before returning while the dhcp address is being acquired
2089 * by the dhcpagent.
2090 * Possible values:
2091 * - IPADM_DHCP_WAIT_FOREVER : Do not return until dhcpagent returns.
2092 * - IPADM_DHCP_WAIT_DEFAULT : Wait a default amount of time before returning.
2093 * - <integer> : Wait the specified number of seconds before returning.
2095 ipadm_status_t
2096 ipadm_set_wait_time(ipadm_addrobj_t ipaddr, int32_t wait)
2098 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2099 return (IPADM_INVALID_ARG);
2100 ipaddr->ipadm_wait = wait;
2101 return (IPADM_SUCCESS);
2105 * Sets the dhcp parameter `ipadm_reqhost' in the address object `ipaddr',
2106 * but validate any non-nil value using ipadm_is_valid_hostname() and also
2107 * check length.
2109 ipadm_status_t
2110 ipadm_set_reqhost(ipadm_addrobj_t ipaddr, const char *reqhost)
2112 const size_t HNLEN = sizeof (ipaddr->ipadm_reqhost);
2114 if (ipaddr == NULL || ipaddr->ipadm_atype != IPADM_ADDR_DHCP)
2115 return (IPADM_INVALID_ARG);
2117 if (ipadm_is_nil_hostname(reqhost))
2118 *ipaddr->ipadm_reqhost = '\0';
2119 else if (!ipadm_is_valid_hostname(reqhost))
2120 return (IPADM_INVALID_ARG);
2121 else if (strlcpy(ipaddr->ipadm_reqhost, reqhost, HNLEN) >= HNLEN)
2122 return (IPADM_INVALID_ARG);
2123 return (IPADM_SUCCESS);
2127 * Creates a placeholder for the `ipadm_aobjname' in the ipmgmtd `aobjmap'.
2128 * If the `aobjname' already exists in the daemon's `aobjmap' then
2129 * IPADM_ADDROBJ_EXISTS will be returned.
2131 * If the libipadm consumer set `ipaddr.ipadm_aobjname[0]' to `\0', then the
2132 * daemon will generate an `aobjname' for the given `ipaddr'.
2134 ipadm_status_t
2135 i_ipadm_lookupadd_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2137 ipmgmt_aobjop_arg_t larg;
2138 ipmgmt_aobjop_rval_t rval, *rvalp;
2139 int err;
2141 bzero(&larg, sizeof (larg));
2142 larg.ia_cmd = IPMGMT_CMD_ADDROBJ_LOOKUPADD;
2143 (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
2144 sizeof (larg.ia_aobjname));
2145 (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
2146 sizeof (larg.ia_ifname));
2147 larg.ia_family = ipaddr->ipadm_af;
2148 larg.ia_atype = ipaddr->ipadm_atype;
2150 rvalp = &rval;
2151 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
2152 sizeof (rval), B_FALSE);
2153 if (err == 0 && ipaddr->ipadm_aobjname[0] == '\0') {
2154 /* copy the daemon generated `aobjname' into `ipadddr' */
2155 (void) strlcpy(ipaddr->ipadm_aobjname, rval.ir_aobjname,
2156 sizeof (ipaddr->ipadm_aobjname));
2158 if (err == EEXIST)
2159 return (IPADM_ADDROBJ_EXISTS);
2160 return (ipadm_errno2status(err));
2164 * Sets the logical interface number in the ipmgmtd's memory map for the
2165 * address object `ipaddr'. If another address object has the same
2166 * logical interface number, IPADM_ADDROBJ_EXISTS is returned.
2168 ipadm_status_t
2169 i_ipadm_setlifnum_addrobj(ipadm_handle_t iph, ipadm_addrobj_t ipaddr)
2171 ipmgmt_aobjop_arg_t larg;
2172 ipmgmt_retval_t rval, *rvalp;
2173 int err;
2175 if (iph->iph_flags & IPH_IPMGMTD)
2176 return (IPADM_SUCCESS);
2178 bzero(&larg, sizeof (larg));
2179 larg.ia_cmd = IPMGMT_CMD_ADDROBJ_SETLIFNUM;
2180 (void) strlcpy(larg.ia_aobjname, ipaddr->ipadm_aobjname,
2181 sizeof (larg.ia_aobjname));
2182 larg.ia_lnum = ipaddr->ipadm_lifnum;
2183 (void) strlcpy(larg.ia_ifname, ipaddr->ipadm_ifname,
2184 sizeof (larg.ia_ifname));
2185 larg.ia_family = ipaddr->ipadm_af;
2187 rvalp = &rval;
2188 err = ipadm_door_call(iph, &larg, sizeof (larg), (void **)&rvalp,
2189 sizeof (rval), B_FALSE);
2190 if (err == EEXIST)
2191 return (IPADM_ADDROBJ_EXISTS);
2192 return (ipadm_errno2status(err));
2196 * Creates the IPv4 or IPv6 address in the nvlist `nvl' on the interface
2197 * `ifname'. If a hostname is present, it is resolved before the address
2198 * is created.
2200 ipadm_status_t
2201 i_ipadm_enable_static(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl,
2202 sa_family_t af)
2204 char *prefixlenstr = NULL;
2205 char *upstr = NULL;
2206 char *sname = NULL, *dname = NULL;
2207 struct ipadm_addrobj_s ipaddr;
2208 char *aobjname = NULL;
2209 nvlist_t *nvaddr = NULL;
2210 nvpair_t *nvp;
2211 char *cidraddr;
2212 char *name;
2213 ipadm_status_t status;
2214 int err = 0;
2215 uint32_t flags = IPADM_OPT_ACTIVE;
2217 /* retrieve the address information */
2218 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2219 nvp = nvlist_next_nvpair(nvl, nvp)) {
2220 name = nvpair_name(nvp);
2221 if (strcmp(name, IPADM_NVP_IPV4ADDR) == 0 ||
2222 strcmp(name, IPADM_NVP_IPV6ADDR) == 0) {
2223 err = nvpair_value_nvlist(nvp, &nvaddr);
2224 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
2225 err = nvpair_value_string(nvp, &aobjname);
2226 } else if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0) {
2227 err = nvpair_value_string(nvp, &prefixlenstr);
2228 } else if (strcmp(name, "up") == 0) {
2229 err = nvpair_value_string(nvp, &upstr);
2231 if (err != 0)
2232 return (ipadm_errno2status(err));
2234 for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
2235 nvp = nvlist_next_nvpair(nvaddr, nvp)) {
2236 name = nvpair_name(nvp);
2237 if (strcmp(name, IPADM_NVP_IPADDRHNAME) == 0)
2238 err = nvpair_value_string(nvp, &sname);
2239 else if (strcmp(name, IPADM_NVP_IPDADDRHNAME) == 0)
2240 err = nvpair_value_string(nvp, &dname);
2241 if (err != 0)
2242 return (ipadm_errno2status(err));
2245 if (strcmp(upstr, "yes") == 0)
2246 flags |= IPADM_OPT_UP;
2248 /* build the address object from the above information */
2249 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_STATIC);
2250 if (prefixlenstr != NULL && atoi(prefixlenstr) > 0) {
2251 if (asprintf(&cidraddr, "%s/%s", sname, prefixlenstr) == -1)
2252 return (IPADM_NO_MEMORY);
2253 status = ipadm_set_addr(&ipaddr, cidraddr, af);
2254 free(cidraddr);
2255 } else {
2256 status = ipadm_set_addr(&ipaddr, sname, af);
2258 if (status != IPADM_SUCCESS)
2259 return (status);
2261 if (dname != NULL) {
2262 status = ipadm_set_dst_addr(&ipaddr, dname, af);
2263 if (status != IPADM_SUCCESS)
2264 return (status);
2266 return (i_ipadm_create_addr(iph, &ipaddr, flags));
2270 * Creates a dhcp address on the interface `ifname' based on the
2271 * IPADM_ADDR_DHCP address object parameters from the nvlist `nvl'.
2273 ipadm_status_t
2274 i_ipadm_enable_dhcp(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2276 int32_t wait = IPADM_DHCP_WAIT_DEFAULT;
2277 boolean_t primary = B_FALSE;
2278 nvlist_t *nvdhcp = NULL;
2279 nvpair_t *nvp;
2280 char *name;
2281 struct ipadm_addrobj_s ipaddr;
2282 char *aobjname = NULL, *reqhost = NULL;
2283 int err = 0;
2284 ipadm_status_t ipadm_err = IPADM_SUCCESS;
2286 /* Extract the dhcp parameters */
2287 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2288 nvp = nvlist_next_nvpair(nvl, nvp)) {
2289 name = nvpair_name(nvp);
2290 if (strcmp(name, IPADM_NVP_DHCP) == 0)
2291 err = nvpair_value_nvlist(nvp, &nvdhcp);
2292 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2293 err = nvpair_value_string(nvp, &aobjname);
2294 else if (strcmp(name, IPADM_NVP_REQHOST) == 0)
2295 err = nvpair_value_string(nvp, &reqhost);
2296 if (err != 0)
2297 return (ipadm_errno2status(err));
2299 for (nvp = nvlist_next_nvpair(nvdhcp, NULL); nvp != NULL;
2300 nvp = nvlist_next_nvpair(nvdhcp, nvp)) {
2301 name = nvpair_name(nvp);
2302 if (strcmp(name, IPADM_NVP_WAIT) == 0)
2303 err = nvpair_value_int32(nvp, &wait);
2304 else if (strcmp(name, IPADM_NVP_PRIMARY) == 0)
2305 err = nvpair_value_boolean_value(nvp, &primary);
2306 if (err != 0)
2307 return (ipadm_errno2status(err));
2310 /* Build the address object */
2311 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_DHCP);
2312 ipaddr.ipadm_primary = primary;
2313 if (iph->iph_flags & IPH_INIT)
2314 ipaddr.ipadm_wait = 0;
2315 else
2316 ipaddr.ipadm_wait = wait;
2317 ipadm_err = ipadm_set_reqhost(&ipaddr, reqhost);
2318 if (ipadm_err != IPADM_SUCCESS)
2319 return (ipadm_err);
2320 ipaddr.ipadm_af = AF_INET;
2321 return (i_ipadm_create_dhcp(iph, &ipaddr, IPADM_OPT_ACTIVE));
2325 * Creates auto-configured addresses on the interface `ifname' based on
2326 * the IPADM_ADDR_IPV6_ADDRCONF address object parameters from the nvlist `nvl'.
2328 ipadm_status_t
2329 i_ipadm_enable_addrconf(ipadm_handle_t iph, const char *ifname, nvlist_t *nvl)
2331 struct ipadm_addrobj_s ipaddr;
2332 char *stateful = NULL, *stateless = NULL;
2333 uint_t n;
2334 uint8_t *addr6 = NULL;
2335 uint32_t intfidlen = 0;
2336 char *aobjname;
2337 nvlist_t *nvaddr;
2338 nvpair_t *nvp;
2339 char *name;
2340 int err = 0;
2342 /* Extract the parameters */
2343 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
2344 nvp = nvlist_next_nvpair(nvl, nvp)) {
2345 name = nvpair_name(nvp);
2346 if (strcmp(name, IPADM_NVP_INTFID) == 0)
2347 err = nvpair_value_nvlist(nvp, &nvaddr);
2348 else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0)
2349 err = nvpair_value_string(nvp, &aobjname);
2350 if (err != 0)
2351 return (ipadm_errno2status(err));
2353 for (nvp = nvlist_next_nvpair(nvaddr, NULL); nvp != NULL;
2354 nvp = nvlist_next_nvpair(nvaddr, nvp)) {
2355 name = nvpair_name(nvp);
2356 if (strcmp(name, IPADM_NVP_IPNUMADDR) == 0)
2357 err = nvpair_value_uint8_array(nvp, &addr6, &n);
2358 if (strcmp(name, IPADM_NVP_PREFIXLEN) == 0)
2359 err = nvpair_value_uint32(nvp, &intfidlen);
2360 else if (strcmp(name, IPADM_NVP_STATELESS) == 0)
2361 err = nvpair_value_string(nvp, &stateless);
2362 else if (strcmp(name, IPADM_NVP_STATEFUL) == 0)
2363 err = nvpair_value_string(nvp, &stateful);
2364 if (err != 0)
2365 return (ipadm_errno2status(err));
2367 /* Build the address object. */
2368 i_ipadm_init_addr(&ipaddr, ifname, aobjname, IPADM_ADDR_IPV6_ADDRCONF);
2369 if (intfidlen > 0) {
2370 ipaddr.ipadm_intfidlen = intfidlen;
2371 bcopy(addr6, &ipaddr.ipadm_intfid.sin6_addr.s6_addr, n);
2373 ipaddr.ipadm_stateless = (strcmp(stateless, "yes") == 0);
2374 ipaddr.ipadm_stateful = (strcmp(stateful, "yes") == 0);
2375 return (i_ipadm_create_ipv6addrs(iph, &ipaddr, IPADM_OPT_ACTIVE));
2379 * Allocates `ipadm_addrobj_t' and populates the relevant member fields based on
2380 * the provided `type'. `aobjname' represents the address object name, which
2381 * is of the form `<ifname>/<addressname>'.
2383 * The caller has to minimally provide <ifname>. If <addressname> is not
2384 * provided, then a default one will be generated by the API.
2386 ipadm_status_t
2387 ipadm_create_addrobj(ipadm_addr_type_t type, const char *aobjname,
2388 ipadm_addrobj_t *ipaddr)
2390 ipadm_addrobj_t newaddr;
2391 ipadm_status_t status;
2392 char *aname, *cp;
2393 char ifname[IPADM_AOBJSIZ];
2394 ifspec_t ifsp;
2396 if (ipaddr == NULL)
2397 return (IPADM_INVALID_ARG);
2398 *ipaddr = NULL;
2400 if (aobjname == NULL || aobjname[0] == '\0')
2401 return (IPADM_INVALID_ARG);
2403 if (strlcpy(ifname, aobjname, IPADM_AOBJSIZ) >= IPADM_AOBJSIZ)
2404 return (IPADM_INVALID_ARG);
2406 if ((aname = strchr(ifname, '/')) != NULL)
2407 *aname++ = '\0';
2409 /* Check if the interface name is valid. */
2410 if (!ifparse_ifspec(ifname, &ifsp))
2411 return (IPADM_INVALID_ARG);
2413 /* Check if the given addrobj name is valid. */
2414 if (aname != NULL && !i_ipadm_is_user_aobjname_valid(aname))
2415 return (IPADM_INVALID_ARG);
2417 if ((newaddr = calloc(1, sizeof (struct ipadm_addrobj_s))) == NULL)
2418 return (IPADM_NO_MEMORY);
2421 * If the ifname has logical interface number, extract it and assign
2422 * it to `ipadm_lifnum'. Only applications with IPH_LEGACY set will do
2423 * this today. We will check for the validity later in
2424 * i_ipadm_validate_create_addr().
2426 if (ifsp.ifsp_lunvalid) {
2427 newaddr->ipadm_lifnum = ifsp.ifsp_lun;
2428 cp = strchr(ifname, IPADM_LOGICAL_SEP);
2429 *cp = '\0';
2431 (void) strlcpy(newaddr->ipadm_ifname, ifname,
2432 sizeof (newaddr->ipadm_ifname));
2434 if (aname != NULL) {
2435 (void) snprintf(newaddr->ipadm_aobjname,
2436 sizeof (newaddr->ipadm_aobjname), "%s/%s", ifname, aname);
2439 switch (type) {
2440 case IPADM_ADDR_IPV6_ADDRCONF:
2441 newaddr->ipadm_intfidlen = 0;
2442 newaddr->ipadm_stateful = B_TRUE;
2443 newaddr->ipadm_stateless = B_TRUE;
2444 newaddr->ipadm_af = AF_INET6;
2445 break;
2447 case IPADM_ADDR_DHCP:
2448 newaddr->ipadm_primary = B_FALSE;
2449 newaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
2450 newaddr->ipadm_af = AF_INET;
2451 break;
2453 case IPADM_ADDR_STATIC:
2454 newaddr->ipadm_af = AF_UNSPEC;
2455 newaddr->ipadm_static_prefixlen = 0;
2456 break;
2458 default:
2459 status = IPADM_INVALID_ARG;
2460 goto fail;
2462 newaddr->ipadm_atype = type;
2463 *ipaddr = newaddr;
2464 return (IPADM_SUCCESS);
2465 fail:
2466 free(newaddr);
2467 return (status);
2471 * Returns `aobjname' from the address object in `ipaddr'.
2473 ipadm_status_t
2474 ipadm_get_aobjname(const ipadm_addrobj_t ipaddr, char *aobjname, size_t len)
2476 if (ipaddr == NULL || aobjname == NULL)
2477 return (IPADM_INVALID_ARG);
2478 if (strlcpy(aobjname, ipaddr->ipadm_aobjname, len) >= len)
2479 return (IPADM_INVALID_ARG);
2481 return (IPADM_SUCCESS);
2485 * Frees the address object in `ipaddr'.
2487 void
2488 ipadm_destroy_addrobj(ipadm_addrobj_t ipaddr)
2490 free(ipaddr);
2494 * Retrieves the logical interface name from `ipaddr' and stores the
2495 * string in `lifname'.
2497 void
2498 i_ipadm_addrobj2lifname(ipadm_addrobj_t ipaddr, char *lifname, int lifnamesize)
2500 if (ipaddr->ipadm_lifnum != 0) {
2501 (void) snprintf(lifname, lifnamesize, "%s:%d",
2502 ipaddr->ipadm_ifname, ipaddr->ipadm_lifnum);
2503 } else {
2504 (void) snprintf(lifname, lifnamesize, "%s",
2505 ipaddr->ipadm_ifname);
2510 * Checks if a non-zero static address is present on the 0th logical interface
2511 * of the given IPv4 or IPv6 physical interface. For an IPv4 interface, it
2512 * also checks if the interface is under DHCP control. If the condition is true,
2513 * the output argument `exists' will be set to B_TRUE. Otherwise, `exists'
2514 * is set to B_FALSE.
2516 * Note that *exists will not be initialized if an error is encountered.
2518 static ipadm_status_t
2519 i_ipadm_addr_exists_on_if(ipadm_handle_t iph, const char *ifname,
2520 sa_family_t af, boolean_t *exists)
2522 struct lifreq lifr;
2523 int sock;
2525 /* For IPH_LEGACY, a new logical interface will never be added. */
2526 if (iph->iph_flags & IPH_LEGACY) {
2527 *exists = B_FALSE;
2528 return (IPADM_SUCCESS);
2530 bzero(&lifr, sizeof (lifr));
2531 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
2532 if (af == AF_INET) {
2533 sock = iph->iph_sock;
2534 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0)
2535 return (ipadm_errno2status(errno));
2536 if (lifr.lifr_flags & IFF_DHCPRUNNING) {
2537 *exists = B_TRUE;
2538 return (IPADM_SUCCESS);
2540 } else {
2541 sock = iph->iph_sock6;
2543 if (ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) < 0)
2544 return (ipadm_errno2status(errno));
2545 *exists = !sockaddrunspec((struct sockaddr *)&lifr.lifr_addr);
2547 return (IPADM_SUCCESS);
2551 * Adds a new logical interface in the kernel for interface
2552 * `addr->ipadm_ifname', if there is a non-zero address on the 0th
2553 * logical interface or if the 0th logical interface is under DHCP
2554 * control. On success, it sets the lifnum in the address object `addr'.
2556 ipadm_status_t
2557 i_ipadm_do_addif(ipadm_handle_t iph, ipadm_addrobj_t addr)
2559 ipadm_status_t status;
2560 boolean_t addif;
2561 struct lifreq lifr;
2562 int sock;
2564 addr->ipadm_lifnum = 0;
2565 status = i_ipadm_addr_exists_on_if(iph, addr->ipadm_ifname,
2566 addr->ipadm_af, &addif);
2567 if (status != IPADM_SUCCESS)
2568 return (status);
2569 if (addif) {
2571 * If there is an address on 0th logical interface,
2572 * add a new logical interface.
2574 bzero(&lifr, sizeof (lifr));
2575 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2576 sizeof (lifr.lifr_name));
2577 sock = (addr->ipadm_af == AF_INET ? iph->iph_sock :
2578 iph->iph_sock6);
2579 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
2580 return (ipadm_errno2status(errno));
2581 addr->ipadm_lifnum = i_ipadm_get_lnum(lifr.lifr_name);
2583 return (IPADM_SUCCESS);
2587 * Reads all the address lines from the persistent DB into the nvlist `onvl',
2588 * when both `ifname' and `aobjname' are NULL. If an `ifname' is provided,
2589 * it returns all the addresses for the given interface `ifname'.
2590 * If an `aobjname' is specified, then the address line corresponding to
2591 * that name will be returned.
2593 static ipadm_status_t
2594 i_ipadm_get_db_addr(ipadm_handle_t iph, const char *ifname,
2595 const char *aobjname, nvlist_t **onvl)
2597 ipmgmt_getaddr_arg_t garg;
2598 ipmgmt_get_rval_t *rvalp;
2599 int err;
2600 size_t nvlsize;
2601 char *nvlbuf;
2603 /* Populate the door_call argument structure */
2604 bzero(&garg, sizeof (garg));
2605 garg.ia_cmd = IPMGMT_CMD_GETADDR;
2606 if (aobjname != NULL)
2607 (void) strlcpy(garg.ia_aobjname, aobjname,
2608 sizeof (garg.ia_aobjname));
2609 if (ifname != NULL)
2610 (void) strlcpy(garg.ia_ifname, ifname, sizeof (garg.ia_ifname));
2612 rvalp = malloc(sizeof (ipmgmt_get_rval_t));
2613 err = ipadm_door_call(iph, &garg, sizeof (garg), (void **)&rvalp,
2614 sizeof (*rvalp), B_TRUE);
2615 if (err == 0) {
2616 nvlsize = rvalp->ir_nvlsize;
2617 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
2618 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
2620 free(rvalp);
2621 return (ipadm_errno2status(err));
2625 * Adds the IP address contained in the 'ipaddr' argument to the physical
2626 * interface represented by 'ifname' after doing the required validation.
2627 * If the interface does not exist, it is created before the address is
2628 * added.
2630 * If IPH_LEGACY is set in iph_flags, flags has to be IPADM_OPT_ACTIVE
2631 * and a default addrobj name will be generated. Input `addr->ipadm_aobjname',
2632 * if provided, will be ignored and replaced with the newly generated name.
2633 * The interface name provided has to be a logical interface name that
2634 * already exists. No new logical interface will be added in this function.
2636 * If IPADM_OPT_V46 is passed in the flags, then both IPv4 and IPv6 interfaces
2637 * are plumbed (if they haven't been already). Otherwise, just the interface
2638 * specified in `addr' is plumbed.
2640 ipadm_status_t
2641 ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
2643 ipadm_status_t status;
2644 sa_family_t af;
2645 sa_family_t daf;
2646 sa_family_t other_af;
2647 boolean_t created_af = B_FALSE;
2648 boolean_t created_other_af = B_FALSE;
2649 ipadm_addr_type_t type;
2650 char *ifname = addr->ipadm_ifname;
2651 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
2652 boolean_t aobjfound;
2653 boolean_t is_6to4;
2654 struct lifreq lifr;
2655 uint64_t ifflags;
2656 boolean_t is_boot = (iph->iph_flags & IPH_IPMGMTD);
2658 /* check for solaris.network.interface.config authorization */
2659 if (!ipadm_check_auth())
2660 return (IPADM_EAUTH);
2662 /* Validate the addrobj. This also fills in addr->ipadm_ifname. */
2663 status = i_ipadm_validate_create_addr(iph, addr, flags);
2664 if (status != IPADM_SUCCESS)
2665 return (status);
2668 * For Legacy case, check if an addrobj already exists for the
2669 * given logical interface name. If one does not exist,
2670 * a default name will be generated and added to the daemon's
2671 * aobjmap.
2673 if (legacy) {
2674 struct ipadm_addrobj_s ipaddr;
2676 ipaddr = *addr;
2677 status = i_ipadm_get_lif2addrobj(iph, &ipaddr);
2678 if (status == IPADM_SUCCESS) {
2679 aobjfound = B_TRUE;
2681 * With IPH_LEGACY, modifying an address that is not
2682 * a static address will return with an error.
2684 if (ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
2685 return (IPADM_NOTSUP);
2687 * we found the addrobj in daemon, copy over the
2688 * aobjname to `addr'.
2690 (void) strlcpy(addr->ipadm_aobjname,
2691 ipaddr.ipadm_aobjname, IPADM_AOBJSIZ);
2692 } else if (status == IPADM_NOTFOUND) {
2693 aobjfound = B_FALSE;
2694 } else {
2695 return (status);
2699 af = addr->ipadm_af;
2701 * Create a placeholder for this address object in the daemon.
2702 * Skip this step if we are booting a zone (and therefore being called
2703 * from ipmgmtd itself), and, for IPH_LEGACY case if the
2704 * addrobj already exists.
2706 * Note that the placeholder is not needed in the NGZ boot case,
2707 * when zoneadmd has itself applied the "allowed-ips" property to clamp
2708 * down any interface configuration, so the namespace for the interface
2709 * is fully controlled by the GZ.
2711 if (!is_boot && (!legacy || !aobjfound)) {
2712 status = i_ipadm_lookupadd_addrobj(iph, addr);
2713 if (status != IPADM_SUCCESS)
2714 return (status);
2717 is_6to4 = i_ipadm_is_6to4(iph, ifname);
2718 /* Plumb the IP interfaces if necessary */
2719 status = i_ipadm_create_if(iph, ifname, af, flags);
2720 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2721 (void) i_ipadm_delete_addrobj(iph, addr, IPADM_OPT_ACTIVE);
2722 return (status);
2724 if (status == IPADM_SUCCESS)
2725 created_af = B_TRUE;
2726 if (!is_6to4 && !legacy && (flags & IPADM_OPT_V46)) {
2727 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
2728 status = i_ipadm_create_if(iph, ifname, other_af, flags);
2729 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS) {
2730 (void) i_ipadm_delete_if(iph, ifname, af, flags);
2731 return (status);
2733 if (status == IPADM_SUCCESS)
2734 created_other_af = B_TRUE;
2738 * Some input validation based on the interface flags:
2739 * 1. in non-global zones, make sure that we are not persistently
2740 * creating addresses on interfaces that are acquiring
2741 * address from the global zone.
2742 * 2. Validate static addresses for IFF_POINTOPOINT interfaces.
2744 if (addr->ipadm_atype == IPADM_ADDR_STATIC) {
2745 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
2746 if (status != IPADM_SUCCESS)
2747 goto fail;
2749 if (iph->iph_zoneid != GLOBAL_ZONEID &&
2750 (ifflags & IFF_L3PROTECT) && (flags & IPADM_OPT_PERSIST)) {
2751 status = IPADM_GZ_PERM;
2752 goto fail;
2754 daf = addr->ipadm_static_dst_addr.ss_family;
2755 if (ifflags & IFF_POINTOPOINT) {
2756 if (is_6to4) {
2757 if (af != AF_INET6 || daf != AF_UNSPEC) {
2758 status = IPADM_INVALID_ARG;
2759 goto fail;
2761 } else {
2762 if (daf != af) {
2763 status = IPADM_INVALID_ARG;
2764 goto fail;
2766 /* Check for a valid dst address. */
2767 if (!legacy && sockaddrunspec(
2768 (struct sockaddr *)
2769 &addr->ipadm_static_dst_addr)) {
2770 status = IPADM_BAD_ADDR;
2771 goto fail;
2774 } else {
2776 * Disallow setting of dstaddr when the link is not
2777 * a point-to-point link.
2779 if (daf != AF_UNSPEC)
2780 return (IPADM_INVALID_ARG);
2785 * For 6to4 interfaces, kernel configures a default link-local
2786 * address. We need to replace it, if the caller has provided
2787 * an address that is different from the default link-local.
2789 if (status == IPADM_SUCCESS && is_6to4) {
2790 bzero(&lifr, sizeof (lifr));
2791 (void) strlcpy(lifr.lifr_name, addr->ipadm_ifname,
2792 sizeof (lifr.lifr_name));
2793 if (ioctl(iph->iph_sock6, SIOCGLIFADDR, &lifr) < 0) {
2794 status = ipadm_errno2status(errno);
2795 goto fail;
2797 if (sockaddrcmp(&lifr.lifr_addr, &addr->ipadm_static_addr))
2798 return (IPADM_SUCCESS);
2801 /* Create the address. */
2802 type = addr->ipadm_atype;
2803 switch (type) {
2804 case IPADM_ADDR_STATIC:
2805 status = i_ipadm_create_addr(iph, addr, flags);
2806 break;
2807 case IPADM_ADDR_DHCP:
2808 status = i_ipadm_create_dhcp(iph, addr, flags);
2809 break;
2810 case IPADM_ADDR_IPV6_ADDRCONF:
2811 status = i_ipadm_create_ipv6addrs(iph, addr, flags);
2812 break;
2813 default:
2814 status = IPADM_INVALID_ARG;
2815 break;
2819 * If address was not created successfully, unplumb the interface
2820 * if it was plumbed implicitly in this function and remove the
2821 * addrobj created by the ipmgmtd daemon as a placeholder.
2822 * If IPH_LEGACY is set, then remove the addrobj only if it was
2823 * created in this function.
2825 fail:
2826 if (status != IPADM_DHCP_IPC_TIMEOUT &&
2827 status != IPADM_SUCCESS) {
2828 if (!legacy) {
2829 if (created_af || created_other_af) {
2830 if (created_af) {
2831 (void) i_ipadm_delete_if(iph, ifname,
2832 af, flags);
2834 if (created_other_af) {
2835 (void) i_ipadm_delete_if(iph, ifname,
2836 other_af, flags);
2838 } else {
2839 (void) i_ipadm_delete_addrobj(iph, addr, flags);
2841 } else if (!aobjfound) {
2842 (void) i_ipadm_delete_addrobj(iph, addr, flags);
2846 return (status);
2850 * Creates the static address in `ipaddr' in kernel. After successfully
2851 * creating it, it updates the ipmgmtd daemon's aobjmap with the logical
2852 * interface information.
2854 static ipadm_status_t
2855 i_ipadm_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr, uint32_t flags)
2857 struct lifreq lifr;
2858 ipadm_status_t status = IPADM_SUCCESS;
2859 int sock;
2860 struct sockaddr_storage m, *mask = &m;
2861 const struct sockaddr_storage *addr = &ipaddr->ipadm_static_addr;
2862 const struct sockaddr_storage *daddr = &ipaddr->ipadm_static_dst_addr;
2863 sa_family_t af;
2864 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
2865 struct ipadm_addrobj_s legacy_addr;
2866 boolean_t default_prefixlen = B_FALSE;
2867 boolean_t is_boot;
2869 is_boot = ((iph->iph_flags & IPH_IPMGMTD) != 0);
2870 af = ipaddr->ipadm_af;
2871 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
2873 /* If prefixlen was not provided, get default prefixlen */
2874 if (ipaddr->ipadm_static_prefixlen == 0) {
2875 /* prefixlen was not provided, get default prefixlen */
2876 status = i_ipadm_get_default_prefixlen(
2877 &ipaddr->ipadm_static_addr,
2878 &ipaddr->ipadm_static_prefixlen);
2879 if (status != IPADM_SUCCESS)
2880 return (status);
2881 default_prefixlen = B_TRUE;
2883 (void) plen2mask(ipaddr->ipadm_static_prefixlen, af,
2884 (struct sockaddr *)mask);
2887 * Create a new logical interface if needed; otherwise, just
2888 * use the 0th logical interface.
2890 retry:
2891 if (!(iph->iph_flags & IPH_LEGACY)) {
2892 status = i_ipadm_do_addif(iph, ipaddr);
2893 if (status != IPADM_SUCCESS)
2894 return (status);
2896 * We don't have to set the lifnum for IPH_INIT case, because
2897 * there is no placeholder created for the address object in
2898 * this case. For IPH_LEGACY, we don't do this because the
2899 * lifnum is given by the caller and it will be set in the
2900 * end while we call the i_ipadm_addr_persist().
2902 if (!(iph->iph_flags & IPH_INIT)) {
2903 status = i_ipadm_setlifnum_addrobj(iph, ipaddr);
2904 if (status == IPADM_ADDROBJ_EXISTS)
2905 goto retry;
2906 if (status != IPADM_SUCCESS)
2907 return (status);
2910 i_ipadm_addrobj2lifname(ipaddr, lifr.lifr_name,
2911 sizeof (lifr.lifr_name));
2912 lifr.lifr_addr = *mask;
2913 if (ioctl(sock, SIOCSLIFNETMASK, (caddr_t)&lifr) < 0) {
2914 status = ipadm_errno2status(errno);
2915 goto ret;
2917 lifr.lifr_addr = *addr;
2918 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0) {
2919 status = ipadm_errno2status(errno);
2920 goto ret;
2922 /* Set the destination address, if one is given. */
2923 if (daddr->ss_family != AF_UNSPEC) {
2924 lifr.lifr_addr = *daddr;
2925 if (ioctl(sock, SIOCSLIFDSTADDR, (caddr_t)&lifr) < 0) {
2926 status = ipadm_errno2status(errno);
2927 goto ret;
2931 if (flags & IPADM_OPT_UP) {
2932 status = i_ipadm_set_flags(iph, lifr.lifr_name, af, IFF_UP, 0);
2935 * IPADM_DAD_FOUND is a soft-error for create-addr.
2936 * No need to tear down the address.
2938 if (status == IPADM_DAD_FOUND)
2939 status = IPADM_SUCCESS;
2942 if (status == IPADM_SUCCESS && !is_boot) {
2944 * For IPH_LEGACY, we might be modifying the address on
2945 * an address object that already exists e.g. by doing
2946 * "ifconfig bge0:1 <addr>; ifconfig bge0:1 <newaddr>"
2947 * So, we need to store the object only if it does not
2948 * already exist in ipmgmtd.
2950 if (legacy) {
2951 bzero(&legacy_addr, sizeof (legacy_addr));
2952 (void) strlcpy(legacy_addr.ipadm_aobjname,
2953 ipaddr->ipadm_aobjname,
2954 sizeof (legacy_addr.ipadm_aobjname));
2955 status = i_ipadm_get_addrobj(iph, &legacy_addr);
2956 if (status == IPADM_SUCCESS &&
2957 legacy_addr.ipadm_lifnum >= 0) {
2958 return (status);
2961 status = i_ipadm_addr_persist(iph, ipaddr, default_prefixlen,
2962 flags, NULL);
2964 ret:
2965 if (status != IPADM_SUCCESS && !legacy)
2966 (void) i_ipadm_delete_addr(iph, ipaddr);
2967 return (status);
2971 * Removes the address object identified by `aobjname' from both active and
2972 * persistent configuration. The address object will be removed from only
2973 * active configuration if IPH_LEGACY is set in `iph->iph_flags'.
2975 * If the address type is IPADM_ADDR_STATIC or IPADM_ADDR_DHCP, the address
2976 * in the address object will be removed from the physical interface.
2977 * If the address type is IPADM_ADDR_DHCP, the flag IPADM_OPT_RELEASE specifies
2978 * whether the lease should be released. If IPADM_OPT_RELEASE is not
2979 * specified, the lease will be dropped. This option is not supported
2980 * for other address types.
2982 * If the address type is IPADM_ADDR_IPV6_ADDRCONF, the link-local address and
2983 * all the autoconfigured addresses will be removed.
2984 * Finally, the address object is also removed from ipmgmtd's aobjmap and from
2985 * the persistent DB.
2987 ipadm_status_t
2988 ipadm_delete_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
2990 ipadm_status_t status;
2991 struct ipadm_addrobj_s ipaddr;
2992 boolean_t release = ((flags & IPADM_OPT_RELEASE) != 0);
2994 /* check for solaris.network.interface.config authorization */
2995 if (!ipadm_check_auth())
2996 return (IPADM_EAUTH);
2998 /* validate input */
2999 if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
3000 !(flags & IPADM_OPT_ACTIVE)) ||
3001 (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_RELEASE))) {
3002 return (IPADM_INVALID_ARG);
3004 bzero(&ipaddr, sizeof (ipaddr));
3005 if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3006 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3007 return (IPADM_INVALID_ARG);
3010 /* Retrieve the address object information from ipmgmtd. */
3011 status = i_ipadm_get_addrobj(iph, &ipaddr);
3012 if (status != IPADM_SUCCESS)
3013 return (status);
3015 if (release && ipaddr.ipadm_atype != IPADM_ADDR_DHCP)
3016 return (IPADM_NOTSUP);
3018 * If requested to delete just from active config but the address
3019 * is not in active config, return error.
3021 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE) &&
3022 (flags & IPADM_OPT_ACTIVE) && !(flags & IPADM_OPT_PERSIST)) {
3023 return (IPADM_NOTFOUND);
3027 * If address is present in active config, remove it from
3028 * kernel.
3030 if (ipaddr.ipadm_flags & IPMGMT_ACTIVE) {
3031 switch (ipaddr.ipadm_atype) {
3032 case IPADM_ADDR_STATIC:
3033 status = i_ipadm_delete_addr(iph, &ipaddr);
3034 break;
3035 case IPADM_ADDR_DHCP:
3036 status = i_ipadm_delete_dhcp(iph, &ipaddr, release);
3037 break;
3038 case IPADM_ADDR_IPV6_ADDRCONF:
3039 status = i_ipadm_delete_ipv6addrs(iph, &ipaddr);
3040 break;
3041 default:
3043 * This is the case of address object name residing in
3044 * daemon's aobjmap (added by ADDROBJ_LOOKUPADD). Fall
3045 * through and delete that address object.
3047 break;
3051 * If the address was previously deleted from the active
3052 * config, we will get a IPADM_ENXIO from kernel.
3053 * We will still proceed and purge the address information
3054 * in the DB.
3056 if (status == IPADM_ENXIO)
3057 status = IPADM_SUCCESS;
3058 else if (status != IPADM_SUCCESS)
3059 return (status);
3062 if (!(ipaddr.ipadm_flags & IPMGMT_PERSIST) &&
3063 (flags & IPADM_OPT_PERSIST)) {
3064 flags &= ~IPADM_OPT_PERSIST;
3066 status = i_ipadm_delete_addrobj(iph, &ipaddr, flags);
3067 if (status == IPADM_NOTFOUND)
3068 return (status);
3069 return (IPADM_SUCCESS);
3073 * Starts the dhcpagent and sends it the message DHCP_START to start
3074 * configuring a dhcp address on the given interface in `addr'.
3075 * After making the dhcpagent request, it also updates the
3076 * address object information in ipmgmtd's aobjmap and creates an
3077 * entry in persistent DB if IPADM_OPT_PERSIST is set in `flags'.
3079 static ipadm_status_t
3080 i_ipadm_create_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, uint32_t flags)
3082 ipadm_status_t status;
3083 ipadm_status_t dh_status;
3085 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3086 return (IPADM_DHCP_START_ERROR);
3088 * Create a new logical interface if needed; otherwise, just
3089 * use the 0th logical interface.
3091 retry:
3092 status = i_ipadm_do_addif(iph, addr);
3093 if (status != IPADM_SUCCESS)
3094 return (status);
3096 * We don't have to set the lifnum for IPH_INIT case, because
3097 * there is no placeholder created for the address object in this
3098 * case.
3100 if (!(iph->iph_flags & IPH_INIT)) {
3101 status = i_ipadm_setlifnum_addrobj(iph, addr);
3102 if (status == IPADM_ADDROBJ_EXISTS)
3103 goto retry;
3104 if (status != IPADM_SUCCESS)
3105 return (status);
3107 /* Send DHCP_START to the dhcpagent. */
3108 status = i_ipadm_op_dhcp(addr, DHCP_START, NULL);
3110 * We do not undo the create-addr operation for IPADM_DHCP_IPC_TIMEOUT
3111 * since it is only a soft error to indicate the caller that the lease
3112 * might be required after the function returns.
3114 if (status != IPADM_SUCCESS && status != IPADM_DHCP_IPC_TIMEOUT)
3115 goto fail;
3116 dh_status = status;
3118 /* Persist the address object information in ipmgmtd. */
3119 status = i_ipadm_addr_persist(iph, addr, B_FALSE, flags, NULL);
3120 if (status != IPADM_SUCCESS)
3121 goto fail;
3123 return (dh_status);
3124 fail:
3125 /* In case of error, delete the dhcp address */
3126 (void) i_ipadm_delete_dhcp(iph, addr, B_TRUE);
3127 return (status);
3131 * Releases/drops the dhcp lease on the logical interface in the address
3132 * object `addr'. If `release' is set to B_FALSE, the lease will be dropped.
3134 static ipadm_status_t
3135 i_ipadm_delete_dhcp(ipadm_handle_t iph, ipadm_addrobj_t addr, boolean_t release)
3137 ipadm_status_t status;
3138 int dherr;
3140 /* Send DHCP_RELEASE or DHCP_DROP to the dhcpagent */
3141 if (release) {
3142 status = i_ipadm_op_dhcp(addr, DHCP_RELEASE, &dherr);
3144 * If no lease was obtained on the object, we should
3145 * drop the dhcp control on the interface.
3147 if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE)
3148 status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
3149 } else {
3150 status = i_ipadm_op_dhcp(addr, DHCP_DROP, NULL);
3152 if (status != IPADM_SUCCESS)
3153 return (status);
3155 /* Delete the logical interface */
3156 if (addr->ipadm_lifnum != 0) {
3157 struct lifreq lifr;
3159 bzero(&lifr, sizeof (lifr));
3160 i_ipadm_addrobj2lifname(addr, lifr.lifr_name,
3161 sizeof (lifr.lifr_name));
3162 if (ioctl(iph->iph_sock, SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0)
3163 return (ipadm_errno2status(errno));
3166 return (IPADM_SUCCESS);
3170 * Communicates with the dhcpagent to send a dhcp message of type `type'.
3171 * It returns the dhcp error in `dhcperror' if a non-null pointer is provided
3172 * in `dhcperror'.
3174 static ipadm_status_t
3175 i_ipadm_op_dhcp(ipadm_addrobj_t addr, dhcp_ipc_type_t type, int *dhcperror)
3177 dhcp_ipc_request_t *request;
3178 dhcp_ipc_reply_t *reply = NULL;
3179 dhcp_symbol_t *entry = NULL;
3180 dhcp_data_type_t dtype = DHCP_TYPE_NONE;
3181 void *d4o = NULL;
3182 uint16_t d4olen = 0;
3183 char ifname[LIFNAMSIZ];
3184 int error;
3185 int dhcp_timeout;
3187 /* Construct a message to the dhcpagent. */
3188 bzero(&ifname, sizeof (ifname));
3189 i_ipadm_addrobj2lifname(addr, ifname, sizeof (ifname));
3190 if (addr->ipadm_primary)
3191 type |= DHCP_PRIMARY;
3193 /* Set up a CD_HOSTNAME option, if applicable, to send through IPC */
3194 switch (DHCP_IPC_CMD(type)) {
3195 case DHCP_START:
3196 case DHCP_EXTEND:
3197 if (addr->ipadm_af == AF_INET && addr->ipadm_reqhost != NULL &&
3198 *addr->ipadm_reqhost != '\0') {
3199 entry = inittab_getbycode(ITAB_CAT_STANDARD,
3200 ITAB_CONS_INFO, CD_HOSTNAME);
3201 if (entry == NULL) {
3202 return (IPADM_FAILURE);
3203 } else {
3204 d4o = inittab_encode(entry, addr->ipadm_reqhost,
3205 &d4olen, B_FALSE);
3206 free(entry);
3207 entry = NULL;
3208 if (d4o == NULL)
3209 return (IPADM_FAILURE);
3210 dtype = DHCP_TYPE_OPTION;
3213 break;
3214 default:
3215 break;
3218 request = dhcp_ipc_alloc_request(type, ifname, d4o, d4olen, dtype);
3219 if (request == NULL) {
3220 free(d4o);
3221 return (IPADM_NO_MEMORY);
3224 if (addr->ipadm_wait == IPADM_DHCP_WAIT_FOREVER)
3225 dhcp_timeout = DHCP_IPC_WAIT_FOREVER;
3226 else if (addr->ipadm_wait == IPADM_DHCP_WAIT_DEFAULT)
3227 dhcp_timeout = DHCP_IPC_WAIT_DEFAULT;
3228 else
3229 dhcp_timeout = addr->ipadm_wait;
3230 /* Send the message to dhcpagent. */
3231 error = dhcp_ipc_make_request(request, &reply, dhcp_timeout);
3232 free(request);
3233 free(d4o);
3234 if (error == 0) {
3235 error = reply->return_code;
3236 free(reply);
3238 if (error != 0) {
3239 if (dhcperror != NULL)
3240 *dhcperror = error;
3241 if (error != DHCP_IPC_E_TIMEOUT)
3242 return (IPADM_DHCP_IPC_ERROR);
3243 else if (dhcp_timeout != 0)
3244 return (IPADM_DHCP_IPC_TIMEOUT);
3247 return (IPADM_SUCCESS);
3251 * Communicates with the dhcpagent to send a dhcp message of type
3252 * DHCP_STATUS, and copy on success into the `status' instance owned by the
3253 * caller. It returns any dhcp error in `dhcperror' if a non-null pointer
3254 * is provided.
3256 static ipadm_status_t
3257 i_ipadm_dhcp_status(ipadm_addrobj_t addr, dhcp_status_t *status,
3258 int *dhcperror)
3260 dhcp_ipc_type_t type = DHCP_STATUS;
3261 dhcp_ipc_request_t *request;
3262 dhcp_ipc_reply_t *reply;
3263 dhcp_status_t *private_status;
3264 size_t reply_size;
3265 int error;
3267 if (addr->ipadm_af == AF_INET6)
3268 type |= DHCP_V6;
3270 request = dhcp_ipc_alloc_request(type, addr->ipadm_ifname, NULL, 0,
3271 DHCP_TYPE_NONE);
3272 if (request == NULL)
3273 return (IPADM_NO_MEMORY);
3275 error = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT);
3276 free(request);
3277 if (error != 0) {
3278 if (dhcperror != NULL)
3279 *dhcperror = error;
3280 return (error != DHCP_IPC_E_TIMEOUT ? IPADM_DHCP_IPC_ERROR
3281 : IPADM_DHCP_IPC_TIMEOUT);
3284 error = reply->return_code;
3285 if (error == DHCP_IPC_E_UNKIF) {
3286 free(reply);
3287 bzero(status, sizeof (dhcp_status_t));
3288 return (IPADM_NOTFOUND);
3291 private_status = dhcp_ipc_get_data(reply, &reply_size, NULL);
3292 if (reply_size < DHCP_STATUS_VER1_SIZE) {
3293 free(reply);
3294 return (IPADM_DHCP_IPC_ERROR);
3298 * Copy the status out of the memory allocated by this function into
3299 * memory owned by the caller.
3301 *status = *private_status;
3302 free(reply);
3303 return (IPADM_SUCCESS);
3307 * Returns the IP addresses of the specified interface in both the
3308 * active and the persistent configuration. If no
3309 * interface is specified, it returns all non-zero IP addresses
3310 * configured on all interfaces in active and persistent
3311 * configurations.
3312 * `addrinfo' will contain addresses that are
3313 * (1) in both active and persistent configuration (created persistently)
3314 * (2) only in active configuration (created temporarily)
3315 * (3) only in persistent configuration (disabled addresses)
3317 * Address list that is returned by this function must be freed
3318 * using the ipadm_freeaddr_info() function.
3320 ipadm_status_t
3321 ipadm_addr_info(ipadm_handle_t iph, const char *ifname,
3322 ipadm_addr_info_t **addrinfo, uint32_t flags, int64_t lifc_flags)
3324 ifspec_t ifsp;
3326 if (addrinfo == NULL || iph == NULL)
3327 return (IPADM_INVALID_ARG);
3328 if (ifname != NULL &&
3329 (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
3330 return (IPADM_INVALID_ARG);
3332 return (i_ipadm_get_all_addr_info(iph, ifname, addrinfo,
3333 flags, lifc_flags));
3337 * Frees the structure allocated by ipadm_addr_info().
3339 void
3340 ipadm_free_addr_info(ipadm_addr_info_t *ainfo)
3342 freeifaddrs((struct ifaddrs *)ainfo);
3346 * Makes a door call to ipmgmtd to update its `aobjmap' with the address
3347 * object in `ipaddr'. This door call also can update the persistent DB to
3348 * remember address object to be recreated on next reboot or on an
3349 * ipadm_enable_addr()/ipadm_enable_if() call.
3351 ipadm_status_t
3352 i_ipadm_addr_persist(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3353 boolean_t default_prefixlen, uint32_t flags, const char *propname)
3355 char *aname = ipaddr->ipadm_aobjname;
3356 nvlist_t *nvl;
3357 int err = 0;
3358 ipadm_status_t status;
3359 uint_t pflags = 0;
3362 * Construct the nvl to send to the door.
3364 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
3365 return (IPADM_NO_MEMORY);
3366 if ((err = nvlist_add_string(nvl, IPADM_NVP_IFNAME,
3367 ipaddr->ipadm_ifname)) != 0 ||
3368 (err = nvlist_add_string(nvl, IPADM_NVP_AOBJNAME, aname)) != 0 ||
3369 (err = nvlist_add_int32(nvl, IPADM_NVP_LIFNUM,
3370 ipaddr->ipadm_lifnum)) != 0) {
3371 status = ipadm_errno2status(err);
3372 goto ret;
3374 switch (ipaddr->ipadm_atype) {
3375 case IPADM_ADDR_STATIC:
3376 status = i_ipadm_add_ipaddr2nvl(nvl, ipaddr);
3377 if (status != IPADM_SUCCESS)
3378 goto ret;
3379 if (flags & IPADM_OPT_UP)
3380 err = nvlist_add_string(nvl, "up", "yes");
3381 else
3382 err = nvlist_add_string(nvl, "up", "no");
3383 status = ipadm_errno2status(err);
3384 break;
3385 case IPADM_ADDR_DHCP:
3386 status = i_ipadm_add_dhcp2nvl(nvl, ipaddr->ipadm_primary,
3387 ipaddr->ipadm_wait);
3388 if (status != IPADM_SUCCESS)
3389 goto ret;
3392 * For purposes of updating the ipmgmtd cached representation of
3393 * reqhost (ipmgmt_am_reqhost), include a value here in `nvl',
3394 * but the value is actually fully persisted as a separate
3395 * i_ipadm_persist_propval below.
3397 err = nvlist_add_string(nvl, IPADM_NVP_REQHOST,
3398 ipaddr->ipadm_reqhost);
3399 status = ipadm_errno2status(err);
3400 break;
3401 case IPADM_ADDR_IPV6_ADDRCONF:
3402 status = i_ipadm_add_intfid2nvl(nvl, ipaddr);
3403 break;
3405 if (status != IPADM_SUCCESS)
3406 goto ret;
3408 if (iph->iph_flags & IPH_INIT) {
3410 * IPMGMT_INIT tells the ipmgmtd to set both IPMGMT_ACTIVE and
3411 * IPMGMT_PERSIST on the address object in its `aobjmap'.
3412 * For the callers ipadm_enable_if() and ipadm_enable_addr(),
3413 * IPADM_OPT_PERSIST is not set in their flags. They send
3414 * IPH_INIT in iph_flags, so that the address object will be
3415 * set as both IPMGMT_ACTIVE and IPMGMT_PERSIST.
3417 pflags |= IPMGMT_INIT;
3418 } else {
3419 if (flags & IPADM_OPT_ACTIVE)
3420 pflags |= IPMGMT_ACTIVE;
3421 if (flags & IPADM_OPT_PERSIST)
3422 pflags |= IPMGMT_PERSIST;
3423 if (flags & IPADM_OPT_SET_PROPS)
3424 pflags |= IPMGMT_PROPS_ONLY;
3426 status = i_ipadm_addr_persist_nvl(iph, nvl, pflags);
3428 if (flags & IPADM_OPT_SET_PROPS) {
3430 * Set PERSIST per IPADM_OPT_PROPS_PERSIST, and then un-set the
3431 * SET_PROPS bits.
3433 flags |= IPADM_OPT_ACTIVE;
3434 if (flags & IPADM_OPT_PERSIST_PROPS)
3435 flags |= IPADM_OPT_PERSIST;
3436 else
3437 flags &= ~IPADM_OPT_PERSIST;
3438 flags &= ~(IPADM_OPT_SET_PROPS | IPADM_OPT_PERSIST_PROPS);
3441 if (status == IPADM_SUCCESS && (flags & IPADM_OPT_PERSIST)) {
3442 char pbuf[MAXPROPVALLEN], *pval = NULL;
3443 ipadm_prop_desc_t *pdp = NULL;
3446 * addprop properties are stored on separate lines in the DB and
3447 * not along with the address itself. Call the function that
3448 * persists address properties.
3451 switch (ipaddr->ipadm_atype) {
3452 case IPADM_ADDR_STATIC:
3453 if (!default_prefixlen && (propname == NULL ||
3454 strcmp(propname, IPADM_NVP_PREFIXLEN) == 0)) {
3455 pdp = i_ipadm_get_addrprop_desc(
3456 IPADM_NVP_PREFIXLEN);
3457 (void) snprintf(pbuf, sizeof (pbuf), "%u",
3458 ipaddr->ipadm_static_prefixlen);
3459 pval = pbuf;
3461 break;
3462 case IPADM_ADDR_DHCP:
3463 if (propname == NULL ||
3464 strcmp(propname, IPADM_NVP_REQHOST) == 0) {
3465 pdp = i_ipadm_get_addrprop_desc(
3466 IPADM_NVP_REQHOST);
3467 pval = ipaddr->ipadm_reqhost;
3469 break;
3470 default:
3471 break;
3474 if (pval != NULL) {
3475 assert(pdp != NULL);
3476 status = i_ipadm_persist_propval(iph, pdp, pval,
3477 ipaddr, flags);
3481 ret:
3482 nvlist_free(nvl);
3483 return (status);
3487 * Makes the door call to ipmgmtd to store the address object in the
3488 * nvlist `nvl'.
3490 static ipadm_status_t
3491 i_ipadm_addr_persist_nvl(ipadm_handle_t iph, nvlist_t *nvl, uint32_t flags)
3493 char *buf = NULL, *nvlbuf = NULL;
3494 size_t nvlsize, bufsize;
3495 ipmgmt_setaddr_arg_t *sargp;
3496 int err;
3498 err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
3499 if (err != 0)
3500 return (ipadm_errno2status(err));
3501 bufsize = sizeof (*sargp) + nvlsize;
3502 buf = calloc(1, bufsize);
3503 sargp = (void *)buf;
3504 sargp->ia_cmd = IPMGMT_CMD_SETADDR;
3505 sargp->ia_flags = flags;
3506 sargp->ia_nvlsize = nvlsize;
3507 (void) bcopy(nvlbuf, buf + sizeof (*sargp), nvlsize);
3508 err = ipadm_door_call(iph, buf, bufsize, NULL, 0, B_FALSE);
3509 free(buf);
3510 free(nvlbuf);
3511 return (ipadm_errno2status(err));
3515 * Makes a door call to ipmgmtd to remove the address object in `ipaddr'
3516 * from its `aobjmap'. This door call also removes the address object and all
3517 * its properties from the persistent DB if IPADM_OPT_PERSIST is set in
3518 * `flags', so that the object will not be recreated on next reboot or on an
3519 * ipadm_enable_addr()/ipadm_enable_if() call.
3521 ipadm_status_t
3522 i_ipadm_delete_addrobj(ipadm_handle_t iph, const ipadm_addrobj_t ipaddr,
3523 uint32_t flags)
3525 ipmgmt_addr_arg_t arg;
3526 int err;
3528 arg.ia_cmd = IPMGMT_CMD_RESETADDR;
3529 arg.ia_flags = 0;
3530 if (flags & IPADM_OPT_ACTIVE)
3531 arg.ia_flags |= IPMGMT_ACTIVE;
3532 if (flags & IPADM_OPT_PERSIST)
3533 arg.ia_flags |= IPMGMT_PERSIST;
3534 (void) strlcpy(arg.ia_aobjname, ipaddr->ipadm_aobjname,
3535 sizeof (arg.ia_aobjname));
3536 arg.ia_lnum = ipaddr->ipadm_lifnum;
3537 err = ipadm_door_call(iph, &arg, sizeof (arg), NULL, 0, B_FALSE);
3538 return (ipadm_errno2status(err));
3542 * Checks if the caller is authorized for the up/down operation.
3543 * Retrieves the address object corresponding to `aobjname' from ipmgmtd
3544 * and retrieves the address flags for that object from kernel.
3545 * The arguments `ipaddr' and `ifflags' must be allocated by the caller.
3547 static ipadm_status_t
3548 i_ipadm_updown_common(ipadm_handle_t iph, const char *aobjname,
3549 ipadm_addrobj_t ipaddr, uint32_t ipadm_flags, uint64_t *ifflags)
3551 ipadm_status_t status;
3552 char lifname[LIFNAMSIZ];
3554 /* check for solaris.network.interface.config authorization */
3555 if (!ipadm_check_auth())
3556 return (IPADM_EAUTH);
3558 /* validate input */
3559 if (aobjname == NULL || strlcpy(ipaddr->ipadm_aobjname, aobjname,
3560 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3561 return (IPADM_INVALID_ARG);
3564 /* Retrieve the address object information. */
3565 status = i_ipadm_get_addrobj(iph, ipaddr);
3566 if (status != IPADM_SUCCESS)
3567 return (status);
3569 if (!(ipaddr->ipadm_flags & IPMGMT_ACTIVE))
3570 return (IPADM_OP_DISABLE_OBJ);
3571 if ((ipadm_flags & IPADM_OPT_PERSIST) &&
3572 !(ipaddr->ipadm_flags & IPMGMT_PERSIST))
3573 return (IPADM_TEMPORARY_OBJ);
3574 if (ipaddr->ipadm_atype == IPADM_ADDR_IPV6_ADDRCONF ||
3575 (ipaddr->ipadm_atype == IPADM_ADDR_DHCP &&
3576 (ipadm_flags & IPADM_OPT_PERSIST)))
3577 return (IPADM_NOTSUP);
3579 i_ipadm_addrobj2lifname(ipaddr, lifname, sizeof (lifname));
3580 return (i_ipadm_get_flags(iph, lifname, ipaddr->ipadm_af, ifflags));
3584 * Marks the address in the address object `aobjname' up. This operation is
3585 * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3586 * For an address object of type IPADM_ADDR_DHCP, this operation can
3587 * only be temporary and no updates will be made to the persistent DB.
3589 ipadm_status_t
3590 ipadm_up_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3592 struct ipadm_addrobj_s ipaddr;
3593 ipadm_status_t status;
3594 uint64_t flags;
3595 char lifname[LIFNAMSIZ];
3597 status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3598 &flags);
3599 if (status != IPADM_SUCCESS)
3600 return (status);
3601 if (flags & IFF_UP)
3602 goto persist;
3604 * If the address is already a duplicate, then refresh-addr
3605 * should be used to mark it up.
3607 if (flags & IFF_DUPLICATE)
3608 return (IPADM_DAD_FOUND);
3610 i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3611 status = i_ipadm_set_flags(iph, lifname, ipaddr.ipadm_af, IFF_UP, 0);
3612 if (status != IPADM_SUCCESS)
3613 return (status);
3615 persist:
3616 /* Update persistent DB. */
3617 if (ipadm_flags & IPADM_OPT_PERSIST) {
3618 status = i_ipadm_persist_propval(iph, &up_addrprop,
3619 "yes", &ipaddr, 0);
3622 return (status);
3626 * Marks the address in the address object `aobjname' down. This operation is
3627 * not supported for an address object of type IPADM_ADDR_IPV6_ADDRCONF.
3628 * For an address object of type IPADM_ADDR_DHCP, this operation can
3629 * only be temporary and no updates will be made to the persistent DB.
3631 ipadm_status_t
3632 ipadm_down_addr(ipadm_handle_t iph, const char *aobjname, uint32_t ipadm_flags)
3634 struct ipadm_addrobj_s ipaddr;
3635 ipadm_status_t status;
3636 struct lifreq lifr;
3637 uint64_t flags;
3639 status = i_ipadm_updown_common(iph, aobjname, &ipaddr, ipadm_flags,
3640 &flags);
3641 if (status != IPADM_SUCCESS)
3642 return (status);
3643 i_ipadm_addrobj2lifname(&ipaddr, lifr.lifr_name,
3644 sizeof (lifr.lifr_name));
3645 if (flags & IFF_UP) {
3646 status = i_ipadm_set_flags(iph, lifr.lifr_name,
3647 ipaddr.ipadm_af, 0, IFF_UP);
3648 if (status != IPADM_SUCCESS)
3649 return (status);
3650 } else if (flags & IFF_DUPLICATE) {
3652 * Clear the IFF_DUPLICATE flag.
3654 if (ioctl(iph->iph_sock, SIOCGLIFADDR, &lifr) < 0)
3655 return (ipadm_errno2status(errno));
3656 if (ioctl(iph->iph_sock, SIOCSLIFADDR, &lifr) < 0)
3657 return (ipadm_errno2status(errno));
3660 /* Update persistent DB */
3661 if (ipadm_flags & IPADM_OPT_PERSIST) {
3662 status = i_ipadm_persist_propval(iph, &up_addrprop,
3663 "no", &ipaddr, 0);
3666 return (status);
3670 * Refreshes the address in the address object `aobjname'. If the address object
3671 * is of type IPADM_ADDR_STATIC, DAD is re-initiated on the address. If
3672 * `ipadm_flags' has IPADM_OPT_INFORM set, a DHCP_INFORM message is sent to the
3673 * dhcpagent for this static address. If the address object is of type
3674 * IPADM_ADDR_DHCP, a DHCP_EXTEND message is sent to the dhcpagent.
3675 * If a dhcp address has not yet been acquired, a DHCP_START is sent to the
3676 * dhcpagent. This operation is not supported for an address object of
3677 * type IPADM_ADDR_IPV6_ADDRCONF.
3679 ipadm_status_t
3680 ipadm_refresh_addr(ipadm_handle_t iph, const char *aobjname,
3681 uint32_t ipadm_flags)
3683 ipadm_status_t status = IPADM_SUCCESS;
3684 uint64_t flags;
3685 struct ipadm_addrobj_s ipaddr;
3686 sa_family_t af;
3687 char lifname[LIFNAMSIZ];
3688 boolean_t inform =
3689 ((ipadm_flags & IPADM_OPT_INFORM) != 0);
3691 /* check for solaris.network.interface.config authorization */
3692 if (!ipadm_check_auth())
3693 return (IPADM_EAUTH);
3695 bzero(&ipaddr, sizeof (ipaddr));
3696 /* validate input */
3697 if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3698 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3699 return (IPADM_INVALID_ARG);
3702 /* Retrieve the address object information. */
3703 status = i_ipadm_get_addrobj(iph, &ipaddr);
3704 if (status != IPADM_SUCCESS)
3705 return (status);
3707 if (!(ipaddr.ipadm_flags & IPMGMT_ACTIVE))
3708 return (IPADM_OP_DISABLE_OBJ);
3710 if (i_ipadm_is_vni(ipaddr.ipadm_ifname))
3711 return (IPADM_NOTSUP);
3712 if (inform && ipaddr.ipadm_atype != IPADM_ADDR_STATIC)
3713 return (IPADM_INVALID_ARG);
3714 af = ipaddr.ipadm_af;
3715 if (ipaddr.ipadm_atype == IPADM_ADDR_STATIC) {
3716 i_ipadm_addrobj2lifname(&ipaddr, lifname, sizeof (lifname));
3717 status = i_ipadm_get_flags(iph, lifname, af, &flags);
3718 if (status != IPADM_SUCCESS)
3719 return (status);
3720 if (inform) {
3721 if (dhcp_start_agent(DHCP_IPC_MAX_WAIT) == -1)
3722 return (IPADM_DHCP_START_ERROR);
3724 ipaddr.ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3725 return (i_ipadm_op_dhcp(&ipaddr, DHCP_INFORM, NULL));
3727 if (!(flags & IFF_DUPLICATE))
3728 return (IPADM_SUCCESS);
3729 status = i_ipadm_set_flags(iph, lifname, af, IFF_UP, 0);
3730 } else if (ipaddr.ipadm_atype == IPADM_ADDR_DHCP) {
3731 status = i_ipadm_refresh_dhcp(&ipaddr);
3732 } else {
3733 status = IPADM_NOTSUP;
3735 return (status);
3739 * This is called from ipadm_refresh_addr() and i_ipadm_set_reqhost() to
3740 * send a DHCP_EXTEND message and possibly a DHCP_START message
3741 * to the dhcpagent.
3743 static ipadm_status_t
3744 i_ipadm_refresh_dhcp(ipadm_addrobj_t ipaddr)
3746 ipadm_status_t status;
3747 int dherr;
3749 status = i_ipadm_op_dhcp(ipaddr, DHCP_EXTEND, &dherr);
3751 * Restart the dhcp address negotiation with server if no
3752 * address has been acquired yet.
3754 if (status != IPADM_SUCCESS && dherr == DHCP_IPC_E_OUTSTATE) {
3755 ipaddr->ipadm_wait = IPADM_DHCP_WAIT_DEFAULT;
3756 status = i_ipadm_op_dhcp(ipaddr, DHCP_START, NULL);
3759 return (status);
3763 * This is called from ipadm_create_addr() to validate the address parameters.
3764 * It does the following steps:
3765 * 1. Validates the interface name.
3766 * 2. Verifies that the interface is not an IPMP meta-interface or an
3767 * underlying interface.
3768 * 3. In case of a persistent operation, verifies that the interface
3769 * is persistent. Returns error if interface is not enabled but
3770 * is in persistent config.
3771 * 4. Verifies that the destination address is not set or the address type is
3772 * not DHCP or ADDRCONF when the interface is a loopback interface.
3773 * 5. Verifies that the address type is not DHCP or ADDRCONF when the interface
3774 * has IFF_VRRP interface flag set.
3776 static ipadm_status_t
3777 i_ipadm_validate_create_addr(ipadm_handle_t iph, ipadm_addrobj_t ipaddr,
3778 uint32_t flags)
3780 sa_family_t af;
3781 sa_family_t other_af;
3782 char *ifname;
3783 ipadm_status_t status;
3784 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
3785 boolean_t islo, isvni;
3786 uint64_t ifflags = 0;
3787 boolean_t p_exists;
3788 boolean_t af_exists, other_af_exists, a_exists;
3790 if (ipaddr == NULL || flags == 0 || flags == IPADM_OPT_PERSIST ||
3791 (flags & ~(IPADM_COMMON_OPT_MASK|IPADM_OPT_UP|IPADM_OPT_V46))) {
3792 return (IPADM_INVALID_ARG);
3795 if (ipaddr->ipadm_af == AF_UNSPEC)
3796 return (IPADM_BAD_ADDR);
3798 if (!legacy && ipaddr->ipadm_lifnum != 0)
3799 return (IPADM_INVALID_ARG);
3801 if (legacy && ipaddr->ipadm_atype != IPADM_ADDR_STATIC)
3802 return (IPADM_NOTSUP);
3804 ifname = ipaddr->ipadm_ifname;
3806 if (i_ipadm_is_ipmp(iph, ifname) || i_ipadm_is_under_ipmp(iph, ifname))
3807 return (IPADM_NOTSUP);
3809 af = ipaddr->ipadm_af;
3810 af_exists = ipadm_if_enabled(iph, ifname, af);
3812 * For legacy case, interfaces are not implicitly plumbed. We need to
3813 * check if the interface exists in the active configuration.
3815 if (legacy && !af_exists)
3816 return (IPADM_ENXIO);
3818 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
3819 other_af_exists = ipadm_if_enabled(iph, ifname, other_af);
3821 * Check if one of the v4 or the v6 interfaces exists in the
3822 * active configuration. An interface is considered disabled only
3823 * if both v4 and v6 are not active.
3825 a_exists = (af_exists || other_af_exists);
3827 /* Check if interface exists in the persistent configuration. */
3828 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
3829 if (status != IPADM_SUCCESS)
3830 return (status);
3831 if (!a_exists && p_exists)
3832 return (IPADM_OP_DISABLE_OBJ);
3833 if ((flags & IPADM_OPT_PERSIST) && a_exists && !p_exists) {
3835 * If address has to be created persistently,
3836 * and the interface does not exist in the persistent
3837 * store but in active config, fail.
3839 return (IPADM_TEMPORARY_OBJ);
3841 if (af_exists) {
3842 status = i_ipadm_get_flags(iph, ifname, af, &ifflags);
3843 if (status != IPADM_SUCCESS)
3844 return (status);
3847 /* Perform validation steps (4) and (5) */
3848 islo = i_ipadm_is_loopback(ifname);
3849 isvni = i_ipadm_is_vni(ifname);
3850 switch (ipaddr->ipadm_atype) {
3851 case IPADM_ADDR_STATIC:
3852 if ((islo || isvni) && ipaddr->ipadm_static_dname[0] != '\0')
3853 return (IPADM_INVALID_ARG);
3854 /* Check for a valid src address */
3855 if (!legacy && sockaddrunspec(
3856 (struct sockaddr *)&ipaddr->ipadm_static_addr))
3857 return (IPADM_BAD_ADDR);
3858 break;
3859 case IPADM_ADDR_DHCP:
3860 if (islo || (ifflags & IFF_VRRP))
3861 return (IPADM_NOTSUP);
3862 break;
3863 case IPADM_ADDR_IPV6_ADDRCONF:
3864 if (islo || (ifflags & IFF_VRRP) ||
3865 i_ipadm_is_6to4(iph, ifname)) {
3866 return (IPADM_NOTSUP);
3868 break;
3869 default:
3870 return (IPADM_INVALID_ARG);
3873 return (IPADM_SUCCESS);
3876 ipadm_status_t
3877 i_ipadm_merge_addrprops_from_nvl(nvlist_t *invl, nvlist_t *onvl,
3878 const char *aobjname)
3880 const char * const ADDRPROPS[] =
3881 { IPADM_NVP_PREFIXLEN, IPADM_NVP_REQHOST };
3882 const size_t ADDRPROPSLEN =
3883 sizeof (ADDRPROPS) / sizeof (*ADDRPROPS);
3884 nvpair_t *nvp, *propnvp;
3885 nvlist_t *tnvl;
3886 char *aname;
3887 const char *propname;
3888 size_t i;
3889 int err;
3891 for (i = 0; i < ADDRPROPSLEN; ++i) {
3892 propname = ADDRPROPS[i];
3894 for (nvp = nvlist_next_nvpair(invl, NULL); nvp != NULL;
3895 nvp = nvlist_next_nvpair(invl, nvp)) {
3896 if (nvpair_value_nvlist(nvp, &tnvl) == 0 &&
3897 nvlist_exists(tnvl, propname) &&
3898 nvlist_lookup_string(tnvl, IPADM_NVP_AOBJNAME,
3899 &aname) == 0 && strcmp(aname, aobjname) == 0) {
3902 * property named `propname' exists for given
3903 * aobj
3905 (void) nvlist_lookup_nvpair(tnvl, propname,
3906 &propnvp);
3907 err = nvlist_add_nvpair(onvl, propnvp);
3908 if (err == 0) {
3909 err = nvlist_remove(invl,
3910 nvpair_name(nvp), nvpair_type(nvp));
3912 if (err != 0)
3913 return (ipadm_errno2status(err));
3914 break;
3918 return (IPADM_SUCCESS);
3922 * Re-enables the address object `aobjname' based on the saved
3923 * configuration for `aobjname'.
3925 ipadm_status_t
3926 ipadm_enable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
3928 nvlist_t *addrnvl, *nvl;
3929 nvpair_t *nvp;
3930 ipadm_status_t status;
3931 struct ipadm_addrobj_s ipaddr;
3933 /* check for solaris.network.interface.config authorization */
3934 if (!ipadm_check_auth())
3935 return (IPADM_EAUTH);
3937 /* validate input */
3938 if (flags & IPADM_OPT_PERSIST)
3939 return (IPADM_NOTSUP);
3940 if (aobjname == NULL || strlcpy(ipaddr.ipadm_aobjname, aobjname,
3941 IPADM_AOBJSIZ) >= IPADM_AOBJSIZ) {
3942 return (IPADM_INVALID_ARG);
3945 /* Retrieve the address object information. */
3946 status = i_ipadm_get_addrobj(iph, &ipaddr);
3947 if (status != IPADM_SUCCESS)
3948 return (status);
3949 if (ipaddr.ipadm_flags & IPMGMT_ACTIVE)
3950 return (IPADM_ADDROBJ_EXISTS);
3952 status = i_ipadm_get_db_addr(iph, NULL, aobjname, &addrnvl);
3953 if (status != IPADM_SUCCESS)
3954 return (status);
3956 assert(addrnvl != NULL);
3958 for (nvp = nvlist_next_nvpair(addrnvl, NULL); nvp != NULL;
3959 nvp = nvlist_next_nvpair(addrnvl, nvp)) {
3960 if (nvpair_value_nvlist(nvp, &nvl) != 0)
3961 continue;
3963 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
3964 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR) ||
3965 nvlist_exists(nvl, IPADM_NVP_DHCP)) {
3966 status = i_ipadm_merge_addrprops_from_nvl(addrnvl, nvl,
3967 aobjname);
3968 if (status != IPADM_SUCCESS)
3969 continue;
3971 iph->iph_flags |= IPH_INIT;
3972 status = i_ipadm_init_addrobj(iph, nvl);
3973 iph->iph_flags &= ~IPH_INIT;
3974 if (status != IPADM_SUCCESS)
3975 break;
3978 nvlist_free(addrnvl);
3979 return (status);
3983 * Disables the address object in `aobjname' from the active configuration.
3984 * Error code return values follow the model in ipadm_delete_addr().
3986 ipadm_status_t
3987 ipadm_disable_addr(ipadm_handle_t iph, const char *aobjname, uint32_t flags)
3989 /* validate input */
3990 if (flags & IPADM_OPT_PERSIST)
3991 return (IPADM_NOTSUP);
3993 return (ipadm_delete_addr(iph, aobjname, IPADM_OPT_ACTIVE));