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