diff options
-rw-r--r-- | net/bridge/br_stp_bpdu.c | 128 |
1 files changed, 59 insertions, 69 deletions
diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index ed3a5441a47e..8934a54792be 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/netfilter_bridge.h> | 17 | #include <linux/netfilter_bridge.h> |
18 | #include <linux/etherdevice.h> | 18 | #include <linux/etherdevice.h> |
19 | #include <linux/llc.h> | 19 | #include <linux/llc.h> |
20 | #include <net/llc.h> | ||
20 | #include <net/llc_pdu.h> | 21 | #include <net/llc_pdu.h> |
21 | 22 | ||
22 | #include "br_private.h" | 23 | #include "br_private.h" |
@@ -24,36 +25,31 @@ | |||
24 | 25 | ||
25 | #define STP_HZ 256 | 26 | #define STP_HZ 256 |
26 | 27 | ||
27 | static void br_send_bpdu(struct net_bridge_port *p, unsigned char *data, int length) | 28 | #define LLC_RESERVE sizeof(struct llc_pdu_un) |
29 | |||
30 | static void br_send_bpdu(struct net_bridge_port *p, | ||
31 | const unsigned char *data, int length) | ||
28 | { | 32 | { |
29 | struct net_device *dev; | ||
30 | struct sk_buff *skb; | 33 | struct sk_buff *skb; |
31 | int size; | ||
32 | 34 | ||
33 | if (!p->br->stp_enabled) | 35 | if (!p->br->stp_enabled) |
34 | return; | 36 | return; |
35 | 37 | ||
36 | size = length + 2*ETH_ALEN + 2; | 38 | skb = dev_alloc_skb(length+LLC_RESERVE); |
37 | if (size < 60) | 39 | if (!skb) |
38 | size = 60; | ||
39 | |||
40 | dev = p->dev; | ||
41 | |||
42 | if ((skb = dev_alloc_skb(size)) == NULL) { | ||
43 | printk(KERN_INFO "br: memory squeeze!\n"); | ||
44 | return; | 40 | return; |
45 | } | ||
46 | 41 | ||
47 | skb->dev = dev; | 42 | skb->dev = p->dev; |
48 | skb->protocol = htons(ETH_P_802_2); | 43 | skb->protocol = htons(ETH_P_802_2); |
49 | skb->mac.raw = skb_put(skb, size); | 44 | |
50 | memcpy(skb->mac.raw, p->br->group_addr, ETH_ALEN); | 45 | skb_reserve(skb, LLC_RESERVE); |
51 | memcpy(skb->mac.raw+ETH_ALEN, dev->dev_addr, ETH_ALEN); | 46 | memcpy(__skb_put(skb, length), data, length); |
52 | skb->mac.raw[2*ETH_ALEN] = 0; | 47 | |
53 | skb->mac.raw[2*ETH_ALEN+1] = length; | 48 | llc_pdu_header_init(skb, LLC_PDU_TYPE_U, LLC_SAP_BSPAN, |
54 | skb->nh.raw = skb->mac.raw + 2*ETH_ALEN + 2; | 49 | LLC_SAP_BSPAN, LLC_PDU_CMD); |
55 | memcpy(skb->nh.raw, data, length); | 50 | llc_pdu_init_as_ui_cmd(skb); |
56 | memset(skb->nh.raw + length, 0xa5, size - length - 2*ETH_ALEN - 2); | 51 | |
52 | llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr); | ||
57 | 53 | ||
58 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, | 54 | NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev, |
59 | dev_queue_xmit); | 55 | dev_queue_xmit); |
@@ -76,60 +72,54 @@ static inline int br_get_ticks(const unsigned char *src) | |||
76 | /* called under bridge lock */ | 72 | /* called under bridge lock */ |
77 | void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) | 73 | void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu) |
78 | { | 74 | { |
79 | unsigned char buf[38]; | 75 | unsigned char buf[35]; |
80 | 76 | ||
81 | buf[0] = 0x42; | 77 | buf[0] = 0; |
82 | buf[1] = 0x42; | 78 | buf[1] = 0; |
83 | buf[2] = 0x03; | 79 | buf[2] = 0; |
84 | buf[3] = 0; | 80 | buf[3] = BPDU_TYPE_CONFIG; |
85 | buf[4] = 0; | 81 | buf[4] = (bpdu->topology_change ? 0x01 : 0) | |
86 | buf[5] = 0; | ||
87 | buf[6] = BPDU_TYPE_CONFIG; | ||
88 | buf[7] = (bpdu->topology_change ? 0x01 : 0) | | ||
89 | (bpdu->topology_change_ack ? 0x80 : 0); | 82 | (bpdu->topology_change_ack ? 0x80 : 0); |
90 | buf[8] = bpdu->root.prio[0]; | 83 | buf[5] = bpdu->root.prio[0]; |
91 | buf[9] = bpdu->root.prio[1]; | 84 | buf[6] = bpdu->root.prio[1]; |
92 | buf[10] = bpdu->root.addr[0]; | 85 | buf[7] = bpdu->root.addr[0]; |
93 | buf[11] = bpdu->root.addr[1]; | 86 | buf[8] = bpdu->root.addr[1]; |
94 | buf[12] = bpdu->root.addr[2]; | 87 | buf[9] = bpdu->root.addr[2]; |
95 | buf[13] = bpdu->root.addr[3]; | 88 | buf[10] = bpdu->root.addr[3]; |
96 | buf[14] = bpdu->root.addr[4]; | 89 | buf[11] = bpdu->root.addr[4]; |
97 | buf[15] = bpdu->root.addr[5]; | 90 | buf[12] = bpdu->root.addr[5]; |
98 | buf[16] = (bpdu->root_path_cost >> 24) & 0xFF; | 91 | buf[13] = (bpdu->root_path_cost >> 24) & 0xFF; |
99 | buf[17] = (bpdu->root_path_cost >> 16) & 0xFF; | 92 | buf[14] = (bpdu->root_path_cost >> 16) & 0xFF; |
100 | buf[18] = (bpdu->root_path_cost >> 8) & 0xFF; | 93 | buf[15] = (bpdu->root_path_cost >> 8) & 0xFF; |
101 | buf[19] = bpdu->root_path_cost & 0xFF; | 94 | buf[16] = bpdu->root_path_cost & 0xFF; |
102 | buf[20] = bpdu->bridge_id.prio[0]; | 95 | buf[17] = bpdu->bridge_id.prio[0]; |
103 | buf[21] = bpdu->bridge_id.prio[1]; | 96 | buf[18] = bpdu->bridge_id.prio[1]; |
104 | buf[22] = bpdu->bridge_id.addr[0]; | 97 | buf[19] = bpdu->bridge_id.addr[0]; |
105 | buf[23] = bpdu->bridge_id.addr[1]; | 98 | buf[20] = bpdu->bridge_id.addr[1]; |
106 | buf[24] = bpdu->bridge_id.addr[2]; | 99 | buf[21] = bpdu->bridge_id.addr[2]; |
107 | buf[25] = bpdu->bridge_id.addr[3]; | 100 | buf[22] = bpdu->bridge_id.addr[3]; |
108 | buf[26] = bpdu->bridge_id.addr[4]; | 101 | buf[23] = bpdu->bridge_id.addr[4]; |
109 | buf[27] = bpdu->bridge_id.addr[5]; | 102 | buf[24] = bpdu->bridge_id.addr[5]; |
110 | buf[28] = (bpdu->port_id >> 8) & 0xFF; | 103 | buf[25] = (bpdu->port_id >> 8) & 0xFF; |
111 | buf[29] = bpdu->port_id & 0xFF; | 104 | buf[26] = bpdu->port_id & 0xFF; |
112 | 105 | ||
113 | br_set_ticks(buf+30, bpdu->message_age); | 106 | br_set_ticks(buf+27, bpdu->message_age); |
114 | br_set_ticks(buf+32, bpdu->max_age); | 107 | br_set_ticks(buf+29, bpdu->max_age); |
115 | br_set_ticks(buf+34, bpdu->hello_time); | 108 | br_set_ticks(buf+31, bpdu->hello_time); |
116 | br_set_ticks(buf+36, bpdu->forward_delay); | 109 | br_set_ticks(buf+33, bpdu->forward_delay); |
117 | 110 | ||
118 | br_send_bpdu(p, buf, 38); | 111 | br_send_bpdu(p, buf, 35); |
119 | } | 112 | } |
120 | 113 | ||
121 | /* called under bridge lock */ | 114 | /* called under bridge lock */ |
122 | void br_send_tcn_bpdu(struct net_bridge_port *p) | 115 | void br_send_tcn_bpdu(struct net_bridge_port *p) |
123 | { | 116 | { |
124 | unsigned char buf[7]; | 117 | unsigned char buf[4]; |
125 | 118 | ||
126 | buf[0] = 0x42; | 119 | buf[0] = 0; |
127 | buf[1] = 0x42; | 120 | buf[1] = 0; |
128 | buf[2] = 0x03; | 121 | buf[2] = 0; |
129 | buf[3] = 0; | 122 | buf[3] = BPDU_TYPE_TCN; |
130 | buf[4] = 0; | ||
131 | buf[5] = 0; | ||
132 | buf[6] = BPDU_TYPE_TCN; | ||
133 | br_send_bpdu(p, buf, 7); | 123 | br_send_bpdu(p, buf, 7); |
134 | } | 124 | } |
135 | 125 | ||