|
|
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) 1998 Luigi Rizzo
24: *
25: * Redistribution and use in source and binary forms, with or without
26: * modification, are permitted provided that the following conditions
27: * are met:
28: * 1. Redistributions of source code must retain the above copyright
29: * notice, this list of conditions and the following disclaimer.
30: * 2. Redistributions in binary form must reproduce the above copyright
31: * notice, this list of conditions and the following disclaimer in the
32: * documentation and/or other materials provided with the distribution.
33: *
34: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
35: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: * SUCH DAMAGE.
45: *
46: */
47:
48: /*
49: * This code implements bridging in FreeBSD. It only acts on ethernet
50: * type of interfaces (others are still usable for routing).
51: * A bridging table holds the source MAC address/dest. interface for each
52: * known node. The table is indexed using an hash of the source address.
53: *
54: * Input packets are tapped near the end of the input routine in each
55: * driver (near the call to bpf_mtap, or before the call to ether_input)
56: * and analysed calling bridge_in(). Depending on the result, the packet
57: * can be forwarded to one or more output interfaces using bdg_forward(),
58: * and/or sent to the upper layer (e.g. in case of multicast).
59: *
60: * Output packets are intercepted near the end of ether_output(),
61: * the correct destination is selected calling bdg_dst_lookup(),
62: * and then forwarding is done using bdg_forward().
63: * Bridging is controlled by the sysctl variable net.link.ether.bridge
64: *
65: * The arp code is also modified to let a machine answer to requests
66: * irrespective of the port the request came from.
67: *
68: * In case of loops in the bridging topology, the bridge detects this
69: * event and temporarily mutes output bridging on one of the ports.
70: * Periodically, interfaces are unmuted by bdg_timeout(). (For the
71: * mute flag i am temporarily using IFF_LINK2 but this has to
72: * change.) Muting is only implemented as a safety measure, and also as
73: * a mechanism to support a user-space implementation of the spanning
74: * tree algorithm. In the final release, unmuting will only occur
75: * because of explicit action of the user-level daemon.
76: *
77: * To build a bridging kernel, use the following option
78: * option BRIDGE
79: * and then at runtime set the sysctl variable to enable bridging.
80: *
81: * Only one interface is supposed to have addresses set (but
82: * there are no problems in practice if you set addresses for more
83: * than one interface).
84: * Bridging will act before routing, but nothing prevents a machine
85: * from doing both (modulo bugs in the implementation...).
86: *
87: * THINGS TO REMEMBER
88: * - bridging requires some (small) modifications to the interface
89: * driver. Currently (980911) the "ed", "de", "tx", "lnc" drivers
90: * have been modified and tested. "fxp", "ep", "fe" have been
91: * modified but not tested. See the "ed" and "de" drivers as
92: * examples on how to operate.
93: * - bridging is incompatible with multicast routing on the same
94: * machine. There is not an easy fix to this.
95: * - loop detection is still not very robust.
96: * - the interface of bdg_forward() could be improved.
97: */
98:
99: #include <sys/param.h>
100: #include <sys/mbuf.h>
101: #include <sys/malloc.h>
102: #include <sys/systm.h>
103: #include <sys/socket.h> /* for net/if.h */
104: #include <sys/kernel.h>
105: #include <sys/sysctl.h>
106:
107: #include <net/if.h>
108: #include <net/if_types.h>
109:
110: #include <netinet/in.h> /* for struct arpcom */
111: #include <netinet/in_systm.h>
112: #include <netinet/in_var.h>
113: #include <netinet/ip.h>
114: #include <netinet/if_ether.h> /* for struct arpcom */
115:
116: #include "opt_ipfw.h"
117: #include "opt_ipdn.h"
118:
119: #if defined(IPFIREWALL) && defined(DUMMYNET)
120: #include <net/route.h>
121: #include <netinet/ip_fw.h>
122: #include <netinet/ip_dummynet.h>
123: #endif
124:
125: #include <net/bridge.h>
126:
127: /*
128: * For debugging, you can use the following macros.
129: * remember, rdtsc() only works on Pentium-class machines
130:
131: quad_t ticks;
132: DDB(ticks = rdtsc();)
133: ... interesting code ...
134: DDB(bdg_fw_ticks += (u_long)(rdtsc() - ticks) ; bdg_fw_count++ ;)
135:
136: *
137: */
138:
139: #define DDB(x) x
140: #define DEB(x)
141:
142: /*
143: * System initialization
144: */
145:
146: static void bdginit(void *);
147: static void flush_table(void);
148:
149: SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, bdginit, NULL)
150:
151: static int bdg_ipfw = 0 ;
152: int do_bridge = 0;
153: bdg_hash_table *bdg_table = NULL ;
154:
155: /*
156: * we need additional info for the bridge. The bdg_ifp2sc[] array
157: * provides a pointer to this struct using the if_index.
158: * bdg_softc has a backpointer to the struct ifnet, the bridge
159: * flags, and a group (bridging occurs only between port of the
160: * same group).
161: */
162: struct bdg_softc {
163: struct ifnet *ifp ;
164: /* ((struct arpcom *)ifp)->ac_enaddr is the eth. addr */
165: int flags ;
166: int group ;
167: } ;
168:
169: static struct bdg_softc **ifp2sc = NULL ;
170:
171: #if 0 /* new code using ifp2sc */
172: #define SAMEGROUP(ifp,src) (src == NULL || \
173: ifp2sc[ifp->if_index]->group == ifp2sc[src->if_index]->group )
174: #define MUTED(ifp) (ifp2sc[ifp->if_index]->flags & IFF_MUTE)
175: #define MUTE(ifp) ifp2sc[ifp->if_index]->flags |= IFF_MUTE
176: #define UNMUTE(ifp) ifp2sc[ifp->if_index]->flags &= ~IFF_MUTE
177: #else
178: #define SAMEGROUP(a,b) 1
179: #define MUTED(ifp) (ifp->if_flags & IFF_MUTE)
180: #define MUTE(ifp) ifp->if_flags |= IFF_MUTE
181: #define UNMUTE(ifp) ifp->if_flags &= ~IFF_MUTE
182: #endif
183:
184: static int
185: sysctl_bdg SYSCTL_HANDLER_ARGS
186: {
187: int error, oldval = do_bridge ;
188:
189: error = sysctl_handle_int(oidp,
190: oidp->oid_arg1, oidp->oid_arg2, req);
191: printf("called sysctl for bridge name %s arg2 %d val %d->%d\n",
192: oidp->oid_name, oidp->oid_arg2,
193: oldval, do_bridge);
194: if (bdg_table == NULL)
195: do_bridge = 0 ;
196: if (oldval != do_bridge) {
197: flush_table();
198: }
199: return error ;
200: }
201:
202: SYSCTL_DECL(_net_link_ether);
203: SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge, CTLTYPE_INT|CTLFLAG_RW,
204: &do_bridge, 0, &sysctl_bdg, "I", "Bridging");
205:
206: SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW, &bdg_ipfw,0,"");
207: #if 1 /* diagnostic vars */
208: int bdg_in_count = 0 , bdg_in_ticks = 0 , bdg_fw_count = 0, bdg_fw_ticks = 0 ;
209: SYSCTL_INT(_net_link_ether, OID_AUTO, bdginc, CTLFLAG_RW, &bdg_in_count,0,"");
210: SYSCTL_INT(_net_link_ether, OID_AUTO, bdgint, CTLFLAG_RW, &bdg_in_ticks,0,"");
211: SYSCTL_INT(_net_link_ether, OID_AUTO, bdgfwc, CTLFLAG_RW, &bdg_fw_count,0,"");
212: SYSCTL_INT(_net_link_ether, OID_AUTO, bdgfwt, CTLFLAG_RW, &bdg_fw_ticks,0,"");
213: #endif
214: static struct bdg_stats bdg_stats ;
215: SYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats,
216: CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics");
217:
218: static int bdg_loops ;
219:
220: /*
221: * completely flush the bridge table.
222: */
223: static void
224: flush_table()
225: {
226: int s,i;
227:
228: if (bdg_table == NULL)
229: return ;
230: s = splimp();
231: for (i=0; i< HASH_SIZE; i++)
232: bdg_table[i].name= NULL; /* clear table */
233: splx(s);
234: }
235:
236: /*
237: * called periodically to flush entries etc.
238: */
239: static void
240: bdg_timeout(void *dummy)
241: {
242: struct ifnet *ifp ;
243: int s ;
244: static int slowtimer = 0 ;
245:
246: if (do_bridge) {
247: static int age_index = 0 ; /* index of table position to age */
248: int l = age_index + HASH_SIZE/4 ;
249: /*
250: * age entries in the forwarding table.
251: */
252: if (l > HASH_SIZE)
253: l = HASH_SIZE ;
254: for (; age_index < l ; age_index++)
255: if (bdg_table[age_index].used)
256: bdg_table[age_index].used = 0 ;
257: else if (bdg_table[age_index].name) {
258: /* printf("xx flushing stale entry %d\n", age_index); */
259: bdg_table[age_index].name = NULL ;
260: }
261: if (age_index >= HASH_SIZE)
262: age_index = 0 ;
263:
264: if (--slowtimer <= 0 ) {
265: slowtimer = 5 ;
266:
267: for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
268: if (ifp->if_type != IFT_ETHER)
269: continue ;
270: if ( 0 == ( ifp->if_flags & IFF_UP) ) {
271: s = splimp();
272: if_up(ifp);
273: splx(s);
274: }
275: if ( 0 == ( ifp->if_flags & IFF_PROMISC) ) {
276: int ret ;
277: s = splimp();
278: ret = ifpromisc(ifp, 1);
279: splx(s);
280: printf(">> now %s%d flags 0x%x promisc %d\n",
281: ifp->if_name, ifp->if_unit,
282: ifp->if_flags, ret);
283: }
284: if (MUTED(ifp)) {
285: printf(">> unmuting %s%d\n", ifp->if_name, ifp->if_unit);
286: UNMUTE(ifp) ;
287: }
288: }
289: bdg_loops = 0 ;
290: }
291: }
292: timeout(bdg_timeout, (void *)0, 2*hz );
293: }
294:
295: /*
296: * local MAC addresses are held in a small array. This makes comparisons
297: * much faster.
298: */
299: unsigned char bdg_addresses[6*BDG_MAX_PORTS];
300: int bdg_ports ;
301:
302: /*
303: * initialization of bridge code.
304: */
305: static void
306: bdginit(dummy)
307: void *dummy;
308: {
309: int i ;
310: struct ifnet *ifp;
311: struct arpcom *ac ;
312: u_char *eth_addr ;
313: /*
314: * initialization of bridge code
315: */
316: if (bdg_table == NULL)
317: bdg_table = (struct hash_table *)
318: _MALLOC(HASH_SIZE * sizeof(struct hash_table),
319: M_IFADDR, M_WAITOK);
320: flush_table();
321:
322: ifp2sc = _MALLOC(if_index * sizeof(struct bdg_softc *), M_IFADDR, M_WAITOK );
323: bzero(ifp2sc, if_index * sizeof(struct bdg_softc *) );
324:
325: bzero(&bdg_stats, sizeof(bdg_stats) );
326: bdg_ports = 0 ;
327: eth_addr = bdg_addresses ;
328:
329: printf("BRIDGE 981214, have %d interfaces\n", if_index);
330: for (i = 0 , ifp = ifnet.tqh_first ; i < if_index ;
331: i++, ifp = ifp->if_link.tqe_next)
332: if (ifp->if_type == IFT_ETHER) { /* ethernet ? */
333: ac = (struct arpcom *)ifp;
334: sprintf(bdg_stats.s[ifp->if_index].name,
335: "%s%d", ifp->if_name, ifp->if_unit);
336: printf("-- index %d %s type %d phy %d addrl %d addr %6D\n",
337: ifp->if_index,
338: bdg_stats.s[ifp->if_index].name,
339: (int)ifp->if_type, (int) ifp->if_physical,
340: (int)ifp->if_addrlen,
341: ac->ac_enaddr, "." );
342: bcopy(ac->ac_enaddr, eth_addr, 6);
343: eth_addr += 6 ;
344:
345: ifp2sc[bdg_ports] = _MALLOC(sizeof(struct bdg_softc),
346: M_IFADDR, M_WAITOK );
347: ifp2sc[bdg_ports]->ifp = ifp ;
348: ifp2sc[bdg_ports]->flags = 0 ;
349: ifp2sc[bdg_ports]->group = 0 ;
350: bdg_ports ++ ;
351: }
352: bdg_timeout(0);
353: do_bridge=0;
354: }
355:
356: /*
357: * bridge_in() is invoked to perform bridging decision on input packets.
358: * On Input:
359: * m packet to be bridged. The mbuf need not to hold the
360: * whole packet, only the first 14 bytes suffice. We
361: * assume them to be contiguous. No alignment assumptions
362: * because they are not a problem on i386 class machines.
363: *
364: * On Return: destination of packet, one of
365: * BDG_BCAST broadcast
366: * BDG_MCAST multicast
367: * BDG_LOCAL is only for a local address (do not forward)
368: * BDG_DROP drop the packet
369: * ifp ifp of the destination interface.
370: *
371: * Forwarding is not done directly to give a chance to some drivers
372: * to fetch more of the packet, or simply drop it completely.
373: */
374:
375:
376: struct ifnet *
377: bridge_in(struct mbuf *m)
378: {
379: int index;
380: struct ifnet *ifp = m->m_pkthdr.rcvif, *dst , *old ;
381: int dropit = MUTED(ifp) ;
382: struct ether_header *eh;
383:
384: eh = mtod(m, struct ether_header *);
385:
386: /*
387: * hash the source address
388: */
389: index= HASH_FN(eh->ether_shost);
390: bdg_table[index].used = 1 ;
391: old = bdg_table[index].name ;
392: if ( old ) { /* the entry is valid. */
393: if (!BDG_MATCH( eh->ether_shost, bdg_table[index].etheraddr) ) {
394: printf("collision at %d\n", index);
395: bdg_table[index].name = NULL ;
396: } else if (old != ifp) {
397: /*
398: * found a loop. Either a machine has moved, or there
399: * is a misconfiguration/reconfiguration of the network.
400: * First, do not forward this packet!
401: * Record the relocation anyways; then, if loops persist,
402: * suspect a reconfiguration and disable forwarding
403: * from the old interface.
404: */
405: bdg_table[index].name = ifp ; /* relocate address */
406: printf("-- loop (%d) %6D to %s%d from %s%d (%s)\n",
407: bdg_loops, eh->ether_shost, ".",
408: ifp->if_name, ifp->if_unit,
409: old->if_name, old->if_unit,
410: old->if_flags & IFF_MUTE ? "muted":"ignore");
411: dropit = 1 ;
412: if ( !MUTED(old) ) {
413: if (++bdg_loops > 10)
414: MUTE(old) ;
415: }
416: }
417: }
418:
419: /*
420: * now write the source address into the table
421: */
422: if (bdg_table[index].name == NULL) {
423: DEB(printf("new addr %6D at %d for %s%d\n",
424: eh->ether_shost, ".", index, ifp->if_name, ifp->if_unit);)
425: bcopy(eh->ether_shost, bdg_table[index].etheraddr, 6);
426: bdg_table[index].name = ifp ;
427: }
428: dst = bridge_dst_lookup(m);
429: /* Return values:
430: * BDG_BCAST, BDG_MCAST, BDG_LOCAL, BDG_UNKNOWN, BDG_DROP, ifp.
431: * For muted interfaces, the first 3 are changed in BDG_LOCAL,
432: * and others to BDG_DROP. Also, for incoming packets, ifp is changed
433: * to BDG_DROP in case ifp == src . These mods are not necessary
434: * for outgoing packets from ether_output().
435: */
436: BDG_STAT(ifp, BDG_IN);
437: switch ((int)dst) {
438: case (int)BDG_BCAST:
439: case (int)BDG_MCAST:
440: case (int)BDG_LOCAL:
441: case (int)BDG_UNKNOWN:
442: case (int)BDG_DROP:
443: BDG_STAT(ifp, dst);
444: break ;
445: default :
446: if (dst == ifp || dropit )
447: BDG_STAT(ifp, BDG_DROP);
448: else
449: BDG_STAT(ifp, BDG_FORWARD);
450: break ;
451: }
452:
453: if ( dropit ) {
454: if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_LOCAL)
455: return BDG_LOCAL ;
456: else
457: return BDG_DROP ;
458: } else {
459: return (dst == ifp ? BDG_DROP : dst ) ;
460: }
461: }
462:
463: /*
464: * Forward to dst, excluding src port and (if not a single interface)
465: * muted interfaces. The packet is freed if marked as such
466: * and not for a local destination.
467: * A cleaner implementation would be to make bdg_forward()
468: * always consume the packet, leaving to the caller the task
469: * to make a copy if it needs it. As it is now, bdg_forward()
470: * can keep a copy alive in some cases.
471: */
472: int
473: bdg_forward (struct mbuf **m0, struct ifnet *dst)
474: {
475: struct ifnet *src = (*m0)->m_pkthdr.rcvif; /* could be NULL in output */
476: struct ifnet *ifp ;
477: struct ip *ip;
478: int error=0, s ;
479: int once = 0; /* execute the loop only once */
480: int canfree = 1 ; /* can free the buf at the end */
481: struct mbuf *m ;
482:
483: struct ether_header *eh = mtod(*m0, struct ether_header *); /* XXX */
484:
485: if (dst == BDG_DROP) { /* this should not happen */
486: printf("xx bdg_forward for BDG_DROP)\n");
487: m_freem(*m0) ;
488: *m0 = NULL ;
489: return 0;
490: }
491: if (dst == BDG_LOCAL) { /* this should not happen as well */
492: printf("xx ouch, bdg_forward for local pkt\n");
493: return 0;
494: }
495: if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_UNKNOWN) {
496: ifp = ifnet.tqh_first ;
497: once = 0 ;
498: if (dst != BDG_UNKNOWN)
499: canfree = 0 ;
500: } else {
501: ifp = dst ;
502: once = 1 ; /* and also canfree */
503: }
504: #if IPFIREWALL
505: /*
506: * do filtering in a very similar way to what is done
507: * in ip_output. Only for IP packets, and only pass/fail/dummynet
508: * is supported. The tricky thing is to make sure that enough of
509: * the packet (basically, Eth+IP+TCP/UDP headers) is contiguous
510: * so that calls to m_pullup in ip_fw_chk will not kill the
511: * ethernet header.
512: */
513: if (ip_fw_chk_ptr) {
514: u_int16_t dummy ;
515: struct ip_fw_chain *rule;
516: int off;
517:
518: m = *m0 ;
519: if (m->m_type == MT_DUMMYNET) {
520: /*
521: * the packet was already tagged, so part of the
522: * processing was already done, and we need to go down.
523: */
524: rule = (struct ip_fw_chain *)(m->m_data) ;
525: (*m0) = m = m->m_next ;
526:
527: src = m->m_pkthdr.rcvif; /* could be NULL in output */
528: eh = mtod(m, struct ether_header *); /* XXX */
529: canfree = 1 ; /* for sure, a copy is not needed later. */
530: goto forward; /* HACK! */
531: } else
532: rule = NULL ;
533: if (bdg_ipfw == 0)
534: goto forward ;
535: if (src == NULL)
536: goto forward ; /* do not apply to packets from ether_output */
537: if (canfree == 0 ) /* need to make a copy */
538: m = m_copypacket(*m0, M_DONTWAIT);
539: if (m == NULL) {
540: /* fail... */
541: return 0 ;
542: }
543:
544: dummy = 0 ;
545: /*
546: * before calling the firewall, swap fields the same as IP does.
547: * here we assume the pkt is an IP one and the header is contiguous
548: */
549: eh = mtod(m, struct ether_header *);
550: ip = (struct ip *)(eh + 1 ) ;
551: NTOHS(ip->ip_len);
552: NTOHS(ip->ip_id);
553: NTOHS(ip->ip_off);
554:
555: /*
556: * The third parameter to the firewall code is the dst. interface.
557: * Since we apply checks only on input pkts we use NULL.
558: */
559: off = (*ip_fw_chk_ptr)(NULL, 0, NULL, &dummy, &m, &rule, NULL) ;
560: if (m == NULL) { /* pkt discarded by firewall */
561: if (canfree)
562: *m0 = NULL ;
563: return 0 ;
564: }
565: /*
566: * on return, the mbuf pointer might have changed. Restore
567: * *m0 (if it was the same as m), eh, ip and then
568: * restore original ordering.
569: */
570: eh = mtod(m, struct ether_header *);
571: ip = (struct ip *)(eh + 1 ) ;
572: if (canfree) /* m was a reference to *m0, so update *m0 */
573: *m0 = m ;
574: HTONS(ip->ip_len);
575: HTONS(ip->ip_id);
576: HTONS(ip->ip_off);
577: if (off == 0) {
578: if (canfree == 0)
579: m_freem(m);
580: goto forward ;
581: }
582: #if DUMMYNET
583: if (off & 0x10000) {
584: /*
585: * pass the pkt to dummynet. Need to include m, dst, rule.
586: * Dummynet consumes the packet in all cases.
587: */
588: dummynet_io((off & 0xffff), DN_TO_BDG_FWD, m, dst, NULL, 0, rule);
589: if (canfree) /* dummynet has consumed the original one */
590: *m0 = NULL ;
591: return 0 ;
592: }
593: #endif
594: /* if none of the above matches, we have to drop the pkt */
595: if (m)
596: m_freem(m);
597: if (canfree && m != *m0) {
598: m_freem(*m0);
599: *m0 = NULL ;
600: }
601: return 0 ;
602: }
603: forward:
604: #endif /* COMPAT_IPFW */
605: if (canfree && once)
606: m = *m0 ;
607: else
608: m = NULL ;
609:
610: for ( ; ifp ; ifp = ifp->if_link.tqe_next ) {
611: if (ifp != src && ifp->if_type == IFT_ETHER &&
612: (ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) &&
613: SAMEGROUP(ifp, src) && !MUTED(ifp) ) {
614: if (m == NULL) { /* do i need to make a copy ? */
615: if (canfree && ifp->if_link.tqe_next == NULL) /* last one! */
616: m = *m0 ;
617: else /* on a P5-90, m_packetcopy takes 540 ticks */
618: m = m_copypacket(*m0, M_DONTWAIT);
619: if (m == NULL) {
620: printf("bdg_forward: sorry, m_copy failed!\n");
621: return ENOBUFS ;
622: }
623: }
624: /*
625: * execute last part of ether_output.
626: */
627: s = splimp();
628: /*
629: * Queue message on interface, and start output if interface
630: * not yet active.
631: */
632: if (IF_QFULL(&ifp->if_snd)) {
633: IF_DROP(&ifp->if_snd);
634: MUTE(ifp); /* good measure... */
635: splx(s);
636: error = ENOBUFS ;
637: } else {
638: ifp->if_obytes += m->m_pkthdr.len ;
639: if (m->m_flags & M_MCAST)
640: ifp->if_omcasts++;
641: IF_ENQUEUE(&ifp->if_snd, m);
642: if ((ifp->if_flags & IFF_OACTIVE) == 0)
643: (*ifp->if_start)(ifp);
644: splx(s);
645: if (m == *m0)
646: *m0 = NULL ; /* the packet is gone... */
647: m = NULL ;
648: }
649: BDG_STAT(ifp, BDG_OUT);
650: }
651: if (once)
652: break ;
653: }
654:
655: /* cleanup any mbuf leftover. */
656: if (m)
657: m_freem(m);
658: if (m == *m0)
659: *m0 = NULL ;
660: if (canfree && *m0) {
661: m_freem(*m0);
662: *m0 = NULL ;
663: }
664: return error ;
665: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.