Commit 350a19f5 authored by Jeroen Vreeken's avatar Jeroen Vreeken Committed by David S. Miller

[AX25]: Fix ax25_cb locking.

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