2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include "kpi_protocol.h"
25 #include <sys/param.h>
26 #include <sys/malloc.h>
27 #include <sys/socket.h>
28 #include <sys/systm.h>
29 #include <sys/kpi_mbuf.h>
30 #include <sys/domain.h>
33 #include <libkern/OSAtomic.h>
35 void proto_kpi_init(void);
36 void proto_input_run(void);
38 typedef int (*attach_t
)(struct ifnet
*ifp
, u_long protocol_family
);
39 typedef int (*detach_t
)(struct ifnet
*ifp
, u_long protocol_family
);
41 /****************************************************************************/
42 /* WARNING: Big assumption made here - there can be only one input thread */
43 struct proto_input_entry
{
44 struct proto_input_entry
*next
;
46 struct domain
*domain
;
48 protocol_family_t protocol
;
49 proto_input_handler input
;
50 proto_input_detached_handler detached
;
56 #define PROTO_HASH_SLOTS 5
58 static struct proto_input_entry
*proto_hash
[PROTO_HASH_SLOTS
];
59 static struct proto_input_entry
*proto_input_add_list
;
60 static lck_mtx_t
*proto_input_lock
= 0;
61 __private_extern__ u_int32_t inject_buckets
= 0;
63 extern thread_t dlil_input_thread_ptr
;
64 extern int dlil_input_thread_wakeup
;
68 protocol_family_t protocol
)
83 __private_extern__
void
86 lck_grp_attr_t
*grp_attrib
= 0;
87 lck_attr_t
*lck_attrib
= 0;
88 lck_grp_t
*lck_group
= 0;
90 /* Allocate a mtx lock */
91 grp_attrib
= lck_grp_attr_alloc_init();
92 lck_grp_attr_setdefault(grp_attrib
);
93 lck_group
= lck_grp_alloc_init("protocol kpi", grp_attrib
);
94 lck_grp_attr_free(grp_attrib
);
95 lck_attrib
= lck_attr_alloc_init();
96 lck_attr_setdefault(lck_attrib
);
97 proto_input_lock
= lck_mtx_alloc_init(lck_group
, lck_attrib
);
98 lck_grp_free(lck_group
);
99 lck_attr_free(lck_attrib
);
102 __private_extern__ errno_t
103 proto_register_input(
104 protocol_family_t protocol
,
105 proto_input_handler input
,
106 proto_input_detached_handler detached
)
109 struct proto_input_entry
*entry
;
111 entry
= _MALLOC(sizeof(*entry
), M_IFADDR
, M_WAITOK
);
116 bzero(entry
, sizeof(*entry
));
117 entry
->protocol
= protocol
;
118 entry
->input
= input
;
119 entry
->detached
= detached
;
122 struct domain
*dp
= domains
;
123 extern lck_mtx_t
*domain_proto_mtx
;
125 lck_mtx_assert(domain_proto_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
126 lck_mtx_lock(domain_proto_mtx
);
127 while (dp
&& dp
->dom_family
!= protocol
)
130 lck_mtx_unlock(domain_proto_mtx
);
135 entry
->next
= proto_input_add_list
;
136 } while(!OSCompareAndSwap((UInt32
)entry
->next
, (UInt32
)entry
, (UInt32
*)&proto_input_add_list
));
138 wakeup((caddr_t
)&dlil_input_thread_wakeup
);
144 __private_extern__
void
145 proto_unregister_input(
146 protocol_family_t protocol
)
148 struct proto_input_entry
*entry
= NULL
;
150 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
; entry
= entry
->next
)
151 if (entry
->protocol
== protocol
)
160 proto_delayed_attach(
161 struct proto_input_entry
*entry
)
163 struct proto_input_entry
*next_entry
;
164 for (next_entry
= entry
->next
; entry
; entry
= next_entry
) {
165 struct proto_input_entry
*exist
;
168 hash_slot
= proto_hash_value(entry
->protocol
);
169 next_entry
= entry
->next
;
171 for (exist
= proto_hash
[hash_slot
]; exist
; exist
= exist
->next
)
172 if (exist
->protocol
== entry
->protocol
)
175 /* If the entry already exists, call detached and dispose */
178 entry
->detached(entry
->protocol
);
179 FREE(entry
, M_IFADDR
);
182 entry
->next
= proto_hash
[hash_slot
];
183 proto_hash
[hash_slot
] = entry
;
189 proto_delayed_inject(
190 struct proto_input_entry
*entry
)
196 lck_mtx_lock(proto_input_lock
);
197 packet_list
= entry
->first_packet
;
198 entry
->first_packet
= entry
->last_packet
= 0;
199 lck_mtx_unlock(proto_input_lock
);
201 if (packet_list
== NULL
)
204 if (entry
->domain
&& (entry
->domain
->dom_flags
& DOM_REENTRANT
) == 0) {
205 lck_mtx_lock(entry
->domain
->dom_mtx
);
209 for (packet
= packet_list
; packet
; packet
= packet_list
) {
210 packet_list
= mbuf_nextpkt(packet
);
211 mbuf_setnextpkt(packet
, NULL
);
212 entry
->input(entry
->protocol
, packet
);
216 lck_mtx_unlock(entry
->domain
->dom_mtx
);
220 /* This function must be called from a single dlil input thread */
221 __private_extern__
void
222 proto_input_run(void)
224 struct proto_input_entry
*entry
;
228 if (current_thread() != dlil_input_thread_ptr
)
229 panic("proto_input_run called from a thread other than dlil_input_thread!\n");
232 entry
= proto_input_add_list
;
233 } while (entry
&& !OSCompareAndSwap((UInt32
)entry
, 0, (UInt32
*)&proto_input_add_list
));
236 proto_delayed_attach(entry
);
239 inject
= inject_buckets
;
240 } while (inject
&& !OSCompareAndSwap(inject
, 0, (UInt32
*)&inject_buckets
));
243 for (i
= 0; i
< PROTO_HASH_SLOTS
; i
++) {
244 if ((inject
& (1L << i
)) != 0) {
245 for (entry
= proto_hash
[i
]; entry
; entry
= entry
->next
) {
246 if (entry
->first_packet
) {
247 proto_delayed_inject(entry
);
257 protocol_family_t protocol
,
260 struct proto_input_entry
*entry
;
262 if (current_thread() != dlil_input_thread_ptr
)
263 panic("proto_input called from a thread other than dlil_input_thread!\n");
265 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
; entry
= entry
->next
) {
266 if (entry
->protocol
== protocol
)
272 #if DIRECT_PROTO_INPUT
273 // See <rdar://problem/3687868> for why this is disabled
274 // We need to release the dlil lock before taking the protocol lock
275 for (packet
= packet_list
; packet
; packet
= packet_list
) {
276 packet_list
= mbuf_nextpkt(packet
);
277 mbuf_setnextpkt(packet
, NULL
);
278 entry
->input(entry
->protocol
, packet
);
282 int hash_slot
= proto_hash_value(protocol
);
284 for (last_packet
= packet_list
; mbuf_nextpkt(last_packet
);
285 last_packet
= mbuf_nextpkt(last_packet
))
286 /* find the last packet */;
288 lck_mtx_lock(proto_input_lock
);
289 if (entry
->first_packet
== NULL
) {
290 entry
->first_packet
= packet_list
;
293 mbuf_setnextpkt(entry
->last_packet
, packet_list
);
295 entry
->last_packet
= last_packet
;
296 lck_mtx_unlock(proto_input_lock
);
298 OSBitOrAtomic((1L << hash_slot
), (UInt32
*)&inject_buckets
);
311 protocol_family_t protocol
,
314 struct proto_input_entry
*entry
;
316 int hash_slot
= proto_hash_value(protocol
);
318 for (last_packet
= packet_list
; mbuf_nextpkt(last_packet
);
319 last_packet
= mbuf_nextpkt(last_packet
))
320 /* find the last packet */;
322 for (entry
= proto_hash
[hash_slot
]; entry
; entry
= entry
->next
) {
323 if (entry
->protocol
== protocol
)
328 lck_mtx_lock(proto_input_lock
);
329 if (entry
->first_packet
== NULL
) {
330 entry
->first_packet
= packet_list
;
333 mbuf_setnextpkt(entry
->last_packet
, packet_list
);
335 entry
->last_packet
= last_packet
;
336 lck_mtx_unlock(proto_input_lock
);
338 OSBitOrAtomic((1L << hash_slot
), (UInt32
*)&inject_buckets
);
340 wakeup((caddr_t
)&dlil_input_thread_wakeup
);
351 proto_register_plumber(
352 protocol_family_t proto_fam
,
353 ifnet_family_t if_fam
,
354 proto_plumb_handler plumb
,
355 proto_unplumb_handler unplumb
)
357 return dlil_reg_proto_module(proto_fam
, if_fam
, (attach_t
)plumb
, (detach_t
)unplumb
);
361 proto_unregister_plumber(
362 protocol_family_t proto_fam
,
363 ifnet_family_t if_fam
)
365 (void)dlil_dereg_proto_module(proto_fam
, if_fam
);