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