NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/48104: Incorrect forwarding of broadcast packets by bridge(4)



>Number:         48104
>Category:       kern
>Synopsis:       Incorrect forwarding of broadcast packets by bridge(4)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Mon Aug 05 00:55:00 +0000 2013
>Originator:     Lloyd Parkes
>Release:        NetBSD 6.1
>Organization:
Must Have Coffee
>Environment:
NetBSD netboot 6.1 NetBSD 6.1 (GENERIC) #8: Mon Aug  5 12:07:00 NZST 2013  
lloyd%castigate.must-have-coffee.gen.nz@localhost:/Volumes/ramdisk/build-6net/obj.i386/sys/arch/i386/compile/GENERIC
 i386
>Description:
When a broadcast packet is received on a bridge(4) port, it is send out all the 
other ports, but it is never passed up the network stack of those ports as an 
input packet. This is at odds with how unicast packets are handled.
>How-To-Repeat:
I have two LANs connected by a router. The first LAN has the addresses 
10.0.1.0/24 and 2002:cb61:d534:3::/64 and it is the desktop LAN in my house. 
The second LAN is for testing this problem and it has the two addresses 
10.0.240.0/24 and 2002:cb61:d534:2000::/64.

I have two computers. The first is my desktop called Castigate and it has a 
single interface on my desktop LAN. The second is my test system and it has 
five ethernet interfaces called ste0, ste1, ste2, ste3, and ex0. ex0 connected 
to my desktop LAN and I use it to keep my monitoring traffic off the test LAN. 
ste0 is connected to an unconfigured router port in order to brink the link up. 
ste3 is connected to the test LAN. ste1 and ste2 and not connected to anything. 
The test system also runs bridge0 which contains ste0 and ste3. The following 
configures my test system.

ifconfig bridge0 create
ifconfig ste0 inet6 2002:cb61:d534:2000:234:78ff:fe00:1
ifconfig ste3 inet6 2002:cb61:d534:2000:234:78ff:fe00:4
brconfig bridge0 add ste0
brconfig bridge0 add ste3
ifconfig bridge0 up
ifconfig ste0 inet 10.0.240.1 netmask 255.255.255.0
ifconfig ste3 inet 10.0.240.4 netmask 255.255.255.0

On Castigate run "ping6 -c 10  2002:cb61:d534:2000:234:78ff:fe00:1" and "ping 
-c 10 10.0.240.1". Note that both commands report a 100% packet loss. tcpdump 
running on ste0 shows the ARP/NDP packets that are ostensibly being lost, so we 
know that the packets are being passed by the bridge. 

On Castigate run "ping6 -c 10  2002:cb61:d534:2000:234:78ff:fe00:4" and "ping 
-c 10 10.0.240.4". Note that we get 0% packet loss because we are now pinging 
the interfaces directly connected to the router.

>Fix:
Index: sys/net/if_bridge.c
===================================================================
RCS file: /vol/src/rsync-src/src/sys/net/if_bridge.c,v
retrieving revision 1.74
diff -u -r1.74 if_bridge.c
--- sys/net/if_bridge.c 19 Nov 2011 22:51:25 -0000      1.74
+++ sys/net/if_bridge.c 5 Aug 2013 00:05:32 -0000
@@ -1633,6 +1633,13 @@
                }

                bridge_enqueue(sc, dst_if, mc, 1);
+               mc = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
+               if (mc == NULL) {
+                       sc->sc_if.if_oerrors++;
+                       continue;
+               }
+               mc->m_pkthdr.rcvif = dst_if;
+               (*dst_if->if_input)(dst_if, mc);
        }
        if (used == 0)
                m_freem(m);
Index: sys/net/if_ethersubr.c
===================================================================
The following works for me. The change to if_bridge.c gets the packets copied 
to all the other bridge ports and the change to if_ethersubr.c prevents packets 
that have already been broadcast from being rebroadcast.

RCS file: /vol/src/rsync-src/src/sys/net/if_ethersubr.c,v
retrieving revision 1.188.8.3
diff -u -r1.188.8.3 if_ethersubr.c
--- sys/net/if_ethersubr.c      31 Oct 2012 16:07:46 -0000      1.188.8.3
+++ sys/net/if_ethersubr.c      4 Aug 2013 06:53:32 -0000
@@ -703,7 +703,8 @@
         * will always return the original packet if we need to
         * process it locally.
         */
-       if (ifp->if_bridge) {
+       if (ifp->if_bridge && (m->m_flags & M_LINK2) == 0) {
+               m->m_flags |= M_LINK2;
                /* clear M_PROMISC, in case the packets comes from a vlan */
                m->m_flags &= ~M_PROMISC;
                m = bridge_input(ifp, m);



Home | Main Index | Thread Index | Old Index