2 * Copyright (c) 2004-2012 Apple 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
, uint32_t protocol_family
);
44 typedef int (*detach_t
)(struct ifnet
*ifp
, uint32_t 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 decl_lck_mtx_data(static, proto_family_mutex_data
);
80 static lck_mtx_t
*proto_family_mutex
= &proto_family_mutex_data
;
81 static TAILQ_HEAD(, proto_family_str
) proto_family_head
=
82 TAILQ_HEAD_INITIALIZER(proto_family_head
);
85 proto_hash_value(protocol_family_t protocol
)
100 __private_extern__
void
103 lck_grp_attr_t
*grp_attrib
= NULL
;
104 lck_attr_t
*lck_attrib
= NULL
;
105 lck_grp_t
*lck_group
= NULL
;
107 /* Allocate a mtx lock */
108 grp_attrib
= lck_grp_attr_alloc_init();
109 lck_group
= lck_grp_alloc_init("protocol kpi", grp_attrib
);
110 lck_grp_attr_free(grp_attrib
);
111 lck_attrib
= lck_attr_alloc_init();
112 lck_mtx_init(proto_family_mutex
, lck_group
, lck_attrib
);
113 lck_grp_free(lck_group
);
114 lck_attr_free(lck_attrib
);
116 bzero(proto_hash
, sizeof (proto_hash
));
119 __private_extern__ errno_t
120 proto_register_input(protocol_family_t protocol
, proto_input_handler input
,
121 proto_input_detached_handler detached
, int chains
)
123 struct proto_input_entry
*entry
;
124 struct dlil_threading_info
*inp
= dlil_main_input_thread
;
125 struct domain
*dp
= domains
;
128 entry
= _MALLOC(sizeof (*entry
), M_IFADDR
, M_WAITOK
);
133 bzero(entry
, sizeof (*entry
));
134 entry
->protocol
= protocol
;
135 entry
->input
= input
;
136 entry
->detached
= detached
;
137 entry
->hash
= proto_hash_value(protocol
);
138 entry
->chain
= chains
;
140 do_unlock
= domain_proto_mtx_lock();
141 while (dp
&& (protocol_family_t
)dp
->dom_family
!= protocol
)
144 domain_proto_mtx_unlock(do_unlock
);
146 lck_mtx_lock(&inp
->input_lck
);
147 entry
->next
= proto_input_add_list
;
148 proto_input_add_list
= entry
;
150 inp
->input_waiting
|= DLIL_PROTO_REGISTER
;
151 if ((inp
->input_waiting
& DLIL_INPUT_RUNNING
) == 0)
152 wakeup((caddr_t
)&inp
->input_waiting
);
153 lck_mtx_unlock(&inp
->input_lck
);
158 __private_extern__
void
159 proto_unregister_input(protocol_family_t protocol
)
161 struct proto_input_entry
*entry
= NULL
;
163 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
!= NULL
;
164 entry
= entry
->next
) {
165 if (entry
->protocol
== protocol
)
174 proto_delayed_attach(struct proto_input_entry
*entry
)
176 struct proto_input_entry
*next_entry
;
178 for (next_entry
= entry
->next
; entry
!= NULL
; entry
= next_entry
) {
179 struct proto_input_entry
*exist
;
182 hash_slot
= proto_hash_value(entry
->protocol
);
183 next_entry
= entry
->next
;
185 for (exist
= proto_hash
[hash_slot
]; exist
!= NULL
;
186 exist
= exist
->next
) {
187 if (exist
->protocol
== entry
->protocol
)
191 /* If the entry already exists, call detached and dispose */
194 entry
->detached(entry
->protocol
);
195 FREE(entry
, M_IFADDR
);
197 entry
->next
= proto_hash
[hash_slot
];
198 proto_hash
[hash_slot
] = entry
;
203 __private_extern__
void
204 proto_input_run(void)
206 struct proto_input_entry
*entry
;
207 struct dlil_threading_info
*inp
= dlil_main_input_thread
;
211 lck_mtx_assert(&inp
->input_lck
, LCK_MTX_ASSERT_NOTOWNED
);
213 if (inp
->input_waiting
& DLIL_PROTO_REGISTER
) {
214 lck_mtx_lock_spin(&inp
->input_lck
);
215 entry
= proto_input_add_list
;
216 proto_input_add_list
= NULL
;
217 inp
->input_waiting
&= ~DLIL_PROTO_REGISTER
;
218 lck_mtx_unlock(&inp
->input_lck
);
219 proto_delayed_attach(entry
);
223 * Move everything from the lock protected list to the thread
226 for (i
= 0; proto_total_waiting
!= 0 && i
< PROTO_HASH_SLOTS
; i
++) {
227 for (entry
= proto_hash
[i
];
228 entry
!= NULL
&& proto_total_waiting
; entry
= entry
->next
) {
229 if (entry
->inject_first
!= NULL
) {
230 lck_mtx_lock_spin(&inp
->input_lck
);
231 inp
->input_waiting
&= ~DLIL_PROTO_WAITING
;
233 packet_list
= entry
->inject_first
;
235 entry
->inject_first
= NULL
;
236 entry
->inject_last
= NULL
;
237 proto_total_waiting
--;
239 lck_mtx_unlock(&inp
->input_lck
);
241 if (entry
->domain
!= NULL
&& !(entry
->domain
->
242 dom_flags
& DOM_REENTRANT
)) {
243 lck_mtx_lock(entry
->domain
->dom_mtx
);
248 entry
->input(entry
->protocol
,
253 for (packet
= packet_list
;
255 packet
= packet_list
) {
257 mbuf_nextpkt(packet
);
258 mbuf_setnextpkt(packet
, NULL
);
259 entry
->input(entry
->protocol
,
265 lck_mtx_unlock(entry
->domain
->dom_mtx
);
273 proto_input(protocol_family_t protocol
, mbuf_t packet_list
)
275 struct proto_input_entry
*entry
;
276 errno_t locked
= 0, result
= 0;
278 for (entry
= proto_hash
[proto_hash_value(protocol
)]; entry
!= NULL
;
279 entry
= entry
->next
) {
280 if (entry
->protocol
== protocol
)
284 if (entry
->domain
&& !(entry
->domain
->dom_flags
& DOM_REENTRANT
)) {
285 lck_mtx_lock(entry
->domain
->dom_mtx
);
290 entry
->input(entry
->protocol
, packet_list
);
294 for (packet
= packet_list
; packet
!= NULL
;
295 packet
= packet_list
) {
296 packet_list
= mbuf_nextpkt(packet
);
297 mbuf_setnextpkt(packet
, NULL
);
298 entry
->input(entry
->protocol
, packet
);
303 lck_mtx_unlock(entry
->domain
->dom_mtx
);
309 proto_inject(protocol_family_t protocol
, mbuf_t packet_list
)
311 struct proto_input_entry
*entry
;
313 int hash_slot
= proto_hash_value(protocol
);
314 struct dlil_threading_info
*inp
= dlil_main_input_thread
;
316 for (last_packet
= packet_list
; mbuf_nextpkt(last_packet
) != NULL
;
317 last_packet
= mbuf_nextpkt(last_packet
))
318 /* find the last packet */;
320 for (entry
= proto_hash
[hash_slot
]; entry
!= NULL
;
321 entry
= entry
->next
) {
322 if (entry
->protocol
== protocol
)
327 lck_mtx_lock(&inp
->input_lck
);
328 if (entry
->inject_first
== NULL
) {
329 proto_total_waiting
++;
330 inp
->input_waiting
|= DLIL_PROTO_WAITING
;
331 entry
->inject_first
= packet_list
;
333 mbuf_setnextpkt(entry
->inject_last
, packet_list
);
335 entry
->inject_last
= last_packet
;
336 if ((inp
->input_waiting
& DLIL_INPUT_RUNNING
) == 0) {
337 wakeup((caddr_t
)&inp
->input_waiting
);
339 lck_mtx_unlock(&inp
->input_lck
);
347 static struct proto_family_str
*
348 proto_plumber_find(protocol_family_t proto_family
, ifnet_family_t if_family
)
350 struct proto_family_str
*mod
= NULL
;
352 TAILQ_FOREACH(mod
, &proto_family_head
, proto_fam_next
) {
353 if ((mod
->proto_family
== (proto_family
& 0xffff)) &&
354 (mod
->if_family
== (if_family
& 0xffff)))
362 proto_register_plumber(protocol_family_t protocol_family
,
363 ifnet_family_t interface_family
, proto_plumb_handler attach
,
364 proto_unplumb_handler detach
)
366 struct proto_family_str
*proto_family
;
371 lck_mtx_lock(proto_family_mutex
);
373 TAILQ_FOREACH(proto_family
, &proto_family_head
, proto_fam_next
) {
374 if (proto_family
->proto_family
== protocol_family
&&
375 proto_family
->if_family
== interface_family
) {
376 lck_mtx_unlock(proto_family_mutex
);
381 proto_family
= (struct proto_family_str
*)
382 _MALLOC(sizeof (struct proto_family_str
), M_IFADDR
, M_WAITOK
);
384 lck_mtx_unlock(proto_family_mutex
);
388 bzero(proto_family
, sizeof (struct proto_family_str
));
389 proto_family
->proto_family
= protocol_family
;
390 proto_family
->if_family
= interface_family
& 0xffff;
391 proto_family
->attach_proto
= attach
;
392 proto_family
->detach_proto
= detach
;
394 TAILQ_INSERT_TAIL(&proto_family_head
, proto_family
, proto_fam_next
);
395 lck_mtx_unlock(proto_family_mutex
);
400 proto_unregister_plumber(protocol_family_t protocol_family
,
401 ifnet_family_t interface_family
)
403 struct proto_family_str
*proto_family
;
405 lck_mtx_lock(proto_family_mutex
);
407 proto_family
= proto_plumber_find(protocol_family
, interface_family
);
408 if (proto_family
== NULL
) {
409 lck_mtx_unlock(proto_family_mutex
);
413 TAILQ_REMOVE(&proto_family_head
, proto_family
, proto_fam_next
);
414 FREE(proto_family
, M_IFADDR
);
416 lck_mtx_unlock(proto_family_mutex
);
419 __private_extern__ errno_t
420 proto_plumb(protocol_family_t protocol_family
, ifnet_t ifp
)
422 struct proto_family_str
*proto_family
;
425 lck_mtx_lock(proto_family_mutex
);
426 proto_family
= proto_plumber_find(protocol_family
, ifp
->if_family
);
427 if (proto_family
== NULL
) {
428 lck_mtx_unlock(proto_family_mutex
);
432 ret
= proto_family
->attach_proto(ifp
, protocol_family
);
434 lck_mtx_unlock(proto_family_mutex
);
439 __private_extern__ errno_t
440 proto_unplumb(protocol_family_t protocol_family
, ifnet_t ifp
)
442 struct proto_family_str
*proto_family
;
445 lck_mtx_lock(proto_family_mutex
);
447 proto_family
= proto_plumber_find(protocol_family
, ifp
->if_family
);
448 if (proto_family
!= NULL
&& proto_family
->detach_proto
)
449 proto_family
->detach_proto(ifp
, protocol_family
);
451 ret
= ifnet_detach_protocol(ifp
, protocol_family
);
453 lck_mtx_unlock(proto_family_mutex
);