xref: /onnv-gate/usr/src/cmd/cmd-inet/lib/nwamd/ncu_ip.c (revision 13107:0e16e468e300)
111767SAnurag.Maskey@Sun.COM /*
211767SAnurag.Maskey@Sun.COM  * CDDL HEADER START
311767SAnurag.Maskey@Sun.COM  *
411767SAnurag.Maskey@Sun.COM  * The contents of this file are subject to the terms of the
511767SAnurag.Maskey@Sun.COM  * Common Development and Distribution License (the "License").
611767SAnurag.Maskey@Sun.COM  * You may not use this file except in compliance with the License.
711767SAnurag.Maskey@Sun.COM  *
811767SAnurag.Maskey@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911767SAnurag.Maskey@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011767SAnurag.Maskey@Sun.COM  * See the License for the specific language governing permissions
1111767SAnurag.Maskey@Sun.COM  * and limitations under the License.
1211767SAnurag.Maskey@Sun.COM  *
1311767SAnurag.Maskey@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411767SAnurag.Maskey@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511767SAnurag.Maskey@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611767SAnurag.Maskey@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711767SAnurag.Maskey@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811767SAnurag.Maskey@Sun.COM  *
1911767SAnurag.Maskey@Sun.COM  * CDDL HEADER END
2011767SAnurag.Maskey@Sun.COM  */
2111767SAnurag.Maskey@Sun.COM 
2211767SAnurag.Maskey@Sun.COM /*
2312576SAnurag.Maskey@Oracle.COM  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2411767SAnurag.Maskey@Sun.COM  */
2511767SAnurag.Maskey@Sun.COM 
2611767SAnurag.Maskey@Sun.COM #include <arpa/inet.h>
2711767SAnurag.Maskey@Sun.COM #include <assert.h>
2811767SAnurag.Maskey@Sun.COM #include <dhcpagent_ipc.h>
2911767SAnurag.Maskey@Sun.COM #include <dhcp_inittab.h>
3011767SAnurag.Maskey@Sun.COM #include <dhcp_symbol.h>
3111767SAnurag.Maskey@Sun.COM #include <dhcpagent_util.h>
3211767SAnurag.Maskey@Sun.COM #include <errno.h>
3311767SAnurag.Maskey@Sun.COM #include <execinfo.h>
3411767SAnurag.Maskey@Sun.COM #include <libnwam.h>
3511767SAnurag.Maskey@Sun.COM #include <stdlib.h>
3611767SAnurag.Maskey@Sun.COM #include <strings.h>
3711767SAnurag.Maskey@Sun.COM #include <ucontext.h>
3811767SAnurag.Maskey@Sun.COM #include <unistd.h>
3911767SAnurag.Maskey@Sun.COM #include <libscf.h>
4011767SAnurag.Maskey@Sun.COM 
4111767SAnurag.Maskey@Sun.COM #include "conditions.h"
4211767SAnurag.Maskey@Sun.COM #include "events.h"
4311767SAnurag.Maskey@Sun.COM #include "ncp.h"
4411767SAnurag.Maskey@Sun.COM #include "ncu.h"
4511767SAnurag.Maskey@Sun.COM #include "objects.h"
4611767SAnurag.Maskey@Sun.COM #include "util.h"
4711767SAnurag.Maskey@Sun.COM 
4811767SAnurag.Maskey@Sun.COM /*
4911767SAnurag.Maskey@Sun.COM  * ncu_ip.c - contains routines that are IP interface-specific for NCUs.
5011767SAnurag.Maskey@Sun.COM  */
5111767SAnurag.Maskey@Sun.COM 
5211767SAnurag.Maskey@Sun.COM #define	STATELESS_RUNNING	(IFF_RUNNING | IFF_UP | IFF_ADDRCONF)
5311767SAnurag.Maskey@Sun.COM #define	DHCP_RUNNING		(IFF_RUNNING | IFF_UP | IFF_DHCPRUNNING)
5411767SAnurag.Maskey@Sun.COM 
5512576SAnurag.Maskey@Oracle.COM static void nwamd_dhcp(const char *, ipadm_addrobj_t, dhcp_ipc_type_t);
5612576SAnurag.Maskey@Oracle.COM static void nwamd_down_interface(const char *, ipadm_addr_type_t, const char *);
5711767SAnurag.Maskey@Sun.COM static boolean_t stateless_running(const nwamd_ncu_t *);
5811767SAnurag.Maskey@Sun.COM 
5912576SAnurag.Maskey@Oracle.COM /*
6012576SAnurag.Maskey@Oracle.COM  * Given a sockaddr representation of an IPv4 or IPv6 address returns the
6112576SAnurag.Maskey@Oracle.COM  * string representation. Note that 'sockaddr' should point at the correct
6212576SAnurag.Maskey@Oracle.COM  * sockaddr structure for the address family (sockaddr_in for AF_INET or
6312576SAnurag.Maskey@Oracle.COM  * sockaddr_in6 for AF_INET6) or alternatively at a sockaddr_storage
6412576SAnurag.Maskey@Oracle.COM  * structure.
6512576SAnurag.Maskey@Oracle.COM  */
6612576SAnurag.Maskey@Oracle.COM static const char *
nwamd_sockaddr2str(const struct sockaddr * addr,char * str,size_t len)6712576SAnurag.Maskey@Oracle.COM nwamd_sockaddr2str(const struct sockaddr *addr, char *str, size_t len)
6811767SAnurag.Maskey@Sun.COM {
6912576SAnurag.Maskey@Oracle.COM 	struct sockaddr_in *sin;
7012576SAnurag.Maskey@Oracle.COM 	struct sockaddr_in6 *sin6;
7112576SAnurag.Maskey@Oracle.COM 	const char *straddr;
7212576SAnurag.Maskey@Oracle.COM 
7312576SAnurag.Maskey@Oracle.COM 	if (addr == NULL)
7411767SAnurag.Maskey@Sun.COM 		return (NULL);
7512576SAnurag.Maskey@Oracle.COM 
7612576SAnurag.Maskey@Oracle.COM 	if (addr->sa_family == AF_INET) {
7712576SAnurag.Maskey@Oracle.COM 		/* LINTED E_BAD_PTR_CAST_ALIGN */
7812576SAnurag.Maskey@Oracle.COM 		sin = (struct sockaddr_in *)addr;
7912576SAnurag.Maskey@Oracle.COM 		straddr = inet_ntop(AF_INET, (void *)&sin->sin_addr, str, len);
8012576SAnurag.Maskey@Oracle.COM 	} else if (addr->sa_family == AF_INET6) {
8112576SAnurag.Maskey@Oracle.COM 		/* LINTED E_BAD_PTR_CAST_ALIGN */
8212576SAnurag.Maskey@Oracle.COM 		sin6 = (struct sockaddr_in6 *)addr;
8312576SAnurag.Maskey@Oracle.COM 		straddr = inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, str,
8412576SAnurag.Maskey@Oracle.COM 		    len);
8511767SAnurag.Maskey@Sun.COM 	} else {
8612576SAnurag.Maskey@Oracle.COM 		errno = EINVAL;
8712576SAnurag.Maskey@Oracle.COM 		return (NULL);
8811767SAnurag.Maskey@Sun.COM 	}
8912576SAnurag.Maskey@Oracle.COM 	return (straddr != NULL ? str : NULL);
9011767SAnurag.Maskey@Sun.COM }
9111767SAnurag.Maskey@Sun.COM 
9211767SAnurag.Maskey@Sun.COM void
nwamd_propogate_link_up_down_to_ip(const char * linkname,boolean_t up)9311767SAnurag.Maskey@Sun.COM nwamd_propogate_link_up_down_to_ip(const char *linkname, boolean_t up)
9411767SAnurag.Maskey@Sun.COM {
9511767SAnurag.Maskey@Sun.COM 	nwamd_object_t ip_ncu = nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE,
9611767SAnurag.Maskey@Sun.COM 	    linkname);
9711767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
9811767SAnurag.Maskey@Sun.COM 
9911767SAnurag.Maskey@Sun.COM 	if (ip_ncu == NULL) {
10011767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_propogate_link_up_down_to_ip: no IP NCU "
10111767SAnurag.Maskey@Sun.COM 		    "for link %s, cannot propogate %s event", linkname,
10211767SAnurag.Maskey@Sun.COM 		    up ? "up" : "down");
10311767SAnurag.Maskey@Sun.COM 		return;
10411767SAnurag.Maskey@Sun.COM 	}
10511767SAnurag.Maskey@Sun.COM 	ncu = ip_ncu->nwamd_object_data;
10611767SAnurag.Maskey@Sun.COM 
10711767SAnurag.Maskey@Sun.COM 	if (ncu->ncu_enabled) {
10811767SAnurag.Maskey@Sun.COM 		if (ip_ncu->nwamd_object_aux_state ==
10911767SAnurag.Maskey@Sun.COM 		    NWAM_AUX_STATE_UNINITIALIZED) {
11011767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG,
11111767SAnurag.Maskey@Sun.COM 			    "nwamd_propogate_link_up_down_to_ip: will not "
11211767SAnurag.Maskey@Sun.COM 			    "propogate link %s event as IP NCU %s is being "
11311767SAnurag.Maskey@Sun.COM 			    "removed", up ? "up" : "down", linkname);
11411767SAnurag.Maskey@Sun.COM 		} else {
11511767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG,
11611767SAnurag.Maskey@Sun.COM 			    "nwamd_propogate_link_up_down_to_ip: propogating "
11711767SAnurag.Maskey@Sun.COM 			    "link %s event to interface %s",
11811767SAnurag.Maskey@Sun.COM 			    up ? "up" : "down", linkname);
11911767SAnurag.Maskey@Sun.COM 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
12011767SAnurag.Maskey@Sun.COM 			    ip_ncu->nwamd_object_name,
12111767SAnurag.Maskey@Sun.COM 			    up ?
12211767SAnurag.Maskey@Sun.COM 			    NWAM_STATE_OFFLINE_TO_ONLINE :
12311767SAnurag.Maskey@Sun.COM 			    NWAM_STATE_ONLINE_TO_OFFLINE,
12411767SAnurag.Maskey@Sun.COM 			    up ? NWAM_AUX_STATE_INITIALIZED :
12511767SAnurag.Maskey@Sun.COM 			    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
12611767SAnurag.Maskey@Sun.COM 		}
12711767SAnurag.Maskey@Sun.COM 	} else {
12811767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG,
12911767SAnurag.Maskey@Sun.COM 		    "nwamd_propogate_link_up_down_to_ip: not propogating "
13011767SAnurag.Maskey@Sun.COM 		    "link %s event to interface %s, IP NCU is disabled",
13111767SAnurag.Maskey@Sun.COM 		    up ? "up" : "down", linkname);
13211767SAnurag.Maskey@Sun.COM 	}
13311767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ip_ncu);
13411767SAnurag.Maskey@Sun.COM }
13511767SAnurag.Maskey@Sun.COM 
13611767SAnurag.Maskey@Sun.COM /*
13711767SAnurag.Maskey@Sun.COM  * Returns the value associated with the given symbol for the given
13811767SAnurag.Maskey@Sun.COM  * interface.  The interface may be NULL, in which case the primary
13911767SAnurag.Maskey@Sun.COM  * interface is used.
14011767SAnurag.Maskey@Sun.COM  * This function substitutes the need to call dhcpinfo(1), thus it is
14111767SAnurag.Maskey@Sun.COM  * very similar to the implementation of dhcpinfo(1).
14211767SAnurag.Maskey@Sun.COM  * When multiple values need to be returned (e.g., nameservers), they
14311767SAnurag.Maskey@Sun.COM  * are separated by a space ' '.
14411767SAnurag.Maskey@Sun.COM  */
14511767SAnurag.Maskey@Sun.COM char *
nwamd_get_dhcpinfo_data(const char * sym_name,char * ifname)14611767SAnurag.Maskey@Sun.COM nwamd_get_dhcpinfo_data(const char *sym_name, char *ifname)
14711767SAnurag.Maskey@Sun.COM {
14811767SAnurag.Maskey@Sun.COM 	dhcp_symbol_t *entry;
14911767SAnurag.Maskey@Sun.COM 	dhcp_optnum_t optnum;
15011767SAnurag.Maskey@Sun.COM 	dhcp_ipc_request_t *request;
15111767SAnurag.Maskey@Sun.COM 	dhcp_ipc_reply_t *reply;
15211767SAnurag.Maskey@Sun.COM 	DHCP_OPT *opt;
15311767SAnurag.Maskey@Sun.COM 	size_t opt_len;
15411767SAnurag.Maskey@Sun.COM 	char *value; /* return value */
15511767SAnurag.Maskey@Sun.COM 	int err;
15611767SAnurag.Maskey@Sun.COM 	char errmsg[LINE_MAX];
15711767SAnurag.Maskey@Sun.COM 
15811767SAnurag.Maskey@Sun.COM 	/* if interface is not given, change it to empty string */
15911767SAnurag.Maskey@Sun.COM 	if (ifname == NULL)
16011767SAnurag.Maskey@Sun.COM 		ifname = "";
16111767SAnurag.Maskey@Sun.COM 
16211767SAnurag.Maskey@Sun.COM 	/* find code and category in dhcp_inittab(4) */
16311767SAnurag.Maskey@Sun.COM 	entry = inittab_getbyname(ITAB_CAT_SITE | ITAB_CAT_STANDARD |
16411767SAnurag.Maskey@Sun.COM 	    ITAB_CAT_VENDOR | ITAB_CAT_FIELD, ITAB_CONS_INFO, sym_name);
16511767SAnurag.Maskey@Sun.COM 
16611767SAnurag.Maskey@Sun.COM 	if (entry == NULL) {
16711767SAnurag.Maskey@Sun.COM 		(void) snprintf(errmsg, LINE_MAX, "unknown identifier: %s",
16811767SAnurag.Maskey@Sun.COM 		    sym_name);
16911767SAnurag.Maskey@Sun.COM 		goto fail;
17011767SAnurag.Maskey@Sun.COM 	}
17111767SAnurag.Maskey@Sun.COM 
17211767SAnurag.Maskey@Sun.COM 	/* allocate request */
17311767SAnurag.Maskey@Sun.COM 	optnum.code = entry->ds_code;
17411767SAnurag.Maskey@Sun.COM 	optnum.category = entry->ds_category;
17511767SAnurag.Maskey@Sun.COM 	optnum.size = entry->ds_max * inittab_type_to_size(entry);
17611767SAnurag.Maskey@Sun.COM 	request = dhcp_ipc_alloc_request(DHCP_GET_TAG, ifname, &optnum,
17711767SAnurag.Maskey@Sun.COM 	    sizeof (dhcp_optnum_t), DHCP_TYPE_OPTNUM);
17811767SAnurag.Maskey@Sun.COM 	if (request == NULL) {
17911767SAnurag.Maskey@Sun.COM 		(void) snprintf(errmsg, LINE_MAX, "failed dhcp alloc request");
18011767SAnurag.Maskey@Sun.COM 		goto fail;
18111767SAnurag.Maskey@Sun.COM 	}
18211767SAnurag.Maskey@Sun.COM 
18311767SAnurag.Maskey@Sun.COM 	/* make the request */
18411767SAnurag.Maskey@Sun.COM 	err = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT);
18511767SAnurag.Maskey@Sun.COM 	if (err != 0 || reply->return_code != 0) {
18611767SAnurag.Maskey@Sun.COM 		(void) snprintf(errmsg, LINE_MAX, "%s",
18711767SAnurag.Maskey@Sun.COM 		    dhcp_ipc_strerror(err == 0 ? reply->return_code : err));
18811767SAnurag.Maskey@Sun.COM 	}
18911767SAnurag.Maskey@Sun.COM 
19011767SAnurag.Maskey@Sun.COM 	/* get data from the reply */
19111767SAnurag.Maskey@Sun.COM 	opt = dhcp_ipc_get_data(reply, &opt_len, NULL);
19211767SAnurag.Maskey@Sun.COM 	if (opt_len == 0) {
19311767SAnurag.Maskey@Sun.COM 		(void) snprintf(errmsg, LINE_MAX, "invalid data");
19411767SAnurag.Maskey@Sun.COM 		goto fail;
19511767SAnurag.Maskey@Sun.COM 	}
19611767SAnurag.Maskey@Sun.COM 
19711767SAnurag.Maskey@Sun.COM 	/* check protocol error */
19811767SAnurag.Maskey@Sun.COM 	if (opt_len < 2 || (opt_len -2 != opt->len)) {
19911767SAnurag.Maskey@Sun.COM 		(void) snprintf(errmsg, LINE_MAX, "data length mismatch");
20011767SAnurag.Maskey@Sun.COM 		goto fail;
20111767SAnurag.Maskey@Sun.COM 	}
20211767SAnurag.Maskey@Sun.COM 	opt_len -= 2;
20311767SAnurag.Maskey@Sun.COM 
20411767SAnurag.Maskey@Sun.COM 	/* decode the data into ascii */
20511767SAnurag.Maskey@Sun.COM 	value = inittab_decode(entry, opt->value, opt_len, B_TRUE);
20611767SAnurag.Maskey@Sun.COM 	if (value == NULL) {
20711767SAnurag.Maskey@Sun.COM 		(void) snprintf(errmsg, LINE_MAX, "cannot decode reply");
20811767SAnurag.Maskey@Sun.COM 		goto fail;
20911767SAnurag.Maskey@Sun.COM 	}
21011767SAnurag.Maskey@Sun.COM 
21111767SAnurag.Maskey@Sun.COM 	free(request);
21211767SAnurag.Maskey@Sun.COM 	free(reply);
21311767SAnurag.Maskey@Sun.COM 	return (value);
21411767SAnurag.Maskey@Sun.COM 
21511767SAnurag.Maskey@Sun.COM fail:
21611767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "get_dhcpinfo_data() failed: %s", errmsg);
21711767SAnurag.Maskey@Sun.COM 	free(request);
21811767SAnurag.Maskey@Sun.COM 	free(reply);
21911767SAnurag.Maskey@Sun.COM 	return (NULL);
22011767SAnurag.Maskey@Sun.COM }
22111767SAnurag.Maskey@Sun.COM 
22211767SAnurag.Maskey@Sun.COM void
nwamd_add_default_routes(nwamd_ncu_t * ncu)22311767SAnurag.Maskey@Sun.COM nwamd_add_default_routes(nwamd_ncu_t *ncu)
22411767SAnurag.Maskey@Sun.COM {
22512576SAnurag.Maskey@Oracle.COM 	nwamd_if_t *nif = &ncu->ncu_if;
22611767SAnurag.Maskey@Sun.COM 	char str[INET6_ADDRSTRLEN];
22711767SAnurag.Maskey@Sun.COM 
22811767SAnurag.Maskey@Sun.COM 	if (nif->nwamd_if_ipv4 && nif->nwamd_if_ipv4_default_route_set) {
22911767SAnurag.Maskey@Sun.COM 		struct sockaddr_in v4dest, v4mask;
23011767SAnurag.Maskey@Sun.COM 
23111767SAnurag.Maskey@Sun.COM 		v4dest.sin_addr.s_addr = htonl(INADDR_ANY);
23211767SAnurag.Maskey@Sun.COM 		v4dest.sin_family = AF_INET;
23311767SAnurag.Maskey@Sun.COM 
23411767SAnurag.Maskey@Sun.COM 		v4mask.sin_addr.s_addr = 0;
23511767SAnurag.Maskey@Sun.COM 		v4mask.sin_family = AF_INET;
23611767SAnurag.Maskey@Sun.COM 
23711767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_add_default_routes: adding default "
23812576SAnurag.Maskey@Oracle.COM 		    "route %s", nwamd_sockaddr2str((struct sockaddr *)
23912576SAnurag.Maskey@Oracle.COM 		    &nif->nwamd_if_ipv4_default_route, str,
24011767SAnurag.Maskey@Sun.COM 		    sizeof (str)));
24111767SAnurag.Maskey@Sun.COM 		nwamd_add_route((struct sockaddr *)&v4dest,
24211767SAnurag.Maskey@Sun.COM 		    (struct sockaddr *)&v4mask,
24311767SAnurag.Maskey@Sun.COM 		    (struct sockaddr *)&nif->nwamd_if_ipv4_default_route,
24411767SAnurag.Maskey@Sun.COM 		    ncu->ncu_name);
24511767SAnurag.Maskey@Sun.COM 	}
24611767SAnurag.Maskey@Sun.COM 
24711767SAnurag.Maskey@Sun.COM 	if (nif->nwamd_if_ipv6 && nif->nwamd_if_ipv6_default_route_set) {
24811767SAnurag.Maskey@Sun.COM 		struct sockaddr_in6 v6dest, v6mask;
24911767SAnurag.Maskey@Sun.COM 
25011767SAnurag.Maskey@Sun.COM 		(void) bzero(&v6dest, sizeof (struct sockaddr_in6));
25111767SAnurag.Maskey@Sun.COM 		v6dest.sin6_family = AF_INET6;
25211767SAnurag.Maskey@Sun.COM 
25311767SAnurag.Maskey@Sun.COM 		(void) bzero(&v6mask, sizeof (struct sockaddr_in6));
25411767SAnurag.Maskey@Sun.COM 		v6mask.sin6_family = AF_INET6;
25511767SAnurag.Maskey@Sun.COM 
25611767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_add_default_routes: adding default "
25712576SAnurag.Maskey@Oracle.COM 		    "route %s", nwamd_sockaddr2str((struct sockaddr *)
25812576SAnurag.Maskey@Oracle.COM 		    &nif->nwamd_if_ipv6_default_route, str,
25911767SAnurag.Maskey@Sun.COM 		    sizeof (str)));
26011767SAnurag.Maskey@Sun.COM 		nwamd_add_route((struct sockaddr *)&v6dest,
26111767SAnurag.Maskey@Sun.COM 		    (struct sockaddr *)&v6mask,
26211767SAnurag.Maskey@Sun.COM 		    (struct sockaddr *)&nif->nwamd_if_ipv6_default_route,
26311767SAnurag.Maskey@Sun.COM 		    ncu->ncu_name);
26411767SAnurag.Maskey@Sun.COM 	}
26511767SAnurag.Maskey@Sun.COM }
26611767SAnurag.Maskey@Sun.COM 
26711767SAnurag.Maskey@Sun.COM /*
26811767SAnurag.Maskey@Sun.COM  * Returns the nwamd_if_address structure for the given static address,
26911767SAnurag.Maskey@Sun.COM  * NULL if not found.
27011767SAnurag.Maskey@Sun.COM  */
27111767SAnurag.Maskey@Sun.COM static struct nwamd_if_address *
find_static_address(const struct sockaddr_storage * addr,const nwamd_ncu_t * ncu)27212576SAnurag.Maskey@Oracle.COM find_static_address(const struct sockaddr_storage *addr, const nwamd_ncu_t *ncu)
27311767SAnurag.Maskey@Sun.COM {
27412576SAnurag.Maskey@Oracle.COM 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
27512576SAnurag.Maskey@Oracle.COM 	struct sockaddr_storage saddr;
27611767SAnurag.Maskey@Sun.COM 	char str[INET6_ADDRSTRLEN];
27711767SAnurag.Maskey@Sun.COM 
27812576SAnurag.Maskey@Oracle.COM 	nlog(LOG_DEBUG, "find_static_address: %s",
27912576SAnurag.Maskey@Oracle.COM 	    nwamd_sockaddr2str((struct sockaddr *)addr, str, sizeof (str)));
28012576SAnurag.Maskey@Oracle.COM 	for (nifap = nifa; nifap != NULL; nifap = nifap->next) {
28112576SAnurag.Maskey@Oracle.COM 		if (nifap->ipaddr_atype != IPADM_ADDR_STATIC ||
28212576SAnurag.Maskey@Oracle.COM 		    ipadm_get_addr(nifap->ipaddr, &saddr) != IPADM_SUCCESS)
28312576SAnurag.Maskey@Oracle.COM 			continue;
28412576SAnurag.Maskey@Oracle.COM 
28512576SAnurag.Maskey@Oracle.COM 		if (sockaddrcmp(addr, &saddr))
28612576SAnurag.Maskey@Oracle.COM 			return (nifap);
28711767SAnurag.Maskey@Sun.COM 	}
28811767SAnurag.Maskey@Sun.COM 	return (NULL);
28911767SAnurag.Maskey@Sun.COM }
29011767SAnurag.Maskey@Sun.COM 
29111767SAnurag.Maskey@Sun.COM /*
29211767SAnurag.Maskey@Sun.COM  * Returns the nwamd_if_address structure representing the non-static address
29312576SAnurag.Maskey@Oracle.COM  * in the NCU.  For IPv6, both stateless and stateful (DHCPv6) share the same
29412576SAnurag.Maskey@Oracle.COM  * nwamd_if_address.  Will only return the nwamd_if_address if the relevant
29512576SAnurag.Maskey@Oracle.COM  * address is configured (v4 DHCP, v6 either stateless or stateless) for the
29612576SAnurag.Maskey@Oracle.COM  * NCU.  Returns NULL if the structure is not found.
29711767SAnurag.Maskey@Sun.COM  */
29811767SAnurag.Maskey@Sun.COM static struct nwamd_if_address *
find_nonstatic_address(const nwamd_ncu_t * ncu,sa_family_t family)29912576SAnurag.Maskey@Oracle.COM find_nonstatic_address(const nwamd_ncu_t *ncu, sa_family_t family)
30011767SAnurag.Maskey@Sun.COM {
30112576SAnurag.Maskey@Oracle.COM 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
30212576SAnurag.Maskey@Oracle.COM 	const nwamd_if_t *u_if = &ncu->ncu_if;
30311767SAnurag.Maskey@Sun.COM 
30412576SAnurag.Maskey@Oracle.COM 	nlog(LOG_DEBUG, "find_nonstatic_address for %s %s",
30512576SAnurag.Maskey@Oracle.COM 	    (family == AF_INET ? "IPv4" : "IPv6"),  ncu->ncu_name);
30612576SAnurag.Maskey@Oracle.COM 	for (nifap = nifa; nifap != NULL; nifap = nifap->next) {
30712576SAnurag.Maskey@Oracle.COM 		if (nifap->ipaddr_atype == IPADM_ADDR_STATIC)
30812576SAnurag.Maskey@Oracle.COM 			continue;
30912576SAnurag.Maskey@Oracle.COM 
31011767SAnurag.Maskey@Sun.COM 		if (family == AF_INET) {
31112576SAnurag.Maskey@Oracle.COM 			if (nifap->ipaddr_atype == IPADM_ADDR_DHCP &&
31212576SAnurag.Maskey@Oracle.COM 			    u_if->nwamd_if_dhcp_requested)
31312576SAnurag.Maskey@Oracle.COM 				return (nifap);
31411767SAnurag.Maskey@Sun.COM 		} else if (family == AF_INET6) {
31512576SAnurag.Maskey@Oracle.COM 			if (nifap->ipaddr_atype == IPADM_ADDR_IPV6_ADDRCONF &&
31612576SAnurag.Maskey@Oracle.COM 			    (u_if->nwamd_if_stateful_requested ||
31712576SAnurag.Maskey@Oracle.COM 			    u_if->nwamd_if_stateless_requested))
31812576SAnurag.Maskey@Oracle.COM 				return (nifap);
31911767SAnurag.Maskey@Sun.COM 		}
32011767SAnurag.Maskey@Sun.COM 	}
32111767SAnurag.Maskey@Sun.COM 	return (NULL);
32211767SAnurag.Maskey@Sun.COM }
32311767SAnurag.Maskey@Sun.COM 
32411767SAnurag.Maskey@Sun.COM /*
32512576SAnurag.Maskey@Oracle.COM  * Returns the nwamd_if_address structure that configured the given address,
32612576SAnurag.Maskey@Oracle.COM  * NULL if not found.
32711767SAnurag.Maskey@Sun.COM  */
32812576SAnurag.Maskey@Oracle.COM static struct nwamd_if_address *
find_configured_address(const struct sockaddr_storage * addr,const nwamd_ncu_t * ncu)32912576SAnurag.Maskey@Oracle.COM find_configured_address(const struct sockaddr_storage *addr,
33012576SAnurag.Maskey@Oracle.COM     const nwamd_ncu_t *ncu)
33111767SAnurag.Maskey@Sun.COM {
33212576SAnurag.Maskey@Oracle.COM 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
33311767SAnurag.Maskey@Sun.COM 	char str[INET6_ADDRSTRLEN];
33411767SAnurag.Maskey@Sun.COM 
33512576SAnurag.Maskey@Oracle.COM 	nlog(LOG_DEBUG, "find_configured_address: %s",
33612576SAnurag.Maskey@Oracle.COM 	    nwamd_sockaddr2str((struct sockaddr *)addr, str, sizeof (str)));
33712576SAnurag.Maskey@Oracle.COM 	for (nifap = nifa; nifap != NULL; nifap = nifap->next) {
33812576SAnurag.Maskey@Oracle.COM 		if (sockaddrcmp(addr, &nifap->conf_addr) ||
33912576SAnurag.Maskey@Oracle.COM 		    sockaddrcmp(addr, &nifap->conf_stateless_addr))
34012576SAnurag.Maskey@Oracle.COM 			return (nifap);
34111767SAnurag.Maskey@Sun.COM 	}
34212576SAnurag.Maskey@Oracle.COM 	return (NULL);
34311767SAnurag.Maskey@Sun.COM }
34411767SAnurag.Maskey@Sun.COM 
34511767SAnurag.Maskey@Sun.COM /*
34611767SAnurag.Maskey@Sun.COM  * Are one or more static addresses configured?
34711767SAnurag.Maskey@Sun.COM  */
34811767SAnurag.Maskey@Sun.COM boolean_t
nwamd_static_addresses_configured(nwamd_ncu_t * ncu,sa_family_t family)34911767SAnurag.Maskey@Sun.COM nwamd_static_addresses_configured(nwamd_ncu_t *ncu, sa_family_t family)
35011767SAnurag.Maskey@Sun.COM {
35111767SAnurag.Maskey@Sun.COM 	struct nwamd_if_address *n;
35211767SAnurag.Maskey@Sun.COM 
35312576SAnurag.Maskey@Oracle.COM 	for (n = ncu->ncu_if.nwamd_if_list; n != NULL; n = n->next) {
35412576SAnurag.Maskey@Oracle.COM 		if (n->ipaddr_atype != IPADM_ADDR_STATIC)
35512576SAnurag.Maskey@Oracle.COM 			continue;
35612576SAnurag.Maskey@Oracle.COM 		if ((family == AF_UNSPEC || family == n->family) &&
35712576SAnurag.Maskey@Oracle.COM 		    n->configured)
35811767SAnurag.Maskey@Sun.COM 			return (B_TRUE);
35911767SAnurag.Maskey@Sun.COM 	}
36011767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "no static addresses configured for %s", ncu->ncu_name);
36111767SAnurag.Maskey@Sun.COM 	return (B_FALSE);
36211767SAnurag.Maskey@Sun.COM }
36311767SAnurag.Maskey@Sun.COM 
36411767SAnurag.Maskey@Sun.COM /*
36511767SAnurag.Maskey@Sun.COM  * Is DHCP probably managing an address on this index.  We decide that it is
36611767SAnurag.Maskey@Sun.COM  * probably managing an address if there is an interface with IFF_DHCP set
36711767SAnurag.Maskey@Sun.COM  * that isn't in our set of static addresses.  Note that IFF_DHCP gets set
36811767SAnurag.Maskey@Sun.COM  * on static addresses when we do a dhcp inform and if that list has changed
36911767SAnurag.Maskey@Sun.COM  * recently then the result of this function could be erronous.
37011767SAnurag.Maskey@Sun.COM  */
37111767SAnurag.Maskey@Sun.COM boolean_t
nwamd_dhcp_managing(int protocol,nwamd_ncu_t * ncu)37211767SAnurag.Maskey@Sun.COM nwamd_dhcp_managing(int protocol, nwamd_ncu_t *ncu)
37311767SAnurag.Maskey@Sun.COM {
37412805SDarren.Reed@Oracle.COM 	struct sockaddr_storage addr;
37511767SAnurag.Maskey@Sun.COM 	uint64_t flags;
37611767SAnurag.Maskey@Sun.COM 	boolean_t rv = B_FALSE;
37712576SAnurag.Maskey@Oracle.COM 	ipadm_addr_info_t *addrinfo, *a;
37812576SAnurag.Maskey@Oracle.COM 	ipadm_status_t ipstatus;
37911767SAnurag.Maskey@Sun.COM 
38012576SAnurag.Maskey@Oracle.COM 	if ((ipstatus = ipadm_addr_info(ipadm_handle, ncu->ncu_name, &addrinfo,
38112576SAnurag.Maskey@Oracle.COM 	    0, 0)) != IPADM_SUCCESS) {
38212576SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "nwamd_dhcp_managing: "
38312576SAnurag.Maskey@Oracle.COM 		    "ipadm_addr_info failed for %s: %s",
38412576SAnurag.Maskey@Oracle.COM 		    ncu->ncu_name, ipadm_status2str(ipstatus));
38512576SAnurag.Maskey@Oracle.COM 		return (B_FALSE);
38612576SAnurag.Maskey@Oracle.COM 	}
38711767SAnurag.Maskey@Sun.COM 
38812576SAnurag.Maskey@Oracle.COM 	for (a = addrinfo; a != NULL; a = IA_NEXT(a)) {
38912805SDarren.Reed@Oracle.COM 		/*
39012805SDarren.Reed@Oracle.COM 		 * WARNING: This memcpy() assumes knowledge of the
39112805SDarren.Reed@Oracle.COM 		 * implementation of getifaddrs() and that it always
39212805SDarren.Reed@Oracle.COM 		 * uses sockaddr_storage as the backing store for
39312805SDarren.Reed@Oracle.COM 		 * address information, thus making it possible to
39412805SDarren.Reed@Oracle.COM 		 * copy the entire structure rather than do it on
39512805SDarren.Reed@Oracle.COM 		 * the size of the sockaddr according to family.
39612805SDarren.Reed@Oracle.COM 		 * This assumption is made elsewhere in this file.
39712805SDarren.Reed@Oracle.COM 		 */
39812805SDarren.Reed@Oracle.COM 		(void) memcpy(&addr, a->ia_ifa.ifa_addr, sizeof (addr));
39912805SDarren.Reed@Oracle.COM 
40011767SAnurag.Maskey@Sun.COM 		/* is this address an expected static one? */
40112805SDarren.Reed@Oracle.COM 		if (find_static_address(&addr, ncu) != NULL)
40211767SAnurag.Maskey@Sun.COM 			continue;
40311767SAnurag.Maskey@Sun.COM 
40411767SAnurag.Maskey@Sun.COM 		/*
40511767SAnurag.Maskey@Sun.COM 		 * For IPv4, DHCPRUNNING flag is set when dhcpagent is in
40611767SAnurag.Maskey@Sun.COM 		 * the process of getting an address, but doesn't have one
40711767SAnurag.Maskey@Sun.COM 		 * yet (interface has 0.0.0.0).  For IPv6, DHCPRUNNING flag
40811767SAnurag.Maskey@Sun.COM 		 * is set on the link-local address if trying to get a
40911767SAnurag.Maskey@Sun.COM 		 * stateful address.  In both cases, consider the interface
41011767SAnurag.Maskey@Sun.COM 		 * as not being managed by DHCP and skip checking of flags.
41111767SAnurag.Maskey@Sun.COM 		 */
41211767SAnurag.Maskey@Sun.COM 		if ((protocol == AF_INET &&
41312805SDarren.Reed@Oracle.COM 		    ((struct sockaddr_in *)&addr)->sin_addr.s_addr ==
41411767SAnurag.Maskey@Sun.COM 		    INADDR_ANY) ||
41511767SAnurag.Maskey@Sun.COM 		    (protocol == AF_INET6 &&
41611767SAnurag.Maskey@Sun.COM 		    IN6_IS_ADDR_LINKLOCAL(
41712805SDarren.Reed@Oracle.COM 		    &((struct sockaddr_in6 *)&addr)->sin6_addr))) {
41811767SAnurag.Maskey@Sun.COM 			continue;
41911767SAnurag.Maskey@Sun.COM 		}
42011767SAnurag.Maskey@Sun.COM 
42112576SAnurag.Maskey@Oracle.COM 		flags = a->ia_ifa.ifa_flags;
42212576SAnurag.Maskey@Oracle.COM 		if (flags & IFF_DHCPRUNNING) {
42311767SAnurag.Maskey@Sun.COM 			/*
42411767SAnurag.Maskey@Sun.COM 			 * If we get here we have an address that has the
42511767SAnurag.Maskey@Sun.COM 			 * DHCP flag set and isn't an expected static address.
42611767SAnurag.Maskey@Sun.COM 			 */
42711767SAnurag.Maskey@Sun.COM 			rv = B_TRUE;
42811767SAnurag.Maskey@Sun.COM 			break;
42911767SAnurag.Maskey@Sun.COM 		}
43011767SAnurag.Maskey@Sun.COM 	}
43111767SAnurag.Maskey@Sun.COM 
43212576SAnurag.Maskey@Oracle.COM 	ipadm_free_addr_info(addrinfo);
43311767SAnurag.Maskey@Sun.COM 	return (rv);
43411767SAnurag.Maskey@Sun.COM }
43511767SAnurag.Maskey@Sun.COM 
43612576SAnurag.Maskey@Oracle.COM /*
43712576SAnurag.Maskey@Oracle.COM  * Return B_TRUE if IPv4 is requested in the given NCU.
43812576SAnurag.Maskey@Oracle.COM  */
43911767SAnurag.Maskey@Sun.COM static boolean_t
nwamd_v4_requested(nwamd_ncu_t * ncu)44011767SAnurag.Maskey@Sun.COM nwamd_v4_requested(nwamd_ncu_t *ncu)
44111767SAnurag.Maskey@Sun.COM {
44211767SAnurag.Maskey@Sun.COM 	boolean_t anyv4_requested;
44311767SAnurag.Maskey@Sun.COM 	nwamd_if_t *u_if;
44411767SAnurag.Maskey@Sun.COM 
44511767SAnurag.Maskey@Sun.COM 	anyv4_requested = B_FALSE;
44612576SAnurag.Maskey@Oracle.COM 	u_if = &ncu->ncu_if;
44711767SAnurag.Maskey@Sun.COM 	if (u_if->nwamd_if_dhcp_requested) {
44811767SAnurag.Maskey@Sun.COM 		anyv4_requested = B_TRUE;
44911767SAnurag.Maskey@Sun.COM 	} else {
45012576SAnurag.Maskey@Oracle.COM 		struct nwamd_if_address *n;
45112576SAnurag.Maskey@Oracle.COM 
45212576SAnurag.Maskey@Oracle.COM 		for (n = u_if->nwamd_if_list; n != NULL; n = n->next) {
45312576SAnurag.Maskey@Oracle.COM 			if (n->family == AF_INET &&
45412576SAnurag.Maskey@Oracle.COM 			    n->ipaddr_atype == IPADM_ADDR_STATIC)
45512576SAnurag.Maskey@Oracle.COM 				break;
45612576SAnurag.Maskey@Oracle.COM 		}
45712576SAnurag.Maskey@Oracle.COM 		if (n != NULL)
45811767SAnurag.Maskey@Sun.COM 			anyv4_requested = B_TRUE;
45911767SAnurag.Maskey@Sun.COM 	}
46011767SAnurag.Maskey@Sun.COM 
46111767SAnurag.Maskey@Sun.COM 	return (anyv4_requested);
46211767SAnurag.Maskey@Sun.COM }
46311767SAnurag.Maskey@Sun.COM 
46412576SAnurag.Maskey@Oracle.COM /*
46512576SAnurag.Maskey@Oracle.COM  * Returns B_TRUE if IPv6 is requested in the given NCU.
46612576SAnurag.Maskey@Oracle.COM  */
46711767SAnurag.Maskey@Sun.COM static boolean_t
nwamd_v6_requested(nwamd_ncu_t * ncu)46811767SAnurag.Maskey@Sun.COM nwamd_v6_requested(nwamd_ncu_t *ncu)
46911767SAnurag.Maskey@Sun.COM {
47011767SAnurag.Maskey@Sun.COM 	boolean_t anyv6_requested;
47111767SAnurag.Maskey@Sun.COM 	nwamd_if_t *u_if;
47211767SAnurag.Maskey@Sun.COM 
47311767SAnurag.Maskey@Sun.COM 	anyv6_requested = B_FALSE;
47412576SAnurag.Maskey@Oracle.COM 	u_if = &ncu->ncu_if;
47511767SAnurag.Maskey@Sun.COM 	if (u_if->nwamd_if_stateful_requested ||
47611767SAnurag.Maskey@Sun.COM 	    u_if->nwamd_if_stateless_requested) {
47711767SAnurag.Maskey@Sun.COM 		anyv6_requested = B_TRUE;
47811767SAnurag.Maskey@Sun.COM 	} else {
47912576SAnurag.Maskey@Oracle.COM 		struct nwamd_if_address *n;
48012576SAnurag.Maskey@Oracle.COM 
48112576SAnurag.Maskey@Oracle.COM 		for (n = u_if->nwamd_if_list; n != NULL; n = n->next) {
48212576SAnurag.Maskey@Oracle.COM 			if (n->family == AF_INET6 &&
48312576SAnurag.Maskey@Oracle.COM 			    n->ipaddr_atype == IPADM_ADDR_STATIC)
48412576SAnurag.Maskey@Oracle.COM 				break;
48512576SAnurag.Maskey@Oracle.COM 		}
48612576SAnurag.Maskey@Oracle.COM 		if (n != NULL)
48711767SAnurag.Maskey@Sun.COM 			anyv6_requested = B_TRUE;
48811767SAnurag.Maskey@Sun.COM 	}
48911767SAnurag.Maskey@Sun.COM 
49011767SAnurag.Maskey@Sun.COM 	return (anyv6_requested);
49111767SAnurag.Maskey@Sun.COM }
49211767SAnurag.Maskey@Sun.COM 
49311767SAnurag.Maskey@Sun.COM /*
49411767SAnurag.Maskey@Sun.COM  * Bring up the ncu if we have the right combination of requested configuration
49511767SAnurag.Maskey@Sun.COM  * and actual configuration and up is true, or bring down the ncu if no
49611767SAnurag.Maskey@Sun.COM  * addresses are configured, and up is false.
49711767SAnurag.Maskey@Sun.COM  */
49811767SAnurag.Maskey@Sun.COM static void
interface_ncu_up_down(nwamd_ncu_t * ncu,boolean_t up)49911767SAnurag.Maskey@Sun.COM interface_ncu_up_down(nwamd_ncu_t *ncu, boolean_t up)
50011767SAnurag.Maskey@Sun.COM {
50111767SAnurag.Maskey@Sun.COM 	boolean_t ncu_online;
50211767SAnurag.Maskey@Sun.COM 	char *name;
50311767SAnurag.Maskey@Sun.COM 
50411767SAnurag.Maskey@Sun.COM 	assert(ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE);
50511767SAnurag.Maskey@Sun.COM 
50611767SAnurag.Maskey@Sun.COM 	/*
50711767SAnurag.Maskey@Sun.COM 	 * If V4 with or without V6 is configured then one of its interfaces
50811767SAnurag.Maskey@Sun.COM 	 * needs to be up for the ncu to come online.  If only V6 is requested
50911767SAnurag.Maskey@Sun.COM 	 * then one of its interfaces needs to be up for the ncu to come online.
51011767SAnurag.Maskey@Sun.COM 	 */
51111767SAnurag.Maskey@Sun.COM 	ncu_online = B_FALSE;
51211767SAnurag.Maskey@Sun.COM 	if (nwamd_v4_requested(ncu)) {
51311767SAnurag.Maskey@Sun.COM 		if (nwamd_dhcp_managing(AF_INET, ncu) ||
51411767SAnurag.Maskey@Sun.COM 		    nwamd_static_addresses_configured(ncu, AF_INET))
51511767SAnurag.Maskey@Sun.COM 			ncu_online = B_TRUE;
51611767SAnurag.Maskey@Sun.COM 	} else if (nwamd_v6_requested(ncu)) {
51711767SAnurag.Maskey@Sun.COM 		if ((nwamd_dhcp_managing(AF_INET6, ncu) ||
51811767SAnurag.Maskey@Sun.COM 		    stateless_running(ncu) ||
51911767SAnurag.Maskey@Sun.COM 		    nwamd_static_addresses_configured(ncu, AF_INET6)))
52011767SAnurag.Maskey@Sun.COM 			ncu_online = B_TRUE;
52111767SAnurag.Maskey@Sun.COM 	}
52211767SAnurag.Maskey@Sun.COM 
52311767SAnurag.Maskey@Sun.COM 	if (nwam_ncu_name_to_typed_name(ncu->ncu_name, ncu->ncu_type, &name) !=
52411767SAnurag.Maskey@Sun.COM 	    NWAM_SUCCESS) {
52511767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "interface_ncu_up_down: "
52611767SAnurag.Maskey@Sun.COM 		    "nwam_ncu_name_to_typed_name failed");
52711767SAnurag.Maskey@Sun.COM 		return;
52811767SAnurag.Maskey@Sun.COM 	}
52911767SAnurag.Maskey@Sun.COM 	if (ncu_online && up) {
53011767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "interface_ncu_up_down: "
53111767SAnurag.Maskey@Sun.COM 		    "bringing %s up", name);
53211767SAnurag.Maskey@Sun.COM 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, name,
53311767SAnurag.Maskey@Sun.COM 		    NWAM_STATE_OFFLINE_TO_ONLINE, NWAM_AUX_STATE_UP);
53411767SAnurag.Maskey@Sun.COM 	} else if (!ncu_online && !up) {
53511767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "interface_ncu_up_down: "
53611767SAnurag.Maskey@Sun.COM 		    "bringing %s down", name);
53711767SAnurag.Maskey@Sun.COM 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, name,
53811767SAnurag.Maskey@Sun.COM 		    NWAM_STATE_ONLINE_TO_OFFLINE,
53911767SAnurag.Maskey@Sun.COM 		    NWAM_AUX_STATE_DOWN);
54011767SAnurag.Maskey@Sun.COM 	}
54111767SAnurag.Maskey@Sun.COM 
54211767SAnurag.Maskey@Sun.COM 	free(name);
54311767SAnurag.Maskey@Sun.COM }
54411767SAnurag.Maskey@Sun.COM 
54511767SAnurag.Maskey@Sun.COM static void
interface_ncu_up(nwamd_ncu_t * ncu)54611767SAnurag.Maskey@Sun.COM interface_ncu_up(nwamd_ncu_t *ncu)
54711767SAnurag.Maskey@Sun.COM {
54811767SAnurag.Maskey@Sun.COM 	interface_ncu_up_down(ncu, B_TRUE);
54911767SAnurag.Maskey@Sun.COM }
55011767SAnurag.Maskey@Sun.COM 
55111767SAnurag.Maskey@Sun.COM static void
interface_ncu_down(nwamd_ncu_t * ncu)55211767SAnurag.Maskey@Sun.COM interface_ncu_down(nwamd_ncu_t *ncu)
55311767SAnurag.Maskey@Sun.COM {
55411767SAnurag.Maskey@Sun.COM 	interface_ncu_up_down(ncu, B_FALSE);
55511767SAnurag.Maskey@Sun.COM }
55611767SAnurag.Maskey@Sun.COM 
55712576SAnurag.Maskey@Oracle.COM static boolean_t
stateless_running(const nwamd_ncu_t * ncu)55812576SAnurag.Maskey@Oracle.COM stateless_running(const nwamd_ncu_t *ncu)
55911767SAnurag.Maskey@Sun.COM {
56012576SAnurag.Maskey@Oracle.COM 	ipadm_addr_info_t *ainfo, *ainfop;
56112576SAnurag.Maskey@Oracle.COM 	ipadm_status_t ipstatus;
56212576SAnurag.Maskey@Oracle.COM 	boolean_t rv = B_FALSE;
56312576SAnurag.Maskey@Oracle.COM 	uint64_t flags;
56411767SAnurag.Maskey@Sun.COM 
56512576SAnurag.Maskey@Oracle.COM 	if ((ipstatus = ipadm_addr_info(ipadm_handle, ncu->ncu_name, &ainfo,
56612576SAnurag.Maskey@Oracle.COM 	    0, 0)) != IPADM_SUCCESS) {
56712576SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "stateless_running: "
56812576SAnurag.Maskey@Oracle.COM 		    "ipadm_addr_info failed for %s: %s",
56912576SAnurag.Maskey@Oracle.COM 		    ncu->ncu_name, ipadm_status2str(ipstatus));
57012576SAnurag.Maskey@Oracle.COM 		return (B_FALSE);
57111767SAnurag.Maskey@Sun.COM 	}
57211767SAnurag.Maskey@Sun.COM 
57312576SAnurag.Maskey@Oracle.COM 	for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
57412805SDarren.Reed@Oracle.COM 		if (ainfop->ia_ifa.ifa_addr->sa_family != AF_INET6)
57512576SAnurag.Maskey@Oracle.COM 			continue;
57612576SAnurag.Maskey@Oracle.COM 		flags = ainfop->ia_ifa.ifa_flags;
57712576SAnurag.Maskey@Oracle.COM 		if (flags & STATELESS_RUNNING) {
57812576SAnurag.Maskey@Oracle.COM 			rv = B_TRUE;
57912576SAnurag.Maskey@Oracle.COM 			break;
58012576SAnurag.Maskey@Oracle.COM 		}
58111767SAnurag.Maskey@Sun.COM 	}
58212576SAnurag.Maskey@Oracle.COM 	ipadm_free_addr_info(ainfo);
58312576SAnurag.Maskey@Oracle.COM 	return (rv);
58411767SAnurag.Maskey@Sun.COM }
58511767SAnurag.Maskey@Sun.COM 
58612576SAnurag.Maskey@Oracle.COM /*
58712576SAnurag.Maskey@Oracle.COM  * Returns the addrinfo associated with the given address.  There is always
58812576SAnurag.Maskey@Oracle.COM  * only one addrinfo for each address.
58912576SAnurag.Maskey@Oracle.COM  */
59012576SAnurag.Maskey@Oracle.COM static boolean_t
addrinfo_for_addr(const struct sockaddr_storage * caddr,const char * ifname,ipadm_addr_info_t ** ainfo)59112576SAnurag.Maskey@Oracle.COM addrinfo_for_addr(const struct sockaddr_storage *caddr, const char *ifname,
59212576SAnurag.Maskey@Oracle.COM     ipadm_addr_info_t **ainfo)
59311767SAnurag.Maskey@Sun.COM {
59412576SAnurag.Maskey@Oracle.COM 	ipadm_addr_info_t *addrinfo, *ainfop, *last = NULL;
59512576SAnurag.Maskey@Oracle.COM 	ipadm_status_t ipstatus;
59612576SAnurag.Maskey@Oracle.COM 
59712576SAnurag.Maskey@Oracle.COM 	ipstatus = ipadm_addr_info(ipadm_handle, ifname, &addrinfo, 0, 0);
59812576SAnurag.Maskey@Oracle.COM 	if (ipstatus != IPADM_SUCCESS) {
59912576SAnurag.Maskey@Oracle.COM 		nlog(LOG_INFO, "addrinfo_for_addr: "
60012576SAnurag.Maskey@Oracle.COM 		    "ipadm_addr_info failed for %s: %s",
60112576SAnurag.Maskey@Oracle.COM 		    ifname, ipadm_status2str(ipstatus));
60212576SAnurag.Maskey@Oracle.COM 		return (B_FALSE);
60312576SAnurag.Maskey@Oracle.COM 	}
60412576SAnurag.Maskey@Oracle.COM 
60512576SAnurag.Maskey@Oracle.COM 	*ainfo = NULL;
60612576SAnurag.Maskey@Oracle.COM 	for (ainfop = addrinfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
60712805SDarren.Reed@Oracle.COM 		struct sockaddr_storage addr;
60812805SDarren.Reed@Oracle.COM 
60912805SDarren.Reed@Oracle.COM 		(void) memcpy(&addr, ainfop->ia_ifa.ifa_addr, sizeof (addr));
61012576SAnurag.Maskey@Oracle.COM 		/*
61112576SAnurag.Maskey@Oracle.COM 		 * If addresses match, rearrange pointers so that addrinfo
61212576SAnurag.Maskey@Oracle.COM 		 * does not contain a, and return a.
61312576SAnurag.Maskey@Oracle.COM 		 */
61412805SDarren.Reed@Oracle.COM 		if (sockaddrcmp(&addr, caddr)) {
61512576SAnurag.Maskey@Oracle.COM 			if (last != NULL)
61612576SAnurag.Maskey@Oracle.COM 				last->ia_ifa.ifa_next = ainfop->ia_ifa.ifa_next;
61712576SAnurag.Maskey@Oracle.COM 			else
61812576SAnurag.Maskey@Oracle.COM 				addrinfo = IA_NEXT(ainfop);
61912576SAnurag.Maskey@Oracle.COM 
62012576SAnurag.Maskey@Oracle.COM 			ainfop->ia_ifa.ifa_next = NULL;
62112576SAnurag.Maskey@Oracle.COM 			*ainfo = ainfop;
62212576SAnurag.Maskey@Oracle.COM 			break;
62312576SAnurag.Maskey@Oracle.COM 		}
62412576SAnurag.Maskey@Oracle.COM 		last = ainfop;
62512576SAnurag.Maskey@Oracle.COM 	}
62612576SAnurag.Maskey@Oracle.COM 	ipadm_free_addr_info(addrinfo);
62712576SAnurag.Maskey@Oracle.COM 	return (*ainfo == NULL ? B_FALSE : B_TRUE);
62811767SAnurag.Maskey@Sun.COM }
62911767SAnurag.Maskey@Sun.COM 
63011767SAnurag.Maskey@Sun.COM /*
63112576SAnurag.Maskey@Oracle.COM  * Returns B_TRUE if the addrinfo associated with the given ipaddr using its
63212576SAnurag.Maskey@Oracle.COM  * aobjname is found.  An addrinfo list is created and returned in ainfo.
63312576SAnurag.Maskey@Oracle.COM  * Stateless and stateful IPv6 addrinfo have the same aobjname, thus the need
63412576SAnurag.Maskey@Oracle.COM  * to create a list of addrinfo.
63511767SAnurag.Maskey@Sun.COM  */
63611767SAnurag.Maskey@Sun.COM static boolean_t
addrinfo_for_ipaddr(ipadm_addrobj_t ipaddr,const char * ifname,ipadm_addr_info_t ** ainfo)63712576SAnurag.Maskey@Oracle.COM addrinfo_for_ipaddr(ipadm_addrobj_t ipaddr, const char *ifname,
63812576SAnurag.Maskey@Oracle.COM     ipadm_addr_info_t **ainfo)
63911767SAnurag.Maskey@Sun.COM {
64012576SAnurag.Maskey@Oracle.COM 	char aobjname[IPADM_AOBJSIZ];
64112576SAnurag.Maskey@Oracle.COM 	ipadm_addr_info_t *addrinfo, *ainfop;
64212576SAnurag.Maskey@Oracle.COM 	ipadm_addr_info_t *last = NULL;
64312576SAnurag.Maskey@Oracle.COM 	ipadm_status_t ipstatus;
64411767SAnurag.Maskey@Sun.COM 
64512576SAnurag.Maskey@Oracle.COM 	ipstatus = ipadm_get_aobjname(ipaddr, aobjname, sizeof (aobjname));
64612576SAnurag.Maskey@Oracle.COM 	if (ipstatus != IPADM_SUCCESS)
64712576SAnurag.Maskey@Oracle.COM 		return (B_FALSE);
64812576SAnurag.Maskey@Oracle.COM 
64912576SAnurag.Maskey@Oracle.COM 	ipstatus = ipadm_addr_info(ipadm_handle, ifname, &addrinfo, 0, 0);
65012576SAnurag.Maskey@Oracle.COM 	if (ipstatus != IPADM_SUCCESS) {
65112576SAnurag.Maskey@Oracle.COM 		nlog(LOG_INFO, "addrinfo_for_ipaddr: "
65212576SAnurag.Maskey@Oracle.COM 		    "ipadm_addr_info failed for %s: %s",
65312576SAnurag.Maskey@Oracle.COM 		    ifname, ipadm_status2str(ipstatus));
65411767SAnurag.Maskey@Sun.COM 		return (B_FALSE);
65511767SAnurag.Maskey@Sun.COM 	}
65611767SAnurag.Maskey@Sun.COM 
65712576SAnurag.Maskey@Oracle.COM 	*ainfo = NULL;
65812576SAnurag.Maskey@Oracle.COM 	ainfop = addrinfo;
65912576SAnurag.Maskey@Oracle.COM 	while (ainfop != NULL) {
66012576SAnurag.Maskey@Oracle.COM 		/* If aobjnames match, rearrange pointers to create new list */
66112576SAnurag.Maskey@Oracle.COM 		if (strcmp(ainfop->ia_aobjname, aobjname) == 0) {
66212576SAnurag.Maskey@Oracle.COM 			ipadm_addr_info_t *match = ainfop;
66312576SAnurag.Maskey@Oracle.COM 
66412576SAnurag.Maskey@Oracle.COM 			ainfop = IA_NEXT(ainfop); /* move iterator */
66512576SAnurag.Maskey@Oracle.COM 			if (last != NULL)
66612576SAnurag.Maskey@Oracle.COM 				last->ia_ifa.ifa_next = match->ia_ifa.ifa_next;
66712576SAnurag.Maskey@Oracle.COM 			else
66812576SAnurag.Maskey@Oracle.COM 				addrinfo = ainfop;
66912576SAnurag.Maskey@Oracle.COM 			if (*ainfo == NULL)
67012576SAnurag.Maskey@Oracle.COM 				match->ia_ifa.ifa_next = NULL;
67112576SAnurag.Maskey@Oracle.COM 			else
67212576SAnurag.Maskey@Oracle.COM 				match->ia_ifa.ifa_next = &(*ainfo)->ia_ifa;
67312576SAnurag.Maskey@Oracle.COM 			*ainfo = match;
67412576SAnurag.Maskey@Oracle.COM 		} else {
67512576SAnurag.Maskey@Oracle.COM 			last = ainfop;
67612576SAnurag.Maskey@Oracle.COM 			ainfop = IA_NEXT(ainfop);
67712576SAnurag.Maskey@Oracle.COM 		}
67812576SAnurag.Maskey@Oracle.COM 	}
67912576SAnurag.Maskey@Oracle.COM 	ipadm_free_addr_info(addrinfo);
68012576SAnurag.Maskey@Oracle.COM 	return (*ainfo == NULL ? B_FALSE : B_TRUE);
68112576SAnurag.Maskey@Oracle.COM }
68212576SAnurag.Maskey@Oracle.COM 
68312576SAnurag.Maskey@Oracle.COM /*
68412576SAnurag.Maskey@Oracle.COM  * Add the address provided in the nwamd_if_address.  If DHCP is required,
68512576SAnurag.Maskey@Oracle.COM  * start DHCP.  If a static address is configured, create the address; then do
68612576SAnurag.Maskey@Oracle.COM  * a DHCP_INFORM (in a separate thread) to get other networking configuration
68712576SAnurag.Maskey@Oracle.COM  * parameters.  RTM_NEWADDRs - translated into IF_STATE events - will then
68812576SAnurag.Maskey@Oracle.COM  * finish the job of bringing the NCU online.
68912576SAnurag.Maskey@Oracle.COM  */
69012576SAnurag.Maskey@Oracle.COM static boolean_t
add_ip_address(const char * ifname,const struct nwamd_if_address * nifa,boolean_t * do_inform)691*13107SRenee.Sommerfeld@Oracle.COM add_ip_address(const char *ifname, const struct nwamd_if_address *nifa,
692*13107SRenee.Sommerfeld@Oracle.COM     boolean_t *do_inform)
69312576SAnurag.Maskey@Oracle.COM {
69412576SAnurag.Maskey@Oracle.COM 	ipadm_status_t ipstatus;
69512576SAnurag.Maskey@Oracle.COM 	ipadm_addr_info_t *addrinfo = NULL;
69612576SAnurag.Maskey@Oracle.COM 	uint64_t flags;
69712576SAnurag.Maskey@Oracle.COM 
69812576SAnurag.Maskey@Oracle.COM 	if (nifa->ipaddr_atype == IPADM_ADDR_DHCP) {
69912576SAnurag.Maskey@Oracle.COM 		/*
70012576SAnurag.Maskey@Oracle.COM 		 * To make getting a DHCP address asynchronous, call
70112576SAnurag.Maskey@Oracle.COM 		 * ipadm_create_addr() in a new thread.
70212576SAnurag.Maskey@Oracle.COM 		 */
70312576SAnurag.Maskey@Oracle.COM 		nlog(LOG_DEBUG, "add_ip_address: "
70412576SAnurag.Maskey@Oracle.COM 		    "adding IPv4 DHCP address on %s", ifname);
70512576SAnurag.Maskey@Oracle.COM 		nwamd_dhcp(ifname, nifa->ipaddr, DHCP_START);
70612576SAnurag.Maskey@Oracle.COM 	} else {
70712576SAnurag.Maskey@Oracle.COM 		nlog(LOG_DEBUG, "add_ip_address: adding %s address on %s",
70812576SAnurag.Maskey@Oracle.COM 		    (nifa->ipaddr_atype == IPADM_ADDR_STATIC ?
70912576SAnurag.Maskey@Oracle.COM 		    "STATIC" : "IPv6 ADDRCONF"), ifname);
71012576SAnurag.Maskey@Oracle.COM 		if ((ipstatus = ipadm_create_addr(ipadm_handle, nifa->ipaddr,
71112576SAnurag.Maskey@Oracle.COM 		    IPADM_OPT_ACTIVE | IPADM_OPT_UP)) != IPADM_SUCCESS) {
71212576SAnurag.Maskey@Oracle.COM 			nlog(LOG_ERR, "add_ip_address: "
71312576SAnurag.Maskey@Oracle.COM 			    "ipadm_create_addr failed on %s: %s",
71412576SAnurag.Maskey@Oracle.COM 			    ifname, ipadm_status2str(ipstatus));
71512576SAnurag.Maskey@Oracle.COM 			return (B_FALSE);
71612576SAnurag.Maskey@Oracle.COM 		}
71712576SAnurag.Maskey@Oracle.COM 		/*
71812576SAnurag.Maskey@Oracle.COM 		 * When creating a static address, ipadm_create_addr() returns
71912576SAnurag.Maskey@Oracle.COM 		 * SUCCESS even if duplicate address is detected.  Retrieve
72012576SAnurag.Maskey@Oracle.COM 		 * the addrinfo to get the flags.
72112576SAnurag.Maskey@Oracle.COM 		 */
72212576SAnurag.Maskey@Oracle.COM 		if (nifa->ipaddr_atype == IPADM_ADDR_STATIC) {
72312576SAnurag.Maskey@Oracle.COM 			/*
72412576SAnurag.Maskey@Oracle.COM 			 * Since we are configuring a static address, there
72512576SAnurag.Maskey@Oracle.COM 			 * will be just *ONE* addrinfo with the aobjname in
72612576SAnurag.Maskey@Oracle.COM 			 * nifa->ipaddr.
72712576SAnurag.Maskey@Oracle.COM 			 */
72812576SAnurag.Maskey@Oracle.COM 			if (!addrinfo_for_ipaddr(nifa->ipaddr, ifname,
72912576SAnurag.Maskey@Oracle.COM 			    &addrinfo)) {
73012576SAnurag.Maskey@Oracle.COM 				nlog(LOG_ERR, "add_ip_address: "
73112576SAnurag.Maskey@Oracle.COM 				    "could not find addrinfo on %s", ifname);
73212576SAnurag.Maskey@Oracle.COM 				return (B_FALSE);
73312576SAnurag.Maskey@Oracle.COM 			}
73412576SAnurag.Maskey@Oracle.COM 
73512576SAnurag.Maskey@Oracle.COM 			flags = addrinfo->ia_ifa.ifa_flags;
73612576SAnurag.Maskey@Oracle.COM 			ipadm_free_addr_info(addrinfo);
73712576SAnurag.Maskey@Oracle.COM 			if (flags & IFF_DUPLICATE) {
73812576SAnurag.Maskey@Oracle.COM 				char *object_name;
73912576SAnurag.Maskey@Oracle.COM 				nwam_error_t err;
74012576SAnurag.Maskey@Oracle.COM 
74112576SAnurag.Maskey@Oracle.COM 				nlog(LOG_INFO, "add_ip_address: "
74212576SAnurag.Maskey@Oracle.COM 				    "duplicate address detected on %s", ifname);
74312576SAnurag.Maskey@Oracle.COM 				if ((err = nwam_ncu_name_to_typed_name(ifname,
74412576SAnurag.Maskey@Oracle.COM 				    NWAM_NCU_TYPE_INTERFACE, &object_name))
74512576SAnurag.Maskey@Oracle.COM 				    == NWAM_SUCCESS) {
74612576SAnurag.Maskey@Oracle.COM 					nwamd_object_set_state(
74712576SAnurag.Maskey@Oracle.COM 					    NWAM_OBJECT_TYPE_NCU,
74812576SAnurag.Maskey@Oracle.COM 					    object_name, NWAM_STATE_MAINTENANCE,
74912576SAnurag.Maskey@Oracle.COM 					    NWAM_AUX_STATE_IF_DUPLICATE_ADDR);
75012576SAnurag.Maskey@Oracle.COM 					free(object_name);
75112576SAnurag.Maskey@Oracle.COM 				} else {
75212576SAnurag.Maskey@Oracle.COM 					nlog(LOG_ERR, "add_ip_address: "
75312576SAnurag.Maskey@Oracle.COM 					    "could not create state event "
75412576SAnurag.Maskey@Oracle.COM 					    "for %s: %s",
75512576SAnurag.Maskey@Oracle.COM 					    ifname, nwam_strerror(err));
75612576SAnurag.Maskey@Oracle.COM 				}
75712576SAnurag.Maskey@Oracle.COM 				return (B_FALSE);
75812576SAnurag.Maskey@Oracle.COM 			}
759*13107SRenee.Sommerfeld@Oracle.COM 			/*
760*13107SRenee.Sommerfeld@Oracle.COM 			 * Do DHCP_INFORM using async ipadm_refresh_addr().
761*13107SRenee.Sommerfeld@Oracle.COM 			 * Only need to do this once per interface, and we
762*13107SRenee.Sommerfeld@Oracle.COM 			 * do *not* need to do it if we are also getting a
763*13107SRenee.Sommerfeld@Oracle.COM 			 * dhcp lease; so we only send the INFORM if the
764*13107SRenee.Sommerfeld@Oracle.COM 			 * passed-in flag says to, and we clear the flag
765*13107SRenee.Sommerfeld@Oracle.COM 			 * once we've initiated the INFORM transaction.
766*13107SRenee.Sommerfeld@Oracle.COM 			 */
767*13107SRenee.Sommerfeld@Oracle.COM 			if (*do_inform) {
768*13107SRenee.Sommerfeld@Oracle.COM 				nwamd_dhcp(ifname, nifa->ipaddr, DHCP_INFORM);
769*13107SRenee.Sommerfeld@Oracle.COM 				*do_inform = B_FALSE;
770*13107SRenee.Sommerfeld@Oracle.COM 			}
77112576SAnurag.Maskey@Oracle.COM 		}
77211767SAnurag.Maskey@Sun.COM 	}
77311767SAnurag.Maskey@Sun.COM 
77412576SAnurag.Maskey@Oracle.COM 	return (B_TRUE);
77511767SAnurag.Maskey@Sun.COM }
77611767SAnurag.Maskey@Sun.COM 
77712576SAnurag.Maskey@Oracle.COM /*
77812576SAnurag.Maskey@Oracle.COM  * Adds addresses for the given NCU.
77912576SAnurag.Maskey@Oracle.COM  */
78011767SAnurag.Maskey@Sun.COM void
nwamd_configure_interface_addresses(nwamd_ncu_t * ncu)78111767SAnurag.Maskey@Sun.COM nwamd_configure_interface_addresses(nwamd_ncu_t *ncu)
78211767SAnurag.Maskey@Sun.COM {
78312576SAnurag.Maskey@Oracle.COM 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
784*13107SRenee.Sommerfeld@Oracle.COM 	boolean_t do_inform;
785*13107SRenee.Sommerfeld@Oracle.COM 
786*13107SRenee.Sommerfeld@Oracle.COM 	/* only need an inform if we're not also getting a dhcp lease */
787*13107SRenee.Sommerfeld@Oracle.COM 	do_inform = !ncu->ncu_if.nwamd_if_dhcp_requested;
78811767SAnurag.Maskey@Sun.COM 
78911767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_configure_interface_addresses(%s)",
79011767SAnurag.Maskey@Sun.COM 	    ncu->ncu_name);
79111767SAnurag.Maskey@Sun.COM 
79212576SAnurag.Maskey@Oracle.COM 	for (nifap = nifa; nifap != NULL; nifap = nifap->next) {
79312576SAnurag.Maskey@Oracle.COM 		if (nifap->configured)
79411767SAnurag.Maskey@Sun.COM 			continue;
79511767SAnurag.Maskey@Sun.COM 
796*13107SRenee.Sommerfeld@Oracle.COM 		nifap->configured = add_ip_address(ncu->ncu_name, nifap,
797*13107SRenee.Sommerfeld@Oracle.COM 		    &do_inform);
79811767SAnurag.Maskey@Sun.COM 	}
79911767SAnurag.Maskey@Sun.COM }
80011767SAnurag.Maskey@Sun.COM 
80111767SAnurag.Maskey@Sun.COM /*
80211767SAnurag.Maskey@Sun.COM  * This event tells us that an interface address has appeared or disappeared,
80311767SAnurag.Maskey@Sun.COM  * or that the interface flags on an interface have changed.
80411767SAnurag.Maskey@Sun.COM  */
80511767SAnurag.Maskey@Sun.COM void
nwamd_ncu_handle_if_state_event(nwamd_event_t event)80611767SAnurag.Maskey@Sun.COM nwamd_ncu_handle_if_state_event(nwamd_event_t event)
80711767SAnurag.Maskey@Sun.COM {
80811767SAnurag.Maskey@Sun.COM 	nwam_event_t evm;
80911767SAnurag.Maskey@Sun.COM 	nwamd_object_t ncu_obj;
81011767SAnurag.Maskey@Sun.COM 	nwamd_ncu_t *ncu;
81111767SAnurag.Maskey@Sun.COM 	nwam_state_t state;
81211767SAnurag.Maskey@Sun.COM 	nwam_aux_state_t aux_state;
81311767SAnurag.Maskey@Sun.COM 
81411767SAnurag.Maskey@Sun.COM 	ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
81511767SAnurag.Maskey@Sun.COM 	    event->event_object);
81611767SAnurag.Maskey@Sun.COM 	if (ncu_obj == NULL) {
81712923SRenee.Sommerfeld@Oracle.COM 		nlog(LOG_INFO, "nwamd_ncu_handle_if_state_event: no object %s",
81811767SAnurag.Maskey@Sun.COM 		    event->event_object);
81911767SAnurag.Maskey@Sun.COM 		nwamd_event_do_not_send(event);
82011767SAnurag.Maskey@Sun.COM 		return;
82111767SAnurag.Maskey@Sun.COM 	}
82211767SAnurag.Maskey@Sun.COM 	ncu = ncu_obj->nwamd_object_data;
82311767SAnurag.Maskey@Sun.COM 	evm = event->event_msg;
82411767SAnurag.Maskey@Sun.COM 	state = ncu_obj->nwamd_object_state;
82511767SAnurag.Maskey@Sun.COM 	aux_state = ncu_obj->nwamd_object_aux_state;
82611767SAnurag.Maskey@Sun.COM 
82711767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "nwamd_ncu_handle_if_state_event: "
82811767SAnurag.Maskey@Sun.COM 	    "if %s, state (%s, %s)", event->event_object,
82911767SAnurag.Maskey@Sun.COM 	    nwam_state_to_string(state), nwam_aux_state_to_string(aux_state));
83011767SAnurag.Maskey@Sun.COM 
83111767SAnurag.Maskey@Sun.COM 	/* Ensure object is in correct state to handle IF state events */
83211767SAnurag.Maskey@Sun.COM 	switch (state) {
83311767SAnurag.Maskey@Sun.COM 	case NWAM_STATE_OFFLINE_TO_ONLINE:
83411767SAnurag.Maskey@Sun.COM 		if (aux_state != NWAM_AUX_STATE_IF_WAITING_FOR_ADDR &&
83511767SAnurag.Maskey@Sun.COM 		    aux_state != NWAM_AUX_STATE_IF_DHCP_TIMED_OUT) {
83611767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_ncu_handle_if_state_event: "
83711767SAnurag.Maskey@Sun.COM 			    "if %s is in invalid aux state %s for IF_STATE "
83811767SAnurag.Maskey@Sun.COM 			    "events", event->event_object,
83911767SAnurag.Maskey@Sun.COM 			    nwam_aux_state_to_string(aux_state));
84011767SAnurag.Maskey@Sun.COM 			nwamd_event_do_not_send(event);
84111767SAnurag.Maskey@Sun.COM 			nwamd_object_release(ncu_obj);
84211767SAnurag.Maskey@Sun.COM 			return;
84311767SAnurag.Maskey@Sun.COM 		}
84411767SAnurag.Maskey@Sun.COM 		break;
84511767SAnurag.Maskey@Sun.COM 	case NWAM_STATE_ONLINE:
84611767SAnurag.Maskey@Sun.COM 	/*
84711767SAnurag.Maskey@Sun.COM 	 * We can get addresses from DHCP after we've taken the interface down.
84811767SAnurag.Maskey@Sun.COM 	 * We deal with those below.
84911767SAnurag.Maskey@Sun.COM 	 */
85011767SAnurag.Maskey@Sun.COM 	case NWAM_STATE_ONLINE_TO_OFFLINE:
85111767SAnurag.Maskey@Sun.COM 	case NWAM_STATE_OFFLINE:
85211767SAnurag.Maskey@Sun.COM 		break;
85311767SAnurag.Maskey@Sun.COM 	default:
85411767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG, "nwamd_ncu_handle_if_state_event: "
85511767SAnurag.Maskey@Sun.COM 		    "if %s is in invalid state %s for IF_STATE events",
85611767SAnurag.Maskey@Sun.COM 		    event->event_object, nwam_state_to_string(state));
85711767SAnurag.Maskey@Sun.COM 		nwamd_event_do_not_send(event);
85811767SAnurag.Maskey@Sun.COM 		nwamd_object_release(ncu_obj);
85911767SAnurag.Maskey@Sun.COM 		return;
86011767SAnurag.Maskey@Sun.COM 	}
86111767SAnurag.Maskey@Sun.COM 
86211767SAnurag.Maskey@Sun.COM 	if (evm->nwe_data.nwe_if_state.nwe_addr_valid) {
86311767SAnurag.Maskey@Sun.COM 		struct nwam_event_if_state *if_state;
86412576SAnurag.Maskey@Oracle.COM 		char addrstr[INET6_ADDRSTRLEN];
86512576SAnurag.Maskey@Oracle.COM 		boolean_t static_addr, addr_added;
86612576SAnurag.Maskey@Oracle.COM 		boolean_t v4dhcp_running, v6dhcp_running, stateless_running;
86712576SAnurag.Maskey@Oracle.COM 		ipadm_addr_info_t *ai = NULL, *addrinfo = NULL;
86812576SAnurag.Maskey@Oracle.COM 		boolean_t stateless_ai_found = B_FALSE;
86912576SAnurag.Maskey@Oracle.COM 		boolean_t stateful_ai_found = B_FALSE;
87012576SAnurag.Maskey@Oracle.COM 		struct nwamd_if_address *nifa = NULL;
87111767SAnurag.Maskey@Sun.COM 		nwamd_if_t *u_if;
87212805SDarren.Reed@Oracle.COM 		struct sockaddr_storage *addr, ai_addr, *aip = NULL;
87311767SAnurag.Maskey@Sun.COM 		ushort_t family;
87411767SAnurag.Maskey@Sun.COM 		uint64_t flags = 0;
87511767SAnurag.Maskey@Sun.COM 
87611767SAnurag.Maskey@Sun.COM 		if_state = &evm->nwe_data.nwe_if_state;
87712576SAnurag.Maskey@Oracle.COM 		u_if = &ncu->ncu_if;
87811767SAnurag.Maskey@Sun.COM 		family = if_state->nwe_addr.ss_family;
87912576SAnurag.Maskey@Oracle.COM 		addr = &if_state->nwe_addr;
88012576SAnurag.Maskey@Oracle.COM 		addr_added = if_state->nwe_addr_added;
88111767SAnurag.Maskey@Sun.COM 
88211767SAnurag.Maskey@Sun.COM 		nlog(LOG_DEBUG,
88311767SAnurag.Maskey@Sun.COM 		    "nwamd_ncu_handle_if_state_event: addr %s %s",
88412576SAnurag.Maskey@Oracle.COM 		    nwamd_sockaddr2str((struct sockaddr *)addr, addrstr,
88512576SAnurag.Maskey@Oracle.COM 		    sizeof (addrstr)), addr_added ? "added" : "removed");
88611767SAnurag.Maskey@Sun.COM 
88712576SAnurag.Maskey@Oracle.COM 		/*
88812576SAnurag.Maskey@Oracle.COM 		 * Need to get flags for this interface.  Get the addrinfo for
88912576SAnurag.Maskey@Oracle.COM 		 * the address that generated this IF_STATE event.
89012576SAnurag.Maskey@Oracle.COM 		 */
89112576SAnurag.Maskey@Oracle.COM 		if (addr_added) {
89212576SAnurag.Maskey@Oracle.COM 			/*
89312576SAnurag.Maskey@Oracle.COM 			 * Address was added.  Find the addrinfo for this
89412576SAnurag.Maskey@Oracle.COM 			 * address and the nwamd_if_address corresponding to
89512576SAnurag.Maskey@Oracle.COM 			 * this address.
89612576SAnurag.Maskey@Oracle.COM 			 */
89712576SAnurag.Maskey@Oracle.COM 			if (!addrinfo_for_addr(addr, ncu->ncu_name, &ai)) {
89811767SAnurag.Maskey@Sun.COM 				nlog(LOG_ERR,
89912576SAnurag.Maskey@Oracle.COM 				    "nwamd_ncu_handle_if_state_event: "
90012576SAnurag.Maskey@Oracle.COM 				    "addrinfo doesn't exist for %s", addrstr);
90111767SAnurag.Maskey@Sun.COM 				nwamd_event_do_not_send(event);
90212576SAnurag.Maskey@Oracle.COM 				goto valid_done;
90311767SAnurag.Maskey@Sun.COM 			}
90412576SAnurag.Maskey@Oracle.COM 			addrinfo = ai;
90512576SAnurag.Maskey@Oracle.COM 			flags = addrinfo->ia_ifa.ifa_flags;
90612805SDarren.Reed@Oracle.COM 			(void) memcpy(&ai_addr, addrinfo->ia_ifa.ifa_addr,
90712805SDarren.Reed@Oracle.COM 			    sizeof (ai_addr));
90812805SDarren.Reed@Oracle.COM 			aip = &ai_addr;
90912576SAnurag.Maskey@Oracle.COM 
91012576SAnurag.Maskey@Oracle.COM 			if (addrinfo->ia_atype == IPADM_ADDR_IPV6_ADDRCONF ||
91112576SAnurag.Maskey@Oracle.COM 			    addrinfo->ia_atype == IPADM_ADDR_DHCP)
91212576SAnurag.Maskey@Oracle.COM 				nifa = find_nonstatic_address(ncu, family);
91312576SAnurag.Maskey@Oracle.COM 			else if (addrinfo->ia_atype == IPADM_ADDR_STATIC)
91412576SAnurag.Maskey@Oracle.COM 				nifa = find_static_address(addr, ncu);
91512576SAnurag.Maskey@Oracle.COM 
91611767SAnurag.Maskey@Sun.COM 			/*
91712576SAnurag.Maskey@Oracle.COM 			 * If nwamd_if_address is not found, then this address
91812576SAnurag.Maskey@Oracle.COM 			 * isn't one that nwamd created.  Remove it.
91911767SAnurag.Maskey@Sun.COM 			 */
92012576SAnurag.Maskey@Oracle.COM 			if (nifa == NULL) {
92111767SAnurag.Maskey@Sun.COM 				nlog(LOG_ERR,
92211767SAnurag.Maskey@Sun.COM 				    "nwamd_ncu_handle_if_state_event: "
92312576SAnurag.Maskey@Oracle.COM 				    "address %s not managed by nwam added, "
92412576SAnurag.Maskey@Oracle.COM 				    "removing it", addrstr);
92512576SAnurag.Maskey@Oracle.COM 				nwamd_down_interface(addrinfo->ia_aobjname,
92612576SAnurag.Maskey@Oracle.COM 				    addrinfo->ia_atype, ncu->ncu_name);
92711767SAnurag.Maskey@Sun.COM 				nwamd_event_do_not_send(event);
92812576SAnurag.Maskey@Oracle.COM 				goto valid_done;
92911767SAnurag.Maskey@Sun.COM 			}
93012576SAnurag.Maskey@Oracle.COM 
93112576SAnurag.Maskey@Oracle.COM 			/* check flags to determine how intf is configured */
93212576SAnurag.Maskey@Oracle.COM 			stateless_running = (family == AF_INET6) &&
93312576SAnurag.Maskey@Oracle.COM 			    ((flags & STATELESS_RUNNING) == STATELESS_RUNNING);
93412576SAnurag.Maskey@Oracle.COM 			v4dhcp_running = (family == AF_INET) &&
93512576SAnurag.Maskey@Oracle.COM 			    ((flags & DHCP_RUNNING) == DHCP_RUNNING);
93612576SAnurag.Maskey@Oracle.COM 			v6dhcp_running = (family == AF_INET6) &&
93712576SAnurag.Maskey@Oracle.COM 			    ((flags & DHCP_RUNNING) == DHCP_RUNNING);
93812576SAnurag.Maskey@Oracle.COM 			static_addr = (addrinfo->ia_atype == IPADM_ADDR_STATIC);
93911767SAnurag.Maskey@Sun.COM 
94012576SAnurag.Maskey@Oracle.COM 			/* copy the configured address into nwamd_if_address */
94112576SAnurag.Maskey@Oracle.COM 			if (stateless_running) {
94212576SAnurag.Maskey@Oracle.COM 				(void) memcpy(&nifa->conf_stateless_addr,
94312576SAnurag.Maskey@Oracle.COM 				    addrinfo->ia_ifa.ifa_addr,
94412576SAnurag.Maskey@Oracle.COM 				    sizeof (struct sockaddr_storage));
94512576SAnurag.Maskey@Oracle.COM 			} else {
94612576SAnurag.Maskey@Oracle.COM 				(void) memcpy(&nifa->conf_addr,
94712576SAnurag.Maskey@Oracle.COM 				    addrinfo->ia_ifa.ifa_addr,
94812576SAnurag.Maskey@Oracle.COM 				    sizeof (struct sockaddr_storage));
94912576SAnurag.Maskey@Oracle.COM 			}
95011767SAnurag.Maskey@Sun.COM 
95112576SAnurag.Maskey@Oracle.COM 		} else {
95212576SAnurag.Maskey@Oracle.COM 			/*
95312576SAnurag.Maskey@Oracle.COM 			 * Address was removed.  Find the nwamd_if_address
95412576SAnurag.Maskey@Oracle.COM 			 * that configured this address.
95512576SAnurag.Maskey@Oracle.COM 			 */
95612576SAnurag.Maskey@Oracle.COM 			nifa = find_configured_address(addr, ncu);
95712576SAnurag.Maskey@Oracle.COM 			if (nifa == NULL) {
95812576SAnurag.Maskey@Oracle.COM 				nlog(LOG_ERR,
95912576SAnurag.Maskey@Oracle.COM 				    "nwamd_ncu_handle_if_state_event: "
96012576SAnurag.Maskey@Oracle.COM 				    "address %s not managed by nwam removed, "
96112576SAnurag.Maskey@Oracle.COM 				    "nothing to do", addrstr);
96212576SAnurag.Maskey@Oracle.COM 				nwamd_event_do_not_send(event);
96312576SAnurag.Maskey@Oracle.COM 				goto valid_done;
96412576SAnurag.Maskey@Oracle.COM 			}
96511767SAnurag.Maskey@Sun.COM 
96612576SAnurag.Maskey@Oracle.COM 			if (addrinfo_for_ipaddr(nifa->ipaddr, ncu->ncu_name,
96712576SAnurag.Maskey@Oracle.COM 			    &ai)) {
96812576SAnurag.Maskey@Oracle.COM 				ipadm_addr_info_t *a;
96912576SAnurag.Maskey@Oracle.COM 				for (a = ai; a != NULL; a = IA_NEXT(a)) {
97012805SDarren.Reed@Oracle.COM 					struct sockaddr_storage stor;
97112805SDarren.Reed@Oracle.COM 
97212805SDarren.Reed@Oracle.COM 					(void) memcpy(&stor, a->ia_ifa.ifa_addr,
97312805SDarren.Reed@Oracle.COM 					    sizeof (stor));
97412576SAnurag.Maskey@Oracle.COM 					/*
97512576SAnurag.Maskey@Oracle.COM 					 * Since multiple addrinfo can have
97612576SAnurag.Maskey@Oracle.COM 					 * the same ipaddr, find the one for
97712576SAnurag.Maskey@Oracle.COM 					 * the address that generated this
97812576SAnurag.Maskey@Oracle.COM 					 * state event.
97912576SAnurag.Maskey@Oracle.COM 					 */
98012805SDarren.Reed@Oracle.COM 					if (sockaddrcmp(addr, &stor)) {
98112576SAnurag.Maskey@Oracle.COM 						flags = a->ia_ifa.ifa_flags;
98212805SDarren.Reed@Oracle.COM 						(void) memcpy(&ai_addr,
98312805SDarren.Reed@Oracle.COM 						    a->ia_ifa.ifa_addr,
98412805SDarren.Reed@Oracle.COM 						    sizeof (ai_addr));
98512805SDarren.Reed@Oracle.COM 						aip = &ai_addr;
98612576SAnurag.Maskey@Oracle.COM 						addrinfo = a;
98712576SAnurag.Maskey@Oracle.COM 					}
98812576SAnurag.Maskey@Oracle.COM 					/*
98912576SAnurag.Maskey@Oracle.COM 					 * Stateful and stateless IPv6
99012576SAnurag.Maskey@Oracle.COM 					 * addrinfo have the same aobjname.
99112576SAnurag.Maskey@Oracle.COM 					 * Use the flags to determine which
99212576SAnurag.Maskey@Oracle.COM 					 * address is present in the system.
99312576SAnurag.Maskey@Oracle.COM 					 */
99412576SAnurag.Maskey@Oracle.COM 					if (family == AF_INET6) {
99512576SAnurag.Maskey@Oracle.COM 						stateless_ai_found =
99612576SAnurag.Maskey@Oracle.COM 						    (a->ia_ifa.ifa_flags &
99712576SAnurag.Maskey@Oracle.COM 						    STATELESS_RUNNING);
99812576SAnurag.Maskey@Oracle.COM 						stateful_ai_found =
99912576SAnurag.Maskey@Oracle.COM 						    (a->ia_ifa.ifa_flags &
100012576SAnurag.Maskey@Oracle.COM 						    DHCP_RUNNING);
100112576SAnurag.Maskey@Oracle.COM 					}
100212576SAnurag.Maskey@Oracle.COM 				}
100311767SAnurag.Maskey@Sun.COM 			}
100411767SAnurag.Maskey@Sun.COM 		}
100511767SAnurag.Maskey@Sun.COM 
100612576SAnurag.Maskey@Oracle.COM 		/* Set the flags in the event for listeners */
100712576SAnurag.Maskey@Oracle.COM 		evm->nwe_data.nwe_if_state.nwe_flags = flags;
100812576SAnurag.Maskey@Oracle.COM 
100912576SAnurag.Maskey@Oracle.COM 		if (family == AF_INET && !addr_added) {
101011767SAnurag.Maskey@Sun.COM 			/*
101111767SAnurag.Maskey@Sun.COM 			 * Check for failure due to CR 6745448: if we get a
101211767SAnurag.Maskey@Sun.COM 			 * report that an address has been deleted, then check
101311767SAnurag.Maskey@Sun.COM 			 * for interface up, datalink down, and actual address
101411767SAnurag.Maskey@Sun.COM 			 * non-zero.  If that combination is seen, then this is
101511767SAnurag.Maskey@Sun.COM 			 * a DHCP cached lease, and we need to remove it from
101611767SAnurag.Maskey@Sun.COM 			 * the system, or it'll louse up the kernel routes
101711767SAnurag.Maskey@Sun.COM 			 * (which aren't smart enough to avoid dead
101811767SAnurag.Maskey@Sun.COM 			 * interfaces).
101911767SAnurag.Maskey@Sun.COM 			 */
102011767SAnurag.Maskey@Sun.COM 			if (((struct sockaddr_in *)addr)->sin_addr.s_addr
102112805SDarren.Reed@Oracle.COM 			    == INADDR_ANY && aip != 0) {
102212576SAnurag.Maskey@Oracle.COM 				struct sockaddr_in *a;
102312576SAnurag.Maskey@Oracle.COM 				char astr[INET6_ADDRSTRLEN];
102412805SDarren.Reed@Oracle.COM 				a = (struct sockaddr_in *)aip;
102511767SAnurag.Maskey@Sun.COM 
102611767SAnurag.Maskey@Sun.COM 				if ((flags & IFF_UP) &&
102711767SAnurag.Maskey@Sun.COM 				    !(flags & IFF_RUNNING) &&
102812576SAnurag.Maskey@Oracle.COM 				    a->sin_addr.s_addr != INADDR_ANY) {
102912576SAnurag.Maskey@Oracle.COM 					nlog(LOG_DEBUG,
103012576SAnurag.Maskey@Oracle.COM 					    "nwamd_ncu_handle_if_state_event: "
103112576SAnurag.Maskey@Oracle.COM 					    "bug workaround: clear out addr "
103212576SAnurag.Maskey@Oracle.COM 					    "%s on %s", nwamd_sockaddr2str
103312576SAnurag.Maskey@Oracle.COM 					    ((struct sockaddr *)a, astr,
103412576SAnurag.Maskey@Oracle.COM 					    sizeof (astr)),
103512576SAnurag.Maskey@Oracle.COM 					    ncu->ncu_name);
103612576SAnurag.Maskey@Oracle.COM 					nwamd_down_interface(
103712576SAnurag.Maskey@Oracle.COM 					    addrinfo->ia_aobjname,
103812576SAnurag.Maskey@Oracle.COM 					    IPADM_ADDR_DHCP, ncu->ncu_name);
103911767SAnurag.Maskey@Sun.COM 				}
104012576SAnurag.Maskey@Oracle.COM 				goto valid_done;
104111767SAnurag.Maskey@Sun.COM 			}
104211767SAnurag.Maskey@Sun.COM 		}
104311767SAnurag.Maskey@Sun.COM 
104411767SAnurag.Maskey@Sun.COM 		/*
104512576SAnurag.Maskey@Oracle.COM 		 * If we received an RTM_NEWADDR and the IFF_UP flags has not
104612576SAnurag.Maskey@Oracle.COM 		 * been set, ignore this IF_STATE event.  Once the IFF_UP flag
104712576SAnurag.Maskey@Oracle.COM 		 * is set, we'll get another RTM_NEWADDR message.
104812576SAnurag.Maskey@Oracle.COM 		 */
104912576SAnurag.Maskey@Oracle.COM 		if (addr_added & !(flags & IFF_UP)) {
105012576SAnurag.Maskey@Oracle.COM 			nlog(LOG_INFO, "nwamd_ncu_handle_if_state_event: "
105112576SAnurag.Maskey@Oracle.COM 			    "address %s added on %s without IFF_UP flag (%x), "
105212576SAnurag.Maskey@Oracle.COM 			    "ignoring IF_STATE event",
105312576SAnurag.Maskey@Oracle.COM 			    addrstr, ncu->ncu_name, flags);
105412576SAnurag.Maskey@Oracle.COM 			nwamd_event_do_not_send(event);
105512576SAnurag.Maskey@Oracle.COM 			goto valid_done;
105612576SAnurag.Maskey@Oracle.COM 		}
105712576SAnurag.Maskey@Oracle.COM 
105812576SAnurag.Maskey@Oracle.COM 		/*
105912576SAnurag.Maskey@Oracle.COM 		 * Has the address really been removed?  Sometimes spurious
106011767SAnurag.Maskey@Sun.COM 		 * RTM_DELADDRs are generated, so we need to ensure that
106111767SAnurag.Maskey@Sun.COM 		 * the address is really gone.  If IFF_DUPLICATE is set,
106211767SAnurag.Maskey@Sun.COM 		 * we're getting the RTM_DELADDR due to DAD, so don't test
106311767SAnurag.Maskey@Sun.COM 		 * in that case.
106411767SAnurag.Maskey@Sun.COM 		 */
106512576SAnurag.Maskey@Oracle.COM 		if (!addr_added && !(flags & IFF_DUPLICATE)) {
106612805SDarren.Reed@Oracle.COM 			if (aip != 0 && sockaddrcmp(addr, aip)) {
106712576SAnurag.Maskey@Oracle.COM 				nlog(LOG_INFO,
106811767SAnurag.Maskey@Sun.COM 				    "nwamd_ncu_handle_if_state_event: "
106911767SAnurag.Maskey@Sun.COM 				    "address %s is not really gone from %s, "
107011767SAnurag.Maskey@Sun.COM 				    "ignoring IF_STATE event",
107112576SAnurag.Maskey@Oracle.COM 				    addrstr, ncu->ncu_name);
107211767SAnurag.Maskey@Sun.COM 				nwamd_event_do_not_send(event);
107312576SAnurag.Maskey@Oracle.COM 				goto valid_done;
107411767SAnurag.Maskey@Sun.COM 			}
107511767SAnurag.Maskey@Sun.COM 		}
107611767SAnurag.Maskey@Sun.COM 
107712576SAnurag.Maskey@Oracle.COM 		if (addr_added) {
107811767SAnurag.Maskey@Sun.COM 			/*
107911767SAnurag.Maskey@Sun.COM 			 * Address has been added.
108011767SAnurag.Maskey@Sun.COM 			 *
108111767SAnurag.Maskey@Sun.COM 			 * We need to make sure that we really want to keep
108211767SAnurag.Maskey@Sun.COM 			 * this address.  There is a race where we requested an
108311767SAnurag.Maskey@Sun.COM 			 * address but by the time we got here we don't really
108411767SAnurag.Maskey@Sun.COM 			 * want it and need to remove it.
108511767SAnurag.Maskey@Sun.COM 			 *
108611767SAnurag.Maskey@Sun.COM 			 * Once we decide we want the address adjust the ncu
108711767SAnurag.Maskey@Sun.COM 			 * state accordingly.  For example if this address is
108811767SAnurag.Maskey@Sun.COM 			 * enough move online.
108911767SAnurag.Maskey@Sun.COM 			 */
109012576SAnurag.Maskey@Oracle.COM 			if (u_if->nwamd_if_dhcp_requested && v4dhcp_running) {
109111767SAnurag.Maskey@Sun.COM 				u_if->nwamd_if_dhcp_configured = B_TRUE;
109211767SAnurag.Maskey@Sun.COM 			} else if (u_if->nwamd_if_stateful_requested &&
109311767SAnurag.Maskey@Sun.COM 			    v6dhcp_running) {
109411767SAnurag.Maskey@Sun.COM 				u_if->nwamd_if_stateful_configured = B_TRUE;
109511767SAnurag.Maskey@Sun.COM 			} else if (u_if->nwamd_if_stateless_requested &&
109611767SAnurag.Maskey@Sun.COM 			    stateless_running) {
109711767SAnurag.Maskey@Sun.COM 				u_if->nwamd_if_stateless_configured = B_TRUE;
109812576SAnurag.Maskey@Oracle.COM 			} else if (!static_addr) {
109911767SAnurag.Maskey@Sun.COM 				/*
110011767SAnurag.Maskey@Sun.COM 				 * This is something we didn't expect.  Remove
110112576SAnurag.Maskey@Oracle.COM 				 * the address.
110211767SAnurag.Maskey@Sun.COM 				 */
110312576SAnurag.Maskey@Oracle.COM 				nwamd_down_interface(addrinfo->ia_aobjname,
110412576SAnurag.Maskey@Oracle.COM 				    addrinfo->ia_atype, ncu->ncu_name);
110512576SAnurag.Maskey@Oracle.COM 				nifa->configured = B_FALSE;
110612576SAnurag.Maskey@Oracle.COM 				goto valid_done;
110711767SAnurag.Maskey@Sun.COM 			}
110811767SAnurag.Maskey@Sun.COM 
110911767SAnurag.Maskey@Sun.COM 			/*
111011767SAnurag.Maskey@Sun.COM 			 * The address looks valid so mark configured and
111111767SAnurag.Maskey@Sun.COM 			 * move online if we either have a v4 address if
111211767SAnurag.Maskey@Sun.COM 			 * v4 is configured or a v6 address if only v6 is
111311767SAnurag.Maskey@Sun.COM 			 * configured.
111411767SAnurag.Maskey@Sun.COM 			 */
111512576SAnurag.Maskey@Oracle.COM 			nifa->configured = B_TRUE;
111611767SAnurag.Maskey@Sun.COM 			if (state != NWAM_STATE_ONLINE)
111711767SAnurag.Maskey@Sun.COM 				interface_ncu_up(ncu);
111811767SAnurag.Maskey@Sun.COM 
111911767SAnurag.Maskey@Sun.COM 			/*
112011767SAnurag.Maskey@Sun.COM 			 * Refresh network/location since we may also have other
112111767SAnurag.Maskey@Sun.COM 			 * DHCP information.  We might have to restore it first
112211767SAnurag.Maskey@Sun.COM 			 * in case it is in maintenance.
112311767SAnurag.Maskey@Sun.COM 			 */
112411767SAnurag.Maskey@Sun.COM 			nlog(LOG_DEBUG, "nwamd_handle_if_state_event: "
112511767SAnurag.Maskey@Sun.COM 			    "refreshing %s as we may have other "
112611767SAnurag.Maskey@Sun.COM 			    "DHCP information", NET_LOC_FMRI);
112711767SAnurag.Maskey@Sun.COM 			(void) smf_restore_instance(NET_LOC_FMRI);
112811767SAnurag.Maskey@Sun.COM 			if (smf_refresh_instance(NET_LOC_FMRI) != 0) {
112911767SAnurag.Maskey@Sun.COM 				nlog(LOG_ERR,
113011767SAnurag.Maskey@Sun.COM 				    "nwamd_ncu_handle_if_state_"
113111767SAnurag.Maskey@Sun.COM 				    "event: refresh of %s "
113211767SAnurag.Maskey@Sun.COM 				    "failed", NET_LOC_FMRI);
113311767SAnurag.Maskey@Sun.COM 			}
113412576SAnurag.Maskey@Oracle.COM 
113511767SAnurag.Maskey@Sun.COM 		} else if (state == NWAM_STATE_ONLINE ||
113611767SAnurag.Maskey@Sun.COM 		    state == NWAM_STATE_OFFLINE_TO_ONLINE) {
113711767SAnurag.Maskey@Sun.COM 			/*
113811767SAnurag.Maskey@Sun.COM 			 * Address has been removed.  Only pay attention to
113911767SAnurag.Maskey@Sun.COM 			 * disappearing addresses if we are online or coming
114011767SAnurag.Maskey@Sun.COM 			 * online.
114111767SAnurag.Maskey@Sun.COM 			 *
114211767SAnurag.Maskey@Sun.COM 			 * Undo whatever configuration is necessary.  Note
114311767SAnurag.Maskey@Sun.COM 			 * that this may or may not cause the NCU to go down.
114411767SAnurag.Maskey@Sun.COM 			 * We can get RTM_DELADDRs for duplicate addresses
114511767SAnurag.Maskey@Sun.COM 			 * so deal with this seperately.
114611767SAnurag.Maskey@Sun.COM 			 */
114712576SAnurag.Maskey@Oracle.COM 			nifa->configured = B_FALSE;
114812576SAnurag.Maskey@Oracle.COM 
114912576SAnurag.Maskey@Oracle.COM 			if (!static_addr && family == AF_INET) {
115011767SAnurag.Maskey@Sun.COM 				u_if->nwamd_if_dhcp_configured = B_FALSE;
115112576SAnurag.Maskey@Oracle.COM 			} else if (!static_addr && family == AF_INET6) {
115211767SAnurag.Maskey@Sun.COM 				/*
115312576SAnurag.Maskey@Oracle.COM 				 * The address is already gone.  When looking
115412576SAnurag.Maskey@Oracle.COM 				 * for the addrinfo (using aobjname in
115512576SAnurag.Maskey@Oracle.COM 				 * ipaddr), we found addrinfo for either one
115612576SAnurag.Maskey@Oracle.COM 				 * or both stateless and stateful.  Using the
115712576SAnurag.Maskey@Oracle.COM 				 * flags we determined whether each was
115812576SAnurag.Maskey@Oracle.COM 				 * configured or not.  Update the flags here
115912576SAnurag.Maskey@Oracle.COM 				 * accordingly.
116011767SAnurag.Maskey@Sun.COM 				 */
116112576SAnurag.Maskey@Oracle.COM 				u_if->nwamd_if_stateful_configured =
116212576SAnurag.Maskey@Oracle.COM 				    stateless_ai_found;
116312576SAnurag.Maskey@Oracle.COM 				u_if->nwamd_if_stateless_configured =
116412576SAnurag.Maskey@Oracle.COM 				    stateful_ai_found;
116511767SAnurag.Maskey@Sun.COM 			}
116611767SAnurag.Maskey@Sun.COM 
116711767SAnurag.Maskey@Sun.COM 			if (flags & IFF_DUPLICATE) {
116811767SAnurag.Maskey@Sun.COM 				nlog(LOG_INFO,
116911767SAnurag.Maskey@Sun.COM 				    "nwamd_ncu_handle_if_state_event: "
117011767SAnurag.Maskey@Sun.COM 				    "duplicate address detected on %s",
117111767SAnurag.Maskey@Sun.COM 				    ncu->ncu_name);
117211767SAnurag.Maskey@Sun.COM 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
117311767SAnurag.Maskey@Sun.COM 				    event->event_object,
117411767SAnurag.Maskey@Sun.COM 				    NWAM_STATE_MAINTENANCE,
117511767SAnurag.Maskey@Sun.COM 				    NWAM_AUX_STATE_IF_DUPLICATE_ADDR);
117611767SAnurag.Maskey@Sun.COM 			} else {
117711767SAnurag.Maskey@Sun.COM 				interface_ncu_down(ncu);
117811767SAnurag.Maskey@Sun.COM 			}
117911767SAnurag.Maskey@Sun.COM 		}
118012576SAnurag.Maskey@Oracle.COM valid_done:
118112576SAnurag.Maskey@Oracle.COM 		ipadm_free_addr_info(ai);
118211767SAnurag.Maskey@Sun.COM 	}
118311767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ncu_obj);
118411767SAnurag.Maskey@Sun.COM }
118511767SAnurag.Maskey@Sun.COM 
118611767SAnurag.Maskey@Sun.COM void
nwamd_ncu_handle_if_action_event(nwamd_event_t event)118711767SAnurag.Maskey@Sun.COM nwamd_ncu_handle_if_action_event(nwamd_event_t event)
118811767SAnurag.Maskey@Sun.COM {
118911767SAnurag.Maskey@Sun.COM 	nwamd_object_t ncu_obj;
119011767SAnurag.Maskey@Sun.COM 
119111767SAnurag.Maskey@Sun.COM 	nlog(LOG_DEBUG, "if action event %s",
119211767SAnurag.Maskey@Sun.COM 	    event->event_object[0] == '\0' ? "n/a" : event->event_object);
119311767SAnurag.Maskey@Sun.COM 
119411767SAnurag.Maskey@Sun.COM 	ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, event->event_object);
119511767SAnurag.Maskey@Sun.COM 	if (ncu_obj == NULL) {
119611767SAnurag.Maskey@Sun.COM 		nlog(LOG_ERR, "nwamd_ncu_handle_if_action_event: no object");
119711767SAnurag.Maskey@Sun.COM 		nwamd_event_do_not_send(event);
119811767SAnurag.Maskey@Sun.COM 		return;
119911767SAnurag.Maskey@Sun.COM 	}
120011767SAnurag.Maskey@Sun.COM 	nwamd_object_release(ncu_obj);
120111767SAnurag.Maskey@Sun.COM }
120211767SAnurag.Maskey@Sun.COM 
120311767SAnurag.Maskey@Sun.COM /*
120412576SAnurag.Maskey@Oracle.COM  * Remove the address in the given aobjname.  IPADM_OPT_RELEASE is specified
120512576SAnurag.Maskey@Oracle.COM  * for a DHCP address and specifies that the DHCP lease should also be released.
120612576SAnurag.Maskey@Oracle.COM  * ifname is only used for nlog().
120711767SAnurag.Maskey@Sun.COM  */
120811767SAnurag.Maskey@Sun.COM static void
nwamd_down_interface(const char * aobjname,ipadm_addr_type_t atype,const char * ifname)120912576SAnurag.Maskey@Oracle.COM nwamd_down_interface(const char *aobjname, ipadm_addr_type_t atype,
121012576SAnurag.Maskey@Oracle.COM     const char *ifname)
121111767SAnurag.Maskey@Sun.COM {
121212576SAnurag.Maskey@Oracle.COM 	ipadm_status_t ipstatus;
121312576SAnurag.Maskey@Oracle.COM 	uint32_t rflags = (atype == IPADM_ADDR_DHCP ? IPADM_OPT_RELEASE : 0);
121411767SAnurag.Maskey@Sun.COM 
121512576SAnurag.Maskey@Oracle.COM 	nlog(LOG_DEBUG, "nwamd_down_interface: %s [aobjname = %s]",
121612576SAnurag.Maskey@Oracle.COM 	    ifname, aobjname);
121712576SAnurag.Maskey@Oracle.COM 	if ((ipstatus = ipadm_delete_addr(ipadm_handle, aobjname,
121812576SAnurag.Maskey@Oracle.COM 	    IPADM_OPT_ACTIVE | rflags)) != IPADM_SUCCESS) {
121912576SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "nwamd_down_interface: "
122012576SAnurag.Maskey@Oracle.COM 		    "ipadm_delete_addr failed on %s: %s",
122112576SAnurag.Maskey@Oracle.COM 		    ifname, ipadm_status2str(ipstatus));
122211767SAnurag.Maskey@Sun.COM 	}
122312576SAnurag.Maskey@Oracle.COM }
122411767SAnurag.Maskey@Sun.COM 
122512576SAnurag.Maskey@Oracle.COM static void
unconfigure_addresses(nwamd_ncu_t * ncu,sa_family_t af)122612576SAnurag.Maskey@Oracle.COM unconfigure_addresses(nwamd_ncu_t *ncu, sa_family_t af)
122712576SAnurag.Maskey@Oracle.COM {
122812576SAnurag.Maskey@Oracle.COM 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
122911767SAnurag.Maskey@Sun.COM 
123012576SAnurag.Maskey@Oracle.COM 	for (nifap = nifa; nifap != NULL; nifap = nifap->next)
123112576SAnurag.Maskey@Oracle.COM 		if (af == AF_UNSPEC || nifap->family == af)
123212576SAnurag.Maskey@Oracle.COM 			nifap->configured = B_FALSE;
123312576SAnurag.Maskey@Oracle.COM }
123412576SAnurag.Maskey@Oracle.COM 
123512576SAnurag.Maskey@Oracle.COM static void
dhcp_release(const char * ifname)123612576SAnurag.Maskey@Oracle.COM dhcp_release(const char *ifname)
123712576SAnurag.Maskey@Oracle.COM {
123812576SAnurag.Maskey@Oracle.COM 	ipadm_addr_info_t *ainfo, *ainfop;
123911767SAnurag.Maskey@Sun.COM 
124012576SAnurag.Maskey@Oracle.COM 	if (ipadm_addr_info(ipadm_handle, ifname, &ainfo, 0, 0)
124112576SAnurag.Maskey@Oracle.COM 	    != IPADM_SUCCESS)
124212576SAnurag.Maskey@Oracle.COM 		return;
124312576SAnurag.Maskey@Oracle.COM 
124412576SAnurag.Maskey@Oracle.COM 	for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
124512576SAnurag.Maskey@Oracle.COM 		if (ainfop->ia_atype == IPADM_ADDR_DHCP)
124612576SAnurag.Maskey@Oracle.COM 			nwamd_down_interface(ainfop->ia_aobjname,
124712576SAnurag.Maskey@Oracle.COM 			    ainfop->ia_atype, ifname);
124811767SAnurag.Maskey@Sun.COM 	}
124912576SAnurag.Maskey@Oracle.COM 	ipadm_free_addr_info(ainfo);
125011767SAnurag.Maskey@Sun.COM }
125111767SAnurag.Maskey@Sun.COM 
125211767SAnurag.Maskey@Sun.COM static void
nwamd_plumb_unplumb_interface(nwamd_ncu_t * ncu,sa_family_t af,boolean_t plumb)125312576SAnurag.Maskey@Oracle.COM nwamd_plumb_unplumb_interface(nwamd_ncu_t *ncu, sa_family_t af, boolean_t plumb)
125411767SAnurag.Maskey@Sun.COM {
125512576SAnurag.Maskey@Oracle.COM 	char *ifname = ncu->ncu_name;
125612576SAnurag.Maskey@Oracle.COM 	nwamd_if_t *u_if = &ncu->ncu_if;
125712576SAnurag.Maskey@Oracle.COM 	ipadm_status_t ipstatus;
125812576SAnurag.Maskey@Oracle.COM 
125912576SAnurag.Maskey@Oracle.COM 	nlog(LOG_DEBUG, "nwamd_plumb_unplumb_interface: %s %s %s",
126012576SAnurag.Maskey@Oracle.COM 	    (plumb ? "plumb" : "unplumb"), (af == AF_INET ? "IPv4" : "IPv6"),
126112576SAnurag.Maskey@Oracle.COM 	    ifname);
126211767SAnurag.Maskey@Sun.COM 
126312576SAnurag.Maskey@Oracle.COM 	if (plumb) {
126412576SAnurag.Maskey@Oracle.COM 		ipstatus = ipadm_create_if(ipadm_handle, ifname, af,
126512576SAnurag.Maskey@Oracle.COM 		    IPADM_OPT_ACTIVE);
126612576SAnurag.Maskey@Oracle.COM 	} else {
126712576SAnurag.Maskey@Oracle.COM 		/* release DHCP address, if any */
126812576SAnurag.Maskey@Oracle.COM 		if (af == AF_INET)
126912576SAnurag.Maskey@Oracle.COM 			dhcp_release(ifname);
127012576SAnurag.Maskey@Oracle.COM 		ipstatus = ipadm_delete_if(ipadm_handle, ifname, af,
127112576SAnurag.Maskey@Oracle.COM 		    IPADM_OPT_ACTIVE);
127211767SAnurag.Maskey@Sun.COM 	}
127311767SAnurag.Maskey@Sun.COM 
127412576SAnurag.Maskey@Oracle.COM 	if (ipstatus != IPADM_SUCCESS) {
127512576SAnurag.Maskey@Oracle.COM 		if ((plumb && ipstatus != IPADM_IF_EXISTS) ||
127612576SAnurag.Maskey@Oracle.COM 		    (!plumb && ipstatus != IPADM_ENXIO)) {
127711767SAnurag.Maskey@Sun.COM 			nlog(LOG_ERR, "nwamd_plumb_unplumb_interface: "
127811767SAnurag.Maskey@Sun.COM 			    "%s %s failed for %s: %s",
127912576SAnurag.Maskey@Oracle.COM 			    (plumb ? "plumb" : "unplumb"),
128012576SAnurag.Maskey@Oracle.COM 			    (af == AF_INET ? "IPv4" : "IPv6"),
128112576SAnurag.Maskey@Oracle.COM 			    ifname, ipadm_status2str(ipstatus));
128211767SAnurag.Maskey@Sun.COM 		}
128311767SAnurag.Maskey@Sun.COM 	}
128411767SAnurag.Maskey@Sun.COM 
128512576SAnurag.Maskey@Oracle.COM 	/* Unset flags */
128611767SAnurag.Maskey@Sun.COM 	if (!plumb) {
128712576SAnurag.Maskey@Oracle.COM 		unconfigure_addresses(ncu, af);
128811767SAnurag.Maskey@Sun.COM 		switch (af) {
128912576SAnurag.Maskey@Oracle.COM 		case AF_INET:
129012576SAnurag.Maskey@Oracle.COM 			u_if->nwamd_if_dhcp_configured = B_FALSE;
129112576SAnurag.Maskey@Oracle.COM 			break;
129212576SAnurag.Maskey@Oracle.COM 		case AF_INET6:
129312576SAnurag.Maskey@Oracle.COM 			u_if->nwamd_if_stateful_configured = B_FALSE;
129412576SAnurag.Maskey@Oracle.COM 			u_if->nwamd_if_stateless_configured = B_FALSE;
129512576SAnurag.Maskey@Oracle.COM 			break;
129611767SAnurag.Maskey@Sun.COM 		}
129711767SAnurag.Maskey@Sun.COM 	}
129811767SAnurag.Maskey@Sun.COM }
129911767SAnurag.Maskey@Sun.COM 
130011767SAnurag.Maskey@Sun.COM void
nwamd_plumb_interface(nwamd_ncu_t * ncu,sa_family_t af)130112576SAnurag.Maskey@Oracle.COM nwamd_plumb_interface(nwamd_ncu_t *ncu, sa_family_t af)
130211767SAnurag.Maskey@Sun.COM {
130311918SMichael.Hunter@Sun.COM 	/*
130411918SMichael.Hunter@Sun.COM 	 * We get all posssible privs by calling nwamd_deescalate().  During
130511918SMichael.Hunter@Sun.COM 	 * startup opening /dev/dld (data link management) needs all privs
130611918SMichael.Hunter@Sun.COM 	 * because we don't have access to /etc/security/device_policy yet.
130711918SMichael.Hunter@Sun.COM 	 */
130811918SMichael.Hunter@Sun.COM 	nwamd_escalate();
130912576SAnurag.Maskey@Oracle.COM 	nwamd_plumb_unplumb_interface(ncu, af, B_TRUE);
131011918SMichael.Hunter@Sun.COM 	nwamd_deescalate();
131111767SAnurag.Maskey@Sun.COM }
131211767SAnurag.Maskey@Sun.COM 
131311767SAnurag.Maskey@Sun.COM void
nwamd_unplumb_interface(nwamd_ncu_t * ncu,sa_family_t af)131412576SAnurag.Maskey@Oracle.COM nwamd_unplumb_interface(nwamd_ncu_t *ncu, sa_family_t af)
131511767SAnurag.Maskey@Sun.COM {
131612576SAnurag.Maskey@Oracle.COM 	nwamd_plumb_unplumb_interface(ncu, af, B_FALSE);
131711767SAnurag.Maskey@Sun.COM }
131811767SAnurag.Maskey@Sun.COM 
131911767SAnurag.Maskey@Sun.COM static void *
start_dhcp_thread(void * arg)132011767SAnurag.Maskey@Sun.COM start_dhcp_thread(void *arg)
132111767SAnurag.Maskey@Sun.COM {
132212576SAnurag.Maskey@Oracle.COM 	struct nwamd_dhcp_thread_arg *thread_arg = arg;
132312576SAnurag.Maskey@Oracle.COM 	nwamd_object_t ncu_obj;
132411767SAnurag.Maskey@Sun.COM 	dhcp_ipc_type_t type;
132511767SAnurag.Maskey@Sun.COM 	char *name;
132612576SAnurag.Maskey@Oracle.COM 	ipadm_addrobj_t ipaddr;
132712576SAnurag.Maskey@Oracle.COM 	ipadm_status_t ipstatus;
132812576SAnurag.Maskey@Oracle.COM 	int retries = 0;
132911767SAnurag.Maskey@Sun.COM 
133011767SAnurag.Maskey@Sun.COM 	name = thread_arg->name;
133111767SAnurag.Maskey@Sun.COM 	type = thread_arg->type;
133212576SAnurag.Maskey@Oracle.COM 	ipaddr = thread_arg->ipaddr;
133311767SAnurag.Maskey@Sun.COM 
133411767SAnurag.Maskey@Sun.COM retry:
133512576SAnurag.Maskey@Oracle.COM 	/* Make sure the NCU is in appropriate state for DHCP command */
133612576SAnurag.Maskey@Oracle.COM 	ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE, name);
133712576SAnurag.Maskey@Oracle.COM 	if (ncu_obj == NULL) {
1338*13107SRenee.Sommerfeld@Oracle.COM 		nlog(LOG_ERR, "start_dhcp: no IP object %s", name);
133912576SAnurag.Maskey@Oracle.COM 		return (NULL);
134011767SAnurag.Maskey@Sun.COM 	}
134111767SAnurag.Maskey@Sun.COM 
134212576SAnurag.Maskey@Oracle.COM 	if (ncu_obj->nwamd_object_state != NWAM_STATE_OFFLINE_TO_ONLINE &&
134312576SAnurag.Maskey@Oracle.COM 	    ncu_obj->nwamd_object_state != NWAM_STATE_ONLINE) {
134412576SAnurag.Maskey@Oracle.COM 		nlog(LOG_INFO, "start_dhcp: IP NCU %s is in invalid state "
134512576SAnurag.Maskey@Oracle.COM 		    "for DHCP command", ncu_obj->nwamd_object_name);
134612576SAnurag.Maskey@Oracle.COM 		nwamd_object_release(ncu_obj);
134712576SAnurag.Maskey@Oracle.COM 		return (NULL);
134811767SAnurag.Maskey@Sun.COM 	}
134912576SAnurag.Maskey@Oracle.COM 	nwamd_object_release(ncu_obj);
135012576SAnurag.Maskey@Oracle.COM 
135112576SAnurag.Maskey@Oracle.COM 	switch (type) {
135212576SAnurag.Maskey@Oracle.COM 	case DHCP_INFORM:
135312576SAnurag.Maskey@Oracle.COM 	{
135412576SAnurag.Maskey@Oracle.COM 		char aobjname[IPADM_AOBJSIZ];
135511767SAnurag.Maskey@Sun.COM 
135612576SAnurag.Maskey@Oracle.COM 		if ((ipstatus = ipadm_get_aobjname(ipaddr, aobjname,
135712576SAnurag.Maskey@Oracle.COM 		    sizeof (aobjname))) != IPADM_SUCCESS) {
135812576SAnurag.Maskey@Oracle.COM 			nlog(LOG_ERR, "start_dhcp: "
135912576SAnurag.Maskey@Oracle.COM 			    "ipadm_get_aobjname failed for %s: %s",
136012576SAnurag.Maskey@Oracle.COM 			    name, ipadm_status2str(ipstatus));
136112576SAnurag.Maskey@Oracle.COM 			goto done;
136211767SAnurag.Maskey@Sun.COM 		}
136312576SAnurag.Maskey@Oracle.COM 		ipstatus = ipadm_refresh_addr(ipadm_handle, aobjname,
136412576SAnurag.Maskey@Oracle.COM 		    IPADM_OPT_ACTIVE | IPADM_OPT_INFORM);
136512576SAnurag.Maskey@Oracle.COM 		break;
136612576SAnurag.Maskey@Oracle.COM 	}
136712576SAnurag.Maskey@Oracle.COM 	case DHCP_START:
136812576SAnurag.Maskey@Oracle.COM 		ipstatus = ipadm_create_addr(ipadm_handle, ipaddr,
136912576SAnurag.Maskey@Oracle.COM 		    IPADM_OPT_ACTIVE);
137012912SAnurag.Maskey@Oracle.COM 		break;
137112912SAnurag.Maskey@Oracle.COM 	default:
137212912SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "start_dhcp: invalid dhcp_ipc_type_t: %d", type);
137312912SAnurag.Maskey@Oracle.COM 		goto done;
137412912SAnurag.Maskey@Oracle.COM 	}
137512576SAnurag.Maskey@Oracle.COM 
137612912SAnurag.Maskey@Oracle.COM 	if (ipstatus == IPADM_DHCP_IPC_TIMEOUT) {
137712912SAnurag.Maskey@Oracle.COM 		/*
137812912SAnurag.Maskey@Oracle.COM 		 * DHCP timed out: for DHCP_START requests, change state for
137912912SAnurag.Maskey@Oracle.COM 		 * this NCU and euqueue event to check NCU priority-groups;
138012912SAnurag.Maskey@Oracle.COM 		 * for DHCP_INFORM requests, nothing to do.
138112912SAnurag.Maskey@Oracle.COM 		 */
138212912SAnurag.Maskey@Oracle.COM 		if (type == DHCP_START) {
138311767SAnurag.Maskey@Sun.COM 			char *object_name;
138411767SAnurag.Maskey@Sun.COM 
138512912SAnurag.Maskey@Oracle.COM 			nlog(LOG_INFO,
138612912SAnurag.Maskey@Oracle.COM 			    "start_dhcp: DHCP_START timed out for %s", name);
138712576SAnurag.Maskey@Oracle.COM 
138811767SAnurag.Maskey@Sun.COM 			if (nwam_ncu_name_to_typed_name(name,
138911767SAnurag.Maskey@Sun.COM 			    NWAM_NCU_TYPE_INTERFACE, &object_name)
139011767SAnurag.Maskey@Sun.COM 			    != NWAM_SUCCESS) {
139111767SAnurag.Maskey@Sun.COM 				nlog(LOG_ERR, "start_dhcp: "
139212912SAnurag.Maskey@Oracle.COM 				    "nwam_ncu_name_to_typed_name failed for %s",
139312912SAnurag.Maskey@Oracle.COM 				    name);
139412576SAnurag.Maskey@Oracle.COM 				goto done;
139511767SAnurag.Maskey@Sun.COM 			}
139611767SAnurag.Maskey@Sun.COM 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
139711767SAnurag.Maskey@Sun.COM 			    object_name, NWAM_STATE_OFFLINE_TO_ONLINE,
139811767SAnurag.Maskey@Sun.COM 			    NWAM_AUX_STATE_IF_DHCP_TIMED_OUT);
139911767SAnurag.Maskey@Sun.COM 			nwamd_create_ncu_check_event(0);
140011767SAnurag.Maskey@Sun.COM 			free(object_name);
140112912SAnurag.Maskey@Oracle.COM 		} else {
140212912SAnurag.Maskey@Oracle.COM 			nlog(LOG_INFO,
140312912SAnurag.Maskey@Oracle.COM 			    "start_dhcp: DHCP_INFORM timed out for %s", name);
140412912SAnurag.Maskey@Oracle.COM 		}
140511767SAnurag.Maskey@Sun.COM 
140612912SAnurag.Maskey@Oracle.COM 	} else if ((ipstatus == IPADM_DHCP_IPC_ERROR ||
140712912SAnurag.Maskey@Oracle.COM 	    ipstatus == IPADM_IPC_ERROR) && retries++ < NWAMD_DHCP_RETRIES) {
140812912SAnurag.Maskey@Oracle.COM 		/*
140912912SAnurag.Maskey@Oracle.COM 		 * Retry DHCP request as we may have been unplumbing as part
141012912SAnurag.Maskey@Oracle.COM 		 * of the configuration phase.
141112912SAnurag.Maskey@Oracle.COM 		 */
141212912SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "start_dhcp: ipadm_%s_addr on %s returned: %s, "
141312912SAnurag.Maskey@Oracle.COM 		    "retrying in %d sec",
141412912SAnurag.Maskey@Oracle.COM 		    (type == DHCP_START ? "create" : "refresh"), name,
141512912SAnurag.Maskey@Oracle.COM 		    ipadm_status2str(ipstatus), NWAMD_DHCP_RETRY_WAIT_TIME);
141612912SAnurag.Maskey@Oracle.COM 		(void) sleep(NWAMD_DHCP_RETRY_WAIT_TIME);
141712912SAnurag.Maskey@Oracle.COM 		goto retry;
141811767SAnurag.Maskey@Sun.COM 
141912912SAnurag.Maskey@Oracle.COM 	} else if (ipstatus != IPADM_SUCCESS) {
142012576SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "start_dhcp: ipadm_%s_addr failed for %s: %s",
142112912SAnurag.Maskey@Oracle.COM 		    (type == DHCP_START ? "create" : "refresh"), name,
142212912SAnurag.Maskey@Oracle.COM 		    ipadm_status2str(ipstatus));
142311767SAnurag.Maskey@Sun.COM 	}
142411767SAnurag.Maskey@Sun.COM 
142512576SAnurag.Maskey@Oracle.COM done:
142612576SAnurag.Maskey@Oracle.COM 	free(name);
142712576SAnurag.Maskey@Oracle.COM 	free(arg);
142811767SAnurag.Maskey@Sun.COM 	return (NULL);
142911767SAnurag.Maskey@Sun.COM }
143011767SAnurag.Maskey@Sun.COM 
143112576SAnurag.Maskey@Oracle.COM static void
nwamd_dhcp(const char * ifname,ipadm_addrobj_t ipaddr,dhcp_ipc_type_t cmd)143212576SAnurag.Maskey@Oracle.COM nwamd_dhcp(const char *ifname, ipadm_addrobj_t ipaddr, dhcp_ipc_type_t cmd)
143311767SAnurag.Maskey@Sun.COM {
143411767SAnurag.Maskey@Sun.COM 	struct nwamd_dhcp_thread_arg *arg;
143511767SAnurag.Maskey@Sun.COM 	pthread_attr_t attr;
143611767SAnurag.Maskey@Sun.COM 
143712576SAnurag.Maskey@Oracle.COM 	nlog(LOG_DEBUG, "nwamd_dhcp: starting DHCP %s thread for %s",
143812576SAnurag.Maskey@Oracle.COM 	    dhcp_ipc_type_to_string(cmd), ifname);
143911767SAnurag.Maskey@Sun.COM 
144011767SAnurag.Maskey@Sun.COM 	arg = malloc(sizeof (*arg));
144111767SAnurag.Maskey@Sun.COM 	if (arg == NULL) {
144212576SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "nwamd_dhcp: error allocating memory for "
144312576SAnurag.Maskey@Oracle.COM 		    "dhcp request");
144411767SAnurag.Maskey@Sun.COM 		return;
144511767SAnurag.Maskey@Sun.COM 	}
144611767SAnurag.Maskey@Sun.COM 
144712576SAnurag.Maskey@Oracle.COM 	arg->name = strdup(ifname);
144812576SAnurag.Maskey@Oracle.COM 	arg->type = cmd;
144912576SAnurag.Maskey@Oracle.COM 	arg->ipaddr = ipaddr;
145011767SAnurag.Maskey@Sun.COM 
145111767SAnurag.Maskey@Sun.COM 	(void) pthread_attr_init(&attr);
145211767SAnurag.Maskey@Sun.COM 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
145311767SAnurag.Maskey@Sun.COM 	if (pthread_create(NULL, &attr, start_dhcp_thread, arg) == -1) {
145412576SAnurag.Maskey@Oracle.COM 		nlog(LOG_ERR, "nwamd_dhcp: cannot start dhcp thread");
145512576SAnurag.Maskey@Oracle.COM 		free(arg->name);
145611767SAnurag.Maskey@Sun.COM 		free(arg);
145711767SAnurag.Maskey@Sun.COM 		(void) pthread_attr_destroy(&attr);
145811767SAnurag.Maskey@Sun.COM 		return;
145911767SAnurag.Maskey@Sun.COM 	}
146011767SAnurag.Maskey@Sun.COM 	(void) pthread_attr_destroy(&attr);
146111767SAnurag.Maskey@Sun.COM }
1462