Commit 2b14075e authored by Jeroen Vreeken's avatar Jeroen Vreeken Committed by David S. Miller

[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
parent d049a43d
...@@ -227,8 +227,7 @@ extern void ax25_cb_add(ax25_cb *); ...@@ -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_find_listener(ax25_address *, int, struct net_device *, int);
struct sock *ax25_get_socket(ax25_address *, ax25_address *, 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 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(ax25_address *, struct sk_buff *, int);
extern void ax25_send_to_raw(struct sock *, struct sk_buff *, int);
extern void ax25_destroy_socket(ax25_cb *); extern void ax25_destroy_socket(ax25_cb *);
extern ax25_cb *ax25_create_cb(void); extern ax25_cb *ax25_create_cb(void);
extern void ax25_fillin_cb(ax25_cb *, ax25_dev *); extern void ax25_fillin_cb(ax25_cb *, ax25_dev *);
......
...@@ -228,45 +228,25 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ...@@ -228,45 +228,25 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
return NULL; return NULL;
} }
/* void ax25_send_to_raw(ax25_address *addr, struct sk_buff *skb, int proto)
* Look for any matching address - RAW sockets can bind to arbitrary names
*/
struct sock *ax25_addr_match(ax25_address *addr)
{ {
struct sock *sk = NULL;
ax25_cb *s; ax25_cb *s;
struct sk_buff *copy;
struct hlist_node *node; struct hlist_node *node;
spin_lock_bh(&ax25_list_lock); spin_lock_bh(&ax25_list_lock);
ax25_for_each(s, node, &ax25_list) { ax25_for_each(s, node, &ax25_list) {
if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 &&
s->sk->sk_type == SOCK_RAW) { s->sk->sk_type == SOCK_RAW &&
sk = s->sk; s->sk->sk_protocol == proto &&
lock_sock(sk); s->ax25_dev->dev == skb->dev &&
break; atomic_read(&s->sk->sk_rmem_alloc) <= s->sk->sk_rcvbuf) {
}
}
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) {
if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL) if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL)
return; continue;
if (sock_queue_rcv_skb(s->sk, copy) != 0)
if (sock_queue_rcv_skb(sk, copy) != 0)
kfree_skb(copy); kfree_skb(copy);
} }
}
} }
/* /*
...@@ -318,7 +298,7 @@ void ax25_destroy_socket(ax25_cb *ax25) ...@@ -318,7 +298,7 @@ void ax25_destroy_socket(ax25_cb *ax25)
ax25_cb *sax25 = ax25_sk(skb->sk); ax25_cb *sax25 = ax25_sk(skb->sk);
/* Queue the unaccepted socket for death */ /* Queue the unaccepted socket for death */
sock_set_flag(skb->sk, SOCK_DEAD); sock_orphan(skb->sk);
ax25_start_heartbeat(sax25); ax25_start_heartbeat(sax25);
sax25->state = AX25_STATE_0; sax25->state = AX25_STATE_0;
...@@ -913,6 +893,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) ...@@ -913,6 +893,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
if (oax25->digipeat != NULL) { if (oax25->digipeat != NULL) {
if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
sk_free(sk); sk_free(sk);
ax25_cb_put(ax25);
return NULL; return NULL;
} }
...@@ -934,20 +915,25 @@ static int ax25_release(struct socket *sock) ...@@ -934,20 +915,25 @@ static int ax25_release(struct socket *sock)
return 0; return 0;
sock_hold(sk); sock_hold(sk);
sock_orphan(sk);
lock_sock(sk); lock_sock(sk);
ax25 = ax25_sk(sk); ax25 = ax25_sk(sk);
if (sk->sk_type == SOCK_SEQPACKET) { if (sk->sk_type == SOCK_SEQPACKET) {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_0: case AX25_STATE_0:
release_sock(sk);
ax25_disconnect(ax25, 0); ax25_disconnect(ax25, 0);
lock_sock(sk);
ax25_destroy_socket(ax25); ax25_destroy_socket(ax25);
break; break;
case AX25_STATE_1: case AX25_STATE_1:
case AX25_STATE_2: case AX25_STATE_2:
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
release_sock(sk);
ax25_disconnect(ax25, 0); ax25_disconnect(ax25, 0);
lock_sock(sk);
ax25_destroy_socket(ax25); ax25_destroy_socket(ax25);
break; break;
...@@ -980,7 +966,6 @@ static int ax25_release(struct socket *sock) ...@@ -980,7 +966,6 @@ static int ax25_release(struct socket *sock)
sk->sk_state = TCP_CLOSE; sk->sk_state = TCP_CLOSE;
sk->sk_shutdown |= SEND_SHUTDOWN; sk->sk_shutdown |= SEND_SHUTDOWN;
sk->sk_state_change(sk); sk->sk_state_change(sk);
sock_set_flag(sk, SOCK_DEAD);
sock_set_flag(sk, SOCK_DESTROY); sock_set_flag(sk, SOCK_DESTROY);
break; break;
...@@ -991,12 +976,10 @@ static int ax25_release(struct socket *sock) ...@@ -991,12 +976,10 @@ static int ax25_release(struct socket *sock)
sk->sk_state = TCP_CLOSE; sk->sk_state = TCP_CLOSE;
sk->sk_shutdown |= SEND_SHUTDOWN; sk->sk_shutdown |= SEND_SHUTDOWN;
sk->sk_state_change(sk); sk->sk_state_change(sk);
sock_set_flag(sk, SOCK_DEAD);
ax25_destroy_socket(ax25); ax25_destroy_socket(ax25);
} }
sock->sk = NULL; sock->sk = NULL;
sk->sk_socket = NULL; /* Not used, but we should do this */
release_sock(sk); release_sock(sk);
sock_put(sk); sock_put(sk);
...@@ -1334,11 +1317,13 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -1334,11 +1317,13 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
release_sock(sk); release_sock(sk);
current->state = TASK_INTERRUPTIBLE; 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; return -EWOULDBLOCK;
}
if (!signal_pending(tsk)) { if (!signal_pending(tsk)) {
schedule(); schedule();
current->state = TASK_RUNNING;
lock_sock(sk); lock_sock(sk);
continue; continue;
} }
......
...@@ -147,7 +147,6 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) ...@@ -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) { 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) || if ((!ax25->pidincl && ax25->sk->sk_protocol == pid) ||
ax25->pidincl) { ax25->pidincl) {
if (sock_queue_rcv_skb(ax25->sk, skb) == 0) if (sock_queue_rcv_skb(ax25->sk, skb) == 0)
...@@ -155,7 +154,6 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) ...@@ -155,7 +154,6 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
else else
ax25->condition |= AX25_COND_OWN_RX_BUSY; ax25->condition |= AX25_COND_OWN_RX_BUSY;
} }
bh_unlock_sock(ax25->sk);
} }
return queued; return queued;
...@@ -195,7 +193,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -195,7 +193,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
{ {
ax25_address src, dest, *next_digi = NULL; ax25_address src, dest, *next_digi = NULL;
int type = 0, mine = 0, dama; int type = 0, mine = 0, dama;
struct sock *make, *sk, *raw; struct sock *make, *sk;
ax25_digi dp, reverse_dp; ax25_digi dp, reverse_dp;
ax25_cb *ax25; ax25_cb *ax25;
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
...@@ -243,10 +241,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *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) { if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
skb->h.raw = skb->data + 2; /* skip control and pid */ skb->h.raw = skb->data + 2; /* skip control and pid */
if ((raw = ax25_addr_match(&dest)) != NULL) { ax25_send_to_raw(&dest, skb, skb->data[1]);
ax25_send_to_raw(raw, skb, skb->data[1]);
release_sock(raw);
}
if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) {
kfree_skb(skb); kfree_skb(skb);
...@@ -381,7 +376,6 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -381,7 +376,6 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
sk->sk_ack_backlog++; sk->sk_ack_backlog++;
bh_unlock_sock(sk); bh_unlock_sock(sk);
sock_put(sk);
} else { } else {
if (!mine) { if (!mine) {
kfree_skb(skb); kfree_skb(skb);
...@@ -407,6 +401,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -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) { (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
kfree_skb(skb); kfree_skb(skb);
ax25_destroy_socket(ax25); ax25_destroy_socket(ax25);
if (sk)
sock_put(sk);
return 0; return 0;
} }
...@@ -446,6 +442,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -446,6 +442,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
if (sk) { if (sk) {
if (!sock_flag(sk, SOCK_DEAD)) if (!sock_flag(sk, SOCK_DEAD))
sk->sk_data_ready(sk, skb->len); sk->sk_data_ready(sk, skb->len);
sock_put(sk);
} else } else
kfree_skb(skb); kfree_skb(skb);
......
...@@ -532,7 +532,7 @@ static int nr_release(struct socket *sock) ...@@ -532,7 +532,7 @@ static int nr_release(struct socket *sock)
sk->sk_state = TCP_CLOSE; sk->sk_state = TCP_CLOSE;
sk->sk_shutdown |= SEND_SHUTDOWN; sk->sk_shutdown |= SEND_SHUTDOWN;
sk->sk_state_change(sk); sk->sk_state_change(sk);
sock_set_flag(sk, SOCK_DEAD); sock_orphan(sk);
sock_set_flag(sk, SOCK_DESTROY); sock_set_flag(sk, SOCK_DESTROY);
sk->sk_socket = NULL; sk->sk_socket = NULL;
break; break;
...@@ -727,6 +727,8 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -727,6 +727,8 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
lock_sock(sk); lock_sock(sk);
continue; continue;
} }
current->state = TASK_RUNNING;
remove_wait_queue(sk->sk_sleep, &wait);
return -ERESTARTSYS; return -ERESTARTSYS;
} }
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
...@@ -780,13 +782,18 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -780,13 +782,18 @@ static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
release_sock(sk); release_sock(sk);
if (flags & O_NONBLOCK) if (flags & O_NONBLOCK) {
current->state = TASK_RUNNING;
remove_wait_queue(sk->sk_sleep, &wait);
return -EWOULDBLOCK; return -EWOULDBLOCK;
}
if (!signal_pending(tsk)) { if (!signal_pending(tsk)) {
schedule(); schedule();
lock_sock(sk); lock_sock(sk);
continue; continue;
} }
current->state = TASK_RUNNING;
remove_wait_queue(sk->sk_sleep, &wait);
return -ERESTARTSYS; return -ERESTARTSYS;
} }
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
......
...@@ -812,6 +812,8 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le ...@@ -812,6 +812,8 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
schedule(); schedule();
continue; continue;
} }
current->state = TASK_RUNNING;
remove_wait_queue(sk->sk_sleep, &wait);
return -ERESTARTSYS; return -ERESTARTSYS;
} }
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
...@@ -863,8 +865,11 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -863,8 +865,11 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
release_sock(sk); release_sock(sk);
if (flags & O_NONBLOCK) if (flags & O_NONBLOCK) {
current->state = TASK_RUNNING;
remove_wait_queue(sk->sk_sleep, &wait);
return -EWOULDBLOCK; return -EWOULDBLOCK;
}
if (!signal_pending(tsk)) { if (!signal_pending(tsk)) {
schedule(); schedule();
lock_sock(sk); lock_sock(sk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment