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.
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.
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]
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
34 #include <sys/sockio.h>
35 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <net/route.h>
39 #include <netinet/in.h>
41 #include <arpa/inet.h>
44 #include <libinetutil.h>
46 #include <libdllink.h>
47 #include <libdliptun.h>
55 #include <auth_attr.h>
57 #include <nss_dbdefs.h>
58 #include "libipadm_impl.h"
60 /* error codes and text description */
61 static struct ipadm_error_info
{
62 ipadm_status_t error_code
;
63 const char *error_desc
;
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"}
106 #define IPADM_NUM_ERRORS (sizeof (ipadm_errors) / sizeof (*ipadm_errors))
109 ipadm_errno2status(int error
)
113 return (IPADM_SUCCESS
);
115 return (IPADM_ENXIO
);
117 return (IPADM_NO_MEMORY
);
119 return (IPADM_NO_BUFS
);
121 return (IPADM_INVALID_ARG
);
123 return (IPADM_IF_INUSE
);
125 return (IPADM_EXISTS
);
127 return (IPADM_ADDR_NOTAVAIL
);
129 return (IPADM_ADDR_INUSE
);
131 return (IPADM_NOTFOUND
);
133 return (IPADM_ERANGE
);
135 return (IPADM_EPERM
);
138 return (IPADM_NOTSUP
);
140 return (IPADM_IPC_ERROR
);
142 return (IPADM_EBADE
);
144 return (IPADM_ESRCH
);
146 return (IPADM_EOVERFLOW
);
148 return (IPADM_FAILURE
);
153 * Returns a message string for the given libipadm error status.
156 ipadm_status2str(ipadm_status_t status
)
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
));
166 return (dgettext(TEXT_DOMAIN
, "<unknown error>"));
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
180 ipadm_open(ipadm_handle_t
*handle
, uint32_t flags
)
183 ipadm_status_t status
= IPADM_SUCCESS
;
189 return (IPADM_INVALID_ARG
);
192 if (flags
& ~(IPH_VRRP
|IPH_LEGACY
|IPH_INIT
|IPH_IPMGMTD
))
193 return (IPADM_INVALID_ARG
);
195 if ((iph
= calloc(1, sizeof (struct ipadm_handle
))) == NULL
)
196 return (IPADM_NO_MEMORY
);
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
);
204 if ((iph
->iph_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0 ||
205 (iph
->iph_sock6
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
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.
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.
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) {
227 if ((zoneid
== GLOBAL_ZONEID
) || (zflags
& ZF_NET_EXCL
)) {
228 if (dladm_open(&iph
->iph_dlh
) != DLADM_STATUS_OK
) {
230 return (IPADM_DLADM_FAILURE
);
232 if (zoneid
!= GLOBAL_ZONEID
) {
233 iph
->iph_rtsock
= socket(PF_ROUTE
, SOCK_RAW
, 0);
235 * Failure to open rtsock is ignored as this is
236 * only used in non-global zones to initialize
237 * routing socket information.
241 assert(zoneid
!= GLOBAL_ZONEID
);
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) {
255 status
= ipadm_errno2status(errno
);
261 * Closes and frees the libipadm handle.
264 ipadm_close(ipadm_handle_t iph
)
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
);
282 * Checks if the caller has the authorization to configure network
286 ipadm_check_auth(void)
289 char buf
[NSS_BUFLEN_PASSWD
];
291 /* get the password entry for the given user ID */
292 if (getpwuid_r(getuid(), &pwd
, buf
, sizeof (buf
)) == NULL
)
295 /* check for presence of given authorization */
296 return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH
, pwd
.pw_name
) != 0);
300 * Stores the index value of the interface in `ifname' for the address
301 * family `af' into the buffer pointed to by `index'.
303 static ipadm_status_t
304 i_ipadm_get_index(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
,
310 bzero(&lifr
, sizeof (lifr
));
311 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
313 sock
= iph
->iph_sock
;
315 sock
= iph
->iph_sock6
;
317 if (ioctl(sock
, SIOCGLIFINDEX
, (caddr_t
)&lifr
) < 0)
318 return (ipadm_errno2status(errno
));
319 *index
= lifr
.lifr_index
;
321 return (IPADM_SUCCESS
);
325 * Maximum amount of time (in milliseconds) to wait for Duplicate Address
326 * Detection to complete in the kernel.
328 #define DAD_WAIT_TIME 1000
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.)
339 static ipadm_status_t
340 i_ipadm_dad_wait(ipadm_handle_t handle
, const char *lifname
, sa_family_t af
,
343 struct pollfd fds
[1];
345 struct if_msghdr ifm
;
351 hrtime_t starttime
, now
;
354 fds
[0].events
= POLLIN
;
357 retv
= i_ipadm_get_index(handle
, lifname
, af
, &index
);
358 if (retv
!= IPADM_SUCCESS
)
361 starttime
= gethrtime();
364 now
= (now
- starttime
) / 1000000;
365 if (now
>= DAD_WAIT_TIME
)
367 if (poll(fds
, 1, DAD_WAIT_TIME
- (int)now
) <= 0)
369 if (read(rtsock
, &msg
, sizeof (msg
)) <= 0)
371 if (msg
.ifm
.ifm_type
!= RTM_NEWADDR
)
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
);
378 retv
= i_ipadm_get_flags(handle
, lifname
, af
, &flags
);
379 if (retv
!= IPADM_SUCCESS
)
381 if (flags
& IFF_DUPLICATE
)
382 return (IPADM_DAD_FOUND
);
384 return (IPADM_SUCCESS
);
388 * Sets the flags `on_flags' and resets the flags `off_flags' for the logical
389 * interface in `lifname'.
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.
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
)
405 ret
= i_ipadm_get_flags(iph
, lifname
, af
, &oflags
);
406 if (ret
!= IPADM_SUCCESS
)
409 sock
= (af
== AF_INET
? iph
->iph_sock
: iph
->iph_sock6
);
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."
416 if (!(oflags
& IFF_UP
) && (on_flags
& IFF_UP
))
417 rtsock
= socket(PF_ROUTE
, SOCK_RAW
, af
);
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) {
427 (void) close(rtsock
);
428 return (ipadm_errno2status(err
));
431 return (IPADM_SUCCESS
);
433 /* Wait for DAD to complete. */
434 ret
= i_ipadm_dad_wait(iph
, lifname
, af
, rtsock
);
435 (void) close(rtsock
);
441 * Returns the flags value for the logical interface in `lifname'
442 * in the buffer pointed to by `flags'.
445 i_ipadm_get_flags(ipadm_handle_t iph
, const char *lifname
, sa_family_t af
,
451 bzero(&lifr
, sizeof (lifr
));
452 (void) strlcpy(lifr
.lifr_name
, lifname
, sizeof (lifr
.lifr_name
));
454 sock
= iph
->iph_sock
;
456 sock
= iph
->iph_sock6
;
458 if (ioctl(sock
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
459 return (ipadm_errno2status(errno
));
461 *flags
= lifr
.lifr_flags
;
463 return (IPADM_SUCCESS
);
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().
472 * Returns: B_TRUE if loopback, B_FALSE if not.
475 i_ipadm_is_loopback(const char *ifname
)
477 int len
= strlen(LOOPBACK_IF
);
479 return (strncmp(ifname
, LOOPBACK_IF
, len
) == 0 &&
480 (ifname
[len
] == '\0' || ifname
[len
] == IPADM_LOGICAL_SEP
));
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().
489 * Returns: B_TRUE if vni, B_FALSE if not.
492 i_ipadm_is_vni(const char *ifname
)
496 return (ifparse_ifspec(ifname
, &ifsp
) &&
497 strcmp(ifsp
.ifsp_devnm
, "vni") == 0);
501 * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel.
504 i_ipadm_is_6to4(ipadm_handle_t iph
, char *ifname
)
506 dladm_status_t dlstatus
;
507 datalink_class_t
class;
508 iptun_params_t params
;
509 datalink_id_t linkid
;
511 if (iph
->iph_dlh
== NULL
) {
512 assert(iph
->iph_zoneid
!= GLOBAL_ZONEID
);
515 dlstatus
= dladm_name2info(iph
->iph_dlh
, ifname
, &linkid
, 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
,
521 if (dlstatus
== DLADM_STATUS_OK
&&
522 params
.iptun_param_type
== IPTUN_TYPE_6TO4
) {
530 * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
533 i_ipadm_is_under_ipmp(ipadm_handle_t iph
, const char *ifname
)
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) {
544 return (lifr
.lifr_groupname
[0] != '\0');
548 * Returns B_TRUE if `ifname' represents an IPMP meta-interface.
551 i_ipadm_is_ipmp(ipadm_handle_t iph
, const char *ifname
)
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
)
559 return ((flags
& IFF_IPMP
) != 0);
563 * For a given interface name, ipadm_if_enabled() checks if v4
564 * or v6 or both IP interfaces exist in the active configuration.
567 ipadm_if_enabled(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
)
570 int s4
= iph
->iph_sock
;
571 int s6
= iph
->iph_sock6
;
573 bzero(&lifr
, sizeof (lifr
));
574 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
577 if (ioctl(s4
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) == 0)
581 if (ioctl(s6
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) == 0)
585 if (ioctl(s4
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) == 0 ||
586 ioctl(s6
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) == 0) {
594 * Apply the interface property by retrieving information from nvl.
596 static ipadm_status_t
597 i_ipadm_init_ifprop(ipadm_handle_t iph
, nvlist_t
*nvl
)
600 char *name
, *pname
= NULL
;
601 char *protostr
= NULL
, *ifname
= NULL
, *pval
= NULL
;
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)
611 } else if (strcmp(name
, IPADM_NVP_PROTONAME
) == 0) {
612 if ((err
= nvpair_value_string(nvp
, &protostr
)) != 0)
615 assert(!IPADM_PRIV_NVP(name
));
617 if ((err
= nvpair_value_string(nvp
, &pval
)) != 0)
622 return (ipadm_errno2status(err
));
623 proto
= ipadm_str2proto(protostr
);
624 return (ipadm_set_ifprop(iph
, ifname
, pname
, pval
, proto
,
629 * Instantiate the address object or set the address object property by
630 * retrieving the configuration from the nvlist `nvl'.
633 i_ipadm_init_addrobj(ipadm_handle_t iph
, nvlist_t
*nvl
)
637 char *aobjname
= NULL
, *pval
= NULL
, *ifname
= NULL
;
638 sa_family_t af
= AF_UNSPEC
;
639 ipadm_addr_type_t atype
= IPADM_ADDR_NONE
;
641 ipadm_status_t status
= IPADM_SUCCESS
;
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)
649 } else if (strcmp(name
, IPADM_NVP_AOBJNAME
) == 0) {
650 if ((err
= nvpair_value_string(nvp
, &aobjname
)) != 0)
652 } else if (i_ipadm_name2atype(name
, &af
, &atype
)) {
655 assert(!IPADM_PRIV_NVP(name
));
656 err
= nvpair_value_string(nvp
, &pval
);
661 return (ipadm_errno2status(err
));
664 case IPADM_ADDR_STATIC
:
665 status
= i_ipadm_enable_static(iph
, ifname
, nvl
, af
);
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
;
672 case IPADM_ADDR_IPV6_ADDRCONF
:
673 status
= i_ipadm_enable_addrconf(iph
, ifname
, nvl
);
675 case IPADM_ADDR_NONE
:
676 status
= ipadm_set_addrprop(iph
, name
, pval
, aobjname
,
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
691 i_ipadm_init_ifobj(ipadm_handle_t iph
, const char *ifname
, nvlist_t
*ifnvl
)
693 nvlist_t
*nvl
= NULL
;
696 ipadm_status_t status
;
697 ipadm_status_t ret_status
= IPADM_SUCCESS
;
698 char newifname
[LIFNAMSIZ
];
700 sa_family_t af
= AF_UNSPEC
;
701 boolean_t is_ngz
= (iph
->iph_zoneid
!= GLOBAL_ZONEID
);
703 (void) strlcpy(newifname
, ifname
, sizeof (newifname
));
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.
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)
714 if (nvlist_lookup_string(nvl
, IPADM_NVP_FAMILY
, &afstr
) == 0) {
715 status
= i_ipadm_plumb_if(iph
, newifname
, atoi(afstr
),
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
723 if (status
== IPADM_IF_EXISTS
)
724 status
= IPADM_SUCCESS
;
728 } else if (nvlist_lookup_string(nvl
, IPADM_NVP_AOBJNAME
,
731 * For a static address, we need to search for
732 * the prefixlen in the nvlist `ifnvl'.
734 if (nvlist_exists(nvl
, IPADM_NVP_IPV4ADDR
) ||
735 nvlist_exists(nvl
, IPADM_NVP_IPV6ADDR
)) {
736 status
= i_ipadm_merge_prefixlen_from_nvl(ifnvl
,
738 if (status
!= IPADM_SUCCESS
)
741 status
= i_ipadm_init_addrobj(iph
, nvl
);
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
748 if (status
== IPADM_ADDR_NOTAVAIL
) {
749 ret_status
= IPADM_ALL_ADDRS_NOT_ENABLED
;
750 status
= IPADM_SUCCESS
;
753 assert(nvlist_exists(nvl
, IPADM_NVP_PROTONAME
));
754 status
= i_ipadm_init_ifprop(iph
, nvl
);
756 if (status
!= IPADM_SUCCESS
)
760 if (is_ngz
&& af
!= AF_UNSPEC
)
761 ret_status
= ipadm_init_net_from_gz(iph
, newifname
, NULL
);
766 * Retrieves the persistent configuration for the given interface(s) in `ifs'
767 * by contacting the daemon and dumps the information in `allifs'.
770 i_ipadm_init_ifs(ipadm_handle_t iph
, const char *ifs
, nvlist_t
**allifs
)
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
;
778 ipadm_status_t status
= IPADM_SUCCESS
;
780 if ((err
= ipadm_str2nvlist(ifs
, &nvl
, IPADM_NORVAL
)) != 0)
781 return (ipadm_errno2status(err
));
783 err
= nvlist_pack(nvl
, &nvlbuf
, &nvlsize
, NV_ENCODE_NATIVE
, 0);
785 status
= ipadm_errno2status(err
);
788 bufsize
= sizeof (*iargp
) + nvlsize
;
789 if ((buf
= malloc(bufsize
)) == NULL
) {
790 status
= ipadm_errno2status(errno
);
794 /* populate the door_call argument structure */
796 iargp
->ia_cmd
= IPMGMT_CMD_INITIF
;
798 iargp
->ia_family
= AF_UNSPEC
;
799 iargp
->ia_nvlsize
= nvlsize
;
800 (void) bcopy(nvlbuf
, buf
+ sizeof (*iargp
), nvlsize
);
802 if ((rvalp
= malloc(sizeof (ipmgmt_get_rval_t
))) == NULL
) {
803 status
= ipadm_errno2status(errno
);
806 if ((err
= ipadm_door_call(iph
, iargp
, bufsize
, (void **)&rvalp
,
807 sizeof (*rvalp
), B_TRUE
)) != 0) {
808 status
= ipadm_errno2status(err
);
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).
817 err
= nvlist_unpack((char *)rvalp
+ sizeof (ipmgmt_get_rval_t
),
818 rvalp
->ir_nvlsize
, allifs
, NV_ENCODE_NATIVE
);
820 status
= ipadm_errno2status(err
);
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
835 i_ipadm_validate_ifname(ipadm_handle_t iph
, const char *ifname
)
839 if (ifname
== NULL
|| ifname
[0] == '\0' ||
840 !ifparse_ifspec(ifname
, &ifsp
))
842 if (ifsp
.ifsp_lunvalid
)
843 return (ifsp
.ifsp_lun
> 0 && (iph
->iph_flags
& IPH_LEGACY
));
848 * Wrapper for sending a non-transparent I_STR ioctl().
849 * Returns: Result from ioctl().
852 i_ipadm_strioctl(int s
, int cmd
, char *buf
, int buflen
)
856 (void) memset(&ioc
, 0, sizeof (ioc
));
862 return (ioctl(s
, I_STR
, (char *)&ioc
));
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).
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.
877 ipadm_door_call(ipadm_handle_t iph
, void *arg
, size_t asize
, void **rbufp
,
878 size_t rsize
, boolean_t is_varsize
)
882 ipmgmt_retval_t rval
, *rvalp
;
883 boolean_t reopen
= B_FALSE
;
887 rbufp
= (void **)&rvalp
;
888 rsize
= sizeof (rval
);
892 darg
.data_size
= asize
;
893 darg
.desc_ptr
= NULL
;
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) {
904 (void) pthread_mutex_unlock(&iph
->iph_lock
);
908 (void) pthread_mutex_unlock(&iph
->iph_lock
);
910 if (door_call(iph
->iph_door_fd
, &darg
) == -1) {
912 * Stale door descriptor is possible if ipmgmtd was restarted
913 * since last iph_door_fd was opened, so try re-opening door
916 if (!reopen
&& errno
== EBADF
) {
917 (void) close(iph
->iph_door_fd
);
918 iph
->iph_door_fd
= -1;
924 err
= ((ipmgmt_retval_t
*)(void *)(darg
.rbuf
))->ir_err
;
925 if (darg
.rbuf
!= *rbufp
) {
927 * if the caller is expecting the result to fit in specified
928 * buffer then return failure.
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
943 /* allocated memory will be freed by the caller */
944 if ((newp
= realloc(*rbufp
, darg
.rsize
)) == NULL
) {
948 (void) memcpy(*rbufp
, darg
.rbuf
, darg
.rsize
);
951 /* munmap() the door buffer */
952 (void) munmap(darg
.rbuf
, darg
.rsize
);
954 if (darg
.rsize
!= rsize
)