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