2 * Spanning tree protocol; BPDU handling
3 * Linux ethernet bridge
6 * Lennert Buytenhek <buytenh@gnu.org>
8 * $Id: br_stp_bpdu.c,v 1.3 2001/11/10 02:35:25 davem Exp $
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
16 #include <linux/kernel.h>
17 #include <linux/netfilter_bridge.h>
19 #include "br_private.h"
20 #include "br_private_stp.h"
22 #define JIFFIES_TO_TICKS(j) (((j) << 8) / HZ)
23 #define TICKS_TO_JIFFIES(j) (((j) * HZ) >> 8)
25 static void br_send_bpdu(struct net_bridge_port
*p
, unsigned char *data
, int length
)
27 struct net_device
*dev
;
31 if (!p
->br
->stp_enabled
)
34 size
= length
+ 2*ETH_ALEN
+ 2;
40 if ((skb
= dev_alloc_skb(size
)) == NULL
) {
41 printk(KERN_INFO
"br: memory squeeze!\n");
46 skb
->protocol
= htons(ETH_P_802_2
);
47 skb
->mac
.raw
= skb_put(skb
, size
);
48 memcpy(skb
->mac
.raw
, bridge_ula
, ETH_ALEN
);
49 memcpy(skb
->mac
.raw
+ETH_ALEN
, dev
->dev_addr
, ETH_ALEN
);
50 skb
->mac
.raw
[2*ETH_ALEN
] = 0;
51 skb
->mac
.raw
[2*ETH_ALEN
+1] = length
;
52 skb
->nh
.raw
= skb
->mac
.raw
+ 2*ETH_ALEN
+ 2;
53 memcpy(skb
->nh
.raw
, data
, length
);
54 memset(skb
->nh
.raw
+ length
, 0xa5, size
- length
- 2*ETH_ALEN
- 2);
56 NF_HOOK(PF_BRIDGE
, NF_BR_LOCAL_OUT
, skb
, NULL
, skb
->dev
,
60 static __inline__
void br_set_ticks(unsigned char *dest
, int jiff
)
64 ticks
= JIFFIES_TO_TICKS(jiff
);
65 dest
[0] = (ticks
>> 8) & 0xFF;
66 dest
[1] = ticks
& 0xFF;
69 static __inline__
int br_get_ticks(unsigned char *dest
)
71 return TICKS_TO_JIFFIES((dest
[0] << 8) | dest
[1]);
74 /* called under bridge lock */
75 void br_send_config_bpdu(struct net_bridge_port
*p
, struct br_config_bpdu
*bpdu
)
77 unsigned char buf
[38];
85 buf
[6] = BPDU_TYPE_CONFIG
;
86 buf
[7] = (bpdu
->topology_change
? 0x01 : 0) |
87 (bpdu
->topology_change_ack
? 0x80 : 0);
88 buf
[8] = bpdu
->root
.prio
[0];
89 buf
[9] = bpdu
->root
.prio
[1];
90 buf
[10] = bpdu
->root
.addr
[0];
91 buf
[11] = bpdu
->root
.addr
[1];
92 buf
[12] = bpdu
->root
.addr
[2];
93 buf
[13] = bpdu
->root
.addr
[3];
94 buf
[14] = bpdu
->root
.addr
[4];
95 buf
[15] = bpdu
->root
.addr
[5];
96 buf
[16] = (bpdu
->root_path_cost
>> 24) & 0xFF;
97 buf
[17] = (bpdu
->root_path_cost
>> 16) & 0xFF;
98 buf
[18] = (bpdu
->root_path_cost
>> 8) & 0xFF;
99 buf
[19] = bpdu
->root_path_cost
& 0xFF;
100 buf
[20] = bpdu
->bridge_id
.prio
[0];
101 buf
[21] = bpdu
->bridge_id
.prio
[1];
102 buf
[22] = bpdu
->bridge_id
.addr
[0];
103 buf
[23] = bpdu
->bridge_id
.addr
[1];
104 buf
[24] = bpdu
->bridge_id
.addr
[2];
105 buf
[25] = bpdu
->bridge_id
.addr
[3];
106 buf
[26] = bpdu
->bridge_id
.addr
[4];
107 buf
[27] = bpdu
->bridge_id
.addr
[5];
108 buf
[28] = (bpdu
->port_id
>> 8) & 0xFF;
109 buf
[29] = bpdu
->port_id
& 0xFF;
111 br_set_ticks(buf
+30, bpdu
->message_age
);
112 br_set_ticks(buf
+32, bpdu
->max_age
);
113 br_set_ticks(buf
+34, bpdu
->hello_time
);
114 br_set_ticks(buf
+36, bpdu
->forward_delay
);
116 br_send_bpdu(p
, buf
, 38);
119 /* called under bridge lock */
120 void br_send_tcn_bpdu(struct net_bridge_port
*p
)
122 unsigned char buf
[7];
130 buf
[6] = BPDU_TYPE_TCN
;
131 br_send_bpdu(p
, buf
, 7);
134 static const unsigned char header
[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
137 int br_stp_handle_bpdu(struct sk_buff
*skb
)
139 struct net_bridge_port
*p
= skb
->dev
->br_port
;
140 struct net_bridge
*br
= p
->br
;
143 /* need at least the 802 and STP headers */
144 if (!pskb_may_pull(skb
, sizeof(header
)+1) ||
145 memcmp(skb
->data
, header
, sizeof(header
)))
148 buf
= skb_pull(skb
, sizeof(header
));
150 spin_lock_bh(&br
->lock
);
151 if (p
->state
== BR_STATE_DISABLED
152 || !(br
->dev
->flags
& IFF_UP
)
156 if (buf
[0] == BPDU_TYPE_CONFIG
) {
157 struct br_config_bpdu bpdu
;
159 if (!pskb_may_pull(skb
, 32))
163 bpdu
.topology_change
= (buf
[1] & 0x01) ? 1 : 0;
164 bpdu
.topology_change_ack
= (buf
[1] & 0x80) ? 1 : 0;
166 bpdu
.root
.prio
[0] = buf
[2];
167 bpdu
.root
.prio
[1] = buf
[3];
168 bpdu
.root
.addr
[0] = buf
[4];
169 bpdu
.root
.addr
[1] = buf
[5];
170 bpdu
.root
.addr
[2] = buf
[6];
171 bpdu
.root
.addr
[3] = buf
[7];
172 bpdu
.root
.addr
[4] = buf
[8];
173 bpdu
.root
.addr
[5] = buf
[9];
174 bpdu
.root_path_cost
=
179 bpdu
.bridge_id
.prio
[0] = buf
[14];
180 bpdu
.bridge_id
.prio
[1] = buf
[15];
181 bpdu
.bridge_id
.addr
[0] = buf
[16];
182 bpdu
.bridge_id
.addr
[1] = buf
[17];
183 bpdu
.bridge_id
.addr
[2] = buf
[18];
184 bpdu
.bridge_id
.addr
[3] = buf
[19];
185 bpdu
.bridge_id
.addr
[4] = buf
[20];
186 bpdu
.bridge_id
.addr
[5] = buf
[21];
187 bpdu
.port_id
= (buf
[22] << 8) | buf
[23];
189 bpdu
.message_age
= br_get_ticks(buf
+24);
190 bpdu
.max_age
= br_get_ticks(buf
+26);
191 bpdu
.hello_time
= br_get_ticks(buf
+28);
192 bpdu
.forward_delay
= br_get_ticks(buf
+30);
194 br_received_config_bpdu(p
, &bpdu
);
197 else if (buf
[0] == BPDU_TYPE_TCN
) {
198 br_received_tcn_bpdu(p
);
201 spin_unlock_bh(&br
->lock
);