aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_device.c4
-rw-r--r--net/bridge/br_forward.c21
-rw-r--r--net/bridge/br_input.c48
-rw-r--r--net/bridge/br_private.h8
4 files changed, 31 insertions, 50 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 0eded176ce99..99292e8e1d0f 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -41,11 +41,11 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
41 skb_pull(skb, ETH_HLEN); 41 skb_pull(skb, ETH_HLEN);
42 42
43 if (dest[0] & 1) 43 if (dest[0] & 1)
44 br_flood_deliver(br, skb, 0); 44 br_flood_deliver(br, skb);
45 else if ((dst = __br_fdb_get(br, dest)) != NULL) 45 else if ((dst = __br_fdb_get(br, dest)) != NULL)
46 br_deliver(dst->dst, skb); 46 br_deliver(dst->dst, skb);
47 else 47 else
48 br_flood_deliver(br, skb, 0); 48 br_flood_deliver(br, skb);
49 49
50 return 0; 50 return 0;
51} 51}
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
index ada7f495445c..bdd7c35c3c7b 100644
--- a/net/bridge/br_forward.c
+++ b/net/bridge/br_forward.c
@@ -100,24 +100,13 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
100} 100}
101 101
102/* called under bridge lock */ 102/* called under bridge lock */
103static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone, 103static void br_flood(struct net_bridge *br, struct sk_buff *skb,
104 void (*__packet_hook)(const struct net_bridge_port *p, 104 void (*__packet_hook)(const struct net_bridge_port *p,
105 struct sk_buff *skb)) 105 struct sk_buff *skb))
106{ 106{
107 struct net_bridge_port *p; 107 struct net_bridge_port *p;
108 struct net_bridge_port *prev; 108 struct net_bridge_port *prev;
109 109
110 if (clone) {
111 struct sk_buff *skb2;
112
113 if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
114 br->statistics.tx_dropped++;
115 return;
116 }
117
118 skb = skb2;
119 }
120
121 prev = NULL; 110 prev = NULL;
122 111
123 list_for_each_entry_rcu(p, &br->port_list, list) { 112 list_for_each_entry_rcu(p, &br->port_list, list) {
@@ -148,13 +137,13 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
148 137
149 138
150/* called with rcu_read_lock */ 139/* called with rcu_read_lock */
151void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone) 140void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
152{ 141{
153 br_flood(br, skb, clone, __br_deliver); 142 br_flood(br, skb, __br_deliver);
154} 143}
155 144
156/* called under bridge lock */ 145/* called under bridge lock */
157void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone) 146void br_flood_forward(struct net_bridge *br, struct sk_buff *skb)
158{ 147{
159 br_flood(br, skb, clone, __br_forward); 148 br_flood(br, skb, __br_forward);
160} 149}
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 6f468fc3357a..3a8a015c92e0 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -43,7 +43,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
43 struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); 43 struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
44 struct net_bridge *br; 44 struct net_bridge *br;
45 struct net_bridge_fdb_entry *dst; 45 struct net_bridge_fdb_entry *dst;
46 int passedup = 0; 46 struct sk_buff *skb2;
47 47
48 if (!p || p->state == BR_STATE_DISABLED) 48 if (!p || p->state == BR_STATE_DISABLED)
49 goto drop; 49 goto drop;
@@ -55,39 +55,35 @@ int br_handle_frame_finish(struct sk_buff *skb)
55 if (p->state == BR_STATE_LEARNING) 55 if (p->state == BR_STATE_LEARNING)
56 goto drop; 56 goto drop;
57 57
58 if (br->dev->flags & IFF_PROMISC) { 58 /* The packet skb2 goes to the local host (NULL to skip). */
59 struct sk_buff *skb2; 59 skb2 = NULL;
60 60
61 skb2 = skb_clone(skb, GFP_ATOMIC); 61 if (br->dev->flags & IFF_PROMISC)
62 if (skb2 != NULL) { 62 skb2 = skb;
63 passedup = 1; 63
64 br_pass_frame_up(br, skb2); 64 dst = NULL;
65 }
66 }
67 65
68 if (is_multicast_ether_addr(dest)) { 66 if (is_multicast_ether_addr(dest)) {
69 br->statistics.multicast++; 67 br->statistics.multicast++;
70 br_flood_forward(br, skb, !passedup); 68 skb2 = skb;
71 if (!passedup) 69 } else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
72 br_pass_frame_up(br, skb); 70 skb2 = skb;
73 goto out; 71 /* Do not forward the packet since it's local. */
72 skb = NULL;
74 } 73 }
75 74
76 dst = __br_fdb_get(br, dest); 75 if (skb2 == skb)
77 if (dst != NULL && dst->is_local) { 76 skb2 = skb_clone(skb, GFP_ATOMIC);
78 if (!passedup)
79 br_pass_frame_up(br, skb);
80 else
81 kfree_skb(skb);
82 goto out;
83 }
84 77
85 if (dst != NULL) { 78 if (skb2)
86 br_forward(dst->dst, skb); 79 br_pass_frame_up(br, skb2);
87 goto out;
88 }
89 80
90 br_flood_forward(br, skb, 0); 81 if (skb) {
82 if (dst)
83 br_forward(dst->dst, skb);
84 else
85 br_flood_forward(br, skb);
86 }
91 87
92out: 88out:
93 return 0; 89 return 0;
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 21bf3a9a03fd..e6dc6f52990d 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -170,12 +170,8 @@ extern int br_dev_queue_push_xmit(struct sk_buff *skb);
170extern void br_forward(const struct net_bridge_port *to, 170extern void br_forward(const struct net_bridge_port *to,
171 struct sk_buff *skb); 171 struct sk_buff *skb);
172extern int br_forward_finish(struct sk_buff *skb); 172extern int br_forward_finish(struct sk_buff *skb);
173extern void br_flood_deliver(struct net_bridge *br, 173extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
174 struct sk_buff *skb, 174extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb);
175 int clone);
176extern void br_flood_forward(struct net_bridge *br,
177 struct sk_buff *skb,
178 int clone);
179 175
180/* br_if.c */ 176/* br_if.c */
181extern void br_port_carrier_check(struct net_bridge_port *p); 177extern void br_port_carrier_check(struct net_bridge_port *p);