14b7cbb46SSowmini Varadhan /* 24b7cbb46SSowmini Varadhan * CDDL HEADER START 34b7cbb46SSowmini Varadhan * 44b7cbb46SSowmini Varadhan * The contents of this file are subject to the terms of the 54b7cbb46SSowmini Varadhan * Common Development and Distribution License (the "License"). 64b7cbb46SSowmini Varadhan * You may not use this file except in compliance with the License. 74b7cbb46SSowmini Varadhan * 84b7cbb46SSowmini Varadhan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94b7cbb46SSowmini Varadhan * or http://www.opensolaris.org/os/licensing. 104b7cbb46SSowmini Varadhan * See the License for the specific language governing permissions 114b7cbb46SSowmini Varadhan * and limitations under the License. 124b7cbb46SSowmini Varadhan * 134b7cbb46SSowmini Varadhan * When distributing Covered Code, include this CDDL HEADER in each 144b7cbb46SSowmini Varadhan * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154b7cbb46SSowmini Varadhan * If applicable, add the following below this CDDL HEADER, with the 164b7cbb46SSowmini Varadhan * fields enclosed by brackets "[]" replaced with your own identifying 174b7cbb46SSowmini Varadhan * information: Portions Copyright [yyyy] [name of copyright owner] 184b7cbb46SSowmini Varadhan * 194b7cbb46SSowmini Varadhan * CDDL HEADER END 204b7cbb46SSowmini Varadhan */ 21bd670b35SErik Nordmark 224b7cbb46SSowmini Varadhan /* 234b7cbb46SSowmini Varadhan * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 244b7cbb46SSowmini Varadhan * Use is subject to license terms. 254b7cbb46SSowmini Varadhan */ 264b7cbb46SSowmini Varadhan 274b7cbb46SSowmini Varadhan /* 284b7cbb46SSowmini Varadhan * Functions to implement IP address -> link layer address (PSARC 2006/482) 294b7cbb46SSowmini Varadhan */ 304b7cbb46SSowmini Varadhan #include <inet/ip2mac.h> 314b7cbb46SSowmini Varadhan #include <inet/ip2mac_impl.h> 324b7cbb46SSowmini Varadhan #include <sys/zone.h> 334b7cbb46SSowmini Varadhan #include <inet/ip_ndp.h> 344b7cbb46SSowmini Varadhan #include <inet/ip_if.h> 354b7cbb46SSowmini Varadhan #include <inet/ip6.h> 364b7cbb46SSowmini Varadhan 374b7cbb46SSowmini Varadhan /* 384b7cbb46SSowmini Varadhan * dispatch pending callbacks. 394b7cbb46SSowmini Varadhan */ 404b7cbb46SSowmini Varadhan void 41bd670b35SErik Nordmark ncec_cb_dispatch(ncec_t *ncec) 424b7cbb46SSowmini Varadhan { 43bd670b35SErik Nordmark ncec_cb_t *ncec_cb; 444b7cbb46SSowmini Varadhan ip2mac_t ip2m; 454b7cbb46SSowmini Varadhan 46bd670b35SErik Nordmark mutex_enter(&ncec->ncec_lock); 47bd670b35SErik Nordmark if (list_is_empty(&ncec->ncec_cb)) { 48bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 494b7cbb46SSowmini Varadhan return; 504b7cbb46SSowmini Varadhan } 51bd670b35SErik Nordmark ncec_ip2mac_response(&ip2m, ncec); 52bd670b35SErik Nordmark ncec_cb_refhold_locked(ncec); 534b7cbb46SSowmini Varadhan /* 544b7cbb46SSowmini Varadhan * IP does not hold internal locks like nce_lock across calls to 554b7cbb46SSowmini Varadhan * other subsystems for fear of recursive lock entry and lock 564b7cbb46SSowmini Varadhan * hierarchy violation. The caller may be holding locks across 574b7cbb46SSowmini Varadhan * the call to IP. (It would be ideal if no subsystem holds locks 584b7cbb46SSowmini Varadhan * across calls into another subsystem, especially if calls can 594b7cbb46SSowmini Varadhan * happen in either direction). 604b7cbb46SSowmini Varadhan */ 61bd670b35SErik Nordmark ncec_cb = list_head(&ncec->ncec_cb); 62bd670b35SErik Nordmark for (; ncec_cb != NULL; ncec_cb = list_next(&ncec->ncec_cb, ncec_cb)) { 63bd670b35SErik Nordmark if (ncec_cb->ncec_cb_flags & NCE_CB_DISPATCHED) 644b7cbb46SSowmini Varadhan continue; 65bd670b35SErik Nordmark ncec_cb->ncec_cb_flags |= NCE_CB_DISPATCHED; 66bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 67bd670b35SErik Nordmark (*ncec_cb->ncec_cb_func)(&ip2m, ncec_cb->ncec_cb_arg); 68bd670b35SErik Nordmark mutex_enter(&ncec->ncec_lock); 694b7cbb46SSowmini Varadhan } 70bd670b35SErik Nordmark ncec_cb_refrele(ncec); 71bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 724b7cbb46SSowmini Varadhan } 734b7cbb46SSowmini Varadhan 744b7cbb46SSowmini Varadhan /* 754b7cbb46SSowmini Varadhan * fill up the ip2m response fields with inforamation from the nce. 764b7cbb46SSowmini Varadhan */ 774b7cbb46SSowmini Varadhan void 78bd670b35SErik Nordmark ncec_ip2mac_response(ip2mac_t *ip2m, ncec_t *ncec) 794b7cbb46SSowmini Varadhan { 80bd670b35SErik Nordmark boolean_t isv6 = (ncec->ncec_ipversion == IPV6_VERSION); 81bd670b35SErik Nordmark sin_t *sin; 824b7cbb46SSowmini Varadhan sin6_t *sin6; 834b7cbb46SSowmini Varadhan struct sockaddr_dl *sdl; 844b7cbb46SSowmini Varadhan 85bd670b35SErik Nordmark ASSERT(MUTEX_HELD(&ncec->ncec_lock)); 864b7cbb46SSowmini Varadhan bzero(ip2m, sizeof (*ip2m)); 87bd670b35SErik Nordmark if (NCE_ISREACHABLE(ncec) && !NCE_ISCONDEMNED(ncec)) 884b7cbb46SSowmini Varadhan ip2m->ip2mac_err = 0; 894b7cbb46SSowmini Varadhan else 904b7cbb46SSowmini Varadhan ip2m->ip2mac_err = ESRCH; 914b7cbb46SSowmini Varadhan if (isv6) { 924b7cbb46SSowmini Varadhan sin6 = (sin6_t *)&ip2m->ip2mac_pa; 934b7cbb46SSowmini Varadhan sin6->sin6_family = AF_INET6; 94bd670b35SErik Nordmark sin6->sin6_addr = ncec->ncec_addr; 95bd670b35SErik Nordmark } else { 96bd670b35SErik Nordmark sin = (sin_t *)&ip2m->ip2mac_pa; 97bd670b35SErik Nordmark sin->sin_family = AF_INET; 98bd670b35SErik Nordmark IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &sin->sin_addr); 994b7cbb46SSowmini Varadhan } 1004b7cbb46SSowmini Varadhan if (ip2m->ip2mac_err == 0) { 1014b7cbb46SSowmini Varadhan sdl = &ip2m->ip2mac_ha; 1024b7cbb46SSowmini Varadhan sdl->sdl_family = AF_LINK; 103bd670b35SErik Nordmark sdl->sdl_type = ncec->ncec_ill->ill_type; 104bd670b35SErik Nordmark /* 105bd670b35SErik Nordmark * should we put ncec_ill->ill_name in there? why? 106bd670b35SErik Nordmark * likewise for the sdl_index 107bd670b35SErik Nordmark */ 1084b7cbb46SSowmini Varadhan sdl->sdl_nlen = 0; 109bd670b35SErik Nordmark sdl->sdl_alen = ncec->ncec_ill->ill_phys_addr_length; 110bd670b35SErik Nordmark if (ncec->ncec_lladdr != NULL) 111bd670b35SErik Nordmark bcopy(ncec->ncec_lladdr, LLADDR(sdl), sdl->sdl_alen); 1124b7cbb46SSowmini Varadhan } 1134b7cbb46SSowmini Varadhan } 1144b7cbb46SSowmini Varadhan 1154b7cbb46SSowmini Varadhan void 116bd670b35SErik Nordmark ncec_cb_refhold_locked(ncec_t *ncec) 1174b7cbb46SSowmini Varadhan { 118bd670b35SErik Nordmark ASSERT(MUTEX_HELD(&ncec->ncec_lock)); 119bd670b35SErik Nordmark ncec->ncec_cb_walker_cnt++; 1204b7cbb46SSowmini Varadhan } 1214b7cbb46SSowmini Varadhan 1224b7cbb46SSowmini Varadhan void 123bd670b35SErik Nordmark ncec_cb_refrele(ncec_t *ncec) 1244b7cbb46SSowmini Varadhan { 125bd670b35SErik Nordmark ncec_cb_t *ncec_cb, *ncec_cb_next = NULL; 1264b7cbb46SSowmini Varadhan 127bd670b35SErik Nordmark ASSERT(MUTEX_HELD(&ncec->ncec_lock)); 128bd670b35SErik Nordmark if (--ncec->ncec_cb_walker_cnt == 0) { 129bd670b35SErik Nordmark for (ncec_cb = list_head(&ncec->ncec_cb); ncec_cb != NULL; 130bd670b35SErik Nordmark ncec_cb = ncec_cb_next) { 1314b7cbb46SSowmini Varadhan 132bd670b35SErik Nordmark ncec_cb_next = list_next(&ncec->ncec_cb, ncec_cb); 133bd670b35SErik Nordmark if ((ncec_cb->ncec_cb_flags & NCE_CB_DISPATCHED) == 0) 1344b7cbb46SSowmini Varadhan continue; 135bd670b35SErik Nordmark list_remove(&ncec->ncec_cb, ncec_cb); 136bd670b35SErik Nordmark kmem_free(ncec_cb, sizeof (*ncec_cb)); 1374b7cbb46SSowmini Varadhan } 1384b7cbb46SSowmini Varadhan } 1394b7cbb46SSowmini Varadhan } 1404b7cbb46SSowmini Varadhan 1414b7cbb46SSowmini Varadhan /* 1424b7cbb46SSowmini Varadhan * add a callback to the nce, so that the callback can be invoked 1434b7cbb46SSowmini Varadhan * after address resolution succeeds/fails. 1444b7cbb46SSowmini Varadhan */ 1454b7cbb46SSowmini Varadhan static ip2mac_id_t 146bd670b35SErik Nordmark ncec_add_cb(ncec_t *ncec, ip2mac_callback_t *cb, void *cbarg) 1474b7cbb46SSowmini Varadhan { 148bd670b35SErik Nordmark ncec_cb_t *nce_cb; 1494b7cbb46SSowmini Varadhan ip2mac_id_t ip2mid = NULL; 1504b7cbb46SSowmini Varadhan 151bd670b35SErik Nordmark ASSERT(MUTEX_HELD(&ncec->ncec_lock)); 1524b7cbb46SSowmini Varadhan if ((nce_cb = kmem_zalloc(sizeof (*nce_cb), KM_NOSLEEP)) == NULL) 1534b7cbb46SSowmini Varadhan return (ip2mid); 154bd670b35SErik Nordmark nce_cb->ncec_cb_func = cb; 155bd670b35SErik Nordmark nce_cb->ncec_cb_arg = cbarg; 1564b7cbb46SSowmini Varadhan /* 157bd670b35SErik Nordmark * We identify the ncec_cb_t during cancellation by the address 1584b7cbb46SSowmini Varadhan * of the nce_cb_t itself, and, as a short-cut for eliminating 159bd670b35SErik Nordmark * clear mismatches, only look in the callback list of ncec's 1604b7cbb46SSowmini Varadhan * whose address is equal to the nce_cb_id. 1614b7cbb46SSowmini Varadhan */ 162bd670b35SErik Nordmark nce_cb->ncec_cb_id = ncec; /* no refs! just an address */ 163bd670b35SErik Nordmark list_insert_tail(&ncec->ncec_cb, nce_cb); 164bd670b35SErik Nordmark ip2mid = ncec; /* this is the id to be used in ip2mac_cancel */ 1654b7cbb46SSowmini Varadhan 1664b7cbb46SSowmini Varadhan return (nce_cb); 1674b7cbb46SSowmini Varadhan } 1684b7cbb46SSowmini Varadhan 1694b7cbb46SSowmini Varadhan /* 1704b7cbb46SSowmini Varadhan * Resolve an IP address to a link-layer address using the data-structures 1714b7cbb46SSowmini Varadhan * defined in PSARC 2006/482. If the current link-layer address for the 1724b7cbb46SSowmini Varadhan * IP address is not known, the state-machine for resolving the resolution 1734b7cbb46SSowmini Varadhan * will be triggered, and the callback function (*cb) will be invoked after 1744b7cbb46SSowmini Varadhan * the resolution completes. 1754b7cbb46SSowmini Varadhan */ 1764b7cbb46SSowmini Varadhan ip2mac_id_t 177bd670b35SErik Nordmark ip2mac(uint_t op, ip2mac_t *ip2m, ip2mac_callback_t *cb, void *cbarg, 1784b7cbb46SSowmini Varadhan zoneid_t zoneid) 1794b7cbb46SSowmini Varadhan { 180bd670b35SErik Nordmark ncec_t *ncec; 181bd670b35SErik Nordmark nce_t *nce = NULL; 1824b7cbb46SSowmini Varadhan boolean_t isv6; 1834b7cbb46SSowmini Varadhan ill_t *ill; 1844b7cbb46SSowmini Varadhan netstack_t *ns; 1854b7cbb46SSowmini Varadhan ip_stack_t *ipst; 1864b7cbb46SSowmini Varadhan ip2mac_id_t ip2mid = NULL; 187bd670b35SErik Nordmark sin_t *sin; 1884b7cbb46SSowmini Varadhan sin6_t *sin6; 1894b7cbb46SSowmini Varadhan int err; 1904b7cbb46SSowmini Varadhan uint64_t delta; 191bd670b35SErik Nordmark boolean_t need_resolve = B_FALSE; 1924b7cbb46SSowmini Varadhan 1934b7cbb46SSowmini Varadhan isv6 = (ip2m->ip2mac_pa.ss_family == AF_INET6); 1944b7cbb46SSowmini Varadhan 1954b7cbb46SSowmini Varadhan ns = netstack_find_by_zoneid(zoneid); 1964b7cbb46SSowmini Varadhan if (ns == NULL) { 1974b7cbb46SSowmini Varadhan ip2m->ip2mac_err = EINVAL; 1984b7cbb46SSowmini Varadhan return (NULL); 1994b7cbb46SSowmini Varadhan } 2004b7cbb46SSowmini Varadhan /* 2014b7cbb46SSowmini Varadhan * For exclusive stacks we reset the zoneid to zero 2024b7cbb46SSowmini Varadhan * since IP uses the global zoneid in the exclusive stacks. 2034b7cbb46SSowmini Varadhan */ 2044b7cbb46SSowmini Varadhan if (ns->netstack_stackid != GLOBAL_NETSTACKID) 2054b7cbb46SSowmini Varadhan zoneid = GLOBAL_ZONEID; 2064b7cbb46SSowmini Varadhan ipst = ns->netstack_ip; 2074b7cbb46SSowmini Varadhan /* 2084b7cbb46SSowmini Varadhan * find the ill from the ip2m->ip2mac_ifindex 2094b7cbb46SSowmini Varadhan */ 210bd670b35SErik Nordmark ill = ill_lookup_on_ifindex(ip2m->ip2mac_ifindex, isv6, ipst); 2114b7cbb46SSowmini Varadhan if (ill == NULL) { 2124b7cbb46SSowmini Varadhan ip2m->ip2mac_err = ENXIO; 2134b7cbb46SSowmini Varadhan netstack_rele(ns); 2144b7cbb46SSowmini Varadhan return (NULL); 2154b7cbb46SSowmini Varadhan } 2164b7cbb46SSowmini Varadhan if (isv6) { 2174b7cbb46SSowmini Varadhan sin6 = (sin6_t *)&ip2m->ip2mac_pa; 218bd670b35SErik Nordmark if (op == IP2MAC_LOOKUP) { 219bd670b35SErik Nordmark nce = nce_lookup_v6(ill, &sin6->sin6_addr); 2204b7cbb46SSowmini Varadhan } else { 221bd670b35SErik Nordmark err = nce_lookup_then_add_v6(ill, NULL, 222bd670b35SErik Nordmark ill->ill_phys_addr_length, 223bd670b35SErik Nordmark &sin6->sin6_addr, 0, ND_UNCHANGED, &nce); 2244b7cbb46SSowmini Varadhan } 2254b7cbb46SSowmini Varadhan } else { 226bd670b35SErik Nordmark sin = (sin_t *)&ip2m->ip2mac_pa; 227bd670b35SErik Nordmark if (op == IP2MAC_LOOKUP) { 228bd670b35SErik Nordmark nce = nce_lookup_v4(ill, &sin->sin_addr.s_addr); 229bd670b35SErik Nordmark } else { 230bd670b35SErik Nordmark err = nce_lookup_then_add_v4(ill, NULL, 231bd670b35SErik Nordmark ill->ill_phys_addr_length, 232bd670b35SErik Nordmark &sin->sin_addr.s_addr, 0, ND_UNCHANGED, &nce); 2334b7cbb46SSowmini Varadhan } 234bd670b35SErik Nordmark } 235bd670b35SErik Nordmark if (op == IP2MAC_LOOKUP) { 2364b7cbb46SSowmini Varadhan if (nce == NULL) { 2374b7cbb46SSowmini Varadhan ip2m->ip2mac_err = ESRCH; 2384b7cbb46SSowmini Varadhan goto done; 2394b7cbb46SSowmini Varadhan } 240bd670b35SErik Nordmark ncec = nce->nce_common; 241*d3d50737SRafael Vanoni delta = TICK_TO_MSEC(ddi_get_lbolt64()) - ncec->ncec_last; 242bd670b35SErik Nordmark mutex_enter(&ncec->ncec_lock); 243bd670b35SErik Nordmark if (NCE_ISREACHABLE(ncec) && 244bd670b35SErik Nordmark delta < (uint64_t)ill->ill_reachable_time) { 245bd670b35SErik Nordmark ncec_ip2mac_response(ip2m, ncec); 2464b7cbb46SSowmini Varadhan ip2m->ip2mac_err = 0; 2474b7cbb46SSowmini Varadhan } else { 2484b7cbb46SSowmini Varadhan ip2m->ip2mac_err = ESRCH; 2494b7cbb46SSowmini Varadhan } 250bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 2514b7cbb46SSowmini Varadhan goto done; 2524b7cbb46SSowmini Varadhan } else { 2534b7cbb46SSowmini Varadhan if (err != 0 && err != EEXIST) { 2544b7cbb46SSowmini Varadhan ip2m->ip2mac_err = err; 2554b7cbb46SSowmini Varadhan goto done; 2564b7cbb46SSowmini Varadhan } 2574b7cbb46SSowmini Varadhan } 258bd670b35SErik Nordmark ncec = nce->nce_common; 259*d3d50737SRafael Vanoni delta = TICK_TO_MSEC(ddi_get_lbolt64()) - ncec->ncec_last; 260bd670b35SErik Nordmark mutex_enter(&ncec->ncec_lock); 261bd670b35SErik Nordmark if (NCE_ISCONDEMNED(ncec)) { 2624b7cbb46SSowmini Varadhan ip2m->ip2mac_err = ESRCH; 263bd670b35SErik Nordmark } else { 264bd670b35SErik Nordmark if (NCE_ISREACHABLE(ncec)) { 265bd670b35SErik Nordmark if (NCE_MYADDR(ncec) || 266bd670b35SErik Nordmark delta < (uint64_t)ill->ill_reachable_time) { 267bd670b35SErik Nordmark ncec_ip2mac_response(ip2m, ncec); 268bd670b35SErik Nordmark ip2m->ip2mac_err = 0; 269bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 270bd670b35SErik Nordmark goto done; 271bd670b35SErik Nordmark } 2724b7cbb46SSowmini Varadhan /* 2734b7cbb46SSowmini Varadhan * Since we do not control the packet output 2744b7cbb46SSowmini Varadhan * path for ip2mac() callers, we need to verify 2754b7cbb46SSowmini Varadhan * if the existing information in the nce is 2764b7cbb46SSowmini Varadhan * very old, and retrigger resolution if necessary. 2774b7cbb46SSowmini Varadhan * We will not return the existing stale 2784b7cbb46SSowmini Varadhan * information until it is verified through a 2794b7cbb46SSowmini Varadhan * resolver request/response exchange. 2804b7cbb46SSowmini Varadhan * 2814b7cbb46SSowmini Varadhan * In the future, we may want to support extensions 2824b7cbb46SSowmini Varadhan * that do additional callbacks on link-layer updates, 2834b7cbb46SSowmini Varadhan * so that we can return the stale information but 2844b7cbb46SSowmini Varadhan * also update the caller if the lladdr changes. 2854b7cbb46SSowmini Varadhan */ 286bd670b35SErik Nordmark ncec->ncec_rcnt = ill->ill_xmit_count; 287bd670b35SErik Nordmark ncec->ncec_state = ND_PROBE; 288bd670b35SErik Nordmark need_resolve = B_TRUE; /* reachable but very old nce */ 289bd670b35SErik Nordmark } else if (ncec->ncec_state == ND_INITIAL) { 290bd670b35SErik Nordmark need_resolve = B_TRUE; /* ND_INITIAL nce */ 291bd670b35SErik Nordmark ncec->ncec_state = ND_INCOMPLETE; 2924b7cbb46SSowmini Varadhan } 2934b7cbb46SSowmini Varadhan /* 294bd670b35SErik Nordmark * NCE not known to be reachable in the recent past. We must 295bd670b35SErik Nordmark * reconfirm the information before returning it to the caller 2964b7cbb46SSowmini Varadhan */ 297bd670b35SErik Nordmark if (ncec->ncec_rcnt > 0) { 298bd670b35SErik Nordmark /* 299bd670b35SErik Nordmark * Still resolving this ncec, so we can queue the 300bd670b35SErik Nordmark * callback information in ncec->ncec_cb 301bd670b35SErik Nordmark */ 302bd670b35SErik Nordmark ip2mid = ncec_add_cb(ncec, cb, cbarg); 3034b7cbb46SSowmini Varadhan ip2m->ip2mac_err = EINPROGRESS; 3044b7cbb46SSowmini Varadhan } else { 3054b7cbb46SSowmini Varadhan /* 306bd670b35SErik Nordmark * No more retransmits allowed -- resolution failed. 3074b7cbb46SSowmini Varadhan */ 3084b7cbb46SSowmini Varadhan ip2m->ip2mac_err = ESRCH; 3094b7cbb46SSowmini Varadhan } 3104b7cbb46SSowmini Varadhan } 311bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 3124b7cbb46SSowmini Varadhan done: 313bd670b35SErik Nordmark /* 314bd670b35SErik Nordmark * if NCE_ISREACHABLE(ncec) but very old, or if it is ND_INITIAL, 315bd670b35SErik Nordmark * trigger resolve. 316bd670b35SErik Nordmark */ 317bd670b35SErik Nordmark if (need_resolve) 318bd670b35SErik Nordmark ip_ndp_resolve(ncec); 319bd670b35SErik Nordmark if (nce != NULL) 320bd670b35SErik Nordmark nce_refrele(nce); 3214b7cbb46SSowmini Varadhan netstack_rele(ns); 3224b7cbb46SSowmini Varadhan ill_refrele(ill); 3234b7cbb46SSowmini Varadhan return (ip2mid); 3244b7cbb46SSowmini Varadhan } 3254b7cbb46SSowmini Varadhan 3264b7cbb46SSowmini Varadhan /* 327bd670b35SErik Nordmark * data passed to ncec_walk for canceling outstanding callbacks. 3284b7cbb46SSowmini Varadhan */ 3294b7cbb46SSowmini Varadhan typedef struct ip2mac_cancel_data_s { 3304b7cbb46SSowmini Varadhan ip2mac_id_t ip2m_cancel_id; 3314b7cbb46SSowmini Varadhan int ip2m_cancel_err; 3324b7cbb46SSowmini Varadhan } ip2mac_cancel_data_t; 3334b7cbb46SSowmini Varadhan 3344b7cbb46SSowmini Varadhan /* 335bd670b35SErik Nordmark * callback invoked for each active ncec. If the ip2mac_id_t corresponds 336bd670b35SErik Nordmark * to an active nce_cb_t in the ncec's callback list, we want to remove 3374b7cbb46SSowmini Varadhan * the callback (if there are no walkers) or return EBUSY to the caller 3384b7cbb46SSowmini Varadhan */ 3394b7cbb46SSowmini Varadhan static int 340bd670b35SErik Nordmark ip2mac_cancel_callback(ncec_t *ncec, void *arg) 3414b7cbb46SSowmini Varadhan { 3424b7cbb46SSowmini Varadhan ip2mac_cancel_data_t *ip2m_wdata = arg; 343bd670b35SErik Nordmark ncec_cb_t *ip2m_nce_cb = ip2m_wdata->ip2m_cancel_id; 344bd670b35SErik Nordmark ncec_cb_t *ncec_cb; 3454b7cbb46SSowmini Varadhan 346bd670b35SErik Nordmark if (ip2m_nce_cb->ncec_cb_id != ncec) 3474b7cbb46SSowmini Varadhan return (0); 3484b7cbb46SSowmini Varadhan 349bd670b35SErik Nordmark mutex_enter(&ncec->ncec_lock); 350bd670b35SErik Nordmark if (list_is_empty(&ncec->ncec_cb)) { 351bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 3524b7cbb46SSowmini Varadhan return (0); 3534b7cbb46SSowmini Varadhan } 3544b7cbb46SSowmini Varadhan /* 3554b7cbb46SSowmini Varadhan * IP does not hold internal locks like nce_lock across calls to 3564b7cbb46SSowmini Varadhan * other subsystems for fear of recursive lock entry and lock 3574b7cbb46SSowmini Varadhan * hierarchy violation. The caller may be holding locks across 3584b7cbb46SSowmini Varadhan * the call to IP. (It would be ideal if no subsystem holds locks 3594b7cbb46SSowmini Varadhan * across calls into another subsystem, especially if calls can 3604b7cbb46SSowmini Varadhan * happen in either direction). 3614b7cbb46SSowmini Varadhan */ 362bd670b35SErik Nordmark ncec_cb = list_head(&ncec->ncec_cb); 363bd670b35SErik Nordmark for (; ncec_cb != NULL; ncec_cb = list_next(&ncec->ncec_cb, ncec_cb)) { 364bd670b35SErik Nordmark if (ncec_cb != ip2m_nce_cb) 3654b7cbb46SSowmini Varadhan continue; 3664b7cbb46SSowmini Varadhan /* 3674b7cbb46SSowmini Varadhan * If there are no walkers we can remove the nce_cb. 3684b7cbb46SSowmini Varadhan * Otherwise the exiting walker will clean up. 3694b7cbb46SSowmini Varadhan */ 370bd670b35SErik Nordmark if (ncec->ncec_cb_walker_cnt == 0) { 371bd670b35SErik Nordmark list_remove(&ncec->ncec_cb, ncec_cb); 3724b7cbb46SSowmini Varadhan } else { 3734b7cbb46SSowmini Varadhan ip2m_wdata->ip2m_cancel_err = EBUSY; 3744b7cbb46SSowmini Varadhan } 3754b7cbb46SSowmini Varadhan break; 3764b7cbb46SSowmini Varadhan } 377bd670b35SErik Nordmark mutex_exit(&ncec->ncec_lock); 3784b7cbb46SSowmini Varadhan return (0); 3794b7cbb46SSowmini Varadhan } 3804b7cbb46SSowmini Varadhan 3814b7cbb46SSowmini Varadhan /* 3824b7cbb46SSowmini Varadhan * cancel an outstanding timeout set up via ip2mac 3834b7cbb46SSowmini Varadhan */ 3844b7cbb46SSowmini Varadhan int 3854b7cbb46SSowmini Varadhan ip2mac_cancel(ip2mac_id_t ip2mid, zoneid_t zoneid) 3864b7cbb46SSowmini Varadhan { 3874b7cbb46SSowmini Varadhan netstack_t *ns; 3884b7cbb46SSowmini Varadhan ip_stack_t *ipst; 3894b7cbb46SSowmini Varadhan ip2mac_cancel_data_t ip2m_wdata; 3904b7cbb46SSowmini Varadhan 3914b7cbb46SSowmini Varadhan ns = netstack_find_by_zoneid(zoneid); 3924b7cbb46SSowmini Varadhan if (ns == NULL) { 3934b7cbb46SSowmini Varadhan ip2m_wdata.ip2m_cancel_err = EINVAL; 3944b7cbb46SSowmini Varadhan return (ip2m_wdata.ip2m_cancel_err); 3954b7cbb46SSowmini Varadhan } 3964b7cbb46SSowmini Varadhan /* 3974b7cbb46SSowmini Varadhan * For exclusive stacks we reset the zoneid to zero 3984b7cbb46SSowmini Varadhan * since IP uses the global zoneid in the exclusive stacks. 3994b7cbb46SSowmini Varadhan */ 4004b7cbb46SSowmini Varadhan if (ns->netstack_stackid != GLOBAL_NETSTACKID) 4014b7cbb46SSowmini Varadhan zoneid = GLOBAL_ZONEID; 4024b7cbb46SSowmini Varadhan ipst = ns->netstack_ip; 4034b7cbb46SSowmini Varadhan 4044b7cbb46SSowmini Varadhan ip2m_wdata.ip2m_cancel_id = ip2mid; 4054b7cbb46SSowmini Varadhan ip2m_wdata.ip2m_cancel_err = 0; 406bd670b35SErik Nordmark ncec_walk(NULL, ip2mac_cancel_callback, &ip2m_wdata, ipst); 4074b7cbb46SSowmini Varadhan /* 4084b7cbb46SSowmini Varadhan * We may return EBUSY if a walk to dispatch callbacks is 4094b7cbb46SSowmini Varadhan * in progress, in which case the caller needs to synchronize 4104b7cbb46SSowmini Varadhan * with the registered callback function to make sure the 4114b7cbb46SSowmini Varadhan * module does not exit when there is a callback pending. 4124b7cbb46SSowmini Varadhan */ 4134b7cbb46SSowmini Varadhan netstack_rele(ns); 4144b7cbb46SSowmini Varadhan return (ip2m_wdata.ip2m_cancel_err); 4154b7cbb46SSowmini Varadhan } 416