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