ip2mac.c (4b7cbb46) ip2mac.c (bd670b35)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 4 unchanged lines hidden (view full) ---

13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 4 unchanged lines hidden (view full) ---

13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
21/*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*
27 * Functions to implement IP address -> link layer address (PSARC 2006/482)
28 */
29#include <inet/ip2mac.h>
30#include <inet/ip2mac_impl.h>
31#include <sys/zone.h>
22/*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Functions to implement IP address -> link layer address (PSARC 2006/482)
29 */
30#include <inet/ip2mac.h>
31#include <inet/ip2mac_impl.h>
32#include <sys/zone.h>
32#include <sys/dlpi.h>
33#include <inet/ip_ndp.h>
34#include <inet/ip_if.h>
35#include <inet/ip6.h>
36
37/*
38 * dispatch pending callbacks.
39 */
40void
33#include <inet/ip_ndp.h>
34#include <inet/ip_if.h>
35#include <inet/ip6.h>
36
37/*
38 * dispatch pending callbacks.
39 */
40void
41nce_cb_dispatch(nce_t *nce)
41ncec_cb_dispatch(ncec_t *ncec)
42{
42{
43 nce_cb_t *nce_cb = list_head(&nce->nce_cb);
43 ncec_cb_t *ncec_cb;
44 ip2mac_t ip2m;
45
44 ip2mac_t ip2m;
45
46 mutex_enter(&nce->nce_lock);
47 if (list_is_empty(&nce->nce_cb)) {
48 mutex_exit(&nce->nce_lock);
46 mutex_enter(&ncec->ncec_lock);
47 if (list_is_empty(&ncec->ncec_cb)) {
48 mutex_exit(&ncec->ncec_lock);
49 return;
50 }
49 return;
50 }
51 nce_ip2mac_response(&ip2m, nce);
52 nce_cb_refhold_locked(nce);
51 ncec_ip2mac_response(&ip2m, ncec);
52 ncec_cb_refhold_locked(ncec);
53 /*
54 * IP does not hold internal locks like nce_lock across calls to
55 * other subsystems for fear of recursive lock entry and lock
56 * hierarchy violation. The caller may be holding locks across
57 * the call to IP. (It would be ideal if no subsystem holds locks
58 * across calls into another subsystem, especially if calls can
59 * happen in either direction).
60 */
53 /*
54 * IP does not hold internal locks like nce_lock across calls to
55 * other subsystems for fear of recursive lock entry and lock
56 * hierarchy violation. The caller may be holding locks across
57 * the call to IP. (It would be ideal if no subsystem holds locks
58 * across calls into another subsystem, especially if calls can
59 * happen in either direction).
60 */
61 nce_cb = list_head(&nce->nce_cb);
62 for (; nce_cb != NULL; nce_cb = list_next(&nce->nce_cb, nce_cb)) {
63 if (nce_cb->nce_cb_flags & NCE_CB_DISPATCHED)
61 ncec_cb = list_head(&ncec->ncec_cb);
62 for (; ncec_cb != NULL; ncec_cb = list_next(&ncec->ncec_cb, ncec_cb)) {
63 if (ncec_cb->ncec_cb_flags & NCE_CB_DISPATCHED)
64 continue;
64 continue;
65 nce_cb->nce_cb_flags |= NCE_CB_DISPATCHED;
66 mutex_exit(&nce->nce_lock);
67 (*nce_cb->nce_cb_func)(&ip2m, nce_cb->nce_cb_arg);
68 mutex_enter(&nce->nce_lock);
65 ncec_cb->ncec_cb_flags |= NCE_CB_DISPATCHED;
66 mutex_exit(&ncec->ncec_lock);
67 (*ncec_cb->ncec_cb_func)(&ip2m, ncec_cb->ncec_cb_arg);
68 mutex_enter(&ncec->ncec_lock);
69 }
69 }
70 nce_cb_refrele(nce);
71 mutex_exit(&nce->nce_lock);
70 ncec_cb_refrele(ncec);
71 mutex_exit(&ncec->ncec_lock);
72}
73
74/*
75 * fill up the ip2m response fields with inforamation from the nce.
76 */
77void
72}
73
74/*
75 * fill up the ip2m response fields with inforamation from the nce.
76 */
77void
78nce_ip2mac_response(ip2mac_t *ip2m, nce_t *nce)
78ncec_ip2mac_response(ip2mac_t *ip2m, ncec_t *ncec)
79{
79{
80 boolean_t isv6 = (nce->nce_ipversion == IPV6_VERSION);
80 boolean_t isv6 = (ncec->ncec_ipversion == IPV6_VERSION);
81 sin_t *sin;
81 sin6_t *sin6;
82 struct sockaddr_dl *sdl;
82 sin6_t *sin6;
83 struct sockaddr_dl *sdl;
83 uchar_t *nce_lladdr;
84
84
85 ASSERT(MUTEX_HELD(&nce->nce_lock));
85 ASSERT(MUTEX_HELD(&ncec->ncec_lock));
86 bzero(ip2m, sizeof (*ip2m));
86 bzero(ip2m, sizeof (*ip2m));
87 if (NCE_ISREACHABLE(nce) && (nce->nce_flags & NCE_F_CONDEMNED) == 0)
87 if (NCE_ISREACHABLE(ncec) && !NCE_ISCONDEMNED(ncec))
88 ip2m->ip2mac_err = 0;
89 else
90 ip2m->ip2mac_err = ESRCH;
91 if (isv6) {
92 sin6 = (sin6_t *)&ip2m->ip2mac_pa;
93 sin6->sin6_family = AF_INET6;
88 ip2m->ip2mac_err = 0;
89 else
90 ip2m->ip2mac_err = ESRCH;
91 if (isv6) {
92 sin6 = (sin6_t *)&ip2m->ip2mac_pa;
93 sin6->sin6_family = AF_INET6;
94 sin6->sin6_addr = nce->nce_addr;
94 sin6->sin6_addr = ncec->ncec_addr;
95 } else {
96 sin = (sin_t *)&ip2m->ip2mac_pa;
97 sin->sin_family = AF_INET;
98 IN6_V4MAPPED_TO_INADDR(&ncec->ncec_addr, &sin->sin_addr);
95 }
96 if (ip2m->ip2mac_err == 0) {
97 sdl = &ip2m->ip2mac_ha;
98 sdl->sdl_family = AF_LINK;
99 }
100 if (ip2m->ip2mac_err == 0) {
101 sdl = &ip2m->ip2mac_ha;
102 sdl->sdl_family = AF_LINK;
99 sdl->sdl_type = nce->nce_ill->ill_type;
103 sdl->sdl_type = ncec->ncec_ill->ill_type;
104 /*
105 * should we put ncec_ill->ill_name in there? why?
106 * likewise for the sdl_index
107 */
100 sdl->sdl_nlen = 0;
108 sdl->sdl_nlen = 0;
101 sdl->sdl_alen = nce->nce_ill->ill_phys_addr_length;
102 nce_lladdr = nce->nce_res_mp->b_rptr +
103 NCE_LL_ADDR_OFFSET(nce->nce_ill);
104 bcopy(nce_lladdr, LLADDR(sdl), sdl->sdl_alen);
109 sdl->sdl_alen = ncec->ncec_ill->ill_phys_addr_length;
110 if (ncec->ncec_lladdr != NULL)
111 bcopy(ncec->ncec_lladdr, LLADDR(sdl), sdl->sdl_alen);
105 }
106}
107
108void
112 }
113}
114
115void
109nce_cb_refhold_locked(nce_t *nce)
116ncec_cb_refhold_locked(ncec_t *ncec)
110{
117{
111 ASSERT(MUTEX_HELD(&nce->nce_lock));
112 nce->nce_cb_walker_cnt++;
118 ASSERT(MUTEX_HELD(&ncec->ncec_lock));
119 ncec->ncec_cb_walker_cnt++;
113}
114
115void
120}
121
122void
116nce_cb_refrele(nce_t *nce)
123ncec_cb_refrele(ncec_t *ncec)
117{
124{
118 nce_cb_t *nce_cb, *nce_cb_next = NULL;
125 ncec_cb_t *ncec_cb, *ncec_cb_next = NULL;
119
126
120 ASSERT(MUTEX_HELD(&nce->nce_lock));
121 if (--nce->nce_cb_walker_cnt == 0) {
122 for (nce_cb = list_head(&nce->nce_cb); nce_cb != NULL;
123 nce_cb = nce_cb_next) {
127 ASSERT(MUTEX_HELD(&ncec->ncec_lock));
128 if (--ncec->ncec_cb_walker_cnt == 0) {
129 for (ncec_cb = list_head(&ncec->ncec_cb); ncec_cb != NULL;
130 ncec_cb = ncec_cb_next) {
124
131
125 nce_cb_next = list_next(&nce->nce_cb, nce_cb);
126 if ((nce_cb->nce_cb_flags & NCE_CB_DISPATCHED) == 0)
132 ncec_cb_next = list_next(&ncec->ncec_cb, ncec_cb);
133 if ((ncec_cb->ncec_cb_flags & NCE_CB_DISPATCHED) == 0)
127 continue;
134 continue;
128 list_remove(&nce->nce_cb, nce_cb);
129 kmem_free(nce_cb, sizeof (*nce_cb));
135 list_remove(&ncec->ncec_cb, ncec_cb);
136 kmem_free(ncec_cb, sizeof (*ncec_cb));
130 }
131 }
132}
133
134/*
135 * add a callback to the nce, so that the callback can be invoked
136 * after address resolution succeeds/fails.
137 */
138static ip2mac_id_t
137 }
138 }
139}
140
141/*
142 * add a callback to the nce, so that the callback can be invoked
143 * after address resolution succeeds/fails.
144 */
145static ip2mac_id_t
139nce_add_cb(nce_t *nce, ip2mac_callback_t *cb, void *cbarg)
146ncec_add_cb(ncec_t *ncec, ip2mac_callback_t *cb, void *cbarg)
140{
147{
141 nce_cb_t *nce_cb;
148 ncec_cb_t *nce_cb;
142 ip2mac_id_t ip2mid = NULL;
143
149 ip2mac_id_t ip2mid = NULL;
150
144 ASSERT(MUTEX_HELD(&nce->nce_lock));
151 ASSERT(MUTEX_HELD(&ncec->ncec_lock));
145 if ((nce_cb = kmem_zalloc(sizeof (*nce_cb), KM_NOSLEEP)) == NULL)
146 return (ip2mid);
152 if ((nce_cb = kmem_zalloc(sizeof (*nce_cb), KM_NOSLEEP)) == NULL)
153 return (ip2mid);
147 nce_cb->nce_cb_func = cb;
148 nce_cb->nce_cb_arg = cbarg;
154 nce_cb->ncec_cb_func = cb;
155 nce_cb->ncec_cb_arg = cbarg;
149 /*
156 /*
150 * We identify the nce_cb_t during cancellation by the address
157 * We identify the ncec_cb_t during cancellation by the address
151 * of the nce_cb_t itself, and, as a short-cut for eliminating
158 * of the nce_cb_t itself, and, as a short-cut for eliminating
152 * clear mismatches, only look in the callback list of nce's
159 * clear mismatches, only look in the callback list of ncec's
153 * whose address is equal to the nce_cb_id.
154 */
160 * whose address is equal to the nce_cb_id.
161 */
155 nce_cb->nce_cb_id = nce; /* no refs! just an address */
156 list_insert_tail(&nce->nce_cb, nce_cb);
157 ip2mid = nce; /* this is the id to be used in ip2mac_cancel */
162 nce_cb->ncec_cb_id = ncec; /* no refs! just an address */
163 list_insert_tail(&ncec->ncec_cb, nce_cb);
164 ip2mid = ncec; /* this is the id to be used in ip2mac_cancel */
158
159 return (nce_cb);
160}
161
162/*
163 * Resolve an IP address to a link-layer address using the data-structures
164 * defined in PSARC 2006/482. If the current link-layer address for the
165 * IP address is not known, the state-machine for resolving the resolution
166 * will be triggered, and the callback function (*cb) will be invoked after
167 * the resolution completes.
168 */
169ip2mac_id_t
165
166 return (nce_cb);
167}
168
169/*
170 * Resolve an IP address to a link-layer address using the data-structures
171 * defined in PSARC 2006/482. If the current link-layer address for the
172 * IP address is not known, the state-machine for resolving the resolution
173 * will be triggered, and the callback function (*cb) will be invoked after
174 * the resolution completes.
175 */
176ip2mac_id_t
170ip2mac(uint_t flags, ip2mac_t *ip2m, ip2mac_callback_t *cb, void *cbarg,
177ip2mac(uint_t op, ip2mac_t *ip2m, ip2mac_callback_t *cb, void *cbarg,
171 zoneid_t zoneid)
172{
178 zoneid_t zoneid)
179{
173 nce_t *nce;
180 ncec_t *ncec;
181 nce_t *nce = NULL;
174 boolean_t isv6;
175 ill_t *ill;
176 netstack_t *ns;
177 ip_stack_t *ipst;
178 ip2mac_id_t ip2mid = NULL;
182 boolean_t isv6;
183 ill_t *ill;
184 netstack_t *ns;
185 ip_stack_t *ipst;
186 ip2mac_id_t ip2mid = NULL;
187 sin_t *sin;
179 sin6_t *sin6;
180 int err;
181 uint64_t delta;
188 sin6_t *sin6;
189 int err;
190 uint64_t delta;
191 boolean_t need_resolve = B_FALSE;
182
183 isv6 = (ip2m->ip2mac_pa.ss_family == AF_INET6);
184
192
193 isv6 = (ip2m->ip2mac_pa.ss_family == AF_INET6);
194
185 if (!isv6) {
186 /*
187 * IPv4 is not currently supported.
188 */
189 ip2m->ip2mac_err = ENOTSUP;
190 return (NULL);
191 }
192
193 ns = netstack_find_by_zoneid(zoneid);
194 if (ns == NULL) {
195 ip2m->ip2mac_err = EINVAL;
196 return (NULL);
197 }
198 /*
199 * For exclusive stacks we reset the zoneid to zero
200 * since IP uses the global zoneid in the exclusive stacks.
201 */
202 if (ns->netstack_stackid != GLOBAL_NETSTACKID)
203 zoneid = GLOBAL_ZONEID;
204 ipst = ns->netstack_ip;
205 /*
206 * find the ill from the ip2m->ip2mac_ifindex
207 */
195 ns = netstack_find_by_zoneid(zoneid);
196 if (ns == NULL) {
197 ip2m->ip2mac_err = EINVAL;
198 return (NULL);
199 }
200 /*
201 * For exclusive stacks we reset the zoneid to zero
202 * since IP uses the global zoneid in the exclusive stacks.
203 */
204 if (ns->netstack_stackid != GLOBAL_NETSTACKID)
205 zoneid = GLOBAL_ZONEID;
206 ipst = ns->netstack_ip;
207 /*
208 * find the ill from the ip2m->ip2mac_ifindex
209 */
208 ill = ill_lookup_on_ifindex(ip2m->ip2mac_ifindex, isv6, NULL,
209 NULL, NULL, NULL, ipst);
210 ill = ill_lookup_on_ifindex(ip2m->ip2mac_ifindex, isv6, ipst);
210 if (ill == NULL) {
211 ip2m->ip2mac_err = ENXIO;
212 netstack_rele(ns);
213 return (NULL);
214 }
215 if (isv6) {
216 sin6 = (sin6_t *)&ip2m->ip2mac_pa;
211 if (ill == NULL) {
212 ip2m->ip2mac_err = ENXIO;
213 netstack_rele(ns);
214 return (NULL);
215 }
216 if (isv6) {
217 sin6 = (sin6_t *)&ip2m->ip2mac_pa;
217 if (flags == IP2MAC_LOOKUP) {
218 nce = ndp_lookup_v6(ill, B_FALSE, &sin6->sin6_addr,
219 B_FALSE);
218 if (op == IP2MAC_LOOKUP) {
219 nce = nce_lookup_v6(ill, &sin6->sin6_addr);
220 } else {
220 } else {
221 err = ndp_lookup_then_add_v6(ill, B_FALSE, NULL,
222 &sin6->sin6_addr, &ipv6_all_ones, &ipv6_all_zeros,
223 0, 0, ND_INCOMPLETE, &nce);
221 err = nce_lookup_then_add_v6(ill, NULL,
222 ill->ill_phys_addr_length,
223 &sin6->sin6_addr, 0, ND_UNCHANGED, &nce);
224 }
225 } else {
224 }
225 } else {
226 ip2m->ip2mac_err = ENOTSUP; /* yet. */
227 goto done;
226 sin = (sin_t *)&ip2m->ip2mac_pa;
227 if (op == IP2MAC_LOOKUP) {
228 nce = nce_lookup_v4(ill, &sin->sin_addr.s_addr);
229 } else {
230 err = nce_lookup_then_add_v4(ill, NULL,
231 ill->ill_phys_addr_length,
232 &sin->sin_addr.s_addr, 0, ND_UNCHANGED, &nce);
233 }
228 }
234 }
229 if (flags == IP2MAC_LOOKUP) {
235 if (op == IP2MAC_LOOKUP) {
230 if (nce == NULL) {
231 ip2m->ip2mac_err = ESRCH;
232 goto done;
233 }
236 if (nce == NULL) {
237 ip2m->ip2mac_err = ESRCH;
238 goto done;
239 }
234 mutex_enter(&nce->nce_lock);
235 if (NCE_ISREACHABLE(nce)) {
236 nce_ip2mac_response(ip2m, nce);
240 ncec = nce->nce_common;
241 delta = TICK_TO_MSEC(lbolt64) - ncec->ncec_last;
242 mutex_enter(&ncec->ncec_lock);
243 if (NCE_ISREACHABLE(ncec) &&
244 delta < (uint64_t)ill->ill_reachable_time) {
245 ncec_ip2mac_response(ip2m, ncec);
237 ip2m->ip2mac_err = 0;
238 } else {
239 ip2m->ip2mac_err = ESRCH;
240 }
246 ip2m->ip2mac_err = 0;
247 } else {
248 ip2m->ip2mac_err = ESRCH;
249 }
241 mutex_exit(&nce->nce_lock);
242 NCE_REFRELE(nce);
250 mutex_exit(&ncec->ncec_lock);
243 goto done;
244 } else {
245 if (err != 0 && err != EEXIST) {
246 ip2m->ip2mac_err = err;
247 goto done;
248 }
249 }
251 goto done;
252 } else {
253 if (err != 0 && err != EEXIST) {
254 ip2m->ip2mac_err = err;
255 goto done;
256 }
257 }
250 delta = TICK_TO_MSEC(lbolt64) - nce->nce_last;
251 mutex_enter(&nce->nce_lock);
252 if (nce->nce_flags & NCE_F_CONDEMNED) {
258 ncec = nce->nce_common;
259 delta = TICK_TO_MSEC(lbolt64) - ncec->ncec_last;
260 mutex_enter(&ncec->ncec_lock);
261 if (NCE_ISCONDEMNED(ncec)) {
253 ip2m->ip2mac_err = ESRCH;
262 ip2m->ip2mac_err = ESRCH;
254 } else if (!NCE_ISREACHABLE(nce) ||
255 delta > (uint64_t)ill->ill_reachable_time) {
256 if (NCE_ISREACHABLE(nce)) {
263 } else {
264 if (NCE_ISREACHABLE(ncec)) {
265 if (NCE_MYADDR(ncec) ||
266 delta < (uint64_t)ill->ill_reachable_time) {
267 ncec_ip2mac_response(ip2m, ncec);
268 ip2m->ip2mac_err = 0;
269 mutex_exit(&ncec->ncec_lock);
270 goto done;
271 }
257 /*
258 * Since we do not control the packet output
259 * path for ip2mac() callers, we need to verify
260 * if the existing information in the nce is
261 * very old, and retrigger resolution if necessary.
262 * We will not return the existing stale
263 * information until it is verified through a
264 * resolver request/response exchange.
265 *
266 * In the future, we may want to support extensions
267 * that do additional callbacks on link-layer updates,
268 * so that we can return the stale information but
269 * also update the caller if the lladdr changes.
270 */
272 /*
273 * Since we do not control the packet output
274 * path for ip2mac() callers, we need to verify
275 * if the existing information in the nce is
276 * very old, and retrigger resolution if necessary.
277 * We will not return the existing stale
278 * information until it is verified through a
279 * resolver request/response exchange.
280 *
281 * In the future, we may want to support extensions
282 * that do additional callbacks on link-layer updates,
283 * so that we can return the stale information but
284 * also update the caller if the lladdr changes.
285 */
271 nce->nce_rcnt = ill->ill_xmit_count;
272 nce->nce_state = ND_PROBE;
273 err = 0; /* treat this nce as a new one */
286 ncec->ncec_rcnt = ill->ill_xmit_count;
287 ncec->ncec_state = ND_PROBE;
288 need_resolve = B_TRUE; /* reachable but very old nce */
289 } else if (ncec->ncec_state == ND_INITIAL) {
290 need_resolve = B_TRUE; /* ND_INITIAL nce */
291 ncec->ncec_state = ND_INCOMPLETE;
274 }
292 }
275 if (nce->nce_rcnt > 0) {
293 /*
294 * NCE not known to be reachable in the recent past. We must
295 * reconfirm the information before returning it to the caller
296 */
297 if (ncec->ncec_rcnt > 0) {
276 /*
298 /*
277 * Still resolving this nce, so we can
278 * queue the callback information in nce->nce_cb
299 * Still resolving this ncec, so we can queue the
300 * callback information in ncec->ncec_cb
279 */
301 */
280 ip2mid = nce_add_cb(nce, cb, cbarg);
302 ip2mid = ncec_add_cb(ncec, cb, cbarg);
281 ip2m->ip2mac_err = EINPROGRESS;
282 } else {
283 /*
303 ip2m->ip2mac_err = EINPROGRESS;
304 } else {
305 /*
284 * Resolution failed.
306 * No more retransmits allowed -- resolution failed.
285 */
286 ip2m->ip2mac_err = ESRCH;
287 }
307 */
308 ip2m->ip2mac_err = ESRCH;
309 }
288 } else {
289 nce_ip2mac_response(ip2m, nce);
290 ip2m->ip2mac_err = 0;
291 }
310 }
292 if (ip2m->ip2mac_err == EINPROGRESS && err != EEXIST)
293 ip_ndp_resolve(nce);
294 mutex_exit(&nce->nce_lock);
295 NCE_REFRELE(nce);
311 mutex_exit(&ncec->ncec_lock);
296done:
312done:
313 /*
314 * if NCE_ISREACHABLE(ncec) but very old, or if it is ND_INITIAL,
315 * trigger resolve.
316 */
317 if (need_resolve)
318 ip_ndp_resolve(ncec);
319 if (nce != NULL)
320 nce_refrele(nce);
297 netstack_rele(ns);
298 ill_refrele(ill);
299 return (ip2mid);
300}
301
302/*
321 netstack_rele(ns);
322 ill_refrele(ill);
323 return (ip2mid);
324}
325
326/*
303 * data passed to nce_walk for canceling outstanding callbacks.
327 * data passed to ncec_walk for canceling outstanding callbacks.
304 */
305typedef struct ip2mac_cancel_data_s {
306 ip2mac_id_t ip2m_cancel_id;
307 int ip2m_cancel_err;
308} ip2mac_cancel_data_t;
309
310/*
328 */
329typedef struct ip2mac_cancel_data_s {
330 ip2mac_id_t ip2m_cancel_id;
331 int ip2m_cancel_err;
332} ip2mac_cancel_data_t;
333
334/*
311 * callback invoked for each active nce. If the ip2mac_id_t corresponds
312 * to an active nce_cb_t in the nce's callback list, we want to remove
335 * callback invoked for each active ncec. If the ip2mac_id_t corresponds
336 * to an active nce_cb_t in the ncec's callback list, we want to remove
313 * the callback (if there are no walkers) or return EBUSY to the caller
314 */
315static int
337 * the callback (if there are no walkers) or return EBUSY to the caller
338 */
339static int
316ip2mac_cancel_callback(nce_t *nce, void *arg)
340ip2mac_cancel_callback(ncec_t *ncec, void *arg)
317{
318 ip2mac_cancel_data_t *ip2m_wdata = arg;
341{
342 ip2mac_cancel_data_t *ip2m_wdata = arg;
319 nce_cb_t *ip2m_nce_cb = ip2m_wdata->ip2m_cancel_id;
320 nce_cb_t *nce_cb;
343 ncec_cb_t *ip2m_nce_cb = ip2m_wdata->ip2m_cancel_id;
344 ncec_cb_t *ncec_cb;
321
345
322 if (ip2m_nce_cb->nce_cb_id != nce)
346 if (ip2m_nce_cb->ncec_cb_id != ncec)
323 return (0);
324
347 return (0);
348
325 mutex_enter(&nce->nce_lock);
326 if (list_is_empty(&nce->nce_cb)) {
327 mutex_exit(&nce->nce_lock);
349 mutex_enter(&ncec->ncec_lock);
350 if (list_is_empty(&ncec->ncec_cb)) {
351 mutex_exit(&ncec->ncec_lock);
328 return (0);
329 }
330 /*
331 * IP does not hold internal locks like nce_lock across calls to
332 * other subsystems for fear of recursive lock entry and lock
333 * hierarchy violation. The caller may be holding locks across
334 * the call to IP. (It would be ideal if no subsystem holds locks
335 * across calls into another subsystem, especially if calls can
336 * happen in either direction).
337 */
352 return (0);
353 }
354 /*
355 * IP does not hold internal locks like nce_lock across calls to
356 * other subsystems for fear of recursive lock entry and lock
357 * hierarchy violation. The caller may be holding locks across
358 * the call to IP. (It would be ideal if no subsystem holds locks
359 * across calls into another subsystem, especially if calls can
360 * happen in either direction).
361 */
338 nce_cb = list_head(&nce->nce_cb);
339 for (; nce_cb != NULL; nce_cb = list_next(&nce->nce_cb, nce_cb)) {
340 if (nce_cb != ip2m_nce_cb)
362 ncec_cb = list_head(&ncec->ncec_cb);
363 for (; ncec_cb != NULL; ncec_cb = list_next(&ncec->ncec_cb, ncec_cb)) {
364 if (ncec_cb != ip2m_nce_cb)
341 continue;
342 /*
343 * If there are no walkers we can remove the nce_cb.
344 * Otherwise the exiting walker will clean up.
345 */
365 continue;
366 /*
367 * If there are no walkers we can remove the nce_cb.
368 * Otherwise the exiting walker will clean up.
369 */
346 if (nce->nce_cb_walker_cnt == 0) {
347 list_remove(&nce->nce_cb, nce_cb);
370 if (ncec->ncec_cb_walker_cnt == 0) {
371 list_remove(&ncec->ncec_cb, ncec_cb);
348 } else {
349 ip2m_wdata->ip2m_cancel_err = EBUSY;
350 }
351 break;
352 }
372 } else {
373 ip2m_wdata->ip2m_cancel_err = EBUSY;
374 }
375 break;
376 }
353 mutex_exit(&nce->nce_lock);
377 mutex_exit(&ncec->ncec_lock);
354 return (0);
355}
356
357/*
358 * cancel an outstanding timeout set up via ip2mac
359 */
360int
361ip2mac_cancel(ip2mac_id_t ip2mid, zoneid_t zoneid)

--- 12 unchanged lines hidden (view full) ---

374 * since IP uses the global zoneid in the exclusive stacks.
375 */
376 if (ns->netstack_stackid != GLOBAL_NETSTACKID)
377 zoneid = GLOBAL_ZONEID;
378 ipst = ns->netstack_ip;
379
380 ip2m_wdata.ip2m_cancel_id = ip2mid;
381 ip2m_wdata.ip2m_cancel_err = 0;
378 return (0);
379}
380
381/*
382 * cancel an outstanding timeout set up via ip2mac
383 */
384int
385ip2mac_cancel(ip2mac_id_t ip2mid, zoneid_t zoneid)

--- 12 unchanged lines hidden (view full) ---

398 * since IP uses the global zoneid in the exclusive stacks.
399 */
400 if (ns->netstack_stackid != GLOBAL_NETSTACKID)
401 zoneid = GLOBAL_ZONEID;
402 ipst = ns->netstack_ip;
403
404 ip2m_wdata.ip2m_cancel_id = ip2mid;
405 ip2m_wdata.ip2m_cancel_err = 0;
382 ndp_walk(NULL, ip2mac_cancel_callback, &ip2m_wdata, ipst);
406 ncec_walk(NULL, ip2mac_cancel_callback, &ip2m_wdata, ipst);
383 /*
384 * We may return EBUSY if a walk to dispatch callbacks is
385 * in progress, in which case the caller needs to synchronize
386 * with the registered callback function to make sure the
387 * module does not exit when there is a callback pending.
388 */
389 netstack_rele(ns);
390 return (ip2m_wdata.ip2m_cancel_err);
391}
407 /*
408 * We may return EBUSY if a walk to dispatch callbacks is
409 * in progress, in which case the caller needs to synchronize
410 * with the registered callback function to make sure the
411 * module does not exit when there is a callback pending.
412 */
413 netstack_rele(ns);
414 return (ip2m_wdata.ip2m_cancel_err);
415}