16ba597c5SAnurag S. Maskey /*
26ba597c5SAnurag S. Maskey  * CDDL HEADER START
36ba597c5SAnurag S. Maskey  *
46ba597c5SAnurag S. Maskey  * The contents of this file are subject to the terms of the
56ba597c5SAnurag S. Maskey  * Common Development and Distribution License (the "License").
66ba597c5SAnurag S. Maskey  * You may not use this file except in compliance with the License.
76ba597c5SAnurag S. Maskey  *
86ba597c5SAnurag S. Maskey  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96ba597c5SAnurag S. Maskey  * or http://www.opensolaris.org/os/licensing.
106ba597c5SAnurag S. Maskey  * See the License for the specific language governing permissions
116ba597c5SAnurag S. Maskey  * and limitations under the License.
126ba597c5SAnurag S. Maskey  *
136ba597c5SAnurag S. Maskey  * When distributing Covered Code, include this CDDL HEADER in each
146ba597c5SAnurag S. Maskey  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156ba597c5SAnurag S. Maskey  * If applicable, add the following below this CDDL HEADER, with the
166ba597c5SAnurag S. Maskey  * fields enclosed by brackets "[]" replaced with your own identifying
176ba597c5SAnurag S. Maskey  * information: Portions Copyright [yyyy] [name of copyright owner]
186ba597c5SAnurag S. Maskey  *
196ba597c5SAnurag S. Maskey  * CDDL HEADER END
206ba597c5SAnurag S. Maskey  */
216ba597c5SAnurag S. Maskey 
226ba597c5SAnurag S. Maskey /*
23f6da83d4SAnurag S. Maskey  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
246ba597c5SAnurag S. Maskey  */
256ba597c5SAnurag S. Maskey 
266ba597c5SAnurag S. Maskey #include <arpa/inet.h>
276ba597c5SAnurag S. Maskey #include <assert.h>
286ba597c5SAnurag S. Maskey #include <dhcpagent_ipc.h>
296ba597c5SAnurag S. Maskey #include <dhcp_inittab.h>
306ba597c5SAnurag S. Maskey #include <dhcp_symbol.h>
316ba597c5SAnurag S. Maskey #include <dhcpagent_util.h>
326ba597c5SAnurag S. Maskey #include <errno.h>
336ba597c5SAnurag S. Maskey #include <execinfo.h>
346ba597c5SAnurag S. Maskey #include <libnwam.h>
356ba597c5SAnurag S. Maskey #include <stdlib.h>
366ba597c5SAnurag S. Maskey #include <strings.h>
376ba597c5SAnurag S. Maskey #include <ucontext.h>
386ba597c5SAnurag S. Maskey #include <unistd.h>
396ba597c5SAnurag S. Maskey #include <libscf.h>
406ba597c5SAnurag S. Maskey 
416ba597c5SAnurag S. Maskey #include "conditions.h"
426ba597c5SAnurag S. Maskey #include "events.h"
436ba597c5SAnurag S. Maskey #include "ncp.h"
446ba597c5SAnurag S. Maskey #include "ncu.h"
456ba597c5SAnurag S. Maskey #include "objects.h"
466ba597c5SAnurag S. Maskey #include "util.h"
476ba597c5SAnurag S. Maskey 
486ba597c5SAnurag S. Maskey /*
496ba597c5SAnurag S. Maskey  * ncu_ip.c - contains routines that are IP interface-specific for NCUs.
506ba597c5SAnurag S. Maskey  */
516ba597c5SAnurag S. Maskey 
526ba597c5SAnurag S. Maskey #define	STATELESS_RUNNING	(IFF_RUNNING | IFF_UP | IFF_ADDRCONF)
536ba597c5SAnurag S. Maskey #define	DHCP_RUNNING		(IFF_RUNNING | IFF_UP | IFF_DHCPRUNNING)
546ba597c5SAnurag S. Maskey 
55f6da83d4SAnurag S. Maskey static void nwamd_dhcp(const char *, ipadm_addrobj_t, dhcp_ipc_type_t);
56f6da83d4SAnurag S. Maskey static void nwamd_down_interface(const char *, ipadm_addr_type_t, const char *);
576ba597c5SAnurag S. Maskey static boolean_t stateless_running(const nwamd_ncu_t *);
586ba597c5SAnurag S. Maskey 
59f6da83d4SAnurag S. Maskey /*
60f6da83d4SAnurag S. Maskey  * Given a sockaddr representation of an IPv4 or IPv6 address returns the
61f6da83d4SAnurag S. Maskey  * string representation. Note that 'sockaddr' should point at the correct
62f6da83d4SAnurag S. Maskey  * sockaddr structure for the address family (sockaddr_in for AF_INET or
63f6da83d4SAnurag S. Maskey  * sockaddr_in6 for AF_INET6) or alternatively at a sockaddr_storage
64f6da83d4SAnurag S. Maskey  * structure.
65f6da83d4SAnurag S. Maskey  */
66f6da83d4SAnurag S. Maskey static const char *
nwamd_sockaddr2str(const struct sockaddr * addr,char * str,size_t len)67f6da83d4SAnurag S. Maskey nwamd_sockaddr2str(const struct sockaddr *addr, char *str, size_t len)
686ba597c5SAnurag S. Maskey {
69f6da83d4SAnurag S. Maskey 	struct sockaddr_in *sin;
70f6da83d4SAnurag S. Maskey 	struct sockaddr_in6 *sin6;
71f6da83d4SAnurag S. Maskey 	const char *straddr;
72f6da83d4SAnurag S. Maskey 
73f6da83d4SAnurag S. Maskey 	if (addr == NULL)
746ba597c5SAnurag S. Maskey 		return (NULL);
75f6da83d4SAnurag S. Maskey 
76f6da83d4SAnurag S. Maskey 	if (addr->sa_family == AF_INET) {
77f6da83d4SAnurag S. Maskey 		/* LINTED E_BAD_PTR_CAST_ALIGN */
78f6da83d4SAnurag S. Maskey 		sin = (struct sockaddr_in *)addr;
79f6da83d4SAnurag S. Maskey 		straddr = inet_ntop(AF_INET, (void *)&sin->sin_addr, str, len);
80f6da83d4SAnurag S. Maskey 	} else if (addr->sa_family == AF_INET6) {
81f6da83d4SAnurag S. Maskey 		/* LINTED E_BAD_PTR_CAST_ALIGN */
82f6da83d4SAnurag S. Maskey 		sin6 = (struct sockaddr_in6 *)addr;
83f6da83d4SAnurag S. Maskey 		straddr = inet_ntop(AF_INET6, (void *)&sin6->sin6_addr, str,
84f6da83d4SAnurag S. Maskey 		    len);
856ba597c5SAnurag S. Maskey 	} else {
86f6da83d4SAnurag S. Maskey 		errno = EINVAL;
87f6da83d4SAnurag S. Maskey 		return (NULL);
886ba597c5SAnurag S. Maskey 	}
89f6da83d4SAnurag S. Maskey 	return (straddr != NULL ? str : NULL);
906ba597c5SAnurag S. Maskey }
916ba597c5SAnurag S. Maskey 
926ba597c5SAnurag S. Maskey void
nwamd_propogate_link_up_down_to_ip(const char * linkname,boolean_t up)936ba597c5SAnurag S. Maskey nwamd_propogate_link_up_down_to_ip(const char *linkname, boolean_t up)
946ba597c5SAnurag S. Maskey {
956ba597c5SAnurag S. Maskey 	nwamd_object_t ip_ncu = nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE,
966ba597c5SAnurag S. Maskey 	    linkname);
976ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu;
986ba597c5SAnurag S. Maskey 
996ba597c5SAnurag S. Maskey 	if (ip_ncu == NULL) {
1006ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_propogate_link_up_down_to_ip: no IP NCU "
1016ba597c5SAnurag S. Maskey 		    "for link %s, cannot propogate %s event", linkname,
1026ba597c5SAnurag S. Maskey 		    up ? "up" : "down");
1036ba597c5SAnurag S. Maskey 		return;
1046ba597c5SAnurag S. Maskey 	}
1056ba597c5SAnurag S. Maskey 	ncu = ip_ncu->nwamd_object_data;
1066ba597c5SAnurag S. Maskey 
1076ba597c5SAnurag S. Maskey 	if (ncu->ncu_enabled) {
1086ba597c5SAnurag S. Maskey 		if (ip_ncu->nwamd_object_aux_state ==
1096ba597c5SAnurag S. Maskey 		    NWAM_AUX_STATE_UNINITIALIZED) {
1106ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG,
1116ba597c5SAnurag S. Maskey 			    "nwamd_propogate_link_up_down_to_ip: will not "
1126ba597c5SAnurag S. Maskey 			    "propogate link %s event as IP NCU %s is being "
1136ba597c5SAnurag S. Maskey 			    "removed", up ? "up" : "down", linkname);
1146ba597c5SAnurag S. Maskey 		} else {
1156ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG,
1166ba597c5SAnurag S. Maskey 			    "nwamd_propogate_link_up_down_to_ip: propogating "
1176ba597c5SAnurag S. Maskey 			    "link %s event to interface %s",
1186ba597c5SAnurag S. Maskey 			    up ? "up" : "down", linkname);
1196ba597c5SAnurag S. Maskey 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
1206ba597c5SAnurag S. Maskey 			    ip_ncu->nwamd_object_name,
1216ba597c5SAnurag S. Maskey 			    up ?
1226ba597c5SAnurag S. Maskey 			    NWAM_STATE_OFFLINE_TO_ONLINE :
1236ba597c5SAnurag S. Maskey 			    NWAM_STATE_ONLINE_TO_OFFLINE,
1246ba597c5SAnurag S. Maskey 			    up ? NWAM_AUX_STATE_INITIALIZED :
1256ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_CONDITIONS_NOT_MET);
1266ba597c5SAnurag S. Maskey 		}
1276ba597c5SAnurag S. Maskey 	} else {
1286ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG,
1296ba597c5SAnurag S. Maskey 		    "nwamd_propogate_link_up_down_to_ip: not propogating "
1306ba597c5SAnurag S. Maskey 		    "link %s event to interface %s, IP NCU is disabled",
1316ba597c5SAnurag S. Maskey 		    up ? "up" : "down", linkname);
1326ba597c5SAnurag S. Maskey 	}
1336ba597c5SAnurag S. Maskey 	nwamd_object_release(ip_ncu);
1346ba597c5SAnurag S. Maskey }
1356ba597c5SAnurag S. Maskey 
1366ba597c5SAnurag S. Maskey /*
1376ba597c5SAnurag S. Maskey  * Returns the value associated with the given symbol for the given
1386ba597c5SAnurag S. Maskey  * interface.  The interface may be NULL, in which case the primary
1396ba597c5SAnurag S. Maskey  * interface is used.
1406ba597c5SAnurag S. Maskey  * This function substitutes the need to call dhcpinfo(1), thus it is
1416ba597c5SAnurag S. Maskey  * very similar to the implementation of dhcpinfo(1).
1426ba597c5SAnurag S. Maskey  * When multiple values need to be returned (e.g., nameservers), they
1436ba597c5SAnurag S. Maskey  * are separated by a space ' '.
1446ba597c5SAnurag S. Maskey  */
1456ba597c5SAnurag S. Maskey char *
nwamd_get_dhcpinfo_data(const char * sym_name,char * ifname)1466ba597c5SAnurag S. Maskey nwamd_get_dhcpinfo_data(const char *sym_name, char *ifname)
1476ba597c5SAnurag S. Maskey {
1486ba597c5SAnurag S. Maskey 	dhcp_symbol_t *entry;
1496ba597c5SAnurag S. Maskey 	dhcp_optnum_t optnum;
150c3dd1218SToomas Soome 	dhcp_ipc_request_t *request = NULL;
1516ba597c5SAnurag S. Maskey 	dhcp_ipc_reply_t *reply;
1526ba597c5SAnurag S. Maskey 	DHCP_OPT *opt;
1536ba597c5SAnurag S. Maskey 	size_t opt_len;
1546ba597c5SAnurag S. Maskey 	char *value; /* return value */
1556ba597c5SAnurag S. Maskey 	int err;
1566ba597c5SAnurag S. Maskey 	char errmsg[LINE_MAX];
1576ba597c5SAnurag S. Maskey 
1586ba597c5SAnurag S. Maskey 	/* if interface is not given, change it to empty string */
1596ba597c5SAnurag S. Maskey 	if (ifname == NULL)
1606ba597c5SAnurag S. Maskey 		ifname = "";
1616ba597c5SAnurag S. Maskey 
162*bbf21555SRichard Lowe 	/* find code and category in dhcp_inittab(5) */
1636ba597c5SAnurag S. Maskey 	entry = inittab_getbyname(ITAB_CAT_SITE | ITAB_CAT_STANDARD |
1646ba597c5SAnurag S. Maskey 	    ITAB_CAT_VENDOR | ITAB_CAT_FIELD, ITAB_CONS_INFO, sym_name);
1656ba597c5SAnurag S. Maskey 
1666ba597c5SAnurag S. Maskey 	if (entry == NULL) {
1676ba597c5SAnurag S. Maskey 		(void) snprintf(errmsg, LINE_MAX, "unknown identifier: %s",
1686ba597c5SAnurag S. Maskey 		    sym_name);
1696ba597c5SAnurag S. Maskey 		goto fail;
1706ba597c5SAnurag S. Maskey 	}
1716ba597c5SAnurag S. Maskey 
1726ba597c5SAnurag S. Maskey 	/* allocate request */
1736ba597c5SAnurag S. Maskey 	optnum.code = entry->ds_code;
1746ba597c5SAnurag S. Maskey 	optnum.category = entry->ds_category;
1756ba597c5SAnurag S. Maskey 	optnum.size = entry->ds_max * inittab_type_to_size(entry);
1766ba597c5SAnurag S. Maskey 	request = dhcp_ipc_alloc_request(DHCP_GET_TAG, ifname, &optnum,
1776ba597c5SAnurag S. Maskey 	    sizeof (dhcp_optnum_t), DHCP_TYPE_OPTNUM);
1786ba597c5SAnurag S. Maskey 	if (request == NULL) {
1796ba597c5SAnurag S. Maskey 		(void) snprintf(errmsg, LINE_MAX, "failed dhcp alloc request");
1806ba597c5SAnurag S. Maskey 		goto fail;
1816ba597c5SAnurag S. Maskey 	}
1826ba597c5SAnurag S. Maskey 
1836ba597c5SAnurag S. Maskey 	/* make the request */
1846ba597c5SAnurag S. Maskey 	err = dhcp_ipc_make_request(request, &reply, DHCP_IPC_WAIT_DEFAULT);
1856ba597c5SAnurag S. Maskey 	if (err != 0 || reply->return_code != 0) {
1866ba597c5SAnurag S. Maskey 		(void) snprintf(errmsg, LINE_MAX, "%s",
1876ba597c5SAnurag S. Maskey 		    dhcp_ipc_strerror(err == 0 ? reply->return_code : err));
1886ba597c5SAnurag S. Maskey 	}
1896ba597c5SAnurag S. Maskey 
1906ba597c5SAnurag S. Maskey 	/* get data from the reply */
1916ba597c5SAnurag S. Maskey 	opt = dhcp_ipc_get_data(reply, &opt_len, NULL);
1926ba597c5SAnurag S. Maskey 	if (opt_len == 0) {
1936ba597c5SAnurag S. Maskey 		(void) snprintf(errmsg, LINE_MAX, "invalid data");
1946ba597c5SAnurag S. Maskey 		goto fail;
1956ba597c5SAnurag S. Maskey 	}
1966ba597c5SAnurag S. Maskey 
1976ba597c5SAnurag S. Maskey 	/* check protocol error */
1986ba597c5SAnurag S. Maskey 	if (opt_len < 2 || (opt_len -2 != opt->len)) {
1996ba597c5SAnurag S. Maskey 		(void) snprintf(errmsg, LINE_MAX, "data length mismatch");
2006ba597c5SAnurag S. Maskey 		goto fail;
2016ba597c5SAnurag S. Maskey 	}
2026ba597c5SAnurag S. Maskey 	opt_len -= 2;
2036ba597c5SAnurag S. Maskey 
2046ba597c5SAnurag S. Maskey 	/* decode the data into ascii */
2056ba597c5SAnurag S. Maskey 	value = inittab_decode(entry, opt->value, opt_len, B_TRUE);
2066ba597c5SAnurag S. Maskey 	if (value == NULL) {
2076ba597c5SAnurag S. Maskey 		(void) snprintf(errmsg, LINE_MAX, "cannot decode reply");
2086ba597c5SAnurag S. Maskey 		goto fail;
2096ba597c5SAnurag S. Maskey 	}
2106ba597c5SAnurag S. Maskey 
2116ba597c5SAnurag S. Maskey 	free(request);
2126ba597c5SAnurag S. Maskey 	free(reply);
2136ba597c5SAnurag S. Maskey 	return (value);
2146ba597c5SAnurag S. Maskey 
2156ba597c5SAnurag S. Maskey fail:
2166ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "get_dhcpinfo_data() failed: %s", errmsg);
2176ba597c5SAnurag S. Maskey 	free(request);
2186ba597c5SAnurag S. Maskey 	free(reply);
2196ba597c5SAnurag S. Maskey 	return (NULL);
2206ba597c5SAnurag S. Maskey }
2216ba597c5SAnurag S. Maskey 
2226ba597c5SAnurag S. Maskey void
nwamd_add_default_routes(nwamd_ncu_t * ncu)2236ba597c5SAnurag S. Maskey nwamd_add_default_routes(nwamd_ncu_t *ncu)
2246ba597c5SAnurag S. Maskey {
225f6da83d4SAnurag S. Maskey 	nwamd_if_t *nif = &ncu->ncu_if;
2266ba597c5SAnurag S. Maskey 	char str[INET6_ADDRSTRLEN];
2276ba597c5SAnurag S. Maskey 
2286ba597c5SAnurag S. Maskey 	if (nif->nwamd_if_ipv4 && nif->nwamd_if_ipv4_default_route_set) {
2296ba597c5SAnurag S. Maskey 		struct sockaddr_in v4dest, v4mask;
2306ba597c5SAnurag S. Maskey 
2316ba597c5SAnurag S. Maskey 		v4dest.sin_addr.s_addr = htonl(INADDR_ANY);
2326ba597c5SAnurag S. Maskey 		v4dest.sin_family = AF_INET;
2336ba597c5SAnurag S. Maskey 
2346ba597c5SAnurag S. Maskey 		v4mask.sin_addr.s_addr = 0;
2356ba597c5SAnurag S. Maskey 		v4mask.sin_family = AF_INET;
2366ba597c5SAnurag S. Maskey 
2376ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_add_default_routes: adding default "
238f6da83d4SAnurag S. Maskey 		    "route %s", nwamd_sockaddr2str((struct sockaddr *)
239f6da83d4SAnurag S. Maskey 		    &nif->nwamd_if_ipv4_default_route, str,
2406ba597c5SAnurag S. Maskey 		    sizeof (str)));
2416ba597c5SAnurag S. Maskey 		nwamd_add_route((struct sockaddr *)&v4dest,
2426ba597c5SAnurag S. Maskey 		    (struct sockaddr *)&v4mask,
2436ba597c5SAnurag S. Maskey 		    (struct sockaddr *)&nif->nwamd_if_ipv4_default_route,
2446ba597c5SAnurag S. Maskey 		    ncu->ncu_name);
2456ba597c5SAnurag S. Maskey 	}
2466ba597c5SAnurag S. Maskey 
2476ba597c5SAnurag S. Maskey 	if (nif->nwamd_if_ipv6 && nif->nwamd_if_ipv6_default_route_set) {
2486ba597c5SAnurag S. Maskey 		struct sockaddr_in6 v6dest, v6mask;
2496ba597c5SAnurag S. Maskey 
2506ba597c5SAnurag S. Maskey 		(void) bzero(&v6dest, sizeof (struct sockaddr_in6));
2516ba597c5SAnurag S. Maskey 		v6dest.sin6_family = AF_INET6;
2526ba597c5SAnurag S. Maskey 
2536ba597c5SAnurag S. Maskey 		(void) bzero(&v6mask, sizeof (struct sockaddr_in6));
2546ba597c5SAnurag S. Maskey 		v6mask.sin6_family = AF_INET6;
2556ba597c5SAnurag S. Maskey 
2566ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_add_default_routes: adding default "
257f6da83d4SAnurag S. Maskey 		    "route %s", nwamd_sockaddr2str((struct sockaddr *)
258f6da83d4SAnurag S. Maskey 		    &nif->nwamd_if_ipv6_default_route, str,
2596ba597c5SAnurag S. Maskey 		    sizeof (str)));
2606ba597c5SAnurag S. Maskey 		nwamd_add_route((struct sockaddr *)&v6dest,
2616ba597c5SAnurag S. Maskey 		    (struct sockaddr *)&v6mask,
2626ba597c5SAnurag S. Maskey 		    (struct sockaddr *)&nif->nwamd_if_ipv6_default_route,
2636ba597c5SAnurag S. Maskey 		    ncu->ncu_name);
2646ba597c5SAnurag S. Maskey 	}
2656ba597c5SAnurag S. Maskey }
2666ba597c5SAnurag S. Maskey 
2676ba597c5SAnurag S. Maskey /*
2686ba597c5SAnurag S. Maskey  * Returns the nwamd_if_address structure for the given static address,
2696ba597c5SAnurag S. Maskey  * NULL if not found.
2706ba597c5SAnurag S. Maskey  */
2716ba597c5SAnurag S. Maskey static struct nwamd_if_address *
find_static_address(const struct sockaddr_storage * addr,const nwamd_ncu_t * ncu)272f6da83d4SAnurag S. Maskey find_static_address(const struct sockaddr_storage *addr, const nwamd_ncu_t *ncu)
2736ba597c5SAnurag S. Maskey {
274f6da83d4SAnurag S. Maskey 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
275f6da83d4SAnurag S. Maskey 	struct sockaddr_storage saddr;
2766ba597c5SAnurag S. Maskey 	char str[INET6_ADDRSTRLEN];
2776ba597c5SAnurag S. Maskey 
278f6da83d4SAnurag S. Maskey 	nlog(LOG_DEBUG, "find_static_address: %s",
279f6da83d4SAnurag S. Maskey 	    nwamd_sockaddr2str((struct sockaddr *)addr, str, sizeof (str)));
280f6da83d4SAnurag S. Maskey 	for (nifap = nifa; nifap != NULL; nifap = nifap->next) {
281f6da83d4SAnurag S. Maskey 		if (nifap->ipaddr_atype != IPADM_ADDR_STATIC ||
282f6da83d4SAnurag S. Maskey 		    ipadm_get_addr(nifap->ipaddr, &saddr) != IPADM_SUCCESS)
283f6da83d4SAnurag S. Maskey 			continue;
284f6da83d4SAnurag S. Maskey 
285f6da83d4SAnurag S. Maskey 		if (sockaddrcmp(addr, &saddr))
286f6da83d4SAnurag S. Maskey 			return (nifap);
2876ba597c5SAnurag S. Maskey 	}
2886ba597c5SAnurag S. Maskey 	return (NULL);
2896ba597c5SAnurag S. Maskey }
2906ba597c5SAnurag S. Maskey 
2916ba597c5SAnurag S. Maskey /*
2926ba597c5SAnurag S. Maskey  * Returns the nwamd_if_address structure representing the non-static address
293f6da83d4SAnurag S. Maskey  * in the NCU.  For IPv6, both stateless and stateful (DHCPv6) share the same
294f6da83d4SAnurag S. Maskey  * nwamd_if_address.  Will only return the nwamd_if_address if the relevant
295f6da83d4SAnurag S. Maskey  * address is configured (v4 DHCP, v6 either stateless or stateless) for the
296f6da83d4SAnurag S. Maskey  * NCU.  Returns NULL if the structure is not found.
2976ba597c5SAnurag S. Maskey  */
2986ba597c5SAnurag S. Maskey static struct nwamd_if_address *
find_nonstatic_address(const nwamd_ncu_t * ncu,sa_family_t family)299f6da83d4SAnurag S. Maskey find_nonstatic_address(const nwamd_ncu_t *ncu, sa_family_t family)
3006ba597c5SAnurag S. Maskey {
301f6da83d4SAnurag S. Maskey 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
302f6da83d4SAnurag S. Maskey 	const nwamd_if_t *u_if = &ncu->ncu_if;
303f6da83d4SAnurag S. Maskey 
304f6da83d4SAnurag S. Maskey 	nlog(LOG_DEBUG, "find_nonstatic_address for %s %s",
305f6da83d4SAnurag S. Maskey 	    (family == AF_INET ? "IPv4" : "IPv6"),  ncu->ncu_name);
306f6da83d4SAnurag S. Maskey 	for (nifap = nifa; nifap != NULL; nifap = nifap->next) {
307f6da83d4SAnurag S. Maskey 		if (nifap->ipaddr_atype == IPADM_ADDR_STATIC)
308f6da83d4SAnurag S. Maskey 			continue;
3096ba597c5SAnurag S. Maskey 
3106ba597c5SAnurag S. Maskey 		if (family == AF_INET) {
311f6da83d4SAnurag S. Maskey 			if (nifap->ipaddr_atype == IPADM_ADDR_DHCP &&
312f6da83d4SAnurag S. Maskey 			    u_if->nwamd_if_dhcp_requested)
313f6da83d4SAnurag S. Maskey 				return (nifap);
3146ba597c5SAnurag S. Maskey 		} else if (family == AF_INET6) {
315f6da83d4SAnurag S. Maskey 			if (nifap->ipaddr_atype == IPADM_ADDR_IPV6_ADDRCONF &&
316f6da83d4SAnurag S. Maskey 			    (u_if->nwamd_if_stateful_requested ||
317f6da83d4SAnurag S. Maskey 			    u_if->nwamd_if_stateless_requested))
318f6da83d4SAnurag S. Maskey 				return (nifap);
3196ba597c5SAnurag S. Maskey 		}
3206ba597c5SAnurag S. Maskey 	}
3216ba597c5SAnurag S. Maskey 	return (NULL);
3226ba597c5SAnurag S. Maskey }
3236ba597c5SAnurag S. Maskey 
3246ba597c5SAnurag S. Maskey /*
325f6da83d4SAnurag S. Maskey  * Returns the nwamd_if_address structure that configured the given address,
326f6da83d4SAnurag S. Maskey  * NULL if not found.
3276ba597c5SAnurag S. Maskey  */
328f6da83d4SAnurag S. Maskey static struct nwamd_if_address *
find_configured_address(const struct sockaddr_storage * addr,const nwamd_ncu_t * ncu)329f6da83d4SAnurag S. Maskey find_configured_address(const struct sockaddr_storage *addr,
330f6da83d4SAnurag S. Maskey     const nwamd_ncu_t *ncu)
3316ba597c5SAnurag S. Maskey {
332f6da83d4SAnurag S. Maskey 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
3336ba597c5SAnurag S. Maskey 	char str[INET6_ADDRSTRLEN];
3346ba597c5SAnurag S. Maskey 
335f6da83d4SAnurag S. Maskey 	nlog(LOG_DEBUG, "find_configured_address: %s",
336f6da83d4SAnurag S. Maskey 	    nwamd_sockaddr2str((struct sockaddr *)addr, str, sizeof (str)));
337f6da83d4SAnurag S. Maskey 	for (nifap = nifa; nifap != NULL; nifap = nifap->next) {
338f6da83d4SAnurag S. Maskey 		if (sockaddrcmp(addr, &nifap->conf_addr) ||
339f6da83d4SAnurag S. Maskey 		    sockaddrcmp(addr, &nifap->conf_stateless_addr))
340f6da83d4SAnurag S. Maskey 			return (nifap);
3416ba597c5SAnurag S. Maskey 	}
342f6da83d4SAnurag S. Maskey 	return (NULL);
3436ba597c5SAnurag S. Maskey }
3446ba597c5SAnurag S. Maskey 
3456ba597c5SAnurag S. Maskey /*
3466ba597c5SAnurag S. Maskey  * Are one or more static addresses configured?
3476ba597c5SAnurag S. Maskey  */
3486ba597c5SAnurag S. Maskey boolean_t
nwamd_static_addresses_configured(nwamd_ncu_t * ncu,sa_family_t family)3496ba597c5SAnurag S. Maskey nwamd_static_addresses_configured(nwamd_ncu_t *ncu, sa_family_t family)
3506ba597c5SAnurag S. Maskey {
3516ba597c5SAnurag S. Maskey 	struct nwamd_if_address *n;
3526ba597c5SAnurag S. Maskey 
353f6da83d4SAnurag S. Maskey 	for (n = ncu->ncu_if.nwamd_if_list; n != NULL; n = n->next) {
354f6da83d4SAnurag S. Maskey 		if (n->ipaddr_atype != IPADM_ADDR_STATIC)
355f6da83d4SAnurag S. Maskey 			continue;
356f6da83d4SAnurag S. Maskey 		if ((family == AF_UNSPEC || family == n->family) &&
357f6da83d4SAnurag S. Maskey 		    n->configured)
3586ba597c5SAnurag S. Maskey 			return (B_TRUE);
3596ba597c5SAnurag S. Maskey 	}
3606ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "no static addresses configured for %s", ncu->ncu_name);
3616ba597c5SAnurag S. Maskey 	return (B_FALSE);
3626ba597c5SAnurag S. Maskey }
3636ba597c5SAnurag S. Maskey 
3646ba597c5SAnurag S. Maskey /*
3656ba597c5SAnurag S. Maskey  * Is DHCP probably managing an address on this index.  We decide that it is
3666ba597c5SAnurag S. Maskey  * probably managing an address if there is an interface with IFF_DHCP set
3676ba597c5SAnurag S. Maskey  * that isn't in our set of static addresses.  Note that IFF_DHCP gets set
3686ba597c5SAnurag S. Maskey  * on static addresses when we do a dhcp inform and if that list has changed
3696ba597c5SAnurag S. Maskey  * recently then the result of this function could be erronous.
3706ba597c5SAnurag S. Maskey  */
3716ba597c5SAnurag S. Maskey boolean_t
nwamd_dhcp_managing(int protocol,nwamd_ncu_t * ncu)3726ba597c5SAnurag S. Maskey nwamd_dhcp_managing(int protocol, nwamd_ncu_t *ncu)
3736ba597c5SAnurag S. Maskey {
37464639aafSDarren Reed 	struct sockaddr_storage addr;
3756ba597c5SAnurag S. Maskey 	uint64_t flags;
3766ba597c5SAnurag S. Maskey 	boolean_t rv = B_FALSE;
377f6da83d4SAnurag S. Maskey 	ipadm_addr_info_t *addrinfo, *a;
378f6da83d4SAnurag S. Maskey 	ipadm_status_t ipstatus;
379f6da83d4SAnurag S. Maskey 
380f6da83d4SAnurag S. Maskey 	if ((ipstatus = ipadm_addr_info(ipadm_handle, ncu->ncu_name, &addrinfo,
381f6da83d4SAnurag S. Maskey 	    0, 0)) != IPADM_SUCCESS) {
382f6da83d4SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_dhcp_managing: "
383f6da83d4SAnurag S. Maskey 		    "ipadm_addr_info failed for %s: %s",
384f6da83d4SAnurag S. Maskey 		    ncu->ncu_name, ipadm_status2str(ipstatus));
385f6da83d4SAnurag S. Maskey 		return (B_FALSE);
3866ba597c5SAnurag S. Maskey 	}
3876ba597c5SAnurag S. Maskey 
388f6da83d4SAnurag S. Maskey 	for (a = addrinfo; a != NULL; a = IA_NEXT(a)) {
38964639aafSDarren Reed 		/*
39064639aafSDarren Reed 		 * WARNING: This memcpy() assumes knowledge of the
39164639aafSDarren Reed 		 * implementation of getifaddrs() and that it always
39264639aafSDarren Reed 		 * uses sockaddr_storage as the backing store for
39364639aafSDarren Reed 		 * address information, thus making it possible to
39464639aafSDarren Reed 		 * copy the entire structure rather than do it on
39564639aafSDarren Reed 		 * the size of the sockaddr according to family.
39664639aafSDarren Reed 		 * This assumption is made elsewhere in this file.
39764639aafSDarren Reed 		 */
39864639aafSDarren Reed 		(void) memcpy(&addr, a->ia_ifa.ifa_addr, sizeof (addr));
39964639aafSDarren Reed 
4006ba597c5SAnurag S. Maskey 		/* is this address an expected static one? */
40164639aafSDarren Reed 		if (find_static_address(&addr, ncu) != NULL)
4026ba597c5SAnurag S. Maskey 			continue;
4036ba597c5SAnurag S. Maskey 
4046ba597c5SAnurag S. Maskey 		/*
4056ba597c5SAnurag S. Maskey 		 * For IPv4, DHCPRUNNING flag is set when dhcpagent is in
4066ba597c5SAnurag S. Maskey 		 * the process of getting an address, but doesn't have one
4076ba597c5SAnurag S. Maskey 		 * yet (interface has 0.0.0.0).  For IPv6, DHCPRUNNING flag
4086ba597c5SAnurag S. Maskey 		 * is set on the link-local address if trying to get a
4096ba597c5SAnurag S. Maskey 		 * stateful address.  In both cases, consider the interface
4106ba597c5SAnurag S. Maskey 		 * as not being managed by DHCP and skip checking of flags.
4116ba597c5SAnurag S. Maskey 		 */
4126ba597c5SAnurag S. Maskey 		if ((protocol == AF_INET &&
41364639aafSDarren Reed 		    ((struct sockaddr_in *)&addr)->sin_addr.s_addr ==
4146ba597c5SAnurag S. Maskey 		    INADDR_ANY) ||
4156ba597c5SAnurag S. Maskey 		    (protocol == AF_INET6 &&
4166ba597c5SAnurag S. Maskey 		    IN6_IS_ADDR_LINKLOCAL(
41764639aafSDarren Reed 		    &((struct sockaddr_in6 *)&addr)->sin6_addr))) {
4186ba597c5SAnurag S. Maskey 			continue;
4196ba597c5SAnurag S. Maskey 		}
4206ba597c5SAnurag S. Maskey 
421f6da83d4SAnurag S. Maskey 		flags = a->ia_ifa.ifa_flags;
422f6da83d4SAnurag S. Maskey 		if (flags & IFF_DHCPRUNNING) {
4236ba597c5SAnurag S. Maskey 			/*
4246ba597c5SAnurag S. Maskey 			 * If we get here we have an address that has the
4256ba597c5SAnurag S. Maskey 			 * DHCP flag set and isn't an expected static address.
4266ba597c5SAnurag S. Maskey 			 */
4276ba597c5SAnurag S. Maskey 			rv = B_TRUE;
4286ba597c5SAnurag S. Maskey 			break;
4296ba597c5SAnurag S. Maskey 		}
4306ba597c5SAnurag S. Maskey 	}
4316ba597c5SAnurag S. Maskey 
432f6da83d4SAnurag S. Maskey 	ipadm_free_addr_info(addrinfo);
4336ba597c5SAnurag S. Maskey 	return (rv);
4346ba597c5SAnurag S. Maskey }
4356ba597c5SAnurag S. Maskey 
436f6da83d4SAnurag S. Maskey /*
437f6da83d4SAnurag S. Maskey  * Return B_TRUE if IPv4 is requested in the given NCU.
438f6da83d4SAnurag S. Maskey  */
4396ba597c5SAnurag S. Maskey static boolean_t
nwamd_v4_requested(nwamd_ncu_t * ncu)4406ba597c5SAnurag S. Maskey nwamd_v4_requested(nwamd_ncu_t *ncu)
4416ba597c5SAnurag S. Maskey {
4426ba597c5SAnurag S. Maskey 	boolean_t anyv4_requested;
4436ba597c5SAnurag S. Maskey 	nwamd_if_t *u_if;
4446ba597c5SAnurag S. Maskey 
4456ba597c5SAnurag S. Maskey 	anyv4_requested = B_FALSE;
446f6da83d4SAnurag S. Maskey 	u_if = &ncu->ncu_if;
4476ba597c5SAnurag S. Maskey 	if (u_if->nwamd_if_dhcp_requested) {
4486ba597c5SAnurag S. Maskey 		anyv4_requested = B_TRUE;
4496ba597c5SAnurag S. Maskey 	} else {
450f6da83d4SAnurag S. Maskey 		struct nwamd_if_address *n;
451f6da83d4SAnurag S. Maskey 
452f6da83d4SAnurag S. Maskey 		for (n = u_if->nwamd_if_list; n != NULL; n = n->next) {
453f6da83d4SAnurag S. Maskey 			if (n->family == AF_INET &&
454f6da83d4SAnurag S. Maskey 			    n->ipaddr_atype == IPADM_ADDR_STATIC)
455f6da83d4SAnurag S. Maskey 				break;
456f6da83d4SAnurag S. Maskey 		}
457f6da83d4SAnurag S. Maskey 		if (n != NULL)
4586ba597c5SAnurag S. Maskey 			anyv4_requested = B_TRUE;
4596ba597c5SAnurag S. Maskey 	}
4606ba597c5SAnurag S. Maskey 
4616ba597c5SAnurag S. Maskey 	return (anyv4_requested);
4626ba597c5SAnurag S. Maskey }
4636ba597c5SAnurag S. Maskey 
464f6da83d4SAnurag S. Maskey /*
465f6da83d4SAnurag S. Maskey  * Returns B_TRUE if IPv6 is requested in the given NCU.
466f6da83d4SAnurag S. Maskey  */
4676ba597c5SAnurag S. Maskey static boolean_t
nwamd_v6_requested(nwamd_ncu_t * ncu)4686ba597c5SAnurag S. Maskey nwamd_v6_requested(nwamd_ncu_t *ncu)
4696ba597c5SAnurag S. Maskey {
4706ba597c5SAnurag S. Maskey 	boolean_t anyv6_requested;
4716ba597c5SAnurag S. Maskey 	nwamd_if_t *u_if;
4726ba597c5SAnurag S. Maskey 
4736ba597c5SAnurag S. Maskey 	anyv6_requested = B_FALSE;
474f6da83d4SAnurag S. Maskey 	u_if = &ncu->ncu_if;
4756ba597c5SAnurag S. Maskey 	if (u_if->nwamd_if_stateful_requested ||
4766ba597c5SAnurag S. Maskey 	    u_if->nwamd_if_stateless_requested) {
4776ba597c5SAnurag S. Maskey 		anyv6_requested = B_TRUE;
4786ba597c5SAnurag S. Maskey 	} else {
479f6da83d4SAnurag S. Maskey 		struct nwamd_if_address *n;
480f6da83d4SAnurag S. Maskey 
481f6da83d4SAnurag S. Maskey 		for (n = u_if->nwamd_if_list; n != NULL; n = n->next) {
482f6da83d4SAnurag S. Maskey 			if (n->family == AF_INET6 &&
483f6da83d4SAnurag S. Maskey 			    n->ipaddr_atype == IPADM_ADDR_STATIC)
484f6da83d4SAnurag S. Maskey 				break;
485f6da83d4SAnurag S. Maskey 		}
486f6da83d4SAnurag S. Maskey 		if (n != NULL)
4876ba597c5SAnurag S. Maskey 			anyv6_requested = B_TRUE;
4886ba597c5SAnurag S. Maskey 	}
4896ba597c5SAnurag S. Maskey 
4906ba597c5SAnurag S. Maskey 	return (anyv6_requested);
4916ba597c5SAnurag S. Maskey }
4926ba597c5SAnurag S. Maskey 
4936ba597c5SAnurag S. Maskey /*
4946ba597c5SAnurag S. Maskey  * Bring up the ncu if we have the right combination of requested configuration
4956ba597c5SAnurag S. Maskey  * and actual configuration and up is true, or bring down the ncu if no
4966ba597c5SAnurag S. Maskey  * addresses are configured, and up is false.
4976ba597c5SAnurag S. Maskey  */
4986ba597c5SAnurag S. Maskey static void
interface_ncu_up_down(nwamd_ncu_t * ncu,boolean_t up)4996ba597c5SAnurag S. Maskey interface_ncu_up_down(nwamd_ncu_t *ncu, boolean_t up)
5006ba597c5SAnurag S. Maskey {
5016ba597c5SAnurag S. Maskey 	boolean_t ncu_online;
5026ba597c5SAnurag S. Maskey 	char *name;
5036ba597c5SAnurag S. Maskey 
5046ba597c5SAnurag S. Maskey 	assert(ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE);
5056ba597c5SAnurag S. Maskey 
5066ba597c5SAnurag S. Maskey 	/*
5076ba597c5SAnurag S. Maskey 	 * If V4 with or without V6 is configured then one of its interfaces
5086ba597c5SAnurag S. Maskey 	 * needs to be up for the ncu to come online.  If only V6 is requested
5096ba597c5SAnurag S. Maskey 	 * then one of its interfaces needs to be up for the ncu to come online.
5106ba597c5SAnurag S. Maskey 	 */
5116ba597c5SAnurag S. Maskey 	ncu_online = B_FALSE;
5126ba597c5SAnurag S. Maskey 	if (nwamd_v4_requested(ncu)) {
5136ba597c5SAnurag S. Maskey 		if (nwamd_dhcp_managing(AF_INET, ncu) ||
5146ba597c5SAnurag S. Maskey 		    nwamd_static_addresses_configured(ncu, AF_INET))
5156ba597c5SAnurag S. Maskey 			ncu_online = B_TRUE;
5166ba597c5SAnurag S. Maskey 	} else if (nwamd_v6_requested(ncu)) {
5176ba597c5SAnurag S. Maskey 		if ((nwamd_dhcp_managing(AF_INET6, ncu) ||
5186ba597c5SAnurag S. Maskey 		    stateless_running(ncu) ||
5196ba597c5SAnurag S. Maskey 		    nwamd_static_addresses_configured(ncu, AF_INET6)))
5206ba597c5SAnurag S. Maskey 			ncu_online = B_TRUE;
5216ba597c5SAnurag S. Maskey 	}
5226ba597c5SAnurag S. Maskey 
5236ba597c5SAnurag S. Maskey 	if (nwam_ncu_name_to_typed_name(ncu->ncu_name, ncu->ncu_type, &name) !=
5246ba597c5SAnurag S. Maskey 	    NWAM_SUCCESS) {
5256ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "interface_ncu_up_down: "
5266ba597c5SAnurag S. Maskey 		    "nwam_ncu_name_to_typed_name failed");
5276ba597c5SAnurag S. Maskey 		return;
5286ba597c5SAnurag S. Maskey 	}
5296ba597c5SAnurag S. Maskey 	if (ncu_online && up) {
5306ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "interface_ncu_up_down: "
5316ba597c5SAnurag S. Maskey 		    "bringing %s up", name);
5326ba597c5SAnurag S. Maskey 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, name,
5336ba597c5SAnurag S. Maskey 		    NWAM_STATE_OFFLINE_TO_ONLINE, NWAM_AUX_STATE_UP);
5346ba597c5SAnurag S. Maskey 	} else if (!ncu_online && !up) {
5356ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "interface_ncu_up_down: "
5366ba597c5SAnurag S. Maskey 		    "bringing %s down", name);
5376ba597c5SAnurag S. Maskey 		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, name,
5386ba597c5SAnurag S. Maskey 		    NWAM_STATE_ONLINE_TO_OFFLINE,
5396ba597c5SAnurag S. Maskey 		    NWAM_AUX_STATE_DOWN);
5406ba597c5SAnurag S. Maskey 	}
5416ba597c5SAnurag S. Maskey 
5426ba597c5SAnurag S. Maskey 	free(name);
5436ba597c5SAnurag S. Maskey }
5446ba597c5SAnurag S. Maskey 
5456ba597c5SAnurag S. Maskey static void
interface_ncu_up(nwamd_ncu_t * ncu)5466ba597c5SAnurag S. Maskey interface_ncu_up(nwamd_ncu_t *ncu)
5476ba597c5SAnurag S. Maskey {
5486ba597c5SAnurag S. Maskey 	interface_ncu_up_down(ncu, B_TRUE);
5496ba597c5SAnurag S. Maskey }
5506ba597c5SAnurag S. Maskey 
5516ba597c5SAnurag S. Maskey static void
interface_ncu_down(nwamd_ncu_t * ncu)5526ba597c5SAnurag S. Maskey interface_ncu_down(nwamd_ncu_t *ncu)
5536ba597c5SAnurag S. Maskey {
5546ba597c5SAnurag S. Maskey 	interface_ncu_up_down(ncu, B_FALSE);
5556ba597c5SAnurag S. Maskey }
5566ba597c5SAnurag S. Maskey 
557f6da83d4SAnurag S. Maskey static boolean_t
stateless_running(const nwamd_ncu_t * ncu)558f6da83d4SAnurag S. Maskey stateless_running(const nwamd_ncu_t *ncu)
5596ba597c5SAnurag S. Maskey {
560f6da83d4SAnurag S. Maskey 	ipadm_addr_info_t *ainfo, *ainfop;
561f6da83d4SAnurag S. Maskey 	ipadm_status_t ipstatus;
562f6da83d4SAnurag S. Maskey 	boolean_t rv = B_FALSE;
563f6da83d4SAnurag S. Maskey 	uint64_t flags;
5646ba597c5SAnurag S. Maskey 
565f6da83d4SAnurag S. Maskey 	if ((ipstatus = ipadm_addr_info(ipadm_handle, ncu->ncu_name, &ainfo,
566f6da83d4SAnurag S. Maskey 	    0, 0)) != IPADM_SUCCESS) {
567f6da83d4SAnurag S. Maskey 		nlog(LOG_ERR, "stateless_running: "
568f6da83d4SAnurag S. Maskey 		    "ipadm_addr_info failed for %s: %s",
569f6da83d4SAnurag S. Maskey 		    ncu->ncu_name, ipadm_status2str(ipstatus));
570f6da83d4SAnurag S. Maskey 		return (B_FALSE);
5716ba597c5SAnurag S. Maskey 	}
5726ba597c5SAnurag S. Maskey 
573f6da83d4SAnurag S. Maskey 	for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
57464639aafSDarren Reed 		if (ainfop->ia_ifa.ifa_addr->sa_family != AF_INET6)
575f6da83d4SAnurag S. Maskey 			continue;
576f6da83d4SAnurag S. Maskey 		flags = ainfop->ia_ifa.ifa_flags;
577f6da83d4SAnurag S. Maskey 		if (flags & STATELESS_RUNNING) {
578f6da83d4SAnurag S. Maskey 			rv = B_TRUE;
579f6da83d4SAnurag S. Maskey 			break;
580f6da83d4SAnurag S. Maskey 		}
581f6da83d4SAnurag S. Maskey 	}
582f6da83d4SAnurag S. Maskey 	ipadm_free_addr_info(ainfo);
583f6da83d4SAnurag S. Maskey 	return (rv);
5846ba597c5SAnurag S. Maskey }
5856ba597c5SAnurag S. Maskey 
5866ba597c5SAnurag S. Maskey /*
587f6da83d4SAnurag S. Maskey  * Returns the addrinfo associated with the given address.  There is always
588f6da83d4SAnurag S. Maskey  * only one addrinfo for each address.
5896ba597c5SAnurag S. Maskey  */
5906ba597c5SAnurag S. Maskey static boolean_t
addrinfo_for_addr(const struct sockaddr_storage * caddr,const char * ifname,ipadm_addr_info_t ** ainfo)591f6da83d4SAnurag S. Maskey addrinfo_for_addr(const struct sockaddr_storage *caddr, const char *ifname,
592f6da83d4SAnurag S. Maskey     ipadm_addr_info_t **ainfo)
5936ba597c5SAnurag S. Maskey {
594f6da83d4SAnurag S. Maskey 	ipadm_addr_info_t *addrinfo, *ainfop, *last = NULL;
595f6da83d4SAnurag S. Maskey 	ipadm_status_t ipstatus;
596f6da83d4SAnurag S. Maskey 
597f6da83d4SAnurag S. Maskey 	ipstatus = ipadm_addr_info(ipadm_handle, ifname, &addrinfo, 0, 0);
598f6da83d4SAnurag S. Maskey 	if (ipstatus != IPADM_SUCCESS) {
599f6da83d4SAnurag S. Maskey 		nlog(LOG_INFO, "addrinfo_for_addr: "
600f6da83d4SAnurag S. Maskey 		    "ipadm_addr_info failed for %s: %s",
601f6da83d4SAnurag S. Maskey 		    ifname, ipadm_status2str(ipstatus));
602f6da83d4SAnurag S. Maskey 		return (B_FALSE);
603f6da83d4SAnurag S. Maskey 	}
604f6da83d4SAnurag S. Maskey 
605f6da83d4SAnurag S. Maskey 	*ainfo = NULL;
606f6da83d4SAnurag S. Maskey 	for (ainfop = addrinfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
60764639aafSDarren Reed 		struct sockaddr_storage addr;
60864639aafSDarren Reed 
60964639aafSDarren Reed 		(void) memcpy(&addr, ainfop->ia_ifa.ifa_addr, sizeof (addr));
610f6da83d4SAnurag S. Maskey 		/*
611f6da83d4SAnurag S. Maskey 		 * If addresses match, rearrange pointers so that addrinfo
612f6da83d4SAnurag S. Maskey 		 * does not contain a, and return a.
613f6da83d4SAnurag S. Maskey 		 */
61464639aafSDarren Reed 		if (sockaddrcmp(&addr, caddr)) {
615f6da83d4SAnurag S. Maskey 			if (last != NULL)
616f6da83d4SAnurag S. Maskey 				last->ia_ifa.ifa_next = ainfop->ia_ifa.ifa_next;
617f6da83d4SAnurag S. Maskey 			else
618f6da83d4SAnurag S. Maskey 				addrinfo = IA_NEXT(ainfop);
619f6da83d4SAnurag S. Maskey 
620f6da83d4SAnurag S. Maskey 			ainfop->ia_ifa.ifa_next = NULL;
621f6da83d4SAnurag S. Maskey 			*ainfo = ainfop;
622f6da83d4SAnurag S. Maskey 			break;
623f6da83d4SAnurag S. Maskey 		}
624f6da83d4SAnurag S. Maskey 		last = ainfop;
625f6da83d4SAnurag S. Maskey 	}
626f6da83d4SAnurag S. Maskey 	ipadm_free_addr_info(addrinfo);
627f6da83d4SAnurag S. Maskey 	return (*ainfo == NULL ? B_FALSE : B_TRUE);
6286ba597c5SAnurag S. Maskey }
6296ba597c5SAnurag S. Maskey 
630f6da83d4SAnurag S. Maskey /*
631f6da83d4SAnurag S. Maskey  * Returns B_TRUE if the addrinfo associated with the given ipaddr using its
632f6da83d4SAnurag S. Maskey  * aobjname is found.  An addrinfo list is created and returned in ainfo.
633f6da83d4SAnurag S. Maskey  * Stateless and stateful IPv6 addrinfo have the same aobjname, thus the need
634f6da83d4SAnurag S. Maskey  * to create a list of addrinfo.
635f6da83d4SAnurag S. Maskey  */
6366ba597c5SAnurag S. Maskey static boolean_t
addrinfo_for_ipaddr(ipadm_addrobj_t ipaddr,const char * ifname,ipadm_addr_info_t ** ainfo)637f6da83d4SAnurag S. Maskey addrinfo_for_ipaddr(ipadm_addrobj_t ipaddr, const char *ifname,
638f6da83d4SAnurag S. Maskey     ipadm_addr_info_t **ainfo)
6396ba597c5SAnurag S. Maskey {
640f6da83d4SAnurag S. Maskey 	char aobjname[IPADM_AOBJSIZ];
641f6da83d4SAnurag S. Maskey 	ipadm_addr_info_t *addrinfo, *ainfop;
642f6da83d4SAnurag S. Maskey 	ipadm_addr_info_t *last = NULL;
643f6da83d4SAnurag S. Maskey 	ipadm_status_t ipstatus;
644f6da83d4SAnurag S. Maskey 
645f6da83d4SAnurag S. Maskey 	ipstatus = ipadm_get_aobjname(ipaddr, aobjname, sizeof (aobjname));
646f6da83d4SAnurag S. Maskey 	if (ipstatus != IPADM_SUCCESS)
6476ba597c5SAnurag S. Maskey 		return (B_FALSE);
6486ba597c5SAnurag S. Maskey 
649f6da83d4SAnurag S. Maskey 	ipstatus = ipadm_addr_info(ipadm_handle, ifname, &addrinfo, 0, 0);
650f6da83d4SAnurag S. Maskey 	if (ipstatus != IPADM_SUCCESS) {
651f6da83d4SAnurag S. Maskey 		nlog(LOG_INFO, "addrinfo_for_ipaddr: "
652f6da83d4SAnurag S. Maskey 		    "ipadm_addr_info failed for %s: %s",
653f6da83d4SAnurag S. Maskey 		    ifname, ipadm_status2str(ipstatus));
6546ba597c5SAnurag S. Maskey 		return (B_FALSE);
6556ba597c5SAnurag S. Maskey 	}
6566ba597c5SAnurag S. Maskey 
657f6da83d4SAnurag S. Maskey 	*ainfo = NULL;
658f6da83d4SAnurag S. Maskey 	ainfop = addrinfo;
659f6da83d4SAnurag S. Maskey 	while (ainfop != NULL) {
660f6da83d4SAnurag S. Maskey 		/* If aobjnames match, rearrange pointers to create new list */
661f6da83d4SAnurag S. Maskey 		if (strcmp(ainfop->ia_aobjname, aobjname) == 0) {
662f6da83d4SAnurag S. Maskey 			ipadm_addr_info_t *match = ainfop;
663f6da83d4SAnurag S. Maskey 
664f6da83d4SAnurag S. Maskey 			ainfop = IA_NEXT(ainfop); /* move iterator */
665f6da83d4SAnurag S. Maskey 			if (last != NULL)
666f6da83d4SAnurag S. Maskey 				last->ia_ifa.ifa_next = match->ia_ifa.ifa_next;
667f6da83d4SAnurag S. Maskey 			else
668f6da83d4SAnurag S. Maskey 				addrinfo = ainfop;
669f6da83d4SAnurag S. Maskey 			if (*ainfo == NULL)
670f6da83d4SAnurag S. Maskey 				match->ia_ifa.ifa_next = NULL;
671f6da83d4SAnurag S. Maskey 			else
672f6da83d4SAnurag S. Maskey 				match->ia_ifa.ifa_next = &(*ainfo)->ia_ifa;
673f6da83d4SAnurag S. Maskey 			*ainfo = match;
674f6da83d4SAnurag S. Maskey 		} else {
675f6da83d4SAnurag S. Maskey 			last = ainfop;
676f6da83d4SAnurag S. Maskey 			ainfop = IA_NEXT(ainfop);
677f6da83d4SAnurag S. Maskey 		}
678f6da83d4SAnurag S. Maskey 	}
679f6da83d4SAnurag S. Maskey 	ipadm_free_addr_info(addrinfo);
680f6da83d4SAnurag S. Maskey 	return (*ainfo == NULL ? B_FALSE : B_TRUE);
6816ba597c5SAnurag S. Maskey }
6826ba597c5SAnurag S. Maskey 
683f6da83d4SAnurag S. Maskey /*
684f6da83d4SAnurag S. Maskey  * Add the address provided in the nwamd_if_address.  If DHCP is required,
685f6da83d4SAnurag S. Maskey  * start DHCP.  If a static address is configured, create the address; then do
686f6da83d4SAnurag S. Maskey  * a DHCP_INFORM (in a separate thread) to get other networking configuration
687f6da83d4SAnurag S. Maskey  * parameters.  RTM_NEWADDRs - translated into IF_STATE events - will then
688f6da83d4SAnurag S. Maskey  * finish the job of bringing the NCU online.
689f6da83d4SAnurag S. Maskey  */
690f6da83d4SAnurag S. Maskey static boolean_t
add_ip_address(const char * ifname,const struct nwamd_if_address * nifa,boolean_t * do_inform)69148fff0e3SRenee Danson Sommerfeld add_ip_address(const char *ifname, const struct nwamd_if_address *nifa,
69248fff0e3SRenee Danson Sommerfeld     boolean_t *do_inform)
6936ba597c5SAnurag S. Maskey {
694f6da83d4SAnurag S. Maskey 	ipadm_status_t ipstatus;
695f6da83d4SAnurag S. Maskey 	ipadm_addr_info_t *addrinfo = NULL;
696f6da83d4SAnurag S. Maskey 	uint64_t flags;
6976ba597c5SAnurag S. Maskey 
698f6da83d4SAnurag S. Maskey 	if (nifa->ipaddr_atype == IPADM_ADDR_DHCP) {
699f6da83d4SAnurag S. Maskey 		/*
700f6da83d4SAnurag S. Maskey 		 * To make getting a DHCP address asynchronous, call
701f6da83d4SAnurag S. Maskey 		 * ipadm_create_addr() in a new thread.
702f6da83d4SAnurag S. Maskey 		 */
703f6da83d4SAnurag S. Maskey 		nlog(LOG_DEBUG, "add_ip_address: "
704f6da83d4SAnurag S. Maskey 		    "adding IPv4 DHCP address on %s", ifname);
705f6da83d4SAnurag S. Maskey 		nwamd_dhcp(ifname, nifa->ipaddr, DHCP_START);
706f6da83d4SAnurag S. Maskey 	} else {
707f6da83d4SAnurag S. Maskey 		nlog(LOG_DEBUG, "add_ip_address: adding %s address on %s",
708f6da83d4SAnurag S. Maskey 		    (nifa->ipaddr_atype == IPADM_ADDR_STATIC ?
709f6da83d4SAnurag S. Maskey 		    "STATIC" : "IPv6 ADDRCONF"), ifname);
710f6da83d4SAnurag S. Maskey 		if ((ipstatus = ipadm_create_addr(ipadm_handle, nifa->ipaddr,
711f6da83d4SAnurag S. Maskey 		    IPADM_OPT_ACTIVE | IPADM_OPT_UP)) != IPADM_SUCCESS) {
712f6da83d4SAnurag S. Maskey 			nlog(LOG_ERR, "add_ip_address: "
713f6da83d4SAnurag S. Maskey 			    "ipadm_create_addr failed on %s: %s",
714f6da83d4SAnurag S. Maskey 			    ifname, ipadm_status2str(ipstatus));
715f6da83d4SAnurag S. Maskey 			return (B_FALSE);
716f6da83d4SAnurag S. Maskey 		}
717f6da83d4SAnurag S. Maskey 		/*
718f6da83d4SAnurag S. Maskey 		 * When creating a static address, ipadm_create_addr() returns
719f6da83d4SAnurag S. Maskey 		 * SUCCESS even if duplicate address is detected.  Retrieve
720f6da83d4SAnurag S. Maskey 		 * the addrinfo to get the flags.
721f6da83d4SAnurag S. Maskey 		 */
722f6da83d4SAnurag S. Maskey 		if (nifa->ipaddr_atype == IPADM_ADDR_STATIC) {
723f6da83d4SAnurag S. Maskey 			/*
724f6da83d4SAnurag S. Maskey 			 * Since we are configuring a static address, there
725f6da83d4SAnurag S. Maskey 			 * will be just *ONE* addrinfo with the aobjname in
726f6da83d4SAnurag S. Maskey 			 * nifa->ipaddr.
727f6da83d4SAnurag S. Maskey 			 */
728f6da83d4SAnurag S. Maskey 			if (!addrinfo_for_ipaddr(nifa->ipaddr, ifname,
729f6da83d4SAnurag S. Maskey 			    &addrinfo)) {
730f6da83d4SAnurag S. Maskey 				nlog(LOG_ERR, "add_ip_address: "
731f6da83d4SAnurag S. Maskey 				    "could not find addrinfo on %s", ifname);
732f6da83d4SAnurag S. Maskey 				return (B_FALSE);
733f6da83d4SAnurag S. Maskey 			}
7346ba597c5SAnurag S. Maskey 
735f6da83d4SAnurag S. Maskey 			flags = addrinfo->ia_ifa.ifa_flags;
736f6da83d4SAnurag S. Maskey 			ipadm_free_addr_info(addrinfo);
737f6da83d4SAnurag S. Maskey 			if (flags & IFF_DUPLICATE) {
738f6da83d4SAnurag S. Maskey 				char *object_name;
739f6da83d4SAnurag S. Maskey 				nwam_error_t err;
740f6da83d4SAnurag S. Maskey 
741f6da83d4SAnurag S. Maskey 				nlog(LOG_INFO, "add_ip_address: "
742f6da83d4SAnurag S. Maskey 				    "duplicate address detected on %s", ifname);
743f6da83d4SAnurag S. Maskey 				if ((err = nwam_ncu_name_to_typed_name(ifname,
744f6da83d4SAnurag S. Maskey 				    NWAM_NCU_TYPE_INTERFACE, &object_name))
745f6da83d4SAnurag S. Maskey 				    == NWAM_SUCCESS) {
746f6da83d4SAnurag S. Maskey 					nwamd_object_set_state(
747f6da83d4SAnurag S. Maskey 					    NWAM_OBJECT_TYPE_NCU,
748f6da83d4SAnurag S. Maskey 					    object_name, NWAM_STATE_MAINTENANCE,
749f6da83d4SAnurag S. Maskey 					    NWAM_AUX_STATE_IF_DUPLICATE_ADDR);
750f6da83d4SAnurag S. Maskey 					free(object_name);
751f6da83d4SAnurag S. Maskey 				} else {
752f6da83d4SAnurag S. Maskey 					nlog(LOG_ERR, "add_ip_address: "
753f6da83d4SAnurag S. Maskey 					    "could not create state event "
754f6da83d4SAnurag S. Maskey 					    "for %s: %s",
755f6da83d4SAnurag S. Maskey 					    ifname, nwam_strerror(err));
756f6da83d4SAnurag S. Maskey 				}
757f6da83d4SAnurag S. Maskey 				return (B_FALSE);
758f6da83d4SAnurag S. Maskey 			}
75948fff0e3SRenee Danson Sommerfeld 			/*
76048fff0e3SRenee Danson Sommerfeld 			 * Do DHCP_INFORM using async ipadm_refresh_addr().
76148fff0e3SRenee Danson Sommerfeld 			 * Only need to do this once per interface, and we
76248fff0e3SRenee Danson Sommerfeld 			 * do *not* need to do it if we are also getting a
76348fff0e3SRenee Danson Sommerfeld 			 * dhcp lease; so we only send the INFORM if the
76448fff0e3SRenee Danson Sommerfeld 			 * passed-in flag says to, and we clear the flag
76548fff0e3SRenee Danson Sommerfeld 			 * once we've initiated the INFORM transaction.
76648fff0e3SRenee Danson Sommerfeld 			 */
76748fff0e3SRenee Danson Sommerfeld 			if (*do_inform) {
76848fff0e3SRenee Danson Sommerfeld 				nwamd_dhcp(ifname, nifa->ipaddr, DHCP_INFORM);
76948fff0e3SRenee Danson Sommerfeld 				*do_inform = B_FALSE;
77048fff0e3SRenee Danson Sommerfeld 			}
7716ba597c5SAnurag S. Maskey 		}
7726ba597c5SAnurag S. Maskey 	}
7736ba597c5SAnurag S. Maskey 
774f6da83d4SAnurag S. Maskey 	return (B_TRUE);
7756ba597c5SAnurag S. Maskey }
7766ba597c5SAnurag S. Maskey 
7776ba597c5SAnurag S. Maskey /*
778f6da83d4SAnurag S. Maskey  * Adds addresses for the given NCU.
7796ba597c5SAnurag S. Maskey  */
780f6da83d4SAnurag S. Maskey void
nwamd_configure_interface_addresses(nwamd_ncu_t * ncu)781f6da83d4SAnurag S. Maskey nwamd_configure_interface_addresses(nwamd_ncu_t *ncu)
7826ba597c5SAnurag S. Maskey {
783f6da83d4SAnurag S. Maskey 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
78448fff0e3SRenee Danson Sommerfeld 	boolean_t do_inform;
78548fff0e3SRenee Danson Sommerfeld 
78648fff0e3SRenee Danson Sommerfeld 	/* only need an inform if we're not also getting a dhcp lease */
78748fff0e3SRenee Danson Sommerfeld 	do_inform = !ncu->ncu_if.nwamd_if_dhcp_requested;
7886ba597c5SAnurag S. Maskey 
789f6da83d4SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_configure_interface_addresses(%s)",
790f6da83d4SAnurag S. Maskey 	    ncu->ncu_name);
791f6da83d4SAnurag S. Maskey 
792f6da83d4SAnurag S. Maskey 	for (nifap = nifa; nifap != NULL; nifap = nifap->next) {
793f6da83d4SAnurag S. Maskey 		if (nifap->configured)
7946ba597c5SAnurag S. Maskey 			continue;
7956ba597c5SAnurag S. Maskey 
79648fff0e3SRenee Danson Sommerfeld 		nifap->configured = add_ip_address(ncu->ncu_name, nifap,
79748fff0e3SRenee Danson Sommerfeld 		    &do_inform);
7986ba597c5SAnurag S. Maskey 	}
7996ba597c5SAnurag S. Maskey }
8006ba597c5SAnurag S. Maskey 
8016ba597c5SAnurag S. Maskey /*
8026ba597c5SAnurag S. Maskey  * This event tells us that an interface address has appeared or disappeared,
8036ba597c5SAnurag S. Maskey  * or that the interface flags on an interface have changed.
8046ba597c5SAnurag S. Maskey  */
8056ba597c5SAnurag S. Maskey void
nwamd_ncu_handle_if_state_event(nwamd_event_t event)8066ba597c5SAnurag S. Maskey nwamd_ncu_handle_if_state_event(nwamd_event_t event)
8076ba597c5SAnurag S. Maskey {
8086ba597c5SAnurag S. Maskey 	nwam_event_t evm;
8096ba597c5SAnurag S. Maskey 	nwamd_object_t ncu_obj;
8106ba597c5SAnurag S. Maskey 	nwamd_ncu_t *ncu;
8116ba597c5SAnurag S. Maskey 	nwam_state_t state;
8126ba597c5SAnurag S. Maskey 	nwam_aux_state_t aux_state;
8136ba597c5SAnurag S. Maskey 
8146ba597c5SAnurag S. Maskey 	ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
8156ba597c5SAnurag S. Maskey 	    event->event_object);
8166ba597c5SAnurag S. Maskey 	if (ncu_obj == NULL) {
817f6904bc3SRenee Danson Sommerfeld 		nlog(LOG_INFO, "nwamd_ncu_handle_if_state_event: no object %s",
8186ba597c5SAnurag S. Maskey 		    event->event_object);
8196ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
8206ba597c5SAnurag S. Maskey 		return;
8216ba597c5SAnurag S. Maskey 	}
8226ba597c5SAnurag S. Maskey 	ncu = ncu_obj->nwamd_object_data;
8236ba597c5SAnurag S. Maskey 	evm = event->event_msg;
8246ba597c5SAnurag S. Maskey 	state = ncu_obj->nwamd_object_state;
8256ba597c5SAnurag S. Maskey 	aux_state = ncu_obj->nwamd_object_aux_state;
8266ba597c5SAnurag S. Maskey 
8276ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_ncu_handle_if_state_event: "
8286ba597c5SAnurag S. Maskey 	    "if %s, state (%s, %s)", event->event_object,
8296ba597c5SAnurag S. Maskey 	    nwam_state_to_string(state), nwam_aux_state_to_string(aux_state));
8306ba597c5SAnurag S. Maskey 
8316ba597c5SAnurag S. Maskey 	/* Ensure object is in correct state to handle IF state events */
8326ba597c5SAnurag S. Maskey 	switch (state) {
8336ba597c5SAnurag S. Maskey 	case NWAM_STATE_OFFLINE_TO_ONLINE:
8346ba597c5SAnurag S. Maskey 		if (aux_state != NWAM_AUX_STATE_IF_WAITING_FOR_ADDR &&
8356ba597c5SAnurag S. Maskey 		    aux_state != NWAM_AUX_STATE_IF_DHCP_TIMED_OUT) {
8366ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_ncu_handle_if_state_event: "
8376ba597c5SAnurag S. Maskey 			    "if %s is in invalid aux state %s for IF_STATE "
8386ba597c5SAnurag S. Maskey 			    "events", event->event_object,
8396ba597c5SAnurag S. Maskey 			    nwam_aux_state_to_string(aux_state));
8406ba597c5SAnurag S. Maskey 			nwamd_event_do_not_send(event);
8416ba597c5SAnurag S. Maskey 			nwamd_object_release(ncu_obj);
8426ba597c5SAnurag S. Maskey 			return;
8436ba597c5SAnurag S. Maskey 		}
8446ba597c5SAnurag S. Maskey 		break;
8456ba597c5SAnurag S. Maskey 	case NWAM_STATE_ONLINE:
8466ba597c5SAnurag S. Maskey 	/*
8476ba597c5SAnurag S. Maskey 	 * We can get addresses from DHCP after we've taken the interface down.
8486ba597c5SAnurag S. Maskey 	 * We deal with those below.
8496ba597c5SAnurag S. Maskey 	 */
8506ba597c5SAnurag S. Maskey 	case NWAM_STATE_ONLINE_TO_OFFLINE:
8516ba597c5SAnurag S. Maskey 	case NWAM_STATE_OFFLINE:
8526ba597c5SAnurag S. Maskey 		break;
8536ba597c5SAnurag S. Maskey 	default:
8546ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG, "nwamd_ncu_handle_if_state_event: "
8556ba597c5SAnurag S. Maskey 		    "if %s is in invalid state %s for IF_STATE events",
8566ba597c5SAnurag S. Maskey 		    event->event_object, nwam_state_to_string(state));
8576ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
8586ba597c5SAnurag S. Maskey 		nwamd_object_release(ncu_obj);
8596ba597c5SAnurag S. Maskey 		return;
8606ba597c5SAnurag S. Maskey 	}
8616ba597c5SAnurag S. Maskey 
8626ba597c5SAnurag S. Maskey 	if (evm->nwe_data.nwe_if_state.nwe_addr_valid) {
8636ba597c5SAnurag S. Maskey 		struct nwam_event_if_state *if_state;
864f6da83d4SAnurag S. Maskey 		char addrstr[INET6_ADDRSTRLEN];
865c3dd1218SToomas Soome 		boolean_t static_addr = B_FALSE, addr_added;
866f6da83d4SAnurag S. Maskey 		boolean_t v4dhcp_running, v6dhcp_running, stateless_running;
867f6da83d4SAnurag S. Maskey 		ipadm_addr_info_t *ai = NULL, *addrinfo = NULL;
868f6da83d4SAnurag S. Maskey 		boolean_t stateless_ai_found = B_FALSE;
869f6da83d4SAnurag S. Maskey 		boolean_t stateful_ai_found = B_FALSE;
870f6da83d4SAnurag S. Maskey 		struct nwamd_if_address *nifa = NULL;
8716ba597c5SAnurag S. Maskey 		nwamd_if_t *u_if;
87264639aafSDarren Reed 		struct sockaddr_storage *addr, ai_addr, *aip = NULL;
8736ba597c5SAnurag S. Maskey 		ushort_t family;
8746ba597c5SAnurag S. Maskey 		uint64_t flags = 0;
8756ba597c5SAnurag S. Maskey 
8766ba597c5SAnurag S. Maskey 		if_state = &evm->nwe_data.nwe_if_state;
877f6da83d4SAnurag S. Maskey 		u_if = &ncu->ncu_if;
8786ba597c5SAnurag S. Maskey 		family = if_state->nwe_addr.ss_family;
879f6da83d4SAnurag S. Maskey 		addr = &if_state->nwe_addr;
880f6da83d4SAnurag S. Maskey 		addr_added = if_state->nwe_addr_added;
8816ba597c5SAnurag S. Maskey 
882c3dd1218SToomas Soome 		v4dhcp_running = B_FALSE;
883c3dd1218SToomas Soome 		v6dhcp_running = B_FALSE;
884c3dd1218SToomas Soome 		stateless_running = B_FALSE;
885c3dd1218SToomas Soome 
8866ba597c5SAnurag S. Maskey 		nlog(LOG_DEBUG,
8876ba597c5SAnurag S. Maskey 		    "nwamd_ncu_handle_if_state_event: addr %s %s",
888f6da83d4SAnurag S. Maskey 		    nwamd_sockaddr2str((struct sockaddr *)addr, addrstr,
889f6da83d4SAnurag S. Maskey 		    sizeof (addrstr)), addr_added ? "added" : "removed");
890f6da83d4SAnurag S. Maskey 
891f6da83d4SAnurag S. Maskey 		/*
892f6da83d4SAnurag S. Maskey 		 * Need to get flags for this interface.  Get the addrinfo for
893f6da83d4SAnurag S. Maskey 		 * the address that generated this IF_STATE event.
894f6da83d4SAnurag S. Maskey 		 */
895f6da83d4SAnurag S. Maskey 		if (addr_added) {
896f6da83d4SAnurag S. Maskey 			/*
897f6da83d4SAnurag S. Maskey 			 * Address was added.  Find the addrinfo for this
898f6da83d4SAnurag S. Maskey 			 * address and the nwamd_if_address corresponding to
899f6da83d4SAnurag S. Maskey 			 * this address.
900f6da83d4SAnurag S. Maskey 			 */
901f6da83d4SAnurag S. Maskey 			if (!addrinfo_for_addr(addr, ncu->ncu_name, &ai)) {
9026ba597c5SAnurag S. Maskey 				nlog(LOG_ERR,
903f6da83d4SAnurag S. Maskey 				    "nwamd_ncu_handle_if_state_event: "
904f6da83d4SAnurag S. Maskey 				    "addrinfo doesn't exist for %s", addrstr);
9056ba597c5SAnurag S. Maskey 				nwamd_event_do_not_send(event);
906f6da83d4SAnurag S. Maskey 				goto valid_done;
9076ba597c5SAnurag S. Maskey 			}
908f6da83d4SAnurag S. Maskey 			addrinfo = ai;
909f6da83d4SAnurag S. Maskey 			flags = addrinfo->ia_ifa.ifa_flags;
91064639aafSDarren Reed 			(void) memcpy(&ai_addr, addrinfo->ia_ifa.ifa_addr,
91164639aafSDarren Reed 			    sizeof (ai_addr));
91264639aafSDarren Reed 			aip = &ai_addr;
913f6da83d4SAnurag S. Maskey 
914f6da83d4SAnurag S. Maskey 			if (addrinfo->ia_atype == IPADM_ADDR_IPV6_ADDRCONF ||
915f6da83d4SAnurag S. Maskey 			    addrinfo->ia_atype == IPADM_ADDR_DHCP)
916f6da83d4SAnurag S. Maskey 				nifa = find_nonstatic_address(ncu, family);
917f6da83d4SAnurag S. Maskey 			else if (addrinfo->ia_atype == IPADM_ADDR_STATIC)
918f6da83d4SAnurag S. Maskey 				nifa = find_static_address(addr, ncu);
919f6da83d4SAnurag S. Maskey 
9206ba597c5SAnurag S. Maskey 			/*
921f6da83d4SAnurag S. Maskey 			 * If nwamd_if_address is not found, then this address
922f6da83d4SAnurag S. Maskey 			 * isn't one that nwamd created.  Remove it.
9236ba597c5SAnurag S. Maskey 			 */
924f6da83d4SAnurag S. Maskey 			if (nifa == NULL) {
9256ba597c5SAnurag S. Maskey 				nlog(LOG_ERR,
9266ba597c5SAnurag S. Maskey 				    "nwamd_ncu_handle_if_state_event: "
927f6da83d4SAnurag S. Maskey 				    "address %s not managed by nwam added, "
928f6da83d4SAnurag S. Maskey 				    "removing it", addrstr);
929f6da83d4SAnurag S. Maskey 				nwamd_down_interface(addrinfo->ia_aobjname,
930f6da83d4SAnurag S. Maskey 				    addrinfo->ia_atype, ncu->ncu_name);
9316ba597c5SAnurag S. Maskey 				nwamd_event_do_not_send(event);
932f6da83d4SAnurag S. Maskey 				goto valid_done;
9336ba597c5SAnurag S. Maskey 			}
9346ba597c5SAnurag S. Maskey 
935f6da83d4SAnurag S. Maskey 			/* check flags to determine how intf is configured */
936f6da83d4SAnurag S. Maskey 			stateless_running = (family == AF_INET6) &&
937f6da83d4SAnurag S. Maskey 			    ((flags & STATELESS_RUNNING) == STATELESS_RUNNING);
938f6da83d4SAnurag S. Maskey 			v4dhcp_running = (family == AF_INET) &&
939f6da83d4SAnurag S. Maskey 			    ((flags & DHCP_RUNNING) == DHCP_RUNNING);
940f6da83d4SAnurag S. Maskey 			v6dhcp_running = (family == AF_INET6) &&
941f6da83d4SAnurag S. Maskey 			    ((flags & DHCP_RUNNING) == DHCP_RUNNING);
942f6da83d4SAnurag S. Maskey 			static_addr = (addrinfo->ia_atype == IPADM_ADDR_STATIC);
943f6da83d4SAnurag S. Maskey 
944f6da83d4SAnurag S. Maskey 			/* copy the configured address into nwamd_if_address */
945f6da83d4SAnurag S. Maskey 			if (stateless_running) {
946f6da83d4SAnurag S. Maskey 				(void) memcpy(&nifa->conf_stateless_addr,
947f6da83d4SAnurag S. Maskey 				    addrinfo->ia_ifa.ifa_addr,
948f6da83d4SAnurag S. Maskey 				    sizeof (struct sockaddr_storage));
949f6da83d4SAnurag S. Maskey 			} else {
950f6da83d4SAnurag S. Maskey 				(void) memcpy(&nifa->conf_addr,
951f6da83d4SAnurag S. Maskey 				    addrinfo->ia_ifa.ifa_addr,
952f6da83d4SAnurag S. Maskey 				    sizeof (struct sockaddr_storage));
953f6da83d4SAnurag S. Maskey 			}
9546ba597c5SAnurag S. Maskey 
955f6da83d4SAnurag S. Maskey 		} else {
9566ba597c5SAnurag S. Maskey 			/*
957f6da83d4SAnurag S. Maskey 			 * Address was removed.  Find the nwamd_if_address
958f6da83d4SAnurag S. Maskey 			 * that configured this address.
9596ba597c5SAnurag S. Maskey 			 */
960f6da83d4SAnurag S. Maskey 			nifa = find_configured_address(addr, ncu);
961f6da83d4SAnurag S. Maskey 			if (nifa == NULL) {
962f6da83d4SAnurag S. Maskey 				nlog(LOG_ERR,
963f6da83d4SAnurag S. Maskey 				    "nwamd_ncu_handle_if_state_event: "
964f6da83d4SAnurag S. Maskey 				    "address %s not managed by nwam removed, "
965f6da83d4SAnurag S. Maskey 				    "nothing to do", addrstr);
966f6da83d4SAnurag S. Maskey 				nwamd_event_do_not_send(event);
967f6da83d4SAnurag S. Maskey 				goto valid_done;
968f6da83d4SAnurag S. Maskey 			}
969f6da83d4SAnurag S. Maskey 
970f6da83d4SAnurag S. Maskey 			if (addrinfo_for_ipaddr(nifa->ipaddr, ncu->ncu_name,
971f6da83d4SAnurag S. Maskey 			    &ai)) {
972f6da83d4SAnurag S. Maskey 				ipadm_addr_info_t *a;
973f6da83d4SAnurag S. Maskey 				for (a = ai; a != NULL; a = IA_NEXT(a)) {
97464639aafSDarren Reed 					struct sockaddr_storage stor;
97564639aafSDarren Reed 
97664639aafSDarren Reed 					(void) memcpy(&stor, a->ia_ifa.ifa_addr,
97764639aafSDarren Reed 					    sizeof (stor));
978f6da83d4SAnurag S. Maskey 					/*
979f6da83d4SAnurag S. Maskey 					 * Since multiple addrinfo can have
980f6da83d4SAnurag S. Maskey 					 * the same ipaddr, find the one for
981f6da83d4SAnurag S. Maskey 					 * the address that generated this
982f6da83d4SAnurag S. Maskey 					 * state event.
983f6da83d4SAnurag S. Maskey 					 */
98464639aafSDarren Reed 					if (sockaddrcmp(addr, &stor)) {
985f6da83d4SAnurag S. Maskey 						flags = a->ia_ifa.ifa_flags;
98664639aafSDarren Reed 						(void) memcpy(&ai_addr,
98764639aafSDarren Reed 						    a->ia_ifa.ifa_addr,
98864639aafSDarren Reed 						    sizeof (ai_addr));
98964639aafSDarren Reed 						aip = &ai_addr;
990f6da83d4SAnurag S. Maskey 						addrinfo = a;
991f6da83d4SAnurag S. Maskey 					}
992f6da83d4SAnurag S. Maskey 					/*
993f6da83d4SAnurag S. Maskey 					 * Stateful and stateless IPv6
994f6da83d4SAnurag S. Maskey 					 * addrinfo have the same aobjname.
995f6da83d4SAnurag S. Maskey 					 * Use the flags to determine which
996f6da83d4SAnurag S. Maskey 					 * address is present in the system.
997f6da83d4SAnurag S. Maskey 					 */
998f6da83d4SAnurag S. Maskey 					if (family == AF_INET6) {
999f6da83d4SAnurag S. Maskey 						stateless_ai_found =
1000f6da83d4SAnurag S. Maskey 						    (a->ia_ifa.ifa_flags &
1001f6da83d4SAnurag S. Maskey 						    STATELESS_RUNNING);
1002f6da83d4SAnurag S. Maskey 						stateful_ai_found =
1003f6da83d4SAnurag S. Maskey 						    (a->ia_ifa.ifa_flags &
1004f6da83d4SAnurag S. Maskey 						    DHCP_RUNNING);
1005f6da83d4SAnurag S. Maskey 					}
1006f6da83d4SAnurag S. Maskey 				}
10076ba597c5SAnurag S. Maskey 			}
10086ba597c5SAnurag S. Maskey 		}
10096ba597c5SAnurag S. Maskey 
1010f6da83d4SAnurag S. Maskey 		/* Set the flags in the event for listeners */
1011f6da83d4SAnurag S. Maskey 		evm->nwe_data.nwe_if_state.nwe_flags = flags;
1012f6da83d4SAnurag S. Maskey 
1013f6da83d4SAnurag S. Maskey 		if (family == AF_INET && !addr_added) {
10146ba597c5SAnurag S. Maskey 			/*
10156ba597c5SAnurag S. Maskey 			 * Check for failure due to CR 6745448: if we get a
10166ba597c5SAnurag S. Maskey 			 * report that an address has been deleted, then check
10176ba597c5SAnurag S. Maskey 			 * for interface up, datalink down, and actual address
10186ba597c5SAnurag S. Maskey 			 * non-zero.  If that combination is seen, then this is
10196ba597c5SAnurag S. Maskey 			 * a DHCP cached lease, and we need to remove it from
10206ba597c5SAnurag S. Maskey 			 * the system, or it'll louse up the kernel routes
10216ba597c5SAnurag S. Maskey 			 * (which aren't smart enough to avoid dead
10226ba597c5SAnurag S. Maskey 			 * interfaces).
10236ba597c5SAnurag S. Maskey 			 */
10246ba597c5SAnurag S. Maskey 			if (((struct sockaddr_in *)addr)->sin_addr.s_addr
102564639aafSDarren Reed 			    == INADDR_ANY && aip != 0) {
1026f6da83d4SAnurag S. Maskey 				struct sockaddr_in *a;
1027f6da83d4SAnurag S. Maskey 				char astr[INET6_ADDRSTRLEN];
102864639aafSDarren Reed 				a = (struct sockaddr_in *)aip;
10296ba597c5SAnurag S. Maskey 
10306ba597c5SAnurag S. Maskey 				if ((flags & IFF_UP) &&
10316ba597c5SAnurag S. Maskey 				    !(flags & IFF_RUNNING) &&
1032f6da83d4SAnurag S. Maskey 				    a->sin_addr.s_addr != INADDR_ANY) {
1033f6da83d4SAnurag S. Maskey 					nlog(LOG_DEBUG,
1034f6da83d4SAnurag S. Maskey 					    "nwamd_ncu_handle_if_state_event: "
1035f6da83d4SAnurag S. Maskey 					    "bug workaround: clear out addr "
1036f6da83d4SAnurag S. Maskey 					    "%s on %s", nwamd_sockaddr2str
1037f6da83d4SAnurag S. Maskey 					    ((struct sockaddr *)a, astr,
1038f6da83d4SAnurag S. Maskey 					    sizeof (astr)),
1039f6da83d4SAnurag S. Maskey 					    ncu->ncu_name);
1040f6da83d4SAnurag S. Maskey 					nwamd_down_interface(
1041f6da83d4SAnurag S. Maskey 					    addrinfo->ia_aobjname,
1042f6da83d4SAnurag S. Maskey 					    IPADM_ADDR_DHCP, ncu->ncu_name);
10436ba597c5SAnurag S. Maskey 				}
1044f6da83d4SAnurag S. Maskey 				goto valid_done;
10456ba597c5SAnurag S. Maskey 			}
10466ba597c5SAnurag S. Maskey 		}
10476ba597c5SAnurag S. Maskey 
10486ba597c5SAnurag S. Maskey 		/*
1049f6da83d4SAnurag S. Maskey 		 * If we received an RTM_NEWADDR and the IFF_UP flags has not
1050f6da83d4SAnurag S. Maskey 		 * been set, ignore this IF_STATE event.  Once the IFF_UP flag
1051f6da83d4SAnurag S. Maskey 		 * is set, we'll get another RTM_NEWADDR message.
1052f6da83d4SAnurag S. Maskey 		 */
1053f6da83d4SAnurag S. Maskey 		if (addr_added & !(flags & IFF_UP)) {
1054f6da83d4SAnurag S. Maskey 			nlog(LOG_INFO, "nwamd_ncu_handle_if_state_event: "
1055f6da83d4SAnurag S. Maskey 			    "address %s added on %s without IFF_UP flag (%x), "
1056f6da83d4SAnurag S. Maskey 			    "ignoring IF_STATE event",
1057f6da83d4SAnurag S. Maskey 			    addrstr, ncu->ncu_name, flags);
1058f6da83d4SAnurag S. Maskey 			nwamd_event_do_not_send(event);
1059f6da83d4SAnurag S. Maskey 			goto valid_done;
1060f6da83d4SAnurag S. Maskey 		}
1061f6da83d4SAnurag S. Maskey 
1062f6da83d4SAnurag S. Maskey 		/*
1063f6da83d4SAnurag S. Maskey 		 * Has the address really been removed?  Sometimes spurious
10646ba597c5SAnurag S. Maskey 		 * RTM_DELADDRs are generated, so we need to ensure that
10656ba597c5SAnurag S. Maskey 		 * the address is really gone.  If IFF_DUPLICATE is set,
10666ba597c5SAnurag S. Maskey 		 * we're getting the RTM_DELADDR due to DAD, so don't test
10676ba597c5SAnurag S. Maskey 		 * in that case.
10686ba597c5SAnurag S. Maskey 		 */
1069f6da83d4SAnurag S. Maskey 		if (!addr_added && !(flags & IFF_DUPLICATE)) {
107064639aafSDarren Reed 			if (aip != 0 && sockaddrcmp(addr, aip)) {
1071f6da83d4SAnurag S. Maskey 				nlog(LOG_INFO,
10726ba597c5SAnurag S. Maskey 				    "nwamd_ncu_handle_if_state_event: "
10736ba597c5SAnurag S. Maskey 				    "address %s is not really gone from %s, "
10746ba597c5SAnurag S. Maskey 				    "ignoring IF_STATE event",
1075f6da83d4SAnurag S. Maskey 				    addrstr, ncu->ncu_name);
10766ba597c5SAnurag S. Maskey 				nwamd_event_do_not_send(event);
1077f6da83d4SAnurag S. Maskey 				goto valid_done;
10786ba597c5SAnurag S. Maskey 			}
10796ba597c5SAnurag S. Maskey 		}
10806ba597c5SAnurag S. Maskey 
1081f6da83d4SAnurag S. Maskey 		if (addr_added) {
10826ba597c5SAnurag S. Maskey 			/*
10836ba597c5SAnurag S. Maskey 			 * Address has been added.
10846ba597c5SAnurag S. Maskey 			 *
10856ba597c5SAnurag S. Maskey 			 * We need to make sure that we really want to keep
10866ba597c5SAnurag S. Maskey 			 * this address.  There is a race where we requested an
10876ba597c5SAnurag S. Maskey 			 * address but by the time we got here we don't really
10886ba597c5SAnurag S. Maskey 			 * want it and need to remove it.
10896ba597c5SAnurag S. Maskey 			 *
10906ba597c5SAnurag S. Maskey 			 * Once we decide we want the address adjust the ncu
10916ba597c5SAnurag S. Maskey 			 * state accordingly.  For example if this address is
10926ba597c5SAnurag S. Maskey 			 * enough move online.
10936ba597c5SAnurag S. Maskey 			 */
1094f6da83d4SAnurag S. Maskey 			if (u_if->nwamd_if_dhcp_requested && v4dhcp_running) {
10956ba597c5SAnurag S. Maskey 				u_if->nwamd_if_dhcp_configured = B_TRUE;
10966ba597c5SAnurag S. Maskey 			} else if (u_if->nwamd_if_stateful_requested &&
10976ba597c5SAnurag S. Maskey 			    v6dhcp_running) {
10986ba597c5SAnurag S. Maskey 				u_if->nwamd_if_stateful_configured = B_TRUE;
10996ba597c5SAnurag S. Maskey 			} else if (u_if->nwamd_if_stateless_requested &&
11006ba597c5SAnurag S. Maskey 			    stateless_running) {
11016ba597c5SAnurag S. Maskey 				u_if->nwamd_if_stateless_configured = B_TRUE;
1102f6da83d4SAnurag S. Maskey 			} else if (!static_addr) {
11036ba597c5SAnurag S. Maskey 				/*
11046ba597c5SAnurag S. Maskey 				 * This is something we didn't expect.  Remove
1105f6da83d4SAnurag S. Maskey 				 * the address.
11066ba597c5SAnurag S. Maskey 				 */
1107f6da83d4SAnurag S. Maskey 				nwamd_down_interface(addrinfo->ia_aobjname,
1108f6da83d4SAnurag S. Maskey 				    addrinfo->ia_atype, ncu->ncu_name);
1109f6da83d4SAnurag S. Maskey 				nifa->configured = B_FALSE;
1110f6da83d4SAnurag S. Maskey 				goto valid_done;
11116ba597c5SAnurag S. Maskey 			}
11126ba597c5SAnurag S. Maskey 
11136ba597c5SAnurag S. Maskey 			/*
11146ba597c5SAnurag S. Maskey 			 * The address looks valid so mark configured and
11156ba597c5SAnurag S. Maskey 			 * move online if we either have a v4 address if
11166ba597c5SAnurag S. Maskey 			 * v4 is configured or a v6 address if only v6 is
11176ba597c5SAnurag S. Maskey 			 * configured.
11186ba597c5SAnurag S. Maskey 			 */
1119f6da83d4SAnurag S. Maskey 			nifa->configured = B_TRUE;
11206ba597c5SAnurag S. Maskey 			if (state != NWAM_STATE_ONLINE)
11216ba597c5SAnurag S. Maskey 				interface_ncu_up(ncu);
11226ba597c5SAnurag S. Maskey 
11236ba597c5SAnurag S. Maskey 			/*
11246ba597c5SAnurag S. Maskey 			 * Refresh network/location since we may also have other
11256ba597c5SAnurag S. Maskey 			 * DHCP information.  We might have to restore it first
11266ba597c5SAnurag S. Maskey 			 * in case it is in maintenance.
11276ba597c5SAnurag S. Maskey 			 */
11286ba597c5SAnurag S. Maskey 			nlog(LOG_DEBUG, "nwamd_handle_if_state_event: "
11296ba597c5SAnurag S. Maskey 			    "refreshing %s as we may have other "
11306ba597c5SAnurag S. Maskey 			    "DHCP information", NET_LOC_FMRI);
11316ba597c5SAnurag S. Maskey 			(void) smf_restore_instance(NET_LOC_FMRI);
11326ba597c5SAnurag S. Maskey 			if (smf_refresh_instance(NET_LOC_FMRI) != 0) {
11336ba597c5SAnurag S. Maskey 				nlog(LOG_ERR,
11346ba597c5SAnurag S. Maskey 				    "nwamd_ncu_handle_if_state_"
11356ba597c5SAnurag S. Maskey 				    "event: refresh of %s "
11366ba597c5SAnurag S. Maskey 				    "failed", NET_LOC_FMRI);
11376ba597c5SAnurag S. Maskey 			}
1138f6da83d4SAnurag S. Maskey 
11396ba597c5SAnurag S. Maskey 		} else if (state == NWAM_STATE_ONLINE ||
11406ba597c5SAnurag S. Maskey 		    state == NWAM_STATE_OFFLINE_TO_ONLINE) {
11416ba597c5SAnurag S. Maskey 			/*
11426ba597c5SAnurag S. Maskey 			 * Address has been removed.  Only pay attention to
11436ba597c5SAnurag S. Maskey 			 * disappearing addresses if we are online or coming
11446ba597c5SAnurag S. Maskey 			 * online.
11456ba597c5SAnurag S. Maskey 			 *
11466ba597c5SAnurag S. Maskey 			 * Undo whatever configuration is necessary.  Note
11476ba597c5SAnurag S. Maskey 			 * that this may or may not cause the NCU to go down.
11486ba597c5SAnurag S. Maskey 			 * We can get RTM_DELADDRs for duplicate addresses
11496ba597c5SAnurag S. Maskey 			 * so deal with this seperately.
11506ba597c5SAnurag S. Maskey 			 */
1151f6da83d4SAnurag S. Maskey 			nifa->configured = B_FALSE;
1152f6da83d4SAnurag S. Maskey 
1153f6da83d4SAnurag S. Maskey 			if (!static_addr && family == AF_INET) {
11546ba597c5SAnurag S. Maskey 				u_if->nwamd_if_dhcp_configured = B_FALSE;
1155f6da83d4SAnurag S. Maskey 			} else if (!static_addr && family == AF_INET6) {
11566ba597c5SAnurag S. Maskey 				/*
1157f6da83d4SAnurag S. Maskey 				 * The address is already gone.  When looking
1158f6da83d4SAnurag S. Maskey 				 * for the addrinfo (using aobjname in
1159f6da83d4SAnurag S. Maskey 				 * ipaddr), we found addrinfo for either one
1160f6da83d4SAnurag S. Maskey 				 * or both stateless and stateful.  Using the
1161f6da83d4SAnurag S. Maskey 				 * flags we determined whether each was
1162f6da83d4SAnurag S. Maskey 				 * configured or not.  Update the flags here
1163f6da83d4SAnurag S. Maskey 				 * accordingly.
11646ba597c5SAnurag S. Maskey 				 */
1165f6da83d4SAnurag S. Maskey 				u_if->nwamd_if_stateful_configured =
1166f6da83d4SAnurag S. Maskey 				    stateless_ai_found;
1167f6da83d4SAnurag S. Maskey 				u_if->nwamd_if_stateless_configured =
1168f6da83d4SAnurag S. Maskey 				    stateful_ai_found;
11696ba597c5SAnurag S. Maskey 			}
11706ba597c5SAnurag S. Maskey 
11716ba597c5SAnurag S. Maskey 			if (flags & IFF_DUPLICATE) {
11726ba597c5SAnurag S. Maskey 				nlog(LOG_INFO,
11736ba597c5SAnurag S. Maskey 				    "nwamd_ncu_handle_if_state_event: "
11746ba597c5SAnurag S. Maskey 				    "duplicate address detected on %s",
11756ba597c5SAnurag S. Maskey 				    ncu->ncu_name);
11766ba597c5SAnurag S. Maskey 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
11776ba597c5SAnurag S. Maskey 				    event->event_object,
11786ba597c5SAnurag S. Maskey 				    NWAM_STATE_MAINTENANCE,
11796ba597c5SAnurag S. Maskey 				    NWAM_AUX_STATE_IF_DUPLICATE_ADDR);
11806ba597c5SAnurag S. Maskey 			} else {
11816ba597c5SAnurag S. Maskey 				interface_ncu_down(ncu);
11826ba597c5SAnurag S. Maskey 			}
11836ba597c5SAnurag S. Maskey 		}
1184f6da83d4SAnurag S. Maskey valid_done:
1185f6da83d4SAnurag S. Maskey 		ipadm_free_addr_info(ai);
11866ba597c5SAnurag S. Maskey 	}
11876ba597c5SAnurag S. Maskey 	nwamd_object_release(ncu_obj);
11886ba597c5SAnurag S. Maskey }
11896ba597c5SAnurag S. Maskey 
11906ba597c5SAnurag S. Maskey void
nwamd_ncu_handle_if_action_event(nwamd_event_t event)11916ba597c5SAnurag S. Maskey nwamd_ncu_handle_if_action_event(nwamd_event_t event)
11926ba597c5SAnurag S. Maskey {
11936ba597c5SAnurag S. Maskey 	nwamd_object_t ncu_obj;
11946ba597c5SAnurag S. Maskey 
11956ba597c5SAnurag S. Maskey 	nlog(LOG_DEBUG, "if action event %s",
11966ba597c5SAnurag S. Maskey 	    event->event_object[0] == '\0' ? "n/a" : event->event_object);
11976ba597c5SAnurag S. Maskey 
11986ba597c5SAnurag S. Maskey 	ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, event->event_object);
11996ba597c5SAnurag S. Maskey 	if (ncu_obj == NULL) {
12006ba597c5SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_ncu_handle_if_action_event: no object");
12016ba597c5SAnurag S. Maskey 		nwamd_event_do_not_send(event);
12026ba597c5SAnurag S. Maskey 		return;
12036ba597c5SAnurag S. Maskey 	}
12046ba597c5SAnurag S. Maskey 	nwamd_object_release(ncu_obj);
12056ba597c5SAnurag S. Maskey }
12066ba597c5SAnurag S. Maskey 
12076ba597c5SAnurag S. Maskey /*
1208f6da83d4SAnurag S. Maskey  * Remove the address in the given aobjname.  IPADM_OPT_RELEASE is specified
1209f6da83d4SAnurag S. Maskey  * for a DHCP address and specifies that the DHCP lease should also be released.
1210f6da83d4SAnurag S. Maskey  * ifname is only used for nlog().
12116ba597c5SAnurag S. Maskey  */
12126ba597c5SAnurag S. Maskey static void
nwamd_down_interface(const char * aobjname,ipadm_addr_type_t atype,const char * ifname)1213f6da83d4SAnurag S. Maskey nwamd_down_interface(const char *aobjname, ipadm_addr_type_t atype,
1214f6da83d4SAnurag S. Maskey     const char *ifname)
12156ba597c5SAnurag S. Maskey {
1216f6da83d4SAnurag S. Maskey 	ipadm_status_t ipstatus;
1217f6da83d4SAnurag S. Maskey 	uint32_t rflags = (atype == IPADM_ADDR_DHCP ? IPADM_OPT_RELEASE : 0);
1218f6da83d4SAnurag S. Maskey 
1219f6da83d4SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_down_interface: %s [aobjname = %s]",
1220f6da83d4SAnurag S. Maskey 	    ifname, aobjname);
1221f6da83d4SAnurag S. Maskey 	if ((ipstatus = ipadm_delete_addr(ipadm_handle, aobjname,
1222f6da83d4SAnurag S. Maskey 	    IPADM_OPT_ACTIVE | rflags)) != IPADM_SUCCESS) {
1223f6da83d4SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_down_interface: "
1224f6da83d4SAnurag S. Maskey 		    "ipadm_delete_addr failed on %s: %s",
1225f6da83d4SAnurag S. Maskey 		    ifname, ipadm_status2str(ipstatus));
12266ba597c5SAnurag S. Maskey 	}
1227f6da83d4SAnurag S. Maskey }
12286ba597c5SAnurag S. Maskey 
1229f6da83d4SAnurag S. Maskey static void
unconfigure_addresses(nwamd_ncu_t * ncu,sa_family_t af)1230f6da83d4SAnurag S. Maskey unconfigure_addresses(nwamd_ncu_t *ncu, sa_family_t af)
1231f6da83d4SAnurag S. Maskey {
1232f6da83d4SAnurag S. Maskey 	struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
12336ba597c5SAnurag S. Maskey 
1234f6da83d4SAnurag S. Maskey 	for (nifap = nifa; nifap != NULL; nifap = nifap->next)
1235f6da83d4SAnurag S. Maskey 		if (af == AF_UNSPEC || nifap->family == af)
1236f6da83d4SAnurag S. Maskey 			nifap->configured = B_FALSE;
12376ba597c5SAnurag S. Maskey }
12386ba597c5SAnurag S. Maskey 
12396ba597c5SAnurag S. Maskey static void
dhcp_release(const char * ifname)1240f6da83d4SAnurag S. Maskey dhcp_release(const char *ifname)
12416ba597c5SAnurag S. Maskey {
1242f6da83d4SAnurag S. Maskey 	ipadm_addr_info_t *ainfo, *ainfop;
12436ba597c5SAnurag S. Maskey 
1244f6da83d4SAnurag S. Maskey 	if (ipadm_addr_info(ipadm_handle, ifname, &ainfo, 0, 0)
1245f6da83d4SAnurag S. Maskey 	    != IPADM_SUCCESS)
12466ba597c5SAnurag S. Maskey 		return;
1247f6da83d4SAnurag S. Maskey 
1248f6da83d4SAnurag S. Maskey 	for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
1249f6da83d4SAnurag S. Maskey 		if (ainfop->ia_atype == IPADM_ADDR_DHCP)
1250f6da83d4SAnurag S. Maskey 			nwamd_down_interface(ainfop->ia_aobjname,
1251f6da83d4SAnurag S. Maskey 			    ainfop->ia_atype, ifname);
12526ba597c5SAnurag S. Maskey 	}
1253f6da83d4SAnurag S. Maskey 	ipadm_free_addr_info(ainfo);
1254f6da83d4SAnurag S. Maskey }
12556ba597c5SAnurag S. Maskey 
1256f6da83d4SAnurag S. Maskey static void
nwamd_plumb_unplumb_interface(nwamd_ncu_t * ncu,sa_family_t af,boolean_t plumb)1257f6da83d4SAnurag S. Maskey nwamd_plumb_unplumb_interface(nwamd_ncu_t *ncu, sa_family_t af, boolean_t plumb)
1258f6da83d4SAnurag S. Maskey {
1259f6da83d4SAnurag S. Maskey 	char *ifname = ncu->ncu_name;
1260f6da83d4SAnurag S. Maskey 	nwamd_if_t *u_if = &ncu->ncu_if;
1261f6da83d4SAnurag S. Maskey 	ipadm_status_t ipstatus;
12626ba597c5SAnurag S. Maskey 
1263f6da83d4SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_plumb_unplumb_interface: %s %s %s",
1264f6da83d4SAnurag S. Maskey 	    (plumb ? "plumb" : "unplumb"), (af == AF_INET ? "IPv4" : "IPv6"),
1265f6da83d4SAnurag S. Maskey 	    ifname);
12666ba597c5SAnurag S. Maskey 
1267f6da83d4SAnurag S. Maskey 	if (plumb) {
1268f6da83d4SAnurag S. Maskey 		ipstatus = ipadm_create_if(ipadm_handle, ifname, af,
1269f6da83d4SAnurag S. Maskey 		    IPADM_OPT_ACTIVE);
1270f6da83d4SAnurag S. Maskey 	} else {
1271f6da83d4SAnurag S. Maskey 		/* release DHCP address, if any */
1272f6da83d4SAnurag S. Maskey 		if (af == AF_INET)
1273f6da83d4SAnurag S. Maskey 			dhcp_release(ifname);
1274f6da83d4SAnurag S. Maskey 		ipstatus = ipadm_delete_if(ipadm_handle, ifname, af,
1275f6da83d4SAnurag S. Maskey 		    IPADM_OPT_ACTIVE);
12766ba597c5SAnurag S. Maskey 	}
12776ba597c5SAnurag S. Maskey 
1278f6da83d4SAnurag S. Maskey 	if (ipstatus != IPADM_SUCCESS) {
1279f6da83d4SAnurag S. Maskey 		if ((plumb && ipstatus != IPADM_IF_EXISTS) ||
1280f6da83d4SAnurag S. Maskey 		    (!plumb && ipstatus != IPADM_ENXIO)) {
12816ba597c5SAnurag S. Maskey 			nlog(LOG_ERR, "nwamd_plumb_unplumb_interface: "
12826ba597c5SAnurag S. Maskey 			    "%s %s failed for %s: %s",
1283f6da83d4SAnurag S. Maskey 			    (plumb ? "plumb" : "unplumb"),
1284f6da83d4SAnurag S. Maskey 			    (af == AF_INET ? "IPv4" : "IPv6"),
1285f6da83d4SAnurag S. Maskey 			    ifname, ipadm_status2str(ipstatus));
12866ba597c5SAnurag S. Maskey 		}
12876ba597c5SAnurag S. Maskey 	}
12886ba597c5SAnurag S. Maskey 
1289f6da83d4SAnurag S. Maskey 	/* Unset flags */
12906ba597c5SAnurag S. Maskey 	if (!plumb) {
1291f6da83d4SAnurag S. Maskey 		unconfigure_addresses(ncu, af);
12926ba597c5SAnurag S. Maskey 		switch (af) {
1293f6da83d4SAnurag S. Maskey 		case AF_INET:
1294f6da83d4SAnurag S. Maskey 			u_if->nwamd_if_dhcp_configured = B_FALSE;
1295f6da83d4SAnurag S. Maskey 			break;
1296f6da83d4SAnurag S. Maskey 		case AF_INET6:
1297f6da83d4SAnurag S. Maskey 			u_if->nwamd_if_stateful_configured = B_FALSE;
1298f6da83d4SAnurag S. Maskey 			u_if->nwamd_if_stateless_configured = B_FALSE;
1299f6da83d4SAnurag S. Maskey 			break;
13006ba597c5SAnurag S. Maskey 		}
13016ba597c5SAnurag S. Maskey 	}
13026ba597c5SAnurag S. Maskey }
13036ba597c5SAnurag S. Maskey 
13046ba597c5SAnurag S. Maskey void
nwamd_plumb_interface(nwamd_ncu_t * ncu,sa_family_t af)1305f6da83d4SAnurag S. Maskey nwamd_plumb_interface(nwamd_ncu_t *ncu, sa_family_t af)
13066ba597c5SAnurag S. Maskey {
130738f140aaSMichael Hunter 	/*
130838f140aaSMichael Hunter 	 * We get all posssible privs by calling nwamd_deescalate().  During
130938f140aaSMichael Hunter 	 * startup opening /dev/dld (data link management) needs all privs
131038f140aaSMichael Hunter 	 * because we don't have access to /etc/security/device_policy yet.
131138f140aaSMichael Hunter 	 */
131238f140aaSMichael Hunter 	nwamd_escalate();
1313f6da83d4SAnurag S. Maskey 	nwamd_plumb_unplumb_interface(ncu, af, B_TRUE);
131438f140aaSMichael Hunter 	nwamd_deescalate();
13156ba597c5SAnurag S. Maskey }
13166ba597c5SAnurag S. Maskey 
13176ba597c5SAnurag S. Maskey void
nwamd_unplumb_interface(nwamd_ncu_t * ncu,sa_family_t af)1318f6da83d4SAnurag S. Maskey nwamd_unplumb_interface(nwamd_ncu_t *ncu, sa_family_t af)
13196ba597c5SAnurag S. Maskey {
1320f6da83d4SAnurag S. Maskey 	nwamd_plumb_unplumb_interface(ncu, af, B_FALSE);
13216ba597c5SAnurag S. Maskey }
13226ba597c5SAnurag S. Maskey 
13236ba597c5SAnurag S. Maskey static void *
start_dhcp_thread(void * arg)13246ba597c5SAnurag S. Maskey start_dhcp_thread(void *arg)
13256ba597c5SAnurag S. Maskey {
1326f6da83d4SAnurag S. Maskey 	struct nwamd_dhcp_thread_arg *thread_arg = arg;
1327f6da83d4SAnurag S. Maskey 	nwamd_object_t ncu_obj;
13286ba597c5SAnurag S. Maskey 	dhcp_ipc_type_t type;
13296ba597c5SAnurag S. Maskey 	char *name;
1330f6da83d4SAnurag S. Maskey 	ipadm_addrobj_t ipaddr;
1331f6da83d4SAnurag S. Maskey 	ipadm_status_t ipstatus;
1332f6da83d4SAnurag S. Maskey 	int retries = 0;
13336ba597c5SAnurag S. Maskey 
13346ba597c5SAnurag S. Maskey 	name = thread_arg->name;
13356ba597c5SAnurag S. Maskey 	type = thread_arg->type;
1336f6da83d4SAnurag S. Maskey 	ipaddr = thread_arg->ipaddr;
13376ba597c5SAnurag S. Maskey 
13386ba597c5SAnurag S. Maskey retry:
1339f6da83d4SAnurag S. Maskey 	/* Make sure the NCU is in appropriate state for DHCP command */
1340f6da83d4SAnurag S. Maskey 	ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE, name);
1341f6da83d4SAnurag S. Maskey 	if (ncu_obj == NULL) {
134248fff0e3SRenee Danson Sommerfeld 		nlog(LOG_ERR, "start_dhcp: no IP object %s", name);
1343f6da83d4SAnurag S. Maskey 		return (NULL);
13446ba597c5SAnurag S. Maskey 	}
13456ba597c5SAnurag S. Maskey 
1346f6da83d4SAnurag S. Maskey 	if (ncu_obj->nwamd_object_state != NWAM_STATE_OFFLINE_TO_ONLINE &&
1347f6da83d4SAnurag S. Maskey 	    ncu_obj->nwamd_object_state != NWAM_STATE_ONLINE) {
1348f6da83d4SAnurag S. Maskey 		nlog(LOG_INFO, "start_dhcp: IP NCU %s is in invalid state "
1349f6da83d4SAnurag S. Maskey 		    "for DHCP command", ncu_obj->nwamd_object_name);
1350f6da83d4SAnurag S. Maskey 		nwamd_object_release(ncu_obj);
1351f6da83d4SAnurag S. Maskey 		return (NULL);
13526ba597c5SAnurag S. Maskey 	}
1353f6da83d4SAnurag S. Maskey 	nwamd_object_release(ncu_obj);
13546ba597c5SAnurag S. Maskey 
1355f6da83d4SAnurag S. Maskey 	switch (type) {
1356f6da83d4SAnurag S. Maskey 	case DHCP_INFORM:
1357f6da83d4SAnurag S. Maskey 	{
1358f6da83d4SAnurag S. Maskey 		char aobjname[IPADM_AOBJSIZ];
1359f6da83d4SAnurag S. Maskey 
1360f6da83d4SAnurag S. Maskey 		if ((ipstatus = ipadm_get_aobjname(ipaddr, aobjname,
1361f6da83d4SAnurag S. Maskey 		    sizeof (aobjname))) != IPADM_SUCCESS) {
1362f6da83d4SAnurag S. Maskey 			nlog(LOG_ERR, "start_dhcp: "
1363f6da83d4SAnurag S. Maskey 			    "ipadm_get_aobjname failed for %s: %s",
1364f6da83d4SAnurag S. Maskey 			    name, ipadm_status2str(ipstatus));
1365f6da83d4SAnurag S. Maskey 			goto done;
13666ba597c5SAnurag S. Maskey 		}
1367f6da83d4SAnurag S. Maskey 		ipstatus = ipadm_refresh_addr(ipadm_handle, aobjname,
1368f6da83d4SAnurag S. Maskey 		    IPADM_OPT_ACTIVE | IPADM_OPT_INFORM);
1369f6da83d4SAnurag S. Maskey 		break;
1370f6da83d4SAnurag S. Maskey 	}
1371f6da83d4SAnurag S. Maskey 	case DHCP_START:
1372f6da83d4SAnurag S. Maskey 		ipstatus = ipadm_create_addr(ipadm_handle, ipaddr,
1373f6da83d4SAnurag S. Maskey 		    IPADM_OPT_ACTIVE);
13743dbbe3fbSAnurag S. Maskey 		break;
13753dbbe3fbSAnurag S. Maskey 	default:
13763dbbe3fbSAnurag S. Maskey 		nlog(LOG_ERR, "start_dhcp: invalid dhcp_ipc_type_t: %d", type);
13773dbbe3fbSAnurag S. Maskey 		goto done;
13783dbbe3fbSAnurag S. Maskey 	}
1379f6da83d4SAnurag S. Maskey 
13803dbbe3fbSAnurag S. Maskey 	if (ipstatus == IPADM_DHCP_IPC_TIMEOUT) {
13813dbbe3fbSAnurag S. Maskey 		/*
13823dbbe3fbSAnurag S. Maskey 		 * DHCP timed out: for DHCP_START requests, change state for
13833dbbe3fbSAnurag S. Maskey 		 * this NCU and euqueue event to check NCU priority-groups;
13843dbbe3fbSAnurag S. Maskey 		 * for DHCP_INFORM requests, nothing to do.
13853dbbe3fbSAnurag S. Maskey 		 */
13863dbbe3fbSAnurag S. Maskey 		if (type == DHCP_START) {
13876ba597c5SAnurag S. Maskey 			char *object_name;
13886ba597c5SAnurag S. Maskey 
13893dbbe3fbSAnurag S. Maskey 			nlog(LOG_INFO,
13903dbbe3fbSAnurag S. Maskey 			    "start_dhcp: DHCP_START timed out for %s", name);
1391f6da83d4SAnurag S. Maskey 
13926ba597c5SAnurag S. Maskey 			if (nwam_ncu_name_to_typed_name(name,
13936ba597c5SAnurag S. Maskey 			    NWAM_NCU_TYPE_INTERFACE, &object_name)
13946ba597c5SAnurag S. Maskey 			    != NWAM_SUCCESS) {
13956ba597c5SAnurag S. Maskey 				nlog(LOG_ERR, "start_dhcp: "
13963dbbe3fbSAnurag S. Maskey 				    "nwam_ncu_name_to_typed_name failed for %s",
13973dbbe3fbSAnurag S. Maskey 				    name);
1398f6da83d4SAnurag S. Maskey 				goto done;
13996ba597c5SAnurag S. Maskey 			}
14006ba597c5SAnurag S. Maskey 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
14016ba597c5SAnurag S. Maskey 			    object_name, NWAM_STATE_OFFLINE_TO_ONLINE,
14026ba597c5SAnurag S. Maskey 			    NWAM_AUX_STATE_IF_DHCP_TIMED_OUT);
14036ba597c5SAnurag S. Maskey 			nwamd_create_ncu_check_event(0);
14046ba597c5SAnurag S. Maskey 			free(object_name);
14053dbbe3fbSAnurag S. Maskey 		} else {
14063dbbe3fbSAnurag S. Maskey 			nlog(LOG_INFO,
14073dbbe3fbSAnurag S. Maskey 			    "start_dhcp: DHCP_INFORM timed out for %s", name);
14086ba597c5SAnurag S. Maskey 		}
14096ba597c5SAnurag S. Maskey 
14103dbbe3fbSAnurag S. Maskey 	} else if ((ipstatus == IPADM_DHCP_IPC_ERROR ||
14113dbbe3fbSAnurag S. Maskey 	    ipstatus == IPADM_IPC_ERROR) && retries++ < NWAMD_DHCP_RETRIES) {
14123dbbe3fbSAnurag S. Maskey 		/*
14133dbbe3fbSAnurag S. Maskey 		 * Retry DHCP request as we may have been unplumbing as part
14143dbbe3fbSAnurag S. Maskey 		 * of the configuration phase.
14153dbbe3fbSAnurag S. Maskey 		 */
14163dbbe3fbSAnurag S. Maskey 		nlog(LOG_ERR, "start_dhcp: ipadm_%s_addr on %s returned: %s, "
14173dbbe3fbSAnurag S. Maskey 		    "retrying in %d sec",
14183dbbe3fbSAnurag S. Maskey 		    (type == DHCP_START ? "create" : "refresh"), name,
14193dbbe3fbSAnurag S. Maskey 		    ipadm_status2str(ipstatus), NWAMD_DHCP_RETRY_WAIT_TIME);
14203dbbe3fbSAnurag S. Maskey 		(void) sleep(NWAMD_DHCP_RETRY_WAIT_TIME);
14213dbbe3fbSAnurag S. Maskey 		goto retry;
14223dbbe3fbSAnurag S. Maskey 
14233dbbe3fbSAnurag S. Maskey 	} else if (ipstatus != IPADM_SUCCESS) {
1424f6da83d4SAnurag S. Maskey 		nlog(LOG_ERR, "start_dhcp: ipadm_%s_addr failed for %s: %s",
14253dbbe3fbSAnurag S. Maskey 		    (type == DHCP_START ? "create" : "refresh"), name,
14263dbbe3fbSAnurag S. Maskey 		    ipadm_status2str(ipstatus));
14276ba597c5SAnurag S. Maskey 	}
1428f6da83d4SAnurag S. Maskey 
1429f6da83d4SAnurag S. Maskey done:
1430f6da83d4SAnurag S. Maskey 	free(name);
1431f6da83d4SAnurag S. Maskey 	free(arg);
14326ba597c5SAnurag S. Maskey 	return (NULL);
14336ba597c5SAnurag S. Maskey }
14346ba597c5SAnurag S. Maskey 
1435f6da83d4SAnurag S. Maskey static void
nwamd_dhcp(const char * ifname,ipadm_addrobj_t ipaddr,dhcp_ipc_type_t cmd)1436f6da83d4SAnurag S. Maskey nwamd_dhcp(const char *ifname, ipadm_addrobj_t ipaddr, dhcp_ipc_type_t cmd)
14376ba597c5SAnurag S. Maskey {
14386ba597c5SAnurag S. Maskey 	struct nwamd_dhcp_thread_arg *arg;
14396ba597c5SAnurag S. Maskey 	pthread_attr_t attr;
14406ba597c5SAnurag S. Maskey 
1441f6da83d4SAnurag S. Maskey 	nlog(LOG_DEBUG, "nwamd_dhcp: starting DHCP %s thread for %s",
1442f6da83d4SAnurag S. Maskey 	    dhcp_ipc_type_to_string(cmd), ifname);
14436ba597c5SAnurag S. Maskey 
14446ba597c5SAnurag S. Maskey 	arg = malloc(sizeof (*arg));
14456ba597c5SAnurag S. Maskey 	if (arg == NULL) {
1446f6da83d4SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_dhcp: error allocating memory for "
1447f6da83d4SAnurag S. Maskey 		    "dhcp request");
14486ba597c5SAnurag S. Maskey 		return;
14496ba597c5SAnurag S. Maskey 	}
14506ba597c5SAnurag S. Maskey 
1451f6da83d4SAnurag S. Maskey 	arg->name = strdup(ifname);
1452f6da83d4SAnurag S. Maskey 	arg->type = cmd;
1453f6da83d4SAnurag S. Maskey 	arg->ipaddr = ipaddr;
14546ba597c5SAnurag S. Maskey 
14556ba597c5SAnurag S. Maskey 	(void) pthread_attr_init(&attr);
14566ba597c5SAnurag S. Maskey 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
14576ba597c5SAnurag S. Maskey 	if (pthread_create(NULL, &attr, start_dhcp_thread, arg) == -1) {
1458f6da83d4SAnurag S. Maskey 		nlog(LOG_ERR, "nwamd_dhcp: cannot start dhcp thread");
1459f6da83d4SAnurag S. Maskey 		free(arg->name);
14606ba597c5SAnurag S. Maskey 		free(arg);
14616ba597c5SAnurag S. Maskey 		(void) pthread_attr_destroy(&attr);
14626ba597c5SAnurag S. Maskey 		return;
14636ba597c5SAnurag S. Maskey 	}
14646ba597c5SAnurag S. Maskey 	(void) pthread_attr_destroy(&attr);
14656ba597c5SAnurag S. Maskey }
1466