aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge/br_stp_bpdu.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2006-03-21 01:59:06 -0500
committerDavid S. Miller <davem@davemloft.net>2006-03-21 01:59:06 -0500
commitcf0f02d04a830c8202e6a8f8bb37acc6c1629a91 (patch)
tree8f3c7af9aee5ea2e1b889c27660e8587307025df /net/bridge/br_stp_bpdu.c
parent18fdb2b25be37e49b1669b5c394671f8c5b6550f (diff)
[BRIDGE]: use llc for receiving STP packets
Use LLC for the receive path of Spanning Tree Protocol packets. This allows link local multicast packets to be received by other protocols (if they care), and uses the existing LLC code to get STP packets back into bridge code. The bridge multicast address is also checked, so bridges using other link local multicast addresses are ignored. This allows for use of different multicast addresses to define separate STP domains. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_stp_bpdu.c')
-rw-r--r--net/bridge/br_stp_bpdu.c51
1 files changed, 33 insertions, 18 deletions
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c
index c3da01cc6a6f..a99e90e20952 100644
--- a/net/bridge/br_stp_bpdu.c
+++ b/net/bridge/br_stp_bpdu.c
@@ -15,6 +15,9 @@
15 15
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/netfilter_bridge.h> 17#include <linux/netfilter_bridge.h>
18#include <linux/etherdevice.h>
19#include <linux/llc.h>
20#include <net/llc_pdu.h>
18 21
19#include "br_private.h" 22#include "br_private.h"
20#include "br_private_stp.h" 23#include "br_private_stp.h"
@@ -130,42 +133,54 @@ void br_send_tcn_bpdu(struct net_bridge_port *p)
130 br_send_bpdu(p, buf, 7); 133 br_send_bpdu(p, buf, 7);
131} 134}
132 135
133static const unsigned char header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; 136/*
134 137 * Called from llc.
135/* NO locks, but rcu_read_lock (preempt_disabled) */ 138 *
136int br_stp_handle_bpdu(struct sk_buff *skb) 139 * NO locks, but rcu_read_lock (preempt_disabled)
140 */
141int br_stp_rcv(struct sk_buff *skb, struct net_device *dev,
142 struct packet_type *pt, struct net_device *orig_dev)
137{ 143{
138 struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); 144 const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
145 const unsigned char *dest = eth_hdr(skb)->h_dest;
146 struct net_bridge_port *p = rcu_dereference(dev->br_port);
139 struct net_bridge *br; 147 struct net_bridge *br;
140 unsigned char *buf; 148 const unsigned char *buf;
141 149
142 if (!p) 150 if (!p)
143 goto err; 151 goto err;
144 152
145 br = p->br; 153 if (pdu->ssap != LLC_SAP_BSPAN
146 spin_lock(&br->lock); 154 || pdu->dsap != LLC_SAP_BSPAN
155 || pdu->ctrl_1 != LLC_PDU_TYPE_U)
156 goto err;
147 157
148 if (p->state == BR_STATE_DISABLED || !(br->dev->flags & IFF_UP)) 158 if (!pskb_may_pull(skb, 4))
149 goto out; 159 goto err;
160
161 /* compare of protocol id and version */
162 buf = skb->data;
163 if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0)
164 goto err;
150 165
151 /* insert into forwarding database after filtering to avoid spoofing */ 166 br = p->br;
152 br_fdb_update(br, p, eth_hdr(skb)->h_source); 167 spin_lock(&br->lock);
153 168
154 if (!br->stp_enabled) 169 if (p->state == BR_STATE_DISABLED
170 || !br->stp_enabled
171 || !(br->dev->flags & IFF_UP))
155 goto out; 172 goto out;
156 173
157 /* need at least the 802 and STP headers */ 174 if (compare_ether_addr(dest, bridge_ula) != 0)
158 if (!pskb_may_pull(skb, sizeof(header)+1) ||
159 memcmp(skb->data, header, sizeof(header)))
160 goto out; 175 goto out;
161 176
162 buf = skb_pull(skb, sizeof(header)); 177 buf = skb_pull(skb, 3);
163 178
164 if (buf[0] == BPDU_TYPE_CONFIG) { 179 if (buf[0] == BPDU_TYPE_CONFIG) {
165 struct br_config_bpdu bpdu; 180 struct br_config_bpdu bpdu;
166 181
167 if (!pskb_may_pull(skb, 32)) 182 if (!pskb_may_pull(skb, 32))
168 goto out; 183 goto out;
169 184
170 buf = skb->data; 185 buf = skb->data;
171 bpdu.topology_change = (buf[1] & 0x01) ? 1 : 0; 186 bpdu.topology_change = (buf[1] & 0x01) ? 1 : 0;