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