19175SSowmini.Varadhan@Sun.COM /* 29175SSowmini.Varadhan@Sun.COM * CDDL HEADER START 39175SSowmini.Varadhan@Sun.COM * 49175SSowmini.Varadhan@Sun.COM * The contents of this file are subject to the terms of the 59175SSowmini.Varadhan@Sun.COM * Common Development and Distribution License (the "License"). 69175SSowmini.Varadhan@Sun.COM * You may not use this file except in compliance with the License. 79175SSowmini.Varadhan@Sun.COM * 89175SSowmini.Varadhan@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99175SSowmini.Varadhan@Sun.COM * or http://www.opensolaris.org/os/licensing. 109175SSowmini.Varadhan@Sun.COM * See the License for the specific language governing permissions 119175SSowmini.Varadhan@Sun.COM * and limitations under the License. 129175SSowmini.Varadhan@Sun.COM * 139175SSowmini.Varadhan@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 149175SSowmini.Varadhan@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159175SSowmini.Varadhan@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 169175SSowmini.Varadhan@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 179175SSowmini.Varadhan@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 189175SSowmini.Varadhan@Sun.COM * 199175SSowmini.Varadhan@Sun.COM * CDDL HEADER END 209175SSowmini.Varadhan@Sun.COM */ 21*11042SErik.Nordmark@Sun.COM 229175SSowmini.Varadhan@Sun.COM /* 239175SSowmini.Varadhan@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 249175SSowmini.Varadhan@Sun.COM * Use is subject to license terms. 259175SSowmini.Varadhan@Sun.COM */ 269175SSowmini.Varadhan@Sun.COM 279175SSowmini.Varadhan@Sun.COM /* 289175SSowmini.Varadhan@Sun.COM * Functions to implement IP address -> link layer address (PSARC 2006/482) 299175SSowmini.Varadhan@Sun.COM */ 309175SSowmini.Varadhan@Sun.COM #include <inet/ip2mac.h> 319175SSowmini.Varadhan@Sun.COM #include <inet/ip2mac_impl.h> 329175SSowmini.Varadhan@Sun.COM #include <sys/zone.h> 339175SSowmini.Varadhan@Sun.COM #include <inet/ip_ndp.h> 349175SSowmini.Varadhan@Sun.COM #include <inet/ip_if.h> 359175SSowmini.Varadhan@Sun.COM #include <inet/ip6.h> 369175SSowmini.Varadhan@Sun.COM 379175SSowmini.Varadhan@Sun.COM /* 389175SSowmini.Varadhan@Sun.COM * dispatch pending callbacks. 399175SSowmini.Varadhan@Sun.COM */ 409175SSowmini.Varadhan@Sun.COM void 41*11042SErik.Nordmark@Sun.COM ncec_cb_dispatch(ncec_t *ncec) 429175SSowmini.Varadhan@Sun.COM { 43*11042SErik.Nordmark@Sun.COM ncec_cb_t *ncec_cb; 449175SSowmini.Varadhan@Sun.COM ip2mac_t ip2m; 459175SSowmini.Varadhan@Sun.COM 46*11042SErik.Nordmark@Sun.COM mutex_enter(&ncec->ncec_lock); 47*11042SErik.Nordmark@Sun.COM if (list_is_empty(&ncec->ncec_cb)) { 48*11042SErik.Nordmark@Sun.COM mutex_exit(&ncec->ncec_lock); 499175SSowmini.Varadhan@Sun.COM return; 509175SSowmini.Varadhan@Sun.COM } 51*11042SErik.Nordmark@Sun.COM ncec_ip2mac_response(&ip2m, ncec); 52*11042SErik.Nordmark@Sun.COM ncec_cb_refhold_locked(ncec); 539175SSowmini.Varadhan@Sun.COM /* 549175SSowmini.Varadhan@Sun.COM * IP does not hold internal locks like nce_lock across calls to 559175SSowmini.Varadhan@Sun.COM * other subsystems for fear of recursive lock entry and lock 569175SSowmini.Varadhan@Sun.COM * hierarchy violation. The caller may be holding locks across 579175SSowmini.Varadhan@Sun.COM * the call to IP. (It would be ideal if no subsystem holds locks 589175SSowmini.Varadhan@Sun.COM * across calls into another subsystem, especially if calls can 599175SSowmini.Varadhan@Sun.COM * happen in either direction). 609175SSowmini.Varadhan@Sun.COM */ 61*11042SErik.Nordmark@Sun.COM ncec_cb = list_head(&ncec->ncec_cb); 62*11042SErik.Nordmark@Sun.COM for (; ncec_cb != NULL; ncec_cb = list_next(&ncec->ncec_cb, ncec_cb)) { 63*11042SErik.Nordmark@Sun.COM if (ncec_cb->ncec_cb_flags & NCE_CB_DISPATCHED) 649175SSowmini.Varadhan@Sun.COM continue; 65*11042SErik.Nordmark@Sun.COM ncec_cb->ncec_cb_flags |= NCE_CB_DISPATCHED; 66*11042SErik.Nordmark@Sun.COM mutex_exit(&ncec->ncec_lock); 67*11042SErik.Nordmark@Sun.COM (*ncec_cb->ncec_cb_func)(&ip2m, ncec_cb->ncec_cb_arg); 68*11042SErik.Nordmark@Sun.COM mutex_enter(&ncec->ncec_lock); 699175SSowmini.Varadhan@Sun.COM } 70*11042SErik.Nordmark@Sun.COM ncec_cb_refrele(ncec); 71*11042SErik.Nordmark@Sun.COM mutex_exit(&ncec->ncec_lock); 729175SSowmini.Varadhan@Sun.COM } 739175SSowmini.Varadhan@Sun.COM 749175SSowmini.Varadhan@Sun.COM /* 759175SSowmini.Varadhan@Sun.COM * fill up the ip2m response fields with inforamation from the nce. 769175SSowmini.Varadhan@Sun.COM */ 779175SSowmini.Varadhan@Sun.COM void 78*11042SErik.Nordmark@Sun.COM ncec_ip2mac_response(ip2mac_t *ip2m, ncec_t *ncec) 799175SSowmini.Varadhan@Sun.COM { 80*11042SErik.Nordmark@Sun.COM boolean_t isv6 = (ncec->ncec_ipversion == IPV6_VERSION); 81*11042SErik.Nordmark@Sun.COM sin_t *sin; 829175SSowmini.Varadhan@Sun.COM sin6_t *sin6; 839175SSowmini.Varadhan@Sun.COM struct sockaddr_dl *sdl; 849175SSowmini.Varadhan@Sun.COM 85*11042SErik.Nordmark@Sun.COM ASSERT(MUTEX_HELD(&ncec->ncec_lock)); 869175SSowmini.Varadhan@Sun.COM bzero(ip2m, sizeof (*ip2m)); 87*11042SErik.Nordmark@Sun.COM if (NCE_ISREACHABLE(ncec) && !NCE_ISCONDEMNED(ncec)) 889175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = 0; 899175SSowmini.Varadhan@Sun.COM else 909175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = ESRCH; 919175SSowmini.Varadhan@Sun.COM if (isv6) { 929175SSowmini.Varadhan@Sun.COM sin6 = (sin6_t *)&ip2m->ip2mac_pa; 939175SSowmini.Varadhan@Sun.COM sin6->sin6_family = AF_INET6; 94*11042SErik.Nordmark@Sun.COM sin6->sin6_addr = ncec->ncec_addr; 95*11042SErik.Nordmark@Sun.COM } else { 96*11042SErik.Nordmark@Sun.COM sin = (sin_t *)&ip2m->ip2mac_pa; 97*11042SErik.Nordmark@Sun.COM sin->sin_family = AF_INET; 98*11042SErik.Nordmark@Sun.COM IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &sin->sin_addr); 999175SSowmini.Varadhan@Sun.COM } 1009175SSowmini.Varadhan@Sun.COM if (ip2m->ip2mac_err == 0) { 1019175SSowmini.Varadhan@Sun.COM sdl = &ip2m->ip2mac_ha; 1029175SSowmini.Varadhan@Sun.COM sdl->sdl_family = AF_LINK; 103*11042SErik.Nordmark@Sun.COM sdl->sdl_type = ncec->ncec_ill->ill_type; 104*11042SErik.Nordmark@Sun.COM /* 105*11042SErik.Nordmark@Sun.COM * should we put ncec_ill->ill_name in there? why? 106*11042SErik.Nordmark@Sun.COM * likewise for the sdl_index 107*11042SErik.Nordmark@Sun.COM */ 1089175SSowmini.Varadhan@Sun.COM sdl->sdl_nlen = 0; 109*11042SErik.Nordmark@Sun.COM sdl->sdl_alen = ncec->ncec_ill->ill_phys_addr_length; 110*11042SErik.Nordmark@Sun.COM if (ncec->ncec_lladdr != NULL) 111*11042SErik.Nordmark@Sun.COM bcopy(ncec->ncec_lladdr, LLADDR(sdl), sdl->sdl_alen); 1129175SSowmini.Varadhan@Sun.COM } 1139175SSowmini.Varadhan@Sun.COM } 1149175SSowmini.Varadhan@Sun.COM 1159175SSowmini.Varadhan@Sun.COM void 116*11042SErik.Nordmark@Sun.COM ncec_cb_refhold_locked(ncec_t *ncec) 1179175SSowmini.Varadhan@Sun.COM { 118*11042SErik.Nordmark@Sun.COM ASSERT(MUTEX_HELD(&ncec->ncec_lock)); 119*11042SErik.Nordmark@Sun.COM ncec->ncec_cb_walker_cnt++; 1209175SSowmini.Varadhan@Sun.COM } 1219175SSowmini.Varadhan@Sun.COM 1229175SSowmini.Varadhan@Sun.COM void 123*11042SErik.Nordmark@Sun.COM ncec_cb_refrele(ncec_t *ncec) 1249175SSowmini.Varadhan@Sun.COM { 125*11042SErik.Nordmark@Sun.COM ncec_cb_t *ncec_cb, *ncec_cb_next = NULL; 1269175SSowmini.Varadhan@Sun.COM 127*11042SErik.Nordmark@Sun.COM ASSERT(MUTEX_HELD(&ncec->ncec_lock)); 128*11042SErik.Nordmark@Sun.COM if (--ncec->ncec_cb_walker_cnt == 0) { 129*11042SErik.Nordmark@Sun.COM for (ncec_cb = list_head(&ncec->ncec_cb); ncec_cb != NULL; 130*11042SErik.Nordmark@Sun.COM ncec_cb = ncec_cb_next) { 1319175SSowmini.Varadhan@Sun.COM 132*11042SErik.Nordmark@Sun.COM ncec_cb_next = list_next(&ncec->ncec_cb, ncec_cb); 133*11042SErik.Nordmark@Sun.COM if ((ncec_cb->ncec_cb_flags & NCE_CB_DISPATCHED) == 0) 1349175SSowmini.Varadhan@Sun.COM continue; 135*11042SErik.Nordmark@Sun.COM list_remove(&ncec->ncec_cb, ncec_cb); 136*11042SErik.Nordmark@Sun.COM kmem_free(ncec_cb, sizeof (*ncec_cb)); 1379175SSowmini.Varadhan@Sun.COM } 1389175SSowmini.Varadhan@Sun.COM } 1399175SSowmini.Varadhan@Sun.COM } 1409175SSowmini.Varadhan@Sun.COM 1419175SSowmini.Varadhan@Sun.COM /* 1429175SSowmini.Varadhan@Sun.COM * add a callback to the nce, so that the callback can be invoked 1439175SSowmini.Varadhan@Sun.COM * after address resolution succeeds/fails. 1449175SSowmini.Varadhan@Sun.COM */ 1459175SSowmini.Varadhan@Sun.COM static ip2mac_id_t 146*11042SErik.Nordmark@Sun.COM ncec_add_cb(ncec_t *ncec, ip2mac_callback_t *cb, void *cbarg) 1479175SSowmini.Varadhan@Sun.COM { 148*11042SErik.Nordmark@Sun.COM ncec_cb_t *nce_cb; 1499175SSowmini.Varadhan@Sun.COM ip2mac_id_t ip2mid = NULL; 1509175SSowmini.Varadhan@Sun.COM 151*11042SErik.Nordmark@Sun.COM ASSERT(MUTEX_HELD(&ncec->ncec_lock)); 1529175SSowmini.Varadhan@Sun.COM if ((nce_cb = kmem_zalloc(sizeof (*nce_cb), KM_NOSLEEP)) == NULL) 1539175SSowmini.Varadhan@Sun.COM return (ip2mid); 154*11042SErik.Nordmark@Sun.COM nce_cb->ncec_cb_func = cb; 155*11042SErik.Nordmark@Sun.COM nce_cb->ncec_cb_arg = cbarg; 1569175SSowmini.Varadhan@Sun.COM /* 157*11042SErik.Nordmark@Sun.COM * We identify the ncec_cb_t during cancellation by the address 1589175SSowmini.Varadhan@Sun.COM * of the nce_cb_t itself, and, as a short-cut for eliminating 159*11042SErik.Nordmark@Sun.COM * clear mismatches, only look in the callback list of ncec's 1609175SSowmini.Varadhan@Sun.COM * whose address is equal to the nce_cb_id. 1619175SSowmini.Varadhan@Sun.COM */ 162*11042SErik.Nordmark@Sun.COM nce_cb->ncec_cb_id = ncec; /* no refs! just an address */ 163*11042SErik.Nordmark@Sun.COM list_insert_tail(&ncec->ncec_cb, nce_cb); 164*11042SErik.Nordmark@Sun.COM ip2mid = ncec; /* this is the id to be used in ip2mac_cancel */ 1659175SSowmini.Varadhan@Sun.COM 1669175SSowmini.Varadhan@Sun.COM return (nce_cb); 1679175SSowmini.Varadhan@Sun.COM } 1689175SSowmini.Varadhan@Sun.COM 1699175SSowmini.Varadhan@Sun.COM /* 1709175SSowmini.Varadhan@Sun.COM * Resolve an IP address to a link-layer address using the data-structures 1719175SSowmini.Varadhan@Sun.COM * defined in PSARC 2006/482. If the current link-layer address for the 1729175SSowmini.Varadhan@Sun.COM * IP address is not known, the state-machine for resolving the resolution 1739175SSowmini.Varadhan@Sun.COM * will be triggered, and the callback function (*cb) will be invoked after 1749175SSowmini.Varadhan@Sun.COM * the resolution completes. 1759175SSowmini.Varadhan@Sun.COM */ 1769175SSowmini.Varadhan@Sun.COM ip2mac_id_t 177*11042SErik.Nordmark@Sun.COM ip2mac(uint_t op, ip2mac_t *ip2m, ip2mac_callback_t *cb, void *cbarg, 1789175SSowmini.Varadhan@Sun.COM zoneid_t zoneid) 1799175SSowmini.Varadhan@Sun.COM { 180*11042SErik.Nordmark@Sun.COM ncec_t *ncec; 181*11042SErik.Nordmark@Sun.COM nce_t *nce = NULL; 1829175SSowmini.Varadhan@Sun.COM boolean_t isv6; 1839175SSowmini.Varadhan@Sun.COM ill_t *ill; 1849175SSowmini.Varadhan@Sun.COM netstack_t *ns; 1859175SSowmini.Varadhan@Sun.COM ip_stack_t *ipst; 1869175SSowmini.Varadhan@Sun.COM ip2mac_id_t ip2mid = NULL; 187*11042SErik.Nordmark@Sun.COM sin_t *sin; 1889175SSowmini.Varadhan@Sun.COM sin6_t *sin6; 1899175SSowmini.Varadhan@Sun.COM int err; 1909175SSowmini.Varadhan@Sun.COM uint64_t delta; 191*11042SErik.Nordmark@Sun.COM boolean_t need_resolve = B_FALSE; 1929175SSowmini.Varadhan@Sun.COM 1939175SSowmini.Varadhan@Sun.COM isv6 = (ip2m->ip2mac_pa.ss_family == AF_INET6); 1949175SSowmini.Varadhan@Sun.COM 1959175SSowmini.Varadhan@Sun.COM ns = netstack_find_by_zoneid(zoneid); 1969175SSowmini.Varadhan@Sun.COM if (ns == NULL) { 1979175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = EINVAL; 1989175SSowmini.Varadhan@Sun.COM return (NULL); 1999175SSowmini.Varadhan@Sun.COM } 2009175SSowmini.Varadhan@Sun.COM /* 2019175SSowmini.Varadhan@Sun.COM * For exclusive stacks we reset the zoneid to zero 2029175SSowmini.Varadhan@Sun.COM * since IP uses the global zoneid in the exclusive stacks. 2039175SSowmini.Varadhan@Sun.COM */ 2049175SSowmini.Varadhan@Sun.COM if (ns->netstack_stackid != GLOBAL_NETSTACKID) 2059175SSowmini.Varadhan@Sun.COM zoneid = GLOBAL_ZONEID; 2069175SSowmini.Varadhan@Sun.COM ipst = ns->netstack_ip; 2079175SSowmini.Varadhan@Sun.COM /* 2089175SSowmini.Varadhan@Sun.COM * find the ill from the ip2m->ip2mac_ifindex 2099175SSowmini.Varadhan@Sun.COM */ 210*11042SErik.Nordmark@Sun.COM ill = ill_lookup_on_ifindex(ip2m->ip2mac_ifindex, isv6, ipst); 2119175SSowmini.Varadhan@Sun.COM if (ill == NULL) { 2129175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = ENXIO; 2139175SSowmini.Varadhan@Sun.COM netstack_rele(ns); 2149175SSowmini.Varadhan@Sun.COM return (NULL); 2159175SSowmini.Varadhan@Sun.COM } 2169175SSowmini.Varadhan@Sun.COM if (isv6) { 2179175SSowmini.Varadhan@Sun.COM sin6 = (sin6_t *)&ip2m->ip2mac_pa; 218*11042SErik.Nordmark@Sun.COM if (op == IP2MAC_LOOKUP) { 219*11042SErik.Nordmark@Sun.COM nce = nce_lookup_v6(ill, &sin6->sin6_addr); 2209175SSowmini.Varadhan@Sun.COM } else { 221*11042SErik.Nordmark@Sun.COM err = nce_lookup_then_add_v6(ill, NULL, 222*11042SErik.Nordmark@Sun.COM ill->ill_phys_addr_length, 223*11042SErik.Nordmark@Sun.COM &sin6->sin6_addr, 0, ND_UNCHANGED, &nce); 2249175SSowmini.Varadhan@Sun.COM } 2259175SSowmini.Varadhan@Sun.COM } else { 226*11042SErik.Nordmark@Sun.COM sin = (sin_t *)&ip2m->ip2mac_pa; 227*11042SErik.Nordmark@Sun.COM if (op == IP2MAC_LOOKUP) { 228*11042SErik.Nordmark@Sun.COM nce = nce_lookup_v4(ill, &sin->sin_addr.s_addr); 229*11042SErik.Nordmark@Sun.COM } else { 230*11042SErik.Nordmark@Sun.COM err = nce_lookup_then_add_v4(ill, NULL, 231*11042SErik.Nordmark@Sun.COM ill->ill_phys_addr_length, 232*11042SErik.Nordmark@Sun.COM &sin->sin_addr.s_addr, 0, ND_UNCHANGED, &nce); 233*11042SErik.Nordmark@Sun.COM } 2349175SSowmini.Varadhan@Sun.COM } 235*11042SErik.Nordmark@Sun.COM if (op == IP2MAC_LOOKUP) { 2369175SSowmini.Varadhan@Sun.COM if (nce == NULL) { 2379175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = ESRCH; 2389175SSowmini.Varadhan@Sun.COM goto done; 2399175SSowmini.Varadhan@Sun.COM } 240*11042SErik.Nordmark@Sun.COM ncec = nce->nce_common; 241*11042SErik.Nordmark@Sun.COM delta = TICK_TO_MSEC(lbolt64) - ncec->ncec_last; 242*11042SErik.Nordmark@Sun.COM mutex_enter(&ncec->ncec_lock); 243*11042SErik.Nordmark@Sun.COM if (NCE_ISREACHABLE(ncec) && 244*11042SErik.Nordmark@Sun.COM delta < (uint64_t)ill->ill_reachable_time) { 245*11042SErik.Nordmark@Sun.COM ncec_ip2mac_response(ip2m, ncec); 2469175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = 0; 2479175SSowmini.Varadhan@Sun.COM } else { 2489175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = ESRCH; 2499175SSowmini.Varadhan@Sun.COM } 250*11042SErik.Nordmark@Sun.COM mutex_exit(&ncec->ncec_lock); 2519175SSowmini.Varadhan@Sun.COM goto done; 2529175SSowmini.Varadhan@Sun.COM } else { 2539175SSowmini.Varadhan@Sun.COM if (err != 0 && err != EEXIST) { 2549175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = err; 2559175SSowmini.Varadhan@Sun.COM goto done; 2569175SSowmini.Varadhan@Sun.COM } 2579175SSowmini.Varadhan@Sun.COM } 258*11042SErik.Nordmark@Sun.COM ncec = nce->nce_common; 259*11042SErik.Nordmark@Sun.COM delta = TICK_TO_MSEC(lbolt64) - ncec->ncec_last; 260*11042SErik.Nordmark@Sun.COM mutex_enter(&ncec->ncec_lock); 261*11042SErik.Nordmark@Sun.COM if (NCE_ISCONDEMNED(ncec)) { 2629175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = ESRCH; 263*11042SErik.Nordmark@Sun.COM } else { 264*11042SErik.Nordmark@Sun.COM if (NCE_ISREACHABLE(ncec)) { 265*11042SErik.Nordmark@Sun.COM if (NCE_MYADDR(ncec) || 266*11042SErik.Nordmark@Sun.COM delta < (uint64_t)ill->ill_reachable_time) { 267*11042SErik.Nordmark@Sun.COM ncec_ip2mac_response(ip2m, ncec); 268*11042SErik.Nordmark@Sun.COM ip2m->ip2mac_err = 0; 269*11042SErik.Nordmark@Sun.COM mutex_exit(&ncec->ncec_lock); 270*11042SErik.Nordmark@Sun.COM goto done; 271*11042SErik.Nordmark@Sun.COM } 2729175SSowmini.Varadhan@Sun.COM /* 2739175SSowmini.Varadhan@Sun.COM * Since we do not control the packet output 2749175SSowmini.Varadhan@Sun.COM * path for ip2mac() callers, we need to verify 2759175SSowmini.Varadhan@Sun.COM * if the existing information in the nce is 2769175SSowmini.Varadhan@Sun.COM * very old, and retrigger resolution if necessary. 2779175SSowmini.Varadhan@Sun.COM * We will not return the existing stale 2789175SSowmini.Varadhan@Sun.COM * information until it is verified through a 2799175SSowmini.Varadhan@Sun.COM * resolver request/response exchange. 2809175SSowmini.Varadhan@Sun.COM * 2819175SSowmini.Varadhan@Sun.COM * In the future, we may want to support extensions 2829175SSowmini.Varadhan@Sun.COM * that do additional callbacks on link-layer updates, 2839175SSowmini.Varadhan@Sun.COM * so that we can return the stale information but 2849175SSowmini.Varadhan@Sun.COM * also update the caller if the lladdr changes. 2859175SSowmini.Varadhan@Sun.COM */ 286*11042SErik.Nordmark@Sun.COM ncec->ncec_rcnt = ill->ill_xmit_count; 287*11042SErik.Nordmark@Sun.COM ncec->ncec_state = ND_PROBE; 288*11042SErik.Nordmark@Sun.COM need_resolve = B_TRUE; /* reachable but very old nce */ 289*11042SErik.Nordmark@Sun.COM } else if (ncec->ncec_state == ND_INITIAL) { 290*11042SErik.Nordmark@Sun.COM need_resolve = B_TRUE; /* ND_INITIAL nce */ 291*11042SErik.Nordmark@Sun.COM ncec->ncec_state = ND_INCOMPLETE; 2929175SSowmini.Varadhan@Sun.COM } 293*11042SErik.Nordmark@Sun.COM /* 294*11042SErik.Nordmark@Sun.COM * NCE not known to be reachable in the recent past. We must 295*11042SErik.Nordmark@Sun.COM * reconfirm the information before returning it to the caller 296*11042SErik.Nordmark@Sun.COM */ 297*11042SErik.Nordmark@Sun.COM if (ncec->ncec_rcnt > 0) { 2989175SSowmini.Varadhan@Sun.COM /* 299*11042SErik.Nordmark@Sun.COM * Still resolving this ncec, so we can queue the 300*11042SErik.Nordmark@Sun.COM * callback information in ncec->ncec_cb 3019175SSowmini.Varadhan@Sun.COM */ 302*11042SErik.Nordmark@Sun.COM ip2mid = ncec_add_cb(ncec, cb, cbarg); 3039175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = EINPROGRESS; 3049175SSowmini.Varadhan@Sun.COM } else { 3059175SSowmini.Varadhan@Sun.COM /* 306*11042SErik.Nordmark@Sun.COM * No more retransmits allowed -- resolution failed. 3079175SSowmini.Varadhan@Sun.COM */ 3089175SSowmini.Varadhan@Sun.COM ip2m->ip2mac_err = ESRCH; 3099175SSowmini.Varadhan@Sun.COM } 3109175SSowmini.Varadhan@Sun.COM } 311*11042SErik.Nordmark@Sun.COM mutex_exit(&ncec->ncec_lock); 3129175SSowmini.Varadhan@Sun.COM done: 313*11042SErik.Nordmark@Sun.COM /* 314*11042SErik.Nordmark@Sun.COM * if NCE_ISREACHABLE(ncec) but very old, or if it is ND_INITIAL, 315*11042SErik.Nordmark@Sun.COM * trigger resolve. 316*11042SErik.Nordmark@Sun.COM */ 317*11042SErik.Nordmark@Sun.COM if (need_resolve) 318*11042SErik.Nordmark@Sun.COM ip_ndp_resolve(ncec); 319*11042SErik.Nordmark@Sun.COM if (nce != NULL) 320*11042SErik.Nordmark@Sun.COM nce_refrele(nce); 3219175SSowmini.Varadhan@Sun.COM netstack_rele(ns); 3229175SSowmini.Varadhan@Sun.COM ill_refrele(ill); 3239175SSowmini.Varadhan@Sun.COM return (ip2mid); 3249175SSowmini.Varadhan@Sun.COM } 3259175SSowmini.Varadhan@Sun.COM 3269175SSowmini.Varadhan@Sun.COM /* 327*11042SErik.Nordmark@Sun.COM * data passed to ncec_walk for canceling outstanding callbacks. 3289175SSowmini.Varadhan@Sun.COM */ 3299175SSowmini.Varadhan@Sun.COM typedef struct ip2mac_cancel_data_s { 3309175SSowmini.Varadhan@Sun.COM ip2mac_id_t ip2m_cancel_id; 3319175SSowmini.Varadhan@Sun.COM int ip2m_cancel_err; 3329175SSowmini.Varadhan@Sun.COM } ip2mac_cancel_data_t; 3339175SSowmini.Varadhan@Sun.COM 3349175SSowmini.Varadhan@Sun.COM /* 335*11042SErik.Nordmark@Sun.COM * callback invoked for each active ncec. If the ip2mac_id_t corresponds 336*11042SErik.Nordmark@Sun.COM * to an active nce_cb_t in the ncec's callback list, we want to remove 3379175SSowmini.Varadhan@Sun.COM * the callback (if there are no walkers) or return EBUSY to the caller 3389175SSowmini.Varadhan@Sun.COM */ 3399175SSowmini.Varadhan@Sun.COM static int 340*11042SErik.Nordmark@Sun.COM ip2mac_cancel_callback(ncec_t *ncec, void *arg) 3419175SSowmini.Varadhan@Sun.COM { 3429175SSowmini.Varadhan@Sun.COM ip2mac_cancel_data_t *ip2m_wdata = arg; 343*11042SErik.Nordmark@Sun.COM ncec_cb_t *ip2m_nce_cb = ip2m_wdata->ip2m_cancel_id; 344*11042SErik.Nordmark@Sun.COM ncec_cb_t *ncec_cb; 3459175SSowmini.Varadhan@Sun.COM 346*11042SErik.Nordmark@Sun.COM if (ip2m_nce_cb->ncec_cb_id != ncec) 3479175SSowmini.Varadhan@Sun.COM return (0); 3489175SSowmini.Varadhan@Sun.COM 349*11042SErik.Nordmark@Sun.COM mutex_enter(&ncec->ncec_lock); 350*11042SErik.Nordmark@Sun.COM if (list_is_empty(&ncec->ncec_cb)) { 351*11042SErik.Nordmark@Sun.COM mutex_exit(&ncec->ncec_lock); 3529175SSowmini.Varadhan@Sun.COM return (0); 3539175SSowmini.Varadhan@Sun.COM } 3549175SSowmini.Varadhan@Sun.COM /* 3559175SSowmini.Varadhan@Sun.COM * IP does not hold internal locks like nce_lock across calls to 3569175SSowmini.Varadhan@Sun.COM * other subsystems for fear of recursive lock entry and lock 3579175SSowmini.Varadhan@Sun.COM * hierarchy violation. The caller may be holding locks across 3589175SSowmini.Varadhan@Sun.COM * the call to IP. (It would be ideal if no subsystem holds locks 3599175SSowmini.Varadhan@Sun.COM * across calls into another subsystem, especially if calls can 3609175SSowmini.Varadhan@Sun.COM * happen in either direction). 3619175SSowmini.Varadhan@Sun.COM */ 362*11042SErik.Nordmark@Sun.COM ncec_cb = list_head(&ncec->ncec_cb); 363*11042SErik.Nordmark@Sun.COM for (; ncec_cb != NULL; ncec_cb = list_next(&ncec->ncec_cb, ncec_cb)) { 364*11042SErik.Nordmark@Sun.COM if (ncec_cb != ip2m_nce_cb) 3659175SSowmini.Varadhan@Sun.COM continue; 3669175SSowmini.Varadhan@Sun.COM /* 3679175SSowmini.Varadhan@Sun.COM * If there are no walkers we can remove the nce_cb. 3689175SSowmini.Varadhan@Sun.COM * Otherwise the exiting walker will clean up. 3699175SSowmini.Varadhan@Sun.COM */ 370*11042SErik.Nordmark@Sun.COM if (ncec->ncec_cb_walker_cnt == 0) { 371*11042SErik.Nordmark@Sun.COM list_remove(&ncec->ncec_cb, ncec_cb); 3729175SSowmini.Varadhan@Sun.COM } else { 3739175SSowmini.Varadhan@Sun.COM ip2m_wdata->ip2m_cancel_err = EBUSY; 3749175SSowmini.Varadhan@Sun.COM } 3759175SSowmini.Varadhan@Sun.COM break; 3769175SSowmini.Varadhan@Sun.COM } 377*11042SErik.Nordmark@Sun.COM mutex_exit(&ncec->ncec_lock); 3789175SSowmini.Varadhan@Sun.COM return (0); 3799175SSowmini.Varadhan@Sun.COM } 3809175SSowmini.Varadhan@Sun.COM 3819175SSowmini.Varadhan@Sun.COM /* 3829175SSowmini.Varadhan@Sun.COM * cancel an outstanding timeout set up via ip2mac 3839175SSowmini.Varadhan@Sun.COM */ 3849175SSowmini.Varadhan@Sun.COM int 3859175SSowmini.Varadhan@Sun.COM ip2mac_cancel(ip2mac_id_t ip2mid, zoneid_t zoneid) 3869175SSowmini.Varadhan@Sun.COM { 3879175SSowmini.Varadhan@Sun.COM netstack_t *ns; 3889175SSowmini.Varadhan@Sun.COM ip_stack_t *ipst; 3899175SSowmini.Varadhan@Sun.COM ip2mac_cancel_data_t ip2m_wdata; 3909175SSowmini.Varadhan@Sun.COM 3919175SSowmini.Varadhan@Sun.COM ns = netstack_find_by_zoneid(zoneid); 3929175SSowmini.Varadhan@Sun.COM if (ns == NULL) { 3939175SSowmini.Varadhan@Sun.COM ip2m_wdata.ip2m_cancel_err = EINVAL; 3949175SSowmini.Varadhan@Sun.COM return (ip2m_wdata.ip2m_cancel_err); 3959175SSowmini.Varadhan@Sun.COM } 3969175SSowmini.Varadhan@Sun.COM /* 3979175SSowmini.Varadhan@Sun.COM * For exclusive stacks we reset the zoneid to zero 3989175SSowmini.Varadhan@Sun.COM * since IP uses the global zoneid in the exclusive stacks. 3999175SSowmini.Varadhan@Sun.COM */ 4009175SSowmini.Varadhan@Sun.COM if (ns->netstack_stackid != GLOBAL_NETSTACKID) 4019175SSowmini.Varadhan@Sun.COM zoneid = GLOBAL_ZONEID; 4029175SSowmini.Varadhan@Sun.COM ipst = ns->netstack_ip; 4039175SSowmini.Varadhan@Sun.COM 4049175SSowmini.Varadhan@Sun.COM ip2m_wdata.ip2m_cancel_id = ip2mid; 4059175SSowmini.Varadhan@Sun.COM ip2m_wdata.ip2m_cancel_err = 0; 406*11042SErik.Nordmark@Sun.COM ncec_walk(NULL, ip2mac_cancel_callback, &ip2m_wdata, ipst); 4079175SSowmini.Varadhan@Sun.COM /* 4089175SSowmini.Varadhan@Sun.COM * We may return EBUSY if a walk to dispatch callbacks is 4099175SSowmini.Varadhan@Sun.COM * in progress, in which case the caller needs to synchronize 4109175SSowmini.Varadhan@Sun.COM * with the registered callback function to make sure the 4119175SSowmini.Varadhan@Sun.COM * module does not exit when there is a callback pending. 4129175SSowmini.Varadhan@Sun.COM */ 4139175SSowmini.Varadhan@Sun.COM netstack_rele(ns); 4149175SSowmini.Varadhan@Sun.COM return (ip2m_wdata.ip2m_cancel_err); 4159175SSowmini.Varadhan@Sun.COM } 416