]> git.neil.brown.name Git - history.git/commitdiff
[AX25]: Fix ax25_cb locking.
authorJeroen Vreeken <pe1rxq@amsat.org>
Thu, 21 Aug 2003 05:04:47 +0000 (22:04 -0700)
committerDavid S. Miller <davem@nuts.ninka.net>
Thu, 21 Aug 2003 05:04:47 +0000 (22:04 -0700)
- ax25_cb's use refcounting
- the ax25_cb list uses hlists
- Lots of socket locking.

13 files changed:
include/net/ax25.h
net/ax25/af_ax25.c
net/ax25/ax25_ds_in.c
net/ax25/ax25_ds_subr.c
net/ax25/ax25_ds_timer.c
net/ax25/ax25_in.c
net/ax25/ax25_ip.c
net/ax25/ax25_out.c
net/ax25/ax25_route.c
net/ax25/ax25_std_in.c
net/ax25/ax25_std_timer.c
net/ax25/ax25_timer.c
net/ax25/sysctl_net_ax25.c

index 6186be2896e096b17dfca69ee8b88943ea9732ec..532b480d02cbb38fc6fabb860b47d609403a2a47 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/ax25.h>
 #include <linux/spinlock.h>
 #include <linux/timer.h>
+#include <linux/list.h>
 #include <asm/atomic.h>
 
 #define        AX25_T1CLAMPLO                  1
@@ -180,7 +181,7 @@ typedef struct ax25_dev {
 } ax25_dev;
 
 typedef struct ax25_cb {
-       struct ax25_cb          *next;
+       struct hlist_node       ax25_node;
        ax25_address            source_addr, dest_addr;
        ax25_digi               *digipeat;
        ax25_dev                *ax25_dev;
@@ -197,17 +198,32 @@ typedef struct ax25_cb {
        struct sk_buff_head     ack_queue;
        struct sk_buff_head     frag_queue;
        unsigned char           window;
-       struct timer_list       timer;
+       struct timer_list       timer, dtimer;
        struct sock             *sk;            /* Backlink to socket */
+       atomic_t                refcount;
 } ax25_cb;
 
 #define ax25_sk(__sk) ((ax25_cb *)(__sk)->sk_protinfo)
 
+#define ax25_for_each(__ax25, node, list) \
+       hlist_for_each_entry(__ax25, node, list, ax25_node)
+
+#define ax25_cb_hold(__ax25) \
+       atomic_inc(&((__ax25)->refcount))
+
+static __inline__ void ax25_cb_put(ax25_cb *ax25)
+{
+       if (atomic_dec_and_test(&ax25->refcount)) {
+               if (ax25->digipeat)
+                       kfree(ax25->digipeat);
+               kfree(ax25);
+       }
+}
+
 /* af_ax25.c */
-extern ax25_cb *ax25_list;
+extern struct hlist_head ax25_list;
 extern spinlock_t ax25_list_lock;
-extern void ax25_free_cb(ax25_cb *);
-extern void ax25_insert_socket(ax25_cb *);
+extern void ax25_cb_add(ax25_cb *);
 struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int);
 struct sock *ax25_get_socket(ax25_address *, ax25_address *, int);
 extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct net_device *);
index 8892894ca9e8f98064a9ec25139bdfe57109692e..a1ebe3cb7ffbb4ece83a21f3558cdc4a72447dea 100644 (file)
 
 
 
-ax25_cb *ax25_list;
+HLIST_HEAD(ax25_list);
 spinlock_t ax25_list_lock = SPIN_LOCK_UNLOCKED;
 
 static struct proto_ops ax25_proto_ops;
 
-/*
- *     Free an allocated ax25 control block. This is done to centralise
- *     the MOD count code.
- */
-void ax25_free_cb(ax25_cb *ax25)
-{
-       if (ax25->digipeat != NULL) {
-               kfree(ax25->digipeat);
-               ax25->digipeat = NULL;
-       }
-
-       kfree(ax25);
-}
-
 static void ax25_free_sock(struct sock *sk)
 {
-       ax25_free_cb(ax25_sk(sk));
+       ax25_cb_put(ax25_sk(sk));
 }
 
 /*
  *     Socket removal during an interrupt is now safe.
  */
-static void ax25_remove_socket(ax25_cb *ax25)
+static void ax25_cb_del(ax25_cb *ax25)
 {
-       ax25_cb *s;
-
-       spin_lock_bh(&ax25_list_lock);
-       if ((s = ax25_list) == ax25) {
-               ax25_list = s->next;
+       if (!hlist_unhashed(&ax25->ax25_node)) {
+               spin_lock_bh(&ax25_list_lock);
+               hlist_del_init(&ax25->ax25_node);
                spin_unlock_bh(&ax25_list_lock);
-               return;
-       }
-
-       while (s != NULL && s->next != NULL) {
-               if (s->next == ax25) {
-                       s->next = ax25->next;
-                       spin_unlock_bh(&ax25_list_lock);
-                       return;
-               }
-
-               s = s->next;
+               ax25_cb_put(ax25);
        }
-       spin_unlock_bh(&ax25_list_lock);
 }
 
 /*
@@ -108,12 +81,13 @@ static void ax25_kill_by_device(struct net_device *dev)
 {
        ax25_dev *ax25_dev;
        ax25_cb *s;
+       struct hlist_node *node;
 
        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
                return;
 
        spin_lock_bh(&ax25_list_lock);
-       for (s = ax25_list; s != NULL; s = s->next) {
+       ax25_for_each(s, node, &ax25_list) {
                if (s->ax25_dev == ax25_dev) {
                        s->ax25_dev = NULL;
                        ax25_disconnect(s, ENETUNREACH);
@@ -153,11 +127,11 @@ static int ax25_device_event(struct notifier_block *this, unsigned long event,
 /*
  *     Add a socket to the bound sockets list.
  */
-void ax25_insert_socket(ax25_cb *ax25)
+void ax25_cb_add(ax25_cb *ax25)
 {
        spin_lock_bh(&ax25_list_lock);
-       ax25->next = ax25_list;
-       ax25_list  = ax25;
+       ax25_cb_hold(ax25);
+       hlist_add_head(&ax25->ax25_node, &ax25_list);
        spin_unlock_bh(&ax25_list_lock);
 }
 
@@ -169,17 +143,18 @@ struct sock *ax25_find_listener(ax25_address *addr, int digi,
        struct net_device *dev, int type)
 {
        ax25_cb *s;
+       struct hlist_node *node;
 
        spin_lock_bh(&ax25_list_lock);
-       for (s = ax25_list; s != NULL; s = s->next) {
+       ax25_for_each(s, node, &ax25_list) {
                if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
                        continue;
                if (s->sk && !ax25cmp(&s->source_addr, addr) &&
                    s->sk->sk_type == type && s->sk->sk_state == TCP_LISTEN) {
                        /* If device is null we match any device */
                        if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) {
+                               sock_hold(s->sk);
                                spin_unlock_bh(&ax25_list_lock);
-
                                return s->sk;
                        }
                }
@@ -197,9 +172,10 @@ struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr,
 {
        struct sock *sk = NULL;
        ax25_cb *s;
+       struct hlist_node *node;
 
        spin_lock_bh(&ax25_list_lock);
-       for (s = ax25_list; s != NULL; s = s->next) {
+       ax25_for_each(s, node, &ax25_list) {
                if (s->sk && !ax25cmp(&s->source_addr, my_addr) &&
                    !ax25cmp(&s->dest_addr, dest_addr) &&
                    s->sk->sk_type == type) {
@@ -223,9 +199,10 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
        ax25_digi *digi, struct net_device *dev)
 {
        ax25_cb *s;
+       struct hlist_node *node;
 
        spin_lock_bh(&ax25_list_lock);
-       for (s = ax25_list; s != NULL; s = s->next) {
+       ax25_for_each(s, node, &ax25_list) {
                if (s->sk && s->sk->sk_type != SOCK_SEQPACKET)
                        continue;
                if (s->ax25_dev == NULL)
@@ -240,6 +217,7 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
                                if (s->digipeat != NULL && s->digipeat->ndigi != 0)
                                        continue;
                        }
+                       ax25_cb_hold(s);
                        spin_unlock_bh(&ax25_list_lock);
 
                        return s;
@@ -257,9 +235,10 @@ struct sock *ax25_addr_match(ax25_address *addr)
 {
        struct sock *sk = NULL;
        ax25_cb *s;
+       struct hlist_node *node;
 
        spin_lock_bh(&ax25_list_lock);
-       for (s = ax25_list; s != NULL; s = s->next) {
+       ax25_for_each(s, node, &ax25_list) {
                if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 &&
                    s->sk->sk_type == SOCK_RAW) {
                        sk = s->sk;
@@ -267,6 +246,7 @@ struct sock *ax25_addr_match(ax25_address *addr)
                        break;
                }
        }
+
        spin_unlock_bh(&ax25_list_lock);
 
        return sk;
@@ -299,7 +279,16 @@ void ax25_destroy_socket(ax25_cb *);
  */
 static void ax25_destroy_timer(unsigned long data)
 {
-       ax25_destroy_socket((ax25_cb *)data);
+       ax25_cb *ax25=(ax25_cb *)data;
+       struct sock *sk;
+       
+       sk=ax25->sk;
+       
+       bh_lock_sock(sk);
+       sock_hold(sk);
+       ax25_destroy_socket(ax25);
+       bh_unlock_sock(sk);
+       sock_put(sk);
 }
 
 /*
@@ -312,7 +301,7 @@ void ax25_destroy_socket(ax25_cb *ax25)
 {
        struct sk_buff *skb;
 
-       ax25_remove_socket(ax25);
+       ax25_cb_del(ax25);
 
        ax25_stop_heartbeat(ax25);
        ax25_stop_t1timer(ax25);
@@ -337,22 +326,27 @@ void ax25_destroy_socket(ax25_cb *ax25)
 
                        kfree_skb(skb);
                }
+               while ((skb = skb_dequeue(&ax25->sk->sk_write_queue)) != NULL) {
+                       kfree_skb(skb);
+               }
        }
 
        if (ax25->sk != NULL) {
                if (atomic_read(&ax25->sk->sk_wmem_alloc) ||
                    atomic_read(&ax25->sk->sk_rmem_alloc)) {
                        /* Defer: outstanding buffers */
-                       init_timer(&ax25->timer);
-                       ax25->timer.expires  = jiffies + 10 * HZ;
-                       ax25->timer.function = ax25_destroy_timer;
-                       ax25->timer.data     = (unsigned long)ax25;
-                       add_timer(&ax25->timer);
+                       init_timer(&ax25->dtimer);
+                       ax25->dtimer.expires  = jiffies + 2 * HZ;
+                       ax25->dtimer.function = ax25_destroy_timer;
+                       ax25->dtimer.data     = (unsigned long)ax25;
+                       add_timer(&ax25->dtimer);
                } else {
-                       sock_put(ax25->sk);
+                       struct sock *sk=ax25->sk;
+                       ax25->sk=NULL;
+                       sock_put(sk);
                }
        } else {
-               ax25_free_cb(ax25);
+               ax25_cb_put(ax25);
        }
 }
 
@@ -421,7 +415,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
 
        case AX25_N2:
                if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
-                       return -EINVAL;
+                       return -EINVAL;
                ax25->n2count = 0;
                ax25->n2 = ax25_ctl.arg;
                break;
@@ -448,7 +442,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
                return -EINVAL;
          }
 
-         return 0;
+       return 0;
 }
 
 /*
@@ -507,6 +501,7 @@ ax25_cb *ax25_create_cb(void)
                return NULL;
 
        memset(ax25, 0x00, sizeof(*ax25));
+       atomic_set(&ax25->refcount, 1);
 
        skb_queue_head_init(&ax25->write_queue);
        skb_queue_head_init(&ax25->frag_queue);
@@ -655,6 +650,7 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname,
                   (sock->state != SS_UNCONNECTED ||
                    sk->sk_state == TCP_LISTEN)) {
                        res = -EADDRNOTAVAIL;
+                       dev_put(dev);
                        break;
                }
 
@@ -877,7 +873,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
                break;
        default:
                sk_free(sk);
-               ax25_free_cb(ax25);
+               ax25_cb_put(ax25);
                return NULL;
        }
 
@@ -937,6 +933,7 @@ static int ax25_release(struct socket *sock)
        if (sk == NULL)
                return 0;
 
+       sock_hold(sk);
        lock_sock(sk);
        ax25 = ax25_sk(sk);
 
@@ -944,13 +941,15 @@ static int ax25_release(struct socket *sock)
                switch (ax25->state) {
                case AX25_STATE_0:
                        ax25_disconnect(ax25, 0);
-                       goto drop;
+                       ax25_destroy_socket(ax25);
+                       break;
 
                case AX25_STATE_1:
                case AX25_STATE_2:
                        ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
                        ax25_disconnect(ax25, 0);
-                       goto drop;
+                       ax25_destroy_socket(ax25);
+                       break;
 
                case AX25_STATE_3:
                case AX25_STATE_4:
@@ -993,16 +992,14 @@ static int ax25_release(struct socket *sock)
                sk->sk_shutdown |= SEND_SHUTDOWN;
                sk->sk_state_change(sk);
                sock_set_flag(sk, SOCK_DEAD);
-               goto drop;
+               ax25_destroy_socket(ax25);
        }
 
        sock->sk   = NULL;
        sk->sk_socket = NULL;   /* Not used, but we should do this */
        release_sock(sk);
-       return 0;
- drop:
-       release_sock(sk);
-       ax25_destroy_socket(ax25);
+       sock_put(sk);
+
        return 0;
 }
 
@@ -1077,7 +1074,7 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
                ax25_fillin_cb(ax25, ax25_dev);
 
 done:
-       ax25_insert_socket(ax25);
+       ax25_cb_add(ax25);
        sk->sk_zapped = 0;
 
 out:
@@ -1093,7 +1090,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
        int addr_len, int flags)
 {
        struct sock *sk = sock->sk;
-       ax25_cb *ax25 = ax25_sk(sk);
+       ax25_cb *ax25 = ax25_sk(sk), *ax25t;
        struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
        ax25_digi *digi = NULL;
        int ct = 0, err = 0;
@@ -1199,7 +1196,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
                        goto out;
 
                ax25_fillin_cb(ax25, ax25->ax25_dev);
-               ax25_insert_socket(ax25);
+               ax25_cb_add(ax25);
        } else {
                if (ax25->ax25_dev == NULL) {
                        err = -EHOSTUNREACH;
@@ -1208,11 +1205,12 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
        }
 
        if (sk->sk_type == SOCK_SEQPACKET &&
-           ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi,
-                        ax25->ax25_dev->dev)) {
+           (ax25t=ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi,
+                        ax25->ax25_dev->dev))) {
                if (digi != NULL)
                        kfree(digi);
                err = -EADDRINUSE;              /* Already such a connection */
+               ax25_cb_put(ax25t);
                goto out;
        }
 
@@ -1273,6 +1271,8 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
                                lock_sock(sk);
                                continue;
                        }
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(sk->sk_sleep, &wait);
                        return -ERESTARTSYS;
                }
                current->state = TASK_RUNNING;
@@ -1288,10 +1288,11 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
 
        sock->state = SS_CONNECTED;
 
+       err=0;
 out:
        release_sock(sk);
 
-       return 0;
+       return err;
 }
 
 
@@ -1331,15 +1332,18 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
                if (skb)
                        break;
 
-               current->state = TASK_INTERRUPTIBLE;
                release_sock(sk);
+               current->state = TASK_INTERRUPTIBLE;
                if (flags & O_NONBLOCK)
                        return -EWOULDBLOCK;
                if (!signal_pending(tsk)) {
                        schedule();
+                       current->state = TASK_RUNNING;
                        lock_sock(sk);
                        continue;
                }
+               current->state = TASK_RUNNING;
+               remove_wait_queue(sk->sk_sleep, &wait);
                return -ERESTARTSYS;
        }
        current->state = TASK_RUNNING;
@@ -1519,7 +1523,7 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
        SOCK_DEBUG(sk, "AX.25: sendto: building packet.\n");
 
        /* Assume the worst case */
-       size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN;
+       size = len + ax25->ax25_dev->dev->hard_header_len;
 
        skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err);
        if (skb == NULL)
@@ -1780,7 +1784,7 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
                /* old structure? */
                if (cmd == SIOCAX25GETINFOOLD) {
-                       static int warned;
+                       static int warned = 0;
                        if (!warned) {
                                printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",
                                        current->comm);
@@ -1845,6 +1849,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
        int len = 0;
        off_t pos = 0;
        off_t begin = 0;
+       struct hlist_node *node;
 
        spin_lock_bh(&ax25_list_lock);
 
@@ -1853,7 +1858,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
         * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode
         */
 
-       for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {
+       ax25_for_each(ax25, node, &ax25_list) {
                len += sprintf(buffer+len, "%8.8lx %s %s%s ",
                                (long) ax25,
                                ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,
@@ -1882,10 +1887,12 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
                        ax25->paclen);
 
                if (ax25->sk != NULL) {
+                       bh_lock_sock(ax25->sk);
                        len += sprintf(buffer + len, " %d %d %ld\n",
                                atomic_read(&ax25->sk->sk_wmem_alloc),
                                atomic_read(&ax25->sk->sk_rmem_alloc),
                                ax25->sk->sk_socket != NULL ? SOCK_INODE(ax25->sk->sk_socket)->i_ino : 0L);
+                       bh_unlock_sock(ax25->sk);
                } else {
                        len += sprintf(buffer + len, " * * *\n");
                }
index 799fb20b531fe106c851becd89f4c851b3fa3d22..8adc0022cf580fe60adc82fb5f58bed34dc089d9 100644 (file)
@@ -65,6 +65,7 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                ax25->state   = AX25_STATE_3;
                ax25->n2count = 0;
                if (ax25->sk != NULL) {
+                       bh_lock_sock(ax25->sk);
                        ax25->sk->sk_state = TCP_ESTABLISHED;
                        /*
                         * For WAIT_SABM connections we will produce an accept
@@ -72,6 +73,7 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
                         */
                        if (!sock_flag(ax25->sk, SOCK_DEAD))
                                ax25->sk->sk_state_change(ax25->sk);
+                       bh_unlock_sock(ax25->sk);
                }
                ax25_dama_on(ax25);
 
index d42b8f22823f4a7203d41b52e91c137d0d276e96..89c07ce023f25d19cef6a130921e54414d4d17af 100644 (file)
@@ -40,6 +40,7 @@ void ax25_ds_nr_error_recovery(ax25_cb *ax25)
 void ax25_ds_enquiry_response(ax25_cb *ax25)
 {
        ax25_cb *ax25o;
+       struct hlist_node *node;
 
        /* Please note that neither DK4EG´s nor DG2FEF´s
         * DAMA spec mention the following behaviour as seen
@@ -80,7 +81,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
        ax25_ds_set_timer(ax25->ax25_dev);
 
        spin_lock_bh(&ax25_list_lock);
-       for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
+       ax25_for_each(ax25o, node, &ax25_list) {
                if (ax25o == ax25)
                        continue;
 
@@ -160,9 +161,10 @@ static int ax25_check_dama_slave(ax25_dev *ax25_dev)
 {
        ax25_cb *ax25;
        int res = 0;
+       struct hlist_node *node;
 
        spin_lock_bh(&ax25_list_lock);
-       for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next)
+       ax25_for_each(ax25, node, &ax25_list)
                if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) {
                        res = 1;
                        break;
index 5ac1f62cba010eea4ffb6604513ebb49ab9f9c2d..1a4660f1e7328af8c7ead391cf267da83ed729c2 100644 (file)
@@ -74,6 +74,7 @@ static void ax25_ds_timeout(unsigned long arg)
 {
        ax25_dev *ax25_dev = (struct ax25_dev *) arg;
        ax25_cb *ax25;
+       struct hlist_node *node;
 
        if (ax25_dev == NULL || !ax25_dev->dama.slave)
                return;                 /* Yikes! */
@@ -84,7 +85,7 @@ static void ax25_ds_timeout(unsigned long arg)
        }
 
        spin_lock_bh(&ax25_list_lock);
-       for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) {
+       ax25_for_each(ax25, node, &ax25_list) {
                if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
                        continue;
 
@@ -98,15 +99,26 @@ static void ax25_ds_timeout(unsigned long arg)
 
 void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
 {
+       struct sock *sk=ax25->sk;
+
+       if (sk)
+               bh_lock_sock(sk);
+
        switch (ax25->state) {
 
        case AX25_STATE_0:
                /* Magic here: If we listen() and a new link dies before it
                   is accepted() it isn't 'dead' so doesn't get removed. */
-               if (!ax25->sk || sock_flag(ax25->sk, SOCK_DESTROY) ||
-                   (ax25->sk->sk_state == TCP_LISTEN &&
-                    sock_flag(ax25->sk, SOCK_DEAD))) {
-                       ax25_destroy_socket(ax25);
+               if (!sk || sock_flag(sk, SOCK_DESTROY) ||
+                   (sk->sk_state == TCP_LISTEN &&
+                    sock_flag(sk, SOCK_DEAD))) {
+                       if (sk) {
+                               sock_hold(sk);
+                               ax25_destroy_socket(ax25);
+                               sock_put(sk);
+                               bh_unlock_sock(sk);
+                       } else
+                               ax25_destroy_socket(ax25);
                        return;
                }
                break;
@@ -115,9 +127,9 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
                /*
                 * Check the state of the receive buffer.
                 */
-               if (ax25->sk != NULL) {
-                       if (atomic_read(&ax25->sk->sk_rmem_alloc) <
-                           (ax25->sk->sk_rcvbuf / 2) &&
+               if (sk != NULL) {
+                       if (atomic_read(&sk->sk_rmem_alloc) <
+                           (sk->sk_rcvbuf / 2) &&
                            (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
                                ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
                                ax25->condition &= ~AX25_COND_ACK_PENDING;
@@ -127,6 +139,9 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
                break;
        }
 
+       if (sk)
+               bh_unlock_sock(sk);
+
        ax25_start_heartbeat(ax25);
 }
 
@@ -157,6 +172,7 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
        ax25_stop_t3timer(ax25);
 
        if (ax25->sk != NULL) {
+               bh_lock_sock(ax25->sk);
                ax25->sk->sk_state     = TCP_CLOSE;
                ax25->sk->sk_err       = 0;
                ax25->sk->sk_shutdown |= SEND_SHUTDOWN;
@@ -164,6 +180,7 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
                        ax25->sk->sk_state_change(ax25->sk);
                        sock_set_flag(ax25->sk, SOCK_DEAD);
                }
+               bh_lock_sock(ax25->sk);
        }
 }
 
index 593d9dbb080bb167a450dcd129fe03f1f10b808a..55927bde23d9d64fb0f84ed86c24a7f04ae0b6c1 100644 (file)
@@ -147,6 +147,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
        }
 
        if (ax25->sk != NULL && ax25->ax25_dev->values[AX25_VALUES_CONMODE] == 2) {
+               bh_lock_sock(ax25->sk);
                if ((!ax25->pidincl && ax25->sk->sk_protocol == pid) ||
                    ax25->pidincl) {
                        if (sock_queue_rcv_skb(ax25->sk, skb) == 0)
@@ -154,6 +155,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
                        else
                                ax25->condition |= AX25_COND_OWN_RX_BUSY;
                }
+               bh_unlock_sock(ax25->sk);
        }
 
        return queued;
@@ -329,6 +331,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
                if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
                        kfree_skb(skb);
 
+               ax25_cb_put(ax25);
                return 0;
        }
 
@@ -357,11 +360,14 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
                sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);
 
        if (sk != NULL) {
+               bh_lock_sock(sk);
                if (sk->sk_ack_backlog == sk->sk_max_ack_backlog ||
                    (make = ax25_make_new(sk, ax25_dev)) == NULL) {
                        if (mine)
                                ax25_return_dm(dev, &src, &dest, &dp);
                        kfree_skb(skb);
+                       bh_unlock_sock(sk);
+                       sock_put(sk);
 
                        return 0;
                }
@@ -374,6 +380,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
                make->sk_pair  = sk;
 
                sk->sk_ack_backlog++;
+               bh_unlock_sock(sk);
+               sock_put(sk);
        } else {
                if (!mine) {
                        kfree_skb(skb);
@@ -429,7 +437,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
 
        ax25->state = AX25_STATE_3;
 
-       ax25_insert_socket(ax25);
+       ax25_cb_add(ax25);
 
        ax25_start_heartbeat(ax25);
        ax25_start_t3timer(ax25);
index dd9b97b001a372e9acbf67b6d7b6cd15318b1728..04d711344d559e712f5389315e596684933e1fe1 100644 (file)
@@ -107,6 +107,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
        ax25_address *src, *dst;
        ax25_dev *ax25_dev;
        ax25_route _route, *route = &_route;
+       ax25_cb *ax25;
 
        dst = (ax25_address *)(bp + 1);
        src = (ax25_address *)(bp + 8);
@@ -167,9 +168,14 @@ int ax25_rebuild_header(struct sk_buff *skb)
                        skb_pull(ourskb, AX25_HEADER_LEN - 1);  /* Keep PID */
                        ourskb->nh.raw = ourskb->data;
 
-                       ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c,
-&dst_c, route->digipeat, dev);
-
+                       ax25=ax25_send_frame(
+                           ourskb, 
+                           ax25_dev->values[AX25_VALUES_PACLEN], 
+                           &src_c,
+                           &dst_c, route->digipeat, dev);
+                       if (ax25) {
+                               ax25_cb_put(ax25);
+                       }
                        goto put;
                }
        }
index e6d25e22d3acb5ae202767be2d3a8c0095b60c40..ae24914271165943d4f4a49071845bfbcf9a6d44 100644 (file)
@@ -71,7 +71,7 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
 
        if (digi != NULL) {
                if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
-                       ax25_free_cb(ax25);
+                       ax25_cb_put(ax25);
                        return NULL;
                }
                memcpy(ax25->digipeat, digi, sizeof(ax25_digi));
@@ -93,7 +93,7 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
 #endif
        }
 
-       ax25_insert_socket(ax25);
+       ax25_cb_add(ax25);
 
        ax25->state = AX25_STATE_1;
 
index 0d3bbcf07fc04ecdb9c9926cc71c90da1e286680..bdbc56a8f71e3d301e91b6eb264c2ec6cc4424d6 100644 (file)
@@ -162,6 +162,7 @@ static void ax25_rt_destroy(ax25_route *ax25_rt)
                if (ax25_rt->digipeat != NULL)
                        kfree(ax25_rt->digipeat);
                kfree(ax25_rt);
+               return;
        }
 
        /*
@@ -434,8 +435,11 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
                ax25_adjust_path(addr, ax25->digipeat);
        }
 
-       if (ax25->sk != NULL)
+       if (ax25->sk != NULL) {
+               bh_lock_sock(ax25->sk);
                ax25->sk->sk_zapped = 0;
+               bh_unlock_sock(ax25->sk);
+       }
 
 put:
        ax25_put_route(ax25_rt);
index ac30541d95a457cce467cd2f8a587c1fc73456ba..7131873322c4cec98554e5334b1899211aca835d 100644 (file)
@@ -73,10 +73,12 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
                        ax25->state   = AX25_STATE_3;
                        ax25->n2count = 0;
                        if (ax25->sk != NULL) {
+                               bh_lock_sock(ax25->sk);
                                ax25->sk->sk_state = TCP_ESTABLISHED;
                                /* For WAIT_SABM connections we will produce an accept ready socket here */
                                if (!sock_flag(ax25->sk, SOCK_DEAD))
                                        ax25->sk->sk_state_change(ax25->sk);
+                               bh_unlock_sock(ax25->sk);
                        }
                }
                break;
index efcfe1d27525592d9a171a2692d6e81d86230596..066897bc074901965b83487c30e850ee27adc105 100644 (file)
 
 void ax25_std_heartbeat_expiry(ax25_cb *ax25)
 {
+       struct sock *sk=ax25->sk;
+       
+       if (sk)
+               bh_lock_sock(sk);
+
        switch (ax25->state) {
        case AX25_STATE_0:
                /* Magic here: If we listen() and a new link dies before it
                   is accepted() it isn't 'dead' so doesn't get removed. */
-               if (!ax25->sk || sock_flag(ax25->sk, SOCK_DESTROY) ||
-                   (ax25->sk->sk_state == TCP_LISTEN &&
-                    sock_flag(ax25->sk, SOCK_DEAD))) {
-                       ax25_destroy_socket(ax25);
+               if (!sk || sock_flag(sk, SOCK_DESTROY) ||
+                   (sk->sk_state == TCP_LISTEN &&
+                    sock_flag(sk, SOCK_DEAD))) {
+                       if (sk) {
+                               sock_hold(sk);
+                               ax25_destroy_socket(ax25);
+                               bh_unlock_sock(sk);
+                               sock_put(sk);
+                       } else
+                               ax25_destroy_socket(ax25);
                        return;
                }
                break;
@@ -50,9 +61,9 @@ void ax25_std_heartbeat_expiry(ax25_cb *ax25)
                /*
                 * Check the state of the receive buffer.
                 */
-               if (ax25->sk != NULL) {
-                       if (atomic_read(&ax25->sk->sk_rmem_alloc) <
-                           (ax25->sk->sk_rcvbuf / 2) &&
+               if (sk != NULL) {
+                       if (atomic_read(&sk->sk_rmem_alloc) <
+                           (sk->sk_rcvbuf / 2) &&
                            (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
                                ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
                                ax25->condition &= ~AX25_COND_ACK_PENDING;
@@ -62,6 +73,9 @@ void ax25_std_heartbeat_expiry(ax25_cb *ax25)
                }
        }
 
+       if (sk)
+               bh_unlock_sock(sk);
+
        ax25_start_heartbeat(ax25);
 }
 
@@ -94,6 +108,7 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25)
        ax25_stop_t3timer(ax25);
 
        if (ax25->sk != NULL) {
+               bh_lock_sock(ax25->sk);
                ax25->sk->sk_state     = TCP_CLOSE;
                ax25->sk->sk_err       = 0;
                ax25->sk->sk_shutdown |= SEND_SHUTDOWN;
@@ -101,6 +116,7 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25)
                        ax25->sk->sk_state_change(ax25->sk);
                        sock_set_flag(ax25->sk, SOCK_DEAD);
                }
+               bh_unlock_sock(ax25->sk);
        }
 }
 
index 7ef07596932fdfa632ed4e9e8f12c3131a40edf5..7a6b50a14554d5cbc1390c11288c0dce4c8f7cca 100644 (file)
@@ -141,13 +141,10 @@ static void ax25_heartbeat_expiry(unsigned long param)
 {
        int proto = AX25_PROTO_STD_SIMPLEX;
        ax25_cb *ax25 = (ax25_cb *)param;
-       struct sock *sk = ax25->sk;
 
        if (ax25->ax25_dev)
                proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL];
 
-       bh_lock_sock(sk);
-
        switch (proto) {
        case AX25_PROTO_STD_SIMPLEX:
        case AX25_PROTO_STD_DUPLEX:
@@ -163,15 +160,12 @@ static void ax25_heartbeat_expiry(unsigned long param)
                break;
 #endif
        }
-       bh_unlock_sock(sk);
 }
 
 static void ax25_t1timer_expiry(unsigned long param)
 {
        ax25_cb *ax25 = (ax25_cb *)param;
-       struct sock *sk = ax25->sk;
 
-       bh_lock_sock(sk);
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
        case AX25_PROTO_STD_SIMPLEX:
        case AX25_PROTO_STD_DUPLEX:
@@ -185,15 +179,12 @@ static void ax25_t1timer_expiry(unsigned long param)
                break;
 #endif
        }
-       bh_unlock_sock(sk);
 }
 
 static void ax25_t2timer_expiry(unsigned long param)
 {
        ax25_cb *ax25 = (ax25_cb *)param;
-       struct sock *sk = ax25->sk;
 
-       bh_lock_sock(sk);
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
        case AX25_PROTO_STD_SIMPLEX:
        case AX25_PROTO_STD_DUPLEX:
@@ -207,15 +198,12 @@ static void ax25_t2timer_expiry(unsigned long param)
                break;
 #endif
        }
-       bh_unlock_sock(sk);
 }
 
 static void ax25_t3timer_expiry(unsigned long param)
 {
        ax25_cb *ax25 = (ax25_cb *)param;
-       struct sock *sk = ax25->sk;
 
-       bh_lock_sock(sk);
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
        case AX25_PROTO_STD_SIMPLEX:
        case AX25_PROTO_STD_DUPLEX:
@@ -231,15 +219,12 @@ static void ax25_t3timer_expiry(unsigned long param)
                break;
 #endif
        }
-       bh_unlock_sock(sk);
 }
 
 static void ax25_idletimer_expiry(unsigned long param)
 {
        ax25_cb *ax25 = (ax25_cb *)param;
-       struct sock *sk = ax25->sk;
 
-       bh_lock_sock(sk);
        switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
        case AX25_PROTO_STD_SIMPLEX:
        case AX25_PROTO_STD_DUPLEX:
@@ -255,5 +240,4 @@ static void ax25_idletimer_expiry(unsigned long param)
                break;
 #endif
        }
-       bh_unlock_sock(sk);
 }
index 2bfe67afa01ed1206913be4d5fd9feb7622cd00f..f67711f2ee96c51dee92fda1779cc039dd987bc4 100644 (file)
@@ -204,8 +204,10 @@ void ax25_register_sysctl(void)
        for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
                ax25_table_size += sizeof(ctl_table);
 
-       if ((ax25_table = kmalloc(ax25_table_size, GFP_ATOMIC)) == NULL)
+       if ((ax25_table = kmalloc(ax25_table_size, GFP_ATOMIC)) == NULL) {
+               spin_unlock_bh(&ax25_dev_lock);
                return;
+       }
 
        memset(ax25_table, 0x00, ax25_table_size);