]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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. | |
11 | * | |
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 | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 1999 Apple Computer, Inc. | |
24 | * | |
25 | * Data Link Inteface Layer | |
26 | * Author: Ted Walker | |
27 | */ | |
28 | ||
29 | ||
30 | ||
31 | #include <sys/param.h> | |
32 | #include <sys/systm.h> | |
33 | #include <sys/kernel.h> | |
34 | #include <sys/malloc.h> | |
35 | #include <sys/mbuf.h> | |
36 | #include <sys/socket.h> | |
37 | #include <net/if_dl.h> | |
38 | #include <net/if.h> | |
39 | #include <net/if_var.h> | |
40 | #include <net/dlil.h> | |
41 | #include <sys/kern_event.h> | |
42 | #include <sys/kdebug.h> | |
43 | #include <string.h> | |
44 | ||
45 | #include <kern/thread.h> | |
46 | #include <kern/task.h> | |
47 | #include <net/netisr.h> | |
48 | #include <net/if_types.h> | |
49 | ||
50 | ||
51 | #define DBG_LAYER_BEG DLILDBG_CODE(DBG_DLIL_STATIC, 0) | |
52 | #define DBG_LAYER_END DLILDBG_CODE(DBG_DLIL_STATIC, 2) | |
53 | #define DBG_FNC_DLIL_INPUT DLILDBG_CODE(DBG_DLIL_STATIC, (1 << 8)) | |
54 | #define DBG_FNC_DLIL_OUTPUT DLILDBG_CODE(DBG_DLIL_STATIC, (2 << 8)) | |
55 | #define DBG_FNC_DLIL_IFOUT DLILDBG_CODE(DBG_DLIL_STATIC, (3 << 8)) | |
56 | ||
57 | ||
58 | #define MAX_DL_TAGS 50 | |
59 | #define MAX_DLIL_FILTERS 50 | |
60 | #define MAX_FRAME_TYPE_SIZE 4 /* LONGWORDS */ | |
61 | #define MAX_LINKADDR 4 /* LONGWORDS */ | |
62 | #define M_NKE M_IFADDR | |
63 | ||
64 | #define PFILT(x) ((struct dlil_filterq_entry *) (x))->variants.pr_filter | |
65 | #define IFILT(x) ((struct dlil_filterq_entry *) (x))->variants.if_filter | |
66 | ||
67 | struct dl_tag_str { | |
68 | struct ifnet *ifp; | |
69 | struct if_proto *proto; | |
70 | struct dlil_filterq_head *pr_flt_head; | |
71 | }; | |
72 | ||
73 | ||
74 | struct dlil_stats_str { | |
75 | int inject_pr_in1; | |
76 | int inject_pr_in2; | |
77 | int inject_pr_out1; | |
78 | int inject_pr_out2; | |
79 | int inject_if_in1; | |
80 | int inject_if_in2; | |
81 | int inject_if_out1; | |
82 | int inject_if_out2; | |
83 | }; | |
84 | ||
85 | ||
86 | struct dlil_filter_id_str { | |
87 | int type; | |
88 | struct dlil_filterq_head *head; | |
89 | struct dlil_filterq_entry *filter_ptr; | |
90 | struct ifnet *ifp; | |
91 | struct if_proto *proto; | |
92 | }; | |
93 | ||
94 | ||
95 | ||
96 | struct if_family_str { | |
97 | TAILQ_ENTRY(if_family_str) if_fam_next; | |
98 | u_long if_family; | |
99 | int refcnt; | |
100 | int flags; | |
101 | ||
102 | #define DLIL_SHUTDOWN 1 | |
103 | ||
104 | int (*add_if)(struct ifnet *ifp); | |
105 | int (*del_if)(struct ifnet *ifp); | |
106 | int (*add_proto)(struct ddesc_head_str *demux_desc_head, | |
107 | struct if_proto *proto, u_long dl_tag); | |
108 | int (*del_proto)(struct if_proto *proto, u_long dl_tag); | |
109 | int (*ifmod_ioctl)(struct ifnet *ifp, u_long command, caddr_t data); | |
110 | int (*shutdown)(); | |
111 | }; | |
112 | ||
113 | ||
114 | ||
115 | struct dlil_stats_str dlil_stats; | |
116 | ||
117 | static | |
118 | struct dlil_filter_id_str dlil_filters[MAX_DLIL_FILTERS+1]; | |
119 | ||
120 | static | |
121 | struct dl_tag_str dl_tag_array[MAX_DL_TAGS+1]; | |
122 | ||
123 | static | |
124 | TAILQ_HEAD(, if_family_str) if_family_head; | |
125 | ||
126 | static ifnet_inited = 0; | |
127 | ||
128 | int dlil_initialized = 0; | |
129 | decl_simple_lock_data(, dlil_input_lock) | |
130 | int dlil_input_thread_wakeup = 0; | |
131 | int dlil_expand_mcl; | |
132 | static struct mbuf *dlil_input_mbuf_head = NULL; | |
133 | static struct mbuf *dlil_input_mbuf_tail = NULL; | |
134 | static struct mbuf *dlil_input_loop_head = NULL; | |
135 | static struct mbuf *dlil_input_loop_tail = NULL; | |
136 | ||
137 | static void dlil_input_thread(void); | |
138 | extern void run_netisr(void); | |
139 | ||
140 | ||
141 | /* | |
142 | * Internal functions. | |
143 | */ | |
144 | ||
145 | static | |
146 | struct if_family_str *find_family_module(u_long if_family) | |
147 | { | |
148 | struct if_family_str *mod = NULL; | |
149 | ||
150 | TAILQ_FOREACH(mod, &if_family_head, if_fam_next) { | |
151 | if (mod->if_family == (if_family & 0xffff)) | |
152 | break; | |
153 | } | |
154 | ||
155 | return mod; | |
156 | } | |
157 | ||
158 | ||
159 | /* | |
160 | * Public functions. | |
161 | */ | |
162 | ||
163 | struct ifnet *ifbyfamily(u_long family, short unit) | |
164 | { | |
165 | struct ifnet *ifp; | |
166 | ||
167 | TAILQ_FOREACH(ifp, &ifnet, if_link) | |
168 | if ((family == ifp->if_family) && | |
169 | (ifp->if_unit == unit)) | |
170 | return ifp; | |
171 | ||
172 | return 0; | |
173 | } | |
174 | ||
175 | struct if_proto *dlttoproto(dl_tag) | |
176 | u_long dl_tag; | |
177 | { | |
178 | return dl_tag_array[dl_tag].proto; | |
179 | } | |
180 | ||
181 | ||
182 | static int dlil_ifp_proto_count(struct ifnet * ifp) | |
183 | { | |
184 | int count = 0; | |
185 | struct if_proto * proto; | |
186 | struct dlil_proto_head * tmp; | |
187 | ||
188 | tmp = (struct dlil_proto_head *) &ifp->proto_head; | |
189 | ||
190 | TAILQ_FOREACH(proto, tmp, next) | |
191 | count++; | |
192 | ||
193 | return count; | |
194 | } | |
195 | ||
196 | u_long ifptodlt(struct ifnet *ifp, u_long proto_family) | |
197 | { | |
198 | struct if_proto *proto; | |
199 | struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head; | |
200 | ||
201 | ||
202 | TAILQ_FOREACH(proto, tmp, next) | |
203 | if (proto->protocol_family == proto_family) | |
204 | return proto->dl_tag; | |
205 | ||
206 | return 0; | |
207 | } | |
208 | ||
209 | ||
210 | int dlil_find_dltag(u_long if_family, short unit, u_long proto_family, u_long *dl_tag) | |
211 | { | |
212 | struct ifnet *ifp; | |
213 | ||
214 | ifp = ifbyfamily(if_family, unit); | |
215 | if (!ifp) | |
216 | return ENOENT; | |
217 | ||
218 | *dl_tag = ifptodlt(ifp, proto_family); | |
219 | if (*dl_tag == 0) | |
220 | return EPROTONOSUPPORT; | |
221 | else | |
222 | return 0; | |
223 | } | |
224 | ||
225 | ||
226 | int dlil_get_next_dl_tag(u_long current_tag, struct dl_tag_attr_str *next) | |
227 | { | |
228 | int i; | |
229 | ||
230 | for (i = (current_tag+1); i < MAX_DL_TAGS; i++) | |
231 | if (dl_tag_array[i].ifp) { | |
232 | next->dl_tag = i; | |
233 | next->if_flags = dl_tag_array[i].ifp->if_flags; | |
234 | next->if_unit = dl_tag_array[i].ifp->if_unit; | |
235 | next->protocol_family = dl_tag_array[i].proto->protocol_family; | |
236 | next->if_family = dl_tag_array[i].ifp->if_family; | |
237 | return 0; | |
238 | } | |
239 | ||
240 | /* | |
241 | * If we got here, there are no more entries | |
242 | */ | |
243 | ||
244 | return ENOENT; | |
245 | } | |
246 | ||
247 | void dlil_post_msg(struct ifnet *ifp, u_long event_subclass, u_long event_code, | |
248 | struct net_event_data *event_data, u_long event_data_len) | |
249 | { | |
250 | struct net_event_data ev_data; | |
251 | struct kev_msg ev_msg; | |
252 | ||
253 | /* | |
254 | * a net event always start with a net_event_data structure | |
255 | * but the caller can generate a simple net event or | |
256 | * provide a longer event structure to post | |
257 | */ | |
258 | ||
259 | ev_msg.vendor_code = KEV_VENDOR_APPLE; | |
260 | ev_msg.kev_class = KEV_NETWORK_CLASS; | |
261 | ev_msg.kev_subclass = event_subclass; | |
262 | ev_msg.event_code = event_code; | |
263 | ||
264 | if (event_data == 0) { | |
265 | event_data = &ev_data; | |
266 | event_data_len = sizeof(struct net_event_data); | |
267 | } | |
268 | ||
269 | strncpy(&event_data->if_name[0], ifp->if_name, IFNAMSIZ); | |
270 | event_data->if_family = ifp->if_family; | |
271 | event_data->if_unit = (unsigned long) ifp->if_unit; | |
272 | ||
273 | ev_msg.dv[0].data_length = event_data_len; | |
274 | ev_msg.dv[0].data_ptr = event_data; | |
275 | ev_msg.dv[1].data_length = 0; | |
276 | ||
277 | kev_post_msg(&ev_msg); | |
278 | } | |
279 | ||
280 | ||
281 | ||
282 | void | |
283 | dlil_init() | |
284 | { | |
285 | int i; | |
286 | ||
287 | printf("dlil_init\n"); | |
288 | ||
289 | TAILQ_INIT(&if_family_head); | |
290 | for (i=0; i < MAX_DL_TAGS; i++) | |
291 | dl_tag_array[i].ifp = 0; | |
292 | ||
293 | for (i=0; i < MAX_DLIL_FILTERS; i++) | |
294 | dlil_filters[i].type = 0; | |
295 | ||
296 | bzero(&dlil_stats, sizeof(dlil_stats)); | |
297 | ||
298 | simple_lock_init(&dlil_input_lock); | |
299 | ||
300 | /* | |
301 | * Start up the dlil input thread once everything is initialized | |
302 | */ | |
303 | (void) kernel_thread(kernel_task, dlil_input_thread); | |
304 | } | |
305 | ||
306 | ||
307 | u_long get_new_filter_id() | |
308 | { | |
309 | u_long i; | |
310 | ||
311 | for (i=1; i < MAX_DLIL_FILTERS; i++) | |
312 | if (dlil_filters[i].type == 0) | |
313 | return i; | |
314 | ||
315 | return 0; | |
316 | } | |
317 | ||
318 | ||
319 | int dlil_attach_interface_filter(struct ifnet *ifp, | |
320 | struct dlil_if_flt_str *if_filter, | |
321 | u_long *filter_id, | |
322 | int insertion_point) | |
323 | { | |
324 | int s; | |
325 | int retval; | |
326 | struct dlil_filterq_entry *tmp_ptr; | |
327 | struct dlil_filterq_entry *if_filt; | |
328 | struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
329 | boolean_t funnel_state; | |
330 | ||
331 | ||
332 | MALLOC(tmp_ptr, struct dlil_filterq_entry *, sizeof(*tmp_ptr), M_NKE, M_WAITOK); | |
333 | if (tmp_ptr == NULL) | |
334 | return (ENOBUFS); | |
335 | ||
336 | bcopy((caddr_t) if_filter, (caddr_t) &tmp_ptr->variants.if_filter, | |
337 | sizeof(struct dlil_if_flt_str)); | |
338 | ||
339 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
340 | ||
341 | s = splnet(); | |
342 | ||
343 | if (insertion_point != DLIL_LAST_FILTER) { | |
344 | TAILQ_FOREACH(if_filt, fhead, que) | |
345 | if (insertion_point == if_filt->filter_id) { | |
346 | TAILQ_INSERT_BEFORE(if_filt, tmp_ptr, que); | |
347 | break; | |
348 | } | |
349 | } | |
350 | else | |
351 | TAILQ_INSERT_TAIL(fhead, tmp_ptr, que); | |
352 | ||
353 | if (*filter_id = get_new_filter_id()) { | |
354 | dlil_filters[*filter_id].filter_ptr = tmp_ptr; | |
355 | dlil_filters[*filter_id].head = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
356 | dlil_filters[*filter_id].type = DLIL_IF_FILTER; | |
357 | dlil_filters[*filter_id].ifp = ifp; | |
358 | tmp_ptr->filter_id = *filter_id; | |
359 | tmp_ptr->type = DLIL_IF_FILTER; | |
360 | retval = 0; | |
361 | } | |
362 | else { | |
363 | kprintf("dlil_attach_interface_filter - can't alloc filter_id\n"); | |
364 | TAILQ_REMOVE(fhead, tmp_ptr, que); | |
365 | FREE(tmp_ptr, M_NKE); | |
366 | retval = ENOMEM; | |
367 | } | |
368 | ||
369 | splx(s); | |
370 | thread_funnel_set(network_flock, funnel_state); | |
371 | return retval; | |
372 | } | |
373 | ||
374 | ||
375 | int dlil_attach_protocol_filter(u_long dl_tag, | |
376 | struct dlil_pr_flt_str *pr_filter, | |
377 | u_long *filter_id, | |
378 | int insertion_point) | |
379 | { | |
380 | struct dlil_filterq_entry *tmp_ptr; | |
381 | struct dlil_filterq_entry *pr_filt; | |
382 | int s; | |
383 | int retval; | |
384 | boolean_t funnel_state; | |
385 | ||
386 | if (dl_tag > MAX_DL_TAGS) | |
387 | return ERANGE; | |
388 | ||
389 | if (dl_tag_array[dl_tag].ifp == 0) | |
390 | return ENOENT; | |
391 | ||
392 | MALLOC(tmp_ptr, struct dlil_filterq_entry *, sizeof(*tmp_ptr), M_NKE, M_WAITOK); | |
393 | if (tmp_ptr == NULL) | |
394 | return (ENOBUFS); | |
395 | ||
396 | bcopy((caddr_t) pr_filter, (caddr_t) &tmp_ptr->variants.pr_filter, | |
397 | sizeof(struct dlil_pr_flt_str)); | |
398 | ||
399 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
400 | ||
401 | s = splnet(); | |
402 | if (insertion_point != DLIL_LAST_FILTER) { | |
403 | TAILQ_FOREACH(pr_filt, dl_tag_array[dl_tag].pr_flt_head, que) | |
404 | if (insertion_point == pr_filt->filter_id) { | |
405 | TAILQ_INSERT_BEFORE(pr_filt, tmp_ptr, que); | |
406 | break; | |
407 | } | |
408 | } | |
409 | else | |
410 | TAILQ_INSERT_TAIL(dl_tag_array[dl_tag].pr_flt_head, tmp_ptr, que); | |
411 | ||
412 | ||
413 | if (*filter_id = get_new_filter_id()) { | |
414 | dlil_filters[*filter_id].filter_ptr = tmp_ptr; | |
415 | dlil_filters[*filter_id].head = dl_tag_array[dl_tag].pr_flt_head; | |
416 | dlil_filters[*filter_id].type = DLIL_PR_FILTER; | |
417 | dlil_filters[*filter_id].proto = dl_tag_array[dl_tag].proto; | |
418 | dlil_filters[*filter_id].ifp = dl_tag_array[dl_tag].ifp; | |
419 | tmp_ptr->filter_id = *filter_id; | |
420 | tmp_ptr->type = DLIL_PR_FILTER; | |
421 | retval = 0; | |
422 | } | |
423 | else { | |
424 | kprintf("dlil_attach_protocol_filter - can't alloc filter_id\n"); | |
425 | TAILQ_REMOVE(dl_tag_array[dl_tag].pr_flt_head, tmp_ptr, que); | |
426 | FREE(tmp_ptr, M_NKE); | |
427 | retval = ENOMEM; | |
428 | } | |
429 | ||
430 | splx(s); | |
431 | thread_funnel_set(network_flock, funnel_state); | |
432 | return retval; | |
433 | } | |
434 | ||
435 | ||
436 | int | |
437 | dlil_detach_filter(u_long filter_id) | |
438 | { | |
439 | struct dlil_filter_id_str *flt; | |
440 | int s; | |
441 | boolean_t funnel_state; | |
442 | ||
443 | if (filter_id > MAX_DLIL_FILTERS) { | |
444 | kprintf("dlil_detach_filter - Bad filter_id value %d\n", filter_id); | |
445 | return ERANGE; | |
446 | } | |
447 | ||
448 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
449 | s = splnet(); | |
450 | flt = &dlil_filters[filter_id]; | |
451 | if (flt->type == 0) { | |
452 | kprintf("dlil_detach_filter - no such filter_id %d\n", filter_id); | |
453 | thread_funnel_set(network_flock, funnel_state); | |
454 | return ENOENT; | |
455 | } | |
456 | ||
457 | ||
458 | if (flt->type == DLIL_IF_FILTER) { | |
459 | if (IFILT(flt->filter_ptr).filter_detach) | |
460 | (*IFILT(flt->filter_ptr).filter_detach)(IFILT(flt->filter_ptr).cookie); | |
461 | } | |
462 | else { | |
463 | if (flt->type == DLIL_PR_FILTER) { | |
464 | if (PFILT(flt->filter_ptr).filter_detach) | |
465 | (*PFILT(flt->filter_ptr).filter_detach)(PFILT(flt->filter_ptr).cookie); | |
466 | } | |
467 | } | |
468 | ||
469 | TAILQ_REMOVE(flt->head, flt->filter_ptr, que); | |
470 | FREE(flt->filter_ptr, M_NKE); | |
471 | flt->type = 0; | |
472 | splx(s); | |
473 | thread_funnel_set(network_flock, funnel_state); | |
474 | return 0; | |
475 | } | |
476 | ||
477 | ||
478 | void | |
479 | dlil_input_thread_continue(void) | |
480 | { | |
481 | while (1) { | |
482 | struct mbuf *m, *m_loop; | |
483 | int expand_mcl; | |
484 | ||
485 | usimple_lock(&dlil_input_lock); | |
486 | m = dlil_input_mbuf_head; | |
487 | dlil_input_mbuf_head = NULL; | |
488 | dlil_input_mbuf_tail = NULL; | |
489 | m_loop = dlil_input_loop_head; | |
490 | dlil_input_loop_head = NULL; | |
491 | dlil_input_loop_tail = NULL; | |
492 | usimple_unlock(&dlil_input_lock); | |
493 | ||
494 | MBUF_LOCK(); | |
495 | expand_mcl = dlil_expand_mcl; | |
496 | dlil_expand_mcl = 0; | |
497 | MBUF_UNLOCK(); | |
498 | if (expand_mcl) { | |
499 | caddr_t p; | |
500 | MCLALLOC(p, M_WAIT); | |
501 | if (p) MCLFREE(p); | |
502 | } | |
503 | ||
504 | /* | |
505 | * NOTE warning %%% attention !!!! | |
506 | * We should think about putting some thread starvation safeguards if | |
507 | * we deal with long chains of packets. | |
508 | */ | |
509 | while (m) { | |
510 | struct mbuf *m0 = m->m_nextpkt; | |
511 | void *header = m->m_pkthdr.header; | |
512 | ||
513 | m->m_nextpkt = NULL; | |
514 | m->m_pkthdr.header = NULL; | |
515 | (void) dlil_input_packet(m->m_pkthdr.rcvif, m, header); | |
516 | m = m0; | |
517 | } | |
518 | m = m_loop; | |
519 | while (m) { | |
520 | struct mbuf *m0 = m->m_nextpkt; | |
521 | void *header = m->m_pkthdr.header; | |
522 | struct ifnet *ifp = (struct ifnet *) m->m_pkthdr.aux; | |
523 | ||
524 | m->m_nextpkt = NULL; | |
525 | m->m_pkthdr.header = NULL; | |
526 | m->m_pkthdr.aux = NULL; | |
527 | (void) dlil_input_packet(ifp, m, header); | |
528 | m = m0; | |
529 | } | |
530 | ||
531 | if (netisr != 0) | |
532 | run_netisr(); | |
533 | ||
534 | if (dlil_input_mbuf_head == NULL && | |
535 | dlil_input_loop_head == NULL && | |
536 | netisr == 0) { | |
537 | assert_wait(&dlil_input_thread_wakeup, THREAD_UNINT); | |
538 | #if defined (__i386__) | |
539 | thread_block(0); | |
540 | #else | |
541 | thread_block(dlil_input_thread_continue); | |
542 | #endif | |
543 | /* NOTREACHED */ | |
544 | } | |
545 | } | |
546 | } | |
547 | ||
548 | void dlil_input_thread(void) | |
549 | { | |
550 | register thread_t self = current_thread(); | |
551 | extern void stack_privilege(thread_t thread); | |
552 | ||
553 | printf("dlil_input_thread %x\n", self); | |
554 | ||
555 | /* | |
556 | * Make sure that this thread | |
557 | * always has a kernel stack, and | |
558 | * bind it to the master cpu. | |
559 | */ | |
560 | stack_privilege(self); | |
561 | ||
562 | /* The dlil thread is always funneled */ | |
563 | thread_funnel_set(network_flock, TRUE); | |
564 | dlil_initialized = 1; | |
565 | dlil_input_thread_continue(); | |
566 | } | |
567 | ||
568 | int | |
569 | dlil_input(struct ifnet *ifp, struct mbuf *m_head, struct mbuf *m_tail) | |
570 | { | |
571 | /* WARNING | |
572 | * Because of loopbacked multicast we cannot stuff the ifp in | |
573 | * the rcvif of the packet header: loopback has its own dlil | |
574 | * input queue | |
575 | */ | |
576 | ||
577 | usimple_lock(&dlil_input_lock); | |
578 | if (ifp->if_type != IFT_LOOP) { | |
579 | if (dlil_input_mbuf_head == NULL) | |
580 | dlil_input_mbuf_head = m_head; | |
581 | else if (dlil_input_mbuf_tail != NULL) | |
582 | dlil_input_mbuf_tail->m_nextpkt = m_head; | |
583 | dlil_input_mbuf_tail = m_tail ? m_tail : m_head; | |
584 | } else { | |
585 | if (dlil_input_loop_head == NULL) | |
586 | dlil_input_loop_head = m_head; | |
587 | else if (dlil_input_loop_tail != NULL) | |
588 | dlil_input_loop_tail->m_nextpkt = m_head; | |
589 | dlil_input_loop_tail = m_tail ? m_tail : m_head; | |
590 | } | |
591 | usimple_unlock(&dlil_input_lock); | |
592 | ||
593 | wakeup((caddr_t)&dlil_input_thread_wakeup); | |
594 | ||
595 | return 0; | |
596 | } | |
597 | ||
598 | int | |
599 | dlil_input_packet(struct ifnet *ifp, struct mbuf *m, | |
600 | char *frame_header) | |
601 | { | |
602 | struct ifnet *orig_ifp = 0; | |
603 | struct dlil_filterq_entry *tmp; | |
604 | int retval; | |
605 | struct if_proto *ifproto = 0; | |
606 | struct if_proto *proto; | |
607 | struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
608 | ||
609 | ||
610 | KERNEL_DEBUG(DBG_FNC_DLIL_INPUT | DBG_FUNC_START,0,0,0,0,0); | |
611 | ||
612 | /* | |
613 | * Run interface filters | |
614 | */ | |
615 | ||
616 | while (orig_ifp != ifp) { | |
617 | orig_ifp = ifp; | |
618 | ||
619 | TAILQ_FOREACH_REVERSE(tmp, fhead, que, dlil_filterq_head) { | |
620 | if (IFILT(tmp).filter_if_input) { | |
621 | retval = (*IFILT(tmp).filter_if_input)(IFILT(tmp).cookie, | |
622 | &ifp, | |
623 | &m, | |
624 | &frame_header); | |
625 | if (retval) { | |
626 | if (retval == EJUSTRETURN) | |
627 | return 0; | |
628 | else { | |
629 | m_freem(m); | |
630 | return retval; | |
631 | } | |
632 | } | |
633 | } | |
634 | ||
635 | if (ifp != orig_ifp) | |
636 | break; | |
637 | } | |
638 | } | |
639 | ||
640 | ifp->if_lastchange = time; | |
641 | ||
642 | /* | |
643 | * Call family demux module. If the demux module finds a match | |
644 | * for the frame it will fill-in the ifproto pointer. | |
645 | */ | |
646 | ||
647 | retval = (*ifp->if_demux)(ifp, m, frame_header, &ifproto ); | |
648 | ||
649 | if (m->m_flags & (M_BCAST|M_MCAST)) | |
650 | ifp->if_imcasts++; | |
651 | ||
652 | if ((retval) && (retval != EJUSTRETURN) && (ifp->offercnt)) { | |
653 | /* | |
654 | * No match was found, look for any offers. | |
655 | */ | |
656 | struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head; | |
657 | TAILQ_FOREACH(proto, tmp, next) { | |
658 | if ((proto->dl_offer) && (proto->dl_offer(m, frame_header) == 0)) { | |
659 | ifproto = proto; | |
660 | retval = 0; | |
661 | break; | |
662 | } | |
663 | } | |
664 | } | |
665 | ||
666 | if (retval) { | |
667 | if (retval != EJUSTRETURN) { | |
668 | m_freem(m); | |
669 | return retval; | |
670 | } | |
671 | else | |
672 | return 0; | |
673 | } | |
674 | else | |
675 | if (ifproto == 0) { | |
676 | printf("ERROR - dlil_input - if_demux didn't return an if_proto pointer\n"); | |
677 | m_freem(m); | |
678 | return 0; | |
679 | } | |
680 | ||
681 | /* | |
682 | * Call any attached protocol filters. | |
683 | */ | |
684 | ||
685 | TAILQ_FOREACH_REVERSE(tmp, &ifproto->pr_flt_head, que, dlil_filterq_head) { | |
686 | if (PFILT(tmp).filter_dl_input) { | |
687 | retval = (*PFILT(tmp).filter_dl_input)(PFILT(tmp).cookie, | |
688 | &m, | |
689 | &frame_header, | |
690 | &ifp); | |
691 | ||
692 | if (retval) { | |
693 | if (retval == EJUSTRETURN) | |
694 | return 0; | |
695 | else { | |
696 | m_freem(m); | |
697 | return retval; | |
698 | } | |
699 | } | |
700 | } | |
701 | } | |
702 | ||
703 | ||
704 | ||
705 | retval = (*ifproto->dl_input)(m, frame_header, | |
706 | ifp, ifproto->dl_tag, | |
707 | TRUE); | |
708 | ||
709 | if (retval == EJUSTRETURN) | |
710 | retval = 0; | |
711 | else | |
712 | if (retval) | |
713 | m_freem(m); | |
714 | ||
715 | KERNEL_DEBUG(DBG_FNC_DLIL_INPUT | DBG_FUNC_END,0,0,0,0,0); | |
716 | return retval; | |
717 | } | |
718 | ||
719 | ||
720 | ||
721 | void ether_input(ifp, eh, m) | |
722 | struct ifnet *ifp; | |
723 | struct ether_header *eh; | |
724 | struct mbuf *m; | |
725 | ||
726 | { | |
727 | kprintf("Someone is calling ether_input!!\n"); | |
728 | ||
729 | dlil_input(ifp, m, NULL); | |
730 | } | |
731 | ||
732 | ||
733 | int | |
734 | dlil_event(struct ifnet *ifp, struct kern_event_msg *event) | |
735 | { | |
736 | struct dlil_filterq_entry *filt; | |
737 | int retval = 0; | |
738 | struct ifnet *orig_ifp = 0; | |
739 | struct if_proto *proto; | |
740 | struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
741 | struct kev_msg kev_msg; | |
742 | struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head; | |
743 | boolean_t funnel_state; | |
744 | ||
745 | ||
746 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
747 | ||
748 | while (orig_ifp != ifp) { | |
749 | orig_ifp = ifp; | |
750 | ||
751 | TAILQ_FOREACH_REVERSE(filt, fhead, que, dlil_filterq_head) { | |
752 | if (IFILT(filt).filter_if_event) { | |
753 | retval = (*IFILT(filt).filter_if_event)(IFILT(filt).cookie, | |
754 | &ifp, | |
755 | &event); | |
756 | ||
757 | if (retval) { | |
758 | (void) thread_funnel_set(network_flock, funnel_state); | |
759 | if (retval == EJUSTRETURN) | |
760 | return 0; | |
761 | else | |
762 | return retval; | |
763 | } | |
764 | } | |
765 | ||
766 | if (ifp != orig_ifp) | |
767 | break; | |
768 | } | |
769 | } | |
770 | ||
771 | ||
772 | /* | |
773 | * Call Interface Module event hook, if any. | |
774 | */ | |
775 | ||
776 | if (ifp->if_event) { | |
777 | retval = ifp->if_event(ifp, (caddr_t) event); | |
778 | ||
779 | if (retval) { | |
780 | (void) thread_funnel_set(network_flock, funnel_state); | |
781 | ||
782 | if (retval == EJUSTRETURN) | |
783 | return 0; | |
784 | else | |
785 | return retval; | |
786 | } | |
787 | } | |
788 | ||
789 | /* | |
790 | * Call dl_event entry point for all protocols attached to this interface | |
791 | */ | |
792 | ||
793 | TAILQ_FOREACH(proto, tmp, next) { | |
794 | /* | |
795 | * Call any attached protocol filters. | |
796 | */ | |
797 | ||
798 | TAILQ_FOREACH_REVERSE(filt, &proto->pr_flt_head, que, dlil_filterq_head) { | |
799 | if (PFILT(filt).filter_dl_event) { | |
800 | retval = (*PFILT(filt).filter_dl_event)(PFILT(filt).cookie, | |
801 | event); | |
802 | ||
803 | if (retval) { | |
804 | (void) thread_funnel_set(network_flock, funnel_state); | |
805 | if (retval == EJUSTRETURN) | |
806 | return 0; | |
807 | else | |
808 | return retval; | |
809 | } | |
810 | } | |
811 | } | |
812 | ||
813 | ||
814 | /* | |
815 | * Finally, call the dl_event entry point (if any) | |
816 | */ | |
817 | ||
818 | if (proto->dl_event) | |
819 | retval = (*proto->dl_event)(event, proto->dl_tag); | |
820 | ||
821 | if (retval == EJUSTRETURN) { | |
822 | (void) thread_funnel_set(network_flock, funnel_state); | |
823 | return 0; | |
824 | } | |
825 | } | |
826 | ||
827 | ||
828 | /* | |
829 | * Now, post this event to the Kernel Event message queue | |
830 | */ | |
831 | ||
832 | kev_msg.vendor_code = event->vendor_code; | |
833 | kev_msg.kev_class = event->kev_class; | |
834 | kev_msg.kev_subclass = event->kev_subclass; | |
835 | kev_msg.event_code = event->event_code; | |
836 | kev_msg.dv[0].data_ptr = &event->event_data[0]; | |
837 | kev_msg.dv[0].data_length = event->total_size - KEV_MSG_HEADER_SIZE; | |
838 | kev_msg.dv[1].data_length = 0; | |
839 | ||
840 | kev_post_msg(&kev_msg); | |
841 | ||
842 | (void) thread_funnel_set(network_flock, funnel_state); | |
843 | return 0; | |
844 | } | |
845 | ||
846 | ||
847 | ||
848 | int | |
849 | dlil_output(u_long dl_tag, | |
850 | struct mbuf *m, | |
851 | caddr_t route, | |
852 | struct sockaddr *dest, | |
853 | int raw | |
854 | ) | |
855 | { | |
856 | char *frame_type; | |
857 | char *dst_linkaddr; | |
858 | struct ifnet *orig_ifp = 0; | |
859 | struct ifnet *ifp; | |
860 | struct if_proto *proto; | |
861 | struct dlil_filterq_entry *tmp; | |
862 | int retval = 0; | |
863 | char frame_type_buffer[MAX_FRAME_TYPE_SIZE * 4]; | |
864 | char dst_linkaddr_buffer[MAX_LINKADDR * 4]; | |
865 | struct dlil_filterq_head *fhead; | |
866 | ||
867 | ||
868 | KERNEL_DEBUG(DBG_FNC_DLIL_OUTPUT | DBG_FUNC_START,0,0,0,0,0); | |
869 | ||
870 | /* | |
871 | * Temporary hackery until all the existing protocols can become fully | |
872 | * "dl_tag aware". Some things only have the ifp, so this handles that | |
873 | * case for the time being. | |
874 | */ | |
875 | ||
876 | if (dl_tag > MAX_DL_TAGS) { | |
877 | /* dl_tag is really an ifnet pointer! */ | |
878 | ||
879 | ifp = (struct ifnet *) dl_tag; | |
880 | dl_tag = ifp->if_data.default_proto; | |
881 | if (dl_tag) | |
882 | proto = dl_tag_array[dl_tag].proto; | |
883 | else | |
884 | retval = ENOENT; | |
885 | } | |
886 | else { | |
887 | if ((dl_tag == 0) || (dl_tag_array[dl_tag].ifp == 0)) | |
888 | retval = ENOENT; | |
889 | else { | |
890 | ifp = dl_tag_array[dl_tag].ifp; | |
891 | proto = dl_tag_array[dl_tag].proto; | |
892 | } | |
893 | } | |
894 | ||
895 | if (retval) { | |
896 | m_freem(m); | |
897 | return retval; | |
898 | } | |
899 | ||
900 | frame_type = frame_type_buffer; | |
901 | dst_linkaddr = dst_linkaddr_buffer; | |
902 | ||
903 | fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
904 | ||
905 | if ((raw == 0) && (proto->dl_pre_output)) { | |
906 | retval = (*proto->dl_pre_output)(ifp, &m, dest, route, | |
907 | frame_type, dst_linkaddr, dl_tag); | |
908 | if (retval) { | |
909 | if (retval == EJUSTRETURN) | |
910 | return 0; | |
911 | else { | |
912 | m_freem(m); | |
913 | return retval; | |
914 | } | |
915 | } | |
916 | } | |
917 | ||
918 | /* | |
919 | * Run any attached protocol filters. | |
920 | */ | |
921 | ||
922 | if (TAILQ_EMPTY(dl_tag_array[dl_tag].pr_flt_head) == 0) { | |
923 | TAILQ_FOREACH(tmp, dl_tag_array[dl_tag].pr_flt_head, que) { | |
924 | if (PFILT(tmp).filter_dl_output) { | |
925 | retval = (*PFILT(tmp).filter_dl_output)(PFILT(tmp).cookie, | |
926 | &m, &ifp, &dest, dst_linkaddr, frame_type); | |
927 | if (retval) { | |
928 | if (retval == EJUSTRETURN) | |
929 | return 0; | |
930 | else { | |
931 | m_freem(m); | |
932 | return retval; | |
933 | } | |
934 | } | |
935 | } | |
936 | } | |
937 | } | |
938 | ||
939 | ||
940 | /* | |
941 | * Call framing module | |
942 | */ | |
943 | if ((raw == 0) && (ifp->if_framer)) { | |
944 | retval = (*ifp->if_framer)(ifp, &m, dest, dst_linkaddr, frame_type); | |
945 | if (retval) { | |
946 | if (retval == EJUSTRETURN) | |
947 | return 0; | |
948 | else | |
949 | { | |
950 | m_freem(m); | |
951 | return retval; | |
952 | } | |
953 | } | |
954 | } | |
955 | ||
956 | #if BRIDGE | |
957 | if (do_bridge) { | |
958 | struct mbuf *m0 = m ; | |
959 | ||
960 | if (m->m_pkthdr.rcvif) | |
961 | m->m_pkthdr.rcvif = NULL ; | |
962 | ifp = bridge_dst_lookup(m); | |
963 | bdg_forward(&m0, ifp); | |
964 | if (m0) | |
965 | m_freem(m0); | |
966 | ||
967 | return 0; | |
968 | } | |
969 | #endif | |
970 | ||
971 | ||
972 | /* | |
973 | * Let interface filters (if any) do their thing ... | |
974 | */ | |
975 | ||
976 | fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
977 | if (TAILQ_EMPTY(fhead) == 0) { | |
978 | while (orig_ifp != ifp) { | |
979 | orig_ifp = ifp; | |
980 | TAILQ_FOREACH(tmp, fhead, que) { | |
981 | if (IFILT(tmp).filter_if_output) { | |
982 | retval = (*IFILT(tmp).filter_if_output)(IFILT(tmp).cookie, | |
983 | &ifp, | |
984 | &m); | |
985 | if (retval) { | |
986 | if (retval == EJUSTRETURN) | |
987 | return 0; | |
988 | else { | |
989 | m_freem(m); | |
990 | return retval; | |
991 | } | |
992 | } | |
993 | ||
994 | } | |
995 | ||
996 | if (ifp != orig_ifp) | |
997 | break; | |
998 | } | |
999 | } | |
1000 | } | |
1001 | ||
1002 | /* | |
1003 | * Finally, call the driver. | |
1004 | */ | |
1005 | ||
1006 | KERNEL_DEBUG(DBG_FNC_DLIL_IFOUT | DBG_FUNC_START, 0,0,0,0,0); | |
1007 | retval = (*ifp->if_output)(ifp, m); | |
1008 | KERNEL_DEBUG(DBG_FNC_DLIL_IFOUT | DBG_FUNC_END, 0,0,0,0,0); | |
1009 | ||
1010 | KERNEL_DEBUG(DBG_FNC_DLIL_OUTPUT | DBG_FUNC_END,0,0,0,0,0); | |
1011 | ||
1012 | if ((retval == 0) || (retval == EJUSTRETURN)) | |
1013 | return 0; | |
1014 | else | |
1015 | return retval; | |
1016 | } | |
1017 | ||
1018 | ||
1019 | int | |
1020 | dlil_ioctl(u_long proto_fam, | |
1021 | struct ifnet *ifp, | |
1022 | u_long ioctl_code, | |
1023 | caddr_t ioctl_arg) | |
1024 | { | |
1025 | struct dlil_filterq_entry *tmp; | |
1026 | struct dlil_filterq_head *fhead; | |
1027 | int retval = EOPNOTSUPP; | |
1028 | int retval2 = EOPNOTSUPP; | |
1029 | u_long dl_tag; | |
1030 | struct if_family_str *if_family; | |
1031 | ||
1032 | ||
1033 | if (proto_fam) { | |
1034 | retval = dlil_find_dltag(ifp->if_family, ifp->if_unit, | |
1035 | proto_fam, &dl_tag); | |
1036 | ||
1037 | if (retval == 0) { | |
1038 | if (dl_tag_array[dl_tag].ifp != ifp) | |
1039 | return ENOENT; | |
1040 | ||
1041 | /* | |
1042 | * Run any attached protocol filters. | |
1043 | */ | |
1044 | TAILQ_FOREACH(tmp, dl_tag_array[dl_tag].pr_flt_head, que) { | |
1045 | if (PFILT(tmp).filter_dl_ioctl) { | |
1046 | retval = | |
1047 | (*PFILT(tmp).filter_dl_ioctl)(PFILT(tmp).cookie, | |
1048 | dl_tag_array[dl_tag].ifp, | |
1049 | ioctl_code, | |
1050 | ioctl_arg); | |
1051 | ||
1052 | if (retval) { | |
1053 | if (retval == EJUSTRETURN) | |
1054 | return 0; | |
1055 | else | |
1056 | return retval; | |
1057 | } | |
1058 | } | |
1059 | } | |
1060 | ||
1061 | if (dl_tag_array[dl_tag].proto->dl_ioctl) | |
1062 | retval = | |
1063 | (*dl_tag_array[dl_tag].proto->dl_ioctl)(dl_tag, | |
1064 | dl_tag_array[dl_tag].ifp, | |
1065 | ioctl_code, | |
1066 | ioctl_arg); | |
1067 | else | |
1068 | retval = EOPNOTSUPP; | |
1069 | } | |
1070 | else | |
1071 | retval = 0; | |
1072 | } | |
1073 | ||
1074 | if ((retval) && (retval != EOPNOTSUPP)) { | |
1075 | if (retval == EJUSTRETURN) | |
1076 | return 0; | |
1077 | else | |
1078 | return retval; | |
1079 | } | |
1080 | ||
1081 | ||
1082 | fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
1083 | TAILQ_FOREACH(tmp, fhead, que) { | |
1084 | if (IFILT(tmp).filter_if_ioctl) { | |
1085 | retval2 = (*IFILT(tmp).filter_if_ioctl)(IFILT(tmp).cookie, ifp, | |
1086 | ioctl_code, ioctl_arg); | |
1087 | if (retval2) { | |
1088 | if (retval2 == EJUSTRETURN) | |
1089 | return 0; | |
1090 | else | |
1091 | return retval2; | |
1092 | } | |
1093 | } | |
1094 | } | |
1095 | ||
1096 | ||
1097 | if_family = find_family_module(ifp->if_family); | |
1098 | if ((if_family) && (if_family->ifmod_ioctl)) { | |
1099 | retval2 = (*if_family->ifmod_ioctl)(ifp, ioctl_code, ioctl_arg); | |
1100 | ||
1101 | if ((retval2) && (retval2 != EOPNOTSUPP)) { | |
1102 | if (retval2 == EJUSTRETURN) | |
1103 | return 0; | |
1104 | else | |
1105 | return retval; | |
1106 | } | |
1107 | ||
1108 | if (retval == EOPNOTSUPP) | |
1109 | retval = retval2; | |
1110 | } | |
1111 | ||
1112 | if (ifp->if_ioctl) | |
1113 | retval2 = (*ifp->if_ioctl)(ifp, ioctl_code, ioctl_arg); | |
1114 | ||
1115 | if (retval == EOPNOTSUPP) | |
1116 | return retval2; | |
1117 | else { | |
1118 | if (retval2 == EOPNOTSUPP) | |
1119 | return 0; | |
1120 | else | |
1121 | return retval2; | |
1122 | } | |
1123 | } | |
1124 | ||
1125 | ||
1126 | int | |
1127 | dlil_attach_protocol(struct dlil_proto_reg_str *proto, | |
1128 | u_long *dl_tag) | |
1129 | { | |
1130 | struct ifnet *ifp; | |
1131 | struct if_proto *ifproto; | |
1132 | u_long i; | |
1133 | struct if_family_str *if_family; | |
1134 | int error; | |
1135 | struct dlil_proto_head *tmp; | |
1136 | struct kev_dl_proto_data ev_pr_data; | |
1137 | int s; | |
1138 | boolean_t funnel_state; | |
1139 | ||
1140 | ||
1141 | if ((proto->protocol_family == 0) || (proto->interface_family == 0)) | |
1142 | return EINVAL; | |
1143 | ||
1144 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
1145 | s = splnet(); | |
1146 | if_family = find_family_module(proto->interface_family); | |
1147 | if ((!if_family) || (if_family->flags & DLIL_SHUTDOWN)) { | |
1148 | kprintf("dlil_attach_protocol -- no interface family module %d", | |
1149 | proto->interface_family); | |
1150 | splx(s); | |
1151 | thread_funnel_set(network_flock, funnel_state); | |
1152 | return ENOENT; | |
1153 | } | |
1154 | ||
1155 | ifp = ifbyfamily(proto->interface_family, proto->unit_number); | |
1156 | if (!ifp) { | |
1157 | kprintf("dlil_attach_protocol -- no such interface %d unit %d\n", | |
1158 | proto->interface_family, proto->unit_number); | |
1159 | splx(s); | |
1160 | thread_funnel_set(network_flock, funnel_state); | |
1161 | return ENOENT; | |
1162 | } | |
1163 | ||
1164 | if (dlil_find_dltag(proto->interface_family, proto->unit_number, | |
1165 | proto->protocol_family, &i) == 0) { | |
1166 | thread_funnel_set(network_flock, funnel_state); | |
1167 | return EEXIST; | |
1168 | } | |
1169 | ||
1170 | for (i=1; i < MAX_DL_TAGS; i++) | |
1171 | if (dl_tag_array[i].ifp == 0) | |
1172 | break; | |
1173 | ||
1174 | if (i >= MAX_DL_TAGS) { | |
1175 | splx(s); | |
1176 | thread_funnel_set(network_flock, funnel_state); | |
1177 | return ENOMEM; | |
1178 | } | |
1179 | ||
1180 | /* | |
1181 | * Allocate and init a new if_proto structure | |
1182 | */ | |
1183 | ||
1184 | ifproto = _MALLOC(sizeof(struct if_proto), M_IFADDR, M_WAITOK); | |
1185 | if (!ifproto) { | |
1186 | printf("ERROR - DLIL failed if_proto allocation\n"); | |
1187 | thread_funnel_set(network_flock, funnel_state); | |
1188 | return ENOMEM; | |
1189 | } | |
1190 | ||
1191 | bzero(ifproto, sizeof(struct if_proto)); | |
1192 | ||
1193 | dl_tag_array[i].ifp = ifp; | |
1194 | dl_tag_array[i].proto = ifproto; | |
1195 | dl_tag_array[i].pr_flt_head = &ifproto->pr_flt_head; | |
1196 | ifproto->dl_tag = i; | |
1197 | *dl_tag = i; | |
1198 | ||
1199 | if (proto->default_proto) { | |
1200 | if (ifp->if_data.default_proto == 0) | |
1201 | ifp->if_data.default_proto = i; | |
1202 | else | |
1203 | printf("ERROR - dlil_attach_protocol -- Attempt to attach more than one default protocol\n"); | |
1204 | } | |
1205 | ||
1206 | ifproto->protocol_family = proto->protocol_family; | |
1207 | ifproto->dl_input = proto->input; | |
1208 | ifproto->dl_pre_output = proto->pre_output; | |
1209 | ifproto->dl_event = proto->event; | |
1210 | ifproto->dl_offer = proto->offer; | |
1211 | ifproto->dl_ioctl = proto->ioctl; | |
1212 | ifproto->ifp = ifp; | |
1213 | TAILQ_INIT(&ifproto->pr_flt_head); | |
1214 | ||
1215 | /* | |
1216 | * Call family module add_proto routine so it can refine the | |
1217 | * demux descriptors as it wishes. | |
1218 | */ | |
1219 | error = (*if_family->add_proto)(&proto->demux_desc_head, ifproto, *dl_tag); | |
1220 | if (error) { | |
1221 | dl_tag_array[*dl_tag].ifp = 0; | |
1222 | FREE(ifproto, M_IFADDR); | |
1223 | splx(s); | |
1224 | thread_funnel_set(network_flock, funnel_state); | |
1225 | return error; | |
1226 | } | |
1227 | ||
1228 | /* | |
1229 | * Add to if_proto list for this interface | |
1230 | */ | |
1231 | ||
1232 | tmp = (struct dlil_proto_head *) &ifp->proto_head; | |
1233 | TAILQ_INSERT_TAIL(tmp, ifproto, next); | |
1234 | ifp->refcnt++; | |
1235 | if (ifproto->dl_offer) | |
1236 | ifp->offercnt++; | |
1237 | ||
1238 | /* the reserved field carries the number of protocol still attached (subject to change) */ | |
1239 | ev_pr_data.proto_family = proto->protocol_family; | |
1240 | ev_pr_data.proto_remaining_count = dlil_ifp_proto_count(ifp); | |
1241 | dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_PROTO_ATTACHED, | |
1242 | (struct net_event_data *)&ev_pr_data, | |
1243 | sizeof(struct kev_dl_proto_data)); | |
1244 | ||
1245 | splx(s); | |
1246 | thread_funnel_set(network_flock, funnel_state); | |
1247 | return 0; | |
1248 | } | |
1249 | ||
1250 | ||
1251 | ||
1252 | int | |
1253 | dlil_detach_protocol(u_long dl_tag) | |
1254 | { | |
1255 | struct ifnet *ifp; | |
1256 | struct ifnet *orig_ifp=0; | |
1257 | struct if_proto *proto; | |
1258 | struct dlil_proto_head *tmp; | |
1259 | struct if_family_str *if_family; | |
1260 | struct dlil_filterq_entry *filter; | |
1261 | int s, retval; | |
1262 | struct dlil_filterq_head *fhead; | |
1263 | struct kev_dl_proto_data ev_pr_data; | |
1264 | boolean_t funnel_state; | |
1265 | ||
1266 | ||
1267 | if (dl_tag > MAX_DL_TAGS) | |
1268 | return ERANGE; | |
1269 | ||
1270 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
1271 | ||
1272 | s = splnet(); | |
1273 | if (dl_tag_array[dl_tag].ifp == 0) { | |
1274 | splx(s); | |
1275 | thread_funnel_set(network_flock, funnel_state); | |
1276 | return ENOENT; | |
1277 | } | |
1278 | ||
1279 | ifp = dl_tag_array[dl_tag].ifp; | |
1280 | proto = dl_tag_array[dl_tag].proto; | |
1281 | ||
1282 | if_family = find_family_module(ifp->if_family); | |
1283 | if (if_family == NULL) { | |
1284 | splx(s); | |
1285 | thread_funnel_set(network_flock, funnel_state); | |
1286 | return ENOENT; | |
1287 | } | |
1288 | ||
1289 | tmp = (struct dlil_proto_head *) &ifp->proto_head; | |
1290 | ||
1291 | /* | |
1292 | * Call family module del_proto | |
1293 | */ | |
1294 | ||
1295 | (*if_family->del_proto)(proto, dl_tag); | |
1296 | ||
1297 | ||
1298 | /* | |
1299 | * Remove and deallocate any attached protocol filters | |
1300 | */ | |
1301 | ||
1302 | while (filter = TAILQ_FIRST(&proto->pr_flt_head)) | |
1303 | dlil_detach_filter(filter->filter_id); | |
1304 | ||
1305 | if (proto->dl_offer) | |
1306 | ifp->offercnt--; | |
1307 | ||
1308 | if (ifp->if_data.default_proto == dl_tag) | |
1309 | ifp->if_data.default_proto = 0; | |
1310 | dl_tag_array[dl_tag].ifp = 0; | |
1311 | ||
1312 | /* the reserved field carries the number of protocol still attached (subject to change) */ | |
1313 | ev_pr_data.proto_family = proto->protocol_family; | |
1314 | TAILQ_REMOVE(tmp, proto, next); | |
1315 | FREE(proto, M_IFADDR); | |
1316 | ||
1317 | ifp->refcnt--; | |
1318 | ev_pr_data.proto_remaining_count = dlil_ifp_proto_count(ifp); | |
1319 | dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_PROTO_DETACHED, | |
1320 | (struct net_event_data *)&ev_pr_data, | |
1321 | sizeof(struct kev_dl_proto_data)); | |
1322 | ||
1323 | if (ifp->refcnt == 0 && (ifp->if_eflags & IFEF_DETACH_DISABLED) == 0) { | |
1324 | if (ifp->if_flags & IFF_UP) | |
1325 | printf("WARNING - dlil_detach_protocol - ifp refcnt 0, but IF still up\n"); | |
1326 | ||
1327 | TAILQ_REMOVE(&ifnet, ifp, if_link); | |
1328 | ||
1329 | (*if_family->del_if)(ifp); | |
1330 | ||
1331 | if (--if_family->refcnt == 0) { | |
1332 | if (if_family->shutdown) | |
1333 | (*if_family->shutdown)(); | |
1334 | ||
1335 | TAILQ_REMOVE(&if_family_head, if_family, if_fam_next); | |
1336 | FREE(if_family, M_IFADDR); | |
1337 | } | |
1338 | ||
1339 | fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
1340 | while (orig_ifp != ifp) { | |
1341 | orig_ifp = ifp; | |
1342 | ||
1343 | TAILQ_FOREACH(filter, fhead, que) { | |
1344 | if (IFILT(filter).filter_if_free) { | |
1345 | retval = (*IFILT(filter).filter_if_free)(IFILT(filter).cookie, ifp); | |
1346 | if (retval) { | |
1347 | splx(s); | |
1348 | thread_funnel_set(network_flock, funnel_state); | |
1349 | return 0; | |
1350 | } | |
1351 | } | |
1352 | if (ifp != orig_ifp) | |
1353 | break; | |
1354 | } | |
1355 | } | |
1356 | ||
1357 | dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IF_DETACHED, 0, 0); | |
1358 | ||
1359 | (*ifp->if_free)(ifp); | |
1360 | } | |
1361 | ||
1362 | splx(s); | |
1363 | thread_funnel_set(network_flock, funnel_state); | |
1364 | return 0; | |
1365 | } | |
1366 | ||
1367 | ||
1368 | ||
1369 | ||
1370 | ||
1371 | int | |
1372 | dlil_if_attach(struct ifnet *ifp) | |
1373 | { | |
1374 | u_long interface_family = ifp->if_family; | |
1375 | struct if_family_str *if_family; | |
1376 | struct dlil_proto_head *tmp; | |
1377 | int stat; | |
1378 | int s; | |
1379 | boolean_t funnel_state; | |
1380 | ||
1381 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
1382 | s = splnet(); | |
1383 | if (ifnet_inited == 0) { | |
1384 | TAILQ_INIT(&ifnet); | |
1385 | ifnet_inited = 1; | |
1386 | } | |
1387 | ||
1388 | if_family = find_family_module(interface_family); | |
1389 | ||
1390 | if ((!if_family) || (if_family->flags & DLIL_SHUTDOWN)) { | |
1391 | splx(s); | |
1392 | kprintf("Attempt to attach interface without family module - %d\n", | |
1393 | interface_family); | |
1394 | thread_funnel_set(network_flock, funnel_state); | |
1395 | return ENODEV; | |
1396 | } | |
1397 | ||
1398 | ||
1399 | /* | |
1400 | * Call the family module to fill in the appropriate fields in the | |
1401 | * ifnet structure. | |
1402 | */ | |
1403 | ||
1404 | stat = (*if_family->add_if)(ifp); | |
1405 | if (stat) { | |
1406 | splx(s); | |
1407 | kprintf("dlil_if_attach -- add_if failed with %d\n", stat); | |
1408 | thread_funnel_set(network_flock, funnel_state); | |
1409 | return stat; | |
1410 | } | |
1411 | ||
1412 | /* | |
1413 | * Add the ifp to the interface list. | |
1414 | */ | |
1415 | ||
1416 | tmp = (struct dlil_proto_head *) &ifp->proto_head; | |
1417 | TAILQ_INIT(tmp); | |
1418 | ||
1419 | ifp->if_data.default_proto = 0; | |
1420 | ifp->refcnt = 1; | |
1421 | ifp->offercnt = 0; | |
1422 | TAILQ_INIT(&ifp->if_flt_head); | |
1423 | old_if_attach(ifp); | |
1424 | if_family->refcnt++; | |
1425 | ||
1426 | dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IF_ATTACHED, 0, 0); | |
1427 | ||
1428 | splx(s); | |
1429 | thread_funnel_set(network_flock, funnel_state); | |
1430 | return 0; | |
1431 | } | |
1432 | ||
1433 | ||
1434 | int | |
1435 | dlil_if_detach(struct ifnet *ifp) | |
1436 | { | |
1437 | struct if_proto *proto; | |
1438 | struct dlil_filterq_entry *if_filter; | |
1439 | struct if_family_str *if_family; | |
1440 | struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
1441 | int s; | |
1442 | struct kev_msg ev_msg; | |
1443 | boolean_t funnel_state; | |
1444 | ||
1445 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
1446 | s = splnet(); | |
1447 | if (ifp->if_flags & IFF_UP) | |
1448 | printf("WARNING - dlil_if_detach called for UP interface\n"); | |
1449 | ||
1450 | if_family = find_family_module(ifp->if_family); | |
1451 | ||
1452 | if (!if_family) { | |
1453 | kprintf("Attempt to detach interface without family module - %s\n", | |
1454 | ifp->if_name); | |
1455 | splx(s); | |
1456 | thread_funnel_set(network_flock, funnel_state); | |
1457 | return ENODEV; | |
1458 | } | |
1459 | ||
1460 | while (if_filter = TAILQ_FIRST(fhead)) | |
1461 | dlil_detach_filter(if_filter->filter_id); | |
1462 | ||
1463 | ifp->refcnt--; | |
1464 | ||
1465 | if (ifp->refcnt == 0 && (ifp->if_eflags & IFEF_DETACH_DISABLED) == 0) { | |
1466 | TAILQ_REMOVE(&ifnet, ifp, if_link); | |
1467 | ||
1468 | (*if_family->del_if)(ifp); | |
1469 | ||
1470 | if (--if_family->refcnt == 0) { | |
1471 | if (if_family->shutdown) | |
1472 | (*if_family->shutdown)(); | |
1473 | ||
1474 | TAILQ_REMOVE(&if_family_head, if_family, if_fam_next); | |
1475 | FREE(if_family, M_IFADDR); | |
1476 | } | |
1477 | ||
1478 | dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IF_DETACHED, 0, 0); | |
1479 | splx(s); | |
1480 | thread_funnel_set(network_flock, funnel_state); | |
1481 | return 0; | |
1482 | } | |
1483 | else | |
1484 | { | |
1485 | dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IF_DETACHING, 0, 0); | |
1486 | splx(s); | |
1487 | thread_funnel_set(network_flock, funnel_state); | |
1488 | return DLIL_WAIT_FOR_FREE; | |
1489 | } | |
1490 | } | |
1491 | ||
1492 | ||
1493 | int | |
1494 | dlil_reg_if_modules(u_long interface_family, | |
1495 | struct dlil_ifmod_reg_str *ifmod) | |
1496 | { | |
1497 | struct if_family_str *if_family; | |
1498 | int s; | |
1499 | boolean_t funnel_state; | |
1500 | ||
1501 | ||
1502 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
1503 | s = splnet(); | |
1504 | if (find_family_module(interface_family)) { | |
1505 | kprintf("Attempt to register dlil family module more than once - %d\n", | |
1506 | interface_family); | |
1507 | splx(s); | |
1508 | thread_funnel_set(network_flock, funnel_state); | |
1509 | return EEXIST; | |
1510 | } | |
1511 | ||
1512 | if ((!ifmod->add_if) || (!ifmod->del_if) || | |
1513 | (!ifmod->add_proto) || (!ifmod->del_proto)) { | |
1514 | kprintf("dlil_reg_if_modules passed at least one null pointer\n"); | |
1515 | splx(s); | |
1516 | thread_funnel_set(network_flock, funnel_state); | |
1517 | return EINVAL; | |
1518 | } | |
1519 | ||
1520 | if_family = (struct if_family_str *) _MALLOC(sizeof(struct if_family_str), M_IFADDR, M_WAITOK); | |
1521 | if (!if_family) { | |
1522 | kprintf("dlil_reg_if_modules failed allocation\n"); | |
1523 | splx(s); | |
1524 | thread_funnel_set(network_flock, funnel_state); | |
1525 | return ENOMEM; | |
1526 | } | |
1527 | ||
1528 | bzero(if_family, sizeof(struct if_family_str)); | |
1529 | ||
1530 | if_family->if_family = interface_family & 0xffff; | |
1531 | if_family->shutdown = ifmod->shutdown; | |
1532 | if_family->add_if = ifmod->add_if; | |
1533 | if_family->del_if = ifmod->del_if; | |
1534 | if_family->add_proto = ifmod->add_proto; | |
1535 | if_family->del_proto = ifmod->del_proto; | |
1536 | if_family->ifmod_ioctl = ifmod->ifmod_ioctl; | |
1537 | if_family->refcnt = 1; | |
1538 | if_family->flags = 0; | |
1539 | ||
1540 | TAILQ_INSERT_TAIL(&if_family_head, if_family, if_fam_next); | |
1541 | splx(s); | |
1542 | thread_funnel_set(network_flock, funnel_state); | |
1543 | return 0; | |
1544 | } | |
1545 | ||
1546 | int dlil_dereg_if_modules(u_long interface_family) | |
1547 | { | |
1548 | struct if_family_str *if_family; | |
1549 | int s; | |
1550 | boolean_t funnel_state; | |
1551 | ||
1552 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
1553 | s = splnet(); | |
1554 | if_family = find_family_module(interface_family); | |
1555 | if (if_family == 0) { | |
1556 | splx(s); | |
1557 | thread_funnel_set(network_flock, funnel_state); | |
1558 | return ENOENT; | |
1559 | } | |
1560 | ||
1561 | if (--if_family->refcnt == 0) { | |
1562 | if (if_family->shutdown) | |
1563 | (*if_family->shutdown)(); | |
1564 | ||
1565 | TAILQ_REMOVE(&if_family_head, if_family, if_fam_next); | |
1566 | FREE(if_family, M_IFADDR); | |
1567 | } | |
1568 | else | |
1569 | if_family->flags |= DLIL_SHUTDOWN; | |
1570 | ||
1571 | splx(s); | |
1572 | thread_funnel_set(network_flock, funnel_state); | |
1573 | return 0; | |
1574 | } | |
1575 | ||
1576 | ||
1577 | ||
1578 | ||
1579 | ||
1580 | /* | |
1581 | * Old if_attach no-op'ed function defined here for temporary backwards compatibility | |
1582 | */ | |
1583 | ||
1584 | void if_attach(ifp) | |
1585 | struct ifnet *ifp; | |
1586 | { | |
1587 | dlil_if_attach(ifp); | |
1588 | } | |
1589 | ||
1590 | ||
1591 | ||
1592 | int | |
1593 | dlil_inject_if_input(struct mbuf *m, char *frame_header, u_long from_id) | |
1594 | { | |
1595 | struct ifnet *orig_ifp = 0; | |
1596 | struct ifnet *ifp; | |
1597 | struct if_proto *ifproto; | |
1598 | struct if_proto *proto; | |
1599 | struct dlil_filterq_entry *tmp; | |
1600 | int retval = 0; | |
1601 | struct dlil_filterq_head *fhead; | |
1602 | int match_found; | |
1603 | ||
1604 | ||
1605 | dlil_stats.inject_if_in1++; | |
1606 | if (from_id > MAX_DLIL_FILTERS) | |
1607 | return ERANGE; | |
1608 | ||
1609 | if (dlil_filters[from_id].type != DLIL_IF_FILTER) | |
1610 | return ENOENT; | |
1611 | ||
1612 | ifp = dlil_filters[from_id].ifp; | |
1613 | ||
1614 | /* | |
1615 | * Let interface filters (if any) do their thing ... | |
1616 | */ | |
1617 | ||
1618 | fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
1619 | match_found = 0; | |
1620 | ||
1621 | if (TAILQ_EMPTY(fhead) == 0) { | |
1622 | while (orig_ifp != ifp) { | |
1623 | orig_ifp = ifp; | |
1624 | TAILQ_FOREACH_REVERSE(tmp, fhead, que, dlil_filterq_head) { | |
1625 | if ((match_found) && (IFILT(tmp).filter_if_input)) { | |
1626 | retval = (*IFILT(tmp).filter_if_input)(IFILT(tmp).cookie, | |
1627 | &ifp, | |
1628 | &m, | |
1629 | &frame_header); | |
1630 | if (retval) { | |
1631 | if (retval == EJUSTRETURN) | |
1632 | return 0; | |
1633 | else { | |
1634 | m_freem(m); | |
1635 | return retval; | |
1636 | } | |
1637 | } | |
1638 | ||
1639 | } | |
1640 | ||
1641 | if (ifp != orig_ifp) | |
1642 | break; | |
1643 | ||
1644 | if (from_id == tmp->filter_id) | |
1645 | match_found = 1; | |
1646 | } | |
1647 | } | |
1648 | } | |
1649 | ||
1650 | ifp->if_lastchange = time; | |
1651 | ||
1652 | /* | |
1653 | * Call family demux module. If the demux module finds a match | |
1654 | * for the frame it will fill-in the ifproto pointer. | |
1655 | */ | |
1656 | ||
1657 | retval = (*ifp->if_demux)(ifp, m, frame_header, &ifproto ); | |
1658 | ||
1659 | if (m->m_flags & (M_BCAST|M_MCAST)) | |
1660 | ifp->if_imcasts++; | |
1661 | ||
1662 | if ((retval) && (ifp->offercnt)) { | |
1663 | /* | |
1664 | * No match was found, look for any offers. | |
1665 | */ | |
1666 | struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head; | |
1667 | TAILQ_FOREACH(proto, tmp, next) { | |
1668 | if ((proto->dl_offer) && (proto->dl_offer(m, frame_header) == 0)) { | |
1669 | ifproto = proto; | |
1670 | retval = 0; | |
1671 | break; | |
1672 | } | |
1673 | } | |
1674 | } | |
1675 | ||
1676 | if (retval) { | |
1677 | if (retval != EJUSTRETURN) { | |
1678 | m_freem(m); | |
1679 | return retval; | |
1680 | } | |
1681 | else | |
1682 | return 0; | |
1683 | } | |
1684 | else | |
1685 | if (ifproto == 0) { | |
1686 | printf("ERROR - dlil_inject_if_input -- if_demux didn't return an if_proto pointer\n"); | |
1687 | m_freem(m); | |
1688 | return 0; | |
1689 | } | |
1690 | ||
1691 | /* | |
1692 | * Call any attached protocol filters. | |
1693 | */ | |
1694 | TAILQ_FOREACH_REVERSE(tmp, &ifproto->pr_flt_head, que, dlil_filterq_head) { | |
1695 | if (PFILT(tmp).filter_dl_input) { | |
1696 | retval = (*PFILT(tmp).filter_dl_input)(PFILT(tmp).cookie, | |
1697 | &m, | |
1698 | &frame_header, | |
1699 | &ifp); | |
1700 | ||
1701 | if (retval) { | |
1702 | if (retval == EJUSTRETURN) | |
1703 | return 0; | |
1704 | else { | |
1705 | m_freem(m); | |
1706 | return retval; | |
1707 | } | |
1708 | } | |
1709 | } | |
1710 | } | |
1711 | ||
1712 | ||
1713 | ||
1714 | retval = (*ifproto->dl_input)(m, frame_header, | |
1715 | ifp, ifproto->dl_tag, | |
1716 | FALSE); | |
1717 | ||
1718 | dlil_stats.inject_if_in2++; | |
1719 | if (retval == EJUSTRETURN) | |
1720 | retval = 0; | |
1721 | else | |
1722 | if (retval) | |
1723 | m_freem(m); | |
1724 | ||
1725 | return retval; | |
1726 | ||
1727 | } | |
1728 | ||
1729 | ||
1730 | ||
1731 | ||
1732 | ||
1733 | int | |
1734 | dlil_inject_pr_input(struct mbuf *m, char *frame_header, u_long from_id) | |
1735 | { | |
1736 | struct ifnet *orig_ifp = 0; | |
1737 | struct dlil_filterq_entry *tmp; | |
1738 | int retval; | |
1739 | struct if_proto *ifproto = 0; | |
1740 | int match_found; | |
1741 | struct ifnet *ifp; | |
1742 | ||
1743 | ||
1744 | dlil_stats.inject_pr_in1++; | |
1745 | if (from_id > MAX_DLIL_FILTERS) | |
1746 | return ERANGE; | |
1747 | ||
1748 | if (dlil_filters[from_id].type != DLIL_PR_FILTER) | |
1749 | return ENOENT; | |
1750 | ||
1751 | ifproto = dlil_filters[from_id].proto; | |
1752 | ifp = dlil_filters[from_id].ifp; | |
1753 | ||
1754 | ||
1755 | /* | |
1756 | * Call any attached protocol filters. | |
1757 | */ | |
1758 | ||
1759 | match_found = 0; | |
1760 | TAILQ_FOREACH_REVERSE(tmp, &ifproto->pr_flt_head, que, dlil_filterq_head) { | |
1761 | if ((match_found) && (PFILT(tmp).filter_dl_input)) { | |
1762 | retval = (*PFILT(tmp).filter_dl_input)(PFILT(tmp).cookie, | |
1763 | &m, | |
1764 | &frame_header, | |
1765 | &ifp); | |
1766 | ||
1767 | if (retval) { | |
1768 | if (retval == EJUSTRETURN) | |
1769 | return 0; | |
1770 | else { | |
1771 | m_freem(m); | |
1772 | return retval; | |
1773 | } | |
1774 | } | |
1775 | } | |
1776 | ||
1777 | if (tmp->filter_id == from_id) | |
1778 | match_found = 1; | |
1779 | } | |
1780 | ||
1781 | ||
1782 | retval = (*ifproto->dl_input)(m, frame_header, | |
1783 | ifp, ifproto->dl_tag, | |
1784 | FALSE); | |
1785 | ||
1786 | if (retval == EJUSTRETURN) | |
1787 | retval = 0; | |
1788 | else | |
1789 | if (retval) | |
1790 | m_freem(m); | |
1791 | ||
1792 | dlil_stats.inject_pr_in2++; | |
1793 | return retval; | |
1794 | } | |
1795 | ||
1796 | ||
1797 | ||
1798 | int | |
1799 | dlil_inject_pr_output(struct mbuf *m, | |
1800 | struct sockaddr *dest, | |
1801 | int raw, | |
1802 | char *frame_type, | |
1803 | char *dst_linkaddr, | |
1804 | u_long from_id) | |
1805 | { | |
1806 | struct ifnet *orig_ifp = 0; | |
1807 | struct ifnet *ifp; | |
1808 | struct dlil_filterq_entry *tmp; | |
1809 | int retval = 0; | |
1810 | char frame_type_buffer[MAX_FRAME_TYPE_SIZE * 4]; | |
1811 | char dst_linkaddr_buffer[MAX_LINKADDR * 4]; | |
1812 | struct dlil_filterq_head *fhead; | |
1813 | int match_found; | |
1814 | u_long dl_tag; | |
1815 | ||
1816 | ||
1817 | dlil_stats.inject_pr_out1++; | |
1818 | if (raw == 0) { | |
1819 | if (frame_type) | |
1820 | bcopy(frame_type, &frame_type_buffer[0], MAX_FRAME_TYPE_SIZE * 4); | |
1821 | else | |
1822 | return EINVAL; | |
1823 | ||
1824 | if (dst_linkaddr) | |
1825 | bcopy(dst_linkaddr, &dst_linkaddr_buffer, MAX_LINKADDR * 4); | |
1826 | else | |
1827 | return EINVAL; | |
1828 | } | |
1829 | ||
1830 | if (from_id > MAX_DLIL_FILTERS) | |
1831 | return ERANGE; | |
1832 | ||
1833 | if (dlil_filters[from_id].type != DLIL_PR_FILTER) | |
1834 | return ENOENT; | |
1835 | ||
1836 | ifp = dlil_filters[from_id].ifp; | |
1837 | dl_tag = dlil_filters[from_id].proto->dl_tag; | |
1838 | ||
1839 | ||
1840 | frame_type = frame_type_buffer; | |
1841 | dst_linkaddr = dst_linkaddr_buffer; | |
1842 | ||
1843 | fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
1844 | ||
1845 | /* | |
1846 | * Run any attached protocol filters. | |
1847 | */ | |
1848 | match_found = 0; | |
1849 | ||
1850 | if (TAILQ_EMPTY(dl_tag_array[dl_tag].pr_flt_head) == 0) { | |
1851 | TAILQ_FOREACH(tmp, dl_tag_array[dl_tag].pr_flt_head, que) { | |
1852 | if ((match_found) && (PFILT(tmp).filter_dl_output)) { | |
1853 | retval = (*PFILT(tmp).filter_dl_output)(PFILT(tmp).cookie, | |
1854 | &m, &ifp, &dest, dst_linkaddr, frame_type); | |
1855 | if (retval) { | |
1856 | if (retval == EJUSTRETURN) | |
1857 | return 0; | |
1858 | else { | |
1859 | m_freem(m); | |
1860 | return retval; | |
1861 | } | |
1862 | } | |
1863 | } | |
1864 | ||
1865 | if (tmp->filter_id == from_id) | |
1866 | match_found = 1; | |
1867 | } | |
1868 | } | |
1869 | ||
1870 | ||
1871 | /* | |
1872 | * Call framing module | |
1873 | */ | |
1874 | if ((raw == 0) && (ifp->if_framer)) { | |
1875 | retval = (*ifp->if_framer)(ifp, &m, dest, dst_linkaddr, frame_type); | |
1876 | if (retval) { | |
1877 | if (retval == EJUSTRETURN) | |
1878 | return 0; | |
1879 | else | |
1880 | { | |
1881 | m_freem(m); | |
1882 | return retval; | |
1883 | } | |
1884 | } | |
1885 | } | |
1886 | ||
1887 | ||
1888 | #if BRIDGE | |
1889 | if (do_bridge) { | |
1890 | struct mbuf *m0 = m ; | |
1891 | ||
1892 | if (m->m_pkthdr.rcvif) | |
1893 | m->m_pkthdr.rcvif = NULL ; | |
1894 | ifp = bridge_dst_lookup(m); | |
1895 | bdg_forward(&m0, ifp); | |
1896 | if (m0) | |
1897 | m_freem(m0); | |
1898 | ||
1899 | return 0; | |
1900 | } | |
1901 | #endif | |
1902 | ||
1903 | ||
1904 | /* | |
1905 | * Let interface filters (if any) do their thing ... | |
1906 | */ | |
1907 | ||
1908 | fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
1909 | if (TAILQ_EMPTY(fhead) == 0) { | |
1910 | while (orig_ifp != ifp) { | |
1911 | orig_ifp = ifp; | |
1912 | TAILQ_FOREACH(tmp, fhead, que) { | |
1913 | if (IFILT(tmp).filter_if_output) { | |
1914 | retval = (*IFILT(tmp).filter_if_output)(IFILT(tmp).cookie, | |
1915 | &ifp, | |
1916 | &m); | |
1917 | if (retval) { | |
1918 | if (retval == EJUSTRETURN) | |
1919 | return 0; | |
1920 | else { | |
1921 | m_freem(m); | |
1922 | return retval; | |
1923 | } | |
1924 | } | |
1925 | ||
1926 | } | |
1927 | ||
1928 | if (ifp != orig_ifp) | |
1929 | break; | |
1930 | } | |
1931 | } | |
1932 | } | |
1933 | ||
1934 | /* | |
1935 | * Finally, call the driver. | |
1936 | */ | |
1937 | ||
1938 | retval = (*ifp->if_output)(ifp, m); | |
1939 | dlil_stats.inject_pr_out2++; | |
1940 | if ((retval == 0) || (retval == EJUSTRETURN)) | |
1941 | return 0; | |
1942 | else | |
1943 | return retval; | |
1944 | } | |
1945 | ||
1946 | ||
1947 | int | |
1948 | dlil_inject_if_output(struct mbuf *m, u_long from_id) | |
1949 | { | |
1950 | struct ifnet *orig_ifp = 0; | |
1951 | struct ifnet *ifp; | |
1952 | struct dlil_filterq_entry *tmp; | |
1953 | int retval = 0; | |
1954 | struct dlil_filterq_head *fhead; | |
1955 | int match_found; | |
1956 | ||
1957 | ||
1958 | dlil_stats.inject_if_out1++; | |
1959 | if (from_id > MAX_DLIL_FILTERS) | |
1960 | return ERANGE; | |
1961 | ||
1962 | if (dlil_filters[from_id].type != DLIL_IF_FILTER) | |
1963 | return ENOENT; | |
1964 | ||
1965 | ifp = dlil_filters[from_id].ifp; | |
1966 | ||
1967 | /* | |
1968 | * Let interface filters (if any) do their thing ... | |
1969 | */ | |
1970 | ||
1971 | fhead = (struct dlil_filterq_head *) &ifp->if_flt_head; | |
1972 | match_found = 0; | |
1973 | ||
1974 | if (TAILQ_EMPTY(fhead) == 0) { | |
1975 | while (orig_ifp != ifp) { | |
1976 | orig_ifp = ifp; | |
1977 | TAILQ_FOREACH(tmp, fhead, que) { | |
1978 | if ((match_found) && (IFILT(tmp).filter_if_output)) { | |
1979 | retval = (*IFILT(tmp).filter_if_output)(IFILT(tmp).cookie, | |
1980 | &ifp, | |
1981 | &m); | |
1982 | if (retval) { | |
1983 | if (retval == EJUSTRETURN) | |
1984 | return 0; | |
1985 | else { | |
1986 | m_freem(m); | |
1987 | return retval; | |
1988 | } | |
1989 | } | |
1990 | ||
1991 | } | |
1992 | ||
1993 | if (ifp != orig_ifp) | |
1994 | break; | |
1995 | ||
1996 | if (from_id == tmp->filter_id) | |
1997 | match_found = 1; | |
1998 | } | |
1999 | } | |
2000 | } | |
2001 | ||
2002 | /* | |
2003 | * Finally, call the driver. | |
2004 | */ | |
2005 | ||
2006 | retval = (*ifp->if_output)(ifp, m); | |
2007 | dlil_stats.inject_if_out2++; | |
2008 | if ((retval == 0) || (retval == EJUSTRETURN)) | |
2009 | return 0; | |
2010 | else | |
2011 | return retval; | |
2012 | } |