2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include "kpi_protocol.h"
31 #include <sys/param.h>
32 #include <sys/malloc.h>
33 #include <sys/socket.h>
34 #include <sys/systm.h>
35 #include <sys/kpi_mbuf.h>
36 #include <sys/domain.h>
39 #include <libkern/OSAtomic.h>
41 void proto_kpi_init(void);
42 void proto_input_run(void);
44 typedef int (*attach_t
)(struct ifnet
*ifp
, u_long protocol_family
);
45 typedef int (*detach_t
)(struct ifnet
*ifp
, u_long protocol_family
);
47 /****************************************************************************/
48 /* WARNING: Big assumption made here - there can be only one input thread */
49 struct proto_input_entry
{
50 struct proto_input_entry
*next
;
52 struct domain
*domain
;
54 protocol_family_t protocol
;
55 proto_input_handler input
;
56 proto_input_detached_handler detached
;
62 #define PROTO_HASH_SLOTS 5
64 static struct proto_input_entry
*proto_hash
[PROTO_HASH_SLOTS
];
65 static struct proto_input_entry
*proto_input_add_list
;
66 static lck_mtx_t
*proto_input_lock
= 0;
67 __private_extern__ u_int32_t inject_buckets
= 0;
69 extern thread_t dlil_input_thread_ptr
;
70 extern int dlil_input_thread_wakeup
;
74 protocol_family_t protocol
)
89 __private_extern__
void
92 lck_grp_attr_t
*grp_attrib
= 0;
93 lck_attr_t
*lck_attrib
= 0;
94 lck_grp_t
*lck_group
= 0;
96 /* Allocate a mtx lock */
97 grp_attrib
= lck_grp_attr_alloc_init();
98 lck_grp_attr_setdefault(grp_attrib
);
99 lck_group
= lck_grp_alloc_init("protocol kpi", grp_attrib
);
100 lck_grp_attr_free(grp_attrib
);
101 lck_attrib
= lck_attr_alloc_init();
102 lck_attr_setdefault(lck_attrib
);
103 proto_input_lock
= lck_mtx_alloc_init(lck_group
, lck_attrib
);
104 lck_grp_free(lck_group
);
105 lck_attr_free(lck_attrib
);
108 __private_extern__ errno_t
109 proto_register_input(
110 protocol_family_t protocol
,
111 proto_input_handler input
,
112 proto_input_detached_handler detached
)
115 struct proto_input_entry
*entry
;
117 entry
= _MALLOC(sizeof(*entry
), M_IFADDR
, M_WAITOK
);
122 bzero(entry
, sizeof(*entry
));
123 entry
->protocol
= protocol
;
124 entry
->input
= input
;
125 entry
->detached
= detached
;
128 struct domain
*dp
= domains
;
129 extern lck_mtx_t
*domain_proto_mtx
;
131 lck_mtx_assert(domain_proto_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
132 lck_mtx_lock(domain_proto_mtx
);
133 while (dp
&& dp
->dom_family
!= protocol
)
136 lck_mtx_unlock(domain_proto_mtx
);
141 entry
->next
= proto_input_add_list
;
142 } while(!OSCompareAndSwap((UInt32
)entry
->next
, (UInt32
)entry
, (UInt32
*)&proto_input_add_list
));
144 wakeup((caddr_t
)&dlil_input_thread_wakeup
);
150 __private_extern__
void
151 proto_unregister_input(
152 protocol_family_t protocol
)
154 struct proto_input_entry
*entry
= NULL
;
156 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
; entry
= entry
->next
)
157 if (entry
->protocol
== protocol
)
166 proto_delayed_attach(
167 struct proto_input_entry
*entry
)
169 struct proto_input_entry
*next_entry
;
170 for (next_entry
= entry
->next
; entry
; entry
= next_entry
) {
171 struct proto_input_entry
*exist
;
174 hash_slot
= proto_hash_value(entry
->protocol
);
175 next_entry
= entry
->next
;
177 for (exist
= proto_hash
[hash_slot
]; exist
; exist
= exist
->next
)
178 if (exist
->protocol
== entry
->protocol
)
181 /* If the entry already exists, call detached and dispose */
184 entry
->detached(entry
->protocol
);
185 FREE(entry
, M_IFADDR
);
188 entry
->next
= proto_hash
[hash_slot
];
189 proto_hash
[hash_slot
] = entry
;
195 proto_delayed_inject(
196 struct proto_input_entry
*entry
)
202 lck_mtx_lock(proto_input_lock
);
203 packet_list
= entry
->first_packet
;
204 entry
->first_packet
= entry
->last_packet
= 0;
205 lck_mtx_unlock(proto_input_lock
);
207 if (packet_list
== NULL
)
210 if (entry
->domain
&& (entry
->domain
->dom_flags
& DOM_REENTRANT
) == 0) {
211 lck_mtx_lock(entry
->domain
->dom_mtx
);
215 for (packet
= packet_list
; packet
; packet
= packet_list
) {
216 packet_list
= mbuf_nextpkt(packet
);
217 mbuf_setnextpkt(packet
, NULL
);
218 entry
->input(entry
->protocol
, packet
);
222 lck_mtx_unlock(entry
->domain
->dom_mtx
);
226 /* This function must be called from a single dlil input thread */
227 __private_extern__
void
228 proto_input_run(void)
230 struct proto_input_entry
*entry
;
234 if (current_thread() != dlil_input_thread_ptr
)
235 panic("proto_input_run called from a thread other than dlil_input_thread!\n");
238 entry
= proto_input_add_list
;
239 } while (entry
&& !OSCompareAndSwap((UInt32
)entry
, 0, (UInt32
*)&proto_input_add_list
));
242 proto_delayed_attach(entry
);
245 inject
= inject_buckets
;
246 } while (inject
&& !OSCompareAndSwap(inject
, 0, (UInt32
*)&inject_buckets
));
249 for (i
= 0; i
< PROTO_HASH_SLOTS
; i
++) {
250 if ((inject
& (1L << i
)) != 0) {
251 for (entry
= proto_hash
[i
]; entry
; entry
= entry
->next
) {
252 if (entry
->first_packet
) {
253 proto_delayed_inject(entry
);
263 protocol_family_t protocol
,
266 struct proto_input_entry
*entry
;
268 if (current_thread() != dlil_input_thread_ptr
)
269 panic("proto_input called from a thread other than dlil_input_thread!\n");
271 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
; entry
= entry
->next
) {
272 if (entry
->protocol
== protocol
)
278 #if DIRECT_PROTO_INPUT
279 // See <rdar://problem/3687868> for why this is disabled
280 // We need to release the dlil lock before taking the protocol lock
281 for (packet
= packet_list
; packet
; packet
= packet_list
) {
282 packet_list
= mbuf_nextpkt(packet
);
283 mbuf_setnextpkt(packet
, NULL
);
284 entry
->input(entry
->protocol
, packet
);
288 int hash_slot
= proto_hash_value(protocol
);
290 for (last_packet
= packet_list
; mbuf_nextpkt(last_packet
);
291 last_packet
= mbuf_nextpkt(last_packet
))
292 /* find the last packet */;
294 lck_mtx_lock(proto_input_lock
);
295 if (entry
->first_packet
== NULL
) {
296 entry
->first_packet
= packet_list
;
299 mbuf_setnextpkt(entry
->last_packet
, packet_list
);
301 entry
->last_packet
= last_packet
;
302 lck_mtx_unlock(proto_input_lock
);
304 OSBitOrAtomic((1L << hash_slot
), (UInt32
*)&inject_buckets
);
317 protocol_family_t protocol
,
320 struct proto_input_entry
*entry
;
322 int hash_slot
= proto_hash_value(protocol
);
324 for (last_packet
= packet_list
; mbuf_nextpkt(last_packet
);
325 last_packet
= mbuf_nextpkt(last_packet
))
326 /* find the last packet */;
328 for (entry
= proto_hash
[hash_slot
]; entry
; entry
= entry
->next
) {
329 if (entry
->protocol
== protocol
)
334 lck_mtx_lock(proto_input_lock
);
335 if (entry
->first_packet
== NULL
) {
336 entry
->first_packet
= packet_list
;
339 mbuf_setnextpkt(entry
->last_packet
, packet_list
);
341 entry
->last_packet
= last_packet
;
342 lck_mtx_unlock(proto_input_lock
);
344 OSBitOrAtomic((1L << hash_slot
), (UInt32
*)&inject_buckets
);
346 wakeup((caddr_t
)&dlil_input_thread_wakeup
);
357 proto_register_plumber(
358 protocol_family_t proto_fam
,
359 ifnet_family_t if_fam
,
360 proto_plumb_handler plumb
,
361 proto_unplumb_handler unplumb
)
363 return dlil_reg_proto_module(proto_fam
, if_fam
, (attach_t
)plumb
, (detach_t
)unplumb
);
367 proto_unregister_plumber(
368 protocol_family_t proto_fam
,
369 ifnet_family_t if_fam
)
371 (void)dlil_dereg_proto_module(proto_fam
, if_fam
);