]> git.hungrycats.org Git - linux/commitdiff
[NET]: AX25, netrom, and rose bug fixes for 2.6.0
authorJeroen Vreeken <pe1rxq@amsat.org>
Wed, 24 Dec 2003 11:37:18 +0000 (03:37 -0800)
committerDavid S. Miller <davem@nuts.ninka.net>
Wed, 24 Dec 2003 11:37:18 +0000 (03:37 -0800)
- Fix socket locking in ax25
- Fix waitqueue handling bug in ax25
- Use sock_orphan in ax25
- Fix waitqueue handling bug in netrom and rose too
- Fix raw socket behavior in ax25

include/net/ax25.h
net/ax25/af_ax25.c
net/ax25/ax25_in.c
net/netrom/af_netrom.c
net/rose/af_rose.c

index 171b92848a25e264c9c232f66ddda77392f5495a..26b5553e3cb0e480ec8b58d6e8b3af3897f3a03e 100644 (file)
@@ -227,8 +227,7 @@ 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 *);
-extern struct sock *ax25_addr_match(ax25_address *);
-extern void ax25_send_to_raw(struct sock *, struct sk_buff *, int);
+extern void ax25_send_to_raw(ax25_address *, struct sk_buff *, int);
 extern void ax25_destroy_socket(ax25_cb *);
 extern ax25_cb *ax25_create_cb(void);
 extern void ax25_fillin_cb(ax25_cb *, ax25_dev *);
index 38eaa7831b2b9bd5ab3e405f9ec8fa246f67e14f..98dab588be1c325159660e3ffaeddd50fce3283a 100644 (file)
@@ -228,45 +228,25 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
        return NULL;
 }
 
-/*
- *     Look for any matching address - RAW sockets can bind to arbitrary names
- */
-struct sock *ax25_addr_match(ax25_address *addr)
+void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto)
 {
-       struct sock *sk = NULL;
        ax25_cb *s;
+       struct sk_buff *copy;
        struct hlist_node *node;
 
        spin_lock_bh(&ax25_list_lock);
        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;
-                       lock_sock(sk);
-                       break;
-               }
-       }
-
-       spin_unlock_bh(&ax25_list_lock);
-
-       return sk;
-}
-
-void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto)
-{
-       struct sk_buff *copy;
-       struct hlist_node *node;
-
-       sk_for_each_from(sk, node)
-               if (sk->sk_type == SOCK_RAW &&
-                   sk->sk_protocol == proto &&
-                   atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
+                   s->sk->sk_type == SOCK_RAW &&
+                   s->sk->sk_protocol == proto &&
+                   s->ax25_dev->dev == skb->dev &&
+                   atomic_read(&s->sk->sk_rmem_alloc) <= s->sk->sk_rcvbuf) {
                        if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL)
-                               return;
-
-                       if (sock_queue_rcv_skb(sk, copy) != 0)
+                               continue;
+                       if (sock_queue_rcv_skb(s->sk, copy) != 0)
                                kfree_skb(copy);
                }
+       }
 }
 
 /*
@@ -318,7 +298,7 @@ void ax25_destroy_socket(ax25_cb *ax25)
                                ax25_cb *sax25 = ax25_sk(skb->sk);
 
                                /* Queue the unaccepted socket for death */
-                               sock_set_flag(skb->sk, SOCK_DEAD);
+                               sock_orphan(skb->sk);
 
                                ax25_start_heartbeat(sax25);
                                sax25->state = AX25_STATE_0;
@@ -913,6 +893,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
        if (oax25->digipeat != NULL) {
                if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                        sk_free(sk);
+                       ax25_cb_put(ax25);
                        return NULL;
                }
 
@@ -934,20 +915,25 @@ static int ax25_release(struct socket *sock)
                return 0;
 
        sock_hold(sk);
+       sock_orphan(sk);
        lock_sock(sk);
        ax25 = ax25_sk(sk);
 
        if (sk->sk_type == SOCK_SEQPACKET) {
                switch (ax25->state) {
                case AX25_STATE_0:
+                       release_sock(sk);
                        ax25_disconnect(ax25, 0);
+                       lock_sock(sk);
                        ax25_destroy_socket(ax25);
                        break;
 
                case AX25_STATE_1:
                case AX25_STATE_2:
                        ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+                       release_sock(sk);
                        ax25_disconnect(ax25, 0);
+                       lock_sock(sk);
                        ax25_destroy_socket(ax25);
                        break;
 
@@ -980,7 +966,6 @@ static int ax25_release(struct socket *sock)
                        sk->sk_state                = TCP_CLOSE;
                        sk->sk_shutdown            |= SEND_SHUTDOWN;
                        sk->sk_state_change(sk);
-                       sock_set_flag(sk, SOCK_DEAD);
                        sock_set_flag(sk, SOCK_DESTROY);
                        break;
 
@@ -991,12 +976,10 @@ static int ax25_release(struct socket *sock)
                sk->sk_state     = TCP_CLOSE;
                sk->sk_shutdown |= SEND_SHUTDOWN;
                sk->sk_state_change(sk);
-               sock_set_flag(sk, SOCK_DEAD);
                ax25_destroy_socket(ax25);
        }
 
        sock->sk   = NULL;
-       sk->sk_socket = NULL;   /* Not used, but we should do this */
        release_sock(sk);
        sock_put(sk);
 
@@ -1334,11 +1317,13 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
 
                release_sock(sk);
                current->state = TASK_INTERRUPTIBLE;
-               if (flags & O_NONBLOCK)
+               if (flags & O_NONBLOCK) {
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(sk->sk_sleep, &wait);
                        return -EWOULDBLOCK;
+               }
                if (!signal_pending(tsk)) {
                        schedule();
-                       current->state = TASK_RUNNING;
                        lock_sock(sk);
                        continue;
                }
index 55927bde23d9d64fb0f84ed86c24a7f04ae0b6c1..e7f9e67938cc245954d221bd9c8ac47de96d6582 100644 (file)
@@ -147,7 +147,6 @@ 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)
@@ -155,7 +154,6 @@ 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;
@@ -195,7 +193,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
 {
        ax25_address src, dest, *next_digi = NULL;
        int type = 0, mine = 0, dama;
-       struct sock *make, *sk, *raw;
+       struct sock *make, *sk;
        ax25_digi dp, reverse_dp;
        ax25_cb *ax25;
        ax25_dev *ax25_dev;
@@ -243,10 +241,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
        if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
                skb->h.raw = skb->data + 2;             /* skip control and pid */
 
-               if ((raw = ax25_addr_match(&dest)) != NULL) {
-                       ax25_send_to_raw(raw, skb, skb->data[1]);
-                       release_sock(raw);
-               }
+               ax25_send_to_raw(&dest, skb, skb->data[1]);
 
                if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) {
                        kfree_skb(skb);
@@ -381,7 +376,6 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
 
                sk->sk_ack_backlog++;
                bh_unlock_sock(sk);
-               sock_put(sk);
        } else {
                if (!mine) {
                        kfree_skb(skb);
@@ -407,6 +401,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
            (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
                kfree_skb(skb);
                ax25_destroy_socket(ax25);
+               if (sk)
+                       sock_put(sk);
                return 0;
        }
 
@@ -446,6 +442,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
        if (sk) {
                if (!sock_flag(sk, SOCK_DEAD))
                        sk->sk_data_ready(sk, skb->len);
+               sock_put(sk);
        } else
                kfree_skb(skb);
 
index 45333133d89119d4174f4fe4a8be5745dac7c5af..97373b80b11f20e73913c6551480165ee2859148 100644 (file)
@@ -532,7 +532,7 @@ static int nr_release(struct socket *sock)
                sk->sk_state    = TCP_CLOSE;
                sk->sk_shutdown |= SEND_SHUTDOWN;
                sk->sk_state_change(sk);
-               sock_set_flag(sk, SOCK_DEAD);
+               sock_orphan(sk);
                sock_set_flag(sk, SOCK_DESTROY);
                sk->sk_socket   = NULL;
                break;
@@ -727,6 +727,8 @@ static int nr_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;
@@ -780,13 +782,18 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
 
                current->state = TASK_INTERRUPTIBLE;
                release_sock(sk);
-               if (flags & O_NONBLOCK)
+               if (flags & O_NONBLOCK) {
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(sk->sk_sleep, &wait);
                        return -EWOULDBLOCK;
+               }
                if (!signal_pending(tsk)) {
                        schedule();
                        lock_sock(sk);
                        continue;
                }
+               current->state = TASK_RUNNING;
+               remove_wait_queue(sk->sk_sleep, &wait);
                return -ERESTARTSYS;
        }
        current->state = TASK_RUNNING;
index db94b996cb025899d9c7da2b7869616308d0bf13..71a639df67615a7a3b08f712e4039c8ca6ed6b6c 100644 (file)
@@ -812,6 +812,8 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
                                schedule();
                                continue;
                        }
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(sk->sk_sleep, &wait);
                        return -ERESTARTSYS;
                }
                current->state = TASK_RUNNING;
@@ -863,8 +865,11 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
 
                current->state = TASK_INTERRUPTIBLE;
                release_sock(sk);
-               if (flags & O_NONBLOCK)
+               if (flags & O_NONBLOCK) {
+                       current->state = TASK_RUNNING;
+                       remove_wait_queue(sk->sk_sleep, &wait);
                        return -EWOULDBLOCK;
+               }
                if (!signal_pending(tsk)) {
                        schedule();
                        lock_sock(sk);