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]
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/sockio.h>
33 #include <libdllink.h>
34 #include <libinetutil.h>
38 #include <ipadm_ndpd.h>
39 #include "libipadm_impl.h"
41 static ipadm_status_t
i_ipadm_slifname_arp(char *, uint64_t, int);
42 static ipadm_status_t
i_ipadm_slifname(ipadm_handle_t
, char *, char *,
43 uint64_t, int, uint32_t);
44 static ipadm_status_t
i_ipadm_create_ipmp_peer(ipadm_handle_t
, char *,
46 static ipadm_status_t
i_ipadm_persist_if(ipadm_handle_t
, const char *,
50 * Returns B_FALSE if the interface in `ifname' has at least one address that is
51 * IFF_UP in the addresses in `ifa'.
54 i_ipadm_is_if_down(char *ifname
, struct ifaddrs
*ifa
)
57 char cifname
[LIFNAMSIZ
];
60 for (ifap
= ifa
; ifap
!= NULL
; ifap
= ifap
->ifa_next
) {
61 (void) strlcpy(cifname
, ifap
->ifa_name
, sizeof (cifname
));
62 if ((sep
= strrchr(cifname
, IPADM_LOGICAL_SEP
)) != NULL
)
65 * If this condition is true, there is at least one
66 * address that is IFF_UP. So, we need to return B_FALSE.
68 if (strcmp(cifname
, ifname
) == 0 &&
69 (ifap
->ifa_flags
& IFF_UP
)) {
73 /* We did not find any IFF_UP addresses. */
78 * Retrieves the information for the interface `ifname' from active
79 * config if `ifname' is specified and returns the result in the list `if_info'.
80 * Otherwise, it retrieves the information for all the interfaces in
81 * the active config and returns the result in the list `if_info'.
84 i_ipadm_active_if_info(ipadm_handle_t iph
, const char *ifname
,
85 ipadm_if_info_t
**if_info
, int64_t lifc_flags
)
90 ipadm_if_info_t
*last
= NULL
;
95 ipadm_status_t status
;
99 * Get information for all interfaces.
101 if (getallifs(iph
->iph_sock
, 0, &buf
, &numifs
, lifc_flags
) != 0)
102 return (ipadm_errno2status(errno
));
105 for (n
= 0; n
< numifs
; n
++, lifrp
++) {
106 /* Skip interfaces with logical num != 0 */
107 if (i_ipadm_get_lnum(lifrp
->lifr_name
) != 0)
110 * Skip the current interface if a specific `ifname' has
111 * been requested and current interface does not match
114 if (ifname
!= NULL
&& strcmp(lifrp
->lifr_name
, ifname
) != 0)
117 * Check if the interface already exists in our list.
118 * If it already exists, we need to update its flags.
120 for (ifp
= *if_info
; ifp
!= NULL
; ifp
= ifp
->ifi_next
) {
121 if (strcmp(lifrp
->lifr_name
, ifp
->ifi_name
) == 0)
125 ifp
= calloc(1, sizeof (ipadm_if_info_t
));
127 status
= ipadm_errno2status(errno
);
130 (void) strlcpy(ifp
->ifi_name
, lifrp
->lifr_name
,
131 sizeof (ifp
->ifi_name
));
132 /* Update the `ifi_next' pointer for this new node */
133 if (*if_info
== NULL
)
136 last
->ifi_next
= ifp
;
141 * Retrieve the flags for the interface by doing a
142 * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
144 (void) strlcpy(lifrl
.lifr_name
,
145 lifrp
->lifr_name
, sizeof (lifrl
.lifr_name
));
146 s
= (lifrp
->lifr_addr
.ss_family
== AF_INET
) ?
147 iph
->iph_sock
: iph
->iph_sock6
;
148 if (ioctl(s
, SIOCGLIFFLAGS
, (caddr_t
)&lifrl
) < 0)
150 if (lifrl
.lifr_flags
& IFF_BROADCAST
)
151 ifp
->ifi_cflags
|= IFIF_BROADCAST
;
152 if (lifrl
.lifr_flags
& IFF_MULTICAST
)
153 ifp
->ifi_cflags
|= IFIF_MULTICAST
;
154 if (lifrl
.lifr_flags
& IFF_POINTOPOINT
)
155 ifp
->ifi_cflags
|= IFIF_POINTOPOINT
;
156 if (lifrl
.lifr_flags
& IFF_VIRTUAL
)
157 ifp
->ifi_cflags
|= IFIF_VIRTUAL
;
158 if (lifrl
.lifr_flags
& IFF_IPMP
)
159 ifp
->ifi_cflags
|= IFIF_IPMP
;
160 if (lifrl
.lifr_flags
& IFF_STANDBY
)
161 ifp
->ifi_cflags
|= IFIF_STANDBY
;
162 if (lifrl
.lifr_flags
& IFF_INACTIVE
)
163 ifp
->ifi_cflags
|= IFIF_INACTIVE
;
164 if (lifrl
.lifr_flags
& IFF_VRRP
)
165 ifp
->ifi_cflags
|= IFIF_VRRP
;
166 if (lifrl
.lifr_flags
& IFF_NOACCEPT
)
167 ifp
->ifi_cflags
|= IFIF_NOACCEPT
;
168 if (lifrl
.lifr_flags
& IFF_IPV4
)
169 ifp
->ifi_cflags
|= IFIF_IPV4
;
170 if (lifrl
.lifr_flags
& IFF_IPV6
)
171 ifp
->ifi_cflags
|= IFIF_IPV6
;
172 if (lifrl
.lifr_flags
& IFF_L3PROTECT
)
173 ifp
->ifi_cflags
|= IFIF_L3PROTECT
;
176 return (IPADM_SUCCESS
);
179 ipadm_free_if_info(*if_info
);
185 * Returns the interface information for `ifname' in `if_info' from persistent
186 * config if `ifname' is non-null. Otherwise, it returns all the interfaces
187 * from persistent config in `if_info'.
189 static ipadm_status_t
190 i_ipadm_persist_if_info(ipadm_handle_t iph
, const char *ifname
,
191 ipadm_if_info_t
**if_info
)
193 ipadm_status_t status
= IPADM_SUCCESS
;
194 ipmgmt_getif_arg_t getif
;
195 ipmgmt_getif_rval_t
*rvalp
;
196 ipadm_if_info_t
*ifp
, *curr
, *prev
= NULL
;
199 bzero(&getif
, sizeof (getif
));
201 (void) strlcpy(getif
.ia_ifname
, ifname
, LIFNAMSIZ
);
202 getif
.ia_cmd
= IPMGMT_CMD_GETIF
;
206 if ((rvalp
= malloc(sizeof (ipmgmt_getif_rval_t
))) == NULL
)
207 return (ipadm_errno2status(errno
));
208 err
= ipadm_door_call(iph
, &getif
, sizeof (getif
), (void **)&rvalp
,
209 sizeof (*rvalp
), B_TRUE
);
213 return (ipadm_errno2status(err
));
214 return (IPADM_SUCCESS
);
215 } else if (err
!= 0) {
217 return (ipadm_errno2status(err
));
220 ifp
= rvalp
->ir_ifinfo
;
221 for (i
= 0; i
< rvalp
->ir_ifcnt
; i
++) {
222 ifp
= rvalp
->ir_ifinfo
+ i
;
223 if ((curr
= malloc(sizeof (*curr
))) == NULL
) {
224 status
= ipadm_errno2status(errno
);
225 ipadm_free_if_info(prev
);
228 (void) bcopy(ifp
, curr
, sizeof (*curr
));
229 curr
->ifi_next
= prev
;
238 * Collects information for `ifname' if one is specified from both
239 * active and persistent config in `if_info'. If no `ifname' is specified,
240 * this returns all the interfaces in active and persistent config in
244 i_ipadm_get_all_if_info(ipadm_handle_t iph
, const char *ifname
,
245 ipadm_if_info_t
**if_info
, int64_t lifc_flags
)
247 ipadm_status_t status
;
248 ipadm_if_info_t
*aifinfo
= NULL
;
249 ipadm_if_info_t
*pifinfo
= NULL
;
250 ipadm_if_info_t
*aifp
;
251 ipadm_if_info_t
*pifp
;
252 ipadm_if_info_t
*last
= NULL
;
254 struct ifaddrs
*ifap
;
257 * Retrive the information for the requested `ifname' or all
258 * interfaces from active configuration.
261 status
= i_ipadm_active_if_info(iph
, ifname
, &aifinfo
, lifc_flags
);
262 if (status
!= IPADM_SUCCESS
)
264 /* Get the interface state for each interface in `aifinfo'. */
265 if (aifinfo
!= NULL
) {
266 /* We need all addresses to get the interface state */
267 if (getallifaddrs(AF_UNSPEC
, &ifa
, (LIFC_NOXMIT
|LIFC_TEMPORARY
|
268 LIFC_ALLZONES
|LIFC_UNDER_IPMP
)) != 0) {
269 status
= ipadm_errno2status(errno
);
272 for (aifp
= aifinfo
; aifp
!= NULL
; aifp
= aifp
->ifi_next
) {
274 * Find the `ifaddrs' structure from `ifa'
275 * for this interface. We need the IFF_* flags
276 * to find the interface state.
278 for (ifap
= ifa
; ifap
!= NULL
; ifap
= ifap
->ifa_next
) {
279 if (strcmp(ifap
->ifa_name
, aifp
->ifi_name
) == 0)
284 * The interface might have been removed
285 * from kernel. Retry getting all the active
289 ipadm_free_if_info(aifinfo
);
293 if (!(ifap
->ifa_flags
& IFF_RUNNING
) ||
294 (ifap
->ifa_flags
& IFF_FAILED
))
295 aifp
->ifi_state
= IFIS_FAILED
;
296 else if (ifap
->ifa_flags
& IFF_OFFLINE
)
297 aifp
->ifi_state
= IFIS_OFFLINE
;
298 else if (i_ipadm_is_if_down(aifp
->ifi_name
, ifa
))
299 aifp
->ifi_state
= IFIS_DOWN
;
301 aifp
->ifi_state
= IFIS_OK
;
302 if (aifp
->ifi_next
== NULL
)
308 * Get the persistent interface information in `pifinfo'.
310 status
= i_ipadm_persist_if_info(iph
, ifname
, &pifinfo
);
311 if (status
== IPADM_NOTFOUND
) {
313 return (IPADM_SUCCESS
);
315 if (status
!= IPADM_SUCCESS
)
318 * If a persistent interface is also found in `aifinfo', update
319 * its entry in `aifinfo' with the persistent information from
320 * `pifinfo'. If an interface is found in `pifinfo', but not in
321 * `aifinfo', it means that this interface was disabled. We should
322 * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
324 for (pifp
= pifinfo
; pifp
!= NULL
; pifp
= pifp
->ifi_next
) {
325 for (aifp
= aifinfo
; aifp
!= NULL
; aifp
= aifp
->ifi_next
) {
326 if (strcmp(aifp
->ifi_name
, pifp
->ifi_name
) == 0) {
327 aifp
->ifi_pflags
= pifp
->ifi_pflags
;
332 aifp
= malloc(sizeof (ipadm_if_info_t
));
334 status
= ipadm_errno2status(errno
);
338 aifp
->ifi_next
= NULL
;
339 aifp
->ifi_state
= IFIS_DISABLED
;
341 last
->ifi_next
= aifp
;
348 ipadm_free_if_info(pifinfo
);
349 return (IPADM_SUCCESS
);
352 ipadm_free_if_info(aifinfo
);
353 ipadm_free_if_info(pifinfo
);
358 i_ipadm_get_lnum(const char *ifname
)
360 char *num
= strrchr(ifname
, IPADM_LOGICAL_SEP
);
365 return (atoi(++num
));
369 * Sets the output argument `exists' to true or false based on whether
370 * any persistent configuration is available for `ifname' and returns
371 * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
372 * `exists' is unmodified and an error status is returned.
375 i_ipadm_if_pexists(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
,
378 ipadm_if_info_t
*ifinfo
;
379 ipadm_status_t status
;
382 * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
383 * knows about persistent configuration in the first place, so we
384 * just return success.
386 if (iph
->iph_flags
& IPH_IPMGMTD
) {
388 return (IPADM_SUCCESS
);
390 status
= i_ipadm_persist_if_info(iph
, ifname
, &ifinfo
);
391 if (status
== IPADM_SUCCESS
) {
392 *exists
= ((af
== AF_INET
&&
393 (ifinfo
->ifi_pflags
& IFIF_IPV4
)) ||
395 (ifinfo
->ifi_pflags
& IFIF_IPV6
)));
397 } else if (status
== IPADM_NOTFOUND
) {
398 status
= IPADM_SUCCESS
;
405 * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
406 * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
407 * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
408 * the bottom of the stream for tunneling interfaces.
411 ipadm_open_arp_on_udp(const char *udp_dev_name
, int *fd
)
415 if ((*fd
= open(udp_dev_name
, O_RDWR
)) == -1)
416 return (ipadm_errno2status(errno
));
419 * Pop off all undesired modules (note that the user may have
420 * configured autopush to add modules above udp), and push the
421 * arp module onto the resulting stream. This is used to make
422 * IP+ARP be able to atomically track the muxid for the I_PLINKed
423 * STREAMS, thus it isn't related to ARP running the ARP protocol.
425 while (ioctl(*fd
, I_POP
, 0) != -1)
427 if (errno
== EINVAL
&& ioctl(*fd
, I_PUSH
, ARP_MOD_NAME
) != -1)
428 return (IPADM_SUCCESS
);
432 return (ipadm_errno2status(err
));
436 * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an
437 * underlying interface in an ipmp group G is plumbed for an address family,
438 * but the meta-interface for the other address family `af' does not exist
439 * yet for the group G. If `af' is IPv6, we need to bring up the
440 * link-local address.
442 static ipadm_status_t
443 i_ipadm_create_ipmp(ipadm_handle_t iph
, char *ifname
, sa_family_t af
,
444 const char *grname
, uint32_t ipadm_flags
)
446 ipadm_status_t status
;
451 assert(ipadm_flags
& IPADM_OPT_IPMP
);
453 /* Create the ipmp underlying interface */
454 status
= i_ipadm_create_if(iph
, ifname
, af
, ipadm_flags
);
455 if (status
!= IPADM_SUCCESS
&& status
!= IPADM_IF_EXISTS
)
459 * To preserve backward-compatibility, always bring up the link-local
460 * address for implicitly-created IPv6 IPMP interfaces.
463 (void) i_ipadm_set_flags(iph
, ifname
, AF_INET6
, IFF_UP
, 0);
465 sock
= (af
== AF_INET
? iph
->iph_sock
: iph
->iph_sock6
);
467 * If the caller requested a different group name, issue a
468 * SIOCSLIFGROUPNAME on the new IPMP interface.
470 bzero(&lifr
, sizeof (lifr
));
471 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
472 if (strcmp(lifr
.lifr_name
, grname
) != 0) {
473 (void) strlcpy(lifr
.lifr_groupname
, grname
, LIFGRNAMSIZ
);
474 if (ioctl(sock
, SIOCSLIFGROUPNAME
, &lifr
) == -1) {
476 /* Remove the interface we created. */
477 if (status
== IPADM_SUCCESS
) {
478 (void) i_ipadm_delete_if(iph
, ifname
, af
,
481 return (ipadm_errno2status(err
));
485 return (IPADM_SUCCESS
);
489 * Checks if `ifname' is plumbed and in an IPMP group on its "other" address
490 * family. If so, create a matching IPMP group for address family `af'.
492 static ipadm_status_t
493 i_ipadm_create_ipmp_peer(ipadm_handle_t iph
, char *ifname
, sa_family_t af
)
495 lifgroupinfo_t lifgr
;
496 ipadm_status_t status
= IPADM_SUCCESS
;
500 assert(af
== AF_INET
|| af
== AF_INET6
);
502 other_af_sock
= (af
== AF_INET
? iph
->iph_sock6
: iph
->iph_sock
);
505 * iph is the handle for the interface that we are trying to plumb.
506 * other_af_sock is the socket for the "other" address family.
508 bzero(&lifr
, sizeof (lifr
));
509 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
510 if (ioctl(other_af_sock
, SIOCGLIFGROUPNAME
, &lifr
) != 0)
511 return (IPADM_SUCCESS
);
513 (void) strlcpy(lifgr
.gi_grname
, lifr
.lifr_groupname
, LIFGRNAMSIZ
);
514 if (ioctl(other_af_sock
, SIOCGLIFGROUPINFO
, &lifgr
) != 0)
515 return (IPADM_SUCCESS
);
518 * If `ifname' *is* the IPMP group interface, or if the relevant
519 * address family is already configured, then there's nothing to do.
521 if (strcmp(lifgr
.gi_grifname
, ifname
) == 0 ||
522 (af
== AF_INET
&& lifgr
.gi_v4
) || (af
== AF_INET6
&& lifgr
.gi_v6
)) {
523 return (IPADM_SUCCESS
);
526 status
= i_ipadm_create_ipmp(iph
, lifgr
.gi_grifname
, af
,
527 lifgr
.gi_grname
, IPADM_OPT_ACTIVE
|IPADM_OPT_IPMP
);
532 * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd.
534 static ipadm_status_t
535 i_ipadm_slifname_arp(char *ifname
, uint64_t flags
, int fd
)
540 bzero(&lifr
, sizeof (lifr
));
541 (void) ifparse_ifspec(ifname
, &ifsp
);
542 lifr
.lifr_ppa
= ifsp
.ifsp_ppa
;
543 lifr
.lifr_flags
= flags
;
544 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
546 * Tell ARP the name and unit number for this interface.
547 * Note that arp has no support for transparent ioctls.
549 if (i_ipadm_strioctl(fd
, SIOCSLIFNAME
, (char *)&lifr
,
550 sizeof (lifr
)) == -1) {
551 return (ipadm_errno2status(errno
));
553 return (IPADM_SUCCESS
);
557 * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in
558 * `ipadm_flags', then a ppa will be generated. `newif' will be updated
559 * with the generated ppa.
561 static ipadm_status_t
562 i_ipadm_slifname(ipadm_handle_t iph
, char *ifname
, char *newif
, uint64_t flags
,
563 int fd
, uint32_t ipadm_flags
)
566 ipadm_status_t status
= IPADM_SUCCESS
;
573 bzero(&lifr
, sizeof (lifr
));
574 if (ipadm_flags
& IPADM_OPT_GENPPA
) {
576 * We'd like to just set lifr_ppa to UINT_MAX and have the
577 * kernel pick a PPA. Unfortunately, that would mishandle
580 * 1. If the PPA is available but the groupname is taken
581 * (e.g., the "ipmp2" IP interface name is available
582 * but the "ipmp2" groupname is taken) then the
583 * auto-assignment by the kernel will fail.
585 * 2. If we're creating (e.g.) an IPv6-only IPMP
586 * interface, and there's already an IPv4-only IPMP
587 * interface, the kernel will allow us to accidentally
588 * reuse the IPv6 IPMP interface name (since
589 * SIOCSLIFNAME uniqueness is per-interface-type).
590 * This will cause administrative confusion.
592 * Thus, we instead take a brute-force approach of checking
593 * whether the IPv4 or IPv6 name is already in-use before
594 * attempting the SIOCSLIFNAME. As per (1) above, the
595 * SIOCSLIFNAME may still fail, in which case we just proceed
596 * to the next one. If this approach becomes too slow, we
597 * can add a new SIOC* to handle this case in the kernel.
599 for (ppa
= 0; ppa
< UINT_MAX
; ppa
++) {
600 (void) snprintf(lifr
.lifr_name
, LIFNAMSIZ
, "%s%d",
603 if (ioctl(iph
->iph_sock
, SIOCGLIFFLAGS
, &lifr
) != -1 ||
607 if (ioctl(iph
->iph_sock6
, SIOCGLIFFLAGS
, &lifr
) != -1 ||
612 lifr
.lifr_flags
= flags
;
614 err
= ioctl(fd
, SIOCSLIFNAME
, &lifr
);
615 if (err
!= -1 || errno
!= EEXIST
)
619 status
= ipadm_errno2status(errno
);
622 * PPA has been successfully established.
623 * Update `newif' with the ppa.
625 assert(newif
!= NULL
);
626 if (snprintf(newif
, LIFNAMSIZ
, "%s%d", ifname
,
628 return (IPADM_INVALID_ARG
);
631 /* We should have already validated the interface name. */
632 valid_if
= ifparse_ifspec(ifname
, &ifsp
);
636 * Before we call SIOCSLIFNAME, ensure that the IPMP group
637 * interface for this address family exists. Otherwise, the
638 * kernel will kick the interface out of the group when we do
641 * Example: suppose bge0 is plumbed for IPv4 and in group "a".
642 * If we're now plumbing bge0 for IPv6, but the IPMP group
643 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME
644 * will kick bge0 out of group "a", which is undesired.
646 if (flags
& IFF_IPV4
)
650 status
= i_ipadm_create_ipmp_peer(iph
, ifname
, af
);
651 if (status
!= IPADM_SUCCESS
)
653 lifr
.lifr_ppa
= ifsp
.ifsp_ppa
;
654 lifr
.lifr_flags
= flags
;
655 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
656 if (ioctl(fd
, SIOCSLIFNAME
, &lifr
) == -1)
657 status
= ipadm_errno2status(errno
);
664 * Plumbs the interface `ifname' for the address family `af'. It also persists
665 * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'.
668 i_ipadm_plumb_if(ipadm_handle_t iph
, char *ifname
, sa_family_t af
,
669 uint32_t ipadm_flags
)
672 int mux_fd
= -1, ip_fd
, arp_fd
;
674 dlpi_handle_t dh_arp
= NULL
, dh_ip
;
678 ipadm_status_t status
= IPADM_SUCCESS
;
680 boolean_t legacy
= (iph
->iph_flags
& IPH_LEGACY
);
682 char newif
[LIFNAMSIZ
];
683 char lifname
[LIFNAMSIZ
];
684 datalink_id_t linkid
;
687 boolean_t is_persistent
=
688 ((ipadm_flags
& IPADM_OPT_PERSIST
) != 0);
690 dladm_status_t dlstatus
;
692 if (iph
->iph_dlh
!= NULL
) {
693 dlstatus
= dladm_name2info(iph
->iph_dlh
, ifname
, &linkid
,
694 &dlflags
, NULL
, NULL
);
697 * If we're in the global zone and we're plumbing a datalink, make
698 * sure that the datalink is not assigned to a non-global zone. Note
699 * that the non-global zones don't need this check, because zoneadm
700 * has taken care of this when the zones boot.
702 if (iph
->iph_zoneid
== GLOBAL_ZONEID
&& dlstatus
== DLADM_STATUS_OK
) {
704 if (zone_check_datalink(&zoneid
, linkid
) == 0) {
705 /* interface is in use by a non-global zone. */
706 return (IPADM_IF_INUSE
);
710 /* loopback interfaces are just added as logical interface */
711 bzero(&lifr
, sizeof (lifr
));
712 islo
= i_ipadm_is_loopback(ifname
);
713 if (islo
|| i_ipadm_get_lnum(ifname
) != 0) {
714 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
716 sock
= iph
->iph_sock
;
718 sock
= iph
->iph_sock6
;
719 if (islo
&& ioctl(sock
, SIOCGLIFADDR
, (caddr_t
)&lifr
) >= 0)
720 return (IPADM_IF_EXISTS
);
721 if (ioctl(sock
, SIOCLIFADDIF
, (caddr_t
)&lifr
) < 0)
722 return (ipadm_errno2status(errno
));
725 * By default, kernel configures 127.0.0.1 on the loopback
726 * interface. Replace this with 0.0.0.0 to be consistent
727 * with interface creation on other physical interfaces.
729 if (islo
&& !legacy
) {
730 bzero(&lifr
.lifr_addr
, sizeof (lifr
.lifr_addr
));
731 lifr
.lifr_addr
.ss_family
= af
;
732 if (ioctl(sock
, SIOCSLIFADDR
, (caddr_t
)&lifr
) < 0)
733 return (ipadm_errno2status(errno
));
735 status
= i_ipadm_persist_if(iph
, ifname
, af
);
736 if (status
!= IPADM_SUCCESS
) {
737 (void) i_ipadm_delete_if(iph
, ifname
,
738 af
, IPADM_OPT_ACTIVE
);
745 dlpi_flags
= DLPI_NOATTACH
;
748 * If IPADM_OPT_IPMP is specified, then this is a request
749 * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply
750 * pass "ipmpstub0" as devname since an admin *could* have a normal
751 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
753 if (ipadm_flags
& IPADM_OPT_IPMP
) {
754 dlpi_flags
|= DLPI_DEVONLY
;
755 linkname
= "ipmpstub0";
758 * Verify that the user is not creating a persistent
759 * IP interface on a non-persistent data-link.
761 if (!i_ipadm_is_vni(ifname
) && dlstatus
== DLADM_STATUS_OK
&&
762 is_persistent
&& !(dlflags
& DLADM_OPT_PERSIST
)) {
763 return (IPADM_TEMPORARY_OBJ
);
769 * We use DLPI_NOATTACH because the ip module will do the attach
770 * itself for DLPI style-2 devices.
772 if (dlpi_open(linkname
, &dh_ip
, dlpi_flags
) != DLPI_SUCCESS
)
773 return (IPADM_DLPI_FAILURE
);
774 ip_fd
= dlpi_fd(dh_ip
);
775 if (ioctl(ip_fd
, I_PUSH
, IP_MOD_NAME
) == -1) {
776 status
= ipadm_errno2status(errno
);
781 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications
782 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL.
786 /* Set the name string and the IFF_IPV* flag */
792 * With the legacy method, the link-local address should be
793 * configured as part of the interface plumb, using the default
794 * token. If IPH_LEGACY is not specified, we want to set :: as
795 * the address and require the admin to explicitly call
796 * ipadm_create_addr() with the address object type set to
797 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address
798 * as well as the autoconfigured addresses.
800 if (!legacy
&& !i_ipadm_is_6to4(iph
, ifname
))
801 ifflags
|= IFF_NOLINKLOCAL
;
803 (void) strlcpy(newif
, ifname
, sizeof (newif
));
804 status
= i_ipadm_slifname(iph
, ifname
, newif
, ifflags
, ip_fd
,
806 if (status
!= IPADM_SUCCESS
)
809 /* Get the full set of existing flags for this stream */
810 status
= i_ipadm_get_flags(iph
, newif
, af
, &ifflags
);
811 if (status
!= IPADM_SUCCESS
)
814 udp_dev_name
= (af
== AF_INET6
? UDP6_DEV_NAME
: UDP_DEV_NAME
);
815 status
= ipadm_open_arp_on_udp(udp_dev_name
, &mux_fd
);
816 if (status
!= IPADM_SUCCESS
)
819 /* Check if arp is not needed */
820 if (ifflags
& (IFF_NOARP
|IFF_IPV6
)) {
822 * PLINK the interface stream so that the application can exit
823 * without tearing down the stream.
825 if ((ip_muxid
= ioctl(mux_fd
, I_PLINK
, ip_fd
)) == -1)
826 status
= ipadm_errno2status(errno
);
831 * This interface does use ARP, so set up a separate stream
832 * from the interface to ARP.
834 * We use DLPI_NOATTACH because the arp module will do the attach
835 * itself for DLPI style-2 devices.
837 if (dlpi_open(linkname
, &dh_arp
, dlpi_flags
) != DLPI_SUCCESS
) {
838 status
= IPADM_DLPI_FAILURE
;
842 arp_fd
= dlpi_fd(dh_arp
);
843 if (ioctl(arp_fd
, I_PUSH
, ARP_MOD_NAME
) == -1) {
844 status
= ipadm_errno2status(errno
);
848 status
= i_ipadm_slifname_arp(newif
, ifflags
, arp_fd
);
849 if (status
!= IPADM_SUCCESS
)
852 * PLINK the IP and ARP streams so that ifconfig can exit
853 * without tearing down the stream.
855 if ((ip_muxid
= ioctl(mux_fd
, I_PLINK
, ip_fd
)) == -1) {
856 status
= ipadm_errno2status(errno
);
860 if (ioctl(mux_fd
, I_PLINK
, arp_fd
) < 0) {
861 status
= ipadm_errno2status(errno
);
862 (void) ioctl(mux_fd
, I_PUNLINK
, ip_muxid
);
871 (void) close(mux_fd
);
873 if (status
== IPADM_SUCCESS
) {
874 /* copy back new ifname */
875 (void) strlcpy(ifname
, newif
, LIFNAMSIZ
);
877 * If it is a 6to4 tunnel, create a default
878 * addrobj name for the default address on the 0'th
879 * logical interface and set IFF_UP in the interface flags.
881 if (i_ipadm_is_6to4(iph
, ifname
)) {
882 struct ipadm_addrobj_s addr
;
884 i_ipadm_init_addr(&addr
, ifname
, "", IPADM_ADDR_STATIC
);
886 status
= i_ipadm_lookupadd_addrobj(iph
, &addr
);
887 if (status
!= IPADM_SUCCESS
)
889 status
= ipadm_add_aobjname(iph
, ifname
,
890 af
, addr
.ipadm_aobjname
, IPADM_ADDR_STATIC
, 0);
891 if (status
!= IPADM_SUCCESS
)
893 addr
.ipadm_lifnum
= 0;
894 i_ipadm_addrobj2lifname(&addr
, lifname
,
896 status
= i_ipadm_set_flags(iph
, lifname
, af
,
898 if (status
!= IPADM_SUCCESS
)
902 * Prevent static IPv6 addresses from triggering
903 * autoconf. This does not have to be done for
904 * 6to4 tunnel interfaces, since in.ndpd will
905 * not autoconfigure those interfaces.
907 if (af
== AF_INET6
&& !legacy
)
908 (void) i_ipadm_disable_autoconf(newif
);
912 * If IPADM_OPT_PERSIST was set in flags, store the
913 * interface in persistent DB.
916 status
= i_ipadm_persist_if(iph
, newif
, af
);
917 if (status
!= IPADM_SUCCESS
) {
918 (void) i_ipadm_delete_if(iph
, newif
, af
,
923 if (status
== IPADM_EXISTS
)
924 status
= IPADM_IF_EXISTS
;
929 * Unplumbs the interface in `ifname' of family `af'.
932 i_ipadm_unplumb_if(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
)
934 int ip_muxid
, arp_muxid
;
939 boolean_t changed_arp_muxid
= B_FALSE
;
942 ipadm_status_t ret
= IPADM_SUCCESS
;
944 lifgroupinfo_t lifgr
;
945 ifaddrlistx_t
*ifaddrs
, *ifaddrp
;
946 boolean_t v6
= (af
== AF_INET6
);
948 /* Just do SIOCLIFREMOVEIF on loopback interfaces */
949 bzero(&lifr
, sizeof (lifr
));
950 if (i_ipadm_is_loopback(ifname
) ||
951 (i_ipadm_get_lnum(ifname
) != 0 && (iph
->iph_flags
& IPH_LEGACY
))) {
952 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
953 if (ioctl((af
== AF_INET
) ? iph
->iph_sock
: iph
->iph_sock6
,
954 SIOCLIFREMOVEIF
, (caddr_t
)&lifr
) < 0) {
955 return (ipadm_errno2status(errno
));
957 return (IPADM_SUCCESS
);
961 * We used /dev/udp or udp6 to set up the mux. So we have to use
962 * the same now for PUNLINK also.
965 udp_dev_name
= UDP6_DEV_NAME
;
966 sock
= iph
->iph_sock6
;
968 udp_dev_name
= UDP_DEV_NAME
;
969 sock
= iph
->iph_sock
;
971 if ((muxid_fd
= open(udp_dev_name
, O_RDWR
)) == -1) {
972 ret
= ipadm_errno2status(errno
);
975 ret
= ipadm_open_arp_on_udp(udp_dev_name
, &mux_fd
);
976 if (ret
!= IPADM_SUCCESS
)
978 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
979 if (ioctl(muxid_fd
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
980 ret
= ipadm_errno2status(errno
);
983 flags
= lifr
.lifr_flags
;
985 if (flags
& IFF_IPMP
) {
987 * There are two reasons the I_PUNLINK can fail with EBUSY:
988 * (1) if IP interfaces are in the group, or (2) if IPMP data
989 * addresses are administratively up. For case (1), we fail
990 * here with a specific error message. For case (2), we bring
991 * down the addresses prior to doing the I_PUNLINK. If the
992 * I_PUNLINK still fails with EBUSY then the configuration
993 * must have changed after our checks, in which case we branch
994 * back up to `again' and rerun this logic. The net effect is
995 * that unplumbing an IPMP interface will only fail with EBUSY
996 * if IP interfaces are in the group.
998 if (ioctl(sock
, SIOCGLIFGROUPNAME
, &lifr
) == -1) {
999 ret
= ipadm_errno2status(errno
);
1002 (void) strlcpy(lifgr
.gi_grname
, lifr
.lifr_groupname
,
1004 if (ioctl(sock
, SIOCGLIFGROUPINFO
, &lifgr
) == -1) {
1005 ret
= ipadm_errno2status(errno
);
1008 if ((v6
&& lifgr
.gi_nv6
!= 0) || (!v6
&& lifgr
.gi_nv4
!= 0)) {
1009 ret
= IPADM_GRP_NOTEMPTY
;
1014 * The kernel will fail the I_PUNLINK if the IPMP interface
1015 * has administratively up addresses; bring them down.
1017 if (ifaddrlistx(ifname
, IFF_UP
|IFF_DUPLICATE
,
1018 0, &ifaddrs
) == -1) {
1019 ret
= ipadm_errno2status(errno
);
1023 for (; ifaddrp
!= NULL
; ifaddrp
= ifaddrp
->ia_next
) {
1024 int sock
= (ifaddrp
->ia_flags
& IFF_IPV4
) ?
1025 iph
->iph_sock
: iph
->iph_sock6
;
1026 struct lifreq lifrl
;
1028 if (((ifaddrp
->ia_flags
& IFF_IPV6
) && !v6
) ||
1029 (!(ifaddrp
->ia_flags
& IFF_IPV6
) && v6
))
1032 bzero(&lifrl
, sizeof (lifrl
));
1033 (void) strlcpy(lifrl
.lifr_name
, ifaddrp
->ia_name
,
1034 sizeof (lifrl
.lifr_name
));
1035 if (ioctl(sock
, SIOCGLIFFLAGS
, &lifrl
) < 0) {
1036 ret
= ipadm_errno2status(errno
);
1037 ifaddrlistx_free(ifaddrs
);
1040 if (lifrl
.lifr_flags
& IFF_UP
) {
1041 ret
= i_ipadm_set_flags(iph
, lifrl
.lifr_name
,
1042 ((lifrl
.lifr_flags
& IFF_IPV4
) ? AF_INET
:
1043 AF_INET6
), 0, IFF_UP
);
1044 if (ret
!= IPADM_SUCCESS
) {
1045 ifaddrlistx_free(ifaddrs
);
1048 } else if (lifrl
.lifr_flags
& IFF_DUPLICATE
) {
1049 if (ioctl(sock
, SIOCGLIFADDR
, &lifrl
) < 0 ||
1050 ioctl(sock
, SIOCSLIFADDR
, &lifrl
) < 0) {
1051 ret
= ipadm_errno2status(errno
);
1052 ifaddrlistx_free(ifaddrs
);
1057 ifaddrlistx_free(ifaddrs
);
1060 if (ioctl(muxid_fd
, SIOCGLIFMUXID
, (caddr_t
)&lifr
) < 0) {
1061 ret
= ipadm_errno2status(errno
);
1064 arp_muxid
= lifr
.lifr_arp_muxid
;
1065 ip_muxid
= lifr
.lifr_ip_muxid
;
1068 * We don't have a good way of knowing whether the arp stream is
1069 * plumbed. We can't rely on IFF_NOARP because someone could
1070 * have turned it off later using "ifconfig xxx -arp".
1072 if (arp_muxid
!= 0) {
1073 if (ioctl(mux_fd
, I_PUNLINK
, arp_muxid
) < 0) {
1075 * See the comment before the SIOCGLIFGROUPNAME call.
1077 if (errno
== EBUSY
&& (flags
& IFF_IPMP
))
1080 if ((errno
== EINVAL
) &&
1081 (flags
& (IFF_NOARP
| IFF_IPV6
))) {
1083 * Some plumbing utilities set the muxid to
1084 * -1 or some invalid value to signify that
1085 * there is no arp stream. Set the muxid to 0
1086 * before trying to unplumb the IP stream.
1087 * IP does not allow the IP stream to be
1088 * unplumbed if it sees a non-null arp muxid,
1089 * for consistency of IP-ARP streams.
1091 lifr
.lifr_arp_muxid
= 0;
1092 (void) ioctl(muxid_fd
, SIOCSLIFMUXID
,
1094 changed_arp_muxid
= B_TRUE
;
1097 * In case of any other error, we continue with
1103 if (ioctl(mux_fd
, I_PUNLINK
, ip_muxid
) < 0) {
1104 if (changed_arp_muxid
) {
1106 * Some error occurred, and we need to restore
1107 * everything back to what it was.
1110 lifr
.lifr_arp_muxid
= arp_muxid
;
1111 lifr
.lifr_ip_muxid
= ip_muxid
;
1112 (void) ioctl(muxid_fd
, SIOCSLIFMUXID
, (caddr_t
)&lifr
);
1116 * See the comment before the SIOCGLIFGROUPNAME call.
1118 if (errno
== EBUSY
&& (flags
& IFF_IPMP
))
1121 ret
= ipadm_errno2status(errno
);
1125 (void) close(muxid_fd
);
1127 (void) close(mux_fd
);
1129 if (af
== AF_INET6
&& ret
== IPADM_SUCCESS
) {
1131 * in.ndpd maintains the phyints in its memory even after
1132 * the interface is plumbed, so that it can be reused when
1133 * the interface gets plumbed again. The default behavior
1134 * of in.ndpd is to start autoconfiguration for an interface
1135 * that gets plumbed. We need to send the
1136 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
1137 * default behavior on replumb.
1139 (void) i_ipadm_enable_autoconf(ifname
);
1145 * Saves the given interface name `ifname' with address family `af' in
1148 static ipadm_status_t
1149 i_ipadm_persist_if(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
)
1151 ipmgmt_if_arg_t ifarg
;
1154 (void) strlcpy(ifarg
.ia_ifname
, ifname
, sizeof (ifarg
.ia_ifname
));
1155 ifarg
.ia_family
= af
;
1156 ifarg
.ia_cmd
= IPMGMT_CMD_SETIF
;
1157 ifarg
.ia_flags
= IPMGMT_PERSIST
;
1158 err
= ipadm_door_call(iph
, &ifarg
, sizeof (ifarg
), NULL
, 0, B_FALSE
);
1159 return (ipadm_errno2status(err
));
1163 * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1164 * is set in `ipadm_flags', it is also removed from persistent configuration.
1167 i_ipadm_delete_if(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
,
1168 uint32_t ipadm_flags
)
1170 ipadm_status_t ret
= IPADM_SUCCESS
;
1171 ipadm_status_t db_status
;
1172 char tmp_ifname
[LIFNAMSIZ
];
1174 struct ipadm_addrobj_s ipaddr
;
1175 boolean_t is_persistent
=
1176 (ipadm_flags
& IPADM_OPT_PERSIST
);
1178 ret
= i_ipadm_unplumb_if(iph
, ifname
, af
);
1179 if (ret
!= IPADM_SUCCESS
)
1182 cp
= strrchr(ifname
, IPADM_LOGICAL_SEP
);
1184 assert(iph
->iph_flags
& IPH_LEGACY
);
1186 * This is a non-zero logical interface.
1187 * Find the addrobj and remove it from the daemon's memory.
1189 (void) strlcpy(tmp_ifname
, ifname
, sizeof (tmp_ifname
));
1190 tmp_ifname
[cp
- ifname
] = '\0';
1192 ipaddr
.ipadm_lifnum
= atoi(cp
);
1193 (void) strlcpy(ipaddr
.ipadm_ifname
, tmp_ifname
,
1194 sizeof (ipaddr
.ipadm_ifname
));
1195 ipaddr
.ipadm_af
= af
;
1196 ret
= i_ipadm_get_lif2addrobj(iph
, &ipaddr
);
1197 if (ret
== IPADM_SUCCESS
) {
1198 ret
= i_ipadm_delete_addrobj(iph
, &ipaddr
,
1200 } else if (ret
== IPADM_NOTFOUND
) {
1201 ret
= IPADM_SUCCESS
;
1207 * Even if interface does not exist, remove all its addresses and
1208 * properties from the persistent store. If interface does not
1209 * exist both in kernel and the persistent store, return IPADM_ENXIO.
1211 if ((ret
== IPADM_ENXIO
&& is_persistent
) || ret
== IPADM_SUCCESS
) {
1212 db_status
= i_ipadm_delete_ifobj(iph
, ifname
, af
,
1214 if (db_status
== IPADM_SUCCESS
)
1215 ret
= IPADM_SUCCESS
;
1222 * Resets all addresses on interface `ifname' with address family `af'
1223 * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties
1224 * and address objects of `ifname' for `af' are also removed from the
1228 i_ipadm_delete_ifobj(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
,
1229 boolean_t is_persistent
)
1231 ipmgmt_if_arg_t ifarg
;
1234 ifarg
.ia_cmd
= IPMGMT_CMD_RESETIF
;
1235 ifarg
.ia_flags
= IPMGMT_ACTIVE
;
1237 ifarg
.ia_flags
|= IPMGMT_PERSIST
;
1238 ifarg
.ia_family
= af
;
1239 (void) strlcpy(ifarg
.ia_ifname
, ifname
, LIFNAMSIZ
);
1241 err
= ipadm_door_call(iph
, &ifarg
, sizeof (ifarg
), NULL
, 0, B_FALSE
);
1242 return (ipadm_errno2status(err
));
1246 * Create the interface by plumbing it for IP.
1247 * This function will check if there is saved configuration information
1248 * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
1249 * for `ifname' is taken.
1252 i_ipadm_create_if(ipadm_handle_t iph
, char *ifname
, sa_family_t af
,
1253 uint32_t ipadm_flags
)
1255 ipadm_status_t status
;
1257 sa_family_t other_af
;
1260 * Return error, if the interface already exists in either the active
1261 * or the persistent configuration.
1263 if (ipadm_if_enabled(iph
, ifname
, af
))
1264 return (IPADM_IF_EXISTS
);
1266 if (!(iph
->iph_flags
& IPH_LEGACY
)) {
1267 status
= i_ipadm_if_pexists(iph
, ifname
, af
, &p_exists
);
1268 if (status
!= IPADM_SUCCESS
)
1270 other_af
= (af
== AF_INET
? AF_INET6
: AF_INET
);
1272 if (!ipadm_if_enabled(iph
, ifname
, other_af
))
1273 return (IPADM_OP_DISABLE_OBJ
);
1275 ipadm_flags
&= ~IPADM_OPT_PERSIST
;
1279 return (i_ipadm_plumb_if(iph
, ifname
, af
, ipadm_flags
));
1283 * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1284 * default, unless a value in `af' is specified. The interface may be plumbed
1285 * only if there is no previously saved persistent configuration information
1286 * for the interface (in which case the ipadm_enable_if() function must
1287 * be used to enable the interface).
1289 * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
1290 * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
1291 * or appropriate ipadm_status_t corresponding to the errno.
1293 * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
1294 * be over-written with the actual interface name when a PPA has to be
1295 * internally generated by the library.
1298 ipadm_create_if(ipadm_handle_t iph
, char *ifname
, sa_family_t af
,
1301 ipadm_status_t status
;
1302 boolean_t created_v4
= B_FALSE
;
1303 char newifname
[LIFNAMSIZ
];
1305 /* Check for the required authorization */
1306 if (!ipadm_check_auth())
1307 return (IPADM_EAUTH
);
1309 if (flags
== 0 || ((flags
& IPADM_OPT_PERSIST
) &&
1310 !(flags
& IPADM_OPT_ACTIVE
)) ||
1311 (flags
& ~(IPADM_COMMON_OPT_MASK
| IPADM_OPT_IPMP
|
1312 IPADM_OPT_GENPPA
))) {
1313 return (IPADM_INVALID_ARG
);
1315 if (flags
& IPADM_OPT_GENPPA
) {
1316 if (snprintf(newifname
, LIFNAMSIZ
, "%s0", ifname
) >=
1318 return (IPADM_INVALID_ARG
);
1320 if (strlcpy(newifname
, ifname
, LIFNAMSIZ
) >= LIFNAMSIZ
)
1321 return (IPADM_INVALID_ARG
);
1324 if (!i_ipadm_validate_ifname(iph
, newifname
))
1325 return (IPADM_INVALID_ARG
);
1327 if ((af
== AF_INET
|| af
== AF_UNSPEC
) &&
1328 !i_ipadm_is_6to4(iph
, ifname
)) {
1329 status
= i_ipadm_create_if(iph
, ifname
, AF_INET
, flags
);
1330 if (status
!= IPADM_SUCCESS
)
1332 created_v4
= B_TRUE
;
1334 if (af
== AF_INET6
|| af
== AF_UNSPEC
) {
1335 status
= i_ipadm_create_if(iph
, ifname
, AF_INET6
, flags
);
1336 if (status
!= IPADM_SUCCESS
) {
1338 (void) i_ipadm_delete_if(iph
, ifname
, AF_INET
,
1345 return (IPADM_SUCCESS
);
1349 * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1350 * when `af' = AF_UNSPEC.
1353 ipadm_delete_if(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
,
1356 ipadm_status_t status1
= IPADM_SUCCESS
;
1357 ipadm_status_t status2
= IPADM_SUCCESS
;
1358 ipadm_status_t other
;
1360 /* Check for the required authorization */
1361 if (!ipadm_check_auth())
1362 return (IPADM_EAUTH
);
1364 /* Validate the `ifname' for any logical interface. */
1365 if (flags
== 0 || (flags
& ~(IPADM_COMMON_OPT_MASK
)) ||
1366 !i_ipadm_validate_ifname(iph
, ifname
))
1367 return (IPADM_INVALID_ARG
);
1369 if (af
== AF_INET
|| af
== AF_UNSPEC
)
1370 status1
= i_ipadm_delete_if(iph
, ifname
, AF_INET
, flags
);
1371 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
1372 status2
= i_ipadm_delete_if(iph
, ifname
, AF_INET6
, flags
);
1374 * If the family has been uniquely identified, we return the
1375 * associated status, even if that is ENXIO. Calls from ifconfig
1376 * which can only unplumb one of IPv4/IPv6 at any time fall under
1381 else if (af
== AF_INET6
)
1383 else if (af
!= AF_UNSPEC
)
1384 return (IPADM_INVALID_ARG
);
1387 * If af is AF_UNSPEC, then we return the following:
1388 * status1, if status1 == status2
1389 * IPADM_SUCCESS, if either of status1 or status2 is SUCCESS
1390 * and the other status is ENXIO
1391 * IPADM_ENXIO, if both status1 and status2 are ENXIO
1392 * IPADM_FAILURE otherwise.
1394 if (status1
== status2
) {
1395 /* covers the case when both status1 and status2 are ENXIO */
1397 } else if (status1
== IPADM_SUCCESS
|| status2
== IPADM_SUCCESS
) {
1398 if (status1
== IPADM_SUCCESS
)
1402 return (other
== IPADM_ENXIO
? IPADM_SUCCESS
: IPADM_FAILURE
);
1404 return (IPADM_FAILURE
);
1409 * Returns information about all interfaces in both active and persistent
1410 * configuration. If `ifname' is not NULL, it returns only the interface
1411 * identified by `ifname'.
1414 * On success: IPADM_SUCCESS.
1415 * On error : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE.
1418 ipadm_if_info(ipadm_handle_t iph
, const char *ifname
,
1419 ipadm_if_info_t
**if_info
, uint32_t flags
, int64_t lifc_flags
)
1421 ipadm_status_t status
;
1424 if (if_info
== NULL
|| iph
== NULL
|| flags
!= 0)
1425 return (IPADM_INVALID_ARG
);
1427 if (ifname
!= NULL
&&
1428 (!ifparse_ifspec(ifname
, &ifsp
) || ifsp
.ifsp_lunvalid
)) {
1429 return (IPADM_INVALID_ARG
);
1432 status
= i_ipadm_get_all_if_info(iph
, ifname
, if_info
, lifc_flags
);
1433 if (status
!= IPADM_SUCCESS
)
1435 if (ifname
!= NULL
&& *if_info
== NULL
)
1436 return (IPADM_ENXIO
);
1438 return (IPADM_SUCCESS
);
1442 * Frees the linked list allocated by ipadm_if_info().
1445 ipadm_free_if_info(ipadm_if_info_t
*ifinfo
)
1447 ipadm_if_info_t
*ifinfo_next
;
1449 for (; ifinfo
!= NULL
; ifinfo
= ifinfo_next
) {
1450 ifinfo_next
= ifinfo
->ifi_next
;
1456 * Re-enable the interface `ifname' based on the saved configuration
1460 ipadm_enable_if(ipadm_handle_t iph
, const char *ifname
, uint32_t flags
)
1463 ipadm_status_t status
;
1466 /* Check for the required authorization */
1467 if (!ipadm_check_auth())
1468 return (IPADM_EAUTH
);
1470 /* Check for logical interfaces. */
1471 if (!ifparse_ifspec(ifname
, &ifsp
) || ifsp
.ifsp_lunvalid
)
1472 return (IPADM_INVALID_ARG
);
1474 /* Enabling an interface persistently is not supported. */
1475 if (flags
& IPADM_OPT_PERSIST
)
1476 return (IPADM_NOTSUP
);
1479 * Return early by checking if the interface is already enabled.
1481 if (ipadm_if_enabled(iph
, ifname
, AF_INET
) &&
1482 ipadm_if_enabled(iph
, ifname
, AF_INET6
)) {
1483 return (IPADM_IF_EXISTS
);
1486 * Enable the interface and restore all its interface properties
1487 * and address objects.
1489 status
= i_ipadm_init_ifs(iph
, ifname
, &ifnvl
);
1490 if (status
!= IPADM_SUCCESS
)
1493 assert(ifnvl
!= NULL
);
1495 * ipadm_enable_if() does exactly what ipadm_init_ifs() does,
1496 * but only for one interface. We need to set IPH_INIT because
1497 * ipmgmtd daemon does not have to write the interface to persistent
1498 * db. The interface is already available in persistent db
1499 * and we are here to re-enable the persistent configuration.
1501 iph
->iph_flags
|= IPH_INIT
;
1502 status
= i_ipadm_init_ifobj(iph
, ifname
, ifnvl
);
1503 iph
->iph_flags
&= ~IPH_INIT
;
1510 * Disable the interface `ifname' by removing it from the active configuration.
1511 * Error code return values follow the model in ipadm_delete_if()
1514 ipadm_disable_if(ipadm_handle_t iph
, const char *ifname
, uint32_t flags
)
1516 ipadm_status_t status1
, status2
, other
;
1519 /* Check for the required authorization */
1520 if (!ipadm_check_auth())
1521 return (IPADM_EAUTH
);
1523 /* Check for logical interfaces. */
1524 if (!ifparse_ifspec(ifname
, &ifsp
) || ifsp
.ifsp_lunvalid
)
1525 return (IPADM_INVALID_ARG
);
1527 /* Disabling an interface persistently is not supported. */
1528 if (flags
& IPADM_OPT_PERSIST
)
1529 return (IPADM_NOTSUP
);
1531 status1
= i_ipadm_unplumb_if(iph
, ifname
, AF_INET6
);
1532 if (status1
== IPADM_SUCCESS
)
1533 status1
= i_ipadm_delete_ifobj(iph
, ifname
, AF_INET6
, B_FALSE
);
1534 status2
= i_ipadm_unplumb_if(iph
, ifname
, AF_INET
);
1535 if (status2
== IPADM_SUCCESS
)
1536 status2
= i_ipadm_delete_ifobj(iph
, ifname
, AF_INET
, B_FALSE
);
1537 if (status1
== status2
) {
1539 } else if (status1
== IPADM_SUCCESS
|| status2
== IPADM_SUCCESS
) {
1540 if (status1
== IPADM_SUCCESS
)
1544 return (other
== IPADM_ENXIO
? IPADM_SUCCESS
: IPADM_FAILURE
);
1546 return (IPADM_FAILURE
);
1551 * This workaround is until libipadm supports IPMP and is required whenever an
1552 * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
1553 * yet, we will have to update the daemon's in-memory mapping of
1554 * `aobjname' to 'lifnum'.
1556 * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1557 * door_call(3C) fails. Also, there is no use in returning error because
1558 * `ifname' would have been successfuly moved into IPMP group, by this time.
1561 ipadm_if_move(ipadm_handle_t iph
, const char *ifname
)
1563 (void) i_ipadm_delete_ifobj(iph
, ifname
, AF_INET
, B_FALSE
);
1564 (void) i_ipadm_delete_ifobj(iph
, ifname
, AF_INET6
, B_FALSE
);