From 2b14075e9a9d56cb2d0da6d968e604b370cb11cc Mon Sep 17 00:00:00 2001 From: Jeroen Vreeken Date: Wed, 24 Dec 2003 03:37:18 -0800 Subject: [PATCH] [NET]: AX25, netrom, and rose bug fixes for 2.6.0 - 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 | 3 +-- net/ax25/af_ax25.c | 55 +++++++++++++++--------------------------- net/ax25/ax25_in.c | 13 ++++------ net/netrom/af_netrom.c | 11 +++++++-- net/rose/af_rose.c | 7 +++++- 5 files changed, 41 insertions(+), 48 deletions(-) diff --git a/include/net/ax25.h b/include/net/ax25.h index 171b92848a25e..26b5553e3cb0e 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -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 *); diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 38eaa7831b2b9..98dab588be1c3 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -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; } diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 55927bde23d9d..e7f9e67938cc2 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -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); diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 45333133d8911..97373b80b11f2 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -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; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index db94b996cb025..71a639df67615 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -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); -- 2.53.0