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]
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>
29 #include <sys/rwlock.h>
30 #include <sys/errno.h>
31 #include <sys/queue.h>
32 #include <inet/common.h>
38 static net_handle_t
net_find(const char *protocol
, neti_stack_t
*ns
);
41 net_find(const char *protocol
, neti_stack_t
*nts
)
45 ASSERT(protocol
!= 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)
56 if (strcmp(n
->netd_info
.netp_name
, protocol
) == 0) {
65 net_protocol_register(netid_t id
, const net_protocol_t
*info
)
67 struct net_data
*n
, *new;
72 nts
= net_getnetistackbyid(id
);
76 new = kmem_alloc(sizeof (*new), KM_SLEEP
);
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
);
86 mutex_exit(&nts
->nts_lock
);
87 kmem_free(new, sizeof (*new));
91 if (LIST_EMPTY(&nts
->nts_netd_head
)) {
92 LIST_INSERT_HEAD(&nts
->nts_netd_head
, new, netd_list
);
94 LIST_INSERT_AFTER(LIST_FIRST(&nts
->nts_netd_head
),
97 mutex_exit(&nts
->nts_lock
);
103 net_protocol_unregister(net_handle_t info
)
107 ASSERT(info
!= NULL
);
109 nts
= info
->netd_stack
;
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
);
123 net_protocol_lookup(netid_t netid
, const char *protocol
)
128 ASSERT(protocol
!= NULL
);
130 nts
= net_getnetistackbyid(netid
);
134 mutex_enter(&nts
->nts_lock
);
135 nd
= net_find(protocol
, nts
);
137 atomic_inc_32((uint_t
*)&nd
->netd_refcnt
);
138 mutex_exit(&nts
->nts_lock
);
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
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
));
170 net_protocol_walk(netid_t netid
, net_handle_t info
)
172 struct net_data
*n
= NULL
;
173 boolean_t found
= B_FALSE
;
176 nts
= net_getnetistackbyid(netid
);
182 mutex_enter(&nts
->nts_lock
);
183 LIST_FOREACH(n
, &nts
->nts_netd_head
, netd_list
) {
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)
201 (void) net_protocol_release(info
);
204 atomic_inc_32((uint_t
*)&n
->netd_refcnt
);
206 mutex_exit(&nts
->nts_lock
);
212 * Public accessor functions
215 net_getifname(net_handle_t info
, phy_if_t nic
, char *buffer
,
219 ASSERT(info
!= NULL
);
221 if (info
->netd_condemned
!= 0 || info
->netd_stack
== NULL
)
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
)
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
)
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
)
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
,
269 ASSERT(info
!= NULL
);
271 if (info
->netd_condemned
!= 0 || info
->netd_stack
== NULL
)
274 return (info
->netd_info
.neti_getlifzone(info
, phy_ifdata
, ifdata
,
279 net_getlifflags(net_handle_t info
, phy_if_t phy_ifdata
, lif_if_t ifdata
,
282 ASSERT(info
!= NULL
);
284 if (info
->netd_condemned
!= 0 || info
->netd_stack
== NULL
)
287 return (info
->netd_info
.neti_getlifflags(info
, phy_ifdata
, ifdata
,
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
));
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
));
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
)
336 return (info
->netd_info
.netp_inject(info
, style
, packet
));
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
);
358 if (info
->netd_condemned
!= 0 || info
->netd_stack
== NULL
)
361 return (info
->netd_info
.netp_ispartialchecksum(info
, mp
));
365 net_isvalidchecksum(net_handle_t info
, mblk_t
*mp
)
368 ASSERT(info
!= NULL
);
371 if (info
->netd_condemned
!= 0 || info
->netd_stack
== NULL
)
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
)
406 ASSERT(info
!= NULL
);
409 if (info
->netd_condemned
!= 0 || info
->netd_stack
== NULL
)
412 if (info
->netd_hooks
!= NULL
)
415 ns
= info
->netd_stack
->nts_netstack
;
417 if (hook_family_add(hf
, ns
->netstack_hook
,
418 (void **)&info
->netd_hooks
) == NULL
)
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
)
437 ASSERT(info
!= NULL
);
440 if (info
->netd_hooks
== NULL
)
443 if (strcmp(info
->netd_hooks
->hfi_family
.hf_name
,
447 ret
= hook_family_remove(info
->netd_hooks
);
449 info
->netd_hooks
= NULL
;
455 net_family_shutdown(net_handle_t info
, hook_family_t
*hf
)
458 ASSERT(info
!= NULL
);
461 if (info
->netd_hooks
== NULL
)
464 if (strcmp(info
->netd_hooks
->hfi_family
.hf_name
,
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
482 net_event_register(net_handle_t info
, hook_event_t
*he
)
484 hook_event_int_t
*hei
;
486 ASSERT(info
!= NULL
);
489 if (info
->netd_hooks
== NULL
|| info
->netd_condemned
!= 0 ||
490 info
->netd_stack
== 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
);
512 if (info
->netd_hooks
== NULL
)
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
);
525 if (info
->netd_hooks
== NULL
)
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
);
548 if (info
->netd_condemned
!= 0 || info
->netd_stack
== NULL
)
551 if (info
->netd_hooks
== NULL
)
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
);
574 if (info
->netd_hooks
== NULL
)
577 return (hook_unregister(info
->netd_hooks
, event
, h
));
581 net_getnetid(net_handle_t netd
)
584 if (netd
->netd_stack
== NULL
)
586 return (netd
->netd_stack
->nts_id
);
590 net_inject_alloc(const int version
)
594 ni
= kmem_zalloc(sizeof (*ni
), KM_NOSLEEP
);
598 ni
->ni_version
= version
;
603 net_inject_free(net_inject_t
*ni
)
605 kmem_free(ni
, sizeof (*ni
));
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
);
617 return (kstat_create_netstack(module
, instance
, name
, class, type
,
618 ndata
, ks_flag
, stackid
));
622 net_kstat_delete(netid_t netid
, kstat_t
*ks
)
624 netstackid_t stackid
= net_getnetstackidbynetid(netid
);
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
)
636 if (family
->netd_condemned
!= 0 || family
->netd_stack
== NULL
)
639 error
= hook_event_notify_register(family
->netd_hooks
, event
,
646 net_event_notify_unregister(net_handle_t family
, char *event
,
647 hook_notify_fn_t callback
)
651 error
= hook_event_notify_unregister(family
->netd_hooks
, event
,
658 net_protocol_notify_register(net_handle_t family
, hook_notify_fn_t callback
,
663 if (family
->netd_condemned
!= 0 || family
->netd_stack
== NULL
)
666 error
= hook_family_notify_register(family
->netd_hooks
, callback
,
673 net_protocol_notify_unregister(net_handle_t family
, hook_notify_fn_t callback
)
677 error
= hook_family_notify_unregister(family
->netd_hooks
, callback
);