]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/dlil.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / bsd / net / dlil.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
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.
1c79356b
A
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
1c79356b 45#include <kern/task.h>
9bccf70c
A
46#include <kern/thread.h>
47#include <kern/sched_prim.h>
48
1c79356b
A
49#include <net/netisr.h>
50#include <net/if_types.h>
51
d52fe63f 52#include <machine/machine_routines.h>
1c79356b
A
53
54#define DBG_LAYER_BEG DLILDBG_CODE(DBG_DLIL_STATIC, 0)
55#define DBG_LAYER_END DLILDBG_CODE(DBG_DLIL_STATIC, 2)
56#define DBG_FNC_DLIL_INPUT DLILDBG_CODE(DBG_DLIL_STATIC, (1 << 8))
57#define DBG_FNC_DLIL_OUTPUT DLILDBG_CODE(DBG_DLIL_STATIC, (2 << 8))
58#define DBG_FNC_DLIL_IFOUT DLILDBG_CODE(DBG_DLIL_STATIC, (3 << 8))
59
60
9bccf70c
A
61#define MAX_DL_TAGS 16
62#define MAX_DLIL_FILTERS 16
1c79356b
A
63#define MAX_FRAME_TYPE_SIZE 4 /* LONGWORDS */
64#define MAX_LINKADDR 4 /* LONGWORDS */
65#define M_NKE M_IFADDR
66
67#define PFILT(x) ((struct dlil_filterq_entry *) (x))->variants.pr_filter
68#define IFILT(x) ((struct dlil_filterq_entry *) (x))->variants.if_filter
69
70struct dl_tag_str {
71 struct ifnet *ifp;
72 struct if_proto *proto;
73 struct dlil_filterq_head *pr_flt_head;
74};
75
76
9bccf70c
A
77struct dlil_ifnet {
78 /* ifnet and drvr_ext are used by the stack and drivers
79 drvr_ext extends the public ifnet and must follow dl_if */
80 struct ifnet dl_if; /* public ifnet */
81 void *drvr_ext[4]; /* driver reserved (e.g arpcom extension for enet) */
82
83 /* dlil private fields */
84 TAILQ_ENTRY(dlil_ifnet) dl_if_link; /* dlil_ifnet are link together */
85 /* it is not the ifnet list */
86 void *if_uniqueid; /* unique id identifying the interface */
87 size_t if_uniqueid_len;/* length of the unique id */
88 char if_namestorage[IFNAMSIZ]; /* interface name storage for detached interfaces */
89};
90
1c79356b
A
91struct dlil_stats_str {
92 int inject_pr_in1;
93 int inject_pr_in2;
94 int inject_pr_out1;
95 int inject_pr_out2;
96 int inject_if_in1;
97 int inject_if_in2;
98 int inject_if_out1;
99 int inject_if_out2;
100};
101
102
103struct dlil_filter_id_str {
104 int type;
105 struct dlil_filterq_head *head;
106 struct dlil_filterq_entry *filter_ptr;
107 struct ifnet *ifp;
108 struct if_proto *proto;
109};
110
111
112
113struct if_family_str {
114 TAILQ_ENTRY(if_family_str) if_fam_next;
115 u_long if_family;
116 int refcnt;
117 int flags;
118
119#define DLIL_SHUTDOWN 1
120
121 int (*add_if)(struct ifnet *ifp);
122 int (*del_if)(struct ifnet *ifp);
9bccf70c 123 int (*init_if)(struct ifnet *ifp);
1c79356b
A
124 int (*add_proto)(struct ddesc_head_str *demux_desc_head,
125 struct if_proto *proto, u_long dl_tag);
126 int (*del_proto)(struct if_proto *proto, u_long dl_tag);
127 int (*ifmod_ioctl)(struct ifnet *ifp, u_long command, caddr_t data);
128 int (*shutdown)();
129};
130
131
55e303ae
A
132struct proto_family_str {
133 TAILQ_ENTRY(proto_family_str) proto_fam_next;
134 u_long proto_family;
135 u_long if_family;
136
137 int (*attach_proto)(struct ifnet *ifp, u_long *dl_tag);
138 int (*detach_proto)(struct ifnet *ifp, u_long dl_tag);
139};
140
141
1c79356b
A
142
143struct dlil_stats_str dlil_stats;
144
145static
9bccf70c
A
146struct dlil_filter_id_str *dlil_filters;
147
148static
149struct dl_tag_str *dl_tag_array;
1c79356b
A
150
151static
9bccf70c 152TAILQ_HEAD(, dlil_ifnet) dlil_ifnet_head;
1c79356b
A
153
154static
155TAILQ_HEAD(, if_family_str) if_family_head;
156
55e303ae
A
157static
158TAILQ_HEAD(, proto_family_str) proto_family_head;
159
1c79356b 160static ifnet_inited = 0;
9bccf70c
A
161static u_long dl_tag_nb = 0;
162static u_long dlil_filters_nb = 0;
1c79356b
A
163
164int dlil_initialized = 0;
165decl_simple_lock_data(, dlil_input_lock)
166int dlil_input_thread_wakeup = 0;
1c79356b
A
167static struct mbuf *dlil_input_mbuf_head = NULL;
168static struct mbuf *dlil_input_mbuf_tail = NULL;
9bccf70c
A
169#if NLOOP > 1
170#error dlil_input() needs to be revised to support more than on loopback interface
171#endif
1c79356b
A
172static struct mbuf *dlil_input_loop_head = NULL;
173static struct mbuf *dlil_input_loop_tail = NULL;
55e303ae 174extern struct ifmultihead ifma_lostlist;
1c79356b
A
175
176static void dlil_input_thread(void);
177extern void run_netisr(void);
9bccf70c 178extern void bpfdetach(struct ifnet*);
1c79356b 179
55e303ae 180int dlil_expand_mcl;
1c79356b
A
181
182/*
183 * Internal functions.
184 */
185
186static
187struct if_family_str *find_family_module(u_long if_family)
188{
189 struct if_family_str *mod = NULL;
190
191 TAILQ_FOREACH(mod, &if_family_head, if_fam_next) {
192 if (mod->if_family == (if_family & 0xffff))
193 break;
194 }
195
196 return mod;
197}
198
55e303ae
A
199static
200struct proto_family_str *find_proto_module(u_long proto_family, u_long if_family)
201{
202 struct proto_family_str *mod = NULL;
203
204 TAILQ_FOREACH(mod, &proto_family_head, proto_fam_next) {
205 if ((mod->proto_family == (proto_family & 0xffff))
206 && (mod->if_family == (if_family & 0xffff)))
207 break;
208 }
209
210 return mod;
211}
212
1c79356b
A
213
214/*
215 * Public functions.
216 */
217
218struct ifnet *ifbyfamily(u_long family, short unit)
219{
220 struct ifnet *ifp;
221
222 TAILQ_FOREACH(ifp, &ifnet, if_link)
223 if ((family == ifp->if_family) &&
224 (ifp->if_unit == unit))
225 return ifp;
226
227 return 0;
228}
229
9bccf70c 230struct if_proto *dlttoproto(u_long dl_tag)
1c79356b 231{
9bccf70c
A
232 if (dl_tag < dl_tag_nb && dl_tag_array[dl_tag].ifp)
233 return dl_tag_array[dl_tag].proto;
234 return 0;
1c79356b
A
235}
236
237
0b4e3aa0
A
238static int dlil_ifp_proto_count(struct ifnet * ifp)
239{
240 int count = 0;
241 struct if_proto * proto;
242 struct dlil_proto_head * tmp;
243
244 tmp = (struct dlil_proto_head *) &ifp->proto_head;
245
246 TAILQ_FOREACH(proto, tmp, next)
247 count++;
248
249 return count;
250}
251
1c79356b
A
252u_long ifptodlt(struct ifnet *ifp, u_long proto_family)
253{
254 struct if_proto *proto;
255 struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head;
256
257
258 TAILQ_FOREACH(proto, tmp, next)
0b4e3aa0
A
259 if (proto->protocol_family == proto_family)
260 return proto->dl_tag;
1c79356b
A
261
262 return 0;
263}
264
265
266int dlil_find_dltag(u_long if_family, short unit, u_long proto_family, u_long *dl_tag)
267{
268 struct ifnet *ifp;
269
270 ifp = ifbyfamily(if_family, unit);
271 if (!ifp)
272 return ENOENT;
273
274 *dl_tag = ifptodlt(ifp, proto_family);
275 if (*dl_tag == 0)
276 return EPROTONOSUPPORT;
277 else
278 return 0;
279}
280
281
0b4e3aa0
A
282void dlil_post_msg(struct ifnet *ifp, u_long event_subclass, u_long event_code,
283 struct net_event_data *event_data, u_long event_data_len)
284{
285 struct net_event_data ev_data;
286 struct kev_msg ev_msg;
287
288 /*
289 * a net event always start with a net_event_data structure
290 * but the caller can generate a simple net event or
291 * provide a longer event structure to post
292 */
293
294 ev_msg.vendor_code = KEV_VENDOR_APPLE;
295 ev_msg.kev_class = KEV_NETWORK_CLASS;
296 ev_msg.kev_subclass = event_subclass;
297 ev_msg.event_code = event_code;
298
299 if (event_data == 0) {
300 event_data = &ev_data;
301 event_data_len = sizeof(struct net_event_data);
302 }
303
304 strncpy(&event_data->if_name[0], ifp->if_name, IFNAMSIZ);
305 event_data->if_family = ifp->if_family;
306 event_data->if_unit = (unsigned long) ifp->if_unit;
307
308 ev_msg.dv[0].data_length = event_data_len;
309 ev_msg.dv[0].data_ptr = event_data;
310 ev_msg.dv[1].data_length = 0;
311
312 kev_post_msg(&ev_msg);
313}
314
315
1c79356b
A
316
317void
318dlil_init()
319{
320 int i;
321
9bccf70c 322 TAILQ_INIT(&dlil_ifnet_head);
1c79356b 323 TAILQ_INIT(&if_family_head);
55e303ae 324 TAILQ_INIT(&proto_family_head);
1c79356b 325
9bccf70c
A
326 // create the dl tag array
327 MALLOC(dl_tag_array, void *, sizeof(struct dl_tag_str) * MAX_DL_TAGS, M_NKE, M_WAITOK);
328 if (dl_tag_array == 0) {
329 printf("dlil_init tags array allocation failed\n");
330 return; //very bad
331 }
332 bzero(dl_tag_array, sizeof(struct dl_tag_str) * MAX_DL_TAGS);
333 dl_tag_nb = MAX_DL_TAGS;
334
335 // create the dl filters array
336 MALLOC(dlil_filters, void *, sizeof(struct dlil_filter_id_str) * MAX_DLIL_FILTERS, M_NKE, M_WAITOK);
337 if (dlil_filters == 0) {
338 printf("dlil_init filters array allocation failed\n");
339 return; //very bad
340 }
341 bzero(dlil_filters, sizeof(struct dlil_filter_id_str) * MAX_DLIL_FILTERS);
342 dlil_filters_nb = MAX_DLIL_FILTERS;
1c79356b
A
343
344 bzero(&dlil_stats, sizeof(dlil_stats));
345
346 simple_lock_init(&dlil_input_lock);
347
348 /*
349 * Start up the dlil input thread once everything is initialized
350 */
351 (void) kernel_thread(kernel_task, dlil_input_thread);
352}
353
1c79356b
A
354u_long get_new_filter_id()
355{
356 u_long i;
9bccf70c
A
357 u_char *p;
358
359 for (i=1; i < dlil_filters_nb; i++)
1c79356b 360 if (dlil_filters[i].type == 0)
9bccf70c
A
361 break;
362
363 if (i == dlil_filters_nb) {
364 // expand the filters array by MAX_DLIL_FILTERS
365 MALLOC(p, u_char *, sizeof(struct dlil_filter_id_str) * (dlil_filters_nb + MAX_DLIL_FILTERS), M_NKE, M_WAITOK);
366 if (p == 0)
367 return 0;
368
369 bcopy(dlil_filters, p, sizeof(struct dlil_filter_id_str) * dlil_filters_nb);
370 bzero(p + sizeof(struct dlil_filter_id_str) * dlil_filters_nb, sizeof(struct dlil_filter_id_str) * MAX_DL_TAGS);
371 dlil_filters_nb += MAX_DLIL_FILTERS;
372 FREE(dlil_filters, M_NKE);
373 dlil_filters = (struct dlil_filter_id_str *)p;
374 }
375
376 return i;
1c79356b
A
377}
378
379
380int dlil_attach_interface_filter(struct ifnet *ifp,
381 struct dlil_if_flt_str *if_filter,
382 u_long *filter_id,
383 int insertion_point)
384{
385 int s;
9bccf70c 386 int retval = 0;
1c79356b
A
387 struct dlil_filterq_entry *tmp_ptr;
388 struct dlil_filterq_entry *if_filt;
389 struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
390 boolean_t funnel_state;
391
1c79356b 392 MALLOC(tmp_ptr, struct dlil_filterq_entry *, sizeof(*tmp_ptr), M_NKE, M_WAITOK);
0b4e3aa0 393 if (tmp_ptr == NULL)
9bccf70c 394 return (ENOBUFS);
0b4e3aa0 395
1c79356b
A
396 bcopy((caddr_t) if_filter, (caddr_t) &tmp_ptr->variants.if_filter,
397 sizeof(struct dlil_if_flt_str));
398
399 funnel_state = thread_funnel_set(network_flock, TRUE);
1c79356b
A
400 s = splnet();
401
9bccf70c
A
402 *filter_id = get_new_filter_id();
403 if (*filter_id == 0) {
404 FREE(tmp_ptr, M_NKE);
405 retval = ENOMEM;
406 goto end;
407 }
408
409 dlil_filters[*filter_id].filter_ptr = tmp_ptr;
410 dlil_filters[*filter_id].head = (struct dlil_filterq_head *) &ifp->if_flt_head;
411 dlil_filters[*filter_id].type = DLIL_IF_FILTER;
412 dlil_filters[*filter_id].ifp = ifp;
413 tmp_ptr->filter_id = *filter_id;
414 tmp_ptr->type = DLIL_IF_FILTER;
415
1c79356b
A
416 if (insertion_point != DLIL_LAST_FILTER) {
417 TAILQ_FOREACH(if_filt, fhead, que)
418 if (insertion_point == if_filt->filter_id) {
419 TAILQ_INSERT_BEFORE(if_filt, tmp_ptr, que);
420 break;
421 }
422 }
423 else
424 TAILQ_INSERT_TAIL(fhead, tmp_ptr, que);
425
9bccf70c 426end:
1c79356b
A
427 splx(s);
428 thread_funnel_set(network_flock, funnel_state);
429 return retval;
430}
431
432
433int dlil_attach_protocol_filter(u_long dl_tag,
434 struct dlil_pr_flt_str *pr_filter,
435 u_long *filter_id,
436 int insertion_point)
437{
9bccf70c 438 struct dlil_filterq_entry *tmp_ptr, *pr_filt;
1c79356b 439 int s;
9bccf70c 440 int retval = 0;
1c79356b 441 boolean_t funnel_state;
9bccf70c
A
442
443 if (dl_tag >= dl_tag_nb || dl_tag_array[dl_tag].ifp == 0)
444 return (ENOENT);
1c79356b
A
445
446 MALLOC(tmp_ptr, struct dlil_filterq_entry *, sizeof(*tmp_ptr), M_NKE, M_WAITOK);
0b4e3aa0 447 if (tmp_ptr == NULL)
9bccf70c 448 return (ENOBUFS);
0b4e3aa0 449
1c79356b
A
450 bcopy((caddr_t) pr_filter, (caddr_t) &tmp_ptr->variants.pr_filter,
451 sizeof(struct dlil_pr_flt_str));
452
453 funnel_state = thread_funnel_set(network_flock, TRUE);
1c79356b 454 s = splnet();
9bccf70c
A
455
456 *filter_id = get_new_filter_id();
457 if (*filter_id == 0) {
458 FREE(tmp_ptr, M_NKE);
459 retval = ENOMEM;
460 goto end;
461 }
462
463 dlil_filters[*filter_id].filter_ptr = tmp_ptr;
464 dlil_filters[*filter_id].head = dl_tag_array[dl_tag].pr_flt_head;
465 dlil_filters[*filter_id].type = DLIL_PR_FILTER;
466 dlil_filters[*filter_id].proto = dl_tag_array[dl_tag].proto;
467 dlil_filters[*filter_id].ifp = dl_tag_array[dl_tag].ifp;
468 tmp_ptr->filter_id = *filter_id;
469 tmp_ptr->type = DLIL_PR_FILTER;
470
1c79356b
A
471 if (insertion_point != DLIL_LAST_FILTER) {
472 TAILQ_FOREACH(pr_filt, dl_tag_array[dl_tag].pr_flt_head, que)
473 if (insertion_point == pr_filt->filter_id) {
474 TAILQ_INSERT_BEFORE(pr_filt, tmp_ptr, que);
475 break;
476 }
477 }
478 else
479 TAILQ_INSERT_TAIL(dl_tag_array[dl_tag].pr_flt_head, tmp_ptr, que);
480
9bccf70c 481end:
1c79356b
A
482 splx(s);
483 thread_funnel_set(network_flock, funnel_state);
484 return retval;
485}
486
487
488int
489dlil_detach_filter(u_long filter_id)
490{
491 struct dlil_filter_id_str *flt;
9bccf70c 492 int s, retval = 0;
1c79356b
A
493 boolean_t funnel_state;
494
1c79356b
A
495 funnel_state = thread_funnel_set(network_flock, TRUE);
496 s = splnet();
9bccf70c
A
497
498 if (filter_id >= dlil_filters_nb || dlil_filters[filter_id].type == 0) {
499 retval = ENOENT;
500 goto end;
1c79356b
A
501 }
502
9bccf70c 503 flt = &dlil_filters[filter_id];
1c79356b
A
504
505 if (flt->type == DLIL_IF_FILTER) {
506 if (IFILT(flt->filter_ptr).filter_detach)
507 (*IFILT(flt->filter_ptr).filter_detach)(IFILT(flt->filter_ptr).cookie);
508 }
509 else {
510 if (flt->type == DLIL_PR_FILTER) {
511 if (PFILT(flt->filter_ptr).filter_detach)
512 (*PFILT(flt->filter_ptr).filter_detach)(PFILT(flt->filter_ptr).cookie);
513 }
514 }
515
516 TAILQ_REMOVE(flt->head, flt->filter_ptr, que);
517 FREE(flt->filter_ptr, M_NKE);
518 flt->type = 0;
9bccf70c
A
519
520end:
1c79356b
A
521 splx(s);
522 thread_funnel_set(network_flock, funnel_state);
9bccf70c 523 return retval;
1c79356b
A
524}
525
1c79356b
A
526void
527dlil_input_thread_continue(void)
528{
529 while (1) {
530 struct mbuf *m, *m_loop;
1c79356b 531
0b4e3aa0 532 usimple_lock(&dlil_input_lock);
1c79356b
A
533 m = dlil_input_mbuf_head;
534 dlil_input_mbuf_head = NULL;
535 dlil_input_mbuf_tail = NULL;
536 m_loop = dlil_input_loop_head;
537 dlil_input_loop_head = NULL;
538 dlil_input_loop_tail = NULL;
0b4e3aa0 539 usimple_unlock(&dlil_input_lock);
1c79356b 540
1c79356b
A
541 /*
542 * NOTE warning %%% attention !!!!
543 * We should think about putting some thread starvation safeguards if
544 * we deal with long chains of packets.
545 */
546 while (m) {
547 struct mbuf *m0 = m->m_nextpkt;
548 void *header = m->m_pkthdr.header;
549
550 m->m_nextpkt = NULL;
551 m->m_pkthdr.header = NULL;
552 (void) dlil_input_packet(m->m_pkthdr.rcvif, m, header);
553 m = m0;
554 }
555 m = m_loop;
556 while (m) {
557 struct mbuf *m0 = m->m_nextpkt;
558 void *header = m->m_pkthdr.header;
9bccf70c 559 struct ifnet *ifp = &loif[0];
1c79356b
A
560
561 m->m_nextpkt = NULL;
562 m->m_pkthdr.header = NULL;
1c79356b
A
563 (void) dlil_input_packet(ifp, m, header);
564 m = m0;
565 }
566
567 if (netisr != 0)
568 run_netisr();
569
570 if (dlil_input_mbuf_head == NULL &&
571 dlil_input_loop_head == NULL &&
572 netisr == 0) {
573 assert_wait(&dlil_input_thread_wakeup, THREAD_UNINT);
9bccf70c 574 (void) thread_block(dlil_input_thread_continue);
1c79356b
A
575 /* NOTREACHED */
576 }
577 }
578}
579
580void dlil_input_thread(void)
581{
55e303ae 582 register thread_t self = current_act();
1c79356b 583
55e303ae
A
584 ml_thread_policy(self, MACHINE_GROUP,
585 (MACHINE_NETWORK_GROUP|MACHINE_NETWORK_NETISR));
1c79356b
A
586
587 /* The dlil thread is always funneled */
588 thread_funnel_set(network_flock, TRUE);
589 dlil_initialized = 1;
590 dlil_input_thread_continue();
591}
592
593int
594dlil_input(struct ifnet *ifp, struct mbuf *m_head, struct mbuf *m_tail)
595{
596 /* WARNING
597 * Because of loopbacked multicast we cannot stuff the ifp in
598 * the rcvif of the packet header: loopback has its own dlil
599 * input queue
600 */
601
0b4e3aa0 602 usimple_lock(&dlil_input_lock);
1c79356b
A
603 if (ifp->if_type != IFT_LOOP) {
604 if (dlil_input_mbuf_head == NULL)
605 dlil_input_mbuf_head = m_head;
606 else if (dlil_input_mbuf_tail != NULL)
607 dlil_input_mbuf_tail->m_nextpkt = m_head;
608 dlil_input_mbuf_tail = m_tail ? m_tail : m_head;
609 } else {
610 if (dlil_input_loop_head == NULL)
611 dlil_input_loop_head = m_head;
612 else if (dlil_input_loop_tail != NULL)
613 dlil_input_loop_tail->m_nextpkt = m_head;
614 dlil_input_loop_tail = m_tail ? m_tail : m_head;
615 }
0b4e3aa0 616 usimple_unlock(&dlil_input_lock);
1c79356b
A
617
618 wakeup((caddr_t)&dlil_input_thread_wakeup);
619
620 return 0;
621}
622
623int
624dlil_input_packet(struct ifnet *ifp, struct mbuf *m,
625 char *frame_header)
626{
627 struct ifnet *orig_ifp = 0;
628 struct dlil_filterq_entry *tmp;
629 int retval;
630 struct if_proto *ifproto = 0;
631 struct if_proto *proto;
632 struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
633
634
635 KERNEL_DEBUG(DBG_FNC_DLIL_INPUT | DBG_FUNC_START,0,0,0,0,0);
636
637 /*
638 * Run interface filters
639 */
640
641 while (orig_ifp != ifp) {
642 orig_ifp = ifp;
643
644 TAILQ_FOREACH_REVERSE(tmp, fhead, que, dlil_filterq_head) {
645 if (IFILT(tmp).filter_if_input) {
646 retval = (*IFILT(tmp).filter_if_input)(IFILT(tmp).cookie,
647 &ifp,
648 &m,
649 &frame_header);
650 if (retval) {
651 if (retval == EJUSTRETURN)
652 return 0;
653 else {
654 m_freem(m);
655 return retval;
656 }
657 }
658 }
659
660 if (ifp != orig_ifp)
661 break;
662 }
663 }
664
665 ifp->if_lastchange = time;
666
667 /*
668 * Call family demux module. If the demux module finds a match
669 * for the frame it will fill-in the ifproto pointer.
670 */
671
672 retval = (*ifp->if_demux)(ifp, m, frame_header, &ifproto );
673
674 if (m->m_flags & (M_BCAST|M_MCAST))
675 ifp->if_imcasts++;
676
677 if ((retval) && (retval != EJUSTRETURN) && (ifp->offercnt)) {
678 /*
679 * No match was found, look for any offers.
680 */
681 struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head;
682 TAILQ_FOREACH(proto, tmp, next) {
683 if ((proto->dl_offer) && (proto->dl_offer(m, frame_header) == 0)) {
684 ifproto = proto;
685 retval = 0;
686 break;
687 }
688 }
689 }
690
691 if (retval) {
692 if (retval != EJUSTRETURN) {
693 m_freem(m);
694 return retval;
695 }
696 else
697 return 0;
698 }
699 else
700 if (ifproto == 0) {
701 printf("ERROR - dlil_input - if_demux didn't return an if_proto pointer\n");
702 m_freem(m);
703 return 0;
704 }
705
706/*
707 * Call any attached protocol filters.
708 */
709
710 TAILQ_FOREACH_REVERSE(tmp, &ifproto->pr_flt_head, que, dlil_filterq_head) {
711 if (PFILT(tmp).filter_dl_input) {
712 retval = (*PFILT(tmp).filter_dl_input)(PFILT(tmp).cookie,
713 &m,
714 &frame_header,
715 &ifp);
716
717 if (retval) {
718 if (retval == EJUSTRETURN)
719 return 0;
720 else {
721 m_freem(m);
722 return retval;
723 }
724 }
725 }
726 }
727
728
729
730 retval = (*ifproto->dl_input)(m, frame_header,
731 ifp, ifproto->dl_tag,
732 TRUE);
733
734 if (retval == EJUSTRETURN)
735 retval = 0;
736 else
737 if (retval)
738 m_freem(m);
739
740 KERNEL_DEBUG(DBG_FNC_DLIL_INPUT | DBG_FUNC_END,0,0,0,0,0);
741 return retval;
742}
743
744
745
746void ether_input(ifp, eh, m)
747 struct ifnet *ifp;
748 struct ether_header *eh;
749 struct mbuf *m;
750
751{
752 kprintf("Someone is calling ether_input!!\n");
753
754 dlil_input(ifp, m, NULL);
755}
756
757
758int
759dlil_event(struct ifnet *ifp, struct kern_event_msg *event)
760{
761 struct dlil_filterq_entry *filt;
762 int retval = 0;
763 struct ifnet *orig_ifp = 0;
764 struct if_proto *proto;
765 struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
766 struct kev_msg kev_msg;
767 struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head;
768 boolean_t funnel_state;
769
770
771 funnel_state = thread_funnel_set(network_flock, TRUE);
772
773 while (orig_ifp != ifp) {
774 orig_ifp = ifp;
775
776 TAILQ_FOREACH_REVERSE(filt, fhead, que, dlil_filterq_head) {
777 if (IFILT(filt).filter_if_event) {
778 retval = (*IFILT(filt).filter_if_event)(IFILT(filt).cookie,
779 &ifp,
780 &event);
781
782 if (retval) {
783 (void) thread_funnel_set(network_flock, funnel_state);
784 if (retval == EJUSTRETURN)
785 return 0;
786 else
787 return retval;
788 }
789 }
790
791 if (ifp != orig_ifp)
792 break;
793 }
794 }
795
796
797 /*
798 * Call Interface Module event hook, if any.
799 */
800
801 if (ifp->if_event) {
802 retval = ifp->if_event(ifp, (caddr_t) event);
803
804 if (retval) {
805 (void) thread_funnel_set(network_flock, funnel_state);
806
807 if (retval == EJUSTRETURN)
808 return 0;
809 else
810 return retval;
811 }
812 }
813
814 /*
815 * Call dl_event entry point for all protocols attached to this interface
816 */
817
818 TAILQ_FOREACH(proto, tmp, next) {
819 /*
820 * Call any attached protocol filters.
821 */
822
823 TAILQ_FOREACH_REVERSE(filt, &proto->pr_flt_head, que, dlil_filterq_head) {
824 if (PFILT(filt).filter_dl_event) {
825 retval = (*PFILT(filt).filter_dl_event)(PFILT(filt).cookie,
826 event);
827
828 if (retval) {
829 (void) thread_funnel_set(network_flock, funnel_state);
830 if (retval == EJUSTRETURN)
831 return 0;
832 else
833 return retval;
834 }
835 }
836 }
837
838
839 /*
840 * Finally, call the dl_event entry point (if any)
841 */
842
843 if (proto->dl_event)
844 retval = (*proto->dl_event)(event, proto->dl_tag);
845
846 if (retval == EJUSTRETURN) {
847 (void) thread_funnel_set(network_flock, funnel_state);
848 return 0;
849 }
850 }
851
852
853 /*
854 * Now, post this event to the Kernel Event message queue
855 */
856
857 kev_msg.vendor_code = event->vendor_code;
858 kev_msg.kev_class = event->kev_class;
859 kev_msg.kev_subclass = event->kev_subclass;
860 kev_msg.event_code = event->event_code;
861 kev_msg.dv[0].data_ptr = &event->event_data[0];
862 kev_msg.dv[0].data_length = event->total_size - KEV_MSG_HEADER_SIZE;
863 kev_msg.dv[1].data_length = 0;
864
865 kev_post_msg(&kev_msg);
866
867 (void) thread_funnel_set(network_flock, funnel_state);
868 return 0;
869}
870
871
872
873int
874dlil_output(u_long dl_tag,
875 struct mbuf *m,
876 caddr_t route,
877 struct sockaddr *dest,
878 int raw
879 )
880{
881 char *frame_type;
882 char *dst_linkaddr;
883 struct ifnet *orig_ifp = 0;
884 struct ifnet *ifp;
885 struct if_proto *proto;
886 struct dlil_filterq_entry *tmp;
887 int retval = 0;
888 char frame_type_buffer[MAX_FRAME_TYPE_SIZE * 4];
889 char dst_linkaddr_buffer[MAX_LINKADDR * 4];
890 struct dlil_filterq_head *fhead;
891
1c79356b
A
892 KERNEL_DEBUG(DBG_FNC_DLIL_OUTPUT | DBG_FUNC_START,0,0,0,0,0);
893
9bccf70c
A
894 if (dl_tag >= dl_tag_nb || dl_tag_array[dl_tag].ifp == 0) {
895 m_freem(m);
896 return ENOENT;
1c79356b
A
897 }
898
9bccf70c
A
899 ifp = dl_tag_array[dl_tag].ifp;
900 proto = dl_tag_array[dl_tag].proto;
901
1c79356b
A
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 ;
9bccf70c 961 struct ether_header *eh = mtod(m, struct ether_header *);
1c79356b
A
962
963 if (m->m_pkthdr.rcvif)
964 m->m_pkthdr.rcvif = NULL ;
9bccf70c 965 ifp = bridge_dst_lookup(eh);
1c79356b
A
966 bdg_forward(&m0, ifp);
967 if (m0)
968 m_freem(m0);
969
970 return 0;
971 }
972#endif
973
974
975/*
976 * Let interface filters (if any) do their thing ...
977 */
978
979 fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
980 if (TAILQ_EMPTY(fhead) == 0) {
981 while (orig_ifp != ifp) {
982 orig_ifp = ifp;
983 TAILQ_FOREACH(tmp, fhead, que) {
984 if (IFILT(tmp).filter_if_output) {
985 retval = (*IFILT(tmp).filter_if_output)(IFILT(tmp).cookie,
986 &ifp,
987 &m);
988 if (retval) {
989 if (retval == EJUSTRETURN)
990 return 0;
991 else {
992 m_freem(m);
993 return retval;
994 }
995 }
996
997 }
998
999 if (ifp != orig_ifp)
1000 break;
1001 }
1002 }
1003 }
1004
1005/*
1006 * Finally, call the driver.
1007 */
1008
1009 KERNEL_DEBUG(DBG_FNC_DLIL_IFOUT | DBG_FUNC_START, 0,0,0,0,0);
1010 retval = (*ifp->if_output)(ifp, m);
1011 KERNEL_DEBUG(DBG_FNC_DLIL_IFOUT | DBG_FUNC_END, 0,0,0,0,0);
1012
1013 KERNEL_DEBUG(DBG_FNC_DLIL_OUTPUT | DBG_FUNC_END,0,0,0,0,0);
1014
1015 if ((retval == 0) || (retval == EJUSTRETURN))
1016 return 0;
1017 else
1018 return retval;
1019}
1020
1021
1022int
1023dlil_ioctl(u_long proto_fam,
1024 struct ifnet *ifp,
1025 u_long ioctl_code,
1026 caddr_t ioctl_arg)
1027{
1028 struct dlil_filterq_entry *tmp;
1029 struct dlil_filterq_head *fhead;
1030 int retval = EOPNOTSUPP;
1031 int retval2 = EOPNOTSUPP;
9bccf70c 1032 u_long dl_tag;
1c79356b
A
1033 struct if_family_str *if_family;
1034
1035
1036 if (proto_fam) {
4a249263
A
1037 if (dlil_find_dltag(ifp->if_family, ifp->if_unit,
1038 proto_fam, &dl_tag) == 0) {
1c79356b
A
1039 if (dl_tag_array[dl_tag].ifp != ifp)
1040 return ENOENT;
1041
1042/*
1043 * Run any attached protocol filters.
1044 */
1045 TAILQ_FOREACH(tmp, dl_tag_array[dl_tag].pr_flt_head, que) {
1046 if (PFILT(tmp).filter_dl_ioctl) {
1047 retval =
1048 (*PFILT(tmp).filter_dl_ioctl)(PFILT(tmp).cookie,
1049 dl_tag_array[dl_tag].ifp,
1050 ioctl_code,
1051 ioctl_arg);
1052
1053 if (retval) {
1054 if (retval == EJUSTRETURN)
1055 return 0;
1056 else
1057 return retval;
1058 }
1059 }
1060 }
1061
1062 if (dl_tag_array[dl_tag].proto->dl_ioctl)
1063 retval =
1064 (*dl_tag_array[dl_tag].proto->dl_ioctl)(dl_tag,
1065 dl_tag_array[dl_tag].ifp,
1066 ioctl_code,
1067 ioctl_arg);
1068 else
1069 retval = EOPNOTSUPP;
1070 }
1c79356b
A
1071 }
1072
1073 if ((retval) && (retval != EOPNOTSUPP)) {
1074 if (retval == EJUSTRETURN)
1075 return 0;
1076 else
1077 return retval;
1078 }
1079
1080
1081 fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
1082 TAILQ_FOREACH(tmp, fhead, que) {
1083 if (IFILT(tmp).filter_if_ioctl) {
1084 retval2 = (*IFILT(tmp).filter_if_ioctl)(IFILT(tmp).cookie, ifp,
1085 ioctl_code, ioctl_arg);
1086 if (retval2) {
1087 if (retval2 == EJUSTRETURN)
1088 return 0;
1089 else
1090 return retval2;
1091 }
1092 }
1093 }
1094
1095
1096 if_family = find_family_module(ifp->if_family);
1097 if ((if_family) && (if_family->ifmod_ioctl)) {
1098 retval2 = (*if_family->ifmod_ioctl)(ifp, ioctl_code, ioctl_arg);
1099
1100 if ((retval2) && (retval2 != EOPNOTSUPP)) {
1101 if (retval2 == EJUSTRETURN)
1102 return 0;
1103 else
1104 return retval;
1105 }
1106
1107 if (retval == EOPNOTSUPP)
1108 retval = retval2;
1109 }
1110
1111 if (ifp->if_ioctl)
1112 retval2 = (*ifp->if_ioctl)(ifp, ioctl_code, ioctl_arg);
1113
1114 if (retval == EOPNOTSUPP)
1115 return retval2;
1116 else {
1117 if (retval2 == EOPNOTSUPP)
1118 return 0;
1119 else
1120 return retval2;
1121 }
1122}
1123
1124
1125int
1126dlil_attach_protocol(struct dlil_proto_reg_str *proto,
1127 u_long *dl_tag)
1128{
1129 struct ifnet *ifp;
1130 struct if_proto *ifproto;
1131 u_long i;
1132 struct if_family_str *if_family;
1c79356b 1133 struct dlil_proto_head *tmp;
0b4e3aa0 1134 struct kev_dl_proto_data ev_pr_data;
9bccf70c 1135 int s, retval = 0;
1c79356b 1136 boolean_t funnel_state;
9bccf70c 1137 u_char *p;
1c79356b
A
1138
1139 if ((proto->protocol_family == 0) || (proto->interface_family == 0))
1140 return EINVAL;
1141
1142 funnel_state = thread_funnel_set(network_flock, TRUE);
1143 s = splnet();
1144 if_family = find_family_module(proto->interface_family);
1145 if ((!if_family) || (if_family->flags & DLIL_SHUTDOWN)) {
1146 kprintf("dlil_attach_protocol -- no interface family module %d",
1147 proto->interface_family);
9bccf70c
A
1148 retval = ENOENT;
1149 goto end;
1c79356b
A
1150 }
1151
1152 ifp = ifbyfamily(proto->interface_family, proto->unit_number);
1153 if (!ifp) {
1154 kprintf("dlil_attach_protocol -- no such interface %d unit %d\n",
1155 proto->interface_family, proto->unit_number);
9bccf70c
A
1156 retval = ENOENT;
1157 goto end;
1c79356b
A
1158 }
1159
1160 if (dlil_find_dltag(proto->interface_family, proto->unit_number,
1161 proto->protocol_family, &i) == 0) {
9bccf70c
A
1162 retval = EEXIST;
1163 goto end;
1c79356b
A
1164 }
1165
9bccf70c 1166 for (i=1; i < dl_tag_nb; i++)
1c79356b
A
1167 if (dl_tag_array[i].ifp == 0)
1168 break;
1169
9bccf70c
A
1170 if (i == dl_tag_nb) {
1171 // expand the tag array by MAX_DL_TAGS
1172 MALLOC(p, u_char *, sizeof(struct dl_tag_str) * (dl_tag_nb + MAX_DL_TAGS), M_NKE, M_WAITOK);
1173 if (p == 0) {
1174 retval = ENOBUFS;
1175 goto end;
1176 }
1177 bcopy(dl_tag_array, p, sizeof(struct dl_tag_str) * dl_tag_nb);
1178 bzero(p + sizeof(struct dl_tag_str) * dl_tag_nb, sizeof(struct dl_tag_str) * MAX_DL_TAGS);
1179 dl_tag_nb += MAX_DL_TAGS;
1180 FREE(dl_tag_array, M_NKE);
1181 dl_tag_array = (struct dl_tag_str *)p;
1c79356b 1182 }
9bccf70c 1183
1c79356b
A
1184 /*
1185 * Allocate and init a new if_proto structure
1186 */
1187
1188 ifproto = _MALLOC(sizeof(struct if_proto), M_IFADDR, M_WAITOK);
1189 if (!ifproto) {
1190 printf("ERROR - DLIL failed if_proto allocation\n");
9bccf70c
A
1191 retval = ENOMEM;
1192 goto end;
1c79356b
A
1193 }
1194
1195 bzero(ifproto, sizeof(struct if_proto));
1196
1197 dl_tag_array[i].ifp = ifp;
1198 dl_tag_array[i].proto = ifproto;
1199 dl_tag_array[i].pr_flt_head = &ifproto->pr_flt_head;
1200 ifproto->dl_tag = i;
1201 *dl_tag = i;
1202
1203 if (proto->default_proto) {
1204 if (ifp->if_data.default_proto == 0)
1205 ifp->if_data.default_proto = i;
1206 else
1207 printf("ERROR - dlil_attach_protocol -- Attempt to attach more than one default protocol\n");
1208 }
1209
1210 ifproto->protocol_family = proto->protocol_family;
1211 ifproto->dl_input = proto->input;
1212 ifproto->dl_pre_output = proto->pre_output;
1213 ifproto->dl_event = proto->event;
1214 ifproto->dl_offer = proto->offer;
1215 ifproto->dl_ioctl = proto->ioctl;
1216 ifproto->ifp = ifp;
1217 TAILQ_INIT(&ifproto->pr_flt_head);
1218
1219 /*
1220 * Call family module add_proto routine so it can refine the
1221 * demux descriptors as it wishes.
1222 */
9bccf70c
A
1223 retval = (*if_family->add_proto)(&proto->demux_desc_head, ifproto, *dl_tag);
1224 if (retval) {
1225 dl_tag_array[i].ifp = 0;
1c79356b 1226 FREE(ifproto, M_IFADDR);
9bccf70c 1227 goto end;
1c79356b 1228 }
1c79356b
A
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
0b4e3aa0
A
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
9bccf70c 1247end:
1c79356b
A
1248 splx(s);
1249 thread_funnel_set(network_flock, funnel_state);
9bccf70c 1250 return retval;
1c79356b
A
1251}
1252
1253
1254
1255int
1256dlil_detach_protocol(u_long dl_tag)
1257{
1258 struct ifnet *ifp;
1259 struct ifnet *orig_ifp=0;
1260 struct if_proto *proto;
1261 struct dlil_proto_head *tmp;
1262 struct if_family_str *if_family;
1263 struct dlil_filterq_entry *filter;
9bccf70c 1264 int s, retval = 0;
1c79356b 1265 struct dlil_filterq_head *fhead;
0b4e3aa0 1266 struct kev_dl_proto_data ev_pr_data;
1c79356b
A
1267 boolean_t funnel_state;
1268
1c79356b 1269 funnel_state = thread_funnel_set(network_flock, TRUE);
1c79356b 1270 s = splnet();
9bccf70c
A
1271
1272 if (dl_tag >= dl_tag_nb || dl_tag_array[dl_tag].ifp == 0) {
1273 retval = ENOENT;
1274 goto end;
1c79356b
A
1275 }
1276
1277 ifp = dl_tag_array[dl_tag].ifp;
1278 proto = dl_tag_array[dl_tag].proto;
1279
1280 if_family = find_family_module(ifp->if_family);
1281 if (if_family == NULL) {
9bccf70c
A
1282 retval = ENOENT;
1283 goto end;
1c79356b
A
1284 }
1285
1286 tmp = (struct dlil_proto_head *) &ifp->proto_head;
1287
1288 /*
1289 * Call family module del_proto
1290 */
1291
1292 (*if_family->del_proto)(proto, dl_tag);
1293
1294
1295 /*
1296 * Remove and deallocate any attached protocol filters
1297 */
1298
1299 while (filter = TAILQ_FIRST(&proto->pr_flt_head))
1300 dlil_detach_filter(filter->filter_id);
1301
1302 if (proto->dl_offer)
1303 ifp->offercnt--;
1304
0b4e3aa0
A
1305 if (ifp->if_data.default_proto == dl_tag)
1306 ifp->if_data.default_proto = 0;
1c79356b 1307 dl_tag_array[dl_tag].ifp = 0;
0b4e3aa0
A
1308
1309 /* the reserved field carries the number of protocol still attached (subject to change) */
1310 ev_pr_data.proto_family = proto->protocol_family;
9bccf70c
A
1311
1312 /*
1313 * Cleanup routes that may still be in the routing table for that interface/protocol pair.
1314 */
1315
1316 if_rtproto_del(ifp, proto->protocol_family);
1317
1c79356b
A
1318 TAILQ_REMOVE(tmp, proto, next);
1319 FREE(proto, M_IFADDR);
1320
0b4e3aa0
A
1321 ifp->refcnt--;
1322 ev_pr_data.proto_remaining_count = dlil_ifp_proto_count(ifp);
1323 dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_PROTO_DETACHED,
1324 (struct net_event_data *)&ev_pr_data,
1325 sizeof(struct kev_dl_proto_data));
1326
9bccf70c 1327 if (ifp->refcnt == 0) {
1c79356b
A
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
0b4e3aa0 1359 dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IF_DETACHED, 0, 0);
1c79356b 1360
0b4e3aa0 1361 (*ifp->if_free)(ifp);
1c79356b
A
1362 }
1363
9bccf70c 1364end:
1c79356b
A
1365 splx(s);
1366 thread_funnel_set(network_flock, funnel_state);
9bccf70c 1367 return retval;
1c79356b
A
1368}
1369
1370
1371
1372
1373
1374int
1375dlil_if_attach(struct ifnet *ifp)
1376{
1377 u_long interface_family = ifp->if_family;
1378 struct if_family_str *if_family;
1379 struct dlil_proto_head *tmp;
1380 int stat;
1381 int s;
1c79356b
A
1382 boolean_t funnel_state;
1383
1384 funnel_state = thread_funnel_set(network_flock, TRUE);
1385 s = splnet();
1386 if (ifnet_inited == 0) {
1387 TAILQ_INIT(&ifnet);
1388 ifnet_inited = 1;
1389 }
1390
1391 if_family = find_family_module(interface_family);
1392
1393 if ((!if_family) || (if_family->flags & DLIL_SHUTDOWN)) {
1394 splx(s);
1395 kprintf("Attempt to attach interface without family module - %d\n",
1396 interface_family);
1397 thread_funnel_set(network_flock, funnel_state);
1398 return ENODEV;
1399 }
1400
9bccf70c
A
1401 if (ifp->refcnt == 0) {
1402 /*
1403 * Call the family module to fill in the appropriate fields in the
1404 * ifnet structure.
1405 */
1406
1407 stat = (*if_family->add_if)(ifp);
1408 if (stat) {
1409 splx(s);
1410 kprintf("dlil_if_attach -- add_if failed with %d\n", stat);
1411 thread_funnel_set(network_flock, funnel_state);
1412 return stat;
1413 }
1414 if_family->refcnt++;
1c79356b 1415
9bccf70c
A
1416 /*
1417 * Add the ifp to the interface list.
1418 */
1419
1420 tmp = (struct dlil_proto_head *) &ifp->proto_head;
1421 TAILQ_INIT(tmp);
1422
1423 ifp->if_data.default_proto = 0;
1424 ifp->offercnt = 0;
1425 TAILQ_INIT(&ifp->if_flt_head);
1426 old_if_attach(ifp);
1427
1428 if (if_family->init_if) {
1429 stat = (*if_family->init_if)(ifp);
1430 if (stat) {
1431 kprintf("dlil_if_attach -- init_if failed with %d\n", stat);
1432 }
1433 }
1c79356b 1434 }
1c79356b 1435
9bccf70c 1436 ifp->refcnt++;
1c79356b 1437
0b4e3aa0 1438 dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IF_ATTACHED, 0, 0);
1c79356b
A
1439
1440 splx(s);
1441 thread_funnel_set(network_flock, funnel_state);
1442 return 0;
1443}
1444
1445
1446int
1447dlil_if_detach(struct ifnet *ifp)
1448{
55e303ae
A
1449 struct if_proto *proto;
1450 struct dlil_filterq_entry *if_filter;
1451 struct if_family_str *if_family;
1452 struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
1453 struct kev_msg ev_msg;
1454 boolean_t funnel_state;
1455
1456 funnel_state = thread_funnel_set(network_flock, TRUE);
1457
1458 if_family = find_family_module(ifp->if_family);
1459
1460 if (!if_family) {
1461 kprintf("Attempt to detach interface without family module - %s\n",
1462 ifp->if_name);
1463 thread_funnel_set(network_flock, funnel_state);
1464 return ENODEV;
1465 }
1466
1467 while (if_filter = TAILQ_FIRST(fhead))
1468 dlil_detach_filter(if_filter->filter_id);
1469
1470 ifp->refcnt--;
1471
1472 if (ifp->refcnt > 0) {
1473 dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IF_DETACHING, 0, 0);
1474 thread_funnel_set(network_flock, funnel_state);
1475 return DLIL_WAIT_FOR_FREE;
1476 }
1477
1478 while (ifp->if_multiaddrs.lh_first) {
1479 struct ifmultiaddr *ifma = ifp->if_multiaddrs.lh_first;
1480
1481 /*
1482 * When the interface is gone, we will no
1483 * longer be listening on these multicasts.
1484 * Various bits of the stack may be referencing
1485 * these multicasts, so we can't just free them.
1486 * We place them on a list so they may be cleaned
1487 * up later as the other bits of the stack release
1488 * them.
1489 */
1490 LIST_REMOVE(ifma, ifma_link);
1491 ifma->ifma_ifp = NULL;
1492 LIST_INSERT_HEAD(&ifma_lostlist, ifma, ifma_link);
1493 }
1494
1495 /* Let BPF know the interface is detaching. */
1496 bpfdetach(ifp);
1c79356b
A
1497 TAILQ_REMOVE(&ifnet, ifp, if_link);
1498
1499 (*if_family->del_if)(ifp);
55e303ae 1500
1c79356b 1501 if (--if_family->refcnt == 0) {
55e303ae
A
1502 if (if_family->shutdown)
1503 (*if_family->shutdown)();
1504
1505 TAILQ_REMOVE(&if_family_head, if_family, if_fam_next);
1506 FREE(if_family, M_IFADDR);
1c79356b 1507 }
55e303ae
A
1508
1509 dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IF_DETACHED, 0, 0);
1c79356b
A
1510 thread_funnel_set(network_flock, funnel_state);
1511 return 0;
1c79356b
A
1512}
1513
1514
1515int
1516dlil_reg_if_modules(u_long interface_family,
1517 struct dlil_ifmod_reg_str *ifmod)
1518{
1519 struct if_family_str *if_family;
1520 int s;
1521 boolean_t funnel_state;
1522
1523
1524 funnel_state = thread_funnel_set(network_flock, TRUE);
1525 s = splnet();
1526 if (find_family_module(interface_family)) {
1527 kprintf("Attempt to register dlil family module more than once - %d\n",
1528 interface_family);
1529 splx(s);
1530 thread_funnel_set(network_flock, funnel_state);
1531 return EEXIST;
1532 }
1533
1534 if ((!ifmod->add_if) || (!ifmod->del_if) ||
1535 (!ifmod->add_proto) || (!ifmod->del_proto)) {
1536 kprintf("dlil_reg_if_modules passed at least one null pointer\n");
1537 splx(s);
1538 thread_funnel_set(network_flock, funnel_state);
1539 return EINVAL;
1540 }
9bccf70c
A
1541
1542 /*
1543 * The following is a gross hack to keep from breaking
1544 * Vicomsoft's internet gateway on Jaguar. Vicomsoft
1545 * does not zero the reserved fields in dlil_ifmod_reg_str.
1546 * As a result, we have to zero any function that used to
1547 * be reserved fields at the time Vicomsoft built their
1548 * kext. Radar #2974305
1549 */
1550 if (ifmod->reserved[0] != 0 || ifmod->reserved[1] != 0 || ifmod->reserved[2]) {
1551 if (interface_family == 123) { /* Vicom */
1552 ifmod->init_if = 0;
1553 } else {
1554 splx(s);
1555 thread_funnel_set(network_flock, funnel_state);
1556 return EINVAL;
1557 }
1558 }
1c79356b
A
1559
1560 if_family = (struct if_family_str *) _MALLOC(sizeof(struct if_family_str), M_IFADDR, M_WAITOK);
1561 if (!if_family) {
1562 kprintf("dlil_reg_if_modules failed allocation\n");
1563 splx(s);
1564 thread_funnel_set(network_flock, funnel_state);
1565 return ENOMEM;
1566 }
1567
1568 bzero(if_family, sizeof(struct if_family_str));
1569
1570 if_family->if_family = interface_family & 0xffff;
1571 if_family->shutdown = ifmod->shutdown;
1572 if_family->add_if = ifmod->add_if;
1573 if_family->del_if = ifmod->del_if;
9bccf70c 1574 if_family->init_if = ifmod->init_if;
1c79356b
A
1575 if_family->add_proto = ifmod->add_proto;
1576 if_family->del_proto = ifmod->del_proto;
1577 if_family->ifmod_ioctl = ifmod->ifmod_ioctl;
1578 if_family->refcnt = 1;
1579 if_family->flags = 0;
1580
1581 TAILQ_INSERT_TAIL(&if_family_head, if_family, if_fam_next);
1582 splx(s);
1583 thread_funnel_set(network_flock, funnel_state);
1584 return 0;
1585}
1586
1587int dlil_dereg_if_modules(u_long interface_family)
1588{
1589 struct if_family_str *if_family;
9bccf70c 1590 int s, ret = 0;
1c79356b
A
1591 boolean_t funnel_state;
1592
1593 funnel_state = thread_funnel_set(network_flock, TRUE);
1594 s = splnet();
1595 if_family = find_family_module(interface_family);
1596 if (if_family == 0) {
1597 splx(s);
1598 thread_funnel_set(network_flock, funnel_state);
1599 return ENOENT;
1600 }
1601
1602 if (--if_family->refcnt == 0) {
1603 if (if_family->shutdown)
1604 (*if_family->shutdown)();
1605
1606 TAILQ_REMOVE(&if_family_head, if_family, if_fam_next);
1607 FREE(if_family, M_IFADDR);
1608 }
9bccf70c 1609 else {
1c79356b 1610 if_family->flags |= DLIL_SHUTDOWN;
9bccf70c
A
1611 ret = DLIL_WAIT_FOR_FREE;
1612 }
1c79356b
A
1613
1614 splx(s);
1615 thread_funnel_set(network_flock, funnel_state);
9bccf70c 1616 return ret;
1c79356b
A
1617}
1618
1619
1620
55e303ae
A
1621int
1622dlil_reg_proto_module(u_long protocol_family, u_long interface_family,
1623 struct dlil_protomod_reg_str *protomod_reg)
1624{
1625 struct proto_family_str *proto_family;
1626 int s;
1627 boolean_t funnel_state;
1628
1629
1630 funnel_state = thread_funnel_set(network_flock, TRUE);
1631 s = splnet();
1632 if (find_proto_module(protocol_family, interface_family)) {
1633 splx(s);
1634 thread_funnel_set(network_flock, funnel_state);
1635 return EEXIST;
1636 }
1637
1638 if (protomod_reg->reserved[0] != 0 || protomod_reg->reserved[1] != 0
1639 || protomod_reg->reserved[2] != 0 || protomod_reg->reserved[3] !=0) {
1640 splx(s);
1641 thread_funnel_set(network_flock, funnel_state);
1642 return EINVAL;
1643 }
1644
1645 if (protomod_reg->attach_proto == NULL) {
1646 splx(s);
1647 thread_funnel_set(network_flock, funnel_state);
1648 return EINVAL;
1649 }
1650
1651 proto_family = (struct proto_family_str *) _MALLOC(sizeof(struct proto_family_str), M_IFADDR, M_WAITOK);
1652 if (!proto_family) {
1653 splx(s);
1654 thread_funnel_set(network_flock, funnel_state);
1655 return ENOMEM;
1656 }
1657
1658 bzero(proto_family, sizeof(struct proto_family_str));
1659 proto_family->proto_family = protocol_family;
1660 proto_family->if_family = interface_family & 0xffff;
1661 proto_family->attach_proto = protomod_reg->attach_proto;
1662 proto_family->detach_proto = protomod_reg->detach_proto;
1663
1664 TAILQ_INSERT_TAIL(&proto_family_head, proto_family, proto_fam_next);
1665 splx(s);
1666 thread_funnel_set(network_flock, funnel_state);
1667 return 0;
1668}
1669
1670int dlil_dereg_proto_module(u_long protocol_family, u_long interface_family)
1671{
1672 struct proto_family_str *proto_family;
1673 int s, ret = 0;
1674 boolean_t funnel_state;
1675
1676 funnel_state = thread_funnel_set(network_flock, TRUE);
1677 s = splnet();
1678 proto_family = find_proto_module(protocol_family, interface_family);
1679 if (proto_family == 0) {
1680 splx(s);
1681 thread_funnel_set(network_flock, funnel_state);
1682 return ENOENT;
1683 }
1684
1685 TAILQ_REMOVE(&proto_family_head, proto_family, proto_fam_next);
1686 FREE(proto_family, M_IFADDR);
1687
1688 splx(s);
1689 thread_funnel_set(network_flock, funnel_state);
1690 return ret;
1691}
1692
1693int dlil_plumb_protocol(u_long protocol_family, struct ifnet *ifp, u_long *dl_tag)
1694{
1695 struct proto_family_str *proto_family;
1696 int s, ret = 0;
1697 boolean_t funnel_state;
1698
1699 funnel_state = thread_funnel_set(network_flock, TRUE);
1700 s = splnet();
1701 proto_family = find_proto_module(protocol_family, ifp->if_family);
1702 if (proto_family == 0) {
1703 splx(s);
1704 thread_funnel_set(network_flock, funnel_state);
1705 return ENOENT;
1706 }
1707
1708 ret = (*proto_family->attach_proto)(ifp, dl_tag);
1709
1710 splx(s);
1711 thread_funnel_set(network_flock, funnel_state);
1712 return ret;
1713}
1714
1715
1716int dlil_unplumb_protocol(u_long protocol_family, struct ifnet *ifp)
1717{
1718 struct proto_family_str *proto_family;
1719 int s, ret = 0;
1720 u_long tag;
1721 boolean_t funnel_state;
1722
1723 funnel_state = thread_funnel_set(network_flock, TRUE);
1724 s = splnet();
1725
1726 ret = dlil_find_dltag(ifp->if_family, ifp->if_unit, protocol_family, &tag);
1727
1728 if (ret == 0) {
1729 proto_family = find_proto_module(protocol_family, ifp->if_family);
1730 if (proto_family && proto_family->detach_proto)
1731 ret = (*proto_family->detach_proto)(ifp, tag);
1732 else
1733 ret = dlil_detach_protocol(tag);
1734 }
1735
1736 splx(s);
1737 thread_funnel_set(network_flock, funnel_state);
1738 return ret;
1739}
1740
1c79356b
A
1741
1742
1743/*
1744 * Old if_attach no-op'ed function defined here for temporary backwards compatibility
1745 */
1746
1747void if_attach(ifp)
1748 struct ifnet *ifp;
1749{
1750 dlil_if_attach(ifp);
1751}
1752
1753
1754
1755int
1756dlil_inject_if_input(struct mbuf *m, char *frame_header, u_long from_id)
1757{
1758 struct ifnet *orig_ifp = 0;
1759 struct ifnet *ifp;
1760 struct if_proto *ifproto;
1761 struct if_proto *proto;
1762 struct dlil_filterq_entry *tmp;
1763 int retval = 0;
1764 struct dlil_filterq_head *fhead;
1765 int match_found;
1766
1c79356b 1767 dlil_stats.inject_if_in1++;
1c79356b 1768
9bccf70c 1769 if (from_id >= dlil_filters_nb || dlil_filters[from_id].type != DLIL_IF_FILTER)
1c79356b
A
1770 return ENOENT;
1771
1772 ifp = dlil_filters[from_id].ifp;
1773
1774/*
1775 * Let interface filters (if any) do their thing ...
1776 */
1777
1778 fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
1779 match_found = 0;
1780
1781 if (TAILQ_EMPTY(fhead) == 0) {
1782 while (orig_ifp != ifp) {
1783 orig_ifp = ifp;
1784 TAILQ_FOREACH_REVERSE(tmp, fhead, que, dlil_filterq_head) {
1785 if ((match_found) && (IFILT(tmp).filter_if_input)) {
1786 retval = (*IFILT(tmp).filter_if_input)(IFILT(tmp).cookie,
1787 &ifp,
1788 &m,
1789 &frame_header);
1790 if (retval) {
1791 if (retval == EJUSTRETURN)
1792 return 0;
1793 else {
1794 m_freem(m);
1795 return retval;
1796 }
1797 }
1798
1799 }
1800
1801 if (ifp != orig_ifp)
1802 break;
1803
1804 if (from_id == tmp->filter_id)
1805 match_found = 1;
1806 }
1807 }
1808 }
1809
1810 ifp->if_lastchange = time;
1811
1812 /*
1813 * Call family demux module. If the demux module finds a match
1814 * for the frame it will fill-in the ifproto pointer.
1815 */
1816
1817 retval = (*ifp->if_demux)(ifp, m, frame_header, &ifproto );
1818
1819 if (m->m_flags & (M_BCAST|M_MCAST))
1820 ifp->if_imcasts++;
1821
1822 if ((retval) && (ifp->offercnt)) {
1823 /*
1824 * No match was found, look for any offers.
1825 */
1826 struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head;
1827 TAILQ_FOREACH(proto, tmp, next) {
1828 if ((proto->dl_offer) && (proto->dl_offer(m, frame_header) == 0)) {
1829 ifproto = proto;
1830 retval = 0;
1831 break;
1832 }
1833 }
1834 }
1835
1836 if (retval) {
1837 if (retval != EJUSTRETURN) {
1838 m_freem(m);
1839 return retval;
1840 }
1841 else
1842 return 0;
1843 }
1844 else
1845 if (ifproto == 0) {
1846 printf("ERROR - dlil_inject_if_input -- if_demux didn't return an if_proto pointer\n");
1847 m_freem(m);
1848 return 0;
1849 }
1850
1851/*
1852 * Call any attached protocol filters.
1853 */
1854 TAILQ_FOREACH_REVERSE(tmp, &ifproto->pr_flt_head, que, dlil_filterq_head) {
1855 if (PFILT(tmp).filter_dl_input) {
1856 retval = (*PFILT(tmp).filter_dl_input)(PFILT(tmp).cookie,
1857 &m,
1858 &frame_header,
1859 &ifp);
1860
1861 if (retval) {
1862 if (retval == EJUSTRETURN)
1863 return 0;
1864 else {
1865 m_freem(m);
1866 return retval;
1867 }
1868 }
1869 }
1870 }
1871
1872
1873
1874 retval = (*ifproto->dl_input)(m, frame_header,
1875 ifp, ifproto->dl_tag,
1876 FALSE);
1877
1878 dlil_stats.inject_if_in2++;
1879 if (retval == EJUSTRETURN)
1880 retval = 0;
1881 else
1882 if (retval)
1883 m_freem(m);
1884
1885 return retval;
1886
1887}
1888
1889
1890
1891
1892
1893int
1894dlil_inject_pr_input(struct mbuf *m, char *frame_header, u_long from_id)
1895{
1896 struct ifnet *orig_ifp = 0;
1897 struct dlil_filterq_entry *tmp;
1898 int retval;
1899 struct if_proto *ifproto = 0;
1900 int match_found;
1901 struct ifnet *ifp;
1c79356b
A
1902
1903 dlil_stats.inject_pr_in1++;
9bccf70c 1904 if (from_id >= dlil_filters_nb || dlil_filters[from_id].type != DLIL_PR_FILTER)
1c79356b
A
1905 return ENOENT;
1906
1907 ifproto = dlil_filters[from_id].proto;
1908 ifp = dlil_filters[from_id].ifp;
1909
1c79356b
A
1910/*
1911 * Call any attached protocol filters.
1912 */
1913
1914 match_found = 0;
1915 TAILQ_FOREACH_REVERSE(tmp, &ifproto->pr_flt_head, que, dlil_filterq_head) {
1916 if ((match_found) && (PFILT(tmp).filter_dl_input)) {
1917 retval = (*PFILT(tmp).filter_dl_input)(PFILT(tmp).cookie,
1918 &m,
1919 &frame_header,
1920 &ifp);
1921
1922 if (retval) {
1923 if (retval == EJUSTRETURN)
1924 return 0;
1925 else {
1926 m_freem(m);
1927 return retval;
1928 }
1929 }
1930 }
1931
1932 if (tmp->filter_id == from_id)
1933 match_found = 1;
1934 }
1935
1936
1937 retval = (*ifproto->dl_input)(m, frame_header,
1938 ifp, ifproto->dl_tag,
1939 FALSE);
1940
1941 if (retval == EJUSTRETURN)
1942 retval = 0;
1943 else
1944 if (retval)
1945 m_freem(m);
1946
1947 dlil_stats.inject_pr_in2++;
1948 return retval;
1949}
1950
1951
1952
1953int
1954dlil_inject_pr_output(struct mbuf *m,
1955 struct sockaddr *dest,
1956 int raw,
1957 char *frame_type,
1958 char *dst_linkaddr,
1959 u_long from_id)
1960{
1961 struct ifnet *orig_ifp = 0;
1962 struct ifnet *ifp;
1963 struct dlil_filterq_entry *tmp;
1964 int retval = 0;
1965 char frame_type_buffer[MAX_FRAME_TYPE_SIZE * 4];
1966 char dst_linkaddr_buffer[MAX_LINKADDR * 4];
1967 struct dlil_filterq_head *fhead;
1968 int match_found;
1969 u_long dl_tag;
1970
1c79356b
A
1971 dlil_stats.inject_pr_out1++;
1972 if (raw == 0) {
1973 if (frame_type)
1974 bcopy(frame_type, &frame_type_buffer[0], MAX_FRAME_TYPE_SIZE * 4);
1975 else
1976 return EINVAL;
1977
1978 if (dst_linkaddr)
1979 bcopy(dst_linkaddr, &dst_linkaddr_buffer, MAX_LINKADDR * 4);
1980 else
1981 return EINVAL;
1982 }
1983
9bccf70c 1984 if (from_id >= dlil_filters_nb || dlil_filters[from_id].type != DLIL_PR_FILTER)
1c79356b
A
1985 return ENOENT;
1986
1987 ifp = dlil_filters[from_id].ifp;
1988 dl_tag = dlil_filters[from_id].proto->dl_tag;
1c79356b
A
1989
1990 frame_type = frame_type_buffer;
1991 dst_linkaddr = dst_linkaddr_buffer;
1992
1993 fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
1994
1995/*
1996 * Run any attached protocol filters.
1997 */
1998 match_found = 0;
1999
2000 if (TAILQ_EMPTY(dl_tag_array[dl_tag].pr_flt_head) == 0) {
2001 TAILQ_FOREACH(tmp, dl_tag_array[dl_tag].pr_flt_head, que) {
2002 if ((match_found) && (PFILT(tmp).filter_dl_output)) {
2003 retval = (*PFILT(tmp).filter_dl_output)(PFILT(tmp).cookie,
2004 &m, &ifp, &dest, dst_linkaddr, frame_type);
2005 if (retval) {
2006 if (retval == EJUSTRETURN)
2007 return 0;
2008 else {
2009 m_freem(m);
2010 return retval;
2011 }
2012 }
2013 }
2014
2015 if (tmp->filter_id == from_id)
2016 match_found = 1;
2017 }
2018 }
2019
2020
2021/*
2022 * Call framing module
2023 */
2024 if ((raw == 0) && (ifp->if_framer)) {
2025 retval = (*ifp->if_framer)(ifp, &m, dest, dst_linkaddr, frame_type);
2026 if (retval) {
2027 if (retval == EJUSTRETURN)
2028 return 0;
2029 else
2030 {
2031 m_freem(m);
2032 return retval;
2033 }
2034 }
2035 }
2036
2037
2038#if BRIDGE
2039 if (do_bridge) {
2040 struct mbuf *m0 = m ;
9bccf70c 2041 struct ether_header *eh = mtod(m, struct ether_header *);
1c79356b
A
2042
2043 if (m->m_pkthdr.rcvif)
2044 m->m_pkthdr.rcvif = NULL ;
9bccf70c 2045 ifp = bridge_dst_lookup(eh);
1c79356b
A
2046 bdg_forward(&m0, ifp);
2047 if (m0)
2048 m_freem(m0);
2049
2050 return 0;
2051 }
2052#endif
2053
2054
2055/*
2056 * Let interface filters (if any) do their thing ...
2057 */
2058
2059 fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
2060 if (TAILQ_EMPTY(fhead) == 0) {
2061 while (orig_ifp != ifp) {
2062 orig_ifp = ifp;
2063 TAILQ_FOREACH(tmp, fhead, que) {
2064 if (IFILT(tmp).filter_if_output) {
2065 retval = (*IFILT(tmp).filter_if_output)(IFILT(tmp).cookie,
2066 &ifp,
2067 &m);
2068 if (retval) {
2069 if (retval == EJUSTRETURN)
2070 return 0;
2071 else {
2072 m_freem(m);
2073 return retval;
2074 }
2075 }
2076
2077 }
2078
2079 if (ifp != orig_ifp)
2080 break;
2081 }
2082 }
2083 }
2084
2085/*
2086 * Finally, call the driver.
2087 */
2088
2089 retval = (*ifp->if_output)(ifp, m);
2090 dlil_stats.inject_pr_out2++;
2091 if ((retval == 0) || (retval == EJUSTRETURN))
2092 return 0;
2093 else
2094 return retval;
2095}
2096
2097
2098int
2099dlil_inject_if_output(struct mbuf *m, u_long from_id)
2100{
2101 struct ifnet *orig_ifp = 0;
2102 struct ifnet *ifp;
2103 struct dlil_filterq_entry *tmp;
2104 int retval = 0;
2105 struct dlil_filterq_head *fhead;
2106 int match_found;
2107
1c79356b 2108 dlil_stats.inject_if_out1++;
9bccf70c 2109 if (from_id > dlil_filters_nb || dlil_filters[from_id].type != DLIL_IF_FILTER)
1c79356b
A
2110 return ENOENT;
2111
2112 ifp = dlil_filters[from_id].ifp;
2113
2114/*
2115 * Let interface filters (if any) do their thing ...
2116 */
2117
2118 fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
2119 match_found = 0;
2120
2121 if (TAILQ_EMPTY(fhead) == 0) {
2122 while (orig_ifp != ifp) {
2123 orig_ifp = ifp;
2124 TAILQ_FOREACH(tmp, fhead, que) {
2125 if ((match_found) && (IFILT(tmp).filter_if_output)) {
2126 retval = (*IFILT(tmp).filter_if_output)(IFILT(tmp).cookie,
2127 &ifp,
2128 &m);
2129 if (retval) {
2130 if (retval == EJUSTRETURN)
2131 return 0;
2132 else {
2133 m_freem(m);
2134 return retval;
2135 }
2136 }
2137
2138 }
2139
2140 if (ifp != orig_ifp)
2141 break;
2142
2143 if (from_id == tmp->filter_id)
2144 match_found = 1;
2145 }
2146 }
2147 }
2148
2149/*
2150 * Finally, call the driver.
2151 */
2152
2153 retval = (*ifp->if_output)(ifp, m);
2154 dlil_stats.inject_if_out2++;
2155 if ((retval == 0) || (retval == EJUSTRETURN))
2156 return 0;
2157 else
2158 return retval;
2159}
9bccf70c
A
2160
2161static
2162int dlil_recycle_ioctl(struct ifnet *ifnet_ptr, u_long ioctl_code, void *ioctl_arg)
2163{
2164
2165 return EOPNOTSUPP;
2166}
2167
2168static
2169int dlil_recycle_output(struct ifnet *ifnet_ptr, struct mbuf *m)
2170{
2171
2172 m_freem(m);
2173 return 0;
2174}
2175
2176static
2177int dlil_recycle_free(struct ifnet *ifnet_ptr)
2178{
2179 return 0;
2180}
2181
2182static
2183int dlil_recycle_set_bpf_tap(struct ifnet *ifp, int mode,
2184 int (*bpf_callback)(struct ifnet *, struct mbuf *))
2185{
2186 /* XXX not sure what to do here */
2187 return 0;
2188}
2189
2190int dlil_if_acquire(u_long family, void *uniqueid, size_t uniqueid_len,
2191 struct ifnet **ifp)
2192{
2193 struct ifnet *ifp1 = NULL;
2194 struct dlil_ifnet *dlifp1 = NULL;
2195 int s, ret = 0;
2196 boolean_t funnel_state;
2197
2198 funnel_state = thread_funnel_set(network_flock, TRUE);
2199 s = splnet();
2200
2201 TAILQ_FOREACH(dlifp1, &dlil_ifnet_head, dl_if_link) {
2202
2203 ifp1 = (struct ifnet *)dlifp1;
2204
2205 if (ifp1->if_family == family) {
2206
2207 /* same uniqueid and same len or no unique id specified */
2208 if ((uniqueid_len == dlifp1->if_uniqueid_len)
2209 && !bcmp(uniqueid, dlifp1->if_uniqueid, uniqueid_len)) {
2210
2211 /* check for matching interface in use */
2212 if (ifp1->if_eflags & IFEF_INUSE) {
2213 if (uniqueid_len) {
2214 ret = EBUSY;
2215 goto end;
2216 }
2217 }
2218 else {
2219
2220 ifp1->if_eflags |= (IFEF_INUSE + IFEF_REUSE);
2221 *ifp = ifp1;
2222 goto end;
2223 }
2224 }
2225 }
2226 }
2227
2228 /* no interface found, allocate a new one */
2229 MALLOC(dlifp1, struct dlil_ifnet *, sizeof(*dlifp1), M_NKE, M_WAITOK);
2230 if (dlifp1 == 0) {
2231 ret = ENOMEM;
2232 goto end;
2233 }
2234
2235 bzero(dlifp1, sizeof(*dlifp1));
2236
2237 if (uniqueid_len) {
2238 MALLOC(dlifp1->if_uniqueid, void *, uniqueid_len, M_NKE, M_WAITOK);
2239 if (dlifp1->if_uniqueid == 0) {
2240 FREE(dlifp1, M_NKE);
2241 ret = ENOMEM;
2242 goto end;
2243 }
2244 bcopy(uniqueid, dlifp1->if_uniqueid, uniqueid_len);
2245 dlifp1->if_uniqueid_len = uniqueid_len;
2246 }
2247
2248 ifp1 = (struct ifnet *)dlifp1;
2249 ifp1->if_eflags |= IFEF_INUSE;
2250
2251 TAILQ_INSERT_TAIL(&dlil_ifnet_head, dlifp1, dl_if_link);
2252
2253 *ifp = ifp1;
2254
2255end:
2256
2257 splx(s);
2258 thread_funnel_set(network_flock, funnel_state);
2259 return ret;
2260}
2261
2262void dlil_if_release(struct ifnet *ifp)
2263{
2264 struct dlil_ifnet *dlifp = (struct dlil_ifnet *)ifp;
2265 int s;
2266 boolean_t funnel_state;
2267
2268 funnel_state = thread_funnel_set(network_flock, TRUE);
2269 s = splnet();
2270
2271 ifp->if_eflags &= ~IFEF_INUSE;
2272 ifp->if_ioctl = dlil_recycle_ioctl;
2273 ifp->if_output = dlil_recycle_output;
2274 ifp->if_free = dlil_recycle_free;
2275 ifp->if_set_bpf_tap = dlil_recycle_set_bpf_tap;
2276
2277 strncpy(dlifp->if_namestorage, ifp->if_name, IFNAMSIZ);
2278 ifp->if_name = dlifp->if_namestorage;
2279
2280 splx(s);
2281 thread_funnel_set(network_flock, funnel_state);
2282}
2283