]>
git.saurik.com Git - apple/xnu.git/blob - bsd/net/bridge.c
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1998 Luigi Rizzo
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
40 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * $FreeBSD: src/sys/net/bridge.c,v 1.16.2.14 2001/02/09 23:13:41 luigi Exp $
56 * This code implements bridging in FreeBSD. It only acts on ethernet
57 * type of interfaces (others are still usable for routing).
58 * A bridging table holds the source MAC address/dest. interface for each
59 * known node. The table is indexed using an hash of the source address.
61 * Input packets are tapped near the beginning of ether_input(), and
62 * analysed by calling bridge_in(). Depending on the result, the packet
63 * can be forwarded to one or more output interfaces using bdg_forward(),
64 * and/or sent to the upper layer (e.g. in case of multicast).
66 * Output packets are intercepted near the end of ether_output(),
67 * the correct destination is selected calling bridge_dst_lookup(),
68 * and then forwarding is done using bdg_forward().
69 * Bridging is controlled by the sysctl variable net.link.ether.bridge
71 * The arp code is also modified to let a machine answer to requests
72 * irrespective of the port the request came from.
74 * In case of loops in the bridging topology, the bridge detects this
75 * event and temporarily mutes output bridging on one of the ports.
76 * Periodically, interfaces are unmuted by bdg_timeout().
77 * Muting is only implemented as a safety measure, and also as
78 * a mechanism to support a user-space implementation of the spanning
79 * tree algorithm. In the final release, unmuting will only occur
80 * because of explicit action of the user-level daemon.
82 * To build a bridging kernel, use the following option
84 * and then at runtime set the sysctl variable to enable bridging.
86 * Only one interface is supposed to have addresses set (but
87 * there are no problems in practice if you set addresses for more
88 * than one interface).
89 * Bridging will act before routing, but nothing prevents a machine
90 * from doing both (modulo bugs in the implementation...).
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.
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>
108 #include <net/if_types.h>
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 */
116 #include "opt_ipfw.h"
117 #include "opt_ipdn.h"
119 #if defined(IPFIREWALL)
120 #include <net/route.h>
121 #include <netinet/ip_fw.h>
122 #if defined(DUMMYNET)
123 #include <netinet/ip_dummynet.h>
127 #include <net/bridge.h>
130 * For debugging, you can use the following macros.
131 * remember, rdtsc() only works on Pentium-class machines
134 DDB(ticks = rdtsc();)
135 ... interesting code ...
136 DDB(bdg_fw_ticks += (u_int32_t)(rdtsc() - ticks) ; bdg_fw_count++ ;)
144 static void bdginit(void *);
145 static void bdgtakeifaces(void);
146 static void flush_table(void);
147 static void bdg_promisc_on(void);
148 static void parse_bdg_cfg(void);
150 static int bdg_ipfw
= 0 ;
152 bdg_hash_table
*bdg_table
= NULL
;
155 * System initialization
158 SYSINIT(interfaces
, SI_SUB_PROTO_IF
, SI_ORDER_FIRST
, bdginit
, NULL
)
160 static struct bdg_stats bdg_stats
;
161 struct bdg_softc
*ifp2sc
= NULL
;
162 /* XXX make it static of size BDG_MAX_PORTS */
164 #define IFP_CHK(ifp, x) \
165 if (ifp2sc[ifp->if_index].magic != 0xDEADBEEF) { x ; }
168 * turn off promisc mode, optionally clear the IFF_USED flag.
169 * The flag is turned on by parse_bdg_config
172 bdg_promisc_off(int clear_used
)
175 ifnet_head_lock_shared();
176 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
177 if ( (ifp2sc
[ifp
->if_index
].flags
& IFF_BDG_PROMISC
) ) {
180 ret
= ifnet_set_promiscuous(ifp
, 0);
182 ifp2sc
[ifp
->if_index
].flags
&= ~(IFF_BDG_PROMISC
|IFF_MUTE
) ;
183 DEB(printf(">> now %s%d promisc OFF if_flags 0x%x bdg_flags 0x%x\n",
184 ifp
->if_name
, ifp
->if_unit
,
185 ifp
->if_flags
, ifp2sc
[ifp
->if_index
].flags
);)
188 ifp2sc
[ifp
->if_index
].flags
&= ~(IFF_USED
) ;
189 bdg_stats
.s
[ifp
->if_index
].name
[0] = '\0';
196 * set promisc mode on the interfaces we use.
204 ifnet_head_lock_shared();
205 TAILQ_FOREACH(ifp
, &ifnet_head
, if_link
) {
206 if ( !BDG_USED(ifp
) )
208 if ( 0 == ( ifp
->if_flags
& IFF_UP
) ) {
213 if ( !(ifp2sc
[ifp
->if_index
].flags
& IFF_BDG_PROMISC
) ) {
216 ret
= ifnet_set_promiscuous(ifp
, 1);
218 ifp2sc
[ifp
->if_index
].flags
|= IFF_BDG_PROMISC
;
219 printf(">> now %s%d promisc ON if_flags 0x%x bdg_flags 0x%x\n",
220 ifp
->if_name
, ifp
->if_unit
,
221 ifp
->if_flags
, ifp2sc
[ifp
->if_index
].flags
);
223 if (BDG_MUTED(ifp
)) {
224 printf(">> unmuting %s%d\n", ifp
->if_name
, ifp
->if_unit
);
232 sysctl_bdg(SYSCTL_HANDLER_ARGS
)
234 int error
, oldval
= do_bridge
;
236 error
= sysctl_handle_int(oidp
,
237 oidp
->oid_arg1
, oidp
->oid_arg2
, req
);
238 DEB( printf("called sysctl for bridge name %s arg2 %d val %d->%d\n",
239 oidp
->oid_name
, oidp
->oid_arg2
,
240 oldval
, do_bridge
); )
242 if (bdg_table
== NULL
)
244 if (oldval
!= do_bridge
) {
245 bdg_promisc_off( 1 ); /* reset previously used interfaces */
255 static char bridge_cfg
[256] = { "" } ;
258 * parse the config string, set IFF_USED, name and cluster_id
259 * for all interfaces found.
268 for (p
= bridge_cfg
; *p
; p
++) {
269 /* interface names begin with [a-z] and continue up to ':' */
270 if (*p
< 'a' || *p
> 'z')
272 for ( beg
= p
; *p
&& *p
!= ':' ; p
++ )
274 if (*p
== 0) /* end of string, ':' not found */
276 l
= p
- beg
; /* length of name string */
278 DEB(printf("-- match beg(%d) <%s> p <%s>\n", l
, beg
, p
);)
279 for (cluster
= 0 ; *p
&& *p
>= '0' && *p
<= '9' ; p
++)
280 cluster
= cluster
*10 + (*p
-'0');
282 * now search in bridge strings
284 for (i
=0, b
= ifp2sc
; i
< if_index
; i
++, b
++) {
286 struct ifnet
*ifp
= b
->ifp
;
290 sprintf(buf
, "%s%d", ifp
->if_name
, ifp
->if_unit
);
291 if (!strncmp(beg
, buf
, l
)) { /* XXX not correct for >10 if! */
292 b
->cluster_id
= htons(cluster
) ;
293 b
->flags
|= IFF_USED
;
294 sprintf(bdg_stats
.s
[ifp
->if_index
].name
,
295 "%s%d:%d", ifp
->if_name
, ifp
->if_unit
, cluster
);
297 DEB(printf("--++ found %s\n",
298 bdg_stats
.s
[ifp
->if_index
].name
);)
308 sysctl_bdg_cfg(SYSCTL_HANDLER_ARGS
)
313 strlcpy(oldval
, bridge_cfg
, sizeof (oldval
));
315 error
= sysctl_handle_string(oidp
,
316 bridge_cfg
, oidp
->oid_arg2
, req
);
318 printf("called sysctl for bridge name %s arg2 %d err %d val %s->%s\n",
319 oidp
->oid_name
, oidp
->oid_arg2
,
323 if (strcmp(oldval
, bridge_cfg
)) {
324 bdg_promisc_off( 1 ); /* reset previously-used interfaces */
326 parse_bdg_cfg(); /* and set new ones... */
328 bdg_promisc_on(); /* re-enable interfaces */
334 sysctl_refresh(SYSCTL_HANDLER_ARGS
)
343 SYSCTL_DECL(_net_link_ether
);
344 SYSCTL_PROC(_net_link_ether
, OID_AUTO
, bridge_cfg
, CTLTYPE_STRING
|CTLFLAG_RW
,
345 &bridge_cfg
, sizeof(bridge_cfg
), &sysctl_bdg_cfg
, "A",
346 "Bridge configuration");
348 SYSCTL_PROC(_net_link_ether
, OID_AUTO
, bridge
, CTLTYPE_INT
|CTLFLAG_RW
,
349 &do_bridge
, 0, &sysctl_bdg
, "I", "Bridging");
351 SYSCTL_INT(_net_link_ether
, OID_AUTO
, bridge_ipfw
, CTLFLAG_RW
,
352 &bdg_ipfw
,0,"Pass bridged pkts through firewall");
354 #define SY(parent, var, comment) \
356 SYSCTL_INT(parent, OID_AUTO, var, CTLFLAG_RW, &(var), 0, comment);
359 SYSCTL_INT(_net_link_ether
, OID_AUTO
, bridge_ipfw_drop
,
360 CTLFLAG_RW
, &bdg_ipfw_drops
,0,"");
363 SYSCTL_INT(_net_link_ether
, OID_AUTO
, bridge_ipfw_collisions
,
364 CTLFLAG_RW
, &bdg_ipfw_colls
,0,"");
366 SYSCTL_PROC(_net_link_ether
, OID_AUTO
, bridge_refresh
, CTLTYPE_INT
|CTLFLAG_WR
,
367 NULL
, 0, &sysctl_refresh
, "I", "iface refresh");
369 #if 1 /* diagnostic vars */
371 SY(_net_link_ether
, verbose
, "Be verbose");
372 SY(_net_link_ether
, bdg_split_pkts
, "Packets split in bdg_forward");
374 SY(_net_link_ether
, bdg_thru
, "Packets through bridge");
376 SY(_net_link_ether
, bdg_copied
, "Packets copied in bdg_forward");
378 SY(_net_link_ether
, bdg_copy
, "Force copy in bdg_forward");
379 SY(_net_link_ether
, bdg_predict
, "Correctly predicted header location");
381 SY(_net_link_ether
, bdg_fw_avg
, "Cycle counter avg");
382 SY(_net_link_ether
, bdg_fw_ticks
, "Cycle counter item");
383 SY(_net_link_ether
, bdg_fw_count
, "Cycle counter count");
386 SYSCTL_STRUCT(_net_link_ether
, PF_BDG
, bdgstats
,
387 CTLFLAG_RD
, &bdg_stats
, bdg_stats
, "bridge statistics");
389 static int bdg_loops
;
392 * completely flush the bridge table.
399 if (bdg_table
== NULL
)
402 for (i
=0; i
< HASH_SIZE
; i
++)
403 bdg_table
[i
].name
= NULL
; /* clear table */
408 * called periodically to flush entries etc.
411 bdg_timeout(void *dummy
)
413 static int slowtimer
= 0 ;
415 if (bdg_inted
== 0) {
417 } else if (do_bridge
) {
418 static int age_index
= 0 ; /* index of table position to age */
419 int l
= age_index
+ HASH_SIZE
/4 ;
421 * age entries in the forwarding table.
425 for (; age_index
< l
; age_index
++)
426 if (bdg_table
[age_index
].used
)
427 bdg_table
[age_index
].used
= 0 ;
428 else if (bdg_table
[age_index
].name
) {
429 /* printf("xx flushing stale entry %d\n", age_index); */
430 bdg_table
[age_index
].name
= NULL
;
432 if (age_index
>= HASH_SIZE
)
435 if (--slowtimer
<= 0 ) {
438 bdg_promisc_on() ; /* we just need unmute, really */
442 timeout(bdg_timeout
, (void *)0, 2*hz
);
446 * local MAC addresses are held in a small array. This makes comparisons
449 bdg_addr bdg_addresses
[BDG_MAX_PORTS
];
453 * initialization of bridge code. This needs to be done after all
454 * interfaces have been configured.
457 static int bdg_inited
= 0;
465 if (bdg_table
== NULL
) {
466 bdg_table
= (struct hash_table
*)
467 _MALLOC(HASH_SIZE
* sizeof(struct hash_table
),
469 if (bdg_table
== NULL
)
475 if (ifp2sc
== NULL
) {
476 ifp2sc
= _MALLOC(BDG_MAX_PORTS
* sizeof(struct bdg_softc
),
477 M_IFADDR
, M_WAITOK
);
481 bzero(ifp2sc
, BDG_MAX_PORTS
* sizeof(struct bdg_softc
) );
491 /* Initialize first what can't fail */
492 bzero(&bdg_stats
, sizeof(bdg_stats
) );
495 /* Attempt to initialize the rest and start the timer */
504 bdg_addr
*p
= bdg_addresses
;
505 struct bdg_softc
*bp
;
510 printf("BRIDGE 010131, have %d interfaces\n", if_index
);
511 ifnet_head_lock_shared();
512 for (i
= 0 , ifp
= ifnet
.tqh_first
; i
< if_index
;
513 i
++, ifp
= TAILQ_NEXT(ifp
, if_link
) )
514 if (ifp
->if_type
== IFT_ETHER
) { /* ethernet ? */
515 ifnet_lladdr_copy_bytes(ifp
, p
->etheraddr
, ETHER_ADDR_LEN
);
516 bp
= &ifp2sc
[ifp
->if_index
] ;
517 sprintf(bridge_cfg
+ strlen(bridge_cfg
),
518 "%s%d:1,", ifp
->if_name
, ifp
->if_unit
);
519 printf("-- index %d %s type %d phy %d addrl %d addr %6D\n",
521 bdg_stats
.s
[ifp
->if_index
].name
,
522 (int)ifp
->if_type
, (int) ifp
->if_physical
,
523 (int)ifp
->if_addrlen
,
527 bp
->flags
= IFF_USED
;
528 bp
->cluster_id
= htons(1) ;
529 bp
->magic
= 0xDEADBEEF ;
531 sprintf(bdg_stats
.s
[ifp
->if_index
].name
,
532 "%s%d:%d", ifp
->if_name
, ifp
->if_unit
,
533 ntohs(bp
->cluster_id
));
540 * bridge_in() is invoked to perform bridging decision on input packets.
543 * eh Ethernet header of the incoming packet.
545 * On Return: destination of packet, one of
546 * BDG_BCAST broadcast
547 * BDG_MCAST multicast
548 * BDG_LOCAL is only for a local address (do not forward)
549 * BDG_DROP drop the packet
550 * ifp ifp of the destination interface.
552 * Forwarding is not done directly to give a chance to some drivers
553 * to fetch more of the packet, or simply drop it completely.
557 bridge_in(struct ifnet
*ifp
, struct ether_header
*eh
)
560 struct ifnet
*dst
, *old
;
561 int dropit
= BDG_MUTED(ifp
) ;
564 * hash the source address
566 index
= HASH_FN(eh
->ether_shost
);
567 bdg_table
[index
].used
= 1 ;
568 old
= bdg_table
[index
].name
;
569 if ( old
) { /* the entry is valid. */
570 IFP_CHK(old
, printf("bridge_in-- reading table\n") );
572 if (!BDG_MATCH( eh
->ether_shost
, bdg_table
[index
].etheraddr
) ) {
574 bdg_table
[index
].name
= NULL
;
575 } else if (old
!= ifp
) {
577 * found a loop. Either a machine has moved, or there
578 * is a misconfiguration/reconfiguration of the network.
579 * First, do not forward this packet!
580 * Record the relocation anyways; then, if loops persist,
581 * suspect a reconfiguration and disable forwarding
582 * from the old interface.
584 bdg_table
[index
].name
= ifp
; /* relocate address */
585 printf("-- loop (%d) %6D to %s%d from %s%d (%s)\n",
586 bdg_loops
, eh
->ether_shost
, ".",
587 ifp
->if_name
, ifp
->if_unit
,
588 old
->if_name
, old
->if_unit
,
589 BDG_MUTED(old
) ? "muted":"active");
591 if ( !BDG_MUTED(old
) ) {
592 if (++bdg_loops
> 10)
599 * now write the source address into the table
601 if (bdg_table
[index
].name
== NULL
) {
602 DEB(printf("new addr %6D at %d for %s%d\n",
603 eh
->ether_shost
, ".", index
, ifp
->if_name
, ifp
->if_unit
);)
604 bcopy(eh
->ether_shost
, bdg_table
[index
].etheraddr
, 6);
605 bdg_table
[index
].name
= ifp
;
607 dst
= bridge_dst_lookup(eh
);
609 * BDG_BCAST, BDG_MCAST, BDG_LOCAL, BDG_UNKNOWN, BDG_DROP, ifp.
610 * For muted interfaces, the first 3 are changed in BDG_LOCAL,
611 * and others to BDG_DROP. Also, for incoming packets, ifp is changed
612 * to BDG_DROP in case ifp == src . These mods are not necessary
613 * for outgoing packets from ether_output().
615 BDG_STAT(ifp
, BDG_IN
);
620 case (int)BDG_UNKNOWN
:
625 if (dst
== ifp
|| dropit
)
626 BDG_STAT(ifp
, BDG_DROP
);
628 BDG_STAT(ifp
, BDG_FORWARD
);
633 if (dst
== BDG_BCAST
|| dst
== BDG_MCAST
|| dst
== BDG_LOCAL
)
638 return (dst
== ifp
? BDG_DROP
: dst
) ;
643 * Forward to dst, excluding src port and muted interfaces.
644 * If src == NULL, the pkt comes from ether_output, and dst is the real
645 * interface the packet is originally sent to. In this case we must forward
646 * it to the whole cluster. We never call bdg_forward ether_output on
647 * interfaces which are not part of a cluster.
649 * The packet is freed if possible (i.e. surely not of interest for
650 * the upper layer), otherwise a copy is left for use by the caller
653 * It would be more efficient to make bdg_forward() always consume
654 * the packet, leaving to the caller the task to check if it needs a copy
655 * and get one in case. As it is now, bdg_forward() can sometimes make
656 * a copy whereas it is not necessary.
658 * XXX be careful about eh, it can be a pointer into *m
661 bdg_forward(struct mbuf
*m0
, struct ether_header
*const eh
, struct ifnet
*dst
)
663 struct ifnet
*src
= m0
->m_pkthdr
.rcvif
; /* could be NULL in output */
664 struct ifnet
*ifp
, *last
= NULL
;
666 int shared
= bdg_copy
; /* someone else is using the mbuf */
667 int once
= 0; /* loop only once */
668 struct ifnet
*real_dst
= dst
; /* real dst from ether_output */
670 struct ip_fw_chain
*rule
= NULL
; /* did we match a firewall rule ? */
674 * XXX eh is usually a pointer within the mbuf (some ethernet drivers
675 * do that), so we better copy it before doing anything with the mbuf,
676 * or we might corrupt the header.
678 struct ether_header save_eh
= *eh
;
680 #if defined(IPFIREWALL) && defined(DUMMYNET)
681 if (m0
->m_type
== MT_DUMMYNET
) {
682 /* extract info from dummynet header */
683 rule
= (struct ip_fw_chain
*)(m0
->m_data
) ;
685 src
= m0
->m_pkthdr
.rcvif
;
686 shared
= 0 ; /* For sure this is our own mbuf. */
689 bdg_thru
++; /* only count once */
691 if (src
== NULL
) /* packet from ether_output */
692 dst
= bridge_dst_lookup(eh
);
693 if (dst
== BDG_DROP
) { /* this should not happen */
694 printf("xx bdg_forward for BDG_DROP\n");
698 if (dst
== BDG_LOCAL
) { /* this should not happen as well */
699 printf("xx ouch, bdg_forward for local pkt\n");
702 if (dst
== BDG_BCAST
|| dst
== BDG_MCAST
|| dst
== BDG_UNKNOWN
) {
703 ifp
= ifnet_head
.tqh_first
; /* scan all ports */
705 if (dst
!= BDG_UNKNOWN
) /* need a copy for the local stack */
711 if ( (u_int
)(ifp
) <= (u_int
)BDG_FORWARD
)
712 panic("bdg_forward: bad dst");
716 * Do filtering in a very similar way to what is done in ip_output.
717 * Only if firewall is loaded, enabled, and the packet is not
718 * from ether_output() (src==NULL, or we would filter it twice).
719 * Additional restrictions may apply e.g. non-IP, short packets,
720 * and pkts already gone through a pipe.
722 if (ip_fw_chk_ptr
&& bdg_ipfw
!= 0 && src
!= NULL
) {
726 if (rule
!= NULL
) /* dummynet packet, already partially processed */
727 goto forward
; /* HACK! I should obey the fw_one_pass */
728 if (ntohs(save_eh
.ether_type
) != ETHERTYPE_IP
)
729 goto forward
; /* not an IP packet, ipfw is not appropriate */
730 if (m0
->m_pkthdr
.len
< sizeof(struct ip
) )
731 goto forward
; /* header too short for an IP pkt, cannot filter */
733 * i need some amt of data to be contiguous, and in case others need
734 * the packet (shared==1) also better be in the first mbuf.
736 i
= min(m0
->m_pkthdr
.len
, max_protohdr
) ;
737 if ( shared
|| m0
->m_len
< i
) {
738 m0
= m_pullup(m0
, i
) ;
740 printf("-- bdg: pullup failed.\n") ;
746 * before calling the firewall, swap fields the same as IP does.
747 * here we assume the pkt is an IP one and the header is contiguous
749 ip
= mtod(m0
, struct ip
*);
754 * The third parameter to the firewall code is the dst. interface.
755 * Since we apply checks only on input pkts we use NULL.
756 * The firewall knows this is a bridged packet as the cookie ptr
759 i
= (*ip_fw_chk_ptr
)(&ip
, 0, NULL
, NULL
/* cookie */, &m0
, &rule
, NULL
);
760 if ( (i
& IP_FW_PORT_DENY_FLAG
) || m0
== NULL
) /* drop */
763 * If we get here, the firewall has passed the pkt, but the mbuf
764 * pointer might have changed. Restore ip and the fields NTOHS()'d.
766 ip
= mtod(m0
, struct ip
*);
770 if (i
== 0) /* a PASS rule. */
773 if (i
& IP_FW_PORT_DYNT_FLAG
) {
775 * Pass the pkt to dummynet, which consumes it.
776 * If shared, make a copy and keep the original.
777 * Need to prepend the ethernet header, optimize the common
778 * case of eh pointing already into the original mbuf.
782 m
= m_copypacket(m0
, M_DONTWAIT
);
784 printf("bdg_fwd: copy(1) failed\n");
788 m
= m0
; /* pass the original to dummynet */
789 m0
= NULL
; /* and nothing back to the caller */
791 if ( (void *)(eh
+ 1) == (void *)m
->m_data
) {
792 m
->m_data
-= ETHER_HDR_LEN
;
793 m
->m_len
+= ETHER_HDR_LEN
;
794 m
->m_pkthdr
.len
+= ETHER_HDR_LEN
;
797 M_PREPEND(m
, ETHER_HDR_LEN
, M_DONTWAIT
);
798 if (!m
&& verbose
) printf("M_PREPEND failed\n");
799 if (m
== NULL
) /* nope... */
801 bcopy(&save_eh
, mtod(m
, struct ether_header
*), ETHER_HDR_LEN
);
803 dummynet_io((i
& 0xffff),DN_TO_BDG_FWD
,m
,real_dst
,NULL
,0,rule
,0);
808 * XXX add divert/forward actions...
810 /* if none of the above matches, we have to drop the pkt */
812 printf("bdg_forward: No rules match, so dropping packet!\n");
816 #endif /* IPFIREWALL */
818 * Again, bring up the headers in case of shared bufs to avoid
819 * corruptions in the future.
822 int i
= min(m0
->m_pkthdr
.len
, max_protohdr
) ;
824 m0
= m_pullup(m0
, i
) ;
826 printf("-- bdg: pullup2 failed.\n") ;
830 /* now real_dst is used to determine the cluster where to forward */
831 if (src
!= NULL
) /* pkt comes from ether_input */
834 if (last
) { /* need to forward packet leftover from previous loop */
836 if (shared
== 0 && once
) { /* no need to copy */
838 m0
= NULL
; /* original is gone */
840 m
= m_copypacket(m0
, M_DONTWAIT
);
842 printf("bdg_forward: sorry, m_copypacket failed!\n");
843 return m0
; /* the original is still there... */
847 * Add header (optimized for the common case of eh pointing
848 * already into the mbuf) and execute last part of ether_output:
849 * queue pkt and start output if interface not yet active.
851 if ( (void *)(eh
+ 1) == (void *)m
->m_data
) {
852 m
->m_data
-= ETHER_HDR_LEN
;
853 m
->m_len
+= ETHER_HDR_LEN
;
854 m
->m_pkthdr
.len
+= ETHER_HDR_LEN
;
857 M_PREPEND(m
, ETHER_HDR_LEN
, M_DONTWAIT
);
858 if (!m
&& verbose
) printf("M_PREPEND failed\n");
861 bcopy(&save_eh
, mtod(m
, struct ether_header
*), ETHER_HDR_LEN
);
864 if (IF_QFULL(&last
->if_snd
)) {
865 IF_DROP(&last
->if_snd
);
867 BDG_MUTE(last
); /* should I also mute ? */
870 m_freem(m
); /* consume the pkt anyways */
872 last
->if_obytes
+= m
->m_pkthdr
.len
;
873 if (m
->m_flags
& M_MCAST
)
875 if (m
->m_pkthdr
.len
!= m
->m_len
) /* this pkt is on >1 bufs */
878 IF_ENQUEUE(&last
->if_snd
, m
);
879 if ((last
->if_flags
& IFF_OACTIVE
) == 0)
880 (*last
->if_start
)(last
);
883 BDG_STAT(last
, BDG_OUT
);
891 * If the interface is used for bridging, not muted, not full,
892 * up and running, is not the source interface, and belongs to
893 * the same cluster as the 'real_dst', then send here.
895 if ( BDG_USED(ifp
) && !BDG_MUTED(ifp
) && !IF_QFULL(&ifp
->if_snd
) &&
896 (ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) == (IFF_UP
|IFF_RUNNING
) &&
897 ifp
!= src
&& BDG_SAMECLUSTER(ifp
, real_dst
) )
899 ifp
= TAILQ_NEXT(ifp
, if_link
) ;
903 DEB(bdg_fw_ticks
+= (u_int32_t
)(rdtsc() - ticks
) ; bdg_fw_count
++ ;
904 if (bdg_fw_count
!= 0) bdg_fw_avg
= bdg_fw_ticks
/bdg_fw_count
; )