diff options
Diffstat (limited to 'net/bridge/br_forward.c')
| -rw-r--r-- | net/bridge/br_forward.c | 166 |
1 files changed, 139 insertions, 27 deletions
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index bc1704ac6cd9..8dbec83e50ca 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | * 2 of the License, or (at your option) any later version. | 11 | * 2 of the License, or (at your option) any later version. |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/err.h> | ||
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 15 | #include <linux/netdevice.h> | 16 | #include <linux/netdevice.h> |
| 16 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
| @@ -18,6 +19,11 @@ | |||
| 18 | #include <linux/netfilter_bridge.h> | 19 | #include <linux/netfilter_bridge.h> |
| 19 | #include "br_private.h" | 20 | #include "br_private.h" |
| 20 | 21 | ||
| 22 | static int deliver_clone(const struct net_bridge_port *prev, | ||
| 23 | struct sk_buff *skb, | ||
| 24 | void (*__packet_hook)(const struct net_bridge_port *p, | ||
| 25 | struct sk_buff *skb)); | ||
| 26 | |||
| 21 | /* Don't forward packets to originating port or forwarding diasabled */ | 27 | /* Don't forward packets to originating port or forwarding diasabled */ |
| 22 | static inline int should_deliver(const struct net_bridge_port *p, | 28 | static inline int should_deliver(const struct net_bridge_port *p, |
| 23 | const struct sk_buff *skb) | 29 | const struct sk_buff *skb) |
| @@ -93,61 +99,167 @@ void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) | |||
| 93 | } | 99 | } |
| 94 | 100 | ||
| 95 | /* called with rcu_read_lock */ | 101 | /* called with rcu_read_lock */ |
| 96 | void br_forward(const struct net_bridge_port *to, struct sk_buff *skb) | 102 | void br_forward(const struct net_bridge_port *to, struct sk_buff *skb, struct sk_buff *skb0) |
| 97 | { | 103 | { |
| 98 | if (should_deliver(to, skb)) { | 104 | if (should_deliver(to, skb)) { |
| 99 | __br_forward(to, skb); | 105 | if (skb0) |
| 106 | deliver_clone(to, skb, __br_forward); | ||
| 107 | else | ||
| 108 | __br_forward(to, skb); | ||
| 100 | return; | 109 | return; |
| 101 | } | 110 | } |
| 102 | 111 | ||
| 103 | kfree_skb(skb); | 112 | if (!skb0) |
| 113 | kfree_skb(skb); | ||
| 104 | } | 114 | } |
| 105 | 115 | ||
| 106 | /* called under bridge lock */ | 116 | static int deliver_clone(const struct net_bridge_port *prev, |
| 107 | static void br_flood(struct net_bridge *br, struct sk_buff *skb, | 117 | struct sk_buff *skb, |
| 118 | void (*__packet_hook)(const struct net_bridge_port *p, | ||
| 119 | struct sk_buff *skb)) | ||
| 120 | { | ||
| 121 | skb = skb_clone(skb, GFP_ATOMIC); | ||
| 122 | if (!skb) { | ||
| 123 | struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; | ||
| 124 | |||
| 125 | dev->stats.tx_dropped++; | ||
| 126 | return -ENOMEM; | ||
| 127 | } | ||
| 128 | |||
| 129 | __packet_hook(prev, skb); | ||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static struct net_bridge_port *maybe_deliver( | ||
| 134 | struct net_bridge_port *prev, struct net_bridge_port *p, | ||
| 135 | struct sk_buff *skb, | ||
| 108 | void (*__packet_hook)(const struct net_bridge_port *p, | 136 | void (*__packet_hook)(const struct net_bridge_port *p, |
| 109 | struct sk_buff *skb)) | 137 | struct sk_buff *skb)) |
| 110 | { | 138 | { |
| 139 | int err; | ||
| 140 | |||
| 141 | if (!should_deliver(p, skb)) | ||
| 142 | return prev; | ||
| 143 | |||
| 144 | if (!prev) | ||
| 145 | goto out; | ||
| 146 | |||
| 147 | err = deliver_clone(prev, skb, __packet_hook); | ||
| 148 | if (err) | ||
| 149 | return ERR_PTR(err); | ||
| 150 | |||
| 151 | out: | ||
| 152 | return p; | ||
| 153 | } | ||
| 154 | |||
| 155 | /* called under bridge lock */ | ||
| 156 | static void br_flood(struct net_bridge *br, struct sk_buff *skb, | ||
| 157 | struct sk_buff *skb0, | ||
| 158 | void (*__packet_hook)(const struct net_bridge_port *p, | ||
| 159 | struct sk_buff *skb)) | ||
| 160 | { | ||
| 111 | struct net_bridge_port *p; | 161 | struct net_bridge_port *p; |
| 112 | struct net_bridge_port *prev; | 162 | struct net_bridge_port *prev; |
| 113 | 163 | ||
| 114 | prev = NULL; | 164 | prev = NULL; |
| 115 | 165 | ||
| 116 | list_for_each_entry_rcu(p, &br->port_list, list) { | 166 | list_for_each_entry_rcu(p, &br->port_list, list) { |
| 117 | if (should_deliver(p, skb)) { | 167 | prev = maybe_deliver(prev, p, skb, __packet_hook); |
| 118 | if (prev != NULL) { | 168 | if (IS_ERR(prev)) |
| 119 | struct sk_buff *skb2; | 169 | goto out; |
| 120 | |||
| 121 | if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) { | ||
| 122 | br->dev->stats.tx_dropped++; | ||
| 123 | kfree_skb(skb); | ||
| 124 | return; | ||
| 125 | } | ||
| 126 | |||
| 127 | __packet_hook(prev, skb2); | ||
| 128 | } | ||
| 129 | |||
| 130 | prev = p; | ||
| 131 | } | ||
| 132 | } | 170 | } |
| 133 | 171 | ||
| 134 | if (prev != NULL) { | 172 | if (!prev) |
| 173 | goto out; | ||
| 174 | |||
| 175 | if (skb0) | ||
| 176 | deliver_clone(prev, skb, __packet_hook); | ||
| 177 | else | ||
| 135 | __packet_hook(prev, skb); | 178 | __packet_hook(prev, skb); |
| 136 | return; | 179 | return; |
| 137 | } | ||
| 138 | 180 | ||
| 139 | kfree_skb(skb); | 181 | out: |
| 182 | if (!skb0) | ||
| 183 | kfree_skb(skb); | ||
| 140 | } | 184 | } |
| 141 | 185 | ||
| 142 | 186 | ||
| 143 | /* called with rcu_read_lock */ | 187 | /* called with rcu_read_lock */ |
| 144 | void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb) | 188 | void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb) |
| 145 | { | 189 | { |
| 146 | br_flood(br, skb, __br_deliver); | 190 | br_flood(br, skb, NULL, __br_deliver); |
| 147 | } | 191 | } |
| 148 | 192 | ||
| 149 | /* called under bridge lock */ | 193 | /* called under bridge lock */ |
| 150 | void br_flood_forward(struct net_bridge *br, struct sk_buff *skb) | 194 | void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, |
| 195 | struct sk_buff *skb2) | ||
| 196 | { | ||
| 197 | br_flood(br, skb, skb2, __br_forward); | ||
| 198 | } | ||
| 199 | |||
| 200 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING | ||
| 201 | /* called with rcu_read_lock */ | ||
| 202 | static void br_multicast_flood(struct net_bridge_mdb_entry *mdst, | ||
| 203 | struct sk_buff *skb, struct sk_buff *skb0, | ||
| 204 | void (*__packet_hook)( | ||
| 205 | const struct net_bridge_port *p, | ||
| 206 | struct sk_buff *skb)) | ||
| 207 | { | ||
| 208 | struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev; | ||
| 209 | struct net_bridge *br = netdev_priv(dev); | ||
| 210 | struct net_bridge_port *port; | ||
| 211 | struct net_bridge_port *lport, *rport; | ||
| 212 | struct net_bridge_port *prev; | ||
| 213 | struct net_bridge_port_group *p; | ||
| 214 | struct hlist_node *rp; | ||
| 215 | |||
| 216 | prev = NULL; | ||
| 217 | |||
| 218 | rp = br->router_list.first; | ||
| 219 | p = mdst ? mdst->ports : NULL; | ||
| 220 | while (p || rp) { | ||
| 221 | lport = p ? p->port : NULL; | ||
| 222 | rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) : | ||
| 223 | NULL; | ||
| 224 | |||
| 225 | port = (unsigned long)lport > (unsigned long)rport ? | ||
| 226 | lport : rport; | ||
| 227 | |||
| 228 | prev = maybe_deliver(prev, port, skb, __packet_hook); | ||
| 229 | if (IS_ERR(prev)) | ||
| 230 | goto out; | ||
| 231 | |||
| 232 | if ((unsigned long)lport >= (unsigned long)port) | ||
| 233 | p = p->next; | ||
| 234 | if ((unsigned long)rport >= (unsigned long)port) | ||
| 235 | rp = rp->next; | ||
| 236 | } | ||
| 237 | |||
| 238 | if (!prev) | ||
| 239 | goto out; | ||
| 240 | |||
| 241 | if (skb0) | ||
| 242 | deliver_clone(prev, skb, __packet_hook); | ||
| 243 | else | ||
| 244 | __packet_hook(prev, skb); | ||
| 245 | return; | ||
| 246 | |||
| 247 | out: | ||
| 248 | if (!skb0) | ||
| 249 | kfree_skb(skb); | ||
| 250 | } | ||
| 251 | |||
| 252 | /* called with rcu_read_lock */ | ||
| 253 | void br_multicast_deliver(struct net_bridge_mdb_entry *mdst, | ||
| 254 | struct sk_buff *skb) | ||
| 255 | { | ||
| 256 | br_multicast_flood(mdst, skb, NULL, __br_deliver); | ||
| 257 | } | ||
| 258 | |||
| 259 | /* called with rcu_read_lock */ | ||
| 260 | void br_multicast_forward(struct net_bridge_mdb_entry *mdst, | ||
| 261 | struct sk_buff *skb, struct sk_buff *skb2) | ||
| 151 | { | 262 | { |
| 152 | br_flood(br, skb, __br_forward); | 263 | br_multicast_flood(mdst, skb, skb2, __br_forward); |
| 153 | } | 264 | } |
| 265 | #endif | ||
