]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/dlil.c
001492dfba5612fc9331b76c0b4a59c6ac0f5416
[apple/xnu.git] / bsd / net / dlil.c
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 }