--- a/Documentation/networking/ip-sysctl.txt	2011-08-15 10:58:36.451532115 -0700
+++ b/Documentation/networking/ip-sysctl.txt	2011-08-15 11:39:57.719438766 -0700
@@ -1289,6 +1289,10 @@ bridge-nf-filter-pppoe-tagged - BOOLEAN
 	0 : disable this.
 	Default: 1
 
+bridge-forward-link-local - BOOLEAN
+	1 : pass link-local multicasts through bridge in STP mode
+	0 : disable this.
+	Default: 0
 
 proc/sys/net/sctp/* Variables:
 
--- a/net/bridge/Makefile	2011-08-15 10:30:25.203595742 -0700
+++ b/net/bridge/Makefile	2011-08-15 11:22:38.139477877 -0700
@@ -9,7 +9,7 @@ bridge-y	:= br.o br_device.o br_fdb.o br
 			br_stp_if.o br_stp_timer.o br_netlink.o
 
 bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
-
+bridge-$(CONFIG_SYSCTL) += br_sysctl.o
 bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
 
 bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o
--- a/net/bridge/br.c	2011-08-15 10:30:48.755594855 -0700
+++ b/net/bridge/br.c	2011-08-15 10:33:07.215589647 -0700
@@ -60,6 +60,12 @@ static int __init br_init(void)
 	if (err)
 		goto err_out4;
 
+#ifdef CONFIG_SYSCTL
+	err = br_sysctl_init();
+	if (err)
+		goto err_out5;
+#endif
+
 	brioctl_set(br_ioctl_deviceless_stub);
 
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
@@ -67,6 +73,9 @@ static int __init br_init(void)
 #endif
 
 	return 0;
+
+err_out5:
+	br_netlink_fini();
 err_out4:
 	unregister_netdevice_notifier(&br_device_notifier);
 err_out3:
@@ -84,6 +93,9 @@ static void __exit br_deinit(void)
 {
 	stp_proto_unregister(&br_stp_proto);
 
+#ifdef CONFIG_SYSCTL
+	br_sysctl_fini();
+#endif
 	br_netlink_fini();
 	unregister_netdevice_notifier(&br_device_notifier);
 	brioctl_set(NULL);
--- a/net/bridge/br_input.c	2011-08-15 10:40:21.435573311 -0700
+++ b/net/bridge/br_input.c	2011-08-15 11:39:57.719438766 -0700
@@ -16,11 +16,18 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/netfilter_bridge.h>
+#include <linux/llc.h>
+#include <net/llc.h>
+#include <net/llc_pdu.h>
+
 #include "br_private.h"
 
 /* Bridge group multicast address 802.1d (pg 51). */
 const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
 
+/* Should link-local packets be forwarded (in STP mode) */
+int br_forward_link_local;
+
 /* Hook for brouter */
 br_should_route_hook_t __rcu *br_should_route_hook __read_mostly;
 EXPORT_SYMBOL(br_should_route_hook);
@@ -138,6 +145,17 @@ static inline int is_link_local(const un
 	return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0;
 }
 
+/* Identify Spanning Tree packets based on header */
+static bool is_stp_bpdu(struct sk_buff *skb)
+{
+	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
+
+	return skb->protocol == htons(ETH_P_802_2) &&
+		pdu->ctrl_1 == LLC_PDU_TYPE_U &&
+		pdu->dsap == LLC_SAP_BSPAN &&
+		pdu->ssap == LLC_SAP_BSPAN;
+}
+
 /*
  * Return NULL if skb is handled
  * note: already called with rcu_read_lock
@@ -166,8 +184,16 @@ rx_handler_result_t br_handle_frame(stru
 		if (skb->protocol == htons(ETH_P_PAUSE))
 			goto drop;
 
-		/* If STP is turned off, then forward */
-		if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)
+		/* If STP is turned off, then in hub mode */
+		if (p->br->stp_enabled == BR_NO_STP)
+			goto forward;
+
+		/*
+		 * If STP is on
+		 * then Always handle STP packets locally,
+		 *      other packets can be forwarded if sysctl is enabled.
+		 */
+		if (!is_stp_bpdu(skb) && br_forward_link_local)
 			goto forward;
 
 		if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
--- a/net/bridge/br_private.h	2011-08-15 10:38:35.587577293 -0700
+++ b/net/bridge/br_private.h	2011-08-15 10:57:36.983534352 -0700
@@ -284,6 +284,7 @@ struct br_input_skb_cb {
 	pr_debug("%s: " format,  (br)->dev->name, ##args)
 
 extern struct notifier_block br_device_notifier;
+extern int br_forward_link_local;
 extern const u8 br_group_address[ETH_ALEN];
 
 /* called under bridge lock */
@@ -546,6 +547,10 @@ extern int br_sysfs_renameif(struct net_
 extern int br_sysfs_addbr(struct net_device *dev);
 extern void br_sysfs_delbr(struct net_device *dev);
 
+/* br_sysctl.c */
+extern int br_sysctl_init(void);
+extern void br_sysctl_fini(void);
+
 #else
 
 #define br_sysfs_addif(p)	(0)
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ b/net/bridge/br_sysctl.c	2011-08-15 11:41:00.819436393 -0700
@@ -0,0 +1,57 @@
+/*
+ *	Sysctl settings for bridge
+ *
+ *	Authors:
+ *	Stephen Hemminger		<shemminger@osdl.org>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ip.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/if_pppox.h>
+#include <linux/sysctl.h>
+
+#include "br_private.h"
+
+static struct ctl_table bridge_table[] = {
+	{
+		.procname	= "bridge-forward-link-local",
+		.data		= &br_forward_link_local,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+};
+
+static struct ctl_path bridge_ctl_path[] = {
+	{ .procname = "net", },
+	{ .procname = "bridge", },
+	{ },
+};
+
+static struct ctl_table_header *br_sysctl;
+
+int __init br_sysctl_init(void)
+{
+	br_sysctl = register_sysctl_paths(bridge_ctl_path, bridge_table);
+	if (br_sysctl == NULL)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void __exit br_sysctl_fini(void)
+{
+	unregister_net_sysctl_table(br_sysctl);
+}
