2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include "kpi_protocol.h"
33 #include <sys/param.h>
34 #include <sys/malloc.h>
35 #include <sys/socket.h>
36 #include <sys/systm.h>
37 #include <sys/kpi_mbuf.h>
38 #include <sys/domain.h>
41 #include <libkern/OSAtomic.h>
43 void proto_kpi_init(void);
44 void proto_input_run(void);
46 typedef int (*attach_t
)(struct ifnet
*ifp
, u_long protocol_family
);
47 typedef int (*detach_t
)(struct ifnet
*ifp
, u_long protocol_family
);
49 /****************************************************************************/
50 /* WARNING: Big assumption made here - there can be only one input thread */
51 struct proto_input_entry
{
52 struct proto_input_entry
*next
;
54 struct domain
*domain
;
56 protocol_family_t protocol
;
57 proto_input_handler input
;
58 proto_input_detached_handler detached
;
64 #define PROTO_HASH_SLOTS 5
66 static struct proto_input_entry
*proto_hash
[PROTO_HASH_SLOTS
];
67 static struct proto_input_entry
*proto_input_add_list
;
68 static lck_mtx_t
*proto_input_lock
= 0;
69 __private_extern__ u_int32_t inject_buckets
= 0;
71 extern thread_t dlil_input_thread_ptr
;
72 extern int dlil_input_thread_wakeup
;
76 protocol_family_t protocol
)
91 __private_extern__
void
94 lck_grp_attr_t
*grp_attrib
= 0;
95 lck_attr_t
*lck_attrib
= 0;
96 lck_grp_t
*lck_group
= 0;
98 /* Allocate a mtx lock */
99 grp_attrib
= lck_grp_attr_alloc_init();
100 lck_grp_attr_setdefault(grp_attrib
);
101 lck_group
= lck_grp_alloc_init("protocol kpi", grp_attrib
);
102 lck_grp_attr_free(grp_attrib
);
103 lck_attrib
= lck_attr_alloc_init();
104 lck_attr_setdefault(lck_attrib
);
105 proto_input_lock
= lck_mtx_alloc_init(lck_group
, lck_attrib
);
106 lck_grp_free(lck_group
);
107 lck_attr_free(lck_attrib
);
110 __private_extern__ errno_t
111 proto_register_input(
112 protocol_family_t protocol
,
113 proto_input_handler input
,
114 proto_input_detached_handler detached
)
117 struct proto_input_entry
*entry
;
119 entry
= _MALLOC(sizeof(*entry
), M_IFADDR
, M_WAITOK
);
124 bzero(entry
, sizeof(*entry
));
125 entry
->protocol
= protocol
;
126 entry
->input
= input
;
127 entry
->detached
= detached
;
130 struct domain
*dp
= domains
;
131 extern lck_mtx_t
*domain_proto_mtx
;
133 lck_mtx_assert(domain_proto_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
134 lck_mtx_lock(domain_proto_mtx
);
135 while (dp
&& dp
->dom_family
!= protocol
)
138 lck_mtx_unlock(domain_proto_mtx
);
143 entry
->next
= proto_input_add_list
;
144 } while(!OSCompareAndSwap((UInt32
)entry
->next
, (UInt32
)entry
, (UInt32
*)&proto_input_add_list
));
146 wakeup((caddr_t
)&dlil_input_thread_wakeup
);
152 __private_extern__
void
153 proto_unregister_input(
154 protocol_family_t protocol
)
156 struct proto_input_entry
*entry
= NULL
;
158 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
; entry
= entry
->next
)
159 if (entry
->protocol
== protocol
)
168 proto_delayed_attach(
169 struct proto_input_entry
*entry
)
171 struct proto_input_entry
*next_entry
;
172 for (next_entry
= entry
->next
; entry
; entry
= next_entry
) {
173 struct proto_input_entry
*exist
;
176 hash_slot
= proto_hash_value(entry
->protocol
);
177 next_entry
= entry
->next
;
179 for (exist
= proto_hash
[hash_slot
]; exist
; exist
= exist
->next
)
180 if (exist
->protocol
== entry
->protocol
)
183 /* If the entry already exists, call detached and dispose */
186 entry
->detached(entry
->protocol
);
187 FREE(entry
, M_IFADDR
);
190 entry
->next
= proto_hash
[hash_slot
];
191 proto_hash
[hash_slot
] = entry
;
197 proto_delayed_inject(
198 struct proto_input_entry
*entry
)
204 lck_mtx_lock(proto_input_lock
);
205 packet_list
= entry
->first_packet
;
206 entry
->first_packet
= entry
->last_packet
= 0;
207 lck_mtx_unlock(proto_input_lock
);
209 if (packet_list
== NULL
)
212 if (entry
->domain
&& (entry
->domain
->dom_flags
& DOM_REENTRANT
) == 0) {
213 lck_mtx_lock(entry
->domain
->dom_mtx
);
217 for (packet
= packet_list
; packet
; packet
= packet_list
) {
218 packet_list
= mbuf_nextpkt(packet
);
219 mbuf_setnextpkt(packet
, NULL
);
220 entry
->input(entry
->protocol
, packet
);
224 lck_mtx_unlock(entry
->domain
->dom_mtx
);
228 /* This function must be called from a single dlil input thread */
229 __private_extern__
void
230 proto_input_run(void)
232 struct proto_input_entry
*entry
;
236 if (current_thread() != dlil_input_thread_ptr
)
237 panic("proto_input_run called from a thread other than dlil_input_thread!\n");
240 entry
= proto_input_add_list
;
241 } while (entry
&& !OSCompareAndSwap((UInt32
)entry
, 0, (UInt32
*)&proto_input_add_list
));
244 proto_delayed_attach(entry
);
247 inject
= inject_buckets
;
248 } while (inject
&& !OSCompareAndSwap(inject
, 0, (UInt32
*)&inject_buckets
));
251 for (i
= 0; i
< PROTO_HASH_SLOTS
; i
++) {
252 if ((inject
& (1L << i
)) != 0) {
253 for (entry
= proto_hash
[i
]; entry
; entry
= entry
->next
) {
254 if (entry
->first_packet
) {
255 proto_delayed_inject(entry
);
265 protocol_family_t protocol
,
268 struct proto_input_entry
*entry
;
270 if (current_thread() != dlil_input_thread_ptr
)
271 panic("proto_input called from a thread other than dlil_input_thread!\n");
273 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
; entry
= entry
->next
) {
274 if (entry
->protocol
== protocol
)
280 #if DIRECT_PROTO_INPUT
281 // See <rdar://problem/3687868> for why this is disabled
282 // We need to release the dlil lock before taking the protocol lock
283 for (packet
= packet_list
; packet
; packet
= packet_list
) {
284 packet_list
= mbuf_nextpkt(packet
);
285 mbuf_setnextpkt(packet
, NULL
);
286 entry
->input(entry
->protocol
, packet
);
290 int hash_slot
= proto_hash_value(protocol
);
292 for (last_packet
= packet_list
; mbuf_nextpkt(last_packet
);
293 last_packet
= mbuf_nextpkt(last_packet
))
294 /* find the last packet */;
296 lck_mtx_lock(proto_input_lock
);
297 if (entry
->first_packet
== NULL
) {
298 entry
->first_packet
= packet_list
;
301 mbuf_setnextpkt(entry
->last_packet
, packet_list
);
303 entry
->last_packet
= last_packet
;
304 lck_mtx_unlock(proto_input_lock
);
306 OSBitOrAtomic((1L << hash_slot
), (UInt32
*)&inject_buckets
);
319 protocol_family_t protocol
,
322 struct proto_input_entry
*entry
;
324 int hash_slot
= proto_hash_value(protocol
);
326 for (last_packet
= packet_list
; mbuf_nextpkt(last_packet
);
327 last_packet
= mbuf_nextpkt(last_packet
))
328 /* find the last packet */;
330 for (entry
= proto_hash
[hash_slot
]; entry
; entry
= entry
->next
) {
331 if (entry
->protocol
== protocol
)
336 lck_mtx_lock(proto_input_lock
);
337 if (entry
->first_packet
== NULL
) {
338 entry
->first_packet
= packet_list
;
341 mbuf_setnextpkt(entry
->last_packet
, packet_list
);
343 entry
->last_packet
= last_packet
;
344 lck_mtx_unlock(proto_input_lock
);
346 OSBitOrAtomic((1L << hash_slot
), (UInt32
*)&inject_buckets
);
348 wakeup((caddr_t
)&dlil_input_thread_wakeup
);
359 proto_register_plumber(
360 protocol_family_t proto_fam
,
361 ifnet_family_t if_fam
,
362 proto_plumb_handler plumb
,
363 proto_unplumb_handler unplumb
)
365 return dlil_reg_proto_module(proto_fam
, if_fam
, (attach_t
)plumb
, (detach_t
)unplumb
);
369 proto_unregister_plumber(
370 protocol_family_t proto_fam
,
371 ifnet_family_t if_fam
)
373 (void)dlil_dereg_proto_module(proto_fam
, if_fam
);