|
|
1.1 root 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:
42:
43:
44: #define MAX_DL_TAGS 50
45: #define MAX_DLIL_FILTERS 50
46: #define MAX_FRAME_TYPE_SIZE 4 /* LONGWORDS */
47: #define MAX_LINKADDR 4 /* LONGWORDS */
48: #define M_NKE M_IFADDR
49:
50: #define PFILT(x) ((struct dlil_filterq_entry *) (x))->variants.pr_filter
51: #define IFILT(x) ((struct dlil_filterq_entry *) (x))->variants.if_filter
52:
53: struct dl_tag_str {
54: struct ifnet *ifp;
55: struct if_proto *proto;
56: struct dlil_filterq_head *pr_flt_head;
57: };
58:
59:
60: struct dlil_stats_str {
61: int inject_pr_in1;
62: int inject_pr_in2;
63: int inject_pr_out1;
64: int inject_pr_out2;
65: int inject_if_in1;
66: int inject_if_in2;
67: int inject_if_out1;
68: int inject_if_out2;
69: };
70:
71:
72: struct dlil_filter_id_str {
73: int type;
74: struct dlil_filterq_head *head;
75: struct dlil_filterq_entry *filter_ptr;
76: struct ifnet *ifp;
77: struct if_proto *proto;
78: };
79:
80:
81:
82: struct if_family_str {
83: TAILQ_ENTRY(if_family_str) if_fam_next;
84: u_long if_family;
85: int refcnt;
86: int flags;
87:
88: #define DLIL_SHUTDOWN 1
89:
90: int (*add_if)(struct ifnet *ifp);
91: int (*del_if)(struct ifnet *ifp);
92: int (*add_proto)(struct ddesc_head_str *demux_desc_head,
93: struct if_proto *proto, u_long dl_tag);
94: int (*del_proto)(struct if_proto *proto, u_long dl_tag);
95: int (*shutdown)();
96: };
97:
98:
99:
100: struct dlil_stats_str dlil_stats;
101:
102: static
103: struct dlil_filter_id_str dlil_filters[MAX_DLIL_FILTERS+1];
104:
105: static
106: struct dl_tag_str dl_tag_array[MAX_DL_TAGS+1];
107:
108: static
109: TAILQ_HEAD(, if_family_str) if_family_head;
110:
111: static ifnet_inited = 0;
112:
113: /*
114: * Internal functions.
115: */
116:
117: static
118: struct if_family_str *find_family_module(u_long if_family)
119: {
120: struct if_family_str *mod = NULL;
121:
122: TAILQ_FOREACH(mod, &if_family_head, if_fam_next) {
123: if (mod->if_family == if_family)
124: break;
125: }
126:
127: return mod;
128: }
129:
130:
131: /*
132: * Public functions.
133: */
134:
135: struct ifnet *ifbyfamily(u_long family, short unit)
136: {
137: struct ifnet *ifp;
138:
139: TAILQ_FOREACH(ifp, &ifnet, if_link)
140: if ((family == ifp->if_family) &&
141: (ifp->if_unit == unit))
142: return ifp;
143:
144: return 0;
145: }
146:
147: struct if_proto *dlttoproto(dl_tag)
148: u_long dl_tag;
149: {
150: return dl_tag_array[dl_tag].proto;
151: }
152:
153:
154: u_long ifptodlt(struct ifnet *ifp, u_long proto_family)
155: {
156: struct if_proto *proto;
157: struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head;
158:
159:
160: TAILQ_FOREACH(proto, tmp, next)
161: if (proto->ifp == ifp)
162: if (proto->protocol_family == proto_family)
163: return proto->dl_tag;
164:
165: return 0;
166: }
167:
168:
169: int dlil_find_dltag(u_long if_family, short unit, u_long proto_family, u_long *dl_tag)
170: {
171: struct ifnet *ifp;
172:
173: ifp = ifbyfamily(if_family, unit);
174: if (!ifp)
175: return ENOENT;
176:
177: *dl_tag = ifptodlt(ifp, proto_family);
178: if (*dl_tag == 0)
179: return EPROTONOSUPPORT;
180: else
181: return 0;
182: }
183:
184:
185: int dlil_get_next_dl_tag(u_long current_tag, struct dl_tag_attr_str *next)
186: {
187: int i;
188:
189: for (i = (current_tag+1); i < MAX_DL_TAGS; i++)
190: if (dl_tag_array[i].ifp) {
191: next->dl_tag = i;
192: next->if_flags = dl_tag_array[i].ifp->if_flags;
193: next->if_unit = dl_tag_array[i].ifp->if_unit;
194: next->protocol_family = dl_tag_array[i].proto->protocol_family;
195: next->if_family = dl_tag_array[i].ifp->if_family;
196: return 0;
197: }
198:
199: /*
200: * If we got here, there are no more entries
201: */
202:
203: return ENOENT;
204: }
205:
206:
207: void
208: dlil_init()
209: {
210: int i;
211:
212: TAILQ_INIT(&if_family_head);
213: for (i=0; i < MAX_DL_TAGS; i++)
214: dl_tag_array[i].ifp = 0;
215:
216: for (i=0; i < MAX_DLIL_FILTERS; i++)
217: dlil_filters[i].type = 0;
218:
219: bzero(&dlil_stats, sizeof(dlil_stats));
220: }
221:
222:
223: u_long get_new_filter_id()
224: {
225: u_long i;
226:
227: for (i=1; i < MAX_DLIL_FILTERS; i++)
228: if (dlil_filters[i].type == 0)
229: return i;
230:
231: return 0;
232: }
233:
234:
235: int dlil_attach_interface_filter(struct ifnet *ifp,
236: struct dlil_if_flt_str *if_filter,
237: u_long *filter_id,
238: int insertion_point)
239: {
240: int s;
241: int retval;
242: struct dlil_filterq_entry *tmp_ptr;
243: struct dlil_filterq_entry *if_filt;
244: struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
245:
246:
247: MALLOC(tmp_ptr, struct dlil_filterq_entry *, sizeof(*tmp_ptr), M_NKE, M_WAITOK);
248: bcopy((caddr_t) if_filter, (caddr_t) &tmp_ptr->variants.if_filter,
249: sizeof(struct dlil_if_flt_str));
250:
251: s = splnet();
252:
253: if (insertion_point != DLIL_LAST_FILTER) {
254: TAILQ_FOREACH(if_filt, fhead, que)
255: if (insertion_point == if_filt->filter_id) {
256: TAILQ_INSERT_BEFORE(if_filt, tmp_ptr, que);
257: break;
258: }
259: }
260: else
261: TAILQ_INSERT_TAIL(fhead, tmp_ptr, que);
262:
263: if (*filter_id = get_new_filter_id()) {
264: dlil_filters[*filter_id].filter_ptr = tmp_ptr;
265: dlil_filters[*filter_id].head = (struct dlil_filterq_head *) &ifp->if_flt_head;
266: dlil_filters[*filter_id].type = DLIL_IF_FILTER;
267: dlil_filters[*filter_id].ifp = ifp;
268: tmp_ptr->filter_id = *filter_id;
269: tmp_ptr->type = DLIL_IF_FILTER;
270: retval = 0;
271: }
272: else {
273: kprintf("dlil_attach_interface_filter - can't alloc filter_id\n");
274: TAILQ_REMOVE(fhead, tmp_ptr, que);
275: FREE(tmp_ptr, M_NKE);
276: retval = EOVERFLOW;
277: }
278:
279: splx(s);
280: return retval;
281: }
282:
283:
284: int dlil_attach_protocol_filter(u_long dl_tag,
285: struct dlil_pr_flt_str *pr_filter,
286: u_long *filter_id,
287: int insertion_point)
288: {
289: struct dlil_filterq_entry *tmp_ptr;
290: struct dlil_filterq_entry *pr_filt;
291: int s;
292: int retval;
293:
294:
295: if (dl_tag > MAX_DL_TAGS)
296: return ERANGE;
297:
298: if (dl_tag_array[dl_tag].ifp == 0)
299: return ENOENT;
300:
301: MALLOC(tmp_ptr, struct dlil_filterq_entry *, sizeof(*tmp_ptr), M_NKE, M_WAITOK);
302: bcopy((caddr_t) pr_filter, (caddr_t) &tmp_ptr->variants.pr_filter,
303: sizeof(struct dlil_pr_flt_str));
304:
305:
306: s = splnet();
307: if (insertion_point != DLIL_LAST_FILTER) {
308: TAILQ_FOREACH(pr_filt, dl_tag_array[dl_tag].pr_flt_head, que)
309: if (insertion_point == pr_filt->filter_id) {
310: TAILQ_INSERT_BEFORE(pr_filt, tmp_ptr, que);
311: break;
312: }
313: }
314: else
315: TAILQ_INSERT_TAIL(dl_tag_array[dl_tag].pr_flt_head, tmp_ptr, que);
316:
317:
318: if (*filter_id = get_new_filter_id()) {
319: dlil_filters[*filter_id].filter_ptr = tmp_ptr;
320: dlil_filters[*filter_id].head = dl_tag_array[dl_tag].pr_flt_head;
321: dlil_filters[*filter_id].type = DLIL_PR_FILTER;
322: dlil_filters[*filter_id].proto = dl_tag_array[dl_tag].proto;
323: dlil_filters[*filter_id].ifp = dl_tag_array[dl_tag].ifp;
324: tmp_ptr->filter_id = *filter_id;
325: tmp_ptr->type = DLIL_PR_FILTER;
326: retval = 0;
327: }
328: else {
329: kprintf("dlil_attach_protocol_filter - can't alloc filter_id\n");
330: TAILQ_REMOVE(dl_tag_array[dl_tag].pr_flt_head, tmp_ptr, que);
331: FREE(tmp_ptr, M_NKE);
332: retval = EOVERFLOW;
333: }
334:
335: splx(s);
336: return retval;
337: }
338:
339:
340: int
341: dlil_detach_filter(u_long filter_id)
342: {
343: struct dlil_filter_id_str *flt;
344: int s;
345:
346: if (filter_id > MAX_DLIL_FILTERS) {
347: kprintf("dlil_detach_filter - Bad filter_id value %d\n", filter_id);
348: return ERANGE;
349: }
350:
351: flt = &dlil_filters[filter_id];
352: if (flt->type == 0) {
353: kprintf("dlil_detach_filter - no such filter_id %d\n", filter_id);
354: return ENOENT;
355: }
356:
357: s = splnet();
358: if (flt->type == DLIL_IF_FILTER) {
359: if (IFILT(flt->filter_ptr).filter_detach)
360: (*IFILT(flt->filter_ptr).filter_detach)(IFILT(flt->filter_ptr).cookie);
361: }
362: else {
363: if (flt->type == DLIL_PR_FILTER) {
364: if (PFILT(flt->filter_ptr).filter_detach)
365: (*PFILT(flt->filter_ptr).filter_detach)(PFILT(flt->filter_ptr).cookie);
366: }
367: }
368:
369: TAILQ_REMOVE(flt->head, flt->filter_ptr, que);
370: FREE(flt->filter_ptr, M_NKE);
371: flt->type = 0;
372: splx(s);
373: return 0;
374: }
375:
376:
377:
378:
379: int
380: dlil_input(struct ifnet *ifp, struct mbuf *m,
381: char *frame_header)
382: {
383: boolean_t funnel_state;
384: int ret;
385:
386: funnel_state = thread_set_funneled(TRUE);
387:
388: ret = dlil_input_funneled(ifp, m, frame_header);
389:
390: (void) thread_set_funneled(funnel_state);
391:
392: return(ret);
393: }
394:
395: int
396: dlil_input_funneled(struct ifnet *ifp, struct mbuf *m,
397: char *frame_header)
398: {
399: struct ifnet *orig_ifp = 0;
400: struct dlil_filterq_entry *tmp;
401: int retval;
402: struct if_proto *ifproto = 0;
403: struct if_proto *proto;
404: struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
405:
406: /*
407: * Temporary, until all drivers do this.
408: */
409:
410: ifp->if_ibytes += m->m_pkthdr.len;
411:
412:
413: /*
414: * Run interface filters
415: */
416:
417: while (orig_ifp != ifp) {
418: orig_ifp = ifp;
419:
420: TAILQ_FOREACH_REVERSE(tmp, fhead, que, dlil_filterq_head) {
421: if (IFILT(tmp).filter_if_input) {
422: retval = (*IFILT(tmp).filter_if_input)(IFILT(tmp).cookie,
423: &ifp,
424: &m,
425: &frame_header);
426: if (retval) {
427: if (retval == EJUSTRETURN)
428: return 0;
429: else {
430: m_freem(m);
431: return retval;
432: }
433: }
434: }
435:
436: if (ifp != orig_ifp)
437: break;
438: }
439: }
440:
441: ifp->if_lastchange = time;
442:
443: /*
444: * Call family demux module. If the demux module finds a match
445: * for the frame it will fill-in the ifproto pointer.
446: */
447:
448: retval = (*ifp->if_demux)(ifp, m, frame_header, &ifproto );
449:
450: if (m->m_flags & (M_BCAST|M_MCAST))
451: ifp->if_imcasts++;
452:
453: if ((retval) && (ifp->offercnt)) {
454: /*
455: * No match was found, look for any offers.
456: */
457: struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head;
458: TAILQ_FOREACH(proto, tmp, next) {
459: if ((proto->dl_offer) && (proto->dl_offer(m, frame_header) == 0)) {
460: ifproto = proto;
461: retval = 0;
462: break;
463: }
464: }
465: }
466:
467: if (retval) {
468: if (retval != EJUSTRETURN) {
469: m_freem(m);
470: return retval;
471: }
472: else
473: return 0;
474: }
475: else
476: if (ifproto == 0) {
477: printf("ERROR - dlil_input - if_demux didn't return an if_proto pointer\n");
478: m_freem(m);
479: return 0;
480: }
481:
482: /*
483: * Call any attached protocol filters.
484: */
485:
486: TAILQ_FOREACH_REVERSE(tmp, &ifproto->pr_flt_head, que, dlil_filterq_head) {
487: if (PFILT(tmp).filter_dl_input) {
488: retval = (*PFILT(tmp).filter_dl_input)(PFILT(tmp).cookie,
489: &m,
490: &frame_header,
491: &ifp);
492:
493: if (retval) {
494: if (retval == EJUSTRETURN)
495: return 0;
496: else {
497: m_freem(m);
498: return retval;
499: }
500: }
501: }
502: }
503:
504:
505:
506: retval = (*ifproto->dl_input)(m, frame_header,
507: ifp, ifproto->dl_tag,
508: (ifp->if_eflags & IFEF_DVR_REENTRY_OK));
509:
510: if (retval == EJUSTRETURN)
511: retval = 0;
512: else
513: if (retval)
514: m_freem(m);
515:
516: return retval;
517: }
518:
519:
520:
521: void ether_input(ifp, eh, m)
522: struct ifnet *ifp;
523: struct ether_header *eh;
524: struct mbuf *m;
525:
526: {
527: kprintf("Someone is calling ether_input!!\n");
528:
529: dlil_input(ifp, m, (char *) eh);
530: }
531:
532:
533: int
534: dlil_event(struct ifnet *ifp, struct event_msg *event)
535: {
536: return 0;
537: }
538:
539:
540:
541: int
542: dlil_output(u_long dl_tag,
543: struct mbuf *m,
544: caddr_t route,
545: struct sockaddr *dest,
546: int raw
547: )
548: {
549: char *frame_type;
550: char *dst_linkaddr;
551: struct ifnet *orig_ifp = 0;
552: struct ifnet *ifp;
553: struct if_proto *proto;
554: struct dlil_filterq_entry *tmp;
555: int retval = 0;
556: char frame_type_buffer[MAX_FRAME_TYPE_SIZE * 4];
557: char dst_linkaddr_buffer[MAX_LINKADDR * 4];
558: struct dlil_filterq_head *fhead;
559:
560:
561:
562:
563: /*
564: * Temporary hackery until all the existing protocols can become fully
565: * "dl_tag aware". Some things only have the ifp, so this handles that
566: * case for the time being.
567: */
568:
569: if (dl_tag > MAX_DL_TAGS) {
570: /* dl_tag is really an ifnet pointer! */
571:
572: ifp = (struct ifnet *) dl_tag;
573: dl_tag = ifp->if_data.default_proto;
574: if (dl_tag)
575: proto = dl_tag_array[dl_tag].proto;
576: }
577: else {
578: if ((dl_tag == 0) || (dl_tag_array[dl_tag].ifp == 0))
579: retval = ENOENT;
580: else {
581: ifp = dl_tag_array[dl_tag].ifp;
582: proto = dl_tag_array[dl_tag].proto;
583: }
584: }
585:
586: if (retval) {
587: m_freem(m);
588: return retval;
589: }
590:
591: frame_type = frame_type_buffer;
592: dst_linkaddr = dst_linkaddr_buffer;
593:
594: fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
595:
596: if ((raw == 0) && (proto->dl_pre_output)) {
597: retval = (*proto->dl_pre_output)(ifp, &m, dest, route,
598: frame_type, dst_linkaddr, dl_tag);
599: if (retval) {
600: if (retval == EJUSTRETURN)
601: return 0;
602: else {
603: m_freem(m);
604: return retval;
605: }
606: }
607: }
608:
609: /*
610: * Run any attached protocol filters.
611: */
612:
613: if (TAILQ_EMPTY(dl_tag_array[dl_tag].pr_flt_head) == 0) {
614: TAILQ_FOREACH(tmp, dl_tag_array[dl_tag].pr_flt_head, que) {
615: if (PFILT(tmp).filter_dl_output) {
616: retval = (*PFILT(tmp).filter_dl_output)(PFILT(tmp).cookie,
617: &m, &ifp, &dest, dst_linkaddr, frame_type);
618: if (retval) {
619: if (retval == EJUSTRETURN)
620: return 0;
621: else {
622: m_freem(m);
623: return retval;
624: }
625: }
626: }
627: }
628: }
629:
630:
631: /*
632: * Call framing module
633: */
634: if ((raw == 0) && (ifp->if_framer)) {
635: retval = (*ifp->if_framer)(ifp, &m, dest, dst_linkaddr, frame_type);
636: if (retval) {
637: if (retval == EJUSTRETURN)
638: return 0;
639: else
640: {
641: m_freem(m);
642: return retval;
643: }
644: }
645: }
646:
647: #if BRIDGE
648: if (do_bridge) {
649: struct mbuf *m0 = m ;
650:
651: if (m->m_pkthdr.rcvif)
652: m->m_pkthdr.rcvif = NULL ;
653: ifp = bridge_dst_lookup(m);
654: bdg_forward(&m0, ifp);
655: if (m0)
656: m_freem(m0);
657:
658: return 0;
659: }
660: #endif
661:
662:
663: /*
664: * Let interface filters (if any) do their thing ...
665: */
666:
667: fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
668: if (TAILQ_EMPTY(fhead) == 0) {
669: while (orig_ifp != ifp) {
670: orig_ifp = ifp;
671: TAILQ_FOREACH(tmp, fhead, que) {
672: if (IFILT(tmp).filter_if_output) {
673: retval = (*IFILT(tmp).filter_if_output)(IFILT(tmp).cookie,
674: &ifp,
675: &m);
676: if (retval) {
677: if (retval == EJUSTRETURN)
678: return 0;
679: else {
680: m_freem(m);
681: return retval;
682: }
683: }
684:
685: }
686:
687: if (ifp != orig_ifp)
688: break;
689: }
690: }
691: }
692:
693: /*
694: * Finally, call the driver.
695: */
696: if (m->m_hdr.mh_type == 0) {
697: printf("ERROR - dlil_output - sending free mbuf\n");
698: m_freem(m);
699: return 0;
700: }
701: /*
702: * Temporary, until all drivers do this.
703: */
704:
705: ifp->if_obytes += m->m_pkthdr.len;
706:
707: retval = (*ifp->if_output)(ifp, m);
708: if ((retval == 0) || (retval == EJUSTRETURN))
709: return 0;
710: else
711: return retval;
712: }
713:
714:
715: int
716: dlil_ioctl(u_long dl_tag,
717: struct ifnet *ifp,
718: u_long ioctl_code,
719: caddr_t ioctl_arg)
720: {
721: struct dlil_filterq_entry *tmp;
722: struct dlil_filterq_head *fhead;
723: int retval;
724:
725:
726: if (dl_tag) {
727: if (dl_tag > MAX_DL_TAGS)
728: return ERANGE;
729:
730: if (dl_tag_array[dl_tag].ifp == 0)
731: return ENOENT;
732:
733:
734: /*
735: * Run any attached protocol filters.
736: */
737: TAILQ_FOREACH(tmp, dl_tag_array[dl_tag].pr_flt_head, que) {
738: if (PFILT(tmp).filter_dl_ioctl) {
739: retval =
740: (*PFILT(tmp).filter_dl_ioctl)(PFILT(tmp).cookie,
741: dl_tag_array[dl_tag].ifp,
742: ioctl_code,
743: ioctl_arg);
744:
745: if (retval) {
746: return 0;
747: }
748: }
749: }
750:
751: if (dl_tag_array[dl_tag].proto->dl_ioctl)
752: retval = (*dl_tag_array[dl_tag].proto->dl_ioctl)(dl_tag,
753: dl_tag_array[dl_tag].ifp,
754: ioctl_code,
755: ioctl_arg);
756:
757: else
758: retval = EINVAL;
759: }
760: else {
761: if (ifp) {
762: fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
763: TAILQ_FOREACH(tmp, fhead, que) {
764: if (IFILT(tmp).filter_if_ioctl) {
765: retval = (*IFILT(tmp).filter_if_ioctl)(IFILT(tmp).cookie, ifp,
766: ioctl_code, ioctl_arg);
767: if (retval) {
768: return 0;
769: }
770: }
771: }
772: if (ifp->if_ioctl)
773: retval = (*ifp->if_ioctl)(ifp, ioctl_code, ioctl_arg);
774: else
775: return 0;
776: }
777: else
778: retval = EINVAL;
779: }
780:
781: return retval;
782: }
783:
784:
785: int
786: dlil_attach_protocol(struct dlil_proto_reg_str *proto,
787: u_long *dl_tag)
788: {
789: struct ifnet *ifp;
790: struct if_proto *ifproto;
791: u_long i;
792: struct if_family_str *if_family;
793: int error;
794: struct dlil_proto_head *tmp;
795: int s;
796:
797:
798: if ((proto->protocol_family == 0) || (proto->interface_family == 0))
799: return EINVAL;
800:
801: s = splnet();
802: if_family = find_family_module(proto->interface_family);
803: if ((!if_family) || (if_family->flags & DLIL_SHUTDOWN)) {
804: kprintf("dlil_attach_protocol -- no interface family module %d",
805: proto->interface_family);
806: splx(s);
807: return ENOENT;
808: }
809:
810: ifp = ifbyfamily(proto->interface_family, proto->unit_number);
811: if (!ifp) {
812: kprintf("dlil_attach_protocol -- no such interface %d unit %d\n",
813: proto->interface_family, proto->unit_number);
814: splx(s);
815: return ENOENT;
816: }
817:
818: if (dlil_find_dltag(proto->interface_family, proto->unit_number,
819: proto->protocol_family, &i) == 0)
820: return EEXIST;
821:
822: for (i=1; i < MAX_DL_TAGS; i++)
823: if (dl_tag_array[i].ifp == 0)
824: break;
825:
826: if (i >= MAX_DL_TAGS) {
827: splx(s);
828: return EOVERFLOW;
829: }
830:
831: /*
832: * Allocate and init a new if_proto structure
833: */
834:
835: ifproto = _MALLOC(sizeof(struct if_proto), M_IFADDR, M_NOWAIT);
836: if (!ifproto) {
837: printf("ERROR - DLIL failed if_proto allocation\n");
838: return ENOMEM;
839: }
840:
841: bzero(ifproto, sizeof(struct if_proto));
842:
843: dl_tag_array[i].ifp = ifp;
844: dl_tag_array[i].proto = ifproto;
845: dl_tag_array[i].pr_flt_head = &ifproto->pr_flt_head;
846: ifproto->dl_tag = i;
847: *dl_tag = i;
848:
849: if (proto->default_proto) {
850: if (ifp->if_data.default_proto == 0)
851: ifp->if_data.default_proto = i;
852: else
853: printf("ERROR - dlil_attach_protocol -- Attempt to attach more than one default protocol\n");
854: }
855:
856: ifproto->protocol_family = proto->protocol_family;
857: ifproto->dl_input = proto->input;
858: ifproto->dl_pre_output = proto->pre_output;
859: ifproto->dl_event = proto->event;
860: ifproto->dl_offer = proto->offer;
861: ifproto->dl_ioctl = proto->ioctl;
862: ifproto->ifp = ifp;
863: TAILQ_INIT(&ifproto->pr_flt_head);
864:
865: /*
866: * Call family module add_proto routine so it can refine the
867: * demux descriptors as it wishes.
868: */
869: error = (*if_family->add_proto)(&proto->demux_desc_head, ifproto, *dl_tag);
870: if (error) {
871: dl_tag_array[*dl_tag].ifp = 0;
872: FREE(ifproto, M_IFADDR);
873: splx(s);
874: return error;
875: }
876:
877:
878: /*
879: * Add to if_proto list for this interface
880: */
881:
882: tmp = (struct dlil_proto_head *) &ifp->proto_head;
883: TAILQ_INSERT_TAIL(tmp, ifproto, next);
884: ifp->refcnt++;
885: if (ifproto->dl_offer)
886: ifp->offercnt++;
887:
888: splx(s);
889: return 0;
890: }
891:
892:
893:
894: int
895: dlil_detach_protocol(u_long dl_tag)
896: {
897: struct ifnet *ifp;
898: struct ifnet *orig_ifp=0;
899: struct if_proto *proto;
900: struct dlil_proto_head *tmp;
901: struct if_family_str *if_family;
902: struct dlil_filterq_entry *filter;
903: int s, retval;
904: struct dlil_filterq_head *fhead;
905:
906:
907:
908: if (dl_tag > MAX_DL_TAGS)
909: return ERANGE;
910:
911: s = splnet();
912: if (dl_tag_array[dl_tag].ifp == 0) {
913: splx(s);
914: return ENOENT;
915: }
916:
917: ifp = dl_tag_array[dl_tag].ifp;
918: proto = dl_tag_array[dl_tag].proto;
919:
920: if_family = find_family_module(ifp->if_family);
921: if (if_family == NULL)
922: return ENOENT;
923:
924: tmp = (struct dlil_proto_head *) &ifp->proto_head;
925:
926: /*
927: * Call family module del_proto
928: */
929:
930: (*if_family->del_proto)(proto, dl_tag);
931:
932:
933: /*
934: * Remove and deallocate any attached protocol filters
935: */
936:
937: while (filter = TAILQ_FIRST(&proto->pr_flt_head))
938: dlil_detach_filter(filter->filter_id);
939:
940: if (proto->dl_offer)
941: ifp->offercnt--;
942:
943: dl_tag_array[dl_tag].ifp = 0;
944:
945: TAILQ_REMOVE(tmp, proto, next);
946: FREE(proto, M_IFADDR);
947:
948: if (--ifp->refcnt == 0) {
949: if (ifp->if_flags & IFF_UP)
950: printf("WARNING - dlil_detach_protocol - ifp refcnt 0, but IF still up\n");
951:
952: TAILQ_REMOVE(&ifnet, ifp, if_link);
953:
954: if (if_family->del_if)
955: (*if_family->del_if)(ifp);
956:
957:
958: fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
959: while (orig_ifp != ifp) {
960: orig_ifp = ifp;
961:
962: TAILQ_FOREACH(filter, fhead, que) {
963: if (IFILT(filter).filter_if_free) {
964: retval = (*IFILT(filter).filter_if_free)(IFILT(filter).cookie, ifp);
965: if (retval) {
966: splx(s);
967: return 0;
968: }
969: }
970: if (ifp != orig_ifp)
971: break;
972: }
973: }
974:
975: (*ifp->if_free)(ifp);
976: }
977:
978: splx(s);
979: return 0;
980: }
981:
982:
983:
984:
985:
986: int
987: dlil_if_attach(struct ifnet *ifp)
988: {
989: u_long interface_family = ifp->if_family;
990: struct if_family_str *if_family;
991: struct dlil_proto_head *tmp;
992: int stat;
993: int s;
994:
995:
996:
997: s = splnet();
998: if (ifnet_inited == 0) {
999: TAILQ_INIT(&ifnet);
1000: ifnet_inited = 1;
1001: }
1002:
1003: if_family = find_family_module(interface_family);
1004:
1005: if ((!if_family) || (if_family->flags & DLIL_SHUTDOWN)) {
1006: splx(s);
1007: kprintf("Attempt to attach interface without family module - %d\n",
1008: interface_family);
1009: return ENODEV;
1010: }
1011:
1012:
1013: /*
1014: * Call the family module to fill in the appropriate fields in the
1015: * ifnet structure.
1016: */
1017:
1018: stat = (*if_family->add_if)(ifp);
1019: if (stat) {
1020: splx(s);
1021: kprintf("dlil_if_attach -- add_if failed with %d\n", stat);
1022: return stat;
1023: }
1024:
1025: /*
1026: * Add the ifp to the interface list.
1027: */
1028:
1029: tmp = (struct dlil_proto_head *) &ifp->proto_head;
1030: TAILQ_INIT(tmp);
1031:
1032: ifp->if_data.default_proto = 0;
1033: ifp->refcnt = 1;
1034: ifp->offercnt = 0;
1035: TAILQ_INIT(&ifp->if_flt_head);
1036: old_if_attach(ifp);
1037: if_family->refcnt++;
1038:
1039: splx(s);
1040: return 0;
1041: }
1042:
1043:
1044: int
1045: dlil_if_detach(struct ifnet *ifp)
1046: {
1047: struct if_proto *proto;
1048: struct dlil_filterq_entry *if_filter;
1049: struct if_family_str *if_family;
1050: struct dlil_filterq_head *fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
1051: int s;
1052:
1053: s = splnet();
1054: if (ifp->if_flags & IFF_UP)
1055: printf("WARNING - dlil_if_detach called for UP interface\n");
1056:
1057: if_family = (struct if_family_str *) ifp->if_family;
1058:
1059: if (!if_family) {
1060: kprintf("Attempt to detach interface without family module - %s\n",
1061: ifp->if_name);
1062: splx(s);
1063: return ENODEV;
1064: }
1065:
1066: while (if_filter = TAILQ_FIRST(fhead))
1067: dlil_detach_filter(if_filter->filter_id);
1068:
1069: if (--ifp->refcnt == 0) {
1070: TAILQ_REMOVE(&ifnet, ifp, if_link);
1071:
1072: if (if_family->del_if)
1073: (*if_family->del_if)(ifp);
1074:
1075: if (--if_family->refcnt == 0) {
1076: if (if_family->shutdown)
1077: (*if_family->shutdown)();
1078:
1079: TAILQ_REMOVE(&if_family_head, if_family, if_fam_next);
1080: FREE(if_family, M_IFADDR);
1081: }
1082: splx(s);
1083: return 0;
1084: }
1085: else
1086: {
1087: splx(s);
1088: return DLIL_WAIT_FOR_FREE;
1089: }
1090: }
1091:
1092:
1093: int
1094: dlil_reg_if_modules(u_long interface_family,
1095: int (*add_if)(struct ifnet *ifp),
1096: int (*del_if)(struct ifnet *ifp),
1097: int (*add_proto)(struct ddesc_head_str *head,
1098: struct if_proto *proto, u_long dl_tag),
1099: int (*del_proto)(struct if_proto *proto, u_long dl_tag),
1100: int (*shutdown)())
1101: {
1102: struct if_family_str *if_family;
1103: int s;
1104:
1105:
1106: s = splnet();
1107: if (find_family_module(interface_family)) {
1108: kprintf("Attempt to register dlil family module more than once - %d\n",
1109: interface_family);
1110: splx(s);
1111: return EEXIST;
1112: }
1113:
1114: if ((!add_if) || (!del_if) ||
1115: (!add_proto) || (!del_proto)) {
1116: kprintf("dlil_reg_if_modules passed at least one null pointer\n");
1117: splx(s);
1118: return EINVAL;
1119: }
1120:
1121: if_family = (struct if_family_str *) _MALLOC(sizeof(struct if_family_str), M_IFADDR, M_NOWAIT);
1122: if (!if_family) {
1123: kprintf("dlil_reg_if_modules failed allocation\n");
1124: splx(s);
1125: return ENOMEM;
1126: }
1127:
1128: bzero(if_family, sizeof(struct if_family_str));
1129:
1130: if_family->if_family = interface_family;
1131: if_family->shutdown = shutdown;
1132: if_family->add_if = add_if;
1133: if_family->del_if = del_if;
1134: if_family->add_proto = add_proto;
1135: if_family->del_proto = del_proto;
1136: if_family->refcnt = 1;
1137: if_family->flags = 0;
1138:
1139: TAILQ_INSERT_TAIL(&if_family_head, if_family, if_fam_next);
1140: splx(s);
1141: return 0;
1142: }
1143:
1144: int dlil_dereg_if_modules(u_long interface_family)
1145: {
1146: struct if_family_str *if_family;
1147: int s;
1148:
1149:
1150: s = splnet();
1151: if_family = find_family_module(interface_family);
1152: if (if_family == 0) {
1153: splx(s);
1154: return ENOENT;
1155: }
1156:
1157: if (--if_family->refcnt) {
1158: if (if_family->shutdown)
1159: (*if_family->shutdown)();
1160:
1161: TAILQ_REMOVE(&if_family_head, if_family, if_fam_next);
1162: FREE(if_family, M_IFADDR);
1163: }
1164: else
1165: if_family->flags |= DLIL_SHUTDOWN;
1166:
1167: splx(s);
1168: return 0;
1169: }
1170:
1171:
1172:
1173:
1174:
1175: /*
1176: * Old if_attach no-op'ed function defined here for temporary backwards compatibility
1177: */
1178:
1179: void if_attach(ifp)
1180: struct ifnet *ifp;
1181: {
1182: dlil_if_attach(ifp);
1183: }
1184:
1185:
1186:
1187: int
1188: dlil_inject_if_input(struct mbuf *m, char *frame_header, u_long from_id)
1189: {
1190: struct ifnet *orig_ifp = 0;
1191: struct ifnet *ifp;
1192: struct if_proto *ifproto;
1193: struct if_proto *proto;
1194: struct dlil_filterq_entry *tmp;
1195: int retval = 0;
1196: struct dlil_filterq_head *fhead;
1197: int match_found;
1198:
1199:
1200: dlil_stats.inject_if_in1++;
1201: if (from_id > MAX_DLIL_FILTERS)
1202: return ERANGE;
1203:
1204: if (dlil_filters[from_id].type != DLIL_IF_FILTER)
1205: return ENOENT;
1206:
1207: ifp = dlil_filters[from_id].ifp;
1208:
1209: /*
1210: * Let interface filters (if any) do their thing ...
1211: */
1212:
1213: fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
1214: if (from_id == DLIL_NULL_FILTER)
1215: match_found = 1;
1216: else
1217: match_found = 0;
1218:
1219: if (TAILQ_EMPTY(fhead) == 0) {
1220: while (orig_ifp != ifp) {
1221: orig_ifp = ifp;
1222: TAILQ_FOREACH_REVERSE(tmp, fhead, que, dlil_filterq_head) {
1223: if ((match_found) && (IFILT(tmp).filter_if_input)) {
1224: retval = (*IFILT(tmp).filter_if_input)(IFILT(tmp).cookie,
1225: &ifp,
1226: &m,
1227: &frame_header);
1228: if (retval) {
1229: if (retval == EJUSTRETURN)
1230: return 0;
1231: else {
1232: m_freem(m);
1233: return retval;
1234: }
1235: }
1236:
1237: }
1238:
1239: if (ifp != orig_ifp)
1240: break;
1241:
1242: if (from_id == tmp->filter_id)
1243: match_found = 1;
1244: }
1245: }
1246: }
1247:
1248: ifp->if_lastchange = time;
1249:
1250: /*
1251: * Call family demux module. If the demux module finds a match
1252: * for the frame it will fill-in the ifproto pointer.
1253: */
1254:
1255: retval = (*ifp->if_demux)(ifp, m, frame_header, &ifproto );
1256:
1257: if (m->m_flags & (M_BCAST|M_MCAST))
1258: ifp->if_imcasts++;
1259:
1260: if ((retval) && (ifp->offercnt)) {
1261: /*
1262: * No match was found, look for any offers.
1263: */
1264: struct dlil_proto_head *tmp = (struct dlil_proto_head *) &ifp->proto_head;
1265: TAILQ_FOREACH(proto, tmp, next) {
1266: if ((proto->dl_offer) && (proto->dl_offer(m, frame_header) == 0)) {
1267: ifproto = proto;
1268: retval = 0;
1269: break;
1270: }
1271: }
1272: }
1273:
1274: if (retval) {
1275: if (retval != EJUSTRETURN) {
1276: m_freem(m);
1277: return retval;
1278: }
1279: else
1280: return 0;
1281: }
1282: else
1283: if (ifproto == 0) {
1284: printf("ERROR - dlil_inject_if_input -- if_demux didn't return an if_proto pointer\n");
1285: m_freem(m);
1286: return 0;
1287: }
1288:
1289: /*
1290: * Call any attached protocol filters.
1291: */
1292: TAILQ_FOREACH_REVERSE(tmp, &ifproto->pr_flt_head, que, dlil_filterq_head) {
1293: if (PFILT(tmp).filter_dl_input) {
1294: retval = (*PFILT(tmp).filter_dl_input)(PFILT(tmp).cookie,
1295: &m,
1296: &frame_header,
1297: &ifp);
1298:
1299: if (retval) {
1300: if (retval == EJUSTRETURN)
1301: return 0;
1302: else {
1303: m_freem(m);
1304: return retval;
1305: }
1306: }
1307: }
1308: }
1309:
1310:
1311:
1312: retval = (*ifproto->dl_input)(m, frame_header,
1313: ifp, ifproto->dl_tag,
1314: (ifp->if_eflags & IFEF_DVR_REENTRY_OK));
1315:
1316: dlil_stats.inject_if_in2++;
1317: if (retval == EJUSTRETURN)
1318: retval = 0;
1319: else
1320: if (retval)
1321: m_freem(m);
1322:
1323: return retval;
1324:
1325: }
1326:
1327:
1328:
1329:
1330:
1331: int
1332: dlil_inject_pr_input(struct mbuf *m, char *frame_header, u_long from_id)
1333: {
1334: struct ifnet *orig_ifp = 0;
1335: struct dlil_filterq_entry *tmp;
1336: int retval;
1337: struct if_proto *ifproto = 0;
1338: int match_found;
1339: struct ifnet *ifp;
1340:
1341:
1342: dlil_stats.inject_pr_in1++;
1343: if (from_id > MAX_DLIL_FILTERS)
1344: return ERANGE;
1345:
1346: if (dlil_filters[from_id].type != DLIL_PR_FILTER)
1347: return ENOENT;
1348:
1349: ifproto = dlil_filters[from_id].proto;
1350: ifp = dlil_filters[from_id].ifp;
1351:
1352:
1353: /*
1354: * Call any attached protocol filters.
1355: */
1356:
1357: if (from_id == DLIL_NULL_FILTER)
1358: match_found = 1;
1359: else
1360: match_found = 0;
1361: TAILQ_FOREACH_REVERSE(tmp, &ifproto->pr_flt_head, que, dlil_filterq_head) {
1362: if ((match_found) && (PFILT(tmp).filter_dl_input)) {
1363: retval = (*PFILT(tmp).filter_dl_input)(PFILT(tmp).cookie,
1364: &m,
1365: &frame_header,
1366: &ifp);
1367:
1368: if (retval) {
1369: if (retval == EJUSTRETURN)
1370: return 0;
1371: else {
1372: m_freem(m);
1373: return retval;
1374: }
1375: }
1376: }
1377:
1378: if (tmp->filter_id == from_id)
1379: match_found = 1;
1380: }
1381:
1382:
1383: retval = (*ifproto->dl_input)(m, frame_header,
1384: ifp, ifproto->dl_tag,
1385: (ifp->if_eflags & IFEF_DVR_REENTRY_OK));
1386:
1387: if (retval == EJUSTRETURN)
1388: retval = 0;
1389: else
1390: if (retval)
1391: m_freem(m);
1392:
1393: dlil_stats.inject_pr_in2++;
1394: return retval;
1395: }
1396:
1397:
1398:
1399: int
1400: dlil_inject_pr_output(struct mbuf *m,
1401: struct sockaddr *dest,
1402: int raw,
1403: char *frame_type,
1404: char *dst_linkaddr,
1405: u_long from_id)
1406: {
1407: struct ifnet *orig_ifp = 0;
1408: struct ifnet *ifp;
1409: struct dlil_filterq_entry *tmp;
1410: int retval = 0;
1411: char frame_type_buffer[MAX_FRAME_TYPE_SIZE * 4];
1412: char dst_linkaddr_buffer[MAX_LINKADDR * 4];
1413: struct dlil_filterq_head *fhead;
1414: int match_found;
1415: u_long dl_tag;
1416:
1417:
1418: dlil_stats.inject_pr_out1++;
1419: if (raw == 0) {
1420: if (frame_type)
1421: bcopy(frame_type, &frame_type_buffer[0], MAX_FRAME_TYPE_SIZE * 4);
1422: else
1423: return EINVAL;
1424:
1425: if (dst_linkaddr)
1426: bcopy(dst_linkaddr, &dst_linkaddr_buffer, MAX_LINKADDR * 4);
1427: else
1428: return EINVAL;
1429: }
1430:
1431: if (from_id > MAX_DLIL_FILTERS)
1432: return ERANGE;
1433:
1434: if (dlil_filters[from_id].type != DLIL_PR_FILTER)
1435: return ENOENT;
1436:
1437: ifp = dlil_filters[from_id].ifp;
1438: dl_tag = dlil_filters[from_id].proto->dl_tag;
1439:
1440:
1441: frame_type = frame_type_buffer;
1442: dst_linkaddr = dst_linkaddr_buffer;
1443:
1444: fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
1445:
1446: /*
1447: * Run any attached protocol filters.
1448: */
1449: if (from_id == DLIL_NULL_FILTER)
1450: match_found = 1;
1451: else
1452: match_found = 0;
1453:
1454: if (TAILQ_EMPTY(dl_tag_array[dl_tag].pr_flt_head) == 0) {
1455: TAILQ_FOREACH(tmp, dl_tag_array[dl_tag].pr_flt_head, que) {
1456: if ((match_found) && (PFILT(tmp).filter_dl_output)) {
1457: retval = (*PFILT(tmp).filter_dl_output)(PFILT(tmp).cookie,
1458: &m, &ifp, &dest, dst_linkaddr, frame_type);
1459: if (retval) {
1460: if (retval == EJUSTRETURN)
1461: return 0;
1462: else {
1463: m_freem(m);
1464: return retval;
1465: }
1466: }
1467: }
1468:
1469: if (tmp->filter_id == from_id)
1470: match_found = 1;
1471: }
1472: }
1473:
1474:
1475: /*
1476: * Call framing module
1477: */
1478: if ((raw == 0) && (ifp->if_framer)) {
1479: retval = (*ifp->if_framer)(ifp, &m, dest, dst_linkaddr, frame_type);
1480: if (retval) {
1481: if (retval == EJUSTRETURN)
1482: return 0;
1483: else
1484: {
1485: m_freem(m);
1486: return retval;
1487: }
1488: }
1489: }
1490:
1491:
1492: #if BRIDGE
1493: if (do_bridge) {
1494: struct mbuf *m0 = m ;
1495:
1496: if (m->m_pkthdr.rcvif)
1497: m->m_pkthdr.rcvif = NULL ;
1498: ifp = bridge_dst_lookup(m);
1499: bdg_forward(&m0, ifp);
1500: if (m0)
1501: m_freem(m0);
1502:
1503: return 0;
1504: }
1505: #endif
1506:
1507:
1508: /*
1509: * Let interface filters (if any) do their thing ...
1510: */
1511:
1512: fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
1513: if (TAILQ_EMPTY(fhead) == 0) {
1514: while (orig_ifp != ifp) {
1515: orig_ifp = ifp;
1516: TAILQ_FOREACH(tmp, fhead, que) {
1517: if (IFILT(tmp).filter_if_output) {
1518: retval = (*IFILT(tmp).filter_if_output)(IFILT(tmp).cookie,
1519: &ifp,
1520: &m);
1521: if (retval) {
1522: if (retval == EJUSTRETURN)
1523: return 0;
1524: else {
1525: m_freem(m);
1526: return retval;
1527: }
1528: }
1529:
1530: }
1531:
1532: if (ifp != orig_ifp)
1533: break;
1534: }
1535: }
1536: }
1537:
1538: /*
1539: * Finally, call the driver.
1540: */
1541: /*
1542: * Temporary, until all drivers do this.
1543: */
1544:
1545: ifp->if_obytes += m->m_pkthdr.len;
1546:
1547: retval = (*ifp->if_output)(ifp, m);
1548: dlil_stats.inject_pr_out2++;
1549: if ((retval == 0) || (retval == EJUSTRETURN))
1550: return 0;
1551: else
1552: return retval;
1553: }
1554:
1555:
1556: int
1557: dlil_inject_if_output(struct mbuf *m, u_long from_id)
1558: {
1559: struct ifnet *orig_ifp = 0;
1560: struct ifnet *ifp;
1561: struct dlil_filterq_entry *tmp;
1562: int retval = 0;
1563: struct dlil_filterq_head *fhead;
1564: int match_found;
1565:
1566:
1567: dlil_stats.inject_if_out1++;
1568: if (from_id > MAX_DLIL_FILTERS)
1569: return ERANGE;
1570:
1571: if (dlil_filters[from_id].type != DLIL_IF_FILTER)
1572: return ENOENT;
1573:
1574: ifp = dlil_filters[from_id].ifp;
1575:
1576: /*
1577: * Let interface filters (if any) do their thing ...
1578: */
1579:
1580: fhead = (struct dlil_filterq_head *) &ifp->if_flt_head;
1581:
1582: if (from_id == DLIL_NULL_FILTER)
1583: match_found = 1;
1584: else
1585: match_found = 0;
1586:
1587: if (TAILQ_EMPTY(fhead) == 0) {
1588: while (orig_ifp != ifp) {
1589: orig_ifp = ifp;
1590: TAILQ_FOREACH(tmp, fhead, que) {
1591: if ((match_found) && (IFILT(tmp).filter_if_output)) {
1592: retval = (*IFILT(tmp).filter_if_output)(IFILT(tmp).cookie,
1593: &ifp,
1594: &m);
1595: if (retval) {
1596: if (retval == EJUSTRETURN)
1597: return 0;
1598: else {
1599: m_freem(m);
1600: return retval;
1601: }
1602: }
1603:
1604: }
1605:
1606: if (ifp != orig_ifp)
1607: break;
1608:
1609: if (from_id == tmp->filter_id)
1610: match_found = 1;
1611: }
1612: }
1613: }
1614:
1615: /*
1616: * Finally, call the driver.
1617: */
1618: /*
1619: * Temporary, until all drivers do this.
1620: */
1621:
1622: ifp->if_obytes += m->m_pkthdr.len;
1623:
1624: retval = (*ifp->if_output)(ifp, m);
1625: dlil_stats.inject_if_out2++;
1626: if ((retval == 0) || (retval == EJUSTRETURN))
1627: return 0;
1628: else
1629: return retval;
1630: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.