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