1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <stropts.h>
33 #include <sys/sockio.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/socket.h>
37 #include <net/route.h>
38 #include <netinet/in.h>
39 #include <inet/ip.h>
40 #include <arpa/inet.h>
41 #include <libintl.h>
42 #include <libdlpi.h>
43 #include <libinetutil.h>
44 #include <libdladm.h>
45 #include <libdllink.h>
46 #include <libdliptun.h>
47 #include <strings.h>
48 #include <zone.h>
49 #include <ctype.h>
50 #include <limits.h>
51 #include <assert.h>
52 #include <netdb.h>
53 #include <pwd.h>
54 #include <auth_attr.h>
55 #include <secdb.h>
56 #include <nss_dbdefs.h>
57 #include "libipadm_impl.h"
58
59 /* error codes and text description */
60 static struct ipadm_error_info {
61 ipadm_status_t error_code;
62 const char *error_desc;
63 } ipadm_errors[] = {
64 { IPADM_SUCCESS, "Operation succeeded" },
65 { IPADM_FAILURE, "Operation failed" },
66 { IPADM_EAUTH, "Insufficient user authorizations" },
67 { IPADM_EPERM, "Permission denied" },
68 { IPADM_NO_BUFS, "No buffer space available" },
69 { IPADM_NO_MEMORY, "Insufficient memory" },
70 { IPADM_BAD_ADDR, "Invalid address" },
71 { IPADM_BAD_PROTOCOL, "Incorrect protocol family for operation" },
72 { IPADM_DAD_FOUND, "Duplicate address detected" },
73 { IPADM_EXISTS, "Already exists" },
74 { IPADM_IF_EXISTS, "Interface already exists" },
75 { IPADM_ADDROBJ_EXISTS, "Address object already exists" },
76 { IPADM_ADDRCONF_EXISTS, "Addrconf already in progress" },
77 { IPADM_ENXIO, "Interface does not exist" },
78 { IPADM_GRP_NOTEMPTY, "IPMP group is not empty" },
79 { IPADM_INVALID_ARG, "Invalid argument provided" },
80 { IPADM_INVALID_NAME, "Invalid name" },
81 { IPADM_DLPI_FAILURE, "Could not open DLPI link" },
82 { IPADM_DLADM_FAILURE, "Datalink does not exist" },
83 { IPADM_PROP_UNKNOWN, "Unknown property" },
84 { IPADM_ERANGE, "Value is outside the allowed range" },
85 { IPADM_ESRCH, "Value does not exist" },
86 { IPADM_EOVERFLOW, "Number of values exceeds the allowed limit" },
87 { IPADM_NOTFOUND, "Object not found" },
88 { IPADM_IF_INUSE, "Interface already in use" },
89 { IPADM_ADDR_INUSE, "Address already in use" },
90 { IPADM_BAD_HOSTNAME, "Hostname maps to multiple IP addresses" },
91 { IPADM_ADDR_NOTAVAIL, "Can't assign requested address" },
92 { IPADM_ALL_ADDRS_NOT_ENABLED, "All addresses could not be enabled" },
93 { IPADM_NDPD_NOT_RUNNING, "IPv6 autoconf daemon in.ndpd not running" },
94 { IPADM_DHCP_START_ERROR, "Could not start dhcpagent" },
95 { IPADM_DHCP_IPC_ERROR, "Could not communicate with dhcpagent" },
96 { IPADM_DHCP_IPC_TIMEOUT, "Communication with dhcpagent timed out" },
97 { IPADM_TEMPORARY_OBJ, "Persistent operation on temporary object" },
98 { IPADM_IPC_ERROR, "Could not communicate with ipmgmtd" },
99 { IPADM_NOTSUP, "Operation not supported" },
100 { IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" },
101 { IPADM_EBADE, "Invalid data exchange with daemon" },
102 { IPADM_GZ_PERM, "Operation not permitted on from-gz interface"}
103 };
104
105 #define IPADM_NUM_ERRORS (sizeof (ipadm_errors) / sizeof (*ipadm_errors))
106
107 ipadm_status_t
108 ipadm_errno2status(int error)
109 {
110 switch (error) {
111 case 0:
112 return (IPADM_SUCCESS);
113 case ENXIO:
114 return (IPADM_ENXIO);
115 case ENOMEM:
116 return (IPADM_NO_MEMORY);
117 case ENOBUFS:
118 return (IPADM_NO_BUFS);
119 case EINVAL:
120 return (IPADM_INVALID_ARG);
121 case EBUSY:
122 return (IPADM_IF_INUSE);
123 case EEXIST:
124 return (IPADM_EXISTS);
125 case EADDRNOTAVAIL:
126 return (IPADM_ADDR_NOTAVAIL);
127 case EADDRINUSE:
128 return (IPADM_ADDR_INUSE);
129 case ENOENT:
130 return (IPADM_NOTFOUND);
131 case ERANGE:
132 return (IPADM_ERANGE);
133 case EPERM:
134 return (IPADM_EPERM);
135 case ENOTSUP:
136 case EOPNOTSUPP:
137 return (IPADM_NOTSUP);
138 case EBADF:
139 return (IPADM_IPC_ERROR);
140 case EBADE:
141 return (IPADM_EBADE);
142 case ESRCH:
143 return (IPADM_ESRCH);
144 case EOVERFLOW:
145 return (IPADM_EOVERFLOW);
146 default:
147 return (IPADM_FAILURE);
148 }
149 }
150
151 /*
152 * Returns a message string for the given libipadm error status.
153 */
154 const char *
155 ipadm_status2str(ipadm_status_t status)
156 {
157 int i;
158
159 for (i = 0; i < IPADM_NUM_ERRORS; i++) {
160 if (status == ipadm_errors[i].error_code)
161 return (dgettext(TEXT_DOMAIN,
162 ipadm_errors[i].error_desc));
163 }
164
165 return (dgettext(TEXT_DOMAIN, "<unknown error>"));
166 }
167
168 /*
169 * Opens a handle to libipadm.
170 * Possible values for flags:
171 * IPH_VRRP: Used by VRRP daemon to set the socket option SO_VRRP.
172 * IPH_LEGACY: This is used whenever an application needs to provide a
173 * logical interface name while creating or deleting
174 * interfaces and static addresses.
175 * IPH_INIT: Used by ipadm_init_prop(), to initialize protocol properties
176 * on reboot.
177 */
178 ipadm_status_t
179 ipadm_open(ipadm_handle_t *handle, uint32_t flags)
180 {
181 ipadm_handle_t iph;
182 ipadm_status_t status = IPADM_SUCCESS;
183 zoneid_t zoneid;
184 ushort_t zflags;
185 int on = B_TRUE;
186
187 if (handle == NULL)
188 return (IPADM_INVALID_ARG);
189 *handle = NULL;
190
191 if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT|IPH_IPMGMTD))
192 return (IPADM_INVALID_ARG);
193
194 if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL)
195 return (IPADM_NO_MEMORY);
196 iph->iph_sock = -1;
197 iph->iph_sock6 = -1;
198 iph->iph_door_fd = -1;
199 iph->iph_rtsock = -1;
200 iph->iph_flags = flags;
201 (void) pthread_mutex_init(&iph->iph_lock, NULL);
202
203 if ((iph->iph_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
204 (iph->iph_sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
205 goto errnofail;
206 }
207
208 /*
209 * We open a handle to libdladm here, to facilitate some daemons (like
210 * nwamd) which opens handle to libipadm before devfsadmd installs the
211 * right device permissions into the kernel and requires "all"
212 * privileges to open DLD_CONTROL_DEV.
213 *
214 * In a non-global shared-ip zone there will be no DLD_CONTROL_DEV node
215 * and dladm_open() will fail. So, we avoid this by not calling
216 * dladm_open() for such zones.
217 */
218 zoneid = getzoneid();
219 iph->iph_zoneid = zoneid;
220 if (zoneid != GLOBAL_ZONEID) {
221 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags,
222 sizeof (zflags)) < 0) {
223 goto errnofail;
224 }
225 }
226 if ((zoneid == GLOBAL_ZONEID) || (zflags & ZF_NET_EXCL)) {
227 if (dladm_open(&iph->iph_dlh) != DLADM_STATUS_OK) {
228 ipadm_close(iph);
229 return (IPADM_DLADM_FAILURE);
230 }
231 if (zoneid != GLOBAL_ZONEID) {
232 iph->iph_rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
233 /*
234 * Failure to open rtsock is ignored as this is
235 * only used in non-global zones to initialize
236 * routing socket information.
237 */
238 }
239 } else {
240 assert(zoneid != GLOBAL_ZONEID);
241 iph->iph_dlh = NULL;
242 }
243 if (flags & IPH_VRRP) {
244 if (setsockopt(iph->iph_sock6, SOL_SOCKET, SO_VRRP, &on,
245 sizeof (on)) < 0 || setsockopt(iph->iph_sock, SOL_SOCKET,
246 SO_VRRP, &on, sizeof (on)) < 0) {
247 goto errnofail;
248 }
249 }
250 *handle = iph;
251 return (status);
252
253 errnofail:
254 status = ipadm_errno2status(errno);
255 ipadm_close(iph);
256 return (status);
257 }
258
259 /*
260 * Closes and frees the libipadm handle.
261 */
262 void
263 ipadm_close(ipadm_handle_t iph)
264 {
265 if (iph == NULL)
266 return;
267 if (iph->iph_sock != -1)
268 (void) close(iph->iph_sock);
269 if (iph->iph_sock6 != -1)
270 (void) close(iph->iph_sock6);
271 if (iph->iph_rtsock != -1)
272 (void) close(iph->iph_rtsock);
273 if (iph->iph_door_fd != -1)
274 (void) close(iph->iph_door_fd);
275 dladm_close(iph->iph_dlh);
276 (void) pthread_mutex_destroy(&iph->iph_lock);
277 free(iph);
278 }
279
280 /*
281 * Checks if the caller has the authorization to configure network
282 * interfaces.
283 */
284 boolean_t
285 ipadm_check_auth(void)
286 {
287 struct passwd pwd;
288 char buf[NSS_BUFLEN_PASSWD];
289
290 /* get the password entry for the given user ID */
291 if (getpwuid_r(getuid(), &pwd, buf, sizeof (buf)) == NULL)
292 return (B_FALSE);
293
294 /* check for presence of given authorization */
295 return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 0);
296 }
297
298 /*
299 * Stores the index value of the interface in `ifname' for the address
300 * family `af' into the buffer pointed to by `index'.
301 */
302 static ipadm_status_t
303 i_ipadm_get_index(ipadm_handle_t iph, const char *ifname, sa_family_t af,
304 int *index)
305 {
306 struct lifreq lifr;
307 int sock;
308
309 bzero(&lifr, sizeof (lifr));
310 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
311 if (af == AF_INET)
312 sock = iph->iph_sock;
313 else
314 sock = iph->iph_sock6;
315
316 if (ioctl(sock, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
317 return (ipadm_errno2status(errno));
318 *index = lifr.lifr_index;
319
320 return (IPADM_SUCCESS);
321 }
322
323 /*
324 * Maximum amount of time (in milliseconds) to wait for Duplicate Address
325 * Detection to complete in the kernel.
326 */
327 #define DAD_WAIT_TIME 1000
328
329 /*
330 * Any time that flags are changed on an interface where either the new or the
331 * existing flags have IFF_UP set, we'll get a RTM_NEWADDR message to
332 * announce the new address added and its flag status.
333 * We wait here for that message and look for IFF_UP.
334 * If something's amiss with the kernel, though, we don't wait forever.
335 * (Note that IFF_DUPLICATE is a high-order bit, and we cannot see
336 * it in the routing socket messages.)
337 */
338 static ipadm_status_t
339 i_ipadm_dad_wait(ipadm_handle_t handle, const char *lifname, sa_family_t af,
340 int rtsock)
341 {
342 struct pollfd fds[1];
343 union {
344 struct if_msghdr ifm;
345 char buf[1024];
346 } msg;
347 int index;
348 ipadm_status_t retv;
349 uint64_t flags;
350 hrtime_t starttime, now;
351
352 fds[0].fd = rtsock;
353 fds[0].events = POLLIN;
354 fds[0].revents = 0;
355
356 retv = i_ipadm_get_index(handle, lifname, af, &index);
357 if (retv != IPADM_SUCCESS)
358 return (retv);
359
360 starttime = gethrtime();
361 for (;;) {
362 now = gethrtime();
363 now = (now - starttime) / 1000000;
364 if (now >= DAD_WAIT_TIME)
365 break;
366 if (poll(fds, 1, DAD_WAIT_TIME - (int)now) <= 0)
367 break;
368 if (read(rtsock, &msg, sizeof (msg)) <= 0)
369 break;
370 if (msg.ifm.ifm_type != RTM_NEWADDR)
371 continue;
372 /* Note that ifm_index is just 16 bits */
373 if (index == msg.ifm.ifm_index && (msg.ifm.ifm_flags & IFF_UP))
374 return (IPADM_SUCCESS);
375 }
376
377 retv = i_ipadm_get_flags(handle, lifname, af, &flags);
378 if (retv != IPADM_SUCCESS)
379 return (retv);
380 if (flags & IFF_DUPLICATE)
381 return (IPADM_DAD_FOUND);
382
383 return (IPADM_SUCCESS);
384 }
385
386 /*
387 * Sets the flags `on_flags' and resets the flags `off_flags' for the logical
388 * interface in `lifname'.
389 *
390 * If the new flags value will transition the interface from "down" to "up"
391 * then duplicate address detection is performed by the kernel. This routine
392 * waits to get the outcome of that test.
393 */
394 ipadm_status_t
395 i_ipadm_set_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
396 uint64_t on_flags, uint64_t off_flags)
397 {
398 struct lifreq lifr;
399 uint64_t oflags;
400 ipadm_status_t ret;
401 int rtsock = -1;
402 int sock, err;
403
404 ret = i_ipadm_get_flags(iph, lifname, af, &oflags);
405 if (ret != IPADM_SUCCESS)
406 return (ret);
407
408 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
409
410 /*
411 * Any time flags are changed on an interface that has IFF_UP set,
412 * we get a routing socket message. We care about the status,
413 * though, only when the new flags are marked "up."
414 */
415 if (!(oflags & IFF_UP) && (on_flags & IFF_UP))
416 rtsock = socket(PF_ROUTE, SOCK_RAW, af);
417
418 oflags |= on_flags;
419 oflags &= ~off_flags;
420 bzero(&lifr, sizeof (lifr));
421 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
422 lifr.lifr_flags = oflags;
423 if (ioctl(sock, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
424 err = errno;
425 if (rtsock != -1)
426 (void) close(rtsock);
427 return (ipadm_errno2status(err));
428 }
429 if (rtsock == -1) {
430 return (IPADM_SUCCESS);
431 } else {
432 /* Wait for DAD to complete. */
433 ret = i_ipadm_dad_wait(iph, lifname, af, rtsock);
434 (void) close(rtsock);
435 return (ret);
436 }
437 }
438
439 /*
440 * Returns the flags value for the logical interface in `lifname'
441 * in the buffer pointed to by `flags'.
442 */
443 ipadm_status_t
444 i_ipadm_get_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
445 uint64_t *flags)
446 {
447 struct lifreq lifr;
448 int sock;
449
450 bzero(&lifr, sizeof (lifr));
451 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
452 if (af == AF_INET)
453 sock = iph->iph_sock;
454 else
455 sock = iph->iph_sock6;
456
457 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
458 return (ipadm_errno2status(errno));
459 }
460 *flags = lifr.lifr_flags;
461
462 return (IPADM_SUCCESS);
463 }
464
465 /*
466 * Determines whether or not an interface name represents a loopback
467 * interface, before the interface has been plumbed.
468 * It is assumed that the interface name in `ifname' is of correct format
469 * as verified by ifparse_ifspec().
470 *
471 * Returns: B_TRUE if loopback, B_FALSE if not.
472 */
473 boolean_t
474 i_ipadm_is_loopback(const char *ifname)
475 {
476 int len = strlen(LOOPBACK_IF);
477
478 return (strncmp(ifname, LOOPBACK_IF, len) == 0 &&
479 (ifname[len] == '\0' || ifname[len] == IPADM_LOGICAL_SEP));
480 }
481
482 /*
483 * Determines whether or not an interface name represents a vni
484 * interface, before the interface has been plumbed.
485 * It is assumed that the interface name in `ifname' is of correct format
486 * as verified by ifparse_ifspec().
487 *
488 * Returns: B_TRUE if vni, B_FALSE if not.
489 */
490 boolean_t
491 i_ipadm_is_vni(const char *ifname)
492 {
493 ifspec_t ifsp;
494
495 return (ifparse_ifspec(ifname, &ifsp) &&
496 strcmp(ifsp.ifsp_devnm, "vni") == 0);
497 }
498
499 /*
500 * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel.
501 */
502 boolean_t
503 i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname)
504 {
505 dladm_status_t dlstatus;
506 datalink_class_t class;
507 iptun_params_t params;
508 datalink_id_t linkid;
509
510 if (iph->iph_dlh == NULL) {
511 assert(iph->iph_zoneid != GLOBAL_ZONEID);
512 return (B_FALSE);
513 }
514 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
515 &class, NULL);
516 if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
517 params.iptun_param_linkid = linkid;
518 dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms,
519 DLADM_OPT_ACTIVE);
520 if (dlstatus == DLADM_STATUS_OK &&
521 params.iptun_param_type == IPTUN_TYPE_6TO4) {
522 return (B_TRUE);
523 }
524 }
525 return (B_FALSE);
526 }
527
528 /*
529 * For a given interface name, ipadm_if_enabled() checks if v4
530 * or v6 or both IP interfaces exist in the active configuration.
531 */
532 boolean_t
533 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
534 {
535 struct lifreq lifr;
536 int s4 = iph->iph_sock;
537 int s6 = iph->iph_sock6;
538
539 bzero(&lifr, sizeof (lifr));
540 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
541 switch (af) {
542 case AF_INET:
543 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
544 return (B_TRUE);
545 break;
546 case AF_INET6:
547 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
548 return (B_TRUE);
549 break;
550 case AF_UNSPEC:
551 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0 ||
552 ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) {
553 return (B_TRUE);
554 }
555 }
556 return (B_FALSE);
557 }
558
559 /*
560 * Apply the interface property by retrieving information from nvl.
561 */
562 static ipadm_status_t
563 i_ipadm_init_ifprop(ipadm_handle_t iph, nvlist_t *nvl)
564 {
565 nvpair_t *nvp;
566 char *name, *pname = NULL;
567 char *protostr = NULL, *ifname = NULL, *pval = NULL;
568 uint_t proto;
569 int err = 0;
570
571 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
572 nvp = nvlist_next_nvpair(nvl, nvp)) {
573 name = nvpair_name(nvp);
574 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
575 if ((err = nvpair_value_string(nvp, &ifname)) != 0)
576 break;
577 } else if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
578 if ((err = nvpair_value_string(nvp, &protostr)) != 0)
579 break;
580 } else {
581 assert(!IPADM_PRIV_NVP(name));
582 pname = name;
583 if ((err = nvpair_value_string(nvp, &pval)) != 0)
584 break;
585 }
586 }
587 if (err != 0)
588 return (ipadm_errno2status(err));
589 proto = ipadm_str2proto(protostr);
590 return (ipadm_set_ifprop(iph, ifname, pname, pval, proto,
591 IPADM_OPT_ACTIVE));
592 }
593
594 /*
595 * Instantiate the address object or set the address object property by
596 * retrieving the configuration from the nvlist `nvl'.
597 */
598 ipadm_status_t
599 i_ipadm_init_addrobj(ipadm_handle_t iph, nvlist_t *nvl)
600 {
601 nvpair_t *nvp;
602 char *name;
603 char *aobjname = NULL, *pval = NULL, *ifname = NULL;
604 sa_family_t af = AF_UNSPEC;
605 ipadm_addr_type_t atype = IPADM_ADDR_NONE;
606 int err = 0;
607 ipadm_status_t status = IPADM_SUCCESS;
608
609 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
610 nvp = nvlist_next_nvpair(nvl, nvp)) {
611 name = nvpair_name(nvp);
612 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
613 if ((err = nvpair_value_string(nvp, &ifname)) != 0)
614 break;
615 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
616 if ((err = nvpair_value_string(nvp, &aobjname)) != 0)
617 break;
618 } else if (i_ipadm_name2atype(name, &af, &atype)) {
619 break;
620 } else {
621 assert(!IPADM_PRIV_NVP(name));
622 err = nvpair_value_string(nvp, &pval);
623 break;
624 }
625 }
626 if (err != 0)
627 return (ipadm_errno2status(err));
628
629 switch (atype) {
630 case IPADM_ADDR_STATIC:
631 status = i_ipadm_enable_static(iph, ifname, nvl, af);
632 break;
633 case IPADM_ADDR_DHCP:
634 status = i_ipadm_enable_dhcp(iph, ifname, nvl);
635 if (status == IPADM_DHCP_IPC_TIMEOUT)
636 status = IPADM_SUCCESS;
637 break;
638 case IPADM_ADDR_IPV6_ADDRCONF:
639 status = i_ipadm_enable_addrconf(iph, ifname, nvl);
640 break;
641 case IPADM_ADDR_NONE:
642 status = ipadm_set_addrprop(iph, name, pval, aobjname,
643 IPADM_OPT_ACTIVE);
644 break;
645 }
646
647 return (status);
648 }
649
650 /*
651 * Instantiate the interface object by retrieving the configuration from
652 * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
653 * (interface properties and address objects on that interface) for the
654 * given `ifname'.
655 */
656 ipadm_status_t
657 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
658 {
659 nvlist_t *nvl = NULL;
660 nvpair_t *nvp;
661 ipadm_status_t status;
662 ipadm_status_t ret_status = IPADM_SUCCESS;
663 char newifname[LIFNAMSIZ];
664 char *aobjstr;
665 char *ifclass_str, *gif_name;
666 uint16_t *families;
667 uint_t nelem = 0;
668 char **members;
669 uint32_t ipadm_flags;
670 boolean_t is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
671 boolean_t init_from_gz = B_FALSE;
672
673 (void) strlcpy(newifname, ifname, sizeof (newifname));
674 /*
675 * First plumb the given interface and then apply all the persistent
676 * interface properties and then instantiate any persistent addresses
677 * objects on that interface.
678 */
679 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
680 nvp = nvlist_next_nvpair(ifnvl, nvp)) {
681
682 if (nvpair_value_nvlist(nvp, &nvl) != 0)
683 continue;
684
685
686 if (nvlist_lookup_uint16_array(nvl, IPADM_NVP_FAMILIES,
687 &families, &nelem) == 0) {
688
689 ipadm_flags = IPADM_OPT_ACTIVE;
690
691 if (nvlist_lookup_string(nvl, IPADM_NVP_IFCLASS, &ifclass_str) == 0 &&
692 atoi(ifclass_str) == IPADM_IF_CLASS_IPMP)
693 ipadm_flags |= IPADM_OPT_IPMP;
694
695 while (nelem--) {
696 assert(families[nelem] == AF_INET ||
697 families[nelem] == AF_INET6);
698
699 status = i_ipadm_plumb_if(iph, newifname, families[nelem],
700 ipadm_flags);
701
702 if (status == IPADM_IF_EXISTS)
703 status = IPADM_SUCCESS;
704
705 /* plumbing can fail for ipmp, this is expected */
706 if (status != IPADM_SUCCESS && !(ipadm_flags & IPADM_OPT_IPMP))
707 break;
708 }
709 /* does this interface belong to ipmp ? */
710 if (nvlist_lookup_string(nvl, IPADM_NVP_GIFNAME, &gif_name) == 0) {
711 (void) ipadm_create_if(iph, gif_name, AF_INET, IPADM_OPT_IPMP |
712 IPADM_OPT_ACTIVE);
713 (void) ipadm_create_if(iph, gif_name, AF_INET6, IPADM_OPT_IPMP |
714 IPADM_OPT_ACTIVE);
715 /** add itself to the group */
716 status = ipadm_add_ipmp_member(iph, gif_name, newifname, IPADM_OPT_ACTIVE);
717 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
718 break;
719 }
720 if (is_ngz)
721 init_from_gz = B_TRUE;
722 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
723 &aobjstr) == 0) {
724 /*
725 * For a static address, we need to search for
726 * the prefixlen in the nvlist `ifnvl'.
727 */
728 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
729 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
730 status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
731 nvl, aobjstr);
732
733 if (status != IPADM_SUCCESS)
734 continue;
735 }
736 status = i_ipadm_init_addrobj(iph, nvl);
737 /*
738 * If this address is in use on some other interface,
739 * we want to record an error to be returned as
740 * a soft error and continue processing the rest of
741 * the addresses.
742 */
743 if (status == IPADM_ADDR_NOTAVAIL) {
744 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
745 status = IPADM_SUCCESS;
746 }
747 } else {
748 assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
749 status = i_ipadm_init_ifprop(iph, nvl);
750 }
751 if (status != IPADM_SUCCESS)
752 return (status);
753 }
754 if (init_from_gz)
755 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
756
757 return (ret_status);
758 }
759
760 /*
761 * Retrieves the persistent configuration for the given interface(s) in `ifs'
762 * by contacting the daemon and dumps the information in `allifs'.
763 */
764 ipadm_status_t
765 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
766 {
767 nvlist_t *nvl = NULL;
768 size_t nvlsize, bufsize;
769 ipmgmt_initif_arg_t *iargp;
770 char *buf = NULL, *nvlbuf = NULL;
771 ipmgmt_get_rval_t *rvalp = NULL;
772 int err;
773 ipadm_status_t status = IPADM_SUCCESS;
774
775 if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
776 return (ipadm_errno2status(err));
777
778 err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
779 if (err != 0) {
780 status = ipadm_errno2status(err);
781 goto done;
782 }
783 bufsize = sizeof (*iargp) + nvlsize;
784 if ((buf = malloc(bufsize)) == NULL) {
785 status = ipadm_errno2status(errno);
786 goto done;
787 }
788
789 /* populate the door_call argument structure */
790 iargp = (void *)buf;
791 iargp->ia_cmd = IPMGMT_CMD_INITIF;
792 iargp->ia_flags = 0;
793 iargp->ia_family = AF_UNSPEC;
794 iargp->ia_nvlsize = nvlsize;
795 (void) bcopy(nvlbuf, buf + sizeof (*iargp), nvlsize);
796
797 if ((rvalp = malloc(sizeof (ipmgmt_get_rval_t))) == NULL) {
798 status = ipadm_errno2status(errno);
799 goto done;
800 }
801 if ((err = ipadm_door_call(iph, iargp, bufsize, (void **)&rvalp,
802 sizeof (*rvalp), B_TRUE)) != 0) {
803 status = ipadm_errno2status(err);
804 goto done;
805 }
806 nvlsize = rvalp->ir_nvlsize;
807 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
808
809 /*
810 * nvlbuf contains a list of nvlists, each of which represents
811 * configuration information for the given interface(s)
812 */
813 err = nvlist_unpack(nvlbuf, nvlsize, allifs, NV_ENCODE_NATIVE);
814 if (err != 0)
815 status = ipadm_errno2status(err);
816 done:
817 nvlist_free(nvl);
818 free(buf);
819 free(nvlbuf);
820 free(rvalp);
821 return (status);
822 }
823
824 /*
825 * Returns B_FALSE if
826 * (1) `ifname' is NULL or has no string or has a string of invalid length
827 * (2) ifname is a logical interface and IPH_LEGACY is not set, or
828 */
829 boolean_t
830 i_ipadm_validate_ifname(ipadm_handle_t iph, const char *ifname)
831 {
832 ifspec_t ifsp;
833
834 if (ifname == NULL || ifname[0] == '\0' ||
835 !ifparse_ifspec(ifname, &ifsp))
836 return (B_FALSE);
837 if (ifsp.ifsp_lunvalid)
838 return (ifsp.ifsp_lun > 0 && (iph->iph_flags & IPH_LEGACY));
839 return (B_TRUE);
840 }
841
842 /*
843 * Wrapper for sending a non-transparent I_STR ioctl().
844 * Returns: Result from ioctl().
845 */
846 int
847 i_ipadm_strioctl(int s, int cmd, char *buf, int buflen)
848 {
849 struct strioctl ioc;
850
851 (void) memset(&ioc, 0, sizeof (ioc));
852 ioc.ic_cmd = cmd;
853 ioc.ic_timout = 0;
854 ioc.ic_len = buflen;
855 ioc.ic_dp = buf;
856
857 return (ioctl(s, I_STR, (char *)&ioc));
858 }
859
860 /*
861 * Make a door call to the server and checks if the door call succeeded or not.
862 * `is_varsize' specifies that the data returned by ipmgmtd daemon is of
863 * variable size and door will allocate buffer using mmap(). In such cases
864 * we re-allocate the required memory,n assign it to `rbufp', copy the data to
865 * `rbufp' and then call munmap() (see below).
866 *
867 * It also checks to see if the server side procedure ran successfully by
868 * checking for ir_err. Therefore, for some callers who just care about the
869 * return status can set `rbufp' to NULL and set `rsize' to 0.
870 */
871 int
872 ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp,
873 size_t rsize, boolean_t is_varsize)
874 {
875 door_arg_t darg;
876 int err;
877 ipmgmt_retval_t rval, *rvalp;
878 boolean_t reopen = B_FALSE;
879
880 if (rbufp == NULL) {
881 rvalp = &rval;
882 rbufp = (void **)&rvalp;
883 rsize = sizeof (rval);
884 }
885
886 darg.data_ptr = arg;
887 darg.data_size = asize;
888 darg.desc_ptr = NULL;
889 darg.desc_num = 0;
890 darg.rbuf = *rbufp;
891 darg.rsize = rsize;
892
893 reopen:
894 (void) pthread_mutex_lock(&iph->iph_lock);
895 /* The door descriptor is opened if it isn't already */
896 if (iph->iph_door_fd == -1) {
897 if ((iph->iph_door_fd = open(IPMGMT_DOOR, O_RDONLY)) < 0) {
898 err = errno;
899 (void) pthread_mutex_unlock(&iph->iph_lock);
900 return (err);
901 }
902 }
903 (void) pthread_mutex_unlock(&iph->iph_lock);
904
905 if (door_call(iph->iph_door_fd, &darg) == -1) {
906 /*
907 * Stale door descriptor is possible if ipmgmtd was restarted
908 * since last iph_door_fd was opened, so try re-opening door
909 * descriptor.
910 */
911 if (!reopen && errno == EBADF) {
912 (void) close(iph->iph_door_fd);
913 iph->iph_door_fd = -1;
914 reopen = B_TRUE;
915 goto reopen;
916 }
917 return (errno);
918 }
919 err = ((ipmgmt_retval_t *)(void *)(darg.rbuf))->ir_err;
920 if (darg.rbuf != *rbufp) {
921 /*
922 * if the caller is expecting the result to fit in specified
923 * buffer then return failure.
924 */
925 if (!is_varsize)
926 err = EBADE;
927 /*
928 * The size of the buffer `*rbufp' was not big enough
929 * and the door itself allocated buffer, for us. We will
930 * hit this, on several occasion as for some cases
931 * we cannot predict the size of the return structure.
932 * Reallocate the buffer `*rbufp' and memcpy() the contents
933 * to new buffer.
934 */
935 if (err == 0) {
936 void *newp;
937
938 /* allocated memory will be freed by the caller */
939 if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
940 err = ENOMEM;
941 } else {
942 *rbufp = newp;
943 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
944 }
945 }
946 /* munmap() the door buffer */
947 (void) munmap(darg.rbuf, darg.rsize);
948 } else {
949 if (darg.rsize != rsize)
950 err = EBADE;
951 }
952 return (err);
953 }
954
955 /*
956 * A helper that is used by i_ipadm_get_db_addr and i_ipadm_get_db_if
957 * to do a door_call to ipmgmtd, that should return persistent information
958 * about interfaces or/and addresses from ipadm DB
959 */
960 ipadm_status_t
961 i_ipadm_call_ipmgmtd(ipadm_handle_t iph, void *garg,
962 size_t garg_size, nvlist_t **onvl)
963 {
964 ipmgmt_get_rval_t *rvalp;
965 int err;
966 size_t nvlsize;
967 char *nvlbuf;
968
969 rvalp = malloc(sizeof (ipmgmt_get_rval_t));
970 err = ipadm_door_call(iph, garg, garg_size, (void **)&rvalp,
971 sizeof (*rvalp), B_TRUE);
972 if (err == 0) {
973 nvlsize = rvalp->ir_nvlsize;
974 nvlbuf = (char *)rvalp + sizeof (ipmgmt_get_rval_t);
975 err = nvlist_unpack(nvlbuf, nvlsize, onvl, NV_ENCODE_NATIVE);
976 }
977 free(rvalp);
978
979 return (ipadm_errno2status(err));
980 }