diff options
Diffstat (limited to 'net/bridge/br_input.c')
-rw-r--r-- | net/bridge/br_input.c | 24 |
1 files changed, 15 insertions, 9 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index d36e700f7a26..826cd5221536 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -27,8 +27,10 @@ static int br_pass_frame_up(struct sk_buff *skb) | |||
27 | struct net_bridge *br = netdev_priv(brdev); | 27 | struct net_bridge *br = netdev_priv(brdev); |
28 | struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats); | 28 | struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats); |
29 | 29 | ||
30 | u64_stats_update_begin(&brstats->syncp); | ||
30 | brstats->rx_packets++; | 31 | brstats->rx_packets++; |
31 | brstats->rx_bytes += skb->len; | 32 | brstats->rx_bytes += skb->len; |
33 | u64_stats_update_end(&brstats->syncp); | ||
32 | 34 | ||
33 | indev = skb->dev; | 35 | indev = skb->dev; |
34 | skb->dev = brdev; | 36 | skb->dev = brdev; |
@@ -37,11 +39,11 @@ static int br_pass_frame_up(struct sk_buff *skb) | |||
37 | netif_receive_skb); | 39 | netif_receive_skb); |
38 | } | 40 | } |
39 | 41 | ||
40 | /* note: already called with rcu_read_lock (preempt_disabled) */ | 42 | /* note: already called with rcu_read_lock */ |
41 | int br_handle_frame_finish(struct sk_buff *skb) | 43 | int br_handle_frame_finish(struct sk_buff *skb) |
42 | { | 44 | { |
43 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 45 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
44 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | 46 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
45 | struct net_bridge *br; | 47 | struct net_bridge *br; |
46 | struct net_bridge_fdb_entry *dst; | 48 | struct net_bridge_fdb_entry *dst; |
47 | struct net_bridge_mdb_entry *mdst; | 49 | struct net_bridge_mdb_entry *mdst; |
@@ -108,13 +110,12 @@ drop: | |||
108 | goto out; | 110 | goto out; |
109 | } | 111 | } |
110 | 112 | ||
111 | /* note: already called with rcu_read_lock (preempt_disabled) */ | 113 | /* note: already called with rcu_read_lock */ |
112 | static int br_handle_local_finish(struct sk_buff *skb) | 114 | static int br_handle_local_finish(struct sk_buff *skb) |
113 | { | 115 | { |
114 | struct net_bridge_port *p = rcu_dereference(skb->dev->br_port); | 116 | struct net_bridge_port *p = br_port_get_rcu(skb->dev); |
115 | 117 | ||
116 | if (p) | 118 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source); |
117 | br_fdb_update(p->br, p, eth_hdr(skb)->h_source); | ||
118 | return 0; /* process further */ | 119 | return 0; /* process further */ |
119 | } | 120 | } |
120 | 121 | ||
@@ -131,15 +132,18 @@ static inline int is_link_local(const unsigned char *dest) | |||
131 | } | 132 | } |
132 | 133 | ||
133 | /* | 134 | /* |
134 | * Called via br_handle_frame_hook. | ||
135 | * Return NULL if skb is handled | 135 | * Return NULL if skb is handled |
136 | * note: already called with rcu_read_lock (preempt_disabled) | 136 | * note: already called with rcu_read_lock |
137 | */ | 137 | */ |
138 | struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) | 138 | struct sk_buff *br_handle_frame(struct sk_buff *skb) |
139 | { | 139 | { |
140 | struct net_bridge_port *p; | ||
140 | const unsigned char *dest = eth_hdr(skb)->h_dest; | 141 | const unsigned char *dest = eth_hdr(skb)->h_dest; |
141 | int (*rhook)(struct sk_buff *skb); | 142 | int (*rhook)(struct sk_buff *skb); |
142 | 143 | ||
144 | if (skb->pkt_type == PACKET_LOOPBACK) | ||
145 | return skb; | ||
146 | |||
143 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) | 147 | if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) |
144 | goto drop; | 148 | goto drop; |
145 | 149 | ||
@@ -147,6 +151,8 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) | |||
147 | if (!skb) | 151 | if (!skb) |
148 | return NULL; | 152 | return NULL; |
149 | 153 | ||
154 | p = br_port_get_rcu(skb->dev); | ||
155 | |||
150 | if (unlikely(is_link_local(dest))) { | 156 | if (unlikely(is_link_local(dest))) { |
151 | /* Pause frames shouldn't be passed up by driver anyway */ | 157 | /* Pause frames shouldn't be passed up by driver anyway */ |
152 | if (skb->protocol == htons(ETH_P_PAUSE)) | 158 | if (skb->protocol == htons(ETH_P_PAUSE)) |