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;
1506ba597c5SAnurag S. Maskey dhcp_ipc_request_t *request;
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
1626ba597c5SAnurag S. Maskey /* find code and category in dhcp_inittab(4) */
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;
3036ba597c5SAnurag 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;
309f6da83d4SAnurag 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;
3796ba597c5SAnurag 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
5576ba597c5SAnurag S. Maskey static boolean_t
stateless_running(const nwamd_ncu_t * ncu)5586ba597c5SAnurag 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));
5706ba597c5SAnurag 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);
584f6da83d4SAnurag S. Maskey }
585f6da83d4SAnurag S. Maskey
586f6da83d4SAnurag 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.
589f6da83d4SAnurag S. Maskey */
590f6da83d4SAnurag 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)
593f6da83d4SAnurag 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));
6026ba597c5SAnurag S. Maskey return (B_FALSE);
6036ba597c5SAnurag S. Maskey }
6046ba597c5SAnurag 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);
6196ba597c5SAnurag 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 */
636f6da83d4SAnurag 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)
639f6da83d4SAnurag 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)
647f6da83d4SAnurag S. Maskey return (B_FALSE);
648f6da83d4SAnurag 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));
654f6da83d4SAnurag S. Maskey return (B_FALSE);
655f6da83d4SAnurag S. Maskey }
656f6da83d4SAnurag 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);
681f6da83d4SAnurag S. Maskey }
682f6da83d4SAnurag 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)691*48fff0e3SRenee Danson Sommerfeld add_ip_address(const char *ifname, const struct nwamd_if_address *nifa,
692*48fff0e3SRenee Danson Sommerfeld boolean_t *do_inform)
693f6da83d4SAnurag S. Maskey {
694f6da83d4SAnurag S. Maskey ipadm_status_t ipstatus;
695f6da83d4SAnurag S. Maskey ipadm_addr_info_t *addrinfo = NULL;
696f6da83d4SAnurag S. Maskey uint64_t flags;
697f6da83d4SAnurag 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 }
734f6da83d4SAnurag 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 }
759*48fff0e3SRenee Danson Sommerfeld /*
760*48fff0e3SRenee Danson Sommerfeld * Do DHCP_INFORM using async ipadm_refresh_addr().
761*48fff0e3SRenee Danson Sommerfeld * Only need to do this once per interface, and we
762*48fff0e3SRenee Danson Sommerfeld * do *not* need to do it if we are also getting a
763*48fff0e3SRenee Danson Sommerfeld * dhcp lease; so we only send the INFORM if the
764*48fff0e3SRenee Danson Sommerfeld * passed-in flag says to, and we clear the flag
765*48fff0e3SRenee Danson Sommerfeld * once we've initiated the INFORM transaction.
766*48fff0e3SRenee Danson Sommerfeld */
767*48fff0e3SRenee Danson Sommerfeld if (*do_inform) {
768f6da83d4SAnurag S. Maskey nwamd_dhcp(ifname, nifa->ipaddr, DHCP_INFORM);
769*48fff0e3SRenee Danson Sommerfeld *do_inform = B_FALSE;
770*48fff0e3SRenee Danson Sommerfeld }
771f6da83d4SAnurag S. Maskey }
772f6da83d4SAnurag S. Maskey }
773f6da83d4SAnurag S. Maskey
774f6da83d4SAnurag S. Maskey return (B_TRUE);
775f6da83d4SAnurag S. Maskey }
776f6da83d4SAnurag S. Maskey
777f6da83d4SAnurag S. Maskey /*
778f6da83d4SAnurag S. Maskey * Adds addresses for the given NCU.
779f6da83d4SAnurag S. Maskey */
7806ba597c5SAnurag S. Maskey void
nwamd_configure_interface_addresses(nwamd_ncu_t * ncu)7816ba597c5SAnurag 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;
784*48fff0e3SRenee Danson Sommerfeld boolean_t do_inform;
785*48fff0e3SRenee Danson Sommerfeld
786*48fff0e3SRenee Danson Sommerfeld /* only need an inform if we're not also getting a dhcp lease */
787*48fff0e3SRenee Danson Sommerfeld do_inform = !ncu->ncu_if.nwamd_if_dhcp_requested;
7886ba597c5SAnurag S. Maskey
7896ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_configure_interface_addresses(%s)",
7906ba597c5SAnurag S. Maskey ncu->ncu_name);
7916ba597c5SAnurag 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
796*48fff0e3SRenee Danson Sommerfeld nifap->configured = add_ip_address(ncu->ncu_name, nifap,
797*48fff0e3SRenee 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];
865f6da83d4SAnurag S. Maskey boolean_t static_addr, 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
8826ba597c5SAnurag S. Maskey nlog(LOG_DEBUG,
8836ba597c5SAnurag S. Maskey "nwamd_ncu_handle_if_state_event: addr %s %s",
884f6da83d4SAnurag S. Maskey nwamd_sockaddr2str((struct sockaddr *)addr, addrstr,
885f6da83d4SAnurag S. Maskey sizeof (addrstr)), addr_added ? "added" : "removed");
8866ba597c5SAnurag S. Maskey
887f6da83d4SAnurag S. Maskey /*
888f6da83d4SAnurag S. Maskey * Need to get flags for this interface. Get the addrinfo for
889f6da83d4SAnurag S. Maskey * the address that generated this IF_STATE event.
890f6da83d4SAnurag S. Maskey */
891f6da83d4SAnurag S. Maskey if (addr_added) {
892f6da83d4SAnurag S. Maskey /*
893f6da83d4SAnurag S. Maskey * Address was added. Find the addrinfo for this
894f6da83d4SAnurag S. Maskey * address and the nwamd_if_address corresponding to
895f6da83d4SAnurag S. Maskey * this address.
896f6da83d4SAnurag S. Maskey */
897f6da83d4SAnurag S. Maskey if (!addrinfo_for_addr(addr, ncu->ncu_name, &ai)) {
8986ba597c5SAnurag S. Maskey nlog(LOG_ERR,
8996ba597c5SAnurag S. Maskey "nwamd_ncu_handle_if_state_event: "
900f6da83d4SAnurag S. Maskey "addrinfo doesn't exist for %s", addrstr);
9016ba597c5SAnurag S. Maskey nwamd_event_do_not_send(event);
902f6da83d4SAnurag S. Maskey goto valid_done;
9036ba597c5SAnurag S. Maskey }
904f6da83d4SAnurag S. Maskey addrinfo = ai;
905f6da83d4SAnurag S. Maskey flags = addrinfo->ia_ifa.ifa_flags;
90664639aafSDarren Reed (void) memcpy(&ai_addr, addrinfo->ia_ifa.ifa_addr,
90764639aafSDarren Reed sizeof (ai_addr));
90864639aafSDarren Reed aip = &ai_addr;
909f6da83d4SAnurag S. Maskey
910f6da83d4SAnurag S. Maskey if (addrinfo->ia_atype == IPADM_ADDR_IPV6_ADDRCONF ||
911f6da83d4SAnurag S. Maskey addrinfo->ia_atype == IPADM_ADDR_DHCP)
912f6da83d4SAnurag S. Maskey nifa = find_nonstatic_address(ncu, family);
913f6da83d4SAnurag S. Maskey else if (addrinfo->ia_atype == IPADM_ADDR_STATIC)
914f6da83d4SAnurag S. Maskey nifa = find_static_address(addr, ncu);
915f6da83d4SAnurag S. Maskey
916f6da83d4SAnurag S. Maskey /*
917f6da83d4SAnurag S. Maskey * If nwamd_if_address is not found, then this address
918f6da83d4SAnurag S. Maskey * isn't one that nwamd created. Remove it.
919f6da83d4SAnurag S. Maskey */
920f6da83d4SAnurag S. Maskey if (nifa == NULL) {
921f6da83d4SAnurag S. Maskey nlog(LOG_ERR,
922f6da83d4SAnurag S. Maskey "nwamd_ncu_handle_if_state_event: "
923f6da83d4SAnurag S. Maskey "address %s not managed by nwam added, "
924f6da83d4SAnurag S. Maskey "removing it", addrstr);
925f6da83d4SAnurag S. Maskey nwamd_down_interface(addrinfo->ia_aobjname,
926f6da83d4SAnurag S. Maskey addrinfo->ia_atype, ncu->ncu_name);
927f6da83d4SAnurag S. Maskey nwamd_event_do_not_send(event);
928f6da83d4SAnurag S. Maskey goto valid_done;
929f6da83d4SAnurag S. Maskey }
930f6da83d4SAnurag S. Maskey
931f6da83d4SAnurag S. Maskey /* check flags to determine how intf is configured */
932f6da83d4SAnurag S. Maskey stateless_running = (family == AF_INET6) &&
933f6da83d4SAnurag S. Maskey ((flags & STATELESS_RUNNING) == STATELESS_RUNNING);
934f6da83d4SAnurag S. Maskey v4dhcp_running = (family == AF_INET) &&
935f6da83d4SAnurag S. Maskey ((flags & DHCP_RUNNING) == DHCP_RUNNING);
936f6da83d4SAnurag S. Maskey v6dhcp_running = (family == AF_INET6) &&
937f6da83d4SAnurag S. Maskey ((flags & DHCP_RUNNING) == DHCP_RUNNING);
938f6da83d4SAnurag S. Maskey static_addr = (addrinfo->ia_atype == IPADM_ADDR_STATIC);
939f6da83d4SAnurag S. Maskey
940f6da83d4SAnurag S. Maskey /* copy the configured address into nwamd_if_address */
941f6da83d4SAnurag S. Maskey if (stateless_running) {
942f6da83d4SAnurag S. Maskey (void) memcpy(&nifa->conf_stateless_addr,
943f6da83d4SAnurag S. Maskey addrinfo->ia_ifa.ifa_addr,
944f6da83d4SAnurag S. Maskey sizeof (struct sockaddr_storage));
945f6da83d4SAnurag S. Maskey } else {
946f6da83d4SAnurag S. Maskey (void) memcpy(&nifa->conf_addr,
947f6da83d4SAnurag S. Maskey addrinfo->ia_ifa.ifa_addr,
948f6da83d4SAnurag S. Maskey sizeof (struct sockaddr_storage));
949f6da83d4SAnurag S. Maskey }
950f6da83d4SAnurag S. Maskey
9516ba597c5SAnurag S. Maskey } else {
9526ba597c5SAnurag S. Maskey /*
953f6da83d4SAnurag S. Maskey * Address was removed. Find the nwamd_if_address
954f6da83d4SAnurag S. Maskey * that configured this address.
9556ba597c5SAnurag S. Maskey */
956f6da83d4SAnurag S. Maskey nifa = find_configured_address(addr, ncu);
957f6da83d4SAnurag S. Maskey if (nifa == NULL) {
9586ba597c5SAnurag S. Maskey nlog(LOG_ERR,
9596ba597c5SAnurag S. Maskey "nwamd_ncu_handle_if_state_event: "
960f6da83d4SAnurag S. Maskey "address %s not managed by nwam removed, "
961f6da83d4SAnurag S. Maskey "nothing to do", addrstr);
9626ba597c5SAnurag S. Maskey nwamd_event_do_not_send(event);
963f6da83d4SAnurag S. Maskey goto valid_done;
9646ba597c5SAnurag S. Maskey }
9656ba597c5SAnurag S. Maskey
966f6da83d4SAnurag S. Maskey if (addrinfo_for_ipaddr(nifa->ipaddr, ncu->ncu_name,
967f6da83d4SAnurag S. Maskey &ai)) {
968f6da83d4SAnurag S. Maskey ipadm_addr_info_t *a;
969f6da83d4SAnurag S. Maskey for (a = ai; a != NULL; a = IA_NEXT(a)) {
97064639aafSDarren Reed struct sockaddr_storage stor;
97164639aafSDarren Reed
97264639aafSDarren Reed (void) memcpy(&stor, a->ia_ifa.ifa_addr,
97364639aafSDarren Reed sizeof (stor));
9746ba597c5SAnurag S. Maskey /*
975f6da83d4SAnurag S. Maskey * Since multiple addrinfo can have
976f6da83d4SAnurag S. Maskey * the same ipaddr, find the one for
977f6da83d4SAnurag S. Maskey * the address that generated this
978f6da83d4SAnurag S. Maskey * state event.
9796ba597c5SAnurag S. Maskey */
98064639aafSDarren Reed if (sockaddrcmp(addr, &stor)) {
981f6da83d4SAnurag S. Maskey flags = a->ia_ifa.ifa_flags;
98264639aafSDarren Reed (void) memcpy(&ai_addr,
98364639aafSDarren Reed a->ia_ifa.ifa_addr,
98464639aafSDarren Reed sizeof (ai_addr));
98564639aafSDarren Reed aip = &ai_addr;
986f6da83d4SAnurag S. Maskey addrinfo = a;
9876ba597c5SAnurag S. Maskey }
9886ba597c5SAnurag S. Maskey /*
989f6da83d4SAnurag S. Maskey * Stateful and stateless IPv6
990f6da83d4SAnurag S. Maskey * addrinfo have the same aobjname.
991f6da83d4SAnurag S. Maskey * Use the flags to determine which
992f6da83d4SAnurag S. Maskey * address is present in the system.
9936ba597c5SAnurag S. Maskey */
994f6da83d4SAnurag S. Maskey if (family == AF_INET6) {
995f6da83d4SAnurag S. Maskey stateless_ai_found =
996f6da83d4SAnurag S. Maskey (a->ia_ifa.ifa_flags &
997f6da83d4SAnurag S. Maskey STATELESS_RUNNING);
998f6da83d4SAnurag S. Maskey stateful_ai_found =
999f6da83d4SAnurag S. Maskey (a->ia_ifa.ifa_flags &
1000f6da83d4SAnurag S. Maskey DHCP_RUNNING);
1001f6da83d4SAnurag S. Maskey }
1002f6da83d4SAnurag S. Maskey }
10036ba597c5SAnurag S. Maskey }
10046ba597c5SAnurag S. Maskey }
10056ba597c5SAnurag S. Maskey
1006f6da83d4SAnurag S. Maskey /* Set the flags in the event for listeners */
1007f6da83d4SAnurag S. Maskey evm->nwe_data.nwe_if_state.nwe_flags = flags;
1008f6da83d4SAnurag S. Maskey
1009f6da83d4SAnurag S. Maskey if (family == AF_INET && !addr_added) {
10106ba597c5SAnurag S. Maskey /*
10116ba597c5SAnurag S. Maskey * Check for failure due to CR 6745448: if we get a
10126ba597c5SAnurag S. Maskey * report that an address has been deleted, then check
10136ba597c5SAnurag S. Maskey * for interface up, datalink down, and actual address
10146ba597c5SAnurag S. Maskey * non-zero. If that combination is seen, then this is
10156ba597c5SAnurag S. Maskey * a DHCP cached lease, and we need to remove it from
10166ba597c5SAnurag S. Maskey * the system, or it'll louse up the kernel routes
10176ba597c5SAnurag S. Maskey * (which aren't smart enough to avoid dead
10186ba597c5SAnurag S. Maskey * interfaces).
10196ba597c5SAnurag S. Maskey */
10206ba597c5SAnurag S. Maskey if (((struct sockaddr_in *)addr)->sin_addr.s_addr
102164639aafSDarren Reed == INADDR_ANY && aip != 0) {
1022f6da83d4SAnurag S. Maskey struct sockaddr_in *a;
1023f6da83d4SAnurag S. Maskey char astr[INET6_ADDRSTRLEN];
102464639aafSDarren Reed a = (struct sockaddr_in *)aip;
10256ba597c5SAnurag S. Maskey
10266ba597c5SAnurag S. Maskey if ((flags & IFF_UP) &&
10276ba597c5SAnurag S. Maskey !(flags & IFF_RUNNING) &&
1028f6da83d4SAnurag S. Maskey a->sin_addr.s_addr != INADDR_ANY) {
1029f6da83d4SAnurag S. Maskey nlog(LOG_DEBUG,
1030f6da83d4SAnurag S. Maskey "nwamd_ncu_handle_if_state_event: "
1031f6da83d4SAnurag S. Maskey "bug workaround: clear out addr "
1032f6da83d4SAnurag S. Maskey "%s on %s", nwamd_sockaddr2str
1033f6da83d4SAnurag S. Maskey ((struct sockaddr *)a, astr,
1034f6da83d4SAnurag S. Maskey sizeof (astr)),
1035f6da83d4SAnurag S. Maskey ncu->ncu_name);
1036f6da83d4SAnurag S. Maskey nwamd_down_interface(
1037f6da83d4SAnurag S. Maskey addrinfo->ia_aobjname,
1038f6da83d4SAnurag S. Maskey IPADM_ADDR_DHCP, ncu->ncu_name);
10396ba597c5SAnurag S. Maskey }
1040f6da83d4SAnurag S. Maskey goto valid_done;
10416ba597c5SAnurag S. Maskey }
10426ba597c5SAnurag S. Maskey }
10436ba597c5SAnurag S. Maskey
10446ba597c5SAnurag S. Maskey /*
1045f6da83d4SAnurag S. Maskey * If we received an RTM_NEWADDR and the IFF_UP flags has not
1046f6da83d4SAnurag S. Maskey * been set, ignore this IF_STATE event. Once the IFF_UP flag
1047f6da83d4SAnurag S. Maskey * is set, we'll get another RTM_NEWADDR message.
1048f6da83d4SAnurag S. Maskey */
1049f6da83d4SAnurag S. Maskey if (addr_added & !(flags & IFF_UP)) {
1050f6da83d4SAnurag S. Maskey nlog(LOG_INFO, "nwamd_ncu_handle_if_state_event: "
1051f6da83d4SAnurag S. Maskey "address %s added on %s without IFF_UP flag (%x), "
1052f6da83d4SAnurag S. Maskey "ignoring IF_STATE event",
1053f6da83d4SAnurag S. Maskey addrstr, ncu->ncu_name, flags);
1054f6da83d4SAnurag S. Maskey nwamd_event_do_not_send(event);
1055f6da83d4SAnurag S. Maskey goto valid_done;
1056f6da83d4SAnurag S. Maskey }
1057f6da83d4SAnurag S. Maskey
1058f6da83d4SAnurag S. Maskey /*
1059f6da83d4SAnurag S. Maskey * Has the address really been removed? Sometimes spurious
10606ba597c5SAnurag S. Maskey * RTM_DELADDRs are generated, so we need to ensure that
10616ba597c5SAnurag S. Maskey * the address is really gone. If IFF_DUPLICATE is set,
10626ba597c5SAnurag S. Maskey * we're getting the RTM_DELADDR due to DAD, so don't test
10636ba597c5SAnurag S. Maskey * in that case.
10646ba597c5SAnurag S. Maskey */
1065f6da83d4SAnurag S. Maskey if (!addr_added && !(flags & IFF_DUPLICATE)) {
106664639aafSDarren Reed if (aip != 0 && sockaddrcmp(addr, aip)) {
1067f6da83d4SAnurag S. Maskey nlog(LOG_INFO,
10686ba597c5SAnurag S. Maskey "nwamd_ncu_handle_if_state_event: "
10696ba597c5SAnurag S. Maskey "address %s is not really gone from %s, "
10706ba597c5SAnurag S. Maskey "ignoring IF_STATE event",
1071f6da83d4SAnurag S. Maskey addrstr, ncu->ncu_name);
10726ba597c5SAnurag S. Maskey nwamd_event_do_not_send(event);
1073f6da83d4SAnurag S. Maskey goto valid_done;
10746ba597c5SAnurag S. Maskey }
10756ba597c5SAnurag S. Maskey }
10766ba597c5SAnurag S. Maskey
1077f6da83d4SAnurag S. Maskey if (addr_added) {
10786ba597c5SAnurag S. Maskey /*
10796ba597c5SAnurag S. Maskey * Address has been added.
10806ba597c5SAnurag S. Maskey *
10816ba597c5SAnurag S. Maskey * We need to make sure that we really want to keep
10826ba597c5SAnurag S. Maskey * this address. There is a race where we requested an
10836ba597c5SAnurag S. Maskey * address but by the time we got here we don't really
10846ba597c5SAnurag S. Maskey * want it and need to remove it.
10856ba597c5SAnurag S. Maskey *
10866ba597c5SAnurag S. Maskey * Once we decide we want the address adjust the ncu
10876ba597c5SAnurag S. Maskey * state accordingly. For example if this address is
10886ba597c5SAnurag S. Maskey * enough move online.
10896ba597c5SAnurag S. Maskey */
1090f6da83d4SAnurag S. Maskey if (u_if->nwamd_if_dhcp_requested && v4dhcp_running) {
10916ba597c5SAnurag S. Maskey u_if->nwamd_if_dhcp_configured = B_TRUE;
10926ba597c5SAnurag S. Maskey } else if (u_if->nwamd_if_stateful_requested &&
10936ba597c5SAnurag S. Maskey v6dhcp_running) {
10946ba597c5SAnurag S. Maskey u_if->nwamd_if_stateful_configured = B_TRUE;
10956ba597c5SAnurag S. Maskey } else if (u_if->nwamd_if_stateless_requested &&
10966ba597c5SAnurag S. Maskey stateless_running) {
10976ba597c5SAnurag S. Maskey u_if->nwamd_if_stateless_configured = B_TRUE;
1098f6da83d4SAnurag S. Maskey } else if (!static_addr) {
10996ba597c5SAnurag S. Maskey /*
11006ba597c5SAnurag S. Maskey * This is something we didn't expect. Remove
1101f6da83d4SAnurag S. Maskey * the address.
11026ba597c5SAnurag S. Maskey */
1103f6da83d4SAnurag S. Maskey nwamd_down_interface(addrinfo->ia_aobjname,
1104f6da83d4SAnurag S. Maskey addrinfo->ia_atype, ncu->ncu_name);
1105f6da83d4SAnurag S. Maskey nifa->configured = B_FALSE;
1106f6da83d4SAnurag S. Maskey goto valid_done;
11076ba597c5SAnurag S. Maskey }
11086ba597c5SAnurag S. Maskey
11096ba597c5SAnurag S. Maskey /*
11106ba597c5SAnurag S. Maskey * The address looks valid so mark configured and
11116ba597c5SAnurag S. Maskey * move online if we either have a v4 address if
11126ba597c5SAnurag S. Maskey * v4 is configured or a v6 address if only v6 is
11136ba597c5SAnurag S. Maskey * configured.
11146ba597c5SAnurag S. Maskey */
1115f6da83d4SAnurag S. Maskey nifa->configured = B_TRUE;
11166ba597c5SAnurag S. Maskey if (state != NWAM_STATE_ONLINE)
11176ba597c5SAnurag S. Maskey interface_ncu_up(ncu);
11186ba597c5SAnurag S. Maskey
11196ba597c5SAnurag S. Maskey /*
11206ba597c5SAnurag S. Maskey * Refresh network/location since we may also have other
11216ba597c5SAnurag S. Maskey * DHCP information. We might have to restore it first
11226ba597c5SAnurag S. Maskey * in case it is in maintenance.
11236ba597c5SAnurag S. Maskey */
11246ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_handle_if_state_event: "
11256ba597c5SAnurag S. Maskey "refreshing %s as we may have other "
11266ba597c5SAnurag S. Maskey "DHCP information", NET_LOC_FMRI);
11276ba597c5SAnurag S. Maskey (void) smf_restore_instance(NET_LOC_FMRI);
11286ba597c5SAnurag S. Maskey if (smf_refresh_instance(NET_LOC_FMRI) != 0) {
11296ba597c5SAnurag S. Maskey nlog(LOG_ERR,
11306ba597c5SAnurag S. Maskey "nwamd_ncu_handle_if_state_"
11316ba597c5SAnurag S. Maskey "event: refresh of %s "
11326ba597c5SAnurag S. Maskey "failed", NET_LOC_FMRI);
11336ba597c5SAnurag S. Maskey }
1134f6da83d4SAnurag S. Maskey
11356ba597c5SAnurag S. Maskey } else if (state == NWAM_STATE_ONLINE ||
11366ba597c5SAnurag S. Maskey state == NWAM_STATE_OFFLINE_TO_ONLINE) {
11376ba597c5SAnurag S. Maskey /*
11386ba597c5SAnurag S. Maskey * Address has been removed. Only pay attention to
11396ba597c5SAnurag S. Maskey * disappearing addresses if we are online or coming
11406ba597c5SAnurag S. Maskey * online.
11416ba597c5SAnurag S. Maskey *
11426ba597c5SAnurag S. Maskey * Undo whatever configuration is necessary. Note
11436ba597c5SAnurag S. Maskey * that this may or may not cause the NCU to go down.
11446ba597c5SAnurag S. Maskey * We can get RTM_DELADDRs for duplicate addresses
11456ba597c5SAnurag S. Maskey * so deal with this seperately.
11466ba597c5SAnurag S. Maskey */
1147f6da83d4SAnurag S. Maskey nifa->configured = B_FALSE;
1148f6da83d4SAnurag S. Maskey
1149f6da83d4SAnurag S. Maskey if (!static_addr && family == AF_INET) {
11506ba597c5SAnurag S. Maskey u_if->nwamd_if_dhcp_configured = B_FALSE;
1151f6da83d4SAnurag S. Maskey } else if (!static_addr && family == AF_INET6) {
11526ba597c5SAnurag S. Maskey /*
1153f6da83d4SAnurag S. Maskey * The address is already gone. When looking
1154f6da83d4SAnurag S. Maskey * for the addrinfo (using aobjname in
1155f6da83d4SAnurag S. Maskey * ipaddr), we found addrinfo for either one
1156f6da83d4SAnurag S. Maskey * or both stateless and stateful. Using the
1157f6da83d4SAnurag S. Maskey * flags we determined whether each was
1158f6da83d4SAnurag S. Maskey * configured or not. Update the flags here
1159f6da83d4SAnurag S. Maskey * accordingly.
11606ba597c5SAnurag S. Maskey */
1161f6da83d4SAnurag S. Maskey u_if->nwamd_if_stateful_configured =
1162f6da83d4SAnurag S. Maskey stateless_ai_found;
1163f6da83d4SAnurag S. Maskey u_if->nwamd_if_stateless_configured =
1164f6da83d4SAnurag S. Maskey stateful_ai_found;
11656ba597c5SAnurag S. Maskey }
11666ba597c5SAnurag S. Maskey
11676ba597c5SAnurag S. Maskey if (flags & IFF_DUPLICATE) {
11686ba597c5SAnurag S. Maskey nlog(LOG_INFO,
11696ba597c5SAnurag S. Maskey "nwamd_ncu_handle_if_state_event: "
11706ba597c5SAnurag S. Maskey "duplicate address detected on %s",
11716ba597c5SAnurag S. Maskey ncu->ncu_name);
11726ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
11736ba597c5SAnurag S. Maskey event->event_object,
11746ba597c5SAnurag S. Maskey NWAM_STATE_MAINTENANCE,
11756ba597c5SAnurag S. Maskey NWAM_AUX_STATE_IF_DUPLICATE_ADDR);
11766ba597c5SAnurag S. Maskey } else {
11776ba597c5SAnurag S. Maskey interface_ncu_down(ncu);
11786ba597c5SAnurag S. Maskey }
11796ba597c5SAnurag S. Maskey }
1180f6da83d4SAnurag S. Maskey valid_done:
1181f6da83d4SAnurag S. Maskey ipadm_free_addr_info(ai);
11826ba597c5SAnurag S. Maskey }
11836ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
11846ba597c5SAnurag S. Maskey }
11856ba597c5SAnurag S. Maskey
11866ba597c5SAnurag S. Maskey void
nwamd_ncu_handle_if_action_event(nwamd_event_t event)11876ba597c5SAnurag S. Maskey nwamd_ncu_handle_if_action_event(nwamd_event_t event)
11886ba597c5SAnurag S. Maskey {
11896ba597c5SAnurag S. Maskey nwamd_object_t ncu_obj;
11906ba597c5SAnurag S. Maskey
11916ba597c5SAnurag S. Maskey nlog(LOG_DEBUG, "if action event %s",
11926ba597c5SAnurag S. Maskey event->event_object[0] == '\0' ? "n/a" : event->event_object);
11936ba597c5SAnurag S. Maskey
11946ba597c5SAnurag S. Maskey ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, event->event_object);
11956ba597c5SAnurag S. Maskey if (ncu_obj == NULL) {
11966ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_ncu_handle_if_action_event: no object");
11976ba597c5SAnurag S. Maskey nwamd_event_do_not_send(event);
11986ba597c5SAnurag S. Maskey return;
11996ba597c5SAnurag S. Maskey }
12006ba597c5SAnurag S. Maskey nwamd_object_release(ncu_obj);
12016ba597c5SAnurag S. Maskey }
12026ba597c5SAnurag S. Maskey
12036ba597c5SAnurag S. Maskey /*
1204f6da83d4SAnurag S. Maskey * Remove the address in the given aobjname. IPADM_OPT_RELEASE is specified
1205f6da83d4SAnurag S. Maskey * for a DHCP address and specifies that the DHCP lease should also be released.
1206f6da83d4SAnurag S. Maskey * ifname is only used for nlog().
12076ba597c5SAnurag S. Maskey */
12086ba597c5SAnurag S. Maskey static void
nwamd_down_interface(const char * aobjname,ipadm_addr_type_t atype,const char * ifname)1209f6da83d4SAnurag S. Maskey nwamd_down_interface(const char *aobjname, ipadm_addr_type_t atype,
1210f6da83d4SAnurag S. Maskey const char *ifname)
12116ba597c5SAnurag S. Maskey {
1212f6da83d4SAnurag S. Maskey ipadm_status_t ipstatus;
1213f6da83d4SAnurag S. Maskey uint32_t rflags = (atype == IPADM_ADDR_DHCP ? IPADM_OPT_RELEASE : 0);
12146ba597c5SAnurag S. Maskey
1215f6da83d4SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_down_interface: %s [aobjname = %s]",
1216f6da83d4SAnurag S. Maskey ifname, aobjname);
1217f6da83d4SAnurag S. Maskey if ((ipstatus = ipadm_delete_addr(ipadm_handle, aobjname,
1218f6da83d4SAnurag S. Maskey IPADM_OPT_ACTIVE | rflags)) != IPADM_SUCCESS) {
1219f6da83d4SAnurag S. Maskey nlog(LOG_ERR, "nwamd_down_interface: "
1220f6da83d4SAnurag S. Maskey "ipadm_delete_addr failed on %s: %s",
1221f6da83d4SAnurag S. Maskey ifname, ipadm_status2str(ipstatus));
12226ba597c5SAnurag S. Maskey }
12236ba597c5SAnurag S. Maskey }
12246ba597c5SAnurag S. Maskey
12256ba597c5SAnurag S. Maskey static void
unconfigure_addresses(nwamd_ncu_t * ncu,sa_family_t af)1226f6da83d4SAnurag S. Maskey unconfigure_addresses(nwamd_ncu_t *ncu, sa_family_t af)
12276ba597c5SAnurag S. Maskey {
1228f6da83d4SAnurag S. Maskey struct nwamd_if_address *nifap, *nifa = ncu->ncu_if.nwamd_if_list;
12296ba597c5SAnurag S. Maskey
1230f6da83d4SAnurag S. Maskey for (nifap = nifa; nifap != NULL; nifap = nifap->next)
1231f6da83d4SAnurag S. Maskey if (af == AF_UNSPEC || nifap->family == af)
1232f6da83d4SAnurag S. Maskey nifap->configured = B_FALSE;
12336ba597c5SAnurag S. Maskey }
12346ba597c5SAnurag S. Maskey
1235f6da83d4SAnurag S. Maskey static void
dhcp_release(const char * ifname)1236f6da83d4SAnurag S. Maskey dhcp_release(const char *ifname)
1237f6da83d4SAnurag S. Maskey {
1238f6da83d4SAnurag S. Maskey ipadm_addr_info_t *ainfo, *ainfop;
12396ba597c5SAnurag S. Maskey
1240f6da83d4SAnurag S. Maskey if (ipadm_addr_info(ipadm_handle, ifname, &ainfo, 0, 0)
1241f6da83d4SAnurag S. Maskey != IPADM_SUCCESS)
12426ba597c5SAnurag S. Maskey return;
12436ba597c5SAnurag S. Maskey
1244f6da83d4SAnurag S. Maskey for (ainfop = ainfo; ainfop != NULL; ainfop = IA_NEXT(ainfop)) {
1245f6da83d4SAnurag S. Maskey if (ainfop->ia_atype == IPADM_ADDR_DHCP)
1246f6da83d4SAnurag S. Maskey nwamd_down_interface(ainfop->ia_aobjname,
1247f6da83d4SAnurag S. Maskey ainfop->ia_atype, ifname);
1248f6da83d4SAnurag S. Maskey }
1249f6da83d4SAnurag S. Maskey ipadm_free_addr_info(ainfo);
1250f6da83d4SAnurag S. Maskey }
1251f6da83d4SAnurag S. Maskey
1252f6da83d4SAnurag S. Maskey static void
nwamd_plumb_unplumb_interface(nwamd_ncu_t * ncu,sa_family_t af,boolean_t plumb)1253f6da83d4SAnurag S. Maskey nwamd_plumb_unplumb_interface(nwamd_ncu_t *ncu, sa_family_t af, boolean_t plumb)
1254f6da83d4SAnurag S. Maskey {
1255f6da83d4SAnurag S. Maskey char *ifname = ncu->ncu_name;
1256f6da83d4SAnurag S. Maskey nwamd_if_t *u_if = &ncu->ncu_if;
1257f6da83d4SAnurag S. Maskey ipadm_status_t ipstatus;
1258f6da83d4SAnurag S. Maskey
1259f6da83d4SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_plumb_unplumb_interface: %s %s %s",
1260f6da83d4SAnurag S. Maskey (plumb ? "plumb" : "unplumb"), (af == AF_INET ? "IPv4" : "IPv6"),
1261f6da83d4SAnurag S. Maskey ifname);
1262f6da83d4SAnurag S. Maskey
1263f6da83d4SAnurag S. Maskey if (plumb) {
1264f6da83d4SAnurag S. Maskey ipstatus = ipadm_create_if(ipadm_handle, ifname, af,
1265f6da83d4SAnurag S. Maskey IPADM_OPT_ACTIVE);
1266f6da83d4SAnurag S. Maskey } else {
1267f6da83d4SAnurag S. Maskey /* release DHCP address, if any */
1268f6da83d4SAnurag S. Maskey if (af == AF_INET)
1269f6da83d4SAnurag S. Maskey dhcp_release(ifname);
1270f6da83d4SAnurag S. Maskey ipstatus = ipadm_delete_if(ipadm_handle, ifname, af,
1271f6da83d4SAnurag S. Maskey IPADM_OPT_ACTIVE);
1272f6da83d4SAnurag S. Maskey }
1273f6da83d4SAnurag S. Maskey
1274f6da83d4SAnurag S. Maskey if (ipstatus != IPADM_SUCCESS) {
1275f6da83d4SAnurag S. Maskey if ((plumb && ipstatus != IPADM_IF_EXISTS) ||
1276f6da83d4SAnurag S. Maskey (!plumb && ipstatus != IPADM_ENXIO)) {
12776ba597c5SAnurag S. Maskey nlog(LOG_ERR, "nwamd_plumb_unplumb_interface: "
12786ba597c5SAnurag S. Maskey "%s %s failed for %s: %s",
1279f6da83d4SAnurag S. Maskey (plumb ? "plumb" : "unplumb"),
1280f6da83d4SAnurag S. Maskey (af == AF_INET ? "IPv4" : "IPv6"),
1281f6da83d4SAnurag S. Maskey ifname, ipadm_status2str(ipstatus));
12826ba597c5SAnurag S. Maskey }
12836ba597c5SAnurag S. Maskey }
12846ba597c5SAnurag S. Maskey
1285f6da83d4SAnurag S. Maskey /* Unset flags */
12866ba597c5SAnurag S. Maskey if (!plumb) {
1287f6da83d4SAnurag S. Maskey unconfigure_addresses(ncu, af);
12886ba597c5SAnurag S. Maskey switch (af) {
12896ba597c5SAnurag S. Maskey case AF_INET:
12906ba597c5SAnurag S. Maskey u_if->nwamd_if_dhcp_configured = B_FALSE;
12916ba597c5SAnurag S. Maskey break;
12926ba597c5SAnurag S. Maskey case AF_INET6:
12936ba597c5SAnurag S. Maskey u_if->nwamd_if_stateful_configured = B_FALSE;
12946ba597c5SAnurag S. Maskey u_if->nwamd_if_stateless_configured = B_FALSE;
12956ba597c5SAnurag S. Maskey break;
12966ba597c5SAnurag S. Maskey }
12976ba597c5SAnurag S. Maskey }
12986ba597c5SAnurag S. Maskey }
12996ba597c5SAnurag S. Maskey
13006ba597c5SAnurag S. Maskey void
nwamd_plumb_interface(nwamd_ncu_t * ncu,sa_family_t af)1301f6da83d4SAnurag S. Maskey nwamd_plumb_interface(nwamd_ncu_t *ncu, sa_family_t af)
13026ba597c5SAnurag S. Maskey {
130338f140aaSMichael Hunter /*
130438f140aaSMichael Hunter * We get all posssible privs by calling nwamd_deescalate(). During
130538f140aaSMichael Hunter * startup opening /dev/dld (data link management) needs all privs
130638f140aaSMichael Hunter * because we don't have access to /etc/security/device_policy yet.
130738f140aaSMichael Hunter */
130838f140aaSMichael Hunter nwamd_escalate();
1309f6da83d4SAnurag S. Maskey nwamd_plumb_unplumb_interface(ncu, af, B_TRUE);
131038f140aaSMichael Hunter nwamd_deescalate();
13116ba597c5SAnurag S. Maskey }
13126ba597c5SAnurag S. Maskey
13136ba597c5SAnurag S. Maskey void
nwamd_unplumb_interface(nwamd_ncu_t * ncu,sa_family_t af)1314f6da83d4SAnurag S. Maskey nwamd_unplumb_interface(nwamd_ncu_t *ncu, sa_family_t af)
13156ba597c5SAnurag S. Maskey {
1316f6da83d4SAnurag S. Maskey nwamd_plumb_unplumb_interface(ncu, af, B_FALSE);
13176ba597c5SAnurag S. Maskey }
13186ba597c5SAnurag S. Maskey
13196ba597c5SAnurag S. Maskey static void *
start_dhcp_thread(void * arg)13206ba597c5SAnurag S. Maskey start_dhcp_thread(void *arg)
13216ba597c5SAnurag S. Maskey {
1322f6da83d4SAnurag S. Maskey struct nwamd_dhcp_thread_arg *thread_arg = arg;
1323f6da83d4SAnurag S. Maskey nwamd_object_t ncu_obj;
13246ba597c5SAnurag S. Maskey dhcp_ipc_type_t type;
13256ba597c5SAnurag S. Maskey char *name;
1326f6da83d4SAnurag S. Maskey ipadm_addrobj_t ipaddr;
1327f6da83d4SAnurag S. Maskey ipadm_status_t ipstatus;
1328f6da83d4SAnurag S. Maskey int retries = 0;
13296ba597c5SAnurag S. Maskey
13306ba597c5SAnurag S. Maskey name = thread_arg->name;
13316ba597c5SAnurag S. Maskey type = thread_arg->type;
1332f6da83d4SAnurag S. Maskey ipaddr = thread_arg->ipaddr;
13336ba597c5SAnurag S. Maskey
13346ba597c5SAnurag S. Maskey retry:
1335f6da83d4SAnurag S. Maskey /* Make sure the NCU is in appropriate state for DHCP command */
1336f6da83d4SAnurag S. Maskey ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE, name);
1337f6da83d4SAnurag S. Maskey if (ncu_obj == NULL) {
1338*48fff0e3SRenee Danson Sommerfeld nlog(LOG_ERR, "start_dhcp: no IP object %s", name);
1339f6da83d4SAnurag S. Maskey return (NULL);
13406ba597c5SAnurag S. Maskey }
13416ba597c5SAnurag S. Maskey
1342f6da83d4SAnurag S. Maskey if (ncu_obj->nwamd_object_state != NWAM_STATE_OFFLINE_TO_ONLINE &&
1343f6da83d4SAnurag S. Maskey ncu_obj->nwamd_object_state != NWAM_STATE_ONLINE) {
1344f6da83d4SAnurag S. Maskey nlog(LOG_INFO, "start_dhcp: IP NCU %s is in invalid state "
1345f6da83d4SAnurag S. Maskey "for DHCP command", ncu_obj->nwamd_object_name);
1346f6da83d4SAnurag S. Maskey nwamd_object_release(ncu_obj);
1347f6da83d4SAnurag S. Maskey return (NULL);
13486ba597c5SAnurag S. Maskey }
1349f6da83d4SAnurag S. Maskey nwamd_object_release(ncu_obj);
13506ba597c5SAnurag S. Maskey
1351f6da83d4SAnurag S. Maskey switch (type) {
1352f6da83d4SAnurag S. Maskey case DHCP_INFORM:
1353f6da83d4SAnurag S. Maskey {
1354f6da83d4SAnurag S. Maskey char aobjname[IPADM_AOBJSIZ];
1355f6da83d4SAnurag S. Maskey
1356f6da83d4SAnurag S. Maskey if ((ipstatus = ipadm_get_aobjname(ipaddr, aobjname,
1357f6da83d4SAnurag S. Maskey sizeof (aobjname))) != IPADM_SUCCESS) {
1358f6da83d4SAnurag S. Maskey nlog(LOG_ERR, "start_dhcp: "
1359f6da83d4SAnurag S. Maskey "ipadm_get_aobjname failed for %s: %s",
1360f6da83d4SAnurag S. Maskey name, ipadm_status2str(ipstatus));
1361f6da83d4SAnurag S. Maskey goto done;
13626ba597c5SAnurag S. Maskey }
1363f6da83d4SAnurag S. Maskey ipstatus = ipadm_refresh_addr(ipadm_handle, aobjname,
1364f6da83d4SAnurag S. Maskey IPADM_OPT_ACTIVE | IPADM_OPT_INFORM);
1365f6da83d4SAnurag S. Maskey break;
1366f6da83d4SAnurag S. Maskey }
1367f6da83d4SAnurag S. Maskey case DHCP_START:
1368f6da83d4SAnurag S. Maskey ipstatus = ipadm_create_addr(ipadm_handle, ipaddr,
1369f6da83d4SAnurag S. Maskey IPADM_OPT_ACTIVE);
13703dbbe3fbSAnurag S. Maskey break;
13713dbbe3fbSAnurag S. Maskey default:
13723dbbe3fbSAnurag S. Maskey nlog(LOG_ERR, "start_dhcp: invalid dhcp_ipc_type_t: %d", type);
13733dbbe3fbSAnurag S. Maskey goto done;
13743dbbe3fbSAnurag S. Maskey }
1375f6da83d4SAnurag S. Maskey
1376f6da83d4SAnurag S. Maskey if (ipstatus == IPADM_DHCP_IPC_TIMEOUT) {
13776ba597c5SAnurag S. Maskey /*
13783dbbe3fbSAnurag S. Maskey * DHCP timed out: for DHCP_START requests, change state for
13793dbbe3fbSAnurag S. Maskey * this NCU and euqueue event to check NCU priority-groups;
13803dbbe3fbSAnurag S. Maskey * for DHCP_INFORM requests, nothing to do.
13816ba597c5SAnurag S. Maskey */
13823dbbe3fbSAnurag S. Maskey if (type == DHCP_START) {
13836ba597c5SAnurag S. Maskey char *object_name;
13846ba597c5SAnurag S. Maskey
13853dbbe3fbSAnurag S. Maskey nlog(LOG_INFO,
13863dbbe3fbSAnurag S. Maskey "start_dhcp: DHCP_START timed out for %s", name);
1387f6da83d4SAnurag S. Maskey
13886ba597c5SAnurag S. Maskey if (nwam_ncu_name_to_typed_name(name,
13896ba597c5SAnurag S. Maskey NWAM_NCU_TYPE_INTERFACE, &object_name)
13906ba597c5SAnurag S. Maskey != NWAM_SUCCESS) {
13916ba597c5SAnurag S. Maskey nlog(LOG_ERR, "start_dhcp: "
13923dbbe3fbSAnurag S. Maskey "nwam_ncu_name_to_typed_name failed for %s",
13933dbbe3fbSAnurag S. Maskey name);
1394f6da83d4SAnurag S. Maskey goto done;
13956ba597c5SAnurag S. Maskey }
13966ba597c5SAnurag S. Maskey nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
13976ba597c5SAnurag S. Maskey object_name, NWAM_STATE_OFFLINE_TO_ONLINE,
13986ba597c5SAnurag S. Maskey NWAM_AUX_STATE_IF_DHCP_TIMED_OUT);
13996ba597c5SAnurag S. Maskey nwamd_create_ncu_check_event(0);
14006ba597c5SAnurag S. Maskey free(object_name);
14013dbbe3fbSAnurag S. Maskey } else {
14023dbbe3fbSAnurag S. Maskey nlog(LOG_INFO,
14033dbbe3fbSAnurag S. Maskey "start_dhcp: DHCP_INFORM timed out for %s", name);
14043dbbe3fbSAnurag S. Maskey }
14056ba597c5SAnurag S. Maskey
14063dbbe3fbSAnurag S. Maskey } else if ((ipstatus == IPADM_DHCP_IPC_ERROR ||
14073dbbe3fbSAnurag S. Maskey ipstatus == IPADM_IPC_ERROR) && retries++ < NWAMD_DHCP_RETRIES) {
14086ba597c5SAnurag S. Maskey /*
14093dbbe3fbSAnurag S. Maskey * Retry DHCP request as we may have been unplumbing as part
14103dbbe3fbSAnurag S. Maskey * of the configuration phase.
14116ba597c5SAnurag S. Maskey */
14123dbbe3fbSAnurag S. Maskey nlog(LOG_ERR, "start_dhcp: ipadm_%s_addr on %s returned: %s, "
14133dbbe3fbSAnurag S. Maskey "retrying in %d sec",
14143dbbe3fbSAnurag S. Maskey (type == DHCP_START ? "create" : "refresh"), name,
14153dbbe3fbSAnurag S. Maskey ipadm_status2str(ipstatus), NWAMD_DHCP_RETRY_WAIT_TIME);
14166ba597c5SAnurag S. Maskey (void) sleep(NWAMD_DHCP_RETRY_WAIT_TIME);
14176ba597c5SAnurag S. Maskey goto retry;
14186ba597c5SAnurag S. Maskey
14193dbbe3fbSAnurag S. Maskey } else if (ipstatus != IPADM_SUCCESS) {
1420f6da83d4SAnurag S. Maskey nlog(LOG_ERR, "start_dhcp: ipadm_%s_addr failed for %s: %s",
14213dbbe3fbSAnurag S. Maskey (type == DHCP_START ? "create" : "refresh"), name,
14223dbbe3fbSAnurag S. Maskey ipadm_status2str(ipstatus));
14236ba597c5SAnurag S. Maskey }
14246ba597c5SAnurag S. Maskey
1425f6da83d4SAnurag S. Maskey done:
14266ba597c5SAnurag S. Maskey free(name);
14276ba597c5SAnurag S. Maskey free(arg);
14286ba597c5SAnurag S. Maskey return (NULL);
14296ba597c5SAnurag S. Maskey }
14306ba597c5SAnurag S. Maskey
1431f6da83d4SAnurag S. Maskey static void
nwamd_dhcp(const char * ifname,ipadm_addrobj_t ipaddr,dhcp_ipc_type_t cmd)1432f6da83d4SAnurag S. Maskey nwamd_dhcp(const char *ifname, ipadm_addrobj_t ipaddr, dhcp_ipc_type_t cmd)
14336ba597c5SAnurag S. Maskey {
14346ba597c5SAnurag S. Maskey struct nwamd_dhcp_thread_arg *arg;
14356ba597c5SAnurag S. Maskey pthread_attr_t attr;
14366ba597c5SAnurag S. Maskey
1437f6da83d4SAnurag S. Maskey nlog(LOG_DEBUG, "nwamd_dhcp: starting DHCP %s thread for %s",
1438f6da83d4SAnurag S. Maskey dhcp_ipc_type_to_string(cmd), ifname);
14396ba597c5SAnurag S. Maskey
14406ba597c5SAnurag S. Maskey arg = malloc(sizeof (*arg));
14416ba597c5SAnurag S. Maskey if (arg == NULL) {
1442f6da83d4SAnurag S. Maskey nlog(LOG_ERR, "nwamd_dhcp: error allocating memory for "
1443f6da83d4SAnurag S. Maskey "dhcp request");
14446ba597c5SAnurag S. Maskey return;
14456ba597c5SAnurag S. Maskey }
14466ba597c5SAnurag S. Maskey
1447f6da83d4SAnurag S. Maskey arg->name = strdup(ifname);
1448f6da83d4SAnurag S. Maskey arg->type = cmd;
1449f6da83d4SAnurag S. Maskey arg->ipaddr = ipaddr;
14506ba597c5SAnurag S. Maskey
14516ba597c5SAnurag S. Maskey (void) pthread_attr_init(&attr);
14526ba597c5SAnurag S. Maskey (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
14536ba597c5SAnurag S. Maskey if (pthread_create(NULL, &attr, start_dhcp_thread, arg) == -1) {
1454f6da83d4SAnurag S. Maskey nlog(LOG_ERR, "nwamd_dhcp: cannot start dhcp thread");
1455f6da83d4SAnurag S. Maskey free(arg->name);
14566ba597c5SAnurag S. Maskey free(arg);
14576ba597c5SAnurag S. Maskey (void) pthread_attr_destroy(&attr);
14586ba597c5SAnurag S. Maskey return;
14596ba597c5SAnurag S. Maskey }
14606ba597c5SAnurag S. Maskey (void) pthread_attr_destroy(&attr);
14616ba597c5SAnurag S. Maskey }
1462