9242 st: this statement may fall through
[unleashed.git] / usr / src / uts / common / io / neti_impl.c
blob05f2549dd74f3bcfbc664241937daae27e5f6277
1 /*
2 * CDDL HEADER START
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.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/param.h>
27 #include <sys/atomic.h>
28 #include <sys/kmem.h>
29 #include <sys/rwlock.h>
30 #include <sys/errno.h>
31 #include <sys/queue.h>
32 #include <inet/common.h>
33 #include <inet/led.h>
34 #include <inet/ip.h>
35 #include <sys/neti.h>
36 #include <sys/zone.h>
38 static net_handle_t net_find(const char *protocol, neti_stack_t *ns);
40 static net_handle_t
41 net_find(const char *protocol, neti_stack_t *nts)
43 struct net_data *n;
45 ASSERT(protocol != NULL);
46 ASSERT(nts != NULL);
48 LIST_FOREACH(n, &nts->nts_netd_head, netd_list) {
49 ASSERT(n->netd_info.netp_name != NULL);
51 * If they're trying to find a protocol that is being
52 * shutdown, just ignore it..
54 if (n->netd_condemned != 0)
55 continue;
56 if (strcmp(n->netd_info.netp_name, protocol) == 0) {
57 break;
61 return (n);
64 net_handle_t
65 net_protocol_register(netid_t id, const net_protocol_t *info)
67 struct net_data *n, *new;
68 neti_stack_t *nts;
70 ASSERT(info != NULL);
72 nts = net_getnetistackbyid(id);
73 if (nts == NULL)
74 return (NULL);
76 new = kmem_alloc(sizeof (*new), KM_SLEEP);
77 new->netd_refcnt = 1;
78 new->netd_hooks = NULL;
79 new->netd_info = *info;
80 new->netd_stack = nts;
81 new->netd_condemned = 0;
83 mutex_enter(&nts->nts_lock);
84 n = net_find(info->netp_name, nts);
85 if (n != NULL) {
86 mutex_exit(&nts->nts_lock);
87 kmem_free(new, sizeof (*new));
88 return (NULL);
91 if (LIST_EMPTY(&nts->nts_netd_head)) {
92 LIST_INSERT_HEAD(&nts->nts_netd_head, new, netd_list);
93 } else {
94 LIST_INSERT_AFTER(LIST_FIRST(&nts->nts_netd_head),
95 new, netd_list);
97 mutex_exit(&nts->nts_lock);
99 return (new);
103 net_protocol_unregister(net_handle_t info)
105 neti_stack_t *nts;
107 ASSERT(info != NULL);
109 nts = info->netd_stack;
110 ASSERT(nts != NULL);
112 mutex_enter(&nts->nts_lock);
113 LIST_REMOVE(info, netd_list);
114 info->netd_stack = NULL;
115 mutex_exit(&nts->nts_lock);
117 (void) net_protocol_release(info);
119 return (0);
122 net_handle_t
123 net_protocol_lookup(netid_t netid, const char *protocol)
125 neti_stack_t *nts;
126 net_handle_t nd;
128 ASSERT(protocol != NULL);
130 nts = net_getnetistackbyid(netid);
131 if (nts == NULL)
132 return (NULL);
134 mutex_enter(&nts->nts_lock);
135 nd = net_find(protocol, nts);
136 if (nd != NULL)
137 atomic_inc_32((uint_t *)&nd->netd_refcnt);
138 mutex_exit(&nts->nts_lock);
139 return (nd);
143 * Note: the man page specifies "returns -1 if the value passed in is unknown
144 * to this framework". We are not doing a lookup in this function, just a
145 * simply add to the netd_refcnt of the net_handle_t passed in, so -1 is never a
146 * return value.
149 net_protocol_release(net_handle_t info)
152 ASSERT(info->netd_refcnt > 0);
154 * Is this safe? No hold on nts_lock? Consider that if the caller
155 * of net_protocol_release() is going to free this structure then
156 * it is now the only owner (refcnt==1) and it will have been
157 * removed from the nts_netd_head list on the neti_stack_t from a
158 * call to net_protocol_unregister already, so it is thus an orphan.
160 if (atomic_dec_32_nv((uint_t *)&info->netd_refcnt) == 0) {
161 ASSERT(info->netd_hooks == NULL);
162 ASSERT(info->netd_stack == NULL);
163 kmem_free(info, sizeof (struct net_data));
166 return (0);
169 net_handle_t
170 net_protocol_walk(netid_t netid, net_handle_t info)
172 struct net_data *n = NULL;
173 boolean_t found = B_FALSE;
174 neti_stack_t *nts;
176 nts = net_getnetistackbyid(netid);
177 ASSERT(nts != NULL);
179 if (info == NULL)
180 found = B_TRUE;
182 mutex_enter(&nts->nts_lock);
183 LIST_FOREACH(n, &nts->nts_netd_head, netd_list) {
184 if (found) {
186 * We are only interested in finding protocols that
187 * are not in some sort of shutdown state. There is
188 * no need to check for netd_stack==NULL because
189 * that implies it is no longer on this list.
191 if (n->netd_condemned == 0)
192 continue;
193 break;
196 if (n == info)
197 found = B_TRUE;
200 if (info != NULL)
201 (void) net_protocol_release(info);
203 if (n != NULL)
204 atomic_inc_32((uint_t *)&n->netd_refcnt);
206 mutex_exit(&nts->nts_lock);
208 return (n);
212 * Public accessor functions
215 net_getifname(net_handle_t info, phy_if_t nic, char *buffer,
216 const size_t buflen)
219 ASSERT(info != NULL);
221 if (info->netd_condemned != 0 || info->netd_stack == NULL)
222 return (-1);
224 return (info->netd_info.netp_getifname(info, nic, buffer, buflen));
228 net_getmtu(net_handle_t info, phy_if_t nic, lif_if_t ifdata)
231 ASSERT(info != NULL);
233 if (info->netd_condemned != 0 || info->netd_stack == NULL)
234 return (-1);
236 return (info->netd_info.netp_getmtu(info, nic, ifdata));
240 net_getpmtuenabled(net_handle_t info)
243 ASSERT(info != NULL);
245 if (info->netd_condemned != 0 || info->netd_stack == NULL)
246 return (-1);
248 return (info->netd_info.netp_getpmtuenabled(info));
252 net_getlifaddr(net_handle_t info, phy_if_t nic, lif_if_t ifdata,
253 int nelem, net_ifaddr_t type[], void *storage)
256 ASSERT(info != NULL);
258 if (info->netd_condemned != 0 || info->netd_stack == NULL)
259 return (-1);
261 return (info->netd_info.netp_getlifaddr(info, nic, ifdata,
262 nelem, type, storage));
266 net_getlifzone(net_handle_t info, phy_if_t phy_ifdata, lif_if_t ifdata,
267 zoneid_t *zoneid)
269 ASSERT(info != NULL);
271 if (info->netd_condemned != 0 || info->netd_stack == NULL)
272 return (-1);
274 return (info->netd_info.neti_getlifzone(info, phy_ifdata, ifdata,
275 zoneid));
279 net_getlifflags(net_handle_t info, phy_if_t phy_ifdata, lif_if_t ifdata,
280 uint64_t *flags)
282 ASSERT(info != NULL);
284 if (info->netd_condemned != 0 || info->netd_stack == NULL)
285 return (-1);
287 return (info->netd_info.neti_getlifflags(info, phy_ifdata, ifdata,
288 flags));
291 phy_if_t
292 net_phygetnext(net_handle_t info, phy_if_t nic)
295 ASSERT(info != NULL);
297 if (info->netd_condemned != 0 || info->netd_stack == NULL)
298 return ((phy_if_t)-1);
300 return (info->netd_info.netp_phygetnext(info, nic));
303 phy_if_t
304 net_phylookup(net_handle_t info, const char *name)
307 ASSERT(info != NULL);
309 if (info->netd_condemned != 0 || info->netd_stack == NULL)
310 return ((phy_if_t)-1);
312 return (info->netd_info.netp_phylookup(info, name));
315 lif_if_t
316 net_lifgetnext(net_handle_t info, phy_if_t ifidx, lif_if_t ifdata)
319 ASSERT(info != NULL);
321 if (info->netd_condemned != 0 || info->netd_stack == NULL)
322 return ((lif_if_t)-1);
324 return (info->netd_info.netp_lifgetnext(info, ifidx, ifdata));
328 net_inject(net_handle_t info, inject_t style, net_inject_t *packet)
331 ASSERT(info != NULL);
333 if (info->netd_condemned != 0 || info->netd_stack == NULL)
334 return (-1);
336 return (info->netd_info.netp_inject(info, style, packet));
339 phy_if_t
340 net_routeto(net_handle_t info, struct sockaddr *address, struct sockaddr *next)
343 ASSERT(info != NULL);
345 if (info->netd_condemned != 0 || info->netd_stack == NULL)
346 return ((phy_if_t)-1);
348 return (info->netd_info.netp_routeto(info, address, next));
352 net_ispartialchecksum(net_handle_t info, mblk_t *mp)
355 ASSERT(info != NULL);
356 ASSERT(mp != NULL);
358 if (info->netd_condemned != 0 || info->netd_stack == NULL)
359 return (-1);
361 return (info->netd_info.netp_ispartialchecksum(info, mp));
365 net_isvalidchecksum(net_handle_t info, mblk_t *mp)
368 ASSERT(info != NULL);
369 ASSERT(mp != NULL);
371 if (info->netd_condemned != 0 || info->netd_stack == NULL)
372 return (-1);
374 return (info->netd_info.netp_isvalidchecksum(info, mp));
378 * Hooks related functions
382 * Function: net_family_register
383 * Returns: int - 0 = Succ, Else = Fail
384 * Parameters: info(I) - protocol
385 * hf(I) - family pointer
387 * Call hook_family_add to register family
389 * There is no need to bump netd_refcnt in the two functions
390 * net_family_register and net_family_unregister because the caller of these
391 * two functions is assumed to "own" a reference on 'info' via an earlier
392 * call to net_protocol_register(). Thus the owner is expected to do a
393 * call to net_protocol_unregister() after having done a
394 * net_family_unregister() to make sure things are properly cleaned up.
395 * Passing a pointer to info->netd_hooks into hook_family_add is required
396 * so that this can be set before the notify functions are called. If this
397 * does not happen, the notify function may do something that seems fine,
398 * like add a notify function to the family but cause a panic because
399 * netd_hooks is NULL when we get to hook_family_notify_register.
402 net_family_register(net_handle_t info, hook_family_t *hf)
404 netstack_t *ns;
406 ASSERT(info != NULL);
407 ASSERT(hf != NULL);
409 if (info->netd_condemned != 0 || info->netd_stack == NULL)
410 return (ESHUTDOWN);
412 if (info->netd_hooks != NULL)
413 return (EEXIST);
415 ns = info->netd_stack->nts_netstack;
416 ASSERT(ns != NULL);
417 if (hook_family_add(hf, ns->netstack_hook,
418 (void **)&info->netd_hooks) == NULL)
419 return (EEXIST);
421 return (0);
425 * Function: net_family_unregister
426 * Returns: int - transparent value, explained by caller
427 * Parameters: info(I) - protocol
428 * hf(I) - family pointer
430 * Call hook_family_remove to unregister family
433 net_family_unregister(net_handle_t info, hook_family_t *hf)
435 int ret;
437 ASSERT(info != NULL);
438 ASSERT(hf != NULL);
440 if (info->netd_hooks == NULL)
441 return (ENXIO);
443 if (strcmp(info->netd_hooks->hfi_family.hf_name,
444 hf->hf_name) != 0)
445 return (EINVAL);
447 ret = hook_family_remove(info->netd_hooks);
448 if (ret == 0)
449 info->netd_hooks = NULL;
451 return (ret);
455 net_family_shutdown(net_handle_t info, hook_family_t *hf)
458 ASSERT(info != NULL);
459 ASSERT(hf != NULL);
461 if (info->netd_hooks == NULL)
462 return (ENXIO);
464 if (strcmp(info->netd_hooks->hfi_family.hf_name,
465 hf->hf_name) != 0)
466 return (EINVAL);
468 return (hook_family_shutdown(info->netd_hooks));
472 * Function: net_event_register
473 * Returns: internal event pointer - NULL = Fail
474 * Parameters: info(I) - protocol
475 * he(I) - event pointer
477 * Call hook_event_add to register event on specific family
478 * Internal event pointer is returned so caller can get
479 * handle to run hooks
481 hook_event_token_t
482 net_event_register(net_handle_t info, hook_event_t *he)
484 hook_event_int_t *hei;
486 ASSERT(info != NULL);
487 ASSERT(he != NULL);
489 if (info->netd_hooks == NULL || info->netd_condemned != 0 ||
490 info->netd_stack == NULL)
491 return (NULL);
493 hei = hook_event_add(info->netd_hooks, he);
494 return ((hook_event_token_t)hei);
498 * Function: net_event_unregister
499 * Returns: int - transparent value, explained by caller
500 * Parameters: info(I) - protocol
501 * he(I) - event pointer
503 * Call hook_event_remove to unregister event on specific family
506 net_event_unregister(net_handle_t info, hook_event_t *he)
509 ASSERT(info != NULL);
510 ASSERT(he != NULL);
512 if (info->netd_hooks == NULL)
513 return (ENXIO);
515 return (hook_event_remove(info->netd_hooks, he));
519 net_event_shutdown(net_handle_t info, hook_event_t *he)
522 ASSERT(info != NULL);
523 ASSERT(he != NULL);
525 if (info->netd_hooks == NULL)
526 return (ENXIO);
528 return (hook_event_shutdown(info->netd_hooks, he));
532 * Function: net_hook_register
533 * Returns: int - transparent value, explained by caller
534 * Parameters: info(I) - protocol
535 * event(I) - event name
536 * h(I) - hook pointer
538 * Call hook_register to add hook on specific family/event
541 net_hook_register(net_handle_t info, char *event, hook_t *h)
544 ASSERT(info != NULL);
545 ASSERT(event != NULL);
546 ASSERT(h != NULL);
548 if (info->netd_condemned != 0 || info->netd_stack == NULL)
549 return (ESHUTDOWN);
551 if (info->netd_hooks == NULL)
552 return (ENXIO);
554 return (hook_register(info->netd_hooks, event, h));
558 * Function: net_hook_unregister
559 * Returns: int - transparent value, explained by caller
560 * Parameters: info(I) - protocol
561 * event(I) - event name
562 * h(I) - hook pointer
564 * Call hook_unregister to remove hook on specific family/event
567 net_hook_unregister(net_handle_t info, char *event, hook_t *h)
570 ASSERT(info != NULL);
571 ASSERT(event != NULL);
572 ASSERT(h != NULL);
574 if (info->netd_hooks == NULL)
575 return (ENXIO);
577 return (hook_unregister(info->netd_hooks, event, h));
580 netid_t
581 net_getnetid(net_handle_t netd)
584 if (netd->netd_stack == NULL)
585 return (-1);
586 return (netd->netd_stack->nts_id);
589 net_inject_t *
590 net_inject_alloc(const int version)
592 net_inject_t *ni;
594 ni = kmem_zalloc(sizeof (*ni), KM_NOSLEEP);
595 if (ni == NULL)
596 return (NULL);
598 ni->ni_version = version;
599 return (ni);
602 void
603 net_inject_free(net_inject_t *ni)
605 kmem_free(ni, sizeof (*ni));
608 kstat_t *
609 net_kstat_create(netid_t netid, char *module, int instance, char *name,
610 char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag)
612 netstackid_t stackid = net_getnetstackidbynetid(netid);
614 if (stackid == -1)
615 return (NULL);
617 return (kstat_create_netstack(module, instance, name, class, type,
618 ndata, ks_flag, stackid));
621 void
622 net_kstat_delete(netid_t netid, kstat_t *ks)
624 netstackid_t stackid = net_getnetstackidbynetid(netid);
626 if (stackid != -1)
627 kstat_delete_netstack(ks, stackid);
631 net_event_notify_register(net_handle_t family, char *event,
632 hook_notify_fn_t callback, void *arg)
634 int error;
636 if (family->netd_condemned != 0 || family->netd_stack == NULL)
637 return (ESHUTDOWN);
639 error = hook_event_notify_register(family->netd_hooks, event,
640 callback, arg);
642 return (error);
646 net_event_notify_unregister(net_handle_t family, char *event,
647 hook_notify_fn_t callback)
649 int error;
651 error = hook_event_notify_unregister(family->netd_hooks, event,
652 callback);
654 return (error);
658 net_protocol_notify_register(net_handle_t family, hook_notify_fn_t callback,
659 void *arg)
661 int error;
663 if (family->netd_condemned != 0 || family->netd_stack == NULL)
664 return (ESHUTDOWN);
666 error = hook_family_notify_register(family->netd_hooks, callback,
667 arg);
669 return (error);
673 net_protocol_notify_unregister(net_handle_t family, hook_notify_fn_t callback)
675 int error;
677 error = hook_family_notify_unregister(family->netd_hooks, callback);
679 return (error);