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_input_run(void);
43 typedef int (*attach_t
)(struct ifnet
*ifp
, u_long protocol_family
);
44 typedef int (*detach_t
)(struct ifnet
*ifp
, u_long protocol_family
);
46 struct proto_input_entry
{
47 struct proto_input_entry
*next
;
49 struct domain
*domain
;
53 protocol_family_t protocol
;
54 proto_input_handler input
;
55 proto_input_detached_handler detached
;
60 struct proto_input_entry
*input_next
;
66 struct proto_family_str
{
67 TAILQ_ENTRY(proto_family_str
) proto_fam_next
;
68 protocol_family_t proto_family
;
69 ifnet_family_t if_family
;
70 proto_plumb_handler attach_proto
;
71 proto_unplumb_handler detach_proto
;
74 #define PROTO_HASH_SLOTS 5
76 static struct proto_input_entry
*proto_hash
[PROTO_HASH_SLOTS
];
77 static int proto_total_waiting
= 0;
78 static struct proto_input_entry
*proto_input_add_list
= NULL
;
79 static lck_mtx_t
*proto_family_mutex
= 0;
80 static TAILQ_HEAD(, proto_family_str
) proto_family_head
=
81 TAILQ_HEAD_INITIALIZER(proto_family_head
);
83 extern lck_mtx_t
*domain_proto_mtx
;
84 extern struct dlil_threading_info
*dlil_lo_thread_ptr
;
88 protocol_family_t protocol
)
103 __private_extern__
void
106 lck_grp_attr_t
*grp_attrib
= 0;
107 lck_attr_t
*lck_attrib
= 0;
108 lck_grp_t
*lck_group
= 0;
110 /* Allocate a mtx lock */
111 grp_attrib
= lck_grp_attr_alloc_init();
112 lck_group
= lck_grp_alloc_init("protocol kpi", grp_attrib
);
113 lck_grp_attr_free(grp_attrib
);
114 lck_attrib
= lck_attr_alloc_init();
115 proto_family_mutex
= lck_mtx_alloc_init(lck_group
, lck_attrib
);
116 lck_grp_free(lck_group
);
117 lck_attr_free(lck_attrib
);
119 bzero(proto_hash
, sizeof(proto_hash
));
122 __private_extern__ errno_t
123 proto_register_input(
124 protocol_family_t protocol
,
125 proto_input_handler input
,
126 proto_input_detached_handler detached
,
130 struct proto_input_entry
*entry
;
131 struct dlil_threading_info
*thread
= dlil_lo_thread_ptr
;
133 entry
= _MALLOC(sizeof(*entry
), M_IFADDR
, M_WAITOK
);
138 bzero(entry
, sizeof(*entry
));
139 entry
->protocol
= protocol
;
140 entry
->input
= input
;
141 entry
->detached
= detached
;
142 entry
->hash
= proto_hash_value(protocol
);
143 entry
->chain
= chains
;
146 struct domain
*dp
= domains
;
148 lck_mtx_assert(domain_proto_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
149 lck_mtx_lock(domain_proto_mtx
);
150 while (dp
&& (protocol_family_t
)dp
->dom_family
!= protocol
)
153 lck_mtx_unlock(domain_proto_mtx
);
157 lck_mtx_lock(thread
->input_lck
);
158 entry
->next
= proto_input_add_list
;
159 proto_input_add_list
= entry
;
161 thread
->input_waiting
|= DLIL_PROTO_REGISTER
;
162 if ((thread
->input_waiting
& DLIL_INPUT_RUNNING
) == 0)
163 wakeup((caddr_t
)&thread
->input_waiting
);
164 lck_mtx_unlock(thread
->input_lck
);
170 __private_extern__
void
171 proto_unregister_input(
172 protocol_family_t protocol
)
174 struct proto_input_entry
*entry
= NULL
;
176 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
; entry
= entry
->next
)
177 if (entry
->protocol
== protocol
)
186 proto_delayed_attach(
187 struct proto_input_entry
*entry
)
189 struct proto_input_entry
*next_entry
;
190 for (next_entry
= entry
->next
; entry
; entry
= next_entry
) {
191 struct proto_input_entry
*exist
;
194 hash_slot
= proto_hash_value(entry
->protocol
);
195 next_entry
= entry
->next
;
197 for (exist
= proto_hash
[hash_slot
]; exist
; exist
= exist
->next
)
198 if (exist
->protocol
== entry
->protocol
)
201 /* If the entry already exists, call detached and dispose */
204 entry
->detached(entry
->protocol
);
205 FREE(entry
, M_IFADDR
);
208 entry
->next
= proto_hash
[hash_slot
];
209 proto_hash
[hash_slot
] = entry
;
214 __private_extern__
void
215 proto_input_run(void)
217 struct proto_input_entry
*entry
;
218 struct dlil_threading_info
*thread
= dlil_lo_thread_ptr
;
222 lck_mtx_assert(thread
->input_lck
, LCK_MTX_ASSERT_NOTOWNED
);
224 if ((thread
->input_waiting
& DLIL_PROTO_REGISTER
) != 0) {
225 lck_mtx_lock(thread
->input_lck
);
226 entry
= proto_input_add_list
;
227 proto_input_add_list
= NULL
;
228 thread
->input_waiting
&= ~DLIL_PROTO_REGISTER
;
229 lck_mtx_unlock(thread
->input_lck
);
230 proto_delayed_attach(entry
);
233 Move everything from the lock protected list to the thread
236 for (i
= 0; proto_total_waiting
!= 0 && i
< PROTO_HASH_SLOTS
; i
++) {
237 for (entry
= proto_hash
[i
]; entry
&& proto_total_waiting
;
238 entry
= entry
->next
) {
239 if (entry
->inject_first
) {
240 lck_mtx_lock(thread
->input_lck
);
241 thread
->input_waiting
&= ~DLIL_PROTO_WAITING
;
243 packet_list
= entry
->inject_first
;
245 entry
->inject_first
= NULL
;
246 entry
->inject_last
= NULL
;
247 proto_total_waiting
--;
249 lck_mtx_unlock(thread
->input_lck
);
251 if (entry
->domain
&& (entry
->domain
->dom_flags
& DOM_REENTRANT
) == 0) {
252 lck_mtx_lock(entry
->domain
->dom_mtx
);
257 entry
->input(entry
->protocol
, packet_list
);
262 for (packet
= packet_list
; packet
; packet
= packet_list
) {
263 packet_list
= mbuf_nextpkt(packet
);
264 mbuf_setnextpkt(packet
, NULL
);
265 entry
->input(entry
->protocol
, packet
);
269 lck_mtx_unlock(entry
->domain
->dom_mtx
);
279 protocol_family_t protocol
,
282 struct proto_input_entry
*entry
;
283 errno_t locked
=0, result
= 0;
285 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
;
286 entry
= entry
->next
) {
287 if (entry
->protocol
== protocol
)
291 if (entry
->domain
&& (entry
->domain
->dom_flags
& DOM_REENTRANT
) == 0) {
292 lck_mtx_lock(entry
->domain
->dom_mtx
);
297 entry
->input(entry
->protocol
, packet_list
);
302 for (packet
= packet_list
; packet
; packet
= packet_list
) {
303 packet_list
= mbuf_nextpkt(packet
);
304 mbuf_setnextpkt(packet
, NULL
);
305 entry
->input(entry
->protocol
, packet
);
310 lck_mtx_unlock(entry
->domain
->dom_mtx
);
317 protocol_family_t protocol
,
320 struct proto_input_entry
*entry
;
322 int hash_slot
= proto_hash_value(protocol
);
323 struct dlil_threading_info
*thread
= dlil_lo_thread_ptr
;
325 for (last_packet
= packet_list
; mbuf_nextpkt(last_packet
);
326 last_packet
= mbuf_nextpkt(last_packet
))
327 /* find the last packet */;
329 for (entry
= proto_hash
[hash_slot
]; entry
; entry
= entry
->next
) {
330 if (entry
->protocol
== protocol
)
335 lck_mtx_lock(thread
->input_lck
);
336 if (entry
->inject_first
== NULL
) {
337 proto_total_waiting
++;
338 thread
->input_waiting
|= DLIL_PROTO_WAITING
;
339 entry
->inject_first
= packet_list
;
342 mbuf_setnextpkt(entry
->inject_last
, packet_list
);
344 entry
->inject_last
= last_packet
;
345 if ((thread
->input_waiting
& DLIL_INPUT_RUNNING
) == 0) {
346 wakeup((caddr_t
)&thread
->input_waiting
);
348 lck_mtx_unlock(thread
->input_lck
);
358 static struct proto_family_str
*
360 protocol_family_t proto_family
,
361 ifnet_family_t if_family
)
363 struct proto_family_str
*mod
= NULL
;
365 TAILQ_FOREACH(mod
, &proto_family_head
, proto_fam_next
) {
366 if ((mod
->proto_family
== (proto_family
& 0xffff))
367 && (mod
->if_family
== (if_family
& 0xffff)))
375 proto_register_plumber(
376 protocol_family_t protocol_family
,
377 ifnet_family_t interface_family
,
378 proto_plumb_handler attach
,
379 proto_unplumb_handler detach
)
381 struct proto_family_str
*proto_family
;
383 if (attach
== NULL
) return EINVAL
;
385 lck_mtx_lock(proto_family_mutex
);
387 TAILQ_FOREACH(proto_family
, &proto_family_head
, proto_fam_next
) {
388 if (proto_family
->proto_family
== protocol_family
&&
389 proto_family
->if_family
== interface_family
) {
390 lck_mtx_unlock(proto_family_mutex
);
395 proto_family
= (struct proto_family_str
*) _MALLOC(sizeof(struct proto_family_str
), M_IFADDR
, M_WAITOK
);
397 lck_mtx_unlock(proto_family_mutex
);
401 bzero(proto_family
, sizeof(struct proto_family_str
));
402 proto_family
->proto_family
= protocol_family
;
403 proto_family
->if_family
= interface_family
& 0xffff;
404 proto_family
->attach_proto
= attach
;
405 proto_family
->detach_proto
= detach
;
407 TAILQ_INSERT_TAIL(&proto_family_head
, proto_family
, proto_fam_next
);
408 lck_mtx_unlock(proto_family_mutex
);
413 proto_unregister_plumber(
414 protocol_family_t protocol_family
,
415 ifnet_family_t interface_family
)
417 struct proto_family_str
*proto_family
;
419 lck_mtx_lock(proto_family_mutex
);
421 proto_family
= proto_plumber_find(protocol_family
, interface_family
);
422 if (proto_family
== 0) {
423 lck_mtx_unlock(proto_family_mutex
);
427 TAILQ_REMOVE(&proto_family_head
, proto_family
, proto_fam_next
);
428 FREE(proto_family
, M_IFADDR
);
430 lck_mtx_unlock(proto_family_mutex
);
434 __private_extern__ errno_t
436 protocol_family_t protocol_family
,
439 struct proto_family_str
*proto_family
;
442 lck_mtx_lock(proto_family_mutex
);
443 proto_family
= proto_plumber_find(protocol_family
, ifp
->if_family
);
444 if (proto_family
== 0) {
445 lck_mtx_unlock(proto_family_mutex
);
449 ret
= proto_family
->attach_proto(ifp
, protocol_family
);
451 lck_mtx_unlock(proto_family_mutex
);
456 __private_extern__ errno_t
458 protocol_family_t protocol_family
,
461 struct proto_family_str
*proto_family
;
464 lck_mtx_lock(proto_family_mutex
);
466 proto_family
= proto_plumber_find(protocol_family
, ifp
->if_family
);
467 if (proto_family
&& proto_family
->detach_proto
)
468 proto_family
->detach_proto(ifp
, protocol_family
);
470 ret
= ifnet_detach_protocol(ifp
, protocol_family
);
472 lck_mtx_unlock(proto_family_mutex
);