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