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 * 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 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 * 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 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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