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