11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Spanning tree protocol; BPDU handling
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Linux ethernet bridge
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Authors:
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Lennert Buytenhek		<buytenh@gnu.org>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This program is free software; you can redistribute it and/or
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	modify it under the terms of the GNU General Public License
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	as published by the Free Software Foundation; either version
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	2 of the License, or (at your option) any later version.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netfilter_bridge.h>
16cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger#include <linux/etherdevice.h>
17cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger#include <linux/llc.h>
185a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
19547b4e718115eea74087e28d7fa70aec619200dbStephen Hemminger#include <linux/pkt_sched.h>
20e730c15519d09ea528b4d2f1103681fa5937c0e6Eric W. Biederman#include <net/net_namespace.h>
2112ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger#include <net/llc.h>
22cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger#include <net/llc_pdu.h>
237c85fbf0657f216557b0c9c4a2e4e07f37d8bb8cPatrick McHardy#include <net/stp.h>
244dc6d9cc38cea1004a7f827cf76409ae42231feePeter Chubb#include <asm/unaligned.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "br_private.h"
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "br_private_stp.h"
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2918fdb2b25be37e49b1669b5c394671f8c5b6550fStephen Hemminger#define STP_HZ		256
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3112ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger#define LLC_RESERVE sizeof(struct llc_pdu_un)
3212ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger
3312ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemmingerstatic void br_send_bpdu(struct net_bridge_port *p,
349d6f229fc45b6ac268020c0c8eff29e94bb34381YOSHIFUJI Hideaki			 const unsigned char *data, int length)
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3812ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	skb = dev_alloc_skb(length+LLC_RESERVE);
3912ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	if (!skb)
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4212ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	skb->dev = p->dev;
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb->protocol = htons(ETH_P_802_2);
44547b4e718115eea74087e28d7fa70aec619200dbStephen Hemminger	skb->priority = TC_PRIO_CONTROL;
4512ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger
4612ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	skb_reserve(skb, LLC_RESERVE);
4712ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	memcpy(__skb_put(skb, length), data, length);
4812ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger
4912ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	llc_pdu_header_init(skb, LLC_PDU_TYPE_U, LLC_SAP_BSPAN,
5012ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger			    LLC_SAP_BSPAN, LLC_PDU_CMD);
5112ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	llc_pdu_init_as_ui_cmd(skb);
5212ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger
5312ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr);
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
55e6f26129ebbb0071016e2526036f42036ccf30e1Florian Westphal	skb_reset_mac_header(skb);
56e6f26129ebbb0071016e2526036f42036ccf30e1Florian Westphal
57713aefa3fb3929ce36305d4d1b7b4059d87ed115Jan Engelhardt	NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_queue_xmit);
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6118fdb2b25be37e49b1669b5c394671f8c5b6550fStephen Hemmingerstatic inline void br_set_ticks(unsigned char *dest, int j)
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6318fdb2b25be37e49b1669b5c394671f8c5b6550fStephen Hemminger	unsigned long ticks = (STP_HZ * j)/ HZ;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
65d3e2ce3bcdbf4319dea308c79b5f72a8ecc8015cHarvey Harrison	put_unaligned_be16(ticks, dest);
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6818fdb2b25be37e49b1669b5c394671f8c5b6550fStephen Hemmingerstatic inline int br_get_ticks(const unsigned char *src)
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
70d3e2ce3bcdbf4319dea308c79b5f72a8ecc8015cHarvey Harrison	unsigned long ticks = get_unaligned_be16(src);
7118fdb2b25be37e49b1669b5c394671f8c5b6550fStephen Hemminger
72172589ccdde41b59861c92c4a971b95514ef24e3Ilpo Järvinen	return DIV_ROUND_UP(ticks * HZ, STP_HZ);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* called under bridge lock */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7812ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	unsigned char buf[35];
7912ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger
809cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger	if (p->br->stp_enabled != BR_KERNEL_STP)
819cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger		return;
829cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger
8312ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[0] = 0;
8412ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[1] = 0;
8512ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[2] = 0;
8612ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[3] = BPDU_TYPE_CONFIG;
8712ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[4] = (bpdu->topology_change ? 0x01 : 0) |
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(bpdu->topology_change_ack ? 0x80 : 0);
8912ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[5] = bpdu->root.prio[0];
9012ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[6] = bpdu->root.prio[1];
9112ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[7] = bpdu->root.addr[0];
9212ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[8] = bpdu->root.addr[1];
9312ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[9] = bpdu->root.addr[2];
9412ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[10] = bpdu->root.addr[3];
9512ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[11] = bpdu->root.addr[4];
9612ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[12] = bpdu->root.addr[5];
9712ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[13] = (bpdu->root_path_cost >> 24) & 0xFF;
9812ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[14] = (bpdu->root_path_cost >> 16) & 0xFF;
9912ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[15] = (bpdu->root_path_cost >> 8) & 0xFF;
10012ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[16] = bpdu->root_path_cost & 0xFF;
10112ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[17] = bpdu->bridge_id.prio[0];
10212ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[18] = bpdu->bridge_id.prio[1];
10312ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[19] = bpdu->bridge_id.addr[0];
10412ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[20] = bpdu->bridge_id.addr[1];
10512ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[21] = bpdu->bridge_id.addr[2];
10612ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[22] = bpdu->bridge_id.addr[3];
10712ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[23] = bpdu->bridge_id.addr[4];
10812ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[24] = bpdu->bridge_id.addr[5];
10912ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[25] = (bpdu->port_id >> 8) & 0xFF;
11012ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[26] = bpdu->port_id & 0xFF;
11112ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger
11212ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	br_set_ticks(buf+27, bpdu->message_age);
11312ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	br_set_ticks(buf+29, bpdu->max_age);
11412ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	br_set_ticks(buf+31, bpdu->hello_time);
11512ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	br_set_ticks(buf+33, bpdu->forward_delay);
11612ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger
11712ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	br_send_bpdu(p, buf, 35);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* called under bridge lock */
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid br_send_tcn_bpdu(struct net_bridge_port *p)
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12312ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	unsigned char buf[4];
12412ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger
1259cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger	if (p->br->stp_enabled != BR_KERNEL_STP)
1269cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger		return;
1279cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger
12812ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[0] = 0;
12912ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[1] = 0;
13012ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[2] = 0;
13112ac84c4a9c505e3e30529563b04cc8f6d5ebbf3Stephen Hemminger	buf[3] = BPDU_TYPE_TCN;
132485c2967d622449f4bbfae305a6fc4e185b5b094Stephen Hemminger	br_send_bpdu(p, buf, 4);
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
135cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger/*
136cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger * Called from llc.
137cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger *
138eeaf61d8891f9c9ed12c1a667e72bf83f0857954stephen hemminger * NO locks, but rcu_read_lock
139cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger */
1407c85fbf0657f216557b0c9c4a2e4e07f37d8bb8cPatrick McHardyvoid br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
1417c85fbf0657f216557b0c9c4a2e4e07f37d8bb8cPatrick McHardy		struct net_device *dev)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
143cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger	const unsigned char *dest = eth_hdr(skb)->h_dest;
144f350a0a87374418635689471606454abc7beaa3aJiri Pirko	struct net_bridge_port *p;
145b3f1be4b5412e34647764457bec901e06b03e624Stephen Hemminger	struct net_bridge *br;
146cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger	const unsigned char *buf;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger	if (!pskb_may_pull(skb, 4))
149cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger		goto err;
150cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger
151cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger	/* compare of protocol id and version */
152cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger	buf = skb->data;
153cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger	if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0)
154cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger		goto err;
155b3f1be4b5412e34647764457bec901e06b03e624Stephen Hemminger
156859828c0ea476b42f3a93d69d117aaba90994b6fJiri Pirko	p = br_port_get_check_rcu(dev);
157b5ed54e94d324f17c97852296d61a143f01b227astephen hemminger	if (!p)
158b5ed54e94d324f17c97852296d61a143f01b227astephen hemminger		goto err;
159b5ed54e94d324f17c97852296d61a143f01b227astephen hemminger
160cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger	br = p->br;
161cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger	spin_lock(&br->lock);
162b3f1be4b5412e34647764457bec901e06b03e624Stephen Hemminger
1639cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger	if (br->stp_enabled != BR_KERNEL_STP)
1649cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger		goto out;
1659cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger
1669cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger	if (!(br->dev->flags & IFF_UP))
1679cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger		goto out;
1689cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger
1699cde070874b822d4677f4f01fe146991785813b1Stephen Hemminger	if (p->state == BR_STATE_DISABLED)
170b3f1be4b5412e34647764457bec901e06b03e624Stephen Hemminger		goto out;
17185967bb46dd1f8f2c49b85a313866c00ac0c9b59Stephen Hemminger
1729a7b6ef9b9938a1f5cb91ccc0b713b9443edc79fJoe Perches	if (!ether_addr_equal(dest, br->group_addr))
173b3f1be4b5412e34647764457bec901e06b03e624Stephen Hemminger		goto out;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
175a2e01a65cd7135dab26d27d4b589b2e5358bec99stephen hemminger	if (p->flags & BR_BPDU_GUARD) {
176a2e01a65cd7135dab26d27d4b589b2e5358bec99stephen hemminger		br_notice(br, "BPDU received on blocked port %u(%s)\n",
177a2e01a65cd7135dab26d27d4b589b2e5358bec99stephen hemminger			  (unsigned int) p->port_no, p->dev->name);
178a2e01a65cd7135dab26d27d4b589b2e5358bec99stephen hemminger		br_stp_disable_port(p);
179a2e01a65cd7135dab26d27d4b589b2e5358bec99stephen hemminger		goto out;
180a2e01a65cd7135dab26d27d4b589b2e5358bec99stephen hemminger	}
181a2e01a65cd7135dab26d27d4b589b2e5358bec99stephen hemminger
182cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger	buf = skb_pull(skb, 3);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (buf[0] == BPDU_TYPE_CONFIG) {
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct br_config_bpdu bpdu;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!pskb_may_pull(skb, 32))
188cf0f02d04a830c8202e6a8f8bb37acc6c1629a91Stephen Hemminger			goto out;
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		buf = skb->data;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.topology_change = (buf[1] & 0x01) ? 1 : 0;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.topology_change_ack = (buf[1] & 0x80) ? 1 : 0;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.root.prio[0] = buf[2];
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.root.prio[1] = buf[3];
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.root.addr[0] = buf[4];
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.root.addr[1] = buf[5];
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.root.addr[2] = buf[6];
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.root.addr[3] = buf[7];
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.root.addr[4] = buf[8];
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.root.addr[5] = buf[9];
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.root_path_cost =
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(buf[10] << 24) |
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(buf[11] << 16) |
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			(buf[12] << 8) |
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			buf[13];
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.bridge_id.prio[0] = buf[14];
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.bridge_id.prio[1] = buf[15];
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.bridge_id.addr[0] = buf[16];
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.bridge_id.addr[1] = buf[17];
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.bridge_id.addr[2] = buf[18];
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.bridge_id.addr[3] = buf[19];
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.bridge_id.addr[4] = buf[20];
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.bridge_id.addr[5] = buf[21];
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.port_id = (buf[22] << 8) | buf[23];
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.message_age = br_get_ticks(buf+24);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.max_age = br_get_ticks(buf+26);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.hello_time = br_get_ticks(buf+28);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		bpdu.forward_delay = br_get_ticks(buf+30);
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2220652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger		if (bpdu.message_age > bpdu.max_age) {
2230652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger			if (net_ratelimit())
2240652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger				br_notice(p->br,
2250652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger					  "port %u config from %pM"
2260652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger					  " (message_age %ul > max_age %ul)\n",
2270652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger					  p->port_no,
2280652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger					  eth_hdr(skb)->h_source,
2290652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger					  bpdu.message_age, bpdu.max_age);
2300652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger			goto out;
2310652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger		}
2320652cac22ce3fa0c90e35d0a2862969fc394cb02stephen hemminger
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		br_received_config_bpdu(p, &bpdu);
234160d73b8455edb1a12967e207790b1a93a4cb0e1stephen hemminger	} else if (buf[0] == BPDU_TYPE_TCN) {
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		br_received_tcn_bpdu(p);
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out:
238b3f1be4b5412e34647764457bec901e06b03e624Stephen Hemminger	spin_unlock(&br->lock);
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err:
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
242