diff options
Diffstat (limited to 'net/packet/af_packet.c')
-rw-r--r-- | net/packet/af_packet.c | 69 |
1 files changed, 42 insertions, 27 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index ac27c86ef6d1..88cfbc189558 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -237,6 +237,30 @@ struct packet_skb_cb { | |||
237 | static void __fanout_unlink(struct sock *sk, struct packet_sock *po); | 237 | static void __fanout_unlink(struct sock *sk, struct packet_sock *po); |
238 | static void __fanout_link(struct sock *sk, struct packet_sock *po); | 238 | static void __fanout_link(struct sock *sk, struct packet_sock *po); |
239 | 239 | ||
240 | static struct net_device *packet_cached_dev_get(struct packet_sock *po) | ||
241 | { | ||
242 | struct net_device *dev; | ||
243 | |||
244 | rcu_read_lock(); | ||
245 | dev = rcu_dereference(po->cached_dev); | ||
246 | if (likely(dev)) | ||
247 | dev_hold(dev); | ||
248 | rcu_read_unlock(); | ||
249 | |||
250 | return dev; | ||
251 | } | ||
252 | |||
253 | static void packet_cached_dev_assign(struct packet_sock *po, | ||
254 | struct net_device *dev) | ||
255 | { | ||
256 | rcu_assign_pointer(po->cached_dev, dev); | ||
257 | } | ||
258 | |||
259 | static void packet_cached_dev_reset(struct packet_sock *po) | ||
260 | { | ||
261 | RCU_INIT_POINTER(po->cached_dev, NULL); | ||
262 | } | ||
263 | |||
240 | /* register_prot_hook must be invoked with the po->bind_lock held, | 264 | /* register_prot_hook must be invoked with the po->bind_lock held, |
241 | * or from a context in which asynchronous accesses to the packet | 265 | * or from a context in which asynchronous accesses to the packet |
242 | * socket is not possible (packet_create()). | 266 | * socket is not possible (packet_create()). |
@@ -246,12 +270,10 @@ static void register_prot_hook(struct sock *sk) | |||
246 | struct packet_sock *po = pkt_sk(sk); | 270 | struct packet_sock *po = pkt_sk(sk); |
247 | 271 | ||
248 | if (!po->running) { | 272 | if (!po->running) { |
249 | if (po->fanout) { | 273 | if (po->fanout) |
250 | __fanout_link(sk, po); | 274 | __fanout_link(sk, po); |
251 | } else { | 275 | else |
252 | dev_add_pack(&po->prot_hook); | 276 | dev_add_pack(&po->prot_hook); |
253 | rcu_assign_pointer(po->cached_dev, po->prot_hook.dev); | ||
254 | } | ||
255 | 277 | ||
256 | sock_hold(sk); | 278 | sock_hold(sk); |
257 | po->running = 1; | 279 | po->running = 1; |
@@ -270,12 +292,11 @@ static void __unregister_prot_hook(struct sock *sk, bool sync) | |||
270 | struct packet_sock *po = pkt_sk(sk); | 292 | struct packet_sock *po = pkt_sk(sk); |
271 | 293 | ||
272 | po->running = 0; | 294 | po->running = 0; |
273 | if (po->fanout) { | 295 | |
296 | if (po->fanout) | ||
274 | __fanout_unlink(sk, po); | 297 | __fanout_unlink(sk, po); |
275 | } else { | 298 | else |
276 | __dev_remove_pack(&po->prot_hook); | 299 | __dev_remove_pack(&po->prot_hook); |
277 | RCU_INIT_POINTER(po->cached_dev, NULL); | ||
278 | } | ||
279 | 300 | ||
280 | __sock_put(sk); | 301 | __sock_put(sk); |
281 | 302 | ||
@@ -439,9 +460,9 @@ static void prb_shutdown_retire_blk_timer(struct packet_sock *po, | |||
439 | 460 | ||
440 | pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc; | 461 | pkc = tx_ring ? &po->tx_ring.prb_bdqc : &po->rx_ring.prb_bdqc; |
441 | 462 | ||
442 | spin_lock(&rb_queue->lock); | 463 | spin_lock_bh(&rb_queue->lock); |
443 | pkc->delete_blk_timer = 1; | 464 | pkc->delete_blk_timer = 1; |
444 | spin_unlock(&rb_queue->lock); | 465 | spin_unlock_bh(&rb_queue->lock); |
445 | 466 | ||
446 | prb_del_retire_blk_timer(pkc); | 467 | prb_del_retire_blk_timer(pkc); |
447 | } | 468 | } |
@@ -2059,19 +2080,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
2059 | return tp_len; | 2080 | return tp_len; |
2060 | } | 2081 | } |
2061 | 2082 | ||
2062 | static struct net_device *packet_cached_dev_get(struct packet_sock *po) | ||
2063 | { | ||
2064 | struct net_device *dev; | ||
2065 | |||
2066 | rcu_read_lock(); | ||
2067 | dev = rcu_dereference(po->cached_dev); | ||
2068 | if (dev) | ||
2069 | dev_hold(dev); | ||
2070 | rcu_read_unlock(); | ||
2071 | |||
2072 | return dev; | ||
2073 | } | ||
2074 | |||
2075 | static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | 2083 | static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) |
2076 | { | 2084 | { |
2077 | struct sk_buff *skb; | 2085 | struct sk_buff *skb; |
@@ -2088,7 +2096,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2088 | 2096 | ||
2089 | mutex_lock(&po->pg_vec_lock); | 2097 | mutex_lock(&po->pg_vec_lock); |
2090 | 2098 | ||
2091 | if (saddr == NULL) { | 2099 | if (likely(saddr == NULL)) { |
2092 | dev = packet_cached_dev_get(po); | 2100 | dev = packet_cached_dev_get(po); |
2093 | proto = po->num; | 2101 | proto = po->num; |
2094 | addr = NULL; | 2102 | addr = NULL; |
@@ -2242,7 +2250,7 @@ static int packet_snd(struct socket *sock, | |||
2242 | * Get and verify the address. | 2250 | * Get and verify the address. |
2243 | */ | 2251 | */ |
2244 | 2252 | ||
2245 | if (saddr == NULL) { | 2253 | if (likely(saddr == NULL)) { |
2246 | dev = packet_cached_dev_get(po); | 2254 | dev = packet_cached_dev_get(po); |
2247 | proto = po->num; | 2255 | proto = po->num; |
2248 | addr = NULL; | 2256 | addr = NULL; |
@@ -2451,6 +2459,8 @@ static int packet_release(struct socket *sock) | |||
2451 | 2459 | ||
2452 | spin_lock(&po->bind_lock); | 2460 | spin_lock(&po->bind_lock); |
2453 | unregister_prot_hook(sk, false); | 2461 | unregister_prot_hook(sk, false); |
2462 | packet_cached_dev_reset(po); | ||
2463 | |||
2454 | if (po->prot_hook.dev) { | 2464 | if (po->prot_hook.dev) { |
2455 | dev_put(po->prot_hook.dev); | 2465 | dev_put(po->prot_hook.dev); |
2456 | po->prot_hook.dev = NULL; | 2466 | po->prot_hook.dev = NULL; |
@@ -2506,14 +2516,17 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protoc | |||
2506 | 2516 | ||
2507 | spin_lock(&po->bind_lock); | 2517 | spin_lock(&po->bind_lock); |
2508 | unregister_prot_hook(sk, true); | 2518 | unregister_prot_hook(sk, true); |
2519 | |||
2509 | po->num = protocol; | 2520 | po->num = protocol; |
2510 | po->prot_hook.type = protocol; | 2521 | po->prot_hook.type = protocol; |
2511 | if (po->prot_hook.dev) | 2522 | if (po->prot_hook.dev) |
2512 | dev_put(po->prot_hook.dev); | 2523 | dev_put(po->prot_hook.dev); |
2513 | po->prot_hook.dev = dev; | ||
2514 | 2524 | ||
2525 | po->prot_hook.dev = dev; | ||
2515 | po->ifindex = dev ? dev->ifindex : 0; | 2526 | po->ifindex = dev ? dev->ifindex : 0; |
2516 | 2527 | ||
2528 | packet_cached_dev_assign(po, dev); | ||
2529 | |||
2517 | if (protocol == 0) | 2530 | if (protocol == 0) |
2518 | goto out_unlock; | 2531 | goto out_unlock; |
2519 | 2532 | ||
@@ -2626,7 +2639,8 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, | |||
2626 | po = pkt_sk(sk); | 2639 | po = pkt_sk(sk); |
2627 | sk->sk_family = PF_PACKET; | 2640 | sk->sk_family = PF_PACKET; |
2628 | po->num = proto; | 2641 | po->num = proto; |
2629 | RCU_INIT_POINTER(po->cached_dev, NULL); | 2642 | |
2643 | packet_cached_dev_reset(po); | ||
2630 | 2644 | ||
2631 | sk->sk_destruct = packet_sock_destruct; | 2645 | sk->sk_destruct = packet_sock_destruct; |
2632 | sk_refcnt_debug_inc(sk); | 2646 | sk_refcnt_debug_inc(sk); |
@@ -3337,6 +3351,7 @@ static int packet_notifier(struct notifier_block *this, | |||
3337 | sk->sk_error_report(sk); | 3351 | sk->sk_error_report(sk); |
3338 | } | 3352 | } |
3339 | if (msg == NETDEV_UNREGISTER) { | 3353 | if (msg == NETDEV_UNREGISTER) { |
3354 | packet_cached_dev_reset(po); | ||
3340 | po->ifindex = -1; | 3355 | po->ifindex = -1; |
3341 | if (po->prot_hook.dev) | 3356 | if (po->prot_hook.dev) |
3342 | dev_put(po->prot_hook.dev); | 3357 | dev_put(po->prot_hook.dev); |