45
45
#include <net/atmclip.h>
46
46
47
47
static struct net_device * clip_devs ;
48
- static struct atm_vcc * atmarpd ;
48
+ static struct atm_vcc __rcu * atmarpd ;
49
+ static DEFINE_MUTEX (atmarpd_lock );
49
50
static struct timer_list idle_timer ;
50
51
static const struct neigh_ops clip_neigh_ops ;
51
52
52
53
static int to_atmarpd (enum atmarp_ctrl_type type , int itf , __be32 ip )
53
54
{
54
55
struct sock * sk ;
55
56
struct atmarp_ctrl * ctrl ;
57
+ struct atm_vcc * vcc ;
56
58
struct sk_buff * skb ;
59
+ int err = 0 ;
57
60
58
61
pr_debug ("(%d)\n" , type );
59
- if (!atmarpd )
60
- return - EUNATCH ;
62
+
63
+ rcu_read_lock ();
64
+ vcc = rcu_dereference (atmarpd );
65
+ if (!vcc ) {
66
+ err = - EUNATCH ;
67
+ goto unlock ;
68
+ }
61
69
skb = alloc_skb (sizeof (struct atmarp_ctrl ), GFP_ATOMIC );
62
- if (!skb )
63
- return - ENOMEM ;
70
+ if (!skb ) {
71
+ err = - ENOMEM ;
72
+ goto unlock ;
73
+ }
64
74
ctrl = skb_put (skb , sizeof (struct atmarp_ctrl ));
65
75
ctrl -> type = type ;
66
76
ctrl -> itf_num = itf ;
67
77
ctrl -> ip = ip ;
68
- atm_force_charge (atmarpd , skb -> truesize );
78
+ atm_force_charge (vcc , skb -> truesize );
69
79
70
- sk = sk_atm (atmarpd );
80
+ sk = sk_atm (vcc );
71
81
skb_queue_tail (& sk -> sk_receive_queue , skb );
72
82
sk -> sk_data_ready (sk );
73
- return 0 ;
83
+ unlock :
84
+ rcu_read_unlock ();
85
+ return err ;
74
86
}
75
87
76
88
static void link_vcc (struct clip_vcc * clip_vcc , struct atmarp_entry * entry )
@@ -417,6 +429,8 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout)
417
429
418
430
if (!vcc -> push )
419
431
return - EBADFD ;
432
+ if (vcc -> user_back )
433
+ return - EINVAL ;
420
434
clip_vcc = kmalloc (sizeof (struct clip_vcc ), GFP_KERNEL );
421
435
if (!clip_vcc )
422
436
return - ENOMEM ;
@@ -607,10 +621,12 @@ static void atmarpd_close(struct atm_vcc *vcc)
607
621
{
608
622
pr_debug ("\n" );
609
623
610
- rtnl_lock ();
611
- atmarpd = NULL ;
624
+ mutex_lock (& atmarpd_lock );
625
+ RCU_INIT_POINTER (atmarpd , NULL );
626
+ mutex_unlock (& atmarpd_lock );
627
+
628
+ synchronize_rcu ();
612
629
skb_queue_purge (& sk_atm (vcc )-> sk_receive_queue );
613
- rtnl_unlock ();
614
630
615
631
pr_debug ("(done)\n" );
616
632
module_put (THIS_MODULE );
@@ -631,15 +647,18 @@ static struct atm_dev atmarpd_dev = {
631
647
632
648
static int atm_init_atmarp (struct atm_vcc * vcc )
633
649
{
634
- rtnl_lock ();
650
+ if (vcc -> push == clip_push )
651
+ return - EINVAL ;
652
+
653
+ mutex_lock (& atmarpd_lock );
635
654
if (atmarpd ) {
636
- rtnl_unlock ( );
655
+ mutex_unlock ( & atmarpd_lock );
637
656
return - EADDRINUSE ;
638
657
}
639
658
640
659
mod_timer (& idle_timer , jiffies + CLIP_CHECK_INTERVAL * HZ );
641
660
642
- atmarpd = vcc ;
661
+ rcu_assign_pointer ( atmarpd , vcc ) ;
643
662
set_bit (ATM_VF_META , & vcc -> flags );
644
663
set_bit (ATM_VF_READY , & vcc -> flags );
645
664
/* allow replies and avoid getting closed if signaling dies */
@@ -648,13 +667,14 @@ static int atm_init_atmarp(struct atm_vcc *vcc)
648
667
vcc -> push = NULL ;
649
668
vcc -> pop = NULL ; /* crash */
650
669
vcc -> push_oam = NULL ; /* crash */
651
- rtnl_unlock ( );
670
+ mutex_unlock ( & atmarpd_lock );
652
671
return 0 ;
653
672
}
654
673
655
674
static int clip_ioctl (struct socket * sock , unsigned int cmd , unsigned long arg )
656
675
{
657
676
struct atm_vcc * vcc = ATM_SD (sock );
677
+ struct sock * sk = sock -> sk ;
658
678
int err = 0 ;
659
679
660
680
switch (cmd ) {
@@ -675,14 +695,18 @@ static int clip_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
675
695
err = clip_create (arg );
676
696
break ;
677
697
case ATMARPD_CTRL :
698
+ lock_sock (sk );
678
699
err = atm_init_atmarp (vcc );
679
700
if (!err ) {
680
701
sock -> state = SS_CONNECTED ;
681
702
__module_get (THIS_MODULE );
682
703
}
704
+ release_sock (sk );
683
705
break ;
684
706
case ATMARP_MKIP :
707
+ lock_sock (sk );
685
708
err = clip_mkip (vcc , arg );
709
+ release_sock (sk );
686
710
break ;
687
711
case ATMARP_SETENTRY :
688
712
err = clip_setentry (vcc , (__force __be32 )arg );
0 commit comments