* [PATCH] ax25 & netrom fixes for 2.6
@ 2003-08-12 17:46 Jeroen Vreeken
2003-08-12 19:48 ` Stephen Hemminger
2003-08-12 20:56 ` Stephen Hemminger
0 siblings, 2 replies; 23+ messages in thread
From: Jeroen Vreeken @ 2003-08-12 17:46 UTC (permalink / raw)
To: linux-hams; +Cc: ralf, davem, netdev
[-- Attachment #1: Type: text/plain, Size: 2056 bytes --]
Hi,
These are the same changes I send earlier in two parts against 2.6.0-test1.
I remade the diff against 2.6.0-test3 as Stephen Hemminger's patch clashed
with mine (My patch already had the fix....)
Jeroen
changes:
-fix waitqueue oops on interrupted socket call
-add refcounting like struct sock for ax25_cb
-skb allocation uses dev->hard_header_len instead off
predicted worst case.
-ax25_cb list uses hlists like struct sock
-lock sk in ax25_find_listener
-ax25_destroy_timer set from 10*HZ to 2*HZ (Tihomir Heidelberg)
-lock sock when calling ax25_destroy_socket() (Tihomir Heidelberg)
-Set ax25->sk to NULL when destroying sk (Tihomir Heidelberg)
-Empty write_queue in ax25_destroy_socket() (Tihomir Heidelberg)
-ax25_destroy_timer() doesn't share its timer with the heartbeat
timer
-lock sock in ax25_destroy_timer()
-return when destroying ax25 route (Ralf Baechle)
-Add ax25_cb_put() calls to netrom
-Initialize ax25_iface lists to NULL
-unlock linkfail_lock in ax25_linkfail_release()
-unlock listen_lock in ax25_listen_release()
-unlock_listen_lock in ax25_listen_mine()
-remove module_owner from nr_init()
-Only release/register listener in nr_set_mac_address() if
interface is up.
-Call nr_destroy_socket() with socket locked
-Free write queue in nr_destroy_socket()
-Add missing sock_[unlock/release] calls in netrom code
-nr_destroy_tmer set from 10*HZ to 2*HZ
-Fixed net_device refcounting to nr_dev_first() and nr_dev_get()
-Added nr_node & nr_neigh refcounting
-Use hlists for nr_node_list and nr_neigh_list
-Added nr_node locking
-Prevent race between freeing dev.priv and freeing dev
-Don't free dev.name on module exit
-Fix error return value from ax25_connect()
-Missing unlock in ax25_register_sysctl()
-nr_route_frame() makes a private copy of skb's instead of using
the one given, it also reserves head room using hard_header_len
from the device the packet goes out removing the need for
AX25_BPQ_HEADER_LEN
-Make ax25_cb refcounting inlined or macro.
-Additional locking in ax25
[-- Attachment #2: linux-2.6.0-test3.rxq3.diff --]
[-- Type: application/octet-stream, Size: 77054 bytes --]
diff -ru linux-2.6.0-test3/net/ax25/af_ax25.c linux-2.6.0-test1.rxq3/net/ax25/af_ax25.c
--- linux-2.6.0-test3/net/ax25/af_ax25.c 2003-08-09 06:41:26.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/af_ax25.c 2003-07-24 20:56:37.000000000 +0200
@@ -51,54 +51,25 @@
-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;
- 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;
- }
+ hlist_del_init(&ax25->ax25_node);
spin_unlock_bh(&ax25_list_lock);
+ ax25_cb_put(ax25);
}
/*
@@ -108,12 +79,13 @@
{
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 +125,11 @@
/*
* 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 +141,18 @@
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 +170,10 @@
{
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 +197,10 @@
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 +215,7 @@
if (s->digipeat != NULL && s->digipeat->ndigi != 0)
continue;
}
+ ax25_cb_hold(s);
spin_unlock_bh(&ax25_list_lock);
return s;
@@ -257,9 +233,10 @@
{
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 +244,7 @@
break;
}
}
+
spin_unlock_bh(&ax25_list_lock);
return sk;
@@ -299,7 +277,16 @@
*/
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 +299,7 @@
{
struct sk_buff *skb;
- ax25_remove_socket(ax25);
+ ax25_cb_del(ax25);
ax25_stop_heartbeat(ax25);
ax25_stop_t1timer(ax25);
@@ -337,22 +324,27 @@
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 +413,7 @@
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 +440,7 @@
return -EINVAL;
}
- return 0;
+ return 0;
}
/*
@@ -507,6 +499,7 @@
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 +648,7 @@
(sock->state != SS_UNCONNECTED ||
sk->sk_state == TCP_LISTEN)) {
res = -EADDRNOTAVAIL;
+ dev_put(dev);
break;
}
@@ -877,7 +871,7 @@
break;
default:
sk_free(sk);
- ax25_free_cb(ax25);
+ ax25_cb_put(ax25);
return NULL;
}
@@ -937,6 +931,7 @@
if (sk == NULL)
return 0;
+ sock_hold(sk);
lock_sock(sk);
ax25 = ax25_sk(sk);
@@ -944,13 +939,15 @@
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 +990,14 @@
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 +1072,7 @@
ax25_fillin_cb(ax25, ax25_dev);
done:
- ax25_insert_socket(ax25);
+ ax25_cb_add(ax25);
sk->sk_zapped = 0;
out:
@@ -1093,7 +1088,7 @@
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 +1194,7 @@
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 +1203,12 @@
}
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 +1269,8 @@
lock_sock(sk);
continue;
}
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sk_sleep, &wait);
return -ERESTARTSYS;
}
current->state = TASK_RUNNING;
@@ -1288,10 +1286,11 @@
sock->state = SS_CONNECTED;
+ err=0;
out:
release_sock(sk);
- return 0;
+ return err;
}
@@ -1331,15 +1330,18 @@
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 +1521,7 @@
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 +1782,7 @@
/* 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 +1847,7 @@
int len = 0;
off_t pos = 0;
off_t begin = 0;
+ struct hlist_node *node;
spin_lock_bh(&ax25_list_lock);
@@ -1853,7 +1856,7 @@
* 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 +1885,12 @@
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");
}
diff -ru linux-2.6.0-test3/net/ax25/ax25_ds_in.c linux-2.6.0-test1.rxq3/net/ax25/ax25_ds_in.c
--- linux-2.6.0-test3/net/ax25/ax25_ds_in.c 2003-08-09 06:38:45.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_ds_in.c 2003-07-24 20:56:38.000000000 +0200
@@ -65,6 +65,7 @@
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 @@
*/
if (!sock_flag(ax25->sk, SOCK_DEAD))
ax25->sk->sk_state_change(ax25->sk);
+ bh_unlock_sock(ax25->sk);
}
ax25_dama_on(ax25);
diff -ru linux-2.6.0-test3/net/ax25/ax25_ds_subr.c linux-2.6.0-test1.rxq3/net/ax25/ax25_ds_subr.c
--- linux-2.6.0-test3/net/ax25/ax25_ds_subr.c 2003-08-09 06:41:32.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_ds_subr.c 2003-07-24 20:56:38.000000000 +0200
@@ -40,6 +40,7 @@
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 @@
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 @@
{
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;
diff -ru linux-2.6.0-test3/net/ax25/ax25_ds_timer.c linux-2.6.0-test1.rxq3/net/ax25/ax25_ds_timer.c
--- linux-2.6.0-test3/net/ax25/ax25_ds_timer.c 2003-08-09 06:41:26.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_ds_timer.c 2003-07-24 20:56:37.000000000 +0200
@@ -74,6 +74,7 @@
{
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 @@
}
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 @@
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 @@
/*
* 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 @@
break;
}
+ if (sk)
+ bh_unlock_sock(sk);
+
ax25_start_heartbeat(ax25);
}
@@ -157,6 +172,7 @@
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 @@
ax25->sk->sk_state_change(ax25->sk);
sock_set_flag(ax25->sk, SOCK_DEAD);
}
+ bh_lock_sock(ax25->sk);
}
}
diff -ru linux-2.6.0-test3/net/ax25/ax25_iface.c linux-2.6.0-test1.rxq3/net/ax25/ax25_iface.c
--- linux-2.6.0-test3/net/ax25/ax25_iface.c 2003-08-09 06:42:13.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_iface.c 2003-07-24 20:56:37.000000000 +0200
@@ -33,20 +33,20 @@
struct protocol_struct *next;
unsigned int pid;
int (*func)(struct sk_buff *, ax25_cb *);
-} *protocol_list;
+} *protocol_list = NULL;
static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED;
static struct linkfail_struct {
struct linkfail_struct *next;
void (*func)(ax25_cb *, int);
-} *linkfail_list;
+} *linkfail_list = NULL;
static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED;
static struct listen_struct {
struct listen_struct *next;
ax25_address callsign;
struct net_device *dev;
-} *listen_list;
+} *listen_list = NULL;
static spinlock_t listen_lock = SPIN_LOCK_UNLOCKED;
int ax25_protocol_register(unsigned int pid,
@@ -129,8 +129,10 @@
spin_lock_bh(&linkfail_lock);
linkfail = linkfail_list;
- if (linkfail == NULL)
+ if (linkfail == NULL) {
+ spin_unlock_bh(&linkfail_lock);
return;
+ }
if (linkfail->func == func) {
linkfail_list = linkfail->next;
@@ -180,8 +182,10 @@
spin_lock_bh(&listen_lock);
listen = listen_list;
- if (listen == NULL)
+ if (listen == NULL) {
+ spin_unlock_bh(&listen_lock);
return;
+ }
if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
listen_list = listen->next;
@@ -226,8 +230,10 @@
spin_lock_bh(&listen_lock);
for (listen = listen_list; listen != NULL; listen = listen->next)
- if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL))
+ if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) {
+ spin_unlock_bh(&listen_lock);
return 1;
+ }
spin_unlock_bh(&listen_lock);
return 0;
diff -ru linux-2.6.0-test3/net/ax25/ax25_in.c linux-2.6.0-test1.rxq3/net/ax25/ax25_in.c
--- linux-2.6.0-test3/net/ax25/ax25_in.c 2003-08-09 06:32:47.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_in.c 2003-07-24 20:56:36.000000000 +0200
@@ -147,6 +147,7 @@
}
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 @@
else
ax25->condition |= AX25_COND_OWN_RX_BUSY;
}
+ bh_unlock_sock(ax25->sk);
}
return queued;
@@ -329,6 +331,7 @@
if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
kfree_skb(skb);
+ ax25_cb_put(ax25);
return 0;
}
@@ -357,11 +360,14 @@
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 @@
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 @@
ax25->state = AX25_STATE_3;
- ax25_insert_socket(ax25);
+ ax25_cb_add(ax25);
ax25_start_heartbeat(ax25);
ax25_start_t3timer(ax25);
diff -ru linux-2.6.0-test3/net/ax25/ax25_ip.c linux-2.6.0-test1.rxq3/net/ax25/ax25_ip.c
--- linux-2.6.0-test3/net/ax25/ax25_ip.c 2003-08-09 06:34:43.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_ip.c 2003-07-24 20:56:37.000000000 +0200
@@ -107,6 +107,7 @@
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 @@
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;
}
}
diff -ru linux-2.6.0-test3/net/ax25/ax25_out.c linux-2.6.0-test1.rxq3/net/ax25/ax25_out.c
--- linux-2.6.0-test3/net/ax25/ax25_out.c 2003-08-09 06:40:10.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_out.c 2003-07-24 20:56:38.000000000 +0200
@@ -71,7 +71,7 @@
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 @@
#endif
}
- ax25_insert_socket(ax25);
+ ax25_cb_add(ax25);
ax25->state = AX25_STATE_1;
diff -ru linux-2.6.0-test3/net/ax25/ax25_route.c linux-2.6.0-test1.rxq3/net/ax25/ax25_route.c
--- linux-2.6.0-test3/net/ax25/ax25_route.c 2003-08-09 06:38:41.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_route.c 2003-07-24 20:56:38.000000000 +0200
@@ -162,6 +162,7 @@
if (ax25_rt->digipeat != NULL)
kfree(ax25_rt->digipeat);
kfree(ax25_rt);
+ return;
}
/*
@@ -434,8 +435,11 @@
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);
diff -ru linux-2.6.0-test3/net/ax25/ax25_std_in.c linux-2.6.0-test1.rxq3/net/ax25/ax25_std_in.c
--- linux-2.6.0-test3/net/ax25/ax25_std_in.c 2003-08-09 06:39:26.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_std_in.c 2003-07-24 20:56:37.000000000 +0200
@@ -73,10 +73,12 @@
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;
diff -ru linux-2.6.0-test3/net/ax25/ax25_std_timer.c linux-2.6.0-test1.rxq3/net/ax25/ax25_std_timer.c
--- linux-2.6.0-test3/net/ax25/ax25_std_timer.c 2003-08-09 06:34:03.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_std_timer.c 2003-07-24 20:56:37.000000000 +0200
@@ -33,14 +33,25 @@
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 @@
/*
* 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 @@
}
}
+ if (sk)
+ bh_unlock_sock(sk);
+
ax25_start_heartbeat(ax25);
}
@@ -94,6 +108,7 @@
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 @@
ax25->sk->sk_state_change(ax25->sk);
sock_set_flag(ax25->sk, SOCK_DEAD);
}
+ bh_unlock_sock(ax25->sk);
}
}
diff -ru linux-2.6.0-test3/net/ax25/ax25_subr.c linux-2.6.0-test1.rxq3/net/ax25/ax25_subr.c
--- linux-2.6.0-test3/net/ax25/ax25_subr.c 2003-08-09 06:41:35.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_subr.c 2003-07-24 20:56:37.000000000 +0200
@@ -158,10 +158,10 @@
struct sk_buff *skb;
unsigned char *dptr;
- if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL)
+ if ((skb = alloc_skb(ax25->ax25_dev->dev->hard_header_len + 2, GFP_ATOMIC)) == NULL)
return;
- skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat));
+ skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len);
skb->nh.raw = skb->data;
@@ -202,10 +202,10 @@
if (dev == NULL)
return;
- if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(digi) + 1, GFP_ATOMIC)) == NULL)
+ if ((skb = alloc_skb(dev->hard_header_len + 1, GFP_ATOMIC)) == NULL)
return; /* Next SABM will get DM'd */
- skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi));
+ skb_reserve(skb, dev->hard_header_len);
skb->nh.raw = skb->data;
ax25_digi_invert(digi, &retdigi);
@@ -282,6 +282,7 @@
ax25_link_failed(ax25, reason);
if (ax25->sk != NULL) {
+ bh_lock_sock(ax25->sk);
ax25->sk->sk_state = TCP_CLOSE;
ax25->sk->sk_err = reason;
ax25->sk->sk_shutdown |= SEND_SHUTDOWN;
@@ -289,5 +290,6 @@
ax25->sk->sk_state_change(ax25->sk);
sock_set_flag(ax25->sk, SOCK_DEAD);
}
+ bh_unlock_sock(ax25->sk);
}
}
diff -ru linux-2.6.0-test3/net/ax25/ax25_timer.c linux-2.6.0-test1.rxq3/net/ax25/ax25_timer.c
--- linux-2.6.0-test3/net/ax25/ax25_timer.c 2003-08-09 06:38:16.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/ax25_timer.c 2003-07-24 20:56:38.000000000 +0200
@@ -141,13 +141,10 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
break;
#endif
}
- bh_unlock_sock(sk);
}
diff -ru linux-2.6.0-test3/net/ax25/sysctl_net_ax25.c linux-2.6.0-test1.rxq3/net/ax25/sysctl_net_ax25.c
--- linux-2.6.0-test3/net/ax25/sysctl_net_ax25.c 2003-08-09 06:41:21.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/ax25/sysctl_net_ax25.c 2003-07-24 20:56:37.000000000 +0200
@@ -12,20 +12,20 @@
#include <linux/spinlock.h>
#include <net/ax25.h>
-static int min_ipdefmode[1], max_ipdefmode[] = {1};
-static int min_axdefmode[1], max_axdefmode[] = {1};
-static int min_backoff[1], max_backoff[] = {2};
-static int min_conmode[1], max_conmode[] = {2};
+static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1};
+static int min_axdefmode[] = {0}, max_axdefmode[] = {1};
+static int min_backoff[] = {0}, max_backoff[] = {2};
+static int min_conmode[] = {0}, max_conmode[] = {2};
static int min_window[] = {1}, max_window[] = {7};
static int min_ewindow[] = {1}, max_ewindow[] = {63};
static int min_t1[] = {1}, max_t1[] = {30 * HZ};
static int min_t2[] = {1}, max_t2[] = {20 * HZ};
-static int min_t3[1], max_t3[] = {3600 * HZ};
-static int min_idle[1], max_idle[] = {65535 * HZ};
+static int min_t3[] = {0}, max_t3[] = {3600 * HZ};
+static int min_idle[] = {0}, max_idle[] = {65535 * HZ};
static int min_n2[] = {1}, max_n2[] = {31};
static int min_paclen[] = {1}, max_paclen[] = {512};
-static int min_proto[1], max_proto[] = {3};
-static int min_ds_timeout[1], max_ds_timeout[] = {65535 * HZ};
+static int min_proto[] = {0}, max_proto[] = {3};
+static int min_ds_timeout[] = {0}, max_ds_timeout[] = {65535 * HZ};
static struct ctl_table_header *ax25_table_header;
@@ -204,8 +204,10 @@
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);
diff -ru linux-2.6.0-test3/net/netrom/af_netrom.c linux-2.6.0-test1.rxq3/net/netrom/af_netrom.c
--- linux-2.6.0-test3/net/netrom/af_netrom.c 2003-08-09 06:36:46.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/netrom/af_netrom.c 2003-07-24 20:56:55.000000000 +0200
@@ -147,8 +147,10 @@
spin_lock_bh(&nr_list_lock);
sk_for_each(s, node, &nr_list)
if (!ax25cmp(&nr_sk(s)->source_addr, addr) &&
- s->sk_state == TCP_LISTEN)
+ s->sk_state == TCP_LISTEN) {
+ bh_lock_sock(s);
goto found;
+ }
s = NULL;
found:
spin_unlock_bh(&nr_list_lock);
@@ -167,8 +169,10 @@
sk_for_each(s, node, &nr_list) {
nr_cb *nr = nr_sk(s);
- if (nr->my_index == index && nr->my_id == id)
+ if (nr->my_index == index && nr->my_id == id) {
+ bh_lock_sock(s);
goto found;
+ }
}
s = NULL;
found:
@@ -190,8 +194,10 @@
nr_cb *nr = nr_sk(s);
if (nr->your_index == index && nr->your_id == id &&
- !ax25cmp(&nr->dest_addr, dest))
+ !ax25cmp(&nr->dest_addr, dest)) {
+ bh_lock_sock(s);
goto found;
+ }
}
s = NULL;
found:
@@ -206,14 +212,17 @@
{
unsigned short id = circuit;
unsigned char i, j;
+ struct sock *sk;
for (;;) {
i = id / 256;
j = id % 256;
- if (i != 0 && j != 0)
- if (nr_find_socket(i, j) == NULL)
+ if (i != 0 && j != 0) {
+ if ((sk=nr_find_socket(i, j)) == NULL)
break;
+ bh_unlock_sock(sk);
+ }
id++;
}
@@ -231,7 +240,12 @@
*/
static void nr_destroy_timer(unsigned long data)
{
- nr_destroy_socket((struct sock *)data);
+ struct sock *sk=(struct sock *)data;
+ bh_lock_sock(sk);
+ sock_hold(sk);
+ nr_destroy_socket(sk);
+ bh_unlock_sock(sk);
+ sock_put(sk);
}
/*
@@ -264,17 +278,20 @@
kfree_skb(skb);
}
+ while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) {
+ kfree_skb(skb);
+ }
if (atomic_read(&sk->sk_wmem_alloc) ||
atomic_read(&sk->sk_rmem_alloc)) {
/* Defer: outstanding buffers */
init_timer(&sk->sk_timer);
- sk->sk_timer.expires = jiffies + 10 * HZ;
+ sk->sk_timer.expires = jiffies + 2 * HZ;
sk->sk_timer.function = nr_destroy_timer;
sk->sk_timer.data = (unsigned long)sk;
add_timer(&sk->sk_timer);
} else
- sk_free(sk);
+ sock_put(sk);
}
/*
@@ -388,12 +405,15 @@
{
struct sock *sk = sock->sk;
+ lock_sock(sk);
if (sk->sk_state != TCP_LISTEN) {
memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
sk->sk_max_ack_backlog = backlog;
sk->sk_state = TCP_LISTEN;
+ release_sock(sk);
return 0;
}
+ release_sock(sk);
return -EOPNOTSUPP;
}
@@ -495,6 +515,7 @@
if (sk == NULL) return 0;
+ lock_sock(sk);
nr = nr_sk(sk);
switch (nr->state) {
@@ -528,6 +549,7 @@
}
sock->sk = NULL;
+ release_sock(sk);
return 0;
}
@@ -540,21 +562,26 @@
struct net_device *dev;
ax25_address *user, *source;
- if (!sk->sk_zapped)
+ lock_sock(sk);
+ if (!sk->sk_zapped) {
+ release_sock(sk);
return -EINVAL;
-
- if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct
-full_sockaddr_ax25))
+ }
+ if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25)) {
+ release_sock(sk);
return -EINVAL;
-
- if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25)))
+ }
+ if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) {
+ release_sock(sk);
return -EINVAL;
-
- if (addr->fsa_ax25.sax25_family != AF_NETROM)
+ }
+ if (addr->fsa_ax25.sax25_family != AF_NETROM) {
+ release_sock(sk);
return -EINVAL;
-
+ }
if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) {
SOCK_DEBUG(sk, "NET/ROM: bind failed: invalid node callsign\n");
+ release_sock(sk);
return -EADDRNOTAVAIL;
}
@@ -562,16 +589,22 @@
* Only the super user can set an arbitrary user callsign.
*/
if (addr->fsa_ax25.sax25_ndigis == 1) {
- if (!capable(CAP_NET_BIND_SERVICE))
+ if (!capable(CAP_NET_BIND_SERVICE)) {
+ dev_put(dev);
+ release_sock(sk);
return -EACCES;
+ }
nr->user_addr = addr->fsa_digipeater[0];
nr->source_addr = addr->fsa_ax25.sax25_call;
} else {
source = &addr->fsa_ax25.sax25_call;
if ((user = ax25_findbyuid(current->euid)) == NULL) {
- if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
+ if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
+ release_sock(sk);
+ dev_put(dev);
return -EPERM;
+ }
user = source;
}
@@ -583,6 +616,8 @@
nr_insert_socket(sk);
sk->sk_zapped = 0;
+ dev_put(dev);
+ release_sock(sk);
SOCK_DEBUG(sk, "NET/ROM: socket is bound\n");
return 0;
}
@@ -596,39 +631,50 @@
ax25_address *user, *source = NULL;
struct net_device *dev;
+ lock_sock(sk);
if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
sock->state = SS_CONNECTED;
+ release_sock(sk);
return 0; /* Connect completed during a ERESTARTSYS event */
}
if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
sock->state = SS_UNCONNECTED;
+ release_sock(sk);
return -ECONNREFUSED;
}
- if (sk->sk_state == TCP_ESTABLISHED)
+ if (sk->sk_state == TCP_ESTABLISHED) {
+ release_sock(sk);
return -EISCONN; /* No reconnect on a seqpacket socket */
+ }
sk->sk_state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
- if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
+ if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) {
+ release_sock(sk);
return -EINVAL;
-
- if (addr->sax25_family != AF_NETROM)
+ }
+ if (addr->sax25_family != AF_NETROM) {
+ release_sock(sk);
return -EINVAL;
-
+ }
if (sk->sk_zapped) { /* Must bind first - autobinding in this may or may not work */
sk->sk_zapped = 0;
- if ((dev = nr_dev_first()) == NULL)
+ if ((dev = nr_dev_first()) == NULL) {
+ release_sock(sk);
return -ENETUNREACH;
-
+ }
source = (ax25_address *)dev->dev_addr;
if ((user = ax25_findbyuid(current->euid)) == NULL) {
- if (ax25_uid_policy && !capable(CAP_NET_ADMIN))
+ if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
+ dev_put(dev);
+ release_sock(sk);
return -EPERM;
+ }
user = source;
}
@@ -636,12 +682,15 @@
nr->source_addr = *source;
nr->device = dev;
+ dev_put(dev);
nr_insert_socket(sk); /* Finish the bind */
}
nr->dest_addr = addr->sax25_call;
+ release_sock(sk);
circuit = nr_find_next_circuit();
+ lock_sock(sk);
nr->my_index = circuit / 256;
nr->my_id = circuit % 256;
@@ -659,8 +708,10 @@
nr_start_heartbeat(sk);
/* Now the loop */
- if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
+ if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
+ release_sock(sk);
return -EINPROGRESS;
+ }
/*
* A Connect Ack with Choke or timeout or failed routing will go to
@@ -675,8 +726,10 @@
set_current_state(TASK_INTERRUPTIBLE);
if (sk->sk_state != TCP_SYN_SENT)
break;
+ release_sock(sk);
if (!signal_pending(tsk)) {
schedule();
+ lock_sock(sk);
continue;
}
return -ERESTARTSYS;
@@ -687,10 +740,12 @@
if (sk->sk_state != TCP_ESTABLISHED) {
sock->state = SS_UNCONNECTED;
+ release_sock(sk);
return sock_error(sk); /* Always set at this point */
}
sock->state = SS_CONNECTED;
+ release_sock(sk);
return 0;
}
@@ -753,6 +808,7 @@
newsock->sk = newsk;
out:
+ release_sock(sk);
return err;
}
@@ -763,9 +819,12 @@
struct sock *sk = sock->sk;
nr_cb *nr = nr_sk(sk);
+ lock_sock(sk);
if (peer != 0) {
- if (sk->sk_state != TCP_ESTABLISHED)
+ if (sk->sk_state != TCP_ESTABLISHED) {
+ release_sock(sk);
return -ENOTCONN;
+ }
sax->fsa_ax25.sax25_family = AF_NETROM;
sax->fsa_ax25.sax25_ndigis = 1;
sax->fsa_ax25.sax25_call = nr->user_addr;
@@ -777,6 +836,7 @@
sax->fsa_ax25.sax25_call = nr->source_addr;
*uaddr_len = sizeof(struct sockaddr_ax25);
}
+ release_sock(sk);
return 0;
}
@@ -790,6 +850,7 @@
unsigned short circuit_index, circuit_id;
unsigned short peer_circuit_index, peer_circuit_id;
unsigned short frametype, flags, window, timeout;
+ int ret;
skb->sk = NULL; /* Initially we don't know who it's for */
@@ -847,7 +908,9 @@
else
nr_sk(sk)->bpqext = 0;
- return nr_process_rx_frame(sk, skb);
+ ret = nr_process_rx_frame(sk, skb);
+ bh_unlock_sock(sk);
+ return ret;
}
/*
@@ -877,6 +940,8 @@
if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog ||
(make = nr_make_new(sk)) == NULL) {
nr_transmit_refusal(skb, 0);
+ if (sk)
+ bh_unlock_sock(sk);
return 0;
}
@@ -894,7 +959,9 @@
nr_make->your_index = circuit_index;
nr_make->your_id = circuit_id;
+ bh_unlock_sock(sk);
circuit = nr_find_next_circuit();
+ bh_lock_sock(sk);
nr_make->my_index = circuit / 256;
nr_make->my_id = circuit % 256;
@@ -936,6 +1003,7 @@
if (!sock_flag(sk, SOCK_DEAD))
sk->sk_data_ready(sk, skb->len);
+ bh_unlock_sock(sk);
return 1;
}
@@ -954,28 +1022,42 @@
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
return -EINVAL;
- if (sk->sk_zapped)
- return -EADDRNOTAVAIL;
+ lock_sock(sk);
+ if (sk->sk_zapped) {
+ err = -EADDRNOTAVAIL;
+ goto out;
+ }
if (sk->sk_shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 0);
- return -EPIPE;
+ err = -EPIPE;
+ goto out;
}
- if (nr->device == NULL)
- return -ENETUNREACH;
+ if (nr->device == NULL) {
+ err = -ENETUNREACH;
+ goto out;
+ }
if (usax) {
- if (msg->msg_namelen < sizeof(sax))
- return -EINVAL;
+ if (msg->msg_namelen < sizeof(sax)) {
+ err = -EINVAL;
+ goto out;
+ }
sax = *usax;
- if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0)
- return -EISCONN;
- if (sax.sax25_family != AF_NETROM)
- return -EINVAL;
+ if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) {
+ err = -EISCONN;
+ goto out;
+ }
+ if (sax.sax25_family != AF_NETROM) {
+ err = -EINVAL;
+ goto out;
+ }
} else {
- if (sk->sk_state != TCP_ESTABLISHED)
- return -ENOTCONN;
+ if (sk->sk_state != TCP_ESTABLISHED) {
+ err = -ENOTCONN;
+ goto out;
+ }
sax.sax25_family = AF_NETROM;
sax.sax25_call = nr->dest_addr;
}
@@ -984,10 +1066,10 @@
/* Build a packet */
SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n");
- size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
+ size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
- return err;
+ goto out;
skb_reserve(skb, size - len);
@@ -1022,12 +1104,16 @@
if (sk->sk_state != TCP_ESTABLISHED) {
kfree_skb(skb);
- return -ENOTCONN;
+ err = -ENOTCONN;
+ goto out;
}
nr_output(sk, skb); /* Shove it onto the queue */
- return len;
+ err = len;
+out:
+ release_sock(sk);
+ return err;
}
static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
@@ -1044,12 +1130,17 @@
* us! We do one quick check first though
*/
- if (sk->sk_state != TCP_ESTABLISHED)
+ lock_sock(sk);
+ if (sk->sk_state != TCP_ESTABLISHED) {
+ release_sock(sk);
return -ENOTCONN;
+ }
/* Now we can treat all alike */
- if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)
+ if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) {
+ release_sock(sk);
return er;
+ }
skb->h.raw = skb->data;
copied = skb->len;
@@ -1070,6 +1161,7 @@
skb_free_datagram(sk, skb);
+ release_sock(sk);
return copied;
}
@@ -1077,13 +1169,16 @@
static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
+ int ret;
+ lock_sock(sk);
switch (cmd) {
case TIOCOUTQ: {
long amount;
amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
if (amount < 0)
amount = 0;
+ release_sock(sk);
return put_user(amount, (int *)arg);
}
@@ -1093,15 +1188,21 @@
/* These two are safe on a single CPU system as only user tasks fiddle here */
if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
amount = skb->len;
+ release_sock(sk);
return put_user(amount, (int *)arg);
}
case SIOCGSTAMP:
if (sk != NULL) {
- if (!sk->sk_stamp.tv_sec)
+ if (!sk->sk_stamp.tv_sec) {
+ release_sock(sk);
return -ENOENT;
- return copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0;
+ }
+ ret = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0;
+ release_sock(sk);
+ return ret;
}
+ release_sock(sk);
return -EINVAL;
case SIOCGIFADDR:
@@ -1114,17 +1215,21 @@
case SIOCSIFNETMASK:
case SIOCGIFMETRIC:
case SIOCSIFMETRIC:
+ release_sock(sk);
return -EINVAL;
case SIOCADDRT:
case SIOCDELRT:
case SIOCNRDECOBS:
+ release_sock(sk);
if (!capable(CAP_NET_ADMIN)) return -EPERM;
return nr_rt_ioctl(cmd, (void *)arg);
default:
+ release_sock(sk);
return dev_ioctl(cmd, (void *)arg);
}
+ release_sock(sk);
return 0;
}
@@ -1144,7 +1249,9 @@
len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n");
sk_for_each(s, node, &nr_list) {
- nr_cb *nr = nr_sk(s);
+ nr_cb *nr;
+ bh_lock_sock(s);
+ nr = nr_sk(s);
if ((dev = nr->device) == NULL)
devname = "???";
@@ -1187,7 +1294,7 @@
len = 0;
begin = pos;
}
-
+ bh_unlock_sock(s);
if (pos > offset + length)
break;
}
@@ -1256,6 +1363,7 @@
for (i = 0; i < nr_ndevs; i++) {
sprintf(dev_nr[i].name, "nr%d", i);
+ dev_nr[i].base_addr = i;
dev_nr[i].init = nr_init;
register_netdev(&dev_nr[i]);
}
@@ -1300,23 +1408,23 @@
nr_rt_free();
- ax25_protocol_release(AX25_P_NETROM);
+#ifdef CONFIG_SYSCTL
+ nr_unregister_sysctl();
+#endif
+
ax25_linkfail_release(nr_link_failed);
+ ax25_protocol_release(AX25_P_NETROM);
unregister_netdevice_notifier(&nr_dev_notifier);
-#ifdef CONFIG_SYSCTL
- nr_unregister_sysctl();
-#endif
sock_unregister(PF_NETROM);
for (i = 0; i < nr_ndevs; i++) {
if (dev_nr[i].priv != NULL) {
+ unregister_netdev(&dev_nr[i]);
kfree(dev_nr[i].priv);
dev_nr[i].priv = NULL;
- unregister_netdev(&dev_nr[i]);
}
- kfree(dev_nr[i].name);
}
kfree(dev_nr);
diff -ru linux-2.6.0-test3/net/netrom/nr_dev.c linux-2.6.0-test1.rxq3/net/netrom/nr_dev.c
--- linux-2.6.0-test3/net/netrom/nr_dev.c 2003-08-09 06:41:27.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/netrom/nr_dev.c 2003-07-24 20:56:54.000000000 +0200
@@ -159,11 +159,13 @@
{
struct sockaddr *sa = addr;
- ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
+ if (dev->flags & IFF_UP)
+ ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
memcpy(dev->dev_addr, sa->sa_data, dev->addr_len);
- ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
+ if (dev->flags & IFF_UP)
+ ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
return 0;
}
@@ -177,8 +179,8 @@
static int nr_close(struct net_device *dev)
{
- netif_stop_queue(dev);
ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
+ netif_stop_queue(dev);
return 0;
}
@@ -197,16 +199,16 @@
int nr_init(struct net_device *dev)
{
- SET_MODULE_OWNER(dev);
dev->mtu = NR_MAX_PACKET_SIZE;
dev->hard_start_xmit = nr_xmit;
dev->open = nr_open;
dev->stop = nr_close;
dev->hard_header = nr_header;
- dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
+ dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
dev->addr_len = AX25_ADDR_LEN;
dev->type = ARPHRD_NETROM;
+ dev->tx_queue_len = 40;
dev->rebuild_header = nr_rebuild_header;
dev->set_mac_address = nr_set_mac_address;
diff -ru linux-2.6.0-test3/net/netrom/nr_in.c linux-2.6.0-test1.rxq3/net/netrom/nr_in.c
--- linux-2.6.0-test3/net/netrom/nr_in.c 2003-08-09 06:34:46.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/netrom/nr_in.c 2003-07-24 20:56:55.000000000 +0200
@@ -74,6 +74,7 @@
static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
int frametype)
{
+ bh_lock_sock(sk);
switch (frametype) {
case NR_CONNACK: {
nr_cb *nr = nr_sk(sk);
@@ -102,6 +103,7 @@
default:
break;
}
+ bh_unlock_sock(sk);
return 0;
}
@@ -114,6 +116,7 @@
static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
int frametype)
{
+ bh_lock_sock(sk);
switch (frametype) {
case NR_CONNACK | NR_CHOKE_FLAG:
nr_disconnect(sk, ECONNRESET);
@@ -129,6 +132,7 @@
default:
break;
}
+ bh_unlock_sock(sk);
return 0;
}
@@ -150,6 +154,7 @@
nr = skb->data[18];
ns = skb->data[17];
+ bh_lock_sock(sk);
switch (frametype) {
case NR_CONNREQ:
nr_write_internal(sk, NR_CONNACK);
@@ -260,6 +265,7 @@
default:
break;
}
+ bh_unlock_sock(sk);
return queued;
}
diff -ru linux-2.6.0-test3/net/netrom/nr_route.c linux-2.6.0-test1.rxq3/net/netrom/nr_route.c
--- linux-2.6.0-test3/net/netrom/nr_route.c 2003-08-09 06:42:17.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/netrom/nr_route.c 2003-07-24 20:56:55.000000000 +0200
@@ -39,10 +39,45 @@
static unsigned int nr_neigh_no = 1;
-static struct nr_node *nr_node_list;
-static spinlock_t nr_node_lock;
-static struct nr_neigh *nr_neigh_list;
-static spinlock_t nr_neigh_lock;
+HLIST_HEAD(nr_node_list);
+spinlock_t nr_node_list_lock = SPIN_LOCK_UNLOCKED;
+HLIST_HEAD(nr_neigh_list);
+spinlock_t nr_neigh_list_lock = SPIN_LOCK_UNLOCKED;
+
+struct nr_node *nr_node_get(ax25_address *callsign)
+{
+ struct nr_node *found = NULL;
+ struct nr_node *nr_node;
+ struct hlist_node *node;
+
+ spin_lock_bh(&nr_node_list_lock);
+ nr_node_for_each(nr_node, node, &nr_node_list)
+ if (ax25cmp(callsign, &nr_node->callsign) == 0) {
+ nr_node_hold(nr_node);
+ found = nr_node;
+ break;
+ }
+ spin_unlock_bh(&nr_node_list_lock);
+ return found;
+}
+
+struct nr_neigh *nr_neigh_get_dev(ax25_address *callsign, struct net_device *dev)
+{
+ struct nr_neigh *found = NULL;
+ struct nr_neigh *nr_neigh;
+ struct hlist_node *node;
+
+ spin_lock_bh(&nr_neigh_list_lock);
+ nr_neigh_for_each(nr_neigh, node, &nr_neigh_list)
+ if (ax25cmp(callsign, &nr_neigh->callsign) == 0 &&
+ nr_neigh->dev == dev) {
+ nr_neigh_hold(nr_neigh);
+ found = nr_neigh;
+ break;
+ }
+ spin_unlock_bh(&nr_neigh_list_lock);
+ return found;
+}
static void nr_remove_neigh(struct nr_neigh *);
@@ -57,17 +92,16 @@
struct nr_neigh *nr_neigh;
struct nr_route nr_route;
int i, found;
+ struct net_device *odev;
- if (nr_dev_get(nr) != NULL) /* Can't add routes to ourself */
+ if ((odev=nr_dev_get(nr)) != NULL) { /* Can't add routes to ourself */
+ dev_put(odev);
return -EINVAL;
+ }
- for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
- if (ax25cmp(nr, &nr_node->callsign) == 0)
- break;
+ nr_node = nr_node_get(nr);
- for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
- if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
- break;
+ nr_neigh = nr_neigh_get_dev(ax25, dev);
/*
* The L2 link to a neighbour has failed in the past
@@ -76,24 +110,36 @@
* routes now (and not wait for a node broadcast).
*/
if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) {
- struct nr_node *node;
+ struct nr_node *nr_nodet;
+ struct hlist_node *node;
- for (node = nr_node_list; node != NULL; node = node->next)
- for (i = 0; i < node->count; i++)
- if (node->routes[i].neighbour == nr_neigh)
- if (i < node->which)
- node->which = i;
+ spin_lock_bh(&nr_node_list_lock);
+ nr_node_for_each(nr_nodet, node, &nr_node_list) {
+ nr_node_lock(nr_nodet);
+ for (i = 0; i < nr_nodet->count; i++)
+ if (nr_nodet->routes[i].neighbour == nr_neigh)
+ if (i < nr_nodet->which)
+ nr_nodet->which = i;
+ nr_node_unlock(nr_nodet);
+ }
+ spin_unlock_bh(&nr_node_list_lock);
}
if (nr_neigh != NULL)
nr_neigh->failed = 0;
- if (quality == 0 && nr_neigh != NULL && nr_node != NULL)
+ if (quality == 0 && nr_neigh != NULL && nr_node != NULL) {
+ nr_neigh_put(nr_neigh);
+ nr_node_put(nr_node);
return 0;
+ }
if (nr_neigh == NULL) {
- if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
+ if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) {
+ if (nr_node)
+ nr_node_put(nr_node);
return -ENOMEM;
+ }
nr_neigh->callsign = *ax25;
nr_neigh->digipeat = NULL;
@@ -104,48 +150,58 @@
nr_neigh->count = 0;
nr_neigh->number = nr_neigh_no++;
nr_neigh->failed = 0;
+ atomic_set(&nr_neigh->refcount, 1);
if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
kfree(nr_neigh);
+ if (nr_node)
+ nr_node_put(nr_node);
return -ENOMEM;
}
memcpy(nr_neigh->digipeat, ax25_digi,
sizeof(*ax25_digi));
}
- spin_lock_bh(&nr_neigh_lock);
- nr_neigh->next = nr_neigh_list;
- nr_neigh_list = nr_neigh;
- spin_unlock_bh(&nr_neigh_lock);
+ spin_lock_bh(&nr_neigh_list_lock);
+ hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
+ nr_neigh_hold(nr_neigh);
+ spin_unlock_bh(&nr_neigh_list_lock);
}
if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
nr_neigh->quality = quality;
if (nr_node == NULL) {
- if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL)
+ if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) {
+ if (nr_neigh)
+ nr_neigh_put(nr_neigh);
return -ENOMEM;
+ }
nr_node->callsign = *nr;
strcpy(nr_node->mnemonic, mnemonic);
nr_node->which = 0;
nr_node->count = 1;
+ atomic_set(&nr_node->refcount, 1);
+ nr_node->node_lock = SPIN_LOCK_UNLOCKED;
nr_node->routes[0].quality = quality;
nr_node->routes[0].obs_count = obs_count;
nr_node->routes[0].neighbour = nr_neigh;
- spin_lock_bh(&nr_node_lock);
- nr_node->next = nr_node_list;
- nr_node_list = nr_node;
- spin_unlock_bh(&nr_node_lock);
-
+ nr_neigh_hold(nr_neigh);
nr_neigh->count++;
+ spin_lock_bh(&nr_node_list_lock);
+ hlist_add_head(&nr_node->node_node, &nr_node_list);
+ /* refcount initialized at 1 */
+ spin_unlock_bh(&nr_node_list_lock);
+
return 0;
}
+ nr_node_lock(nr_node);
if (quality != 0)
strcpy(nr_node->mnemonic, mnemonic);
@@ -171,11 +227,13 @@
nr_node->which++;
nr_node->count++;
+ nr_neigh_hold(nr_neigh);
nr_neigh->count++;
} else {
/* It must be better than the worst */
if (quality > nr_node->routes[2].quality) {
nr_node->routes[2].neighbour->count--;
+ nr_neigh_put(nr_node->routes[2].neighbour);
if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked)
nr_remove_neigh(nr_node->routes[2].neighbour);
@@ -184,6 +242,7 @@
nr_node->routes[2].obs_count = obs_count;
nr_node->routes[2].neighbour = nr_neigh;
+ nr_neigh_hold(nr_neigh);
nr_neigh->count++;
}
}
@@ -244,62 +303,42 @@
}
}
+ nr_neigh_put(nr_neigh);
+ nr_node_unlock(nr_node);
+ nr_node_put(nr_node);
return 0;
}
-static void nr_remove_node(struct nr_node *nr_node)
+static inline void __nr_remove_node(struct nr_node *nr_node)
{
- struct nr_node *s;
-
- spin_lock_bh(&nr_node_lock);
- if ((s = nr_node_list) == nr_node) {
- nr_node_list = nr_node->next;
- spin_unlock_bh(&nr_node_lock);
- kfree(nr_node);
- return;
- }
-
- while (s != NULL && s->next != NULL) {
- if (s->next == nr_node) {
- s->next = nr_node->next;
- spin_unlock_bh(&nr_node_lock);
- kfree(nr_node);
- return;
- }
+ hlist_del_init(&nr_node->node_node);
+ nr_node_put(nr_node);
+}
- s = s->next;
- }
+#define nr_remove_node_locked(__node) \
+ __nr_remove_node(__node)
- spin_unlock_bh(&nr_node_lock);
+static void nr_remove_node(struct nr_node *nr_node)
+{
+ spin_lock_bh(&nr_node_list_lock);
+ __nr_remove_node(nr_node);
+ spin_unlock_bh(&nr_node_list_lock);
}
-static void nr_remove_neigh(struct nr_neigh *nr_neigh)
+static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh)
{
- struct nr_neigh *s;
+ hlist_del_init(&nr_neigh->neigh_node);
+ nr_neigh_put(nr_neigh);
+}
- spin_lock_bh(&nr_neigh_lock);
- if ((s = nr_neigh_list) == nr_neigh) {
- nr_neigh_list = nr_neigh->next;
- spin_unlock_bh(&nr_neigh_lock);
- if (nr_neigh->digipeat != NULL)
- kfree(nr_neigh->digipeat);
- kfree(nr_neigh);
- return;
- }
+#define nr_remove_neigh_locked(__neigh) \
+ __nr_remove_neigh(__neigh)
- while (s != NULL && s->next != NULL) {
- if (s->next == nr_neigh) {
- s->next = nr_neigh->next;
- spin_unlock_bh(&nr_neigh_lock);
- if (nr_neigh->digipeat != NULL)
- kfree(nr_neigh->digipeat);
- kfree(nr_neigh);
- return;
- }
-
- s = s->next;
- }
- spin_unlock_bh(&nr_neigh_lock);
+static void nr_remove_neigh(struct nr_neigh *nr_neigh)
+{
+ spin_lock_bh(&nr_neigh_list_lock);
+ __nr_remove_neigh(nr_neigh);
+ spin_unlock_bh(&nr_neigh_list_lock);
}
/*
@@ -312,26 +351,27 @@
struct nr_neigh *nr_neigh;
int i;
- for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
- if (ax25cmp(callsign, &nr_node->callsign) == 0)
- break;
+ nr_node = nr_node_get(callsign);
if (nr_node == NULL)
return -EINVAL;
- for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
- if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
- break;
+ nr_neigh = nr_neigh_get_dev(neighbour, dev);
- if (nr_neigh == NULL)
+ if (nr_neigh == NULL) {
+ nr_node_put(nr_node);
return -EINVAL;
+ }
+ nr_node_lock(nr_node);
for (i = 0; i < nr_node->count; i++) {
if (nr_node->routes[i].neighbour == nr_neigh) {
nr_neigh->count--;
+ nr_neigh_put(nr_neigh);
if (nr_neigh->count == 0 && !nr_neigh->locked)
nr_remove_neigh(nr_neigh);
+ nr_neigh_put(nr_neigh);
nr_node->count--;
@@ -346,11 +386,16 @@
case 2:
break;
}
+ nr_node_put(nr_node);
}
+ nr_node_unlock(nr_node);
return 0;
}
}
+ nr_neigh_put(nr_neigh);
+ nr_node_unlock(nr_node);
+ nr_node_put(nr_node);
return -EINVAL;
}
@@ -362,12 +407,12 @@
{
struct nr_neigh *nr_neigh;
- for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
- if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) {
- nr_neigh->quality = quality;
- nr_neigh->locked = 1;
- return 0;
- }
+ nr_neigh = nr_neigh_get_dev(callsign, dev);
+ if (nr_neigh) {
+ nr_neigh->quality = quality;
+ nr_neigh->locked = 1;
+ nr_neigh_put(nr_neigh);
+ return 0;
}
if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL)
@@ -382,6 +427,7 @@
nr_neigh->count = 0;
nr_neigh->number = nr_neigh_no++;
nr_neigh->failed = 0;
+ atomic_set(&nr_neigh->refcount, 1);
if (ax25_digi != NULL && ax25_digi->ndigi > 0) {
if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) {
@@ -391,10 +437,10 @@
memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi));
}
- spin_lock_bh(&nr_neigh_lock);
- nr_neigh->next = nr_neigh_list;
- nr_neigh_list = nr_neigh;
- spin_unlock_bh(&nr_neigh_lock);
+ spin_lock_bh(&nr_neigh_list_lock);
+ hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list);
+ /* refcount is initialized at 1 */
+ spin_unlock_bh(&nr_neigh_list_lock);
return 0;
}
@@ -407,9 +453,7 @@
{
struct nr_neigh *nr_neigh;
- for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
- if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
- break;
+ nr_neigh = nr_neigh_get_dev(callsign, dev);
if (nr_neigh == NULL) return -EINVAL;
@@ -418,6 +462,7 @@
if (nr_neigh->count == 0)
nr_remove_neigh(nr_neigh);
+ nr_neigh_put(nr_neigh);
return 0;
}
@@ -430,15 +475,13 @@
static int nr_dec_obs(void)
{
struct nr_neigh *nr_neigh;
- struct nr_node *s, *nr_node;
+ struct nr_node *s;
+ struct hlist_node *node, *nodet;
int i;
- nr_node = nr_node_list;
-
- while (nr_node != NULL) {
- s = nr_node;
- nr_node = nr_node->next;
-
+ spin_lock_bh(&nr_node_list_lock);
+ nr_node_for_each_safe(s, node, nodet, &nr_node_list) {
+ nr_node_lock(s);
for (i = 0; i < s->count; i++) {
switch (s->routes[i].obs_count) {
case 0: /* A locked entry */
@@ -448,6 +491,7 @@
nr_neigh = s->routes[i].neighbour;
nr_neigh->count--;
+ nr_neigh_put(nr_neigh);
if (nr_neigh->count == 0 && !nr_neigh->locked)
nr_remove_neigh(nr_neigh);
@@ -472,8 +516,10 @@
}
if (s->count <= 0)
- nr_remove_node(s);
+ nr_remove_node_locked(s);
+ nr_node_unlock(s);
}
+ spin_unlock_bh(&nr_node_list_lock);
return 0;
}
@@ -483,21 +529,17 @@
*/
void nr_rt_device_down(struct net_device *dev)
{
- struct nr_neigh *s, *nr_neigh = nr_neigh_list;
- struct nr_node *t, *nr_node;
+ struct nr_neigh *s;
+ struct hlist_node *node, *nodet, *node2, *node2t;
+ struct nr_node *t;
int i;
- while (nr_neigh != NULL) {
- s = nr_neigh;
- nr_neigh = nr_neigh->next;
-
+ spin_lock_bh(&nr_neigh_list_lock);
+ nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
if (s->dev == dev) {
- nr_node = nr_node_list;
-
- while (nr_node != NULL) {
- t = nr_node;
- nr_node = nr_node->next;
-
+ spin_lock_bh(&nr_node_list_lock);
+ nr_node_for_each_safe(t, node2, node2t, &nr_node_list) {
+ nr_node_lock(t);
for (i = 0; i < t->count; i++) {
if (t->routes[i].neighbour == s) {
t->count--;
@@ -514,12 +556,15 @@
}
if (t->count <= 0)
- nr_remove_node(t);
+ nr_remove_node_locked(t);
+ nr_node_unlock(t);
}
+ spin_unlock_bh(&nr_node_list_lock);
- nr_remove_neigh(s);
+ nr_remove_neigh_locked(s);
}
}
+ spin_unlock_bh(&nr_neigh_list_lock);
}
/*
@@ -553,6 +598,8 @@
if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
first = dev;
}
+ if (first)
+ dev_hold(first);
read_unlock(&dev_base_lock);
return first;
@@ -603,6 +650,7 @@
{
struct nr_route_struct nr_route;
struct net_device *dev;
+ int ret;
switch (cmd) {
case SIOCADDRT:
@@ -610,23 +658,29 @@
return -EFAULT;
if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
return -EINVAL;
- if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS)
+ if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) {
+ dev_put(dev);
return -EINVAL;
+ }
switch (nr_route.type) {
case NETROM_NODE:
- return nr_add_node(&nr_route.callsign,
+ ret = nr_add_node(&nr_route.callsign,
nr_route.mnemonic,
&nr_route.neighbour,
nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
dev, nr_route.quality,
nr_route.obs_count);
+ break;
case NETROM_NEIGH:
- return nr_add_neigh(&nr_route.callsign,
+ ret = nr_add_neigh(&nr_route.callsign,
nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
dev, nr_route.quality);
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
+ dev_put(dev);
+ return ret;
case SIOCDELRT:
if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
@@ -635,14 +689,18 @@
return -EINVAL;
switch (nr_route.type) {
case NETROM_NODE:
- return nr_del_node(&nr_route.callsign,
+ ret = nr_del_node(&nr_route.callsign,
&nr_route.neighbour, dev);
+ break;
case NETROM_NEIGH:
- return nr_del_neigh(&nr_route.callsign,
+ ret = nr_del_neigh(&nr_route.callsign,
dev, nr_route.quality);
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
+ dev_put(dev);
+ return ret;
case SIOCNRDECOBS:
return nr_dec_obs();
@@ -660,22 +718,36 @@
*/
void nr_link_failed(ax25_cb *ax25, int reason)
{
- struct nr_neigh *nr_neigh;
- struct nr_node *nr_node;
-
- for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
- if (nr_neigh->ax25 == ax25)
+ struct nr_neigh *s, *nr_neigh = NULL;
+ struct hlist_node *node;
+ struct nr_node *nr_node = NULL;
+
+ spin_lock_bh(&nr_neigh_list_lock);
+ nr_neigh_for_each(s, node, &nr_neigh_list)
+ if (s->ax25 == ax25) {
+ nr_neigh_hold(s);
+ nr_neigh = s;
break;
+ }
+ spin_unlock_bh(&nr_neigh_list_lock);
if (nr_neigh == NULL) return;
nr_neigh->ax25 = NULL;
+ ax25_cb_put(ax25);
- if (++nr_neigh->failed < sysctl_netrom_link_fails_count) return;
-
- for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
+ if (++nr_neigh->failed < sysctl_netrom_link_fails_count) {
+ nr_neigh_put(nr_neigh);
+ return;
+ }
+ spin_lock_bh(&nr_node_list_lock);
+ nr_node_for_each(nr_node, node, &nr_node_list)
+ nr_node_lock(nr_node);
if (nr_node->which < nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh)
nr_node->which++;
+ nr_node_unlock(nr_node);
+ spin_unlock_bh(&nr_node_list_lock);
+ nr_neigh_put(nr_neigh);
}
/*
@@ -689,6 +761,9 @@
struct nr_node *nr_node;
struct net_device *dev;
unsigned char *dptr;
+ ax25_cb *ax25s;
+ int ret;
+ struct sk_buff *skbn;
nr_src = (ax25_address *)(skb->data + 0);
@@ -700,50 +775,84 @@
if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */
if (ax25 == NULL) /* Its from me */
- return nr_loopback_queue(skb);
+ ret = nr_loopback_queue(skb);
else
- return nr_rx_frame(skb, dev);
+ ret = nr_rx_frame(skb, dev);
+ dev_put(dev);
+ return ret;
}
if (!sysctl_netrom_routing_control && ax25 != NULL)
return 0;
/* Its Time-To-Live has expired */
- if (--skb->data[14] == 0)
+ if (skb->data[14] == 1) {
return 0;
+ }
- for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next)
- if (ax25cmp(nr_dest, &nr_node->callsign) == 0)
- break;
+ nr_node = nr_node_get(nr_dest);
+ if (nr_node == NULL)
+ return 0;
+ nr_node_lock(nr_node);
- if (nr_node == NULL || nr_node->which >= nr_node->count)
+ if (nr_node->which >= nr_node->count) {
+ nr_node_unlock(nr_node);
+ nr_node_put(nr_node);
return 0;
+ }
nr_neigh = nr_node->routes[nr_node->which].neighbour;
- if ((dev = nr_dev_first()) == NULL)
+ if ((dev = nr_dev_first()) == NULL) {
+ nr_node_unlock(nr_node);
+ nr_node_put(nr_node);
+ return 0;
+ }
+
+ /* We are going to change the netrom headers so we should get our
+ own skb, we also did not know until now how much header space
+ we had to reserve... - RXQ */
+ if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) {
+ nr_node_unlock(nr_node);
+ nr_node_put(nr_node);
+ dev_put(dev);
return 0;
+ }
+ kfree_skb(skb);
+ skb=skbn;
+ skb->data[14]--;
dptr = skb_push(skb, 1);
*dptr = AX25_P_NETROM;
- nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
+ ax25s = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev);
+ if (nr_neigh->ax25 && ax25s) {
+ /* We were already holding this ax25_cb */
+ ax25_cb_put(ax25s);
+ }
+ nr_neigh->ax25 = ax25s;
- return (nr_neigh->ax25 != NULL);
+ dev_put(dev);
+ ret = (nr_neigh->ax25 != NULL);
+ nr_node_unlock(nr_node);
+ nr_node_put(nr_node);
+ return ret;
}
int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
{
struct nr_node *nr_node;
+ struct hlist_node *node;
int len = 0;
off_t pos = 0;
off_t begin = 0;
int i;
- spin_lock_bh(&nr_node_lock);
+ spin_lock_bh(&nr_node_list_lock);
len += sprintf(buffer, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
- for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
+ nr_node_for_each(nr_node, node, &nr_node_list) {
+ nr_node_lock(nr_node);
len += sprintf(buffer + len, "%-9s %-7s %d %d",
ax2asc(&nr_node->callsign),
(nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
@@ -756,6 +865,7 @@
nr_node->routes[i].obs_count,
nr_node->routes[i].neighbour->number);
}
+ nr_node_unlock(nr_node);
len += sprintf(buffer + len, "\n");
@@ -769,7 +879,7 @@
if (pos > offset + length)
break;
}
- spin_unlock_bh(&nr_node_lock);
+ spin_unlock_bh(&nr_node_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
@@ -782,15 +892,16 @@
int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
{
struct nr_neigh *nr_neigh;
+ struct hlist_node *node;
int len = 0;
off_t pos = 0;
off_t begin = 0;
int i;
- spin_lock_bh(&nr_neigh_lock);
+ spin_lock_bh(&nr_neigh_list_lock);
len += sprintf(buffer, "addr callsign dev qual lock count failed digipeaters\n");
- for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
+ nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) {
len += sprintf(buffer + len, "%05d %-9s %-4s %3d %d %3d %3d",
nr_neigh->number,
ax2asc(&nr_neigh->callsign),
@@ -818,7 +929,7 @@
break;
}
- spin_unlock_bh(&nr_neigh_lock);
+ spin_unlock_bh(&nr_neigh_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
@@ -833,20 +944,24 @@
*/
void __exit nr_rt_free(void)
{
- struct nr_neigh *s, *nr_neigh = nr_neigh_list;
- struct nr_node *t, *nr_node = nr_node_list;
-
- while (nr_node != NULL) {
- t = nr_node;
- nr_node = nr_node->next;
-
- nr_remove_node(t);
- }
-
- while (nr_neigh != NULL) {
- s = nr_neigh;
- nr_neigh = nr_neigh->next;
-
- nr_remove_neigh(s);
+ struct nr_neigh *s = NULL;
+ struct nr_node *t = NULL;
+ struct hlist_node *node, *nodet;
+
+ spin_lock_bh(&nr_neigh_list_lock);
+ spin_lock_bh(&nr_node_list_lock);
+ nr_node_for_each_safe(t, node, nodet, &nr_node_list) {
+ nr_node_lock(t);
+ nr_remove_node_locked(t);
+ nr_node_unlock(t);
+ }
+ nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) {
+ while(s->count) {
+ s->count--;
+ nr_neigh_put(s);
+ }
+ nr_remove_neigh_locked(s);
}
+ spin_unlock_bh(&nr_node_list_lock);
+ spin_unlock_bh(&nr_neigh_list_lock);
}
diff -ru linux-2.6.0-test3/net/netrom/nr_subr.c linux-2.6.0-test1.rxq3/net/netrom/nr_subr.c
--- linux-2.6.0-test3/net/netrom/nr_subr.c 2003-08-09 06:42:56.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/netrom/nr_subr.c 2003-07-24 20:56:54.000000000 +0200
@@ -127,7 +127,7 @@
unsigned char *dptr;
int len, timeout;
- len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
+ len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
switch (frametype & 0x0F) {
case NR_CONNREQ:
@@ -151,7 +151,7 @@
/*
* Space for AX.25 and NET/ROM network header
*/
- skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN);
+ skb_reserve(skb, NR_NETWORK_LEN);
dptr = skb_put(skb, skb_tailroom(skb));
@@ -219,12 +219,12 @@
unsigned char *dptr;
int len;
- len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1;
+ len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1;
if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL)
return;
- skb_reserve(skbn, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN);
+ skb_reserve(skbn, 0);
dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
diff -ru linux-2.6.0-test3/net/netrom/nr_timer.c linux-2.6.0-test1.rxq3/net/netrom/nr_timer.c
--- linux-2.6.0-test3/net/netrom/nr_timer.c 2003-08-09 06:38:56.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/netrom/nr_timer.c 2003-07-24 20:56:55.000000000 +0200
@@ -143,7 +143,10 @@
is accepted() it isn't 'dead' so doesn't get removed. */
if (sock_flag(sk, SOCK_DESTROY) ||
(sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
+ sock_hold(sk);
nr_destroy_socket(sk);
+ bh_unlock_sock(sk);
+ sock_put(sk);
return;
}
break;
@@ -227,6 +230,7 @@
case NR_STATE_1:
if (nr->n2count == nr->n2) {
nr_disconnect(sk, ETIMEDOUT);
+ bh_unlock_sock(sk);
return;
} else {
nr->n2count++;
@@ -237,6 +241,7 @@
case NR_STATE_2:
if (nr->n2count == nr->n2) {
nr_disconnect(sk, ETIMEDOUT);
+ bh_unlock_sock(sk);
return;
} else {
nr->n2count++;
@@ -247,6 +252,7 @@
case NR_STATE_3:
if (nr->n2count == nr->n2) {
nr_disconnect(sk, ETIMEDOUT);
+ bh_unlock_sock(sk);
return;
} else {
nr->n2count++;
diff -ru linux-2.6.0-test3/net/netrom/sysctl_net_netrom.c linux-2.6.0-test1.rxq3/net/netrom/sysctl_net_netrom.c
--- linux-2.6.0-test3/net/netrom/sysctl_net_netrom.c 2003-08-09 06:33:21.000000000 +0200
+++ linux-2.6.0-test1.rxq3/net/netrom/sysctl_net_netrom.c 2003-07-24 20:56:54.000000000 +0200
@@ -15,9 +15,9 @@
/*
* Values taken from NET/ROM documentation.
*/
-static int min_quality[1], max_quality[] = {255};
-static int min_obs[1], max_obs[] = {255};
-static int min_ttl[1], max_ttl[] = {255};
+static int min_quality[] = {0}, max_quality[] = {255};
+static int min_obs[] = {0}, max_obs[] = {255};
+static int min_ttl[] = {0}, max_ttl[] = {255};
static int min_t1[] = {5 * HZ};
static int max_t1[] = {600 * HZ};
static int min_n2[] = {2}, max_n2[] = {127};
@@ -28,7 +28,7 @@
static int min_window[] = {1}, max_window[] = {127};
static int min_idle[] = {0 * HZ};
static int max_idle[] = {65535 * HZ};
-static int min_route[1], max_route[] = {1};
+static int min_route[] = {0}, max_route[] = {1};
static int min_fails[] = {1}, max_fails[] = {10};
static struct ctl_table_header *nr_table_header;
--- linux-2.6.0-test3/include/net/ax25.h 2003-08-09 06:38:16.000000000 +0200
+++ linux-2.6.0-test1.rxq3/include/net/ax25.h 2003-07-24 21:01:59.000000000 +0200
@@ -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 @@
} 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 @@
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 *);
--- linux-2.6.0-test3/include/net/netrom.h 2003-08-09 06:37:18.000000000 +0200
+++ linux-2.6.0-test1.rxq3/include/net/netrom.h 2003-07-24 21:01:59.000000000 +0200
@@ -7,6 +7,7 @@
#ifndef _NETROM_H
#define _NETROM_H
#include <linux/netrom.h>
+#include <linux/list.h>
#define NR_NETWORK_LEN 15
#define NR_TRANSPORT_LEN 5
@@ -77,16 +78,17 @@
#define nr_sk(__sk) ((nr_cb *)(__sk)->sk_protinfo)
struct nr_neigh {
- struct nr_neigh *next;
- ax25_address callsign;
- ax25_digi *digipeat;
- ax25_cb *ax25;
- struct net_device *dev;
- unsigned char quality;
- unsigned char locked;
- unsigned short count;
- unsigned int number;
- unsigned char failed;
+ struct hlist_node neigh_node;
+ ax25_address callsign;
+ ax25_digi *digipeat;
+ ax25_cb *ax25;
+ struct net_device *dev;
+ unsigned char quality;
+ unsigned char locked;
+ unsigned short count;
+ unsigned int number;
+ unsigned char failed;
+ atomic_t refcount;
};
struct nr_route {
@@ -96,14 +98,74 @@
};
struct nr_node {
- struct nr_node *next;
- ax25_address callsign;
- char mnemonic[7];
- unsigned char which;
- unsigned char count;
- struct nr_route routes[3];
+ struct hlist_node node_node;
+ ax25_address callsign;
+ char mnemonic[7];
+ unsigned char which;
+ unsigned char count;
+ struct nr_route routes[3];
+ atomic_t refcount;
+ spinlock_t node_lock;
};
+/*********************************************************************
+ * nr_node & nr_neigh lists, refcounting and locking
+ *********************************************************************/
+
+extern struct hlist_head nr_node_list;
+extern struct hlist_head nr_neigh_list;
+
+#define nr_node_hold(__nr_node) \
+ atomic_inc(&((__nr_node)->refcount))
+
+static __inline__ void nr_node_put(struct nr_node *nr_node)
+{
+ if (atomic_dec_and_test(&nr_node->refcount)) {
+ kfree(nr_node);
+ }
+}
+
+#define nr_neigh_hold(__nr_neigh) \
+ atomic_inc(&((__nr_neigh)->refcount))
+
+static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh)
+{
+ if (atomic_dec_and_test(&nr_neigh->refcount)) {
+ if (nr_neigh->digipeat != NULL)
+ kfree(nr_neigh->digipeat);
+ kfree(nr_neigh);
+ }
+}
+
+/* nr_node_lock and nr_node_unlock also hold/put the node's refcounter.
+ */
+static __inline__ void nr_node_lock(struct nr_node *nr_node)
+{
+ nr_node_hold(nr_node);
+ spin_lock_bh(&nr_node->node_lock);
+}
+
+static __inline__ void nr_node_unlock(struct nr_node *nr_node)
+{
+ spin_unlock_bh(&nr_node->node_lock);
+ nr_node_put(nr_node);
+}
+
+#define nr_neigh_for_each(__nr_neigh, node, list) \
+ hlist_for_each_entry(__nr_neigh, node, list, neigh_node)
+
+#define nr_neigh_for_each_safe(__nr_neigh, node, node2, list) \
+ hlist_for_each_entry_safe(__nr_neigh, node, node2, list, neigh_node)
+
+#define nr_node_for_each(__nr_node, node, list) \
+ hlist_for_each_entry(__nr_node, node, list, node_node)
+
+#define nr_node_for_each_safe(__nr_node, node, node2, list) \
+ hlist_for_each_entry_safe(__nr_node, node, node2, list, node_node)
+
+
+/*********************************************************************/
+
/* af_netrom.c */
extern int sysctl_netrom_default_path_quality;
extern int sysctl_netrom_obsolescence_count_initialiser;
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: [PATCH] ax25 & netrom fixes for 2.6 2003-08-12 17:46 [PATCH] ax25 & netrom fixes for 2.6 Jeroen Vreeken @ 2003-08-12 19:48 ` Stephen Hemminger 2003-08-12 20:59 ` Jeroen Vreeken 2003-08-12 20:56 ` Stephen Hemminger 1 sibling, 1 reply; 23+ messages in thread From: Stephen Hemminger @ 2003-08-12 19:48 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: linux-hams, netdev You lost a critical fix to ax25; it oop's if I bring up any device then do "ifconfig -a" due to use after free. PLEASE do some debugging with some of the kernel debugging options enabled! Uninitialised timer! This is just a warning. Your computer is OK function=0x6b6b6b6b, data=0x6b6b6b6b Call Trace: [<c012ad43>] check_timer_failed+0x73/0x75 [<c012b297>] del_timer+0x1d/0xe8 [<fa4f70d0>] ax25_cb_del+0x96/0xdc [ax25] [<c011da1d>] default_wake_function+0x0/0x2e [<fa4f7c21>] ax25_destroy_socket+0x1f/0x335 [ax25] [<c011da1d>] default_wake_function+0x0/0x2e [<fa4f9346>] ax25_release+0xc1/0x2c0 [ax25] [<c0247e08>] sock_fasync+0x190/0x363 [<c024728b>] sock_release+0x79/0xb4 [<c0247c61>] sock_close+0x36/0x4d [<c01602ec>] __fput+0x103/0x115 [<c015e805>] filp_close+0x4b/0x74 [<c015e8b4>] sys_close+0x86/0xf8 [<c010b2b5>] sysenter_past_esp+0x52/0x71 Debug: sleeping function called from invalid context at include/linux/rwsem.h:43Call Trace: [<c011fb3f>] __might_sleep+0x5c/0x60 [<c011b1b8>] do_page_fault+0x78/0x4ab [<c011da83>] __wake_up_common+0x38/0x57 [<c0123170>] release_console_sem+0xfc/0x133 [<c0122f76>] printk+0x1b6/0x25a [<c011b140>] do_page_fault+0x0/0x4ab [<c010bd91>] error_code+0x2d/0x38 [<c012b2a7>] del_timer+0x2d/0xe8 [<fa4f70d0>] ax25_cb_del+0x96/0xdc [ax25] [<c011da1d>] default_wake_function+0x0/0x2e [<fa4f7c21>] ax25_destroy_socket+0x1f/0x335 [ax25] [<c011da1d>] default_wake_function+0x0/0x2e [<fa4f9346>] ax25_release+0xc1/0x2c0 [ax25] [<c0247e08>] sock_fasync+0x190/0x363 [<c024728b>] sock_release+0x79/0xb4 [<c0247c61>] sock_close+0x36/0x4d [<c01602ec>] __fput+0x103/0x115 [<c015e805>] filp_close+0x4b/0x74 [<c015e8b4>] sys_close+0x86/0xf8 [<c010b2b5>] sysenter_past_esp+0x52/0x71 Unable to handle kernel paging request at virtual address 6b6b6b6f printing eip: c012b2a7 *pde = 00000000 Oops: 0000 [#1] CPU: 0 EIP: 0060:[<c012b2a7>] Not tainted EFLAGS: 00010002 EIP is at del_timer+0x2d/0xe8 eax: 00000000 ebx: 6b6b6b6b ecx: 00000001 edx: dead4ead esi: 00000202 edi: f723364c ebp: f4267ed0 esp: f4267eb4 ds: 007b es: 007b ss: 0068 Process ifconfig (pid: 1760, threadinfo=f4266000 task=f561a080) Stack: f723364c fa4f70d0 f723351c c011da1d f736fc84 f723351c f736fca4 f4267f00 fa4f7c21 f723364c f561a080 c011da1d 00100100 00000246 00000246 00000246 f736fc84 f723351c f736fca4 f4267f30 fa4f9346 f723351c 000003a7 f736fcb0 Call Trace: [<fa4f70d0>] ax25_cb_del+0x96/0xdc [ax25] [<c011da1d>] default_wake_function+0x0/0x2e [<fa4f7c21>] ax25_destroy_socket+0x1f/0x335 [ax25] [<c011da1d>] default_wake_function+0x0/0x2e [<fa4f9346>] ax25_release+0xc1/0x2c0 [ax25] [<c0247e08>] sock_fasync+0x190/0x363 [<c024728b>] sock_release+0x79/0xb4 [<c0247c61>] sock_close+0x36/0x4d [<c01602ec>] __fput+0x103/0x115 [<c015e805>] filp_close+0x4b/0x74 [<c015e8b4>] sys_close+0x86/0xf8 [<c010b2b5>] sysenter_past_esp+0x52/0x71 Code: 81 7b 04 ad 4e ad de 0f 85 8d 00 00 00 f0 fe 0b 0f 88 3e 0d <3>Slab corruption: start=f723351c, expend=f723371b, problemat=f7233658 Last user: [<fa4f70d0>](ax25_cb_del+0x96/0xdc [ax25]) Data: ************************************************************************* Next: 71 F0 2C .D0 70 4F FA 71 F0 2C .******************** slab error in check_poison_obj(): cache `size-512': object was modified after fgCall Trace: [<c01453b1>] check_poison_obj+0x16c/0x1ac [<c0147174>] __kmalloc+0x172/0x1d1 [<c024b14e>] alloc_skb+0x48/0xe1 [<c024b14e>] alloc_skb+0x48/0xe1 [<c024a7c9>] sock_alloc_send_pskb+0xce/0x1f6 [<c024a91f>] sock_alloc_send_skb+0x2e/0x32 [<c02b5400>] unix_stream_sendmsg+0x194/0x46d [<c02475b9>] sock_aio_write+0xbd/0xd9 [<c015f301>] do_sync_write+0x89/0xb4 [<c012bcfe>] schedule_timeout+0x72/0xbb [<c0247bf4>] sock_poll+0x29/0x30 [<c017481f>] sys_poll+0x228/0x27c [<c015f415>] vfs_write+0xe9/0x119 [<c015f4e1>] sys_write+0x3f/0x5d [<c010b2b5>] sysenter_past_esp+0x52/0x71 ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ax25 & netrom fixes for 2.6 2003-08-12 19:48 ` Stephen Hemminger @ 2003-08-12 20:59 ` Jeroen Vreeken 0 siblings, 0 replies; 23+ messages in thread From: Jeroen Vreeken @ 2003-08-12 20:59 UTC (permalink / raw) To: Stephen Hemminger; +Cc: linux-hams, netdev On 2003.08.12 21:48:20 +0200 Stephen Hemminger wrote: > You lost a critical fix to ax25; it oop's if I bring up any device > then do "ifconfig -a" due to use after free. > > PLEASE do some debugging with some of the kernel debugging options > enabled! Which fix exactly did I miss? the only thing I see in your patch is the change to use sock_put in ax25_destroy_sock() and that was in my original patch... btw, I do have debugging enabled... Jeroen ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ax25 & netrom fixes for 2.6 2003-08-12 17:46 [PATCH] ax25 & netrom fixes for 2.6 Jeroen Vreeken 2003-08-12 19:48 ` Stephen Hemminger @ 2003-08-12 20:56 ` Stephen Hemminger 2003-08-12 21:09 ` Jeroen Vreeken 1 sibling, 1 reply; 23+ messages in thread From: Stephen Hemminger @ 2003-08-12 20:56 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: linux-hams, ralf, davem, netdev It looks like af_x25 is advertising itself as a new style protocol, yet if I walk the receive path: ax25_kiss_rcv -> ax25_rcv -> ax25_addr_parse there is no place that checks that the address portion of the buffer isn't fragmented into a non_linear skb. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ax25 & netrom fixes for 2.6 2003-08-12 20:56 ` Stephen Hemminger @ 2003-08-12 21:09 ` Jeroen Vreeken 2003-08-12 22:39 ` [PATCH] ax25 fix for premature free Stephen Hemminger 2003-08-13 10:10 ` [PATCH] ax25 & netrom fixes for 2.6 David S. Miller 0 siblings, 2 replies; 23+ messages in thread From: Jeroen Vreeken @ 2003-08-12 21:09 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Jeroen Vreeken, linux-hams, ralf, davem, netdev On 2003.08.12 22:56:55 +0200 Stephen Hemminger wrote: > It looks like af_x25 is advertising itself as a new style protocol, yet > if > I walk the receive path: > ax25_kiss_rcv -> ax25_rcv -> ax25_addr_parse > there is no place that checks that the address portion of the buffer > isn't fragmented > into a non_linear skb. Since at the moment the only zero-copy path I can imagine is from packets over a bpq ethernet device wouldn't it be the easiest to just check at ax25_rcv() for non-linear packets and call skb_linearize() for them? That way we would be safe untill we can make sure that the whole of the ax25 stack is non-linear safe? Should I make a new patch with this included? (and possibly the ifconfig problem you mentioned?) Jeroen ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH] ax25 fix for premature free. 2003-08-12 21:09 ` Jeroen Vreeken @ 2003-08-12 22:39 ` Stephen Hemminger 2003-08-12 23:03 ` Jeroen Vreeken 2003-08-13 10:10 ` [PATCH] ax25 & netrom fixes for 2.6 David S. Miller 1 sibling, 1 reply; 23+ messages in thread From: Stephen Hemminger @ 2003-08-12 22:39 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: linux-hams, ralf, davem, netdev The problem is that you are freeing the ax25 control block too soon for the case of sockets that were never bound. If the socket is not bound, it never makes it into the node list and the refcount is 1. So when you decrement in ax25_cb_del by calling ax25_cb_put it gets freed. This fixes the problem, it assumes your earlier patch has been applied. diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c --- a/net/ax25/af_ax25.c Tue Aug 12 15:35:33 2003 +++ b/net/ax25/af_ax25.c Tue Aug 12 15:35:33 2003 @@ -66,10 +66,12 @@ */ static void ax25_cb_del(ax25_cb *ax25) { - spin_lock_bh(&ax25_list_lock); - hlist_del_init(&ax25->ax25_node); - spin_unlock_bh(&ax25_list_lock); - ax25_cb_put(ax25); + if (!hlist_unhashed(&ax25->ax25_node)) { + spin_lock_bh(&ax25_list_lock); + hlist_del(&ax25->ax25_node); + spin_unlock_bh(&ax25_list_lock); + ax25_cb_put(ax25); + } } /* ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ax25 fix for premature free. 2003-08-12 22:39 ` [PATCH] ax25 fix for premature free Stephen Hemminger @ 2003-08-12 23:03 ` Jeroen Vreeken 2003-08-12 23:49 ` [PATCH] ax25 use dev_hold/dev_put as required for net_devices Stephen Hemminger ` (2 more replies) 0 siblings, 3 replies; 23+ messages in thread From: Jeroen Vreeken @ 2003-08-12 23:03 UTC (permalink / raw) To: Stephen Hemminger; +Cc: linux-hams, ralf, davem, netdev [-- Attachment #1: Type: text/plain, Size: 134 bytes --] This is the same patch as earlier today with the bug Stephen mentioned in ax25_cb_del patched. It is made against 2.6.0-test3 Jeroen [-- Attachment #2: linux-2.6.0-test3.rxq4.diff --] [-- Type: application/octet-stream, Size: 80785 bytes --] Only in linux-2.6.0-test3.rxq/net/ax25: .af_ax25.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25.ko.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25.mod.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_addr.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_dev.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_iface.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_in.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_ip.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_out.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_route.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_std_in.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_std_subr.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_std_timer.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_subr.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_timer.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_uid.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .built-in.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .sysctl_net_ax25.o.cmd diff -ru linux-2.6.0-test3/net/ax25/af_ax25.c linux-2.6.0-test3.rxq/net/ax25/af_ax25.c --- linux-2.6.0-test3/net/ax25/af_ax25.c 2003-08-09 06:41:26.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/af_ax25.c 2003-08-13 00:29:48.000000000 +0200 @@ -51,54 +51,27 @@ -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 @@ { 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 @@ /* * 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 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 *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_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 @@ 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 *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 @@ break; } } + spin_unlock_bh(&ax25_list_lock); return sk; @@ -299,7 +279,16 @@ */ 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 @@ { struct sk_buff *skb; - ax25_remove_socket(ax25); + ax25_cb_del(ax25); ax25_stop_heartbeat(ax25); ax25_stop_t1timer(ax25); @@ -337,22 +326,27 @@ 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 @@ 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 @@ return -EINVAL; } - return 0; + return 0; } /* @@ -507,6 +501,7 @@ 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 @@ (sock->state != SS_UNCONNECTED || sk->sk_state == TCP_LISTEN)) { res = -EADDRNOTAVAIL; + dev_put(dev); break; } @@ -877,7 +873,7 @@ break; default: sk_free(sk); - ax25_free_cb(ax25); + ax25_cb_put(ax25); return NULL; } @@ -937,6 +933,7 @@ if (sk == NULL) return 0; + sock_hold(sk); lock_sock(sk); ax25 = ax25_sk(sk); @@ -944,13 +941,15 @@ 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 @@ 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 @@ ax25_fillin_cb(ax25, ax25_dev); done: - ax25_insert_socket(ax25); + ax25_cb_add(ax25); sk->sk_zapped = 0; out: @@ -1093,7 +1090,7 @@ 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 @@ 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 @@ } 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 @@ 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 @@ sock->state = SS_CONNECTED; + err=0; out: release_sock(sk); - return 0; + return err; } @@ -1331,15 +1332,18 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ * 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 @@ 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"); } Only in linux-2.6.0-test3.rxq/net/ax25: af_ax25.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25.ko Only in linux-2.6.0-test3.rxq/net/ax25: ax25.mod.c Only in linux-2.6.0-test3.rxq/net/ax25: ax25.mod.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25_addr.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25_dev.o diff -ru linux-2.6.0-test3/net/ax25/ax25_ds_in.c linux-2.6.0-test3.rxq/net/ax25/ax25_ds_in.c --- linux-2.6.0-test3/net/ax25/ax25_ds_in.c 2003-08-09 06:38:45.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_ds_in.c 2003-08-12 23:40:35.000000000 +0200 @@ -65,6 +65,7 @@ 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 @@ */ if (!sock_flag(ax25->sk, SOCK_DEAD)) ax25->sk->sk_state_change(ax25->sk); + bh_unlock_sock(ax25->sk); } ax25_dama_on(ax25); diff -ru linux-2.6.0-test3/net/ax25/ax25_ds_subr.c linux-2.6.0-test3.rxq/net/ax25/ax25_ds_subr.c --- linux-2.6.0-test3/net/ax25/ax25_ds_subr.c 2003-08-09 06:41:32.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_ds_subr.c 2003-08-12 23:40:35.000000000 +0200 @@ -40,6 +40,7 @@ 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 @@ 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 @@ { 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; diff -ru linux-2.6.0-test3/net/ax25/ax25_ds_timer.c linux-2.6.0-test3.rxq/net/ax25/ax25_ds_timer.c --- linux-2.6.0-test3/net/ax25/ax25_ds_timer.c 2003-08-09 06:41:26.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_ds_timer.c 2003-08-12 23:40:35.000000000 +0200 @@ -74,6 +74,7 @@ { 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 @@ } 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 @@ 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 @@ /* * 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 @@ break; } + if (sk) + bh_unlock_sock(sk); + ax25_start_heartbeat(ax25); } @@ -157,6 +172,7 @@ 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 @@ ax25->sk->sk_state_change(ax25->sk); sock_set_flag(ax25->sk, SOCK_DEAD); } + bh_lock_sock(ax25->sk); } } diff -ru linux-2.6.0-test3/net/ax25/ax25_iface.c linux-2.6.0-test3.rxq/net/ax25/ax25_iface.c --- linux-2.6.0-test3/net/ax25/ax25_iface.c 2003-08-09 06:42:13.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_iface.c 2003-08-12 23:40:35.000000000 +0200 @@ -33,20 +33,20 @@ struct protocol_struct *next; unsigned int pid; int (*func)(struct sk_buff *, ax25_cb *); -} *protocol_list; +} *protocol_list = NULL; static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED; static struct linkfail_struct { struct linkfail_struct *next; void (*func)(ax25_cb *, int); -} *linkfail_list; +} *linkfail_list = NULL; static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED; static struct listen_struct { struct listen_struct *next; ax25_address callsign; struct net_device *dev; -} *listen_list; +} *listen_list = NULL; static spinlock_t listen_lock = SPIN_LOCK_UNLOCKED; int ax25_protocol_register(unsigned int pid, @@ -129,8 +129,10 @@ spin_lock_bh(&linkfail_lock); linkfail = linkfail_list; - if (linkfail == NULL) + if (linkfail == NULL) { + spin_unlock_bh(&linkfail_lock); return; + } if (linkfail->func == func) { linkfail_list = linkfail->next; @@ -180,8 +182,10 @@ spin_lock_bh(&listen_lock); listen = listen_list; - if (listen == NULL) + if (listen == NULL) { + spin_unlock_bh(&listen_lock); return; + } if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { listen_list = listen->next; @@ -226,8 +230,10 @@ spin_lock_bh(&listen_lock); for (listen = listen_list; listen != NULL; listen = listen->next) - if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) + if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) { + spin_unlock_bh(&listen_lock); return 1; + } spin_unlock_bh(&listen_lock); return 0; Only in linux-2.6.0-test3.rxq/net/ax25: ax25_iface.o diff -ru linux-2.6.0-test3/net/ax25/ax25_in.c linux-2.6.0-test3.rxq/net/ax25/ax25_in.c --- linux-2.6.0-test3/net/ax25/ax25_in.c 2003-08-09 06:32:47.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_in.c 2003-08-12 23:40:35.000000000 +0200 @@ -147,6 +147,7 @@ } 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 @@ else ax25->condition |= AX25_COND_OWN_RX_BUSY; } + bh_unlock_sock(ax25->sk); } return queued; @@ -329,6 +331,7 @@ if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) kfree_skb(skb); + ax25_cb_put(ax25); return 0; } @@ -357,11 +360,14 @@ 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 @@ 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 @@ ax25->state = AX25_STATE_3; - ax25_insert_socket(ax25); + ax25_cb_add(ax25); ax25_start_heartbeat(ax25); ax25_start_t3timer(ax25); Only in linux-2.6.0-test3.rxq/net/ax25: ax25_in.o diff -ru linux-2.6.0-test3/net/ax25/ax25_ip.c linux-2.6.0-test3.rxq/net/ax25/ax25_ip.c --- linux-2.6.0-test3/net/ax25/ax25_ip.c 2003-08-09 06:34:43.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_ip.c 2003-08-12 23:40:35.000000000 +0200 @@ -107,6 +107,7 @@ 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 @@ 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; } } Only in linux-2.6.0-test3.rxq/net/ax25: ax25_ip.o diff -ru linux-2.6.0-test3/net/ax25/ax25_out.c linux-2.6.0-test3.rxq/net/ax25/ax25_out.c --- linux-2.6.0-test3/net/ax25/ax25_out.c 2003-08-09 06:40:10.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_out.c 2003-08-12 23:40:35.000000000 +0200 @@ -71,7 +71,7 @@ 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 @@ #endif } - ax25_insert_socket(ax25); + ax25_cb_add(ax25); ax25->state = AX25_STATE_1; Only in linux-2.6.0-test3.rxq/net/ax25: ax25_out.o diff -ru linux-2.6.0-test3/net/ax25/ax25_route.c linux-2.6.0-test3.rxq/net/ax25/ax25_route.c --- linux-2.6.0-test3/net/ax25/ax25_route.c 2003-08-09 06:38:41.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_route.c 2003-08-12 23:40:35.000000000 +0200 @@ -162,6 +162,7 @@ if (ax25_rt->digipeat != NULL) kfree(ax25_rt->digipeat); kfree(ax25_rt); + return; } /* @@ -434,8 +435,11 @@ 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); Only in linux-2.6.0-test3.rxq/net/ax25: ax25_route.o diff -ru linux-2.6.0-test3/net/ax25/ax25_std_in.c linux-2.6.0-test3.rxq/net/ax25/ax25_std_in.c --- linux-2.6.0-test3/net/ax25/ax25_std_in.c 2003-08-09 06:39:26.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_std_in.c 2003-08-12 23:40:35.000000000 +0200 @@ -73,10 +73,12 @@ 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; Only in linux-2.6.0-test3.rxq/net/ax25: ax25_std_in.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25_std_subr.o diff -ru linux-2.6.0-test3/net/ax25/ax25_std_timer.c linux-2.6.0-test3.rxq/net/ax25/ax25_std_timer.c --- linux-2.6.0-test3/net/ax25/ax25_std_timer.c 2003-08-09 06:34:03.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_std_timer.c 2003-08-12 23:40:35.000000000 +0200 @@ -33,14 +33,25 @@ 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 @@ /* * 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 @@ } } + if (sk) + bh_unlock_sock(sk); + ax25_start_heartbeat(ax25); } @@ -94,6 +108,7 @@ 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 @@ ax25->sk->sk_state_change(ax25->sk); sock_set_flag(ax25->sk, SOCK_DEAD); } + bh_unlock_sock(ax25->sk); } } Only in linux-2.6.0-test3.rxq/net/ax25: ax25_std_timer.o diff -ru linux-2.6.0-test3/net/ax25/ax25_subr.c linux-2.6.0-test3.rxq/net/ax25/ax25_subr.c --- linux-2.6.0-test3/net/ax25/ax25_subr.c 2003-08-09 06:41:35.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_subr.c 2003-08-12 23:40:35.000000000 +0200 @@ -158,10 +158,10 @@ struct sk_buff *skb; unsigned char *dptr; - if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(ax25->ax25_dev->dev->hard_header_len + 2, GFP_ATOMIC)) == NULL) return; - skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat)); + skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len); skb->nh.raw = skb->data; @@ -202,10 +202,10 @@ if (dev == NULL) return; - if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(digi) + 1, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(dev->hard_header_len + 1, GFP_ATOMIC)) == NULL) return; /* Next SABM will get DM'd */ - skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi)); + skb_reserve(skb, dev->hard_header_len); skb->nh.raw = skb->data; ax25_digi_invert(digi, &retdigi); @@ -282,6 +282,7 @@ ax25_link_failed(ax25, reason); if (ax25->sk != NULL) { + bh_lock_sock(ax25->sk); ax25->sk->sk_state = TCP_CLOSE; ax25->sk->sk_err = reason; ax25->sk->sk_shutdown |= SEND_SHUTDOWN; @@ -289,5 +290,6 @@ ax25->sk->sk_state_change(ax25->sk); sock_set_flag(ax25->sk, SOCK_DEAD); } + bh_unlock_sock(ax25->sk); } } Only in linux-2.6.0-test3.rxq/net/ax25: ax25_subr.o diff -ru linux-2.6.0-test3/net/ax25/ax25_timer.c linux-2.6.0-test3.rxq/net/ax25/ax25_timer.c --- linux-2.6.0-test3/net/ax25/ax25_timer.c 2003-08-09 06:38:16.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_timer.c 2003-08-12 23:40:35.000000000 +0200 @@ -141,13 +141,10 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ break; #endif } - bh_unlock_sock(sk); } Only in linux-2.6.0-test3.rxq/net/ax25: ax25_timer.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25_uid.o Only in linux-2.6.0-test3.rxq/net/ax25: built-in.o diff -ru linux-2.6.0-test3/net/ax25/sysctl_net_ax25.c linux-2.6.0-test3.rxq/net/ax25/sysctl_net_ax25.c --- linux-2.6.0-test3/net/ax25/sysctl_net_ax25.c 2003-08-09 06:41:21.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/sysctl_net_ax25.c 2003-08-12 23:40:35.000000000 +0200 @@ -12,20 +12,20 @@ #include <linux/spinlock.h> #include <net/ax25.h> -static int min_ipdefmode[1], max_ipdefmode[] = {1}; -static int min_axdefmode[1], max_axdefmode[] = {1}; -static int min_backoff[1], max_backoff[] = {2}; -static int min_conmode[1], max_conmode[] = {2}; +static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1}; +static int min_axdefmode[] = {0}, max_axdefmode[] = {1}; +static int min_backoff[] = {0}, max_backoff[] = {2}; +static int min_conmode[] = {0}, max_conmode[] = {2}; static int min_window[] = {1}, max_window[] = {7}; static int min_ewindow[] = {1}, max_ewindow[] = {63}; static int min_t1[] = {1}, max_t1[] = {30 * HZ}; static int min_t2[] = {1}, max_t2[] = {20 * HZ}; -static int min_t3[1], max_t3[] = {3600 * HZ}; -static int min_idle[1], max_idle[] = {65535 * HZ}; +static int min_t3[] = {0}, max_t3[] = {3600 * HZ}; +static int min_idle[] = {0}, max_idle[] = {65535 * HZ}; static int min_n2[] = {1}, max_n2[] = {31}; static int min_paclen[] = {1}, max_paclen[] = {512}; -static int min_proto[1], max_proto[] = {3}; -static int min_ds_timeout[1], max_ds_timeout[] = {65535 * HZ}; +static int min_proto[] = {0}, max_proto[] = {3}; +static int min_ds_timeout[] = {0}, max_ds_timeout[] = {65535 * HZ}; static struct ctl_table_header *ax25_table_header; @@ -204,8 +204,10 @@ 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); Only in linux-2.6.0-test3.rxq/net/ax25: sysctl_net_ax25.o Only in linux-2.6.0-test3.rxq/net/netrom: .af_netrom.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .built-in.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .netrom.ko.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .netrom.mod.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .netrom.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_dev.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_in.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_loopback.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_out.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_route.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_subr.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_timer.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .sysctl_net_netrom.o.cmd diff -ru linux-2.6.0-test3/net/netrom/af_netrom.c linux-2.6.0-test3.rxq/net/netrom/af_netrom.c --- linux-2.6.0-test3/net/netrom/af_netrom.c 2003-08-09 06:36:46.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/af_netrom.c 2003-08-12 23:40:35.000000000 +0200 @@ -147,8 +147,10 @@ spin_lock_bh(&nr_list_lock); sk_for_each(s, node, &nr_list) if (!ax25cmp(&nr_sk(s)->source_addr, addr) && - s->sk_state == TCP_LISTEN) + s->sk_state == TCP_LISTEN) { + bh_lock_sock(s); goto found; + } s = NULL; found: spin_unlock_bh(&nr_list_lock); @@ -167,8 +169,10 @@ sk_for_each(s, node, &nr_list) { nr_cb *nr = nr_sk(s); - if (nr->my_index == index && nr->my_id == id) + if (nr->my_index == index && nr->my_id == id) { + bh_lock_sock(s); goto found; + } } s = NULL; found: @@ -190,8 +194,10 @@ nr_cb *nr = nr_sk(s); if (nr->your_index == index && nr->your_id == id && - !ax25cmp(&nr->dest_addr, dest)) + !ax25cmp(&nr->dest_addr, dest)) { + bh_lock_sock(s); goto found; + } } s = NULL; found: @@ -206,14 +212,17 @@ { unsigned short id = circuit; unsigned char i, j; + struct sock *sk; for (;;) { i = id / 256; j = id % 256; - if (i != 0 && j != 0) - if (nr_find_socket(i, j) == NULL) + if (i != 0 && j != 0) { + if ((sk=nr_find_socket(i, j)) == NULL) break; + bh_unlock_sock(sk); + } id++; } @@ -231,7 +240,12 @@ */ static void nr_destroy_timer(unsigned long data) { - nr_destroy_socket((struct sock *)data); + struct sock *sk=(struct sock *)data; + bh_lock_sock(sk); + sock_hold(sk); + nr_destroy_socket(sk); + bh_unlock_sock(sk); + sock_put(sk); } /* @@ -264,17 +278,20 @@ kfree_skb(skb); } + while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) { + kfree_skb(skb); + } if (atomic_read(&sk->sk_wmem_alloc) || atomic_read(&sk->sk_rmem_alloc)) { /* Defer: outstanding buffers */ init_timer(&sk->sk_timer); - sk->sk_timer.expires = jiffies + 10 * HZ; + sk->sk_timer.expires = jiffies + 2 * HZ; sk->sk_timer.function = nr_destroy_timer; sk->sk_timer.data = (unsigned long)sk; add_timer(&sk->sk_timer); } else - sk_free(sk); + sock_put(sk); } /* @@ -388,12 +405,15 @@ { struct sock *sk = sock->sk; + lock_sock(sk); if (sk->sk_state != TCP_LISTEN) { memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN); sk->sk_max_ack_backlog = backlog; sk->sk_state = TCP_LISTEN; + release_sock(sk); return 0; } + release_sock(sk); return -EOPNOTSUPP; } @@ -495,6 +515,7 @@ if (sk == NULL) return 0; + lock_sock(sk); nr = nr_sk(sk); switch (nr->state) { @@ -528,6 +549,7 @@ } sock->sk = NULL; + release_sock(sk); return 0; } @@ -540,21 +562,26 @@ struct net_device *dev; ax25_address *user, *source; - if (!sk->sk_zapped) + lock_sock(sk); + if (!sk->sk_zapped) { + release_sock(sk); return -EINVAL; - - if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct -full_sockaddr_ax25)) + } + if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25)) { + release_sock(sk); return -EINVAL; - - if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) + } + if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) { + release_sock(sk); return -EINVAL; - - if (addr->fsa_ax25.sax25_family != AF_NETROM) + } + if (addr->fsa_ax25.sax25_family != AF_NETROM) { + release_sock(sk); return -EINVAL; - + } if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) { SOCK_DEBUG(sk, "NET/ROM: bind failed: invalid node callsign\n"); + release_sock(sk); return -EADDRNOTAVAIL; } @@ -562,16 +589,22 @@ * Only the super user can set an arbitrary user callsign. */ if (addr->fsa_ax25.sax25_ndigis == 1) { - if (!capable(CAP_NET_BIND_SERVICE)) + if (!capable(CAP_NET_BIND_SERVICE)) { + dev_put(dev); + release_sock(sk); return -EACCES; + } nr->user_addr = addr->fsa_digipeater[0]; nr->source_addr = addr->fsa_ax25.sax25_call; } else { source = &addr->fsa_ax25.sax25_call; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) + if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { + release_sock(sk); + dev_put(dev); return -EPERM; + } user = source; } @@ -583,6 +616,8 @@ nr_insert_socket(sk); sk->sk_zapped = 0; + dev_put(dev); + release_sock(sk); SOCK_DEBUG(sk, "NET/ROM: socket is bound\n"); return 0; } @@ -596,39 +631,50 @@ ax25_address *user, *source = NULL; struct net_device *dev; + lock_sock(sk); if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; + release_sock(sk); return 0; /* Connect completed during a ERESTARTSYS event */ } if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { sock->state = SS_UNCONNECTED; + release_sock(sk); return -ECONNREFUSED; } - if (sk->sk_state == TCP_ESTABLISHED) + if (sk->sk_state == TCP_ESTABLISHED) { + release_sock(sk); return -EISCONN; /* No reconnect on a seqpacket socket */ + } sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; - if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) + if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) { + release_sock(sk); return -EINVAL; - - if (addr->sax25_family != AF_NETROM) + } + if (addr->sax25_family != AF_NETROM) { + release_sock(sk); return -EINVAL; - + } if (sk->sk_zapped) { /* Must bind first - autobinding in this may or may not work */ sk->sk_zapped = 0; - if ((dev = nr_dev_first()) == NULL) + if ((dev = nr_dev_first()) == NULL) { + release_sock(sk); return -ENETUNREACH; - + } source = (ax25_address *)dev->dev_addr; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) + if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) { + dev_put(dev); + release_sock(sk); return -EPERM; + } user = source; } @@ -636,12 +682,15 @@ nr->source_addr = *source; nr->device = dev; + dev_put(dev); nr_insert_socket(sk); /* Finish the bind */ } nr->dest_addr = addr->sax25_call; + release_sock(sk); circuit = nr_find_next_circuit(); + lock_sock(sk); nr->my_index = circuit / 256; nr->my_id = circuit % 256; @@ -659,8 +708,10 @@ nr_start_heartbeat(sk); /* Now the loop */ - if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { + release_sock(sk); return -EINPROGRESS; + } /* * A Connect Ack with Choke or timeout or failed routing will go to @@ -675,8 +726,10 @@ set_current_state(TASK_INTERRUPTIBLE); if (sk->sk_state != TCP_SYN_SENT) break; + release_sock(sk); if (!signal_pending(tsk)) { schedule(); + lock_sock(sk); continue; } return -ERESTARTSYS; @@ -687,10 +740,12 @@ if (sk->sk_state != TCP_ESTABLISHED) { sock->state = SS_UNCONNECTED; + release_sock(sk); return sock_error(sk); /* Always set at this point */ } sock->state = SS_CONNECTED; + release_sock(sk); return 0; } @@ -753,6 +808,7 @@ newsock->sk = newsk; out: + release_sock(sk); return err; } @@ -763,9 +819,12 @@ struct sock *sk = sock->sk; nr_cb *nr = nr_sk(sk); + lock_sock(sk); if (peer != 0) { - if (sk->sk_state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) { + release_sock(sk); return -ENOTCONN; + } sax->fsa_ax25.sax25_family = AF_NETROM; sax->fsa_ax25.sax25_ndigis = 1; sax->fsa_ax25.sax25_call = nr->user_addr; @@ -777,6 +836,7 @@ sax->fsa_ax25.sax25_call = nr->source_addr; *uaddr_len = sizeof(struct sockaddr_ax25); } + release_sock(sk); return 0; } @@ -790,6 +850,7 @@ unsigned short circuit_index, circuit_id; unsigned short peer_circuit_index, peer_circuit_id; unsigned short frametype, flags, window, timeout; + int ret; skb->sk = NULL; /* Initially we don't know who it's for */ @@ -847,7 +908,9 @@ else nr_sk(sk)->bpqext = 0; - return nr_process_rx_frame(sk, skb); + ret = nr_process_rx_frame(sk, skb); + bh_unlock_sock(sk); + return ret; } /* @@ -877,6 +940,8 @@ if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog || (make = nr_make_new(sk)) == NULL) { nr_transmit_refusal(skb, 0); + if (sk) + bh_unlock_sock(sk); return 0; } @@ -894,7 +959,9 @@ nr_make->your_index = circuit_index; nr_make->your_id = circuit_id; + bh_unlock_sock(sk); circuit = nr_find_next_circuit(); + bh_lock_sock(sk); nr_make->my_index = circuit / 256; nr_make->my_id = circuit % 256; @@ -936,6 +1003,7 @@ if (!sock_flag(sk, SOCK_DEAD)) sk->sk_data_ready(sk, skb->len); + bh_unlock_sock(sk); return 1; } @@ -954,28 +1022,42 @@ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) return -EINVAL; - if (sk->sk_zapped) - return -EADDRNOTAVAIL; + lock_sock(sk); + if (sk->sk_zapped) { + err = -EADDRNOTAVAIL; + goto out; + } if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); - return -EPIPE; + err = -EPIPE; + goto out; } - if (nr->device == NULL) - return -ENETUNREACH; + if (nr->device == NULL) { + err = -ENETUNREACH; + goto out; + } if (usax) { - if (msg->msg_namelen < sizeof(sax)) - return -EINVAL; + if (msg->msg_namelen < sizeof(sax)) { + err = -EINVAL; + goto out; + } sax = *usax; - if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) - return -EISCONN; - if (sax.sax25_family != AF_NETROM) - return -EINVAL; + if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) { + err = -EISCONN; + goto out; + } + if (sax.sax25_family != AF_NETROM) { + err = -EINVAL; + goto out; + } } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; + if (sk->sk_state != TCP_ESTABLISHED) { + err = -ENOTCONN; + goto out; + } sax.sax25_family = AF_NETROM; sax.sax25_call = nr->dest_addr; } @@ -984,10 +1066,10 @@ /* Build a packet */ SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); - size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN; + size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN; if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) - return err; + goto out; skb_reserve(skb, size - len); @@ -1022,12 +1104,16 @@ if (sk->sk_state != TCP_ESTABLISHED) { kfree_skb(skb); - return -ENOTCONN; + err = -ENOTCONN; + goto out; } nr_output(sk, skb); /* Shove it onto the queue */ - return len; + err = len; +out: + release_sock(sk); + return err; } static int nr_recvmsg(struct kiocb *iocb, struct socket *sock, @@ -1044,12 +1130,17 @@ * us! We do one quick check first though */ - if (sk->sk_state != TCP_ESTABLISHED) + lock_sock(sk); + if (sk->sk_state != TCP_ESTABLISHED) { + release_sock(sk); return -ENOTCONN; + } /* Now we can treat all alike */ - if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) + if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) { + release_sock(sk); return er; + } skb->h.raw = skb->data; copied = skb->len; @@ -1070,6 +1161,7 @@ skb_free_datagram(sk, skb); + release_sock(sk); return copied; } @@ -1077,13 +1169,16 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; + int ret; + lock_sock(sk); switch (cmd) { case TIOCOUTQ: { long amount; amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; + release_sock(sk); return put_user(amount, (int *)arg); } @@ -1093,15 +1188,21 @@ /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; + release_sock(sk); return put_user(amount, (int *)arg); } case SIOCGSTAMP: if (sk != NULL) { - if (!sk->sk_stamp.tv_sec) + if (!sk->sk_stamp.tv_sec) { + release_sock(sk); return -ENOENT; - return copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0; + } + ret = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0; + release_sock(sk); + return ret; } + release_sock(sk); return -EINVAL; case SIOCGIFADDR: @@ -1114,17 +1215,21 @@ case SIOCSIFNETMASK: case SIOCGIFMETRIC: case SIOCSIFMETRIC: + release_sock(sk); return -EINVAL; case SIOCADDRT: case SIOCDELRT: case SIOCNRDECOBS: + release_sock(sk); if (!capable(CAP_NET_ADMIN)) return -EPERM; return nr_rt_ioctl(cmd, (void *)arg); default: + release_sock(sk); return dev_ioctl(cmd, (void *)arg); } + release_sock(sk); return 0; } @@ -1144,7 +1249,9 @@ len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n"); sk_for_each(s, node, &nr_list) { - nr_cb *nr = nr_sk(s); + nr_cb *nr; + bh_lock_sock(s); + nr = nr_sk(s); if ((dev = nr->device) == NULL) devname = "???"; @@ -1187,7 +1294,7 @@ len = 0; begin = pos; } - + bh_unlock_sock(s); if (pos > offset + length) break; } @@ -1256,6 +1363,7 @@ for (i = 0; i < nr_ndevs; i++) { sprintf(dev_nr[i].name, "nr%d", i); + dev_nr[i].base_addr = i; dev_nr[i].init = nr_init; register_netdev(&dev_nr[i]); } @@ -1300,23 +1408,23 @@ nr_rt_free(); - ax25_protocol_release(AX25_P_NETROM); +#ifdef CONFIG_SYSCTL + nr_unregister_sysctl(); +#endif + ax25_linkfail_release(nr_link_failed); + ax25_protocol_release(AX25_P_NETROM); unregister_netdevice_notifier(&nr_dev_notifier); -#ifdef CONFIG_SYSCTL - nr_unregister_sysctl(); -#endif sock_unregister(PF_NETROM); for (i = 0; i < nr_ndevs; i++) { if (dev_nr[i].priv != NULL) { + unregister_netdev(&dev_nr[i]); kfree(dev_nr[i].priv); dev_nr[i].priv = NULL; - unregister_netdev(&dev_nr[i]); } - kfree(dev_nr[i].name); } kfree(dev_nr); Only in linux-2.6.0-test3.rxq/net/netrom: af_netrom.o Only in linux-2.6.0-test3.rxq/net/netrom: built-in.o Only in linux-2.6.0-test3.rxq/net/netrom: netrom.ko Only in linux-2.6.0-test3.rxq/net/netrom: netrom.mod.c Only in linux-2.6.0-test3.rxq/net/netrom: netrom.mod.o Only in linux-2.6.0-test3.rxq/net/netrom: netrom.o diff -ru linux-2.6.0-test3/net/netrom/nr_dev.c linux-2.6.0-test3.rxq/net/netrom/nr_dev.c --- linux-2.6.0-test3/net/netrom/nr_dev.c 2003-08-09 06:41:27.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_dev.c 2003-08-12 23:40:35.000000000 +0200 @@ -159,11 +159,13 @@ { struct sockaddr *sa = addr; - ax25_listen_release((ax25_address *)dev->dev_addr, NULL); + if (dev->flags & IFF_UP) + ax25_listen_release((ax25_address *)dev->dev_addr, NULL); memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); - ax25_listen_register((ax25_address *)dev->dev_addr, NULL); + if (dev->flags & IFF_UP) + ax25_listen_register((ax25_address *)dev->dev_addr, NULL); return 0; } @@ -177,8 +179,8 @@ static int nr_close(struct net_device *dev) { - netif_stop_queue(dev); ax25_listen_release((ax25_address *)dev->dev_addr, NULL); + netif_stop_queue(dev); return 0; } @@ -197,16 +199,16 @@ int nr_init(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->mtu = NR_MAX_PACKET_SIZE; dev->hard_start_xmit = nr_xmit; dev->open = nr_open; dev->stop = nr_close; dev->hard_header = nr_header; - dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN; + dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN; dev->addr_len = AX25_ADDR_LEN; dev->type = ARPHRD_NETROM; + dev->tx_queue_len = 40; dev->rebuild_header = nr_rebuild_header; dev->set_mac_address = nr_set_mac_address; Only in linux-2.6.0-test3.rxq/net/netrom: nr_dev.o diff -ru linux-2.6.0-test3/net/netrom/nr_in.c linux-2.6.0-test3.rxq/net/netrom/nr_in.c --- linux-2.6.0-test3/net/netrom/nr_in.c 2003-08-09 06:34:46.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_in.c 2003-08-12 23:40:35.000000000 +0200 @@ -74,6 +74,7 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) { + bh_lock_sock(sk); switch (frametype) { case NR_CONNACK: { nr_cb *nr = nr_sk(sk); @@ -102,6 +103,7 @@ default: break; } + bh_unlock_sock(sk); return 0; } @@ -114,6 +116,7 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) { + bh_lock_sock(sk); switch (frametype) { case NR_CONNACK | NR_CHOKE_FLAG: nr_disconnect(sk, ECONNRESET); @@ -129,6 +132,7 @@ default: break; } + bh_unlock_sock(sk); return 0; } @@ -150,6 +154,7 @@ nr = skb->data[18]; ns = skb->data[17]; + bh_lock_sock(sk); switch (frametype) { case NR_CONNREQ: nr_write_internal(sk, NR_CONNACK); @@ -260,6 +265,7 @@ default: break; } + bh_unlock_sock(sk); return queued; } Only in linux-2.6.0-test3.rxq/net/netrom: nr_in.o Only in linux-2.6.0-test3.rxq/net/netrom: nr_loopback.o Only in linux-2.6.0-test3.rxq/net/netrom: nr_out.o diff -ru linux-2.6.0-test3/net/netrom/nr_route.c linux-2.6.0-test3.rxq/net/netrom/nr_route.c --- linux-2.6.0-test3/net/netrom/nr_route.c 2003-08-09 06:42:17.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_route.c 2003-08-12 23:40:35.000000000 +0200 @@ -39,10 +39,45 @@ static unsigned int nr_neigh_no = 1; -static struct nr_node *nr_node_list; -static spinlock_t nr_node_lock; -static struct nr_neigh *nr_neigh_list; -static spinlock_t nr_neigh_lock; +HLIST_HEAD(nr_node_list); +spinlock_t nr_node_list_lock = SPIN_LOCK_UNLOCKED; +HLIST_HEAD(nr_neigh_list); +spinlock_t nr_neigh_list_lock = SPIN_LOCK_UNLOCKED; + +struct nr_node *nr_node_get(ax25_address *callsign) +{ + struct nr_node *found = NULL; + struct nr_node *nr_node; + struct hlist_node *node; + + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each(nr_node, node, &nr_node_list) + if (ax25cmp(callsign, &nr_node->callsign) == 0) { + nr_node_hold(nr_node); + found = nr_node; + break; + } + spin_unlock_bh(&nr_node_list_lock); + return found; +} + +struct nr_neigh *nr_neigh_get_dev(ax25_address *callsign, struct net_device *dev) +{ + struct nr_neigh *found = NULL; + struct nr_neigh *nr_neigh; + struct hlist_node *node; + + spin_lock_bh(&nr_neigh_list_lock); + nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) + if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && + nr_neigh->dev == dev) { + nr_neigh_hold(nr_neigh); + found = nr_neigh; + break; + } + spin_unlock_bh(&nr_neigh_list_lock); + return found; +} static void nr_remove_neigh(struct nr_neigh *); @@ -57,17 +92,16 @@ struct nr_neigh *nr_neigh; struct nr_route nr_route; int i, found; + struct net_device *odev; - if (nr_dev_get(nr) != NULL) /* Can't add routes to ourself */ + if ((odev=nr_dev_get(nr)) != NULL) { /* Can't add routes to ourself */ + dev_put(odev); return -EINVAL; + } - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) - if (ax25cmp(nr, &nr_node->callsign) == 0) - break; + nr_node = nr_node_get(nr); - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) - break; + nr_neigh = nr_neigh_get_dev(ax25, dev); /* * The L2 link to a neighbour has failed in the past @@ -76,24 +110,36 @@ * routes now (and not wait for a node broadcast). */ if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) { - struct nr_node *node; + struct nr_node *nr_nodet; + struct hlist_node *node; - for (node = nr_node_list; node != NULL; node = node->next) - for (i = 0; i < node->count; i++) - if (node->routes[i].neighbour == nr_neigh) - if (i < node->which) - node->which = i; + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each(nr_nodet, node, &nr_node_list) { + nr_node_lock(nr_nodet); + for (i = 0; i < nr_nodet->count; i++) + if (nr_nodet->routes[i].neighbour == nr_neigh) + if (i < nr_nodet->which) + nr_nodet->which = i; + nr_node_unlock(nr_nodet); + } + spin_unlock_bh(&nr_node_list_lock); } if (nr_neigh != NULL) nr_neigh->failed = 0; - if (quality == 0 && nr_neigh != NULL && nr_node != NULL) + if (quality == 0 && nr_neigh != NULL && nr_node != NULL) { + nr_neigh_put(nr_neigh); + nr_node_put(nr_node); return 0; + } if (nr_neigh == NULL) { - if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) + if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) { + if (nr_node) + nr_node_put(nr_node); return -ENOMEM; + } nr_neigh->callsign = *ax25; nr_neigh->digipeat = NULL; @@ -104,48 +150,58 @@ nr_neigh->count = 0; nr_neigh->number = nr_neigh_no++; nr_neigh->failed = 0; + atomic_set(&nr_neigh->refcount, 1); if (ax25_digi != NULL && ax25_digi->ndigi > 0) { if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) { kfree(nr_neigh); + if (nr_node) + nr_node_put(nr_node); return -ENOMEM; } memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi)); } - spin_lock_bh(&nr_neigh_lock); - nr_neigh->next = nr_neigh_list; - nr_neigh_list = nr_neigh; - spin_unlock_bh(&nr_neigh_lock); + spin_lock_bh(&nr_neigh_list_lock); + hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list); + nr_neigh_hold(nr_neigh); + spin_unlock_bh(&nr_neigh_list_lock); } if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked) nr_neigh->quality = quality; if (nr_node == NULL) { - if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) + if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) { + if (nr_neigh) + nr_neigh_put(nr_neigh); return -ENOMEM; + } nr_node->callsign = *nr; strcpy(nr_node->mnemonic, mnemonic); nr_node->which = 0; nr_node->count = 1; + atomic_set(&nr_node->refcount, 1); + nr_node->node_lock = SPIN_LOCK_UNLOCKED; nr_node->routes[0].quality = quality; nr_node->routes[0].obs_count = obs_count; nr_node->routes[0].neighbour = nr_neigh; - spin_lock_bh(&nr_node_lock); - nr_node->next = nr_node_list; - nr_node_list = nr_node; - spin_unlock_bh(&nr_node_lock); - + nr_neigh_hold(nr_neigh); nr_neigh->count++; + spin_lock_bh(&nr_node_list_lock); + hlist_add_head(&nr_node->node_node, &nr_node_list); + /* refcount initialized at 1 */ + spin_unlock_bh(&nr_node_list_lock); + return 0; } + nr_node_lock(nr_node); if (quality != 0) strcpy(nr_node->mnemonic, mnemonic); @@ -171,11 +227,13 @@ nr_node->which++; nr_node->count++; + nr_neigh_hold(nr_neigh); nr_neigh->count++; } else { /* It must be better than the worst */ if (quality > nr_node->routes[2].quality) { nr_node->routes[2].neighbour->count--; + nr_neigh_put(nr_node->routes[2].neighbour); if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked) nr_remove_neigh(nr_node->routes[2].neighbour); @@ -184,6 +242,7 @@ nr_node->routes[2].obs_count = obs_count; nr_node->routes[2].neighbour = nr_neigh; + nr_neigh_hold(nr_neigh); nr_neigh->count++; } } @@ -244,62 +303,42 @@ } } + nr_neigh_put(nr_neigh); + nr_node_unlock(nr_node); + nr_node_put(nr_node); return 0; } -static void nr_remove_node(struct nr_node *nr_node) +static inline void __nr_remove_node(struct nr_node *nr_node) { - struct nr_node *s; - - spin_lock_bh(&nr_node_lock); - if ((s = nr_node_list) == nr_node) { - nr_node_list = nr_node->next; - spin_unlock_bh(&nr_node_lock); - kfree(nr_node); - return; - } - - while (s != NULL && s->next != NULL) { - if (s->next == nr_node) { - s->next = nr_node->next; - spin_unlock_bh(&nr_node_lock); - kfree(nr_node); - return; - } + hlist_del_init(&nr_node->node_node); + nr_node_put(nr_node); +} - s = s->next; - } +#define nr_remove_node_locked(__node) \ + __nr_remove_node(__node) - spin_unlock_bh(&nr_node_lock); +static void nr_remove_node(struct nr_node *nr_node) +{ + spin_lock_bh(&nr_node_list_lock); + __nr_remove_node(nr_node); + spin_unlock_bh(&nr_node_list_lock); } -static void nr_remove_neigh(struct nr_neigh *nr_neigh) +static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh) { - struct nr_neigh *s; + hlist_del_init(&nr_neigh->neigh_node); + nr_neigh_put(nr_neigh); +} - spin_lock_bh(&nr_neigh_lock); - if ((s = nr_neigh_list) == nr_neigh) { - nr_neigh_list = nr_neigh->next; - spin_unlock_bh(&nr_neigh_lock); - if (nr_neigh->digipeat != NULL) - kfree(nr_neigh->digipeat); - kfree(nr_neigh); - return; - } +#define nr_remove_neigh_locked(__neigh) \ + __nr_remove_neigh(__neigh) - while (s != NULL && s->next != NULL) { - if (s->next == nr_neigh) { - s->next = nr_neigh->next; - spin_unlock_bh(&nr_neigh_lock); - if (nr_neigh->digipeat != NULL) - kfree(nr_neigh->digipeat); - kfree(nr_neigh); - return; - } - - s = s->next; - } - spin_unlock_bh(&nr_neigh_lock); +static void nr_remove_neigh(struct nr_neigh *nr_neigh) +{ + spin_lock_bh(&nr_neigh_list_lock); + __nr_remove_neigh(nr_neigh); + spin_unlock_bh(&nr_neigh_list_lock); } /* @@ -312,26 +351,27 @@ struct nr_neigh *nr_neigh; int i; - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) - if (ax25cmp(callsign, &nr_node->callsign) == 0) - break; + nr_node = nr_node_get(callsign); if (nr_node == NULL) return -EINVAL; - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) - break; + nr_neigh = nr_neigh_get_dev(neighbour, dev); - if (nr_neigh == NULL) + if (nr_neigh == NULL) { + nr_node_put(nr_node); return -EINVAL; + } + nr_node_lock(nr_node); for (i = 0; i < nr_node->count; i++) { if (nr_node->routes[i].neighbour == nr_neigh) { nr_neigh->count--; + nr_neigh_put(nr_neigh); if (nr_neigh->count == 0 && !nr_neigh->locked) nr_remove_neigh(nr_neigh); + nr_neigh_put(nr_neigh); nr_node->count--; @@ -346,11 +386,16 @@ case 2: break; } + nr_node_put(nr_node); } + nr_node_unlock(nr_node); return 0; } } + nr_neigh_put(nr_neigh); + nr_node_unlock(nr_node); + nr_node_put(nr_node); return -EINVAL; } @@ -362,12 +407,12 @@ { struct nr_neigh *nr_neigh; - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) { - if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) { - nr_neigh->quality = quality; - nr_neigh->locked = 1; - return 0; - } + nr_neigh = nr_neigh_get_dev(callsign, dev); + if (nr_neigh) { + nr_neigh->quality = quality; + nr_neigh->locked = 1; + nr_neigh_put(nr_neigh); + return 0; } if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) @@ -382,6 +427,7 @@ nr_neigh->count = 0; nr_neigh->number = nr_neigh_no++; nr_neigh->failed = 0; + atomic_set(&nr_neigh->refcount, 1); if (ax25_digi != NULL && ax25_digi->ndigi > 0) { if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) { @@ -391,10 +437,10 @@ memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi)); } - spin_lock_bh(&nr_neigh_lock); - nr_neigh->next = nr_neigh_list; - nr_neigh_list = nr_neigh; - spin_unlock_bh(&nr_neigh_lock); + spin_lock_bh(&nr_neigh_list_lock); + hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list); + /* refcount is initialized at 1 */ + spin_unlock_bh(&nr_neigh_list_lock); return 0; } @@ -407,9 +453,7 @@ { struct nr_neigh *nr_neigh; - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) - break; + nr_neigh = nr_neigh_get_dev(callsign, dev); if (nr_neigh == NULL) return -EINVAL; @@ -418,6 +462,7 @@ if (nr_neigh->count == 0) nr_remove_neigh(nr_neigh); + nr_neigh_put(nr_neigh); return 0; } @@ -430,15 +475,13 @@ static int nr_dec_obs(void) { struct nr_neigh *nr_neigh; - struct nr_node *s, *nr_node; + struct nr_node *s; + struct hlist_node *node, *nodet; int i; - nr_node = nr_node_list; - - while (nr_node != NULL) { - s = nr_node; - nr_node = nr_node->next; - + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each_safe(s, node, nodet, &nr_node_list) { + nr_node_lock(s); for (i = 0; i < s->count; i++) { switch (s->routes[i].obs_count) { case 0: /* A locked entry */ @@ -448,6 +491,7 @@ nr_neigh = s->routes[i].neighbour; nr_neigh->count--; + nr_neigh_put(nr_neigh); if (nr_neigh->count == 0 && !nr_neigh->locked) nr_remove_neigh(nr_neigh); @@ -472,8 +516,10 @@ } if (s->count <= 0) - nr_remove_node(s); + nr_remove_node_locked(s); + nr_node_unlock(s); } + spin_unlock_bh(&nr_node_list_lock); return 0; } @@ -483,21 +529,17 @@ */ void nr_rt_device_down(struct net_device *dev) { - struct nr_neigh *s, *nr_neigh = nr_neigh_list; - struct nr_node *t, *nr_node; + struct nr_neigh *s; + struct hlist_node *node, *nodet, *node2, *node2t; + struct nr_node *t; int i; - while (nr_neigh != NULL) { - s = nr_neigh; - nr_neigh = nr_neigh->next; - + spin_lock_bh(&nr_neigh_list_lock); + nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) { if (s->dev == dev) { - nr_node = nr_node_list; - - while (nr_node != NULL) { - t = nr_node; - nr_node = nr_node->next; - + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each_safe(t, node2, node2t, &nr_node_list) { + nr_node_lock(t); for (i = 0; i < t->count; i++) { if (t->routes[i].neighbour == s) { t->count--; @@ -514,12 +556,15 @@ } if (t->count <= 0) - nr_remove_node(t); + nr_remove_node_locked(t); + nr_node_unlock(t); } + spin_unlock_bh(&nr_node_list_lock); - nr_remove_neigh(s); + nr_remove_neigh_locked(s); } } + spin_unlock_bh(&nr_neigh_list_lock); } /* @@ -553,6 +598,8 @@ if (first == NULL || strncmp(dev->name, first->name, 3) < 0) first = dev; } + if (first) + dev_hold(first); read_unlock(&dev_base_lock); return first; @@ -603,6 +650,7 @@ { struct nr_route_struct nr_route; struct net_device *dev; + int ret; switch (cmd) { case SIOCADDRT: @@ -610,23 +658,29 @@ return -EFAULT; if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) return -EINVAL; - if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) + if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) { + dev_put(dev); return -EINVAL; + } switch (nr_route.type) { case NETROM_NODE: - return nr_add_node(&nr_route.callsign, + ret = nr_add_node(&nr_route.callsign, nr_route.mnemonic, &nr_route.neighbour, nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), dev, nr_route.quality, nr_route.obs_count); + break; case NETROM_NEIGH: - return nr_add_neigh(&nr_route.callsign, + ret = nr_add_neigh(&nr_route.callsign, nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), dev, nr_route.quality); + break; default: - return -EINVAL; + ret = -EINVAL; } + dev_put(dev); + return ret; case SIOCDELRT: if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) @@ -635,14 +689,18 @@ return -EINVAL; switch (nr_route.type) { case NETROM_NODE: - return nr_del_node(&nr_route.callsign, + ret = nr_del_node(&nr_route.callsign, &nr_route.neighbour, dev); + break; case NETROM_NEIGH: - return nr_del_neigh(&nr_route.callsign, + ret = nr_del_neigh(&nr_route.callsign, dev, nr_route.quality); + break; default: - return -EINVAL; + ret = -EINVAL; } + dev_put(dev); + return ret; case SIOCNRDECOBS: return nr_dec_obs(); @@ -660,22 +718,36 @@ */ void nr_link_failed(ax25_cb *ax25, int reason) { - struct nr_neigh *nr_neigh; - struct nr_node *nr_node; - - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (nr_neigh->ax25 == ax25) + struct nr_neigh *s, *nr_neigh = NULL; + struct hlist_node *node; + struct nr_node *nr_node = NULL; + + spin_lock_bh(&nr_neigh_list_lock); + nr_neigh_for_each(s, node, &nr_neigh_list) + if (s->ax25 == ax25) { + nr_neigh_hold(s); + nr_neigh = s; break; + } + spin_unlock_bh(&nr_neigh_list_lock); if (nr_neigh == NULL) return; nr_neigh->ax25 = NULL; + ax25_cb_put(ax25); - if (++nr_neigh->failed < sysctl_netrom_link_fails_count) return; - - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) + if (++nr_neigh->failed < sysctl_netrom_link_fails_count) { + nr_neigh_put(nr_neigh); + return; + } + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each(nr_node, node, &nr_node_list) + nr_node_lock(nr_node); if (nr_node->which < nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh) nr_node->which++; + nr_node_unlock(nr_node); + spin_unlock_bh(&nr_node_list_lock); + nr_neigh_put(nr_neigh); } /* @@ -689,6 +761,9 @@ struct nr_node *nr_node; struct net_device *dev; unsigned char *dptr; + ax25_cb *ax25s; + int ret; + struct sk_buff *skbn; nr_src = (ax25_address *)(skb->data + 0); @@ -700,50 +775,84 @@ if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */ if (ax25 == NULL) /* Its from me */ - return nr_loopback_queue(skb); + ret = nr_loopback_queue(skb); else - return nr_rx_frame(skb, dev); + ret = nr_rx_frame(skb, dev); + dev_put(dev); + return ret; } if (!sysctl_netrom_routing_control && ax25 != NULL) return 0; /* Its Time-To-Live has expired */ - if (--skb->data[14] == 0) + if (skb->data[14] == 1) { return 0; + } - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) - if (ax25cmp(nr_dest, &nr_node->callsign) == 0) - break; + nr_node = nr_node_get(nr_dest); + if (nr_node == NULL) + return 0; + nr_node_lock(nr_node); - if (nr_node == NULL || nr_node->which >= nr_node->count) + if (nr_node->which >= nr_node->count) { + nr_node_unlock(nr_node); + nr_node_put(nr_node); return 0; + } nr_neigh = nr_node->routes[nr_node->which].neighbour; - if ((dev = nr_dev_first()) == NULL) + if ((dev = nr_dev_first()) == NULL) { + nr_node_unlock(nr_node); + nr_node_put(nr_node); + return 0; + } + + /* We are going to change the netrom headers so we should get our + own skb, we also did not know until now how much header space + we had to reserve... - RXQ */ + if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) { + nr_node_unlock(nr_node); + nr_node_put(nr_node); + dev_put(dev); return 0; + } + kfree_skb(skb); + skb=skbn; + skb->data[14]--; dptr = skb_push(skb, 1); *dptr = AX25_P_NETROM; - nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); + ax25s = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); + if (nr_neigh->ax25 && ax25s) { + /* We were already holding this ax25_cb */ + ax25_cb_put(ax25s); + } + nr_neigh->ax25 = ax25s; - return (nr_neigh->ax25 != NULL); + dev_put(dev); + ret = (nr_neigh->ax25 != NULL); + nr_node_unlock(nr_node); + nr_node_put(nr_node); + return ret; } int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length) { struct nr_node *nr_node; + struct hlist_node *node; int len = 0; off_t pos = 0; off_t begin = 0; int i; - spin_lock_bh(&nr_node_lock); + spin_lock_bh(&nr_node_list_lock); len += sprintf(buffer, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n"); - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) { + nr_node_for_each(nr_node, node, &nr_node_list) { + nr_node_lock(nr_node); len += sprintf(buffer + len, "%-9s %-7s %d %d", ax2asc(&nr_node->callsign), (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic, @@ -756,6 +865,7 @@ nr_node->routes[i].obs_count, nr_node->routes[i].neighbour->number); } + nr_node_unlock(nr_node); len += sprintf(buffer + len, "\n"); @@ -769,7 +879,7 @@ if (pos > offset + length) break; } - spin_unlock_bh(&nr_node_lock); + spin_unlock_bh(&nr_node_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -782,15 +892,16 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length) { struct nr_neigh *nr_neigh; + struct hlist_node *node; int len = 0; off_t pos = 0; off_t begin = 0; int i; - spin_lock_bh(&nr_neigh_lock); + spin_lock_bh(&nr_neigh_list_lock); len += sprintf(buffer, "addr callsign dev qual lock count failed digipeaters\n"); - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) { + nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) { len += sprintf(buffer + len, "%05d %-9s %-4s %3d %d %3d %3d", nr_neigh->number, ax2asc(&nr_neigh->callsign), @@ -818,7 +929,7 @@ break; } - spin_unlock_bh(&nr_neigh_lock); + spin_unlock_bh(&nr_neigh_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -833,20 +944,24 @@ */ void __exit nr_rt_free(void) { - struct nr_neigh *s, *nr_neigh = nr_neigh_list; - struct nr_node *t, *nr_node = nr_node_list; - - while (nr_node != NULL) { - t = nr_node; - nr_node = nr_node->next; - - nr_remove_node(t); - } - - while (nr_neigh != NULL) { - s = nr_neigh; - nr_neigh = nr_neigh->next; - - nr_remove_neigh(s); + struct nr_neigh *s = NULL; + struct nr_node *t = NULL; + struct hlist_node *node, *nodet; + + spin_lock_bh(&nr_neigh_list_lock); + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each_safe(t, node, nodet, &nr_node_list) { + nr_node_lock(t); + nr_remove_node_locked(t); + nr_node_unlock(t); + } + nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) { + while(s->count) { + s->count--; + nr_neigh_put(s); + } + nr_remove_neigh_locked(s); } + spin_unlock_bh(&nr_node_list_lock); + spin_unlock_bh(&nr_neigh_list_lock); } Only in linux-2.6.0-test3.rxq/net/netrom: nr_route.o diff -ru linux-2.6.0-test3/net/netrom/nr_subr.c linux-2.6.0-test3.rxq/net/netrom/nr_subr.c --- linux-2.6.0-test3/net/netrom/nr_subr.c 2003-08-09 06:42:56.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_subr.c 2003-08-12 23:40:35.000000000 +0200 @@ -127,7 +127,7 @@ unsigned char *dptr; int len, timeout; - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN; + len = NR_NETWORK_LEN + NR_TRANSPORT_LEN; switch (frametype & 0x0F) { case NR_CONNREQ: @@ -151,7 +151,7 @@ /* * Space for AX.25 and NET/ROM network header */ - skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN); + skb_reserve(skb, NR_NETWORK_LEN); dptr = skb_put(skb, skb_tailroom(skb)); @@ -219,12 +219,12 @@ unsigned char *dptr; int len; - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; + len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL) return; - skb_reserve(skbn, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN); + skb_reserve(skbn, 0); dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN); Only in linux-2.6.0-test3.rxq/net/netrom: nr_subr.o diff -ru linux-2.6.0-test3/net/netrom/nr_timer.c linux-2.6.0-test3.rxq/net/netrom/nr_timer.c --- linux-2.6.0-test3/net/netrom/nr_timer.c 2003-08-09 06:38:56.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_timer.c 2003-08-12 23:40:35.000000000 +0200 @@ -143,7 +143,10 @@ is accepted() it isn't 'dead' so doesn't get removed. */ if (sock_flag(sk, SOCK_DESTROY) || (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { + sock_hold(sk); nr_destroy_socket(sk); + bh_unlock_sock(sk); + sock_put(sk); return; } break; @@ -227,6 +230,7 @@ case NR_STATE_1: if (nr->n2count == nr->n2) { nr_disconnect(sk, ETIMEDOUT); + bh_unlock_sock(sk); return; } else { nr->n2count++; @@ -237,6 +241,7 @@ case NR_STATE_2: if (nr->n2count == nr->n2) { nr_disconnect(sk, ETIMEDOUT); + bh_unlock_sock(sk); return; } else { nr->n2count++; @@ -247,6 +252,7 @@ case NR_STATE_3: if (nr->n2count == nr->n2) { nr_disconnect(sk, ETIMEDOUT); + bh_unlock_sock(sk); return; } else { nr->n2count++; Only in linux-2.6.0-test3.rxq/net/netrom: nr_timer.o diff -ru linux-2.6.0-test3/net/netrom/sysctl_net_netrom.c linux-2.6.0-test3.rxq/net/netrom/sysctl_net_netrom.c --- linux-2.6.0-test3/net/netrom/sysctl_net_netrom.c 2003-08-09 06:33:21.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/sysctl_net_netrom.c 2003-08-12 23:40:35.000000000 +0200 @@ -15,9 +15,9 @@ /* * Values taken from NET/ROM documentation. */ -static int min_quality[1], max_quality[] = {255}; -static int min_obs[1], max_obs[] = {255}; -static int min_ttl[1], max_ttl[] = {255}; +static int min_quality[] = {0}, max_quality[] = {255}; +static int min_obs[] = {0}, max_obs[] = {255}; +static int min_ttl[] = {0}, max_ttl[] = {255}; static int min_t1[] = {5 * HZ}; static int max_t1[] = {600 * HZ}; static int min_n2[] = {2}, max_n2[] = {127}; @@ -28,7 +28,7 @@ static int min_window[] = {1}, max_window[] = {127}; static int min_idle[] = {0 * HZ}; static int max_idle[] = {65535 * HZ}; -static int min_route[1], max_route[] = {1}; +static int min_route[] = {0}, max_route[] = {1}; static int min_fails[] = {1}, max_fails[] = {10}; static struct ctl_table_header *nr_table_header; Only in linux-2.6.0-test3.rxq/net/netrom: sysctl_net_netrom.o --- linux-2.6.0-test3/include/net/ax25.h 2003-08-09 06:38:16.000000000 +0200 +++ linux-2.6.0-test3.rxq/include/net/ax25.h 2003-08-12 23:40:35.000000000 +0200 @@ -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 @@ } 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 @@ 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 *); --- linux-2.6.0-test3/include/net/netrom.h 2003-08-09 06:37:18.000000000 +0200 +++ linux-2.6.0-test3.rxq/include/net/netrom.h 2003-08-12 23:40:35.000000000 +0200 @@ -7,6 +7,7 @@ #ifndef _NETROM_H #define _NETROM_H #include <linux/netrom.h> +#include <linux/list.h> #define NR_NETWORK_LEN 15 #define NR_TRANSPORT_LEN 5 @@ -77,16 +78,17 @@ #define nr_sk(__sk) ((nr_cb *)(__sk)->sk_protinfo) struct nr_neigh { - struct nr_neigh *next; - ax25_address callsign; - ax25_digi *digipeat; - ax25_cb *ax25; - struct net_device *dev; - unsigned char quality; - unsigned char locked; - unsigned short count; - unsigned int number; - unsigned char failed; + struct hlist_node neigh_node; + ax25_address callsign; + ax25_digi *digipeat; + ax25_cb *ax25; + struct net_device *dev; + unsigned char quality; + unsigned char locked; + unsigned short count; + unsigned int number; + unsigned char failed; + atomic_t refcount; }; struct nr_route { @@ -96,14 +98,74 @@ }; struct nr_node { - struct nr_node *next; - ax25_address callsign; - char mnemonic[7]; - unsigned char which; - unsigned char count; - struct nr_route routes[3]; + struct hlist_node node_node; + ax25_address callsign; + char mnemonic[7]; + unsigned char which; + unsigned char count; + struct nr_route routes[3]; + atomic_t refcount; + spinlock_t node_lock; }; +/********************************************************************* + * nr_node & nr_neigh lists, refcounting and locking + *********************************************************************/ + +extern struct hlist_head nr_node_list; +extern struct hlist_head nr_neigh_list; + +#define nr_node_hold(__nr_node) \ + atomic_inc(&((__nr_node)->refcount)) + +static __inline__ void nr_node_put(struct nr_node *nr_node) +{ + if (atomic_dec_and_test(&nr_node->refcount)) { + kfree(nr_node); + } +} + +#define nr_neigh_hold(__nr_neigh) \ + atomic_inc(&((__nr_neigh)->refcount)) + +static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh) +{ + if (atomic_dec_and_test(&nr_neigh->refcount)) { + if (nr_neigh->digipeat != NULL) + kfree(nr_neigh->digipeat); + kfree(nr_neigh); + } +} + +/* nr_node_lock and nr_node_unlock also hold/put the node's refcounter. + */ +static __inline__ void nr_node_lock(struct nr_node *nr_node) +{ + nr_node_hold(nr_node); + spin_lock_bh(&nr_node->node_lock); +} + +static __inline__ void nr_node_unlock(struct nr_node *nr_node) +{ + spin_unlock_bh(&nr_node->node_lock); + nr_node_put(nr_node); +} + +#define nr_neigh_for_each(__nr_neigh, node, list) \ + hlist_for_each_entry(__nr_neigh, node, list, neigh_node) + +#define nr_neigh_for_each_safe(__nr_neigh, node, node2, list) \ + hlist_for_each_entry_safe(__nr_neigh, node, node2, list, neigh_node) + +#define nr_node_for_each(__nr_node, node, list) \ + hlist_for_each_entry(__nr_node, node, list, node_node) + +#define nr_node_for_each_safe(__nr_node, node, node2, list) \ + hlist_for_each_entry_safe(__nr_node, node, node2, list, node_node) + + +/*********************************************************************/ + /* af_netrom.c */ extern int sysctl_netrom_default_path_quality; extern int sysctl_netrom_obsolescence_count_initialiser; ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH] ax25 use dev_hold/dev_put as required for net_devices. 2003-08-12 23:03 ` Jeroen Vreeken @ 2003-08-12 23:49 ` Stephen Hemminger 2003-08-13 0:19 ` [PATCH] ax25 setsockopt(SO_BINDTODEVICE) bug fix Stephen Hemminger 2003-08-13 0:21 ` [PATCH] Convert ax25 to seq_file Stephen Hemminger 2 siblings, 0 replies; 23+ messages in thread From: Stephen Hemminger @ 2003-08-12 23:49 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: linux-hams, ralf, davem, netdev Ax25 holds a reference to the net device below, in the ax25_dev structure; therefore it needs to use dev_hold/dev_put. This is against 2.6.0-test3 with your earlier patch diff -Nru a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c --- a/net/ax25/ax25_dev.c Tue Aug 12 16:45:51 2003 +++ b/net/ax25/ax25_dev.c Tue Aug 12 16:45:51 2003 @@ -67,6 +67,7 @@ dev->ax25_ptr = ax25_dev; ax25_dev->dev = dev; + dev_hold(dev); ax25_dev->forward = NULL; ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE; @@ -121,6 +122,7 @@ if ((s = ax25_dev_list) == ax25_dev) { ax25_dev_list = s->next; spin_unlock_bh(&ax25_dev_lock); + dev_put(dev); kfree(ax25_dev); ax25_register_sysctl(); return; @@ -131,6 +133,7 @@ s->next = ax25_dev->next; spin_unlock_bh(&ax25_dev_lock); kfree(ax25_dev); + dev_put(dev); ax25_register_sysctl(); return; } ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH] ax25 setsockopt(SO_BINDTODEVICE) bug fix 2003-08-12 23:03 ` Jeroen Vreeken 2003-08-12 23:49 ` [PATCH] ax25 use dev_hold/dev_put as required for net_devices Stephen Hemminger @ 2003-08-13 0:19 ` Stephen Hemminger 2003-08-13 0:21 ` [PATCH] Convert ax25 to seq_file Stephen Hemminger 2 siblings, 0 replies; 23+ messages in thread From: Stephen Hemminger @ 2003-08-13 0:19 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: linux-hams, ralf, davem, netdev Fix the error path (and indentation) in the SO_BINDTODEVICE setsockopt. As it was, a reference to the device was left hanging, and it would not check to see if the device was really an AX25 device. Found this with a simple test program on 2.6.0-test3 with your rqx4 patch. --- ax25/net/ax25/af_ax25.c 2003-08-12 17:08:42.025816088 -0700 +++ linux-2.5-net/net/ax25/af_ax25.c 2003-08-12 16:47:07.802057749 -0700 if (optlen > IFNAMSIZ) optlen=IFNAMSIZ; if (copy_from_user(devname, optval, optlen)) { - res = -EFAULT; + res = -EFAULT; break; } @@ -650,12 +650,14 @@ static int ax25_setsockopt(struct socket (sock->state != SS_UNCONNECTED || sk->sk_state == TCP_LISTEN)) { res = -EADDRNOTAVAIL; - dev_put(dev); - break; } - ax25->ax25_dev = ax25_dev_ax25dev(dev); - ax25_fillin_cb(ax25, ax25->ax25_dev); + else if ((ax25->ax25_dev = ax25_dev_ax25dev(dev)) == NULL) + res = -EINVAL; + else + ax25_fillin_cb(ax25, ax25->ax25_dev); + + dev_put(dev); break; default: ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH] Convert ax25 to seq_file 2003-08-12 23:03 ` Jeroen Vreeken 2003-08-12 23:49 ` [PATCH] ax25 use dev_hold/dev_put as required for net_devices Stephen Hemminger 2003-08-13 0:19 ` [PATCH] ax25 setsockopt(SO_BINDTODEVICE) bug fix Stephen Hemminger @ 2003-08-13 0:21 ` Stephen Hemminger 2003-08-13 10:11 ` David S. Miller 2 siblings, 1 reply; 23+ messages in thread From: Stephen Hemminger @ 2003-08-13 0:21 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: linux-hams, ralf, davem, netdev Convert AX25 /proc interface over to using the seq_file library. This is avoids bugs, and also because there is an fops structure, correctly assigns the owner field so module refcounting works right. This is against 2.6.0-test3 with your rqx4 patch and my earlier bug fixes. diff -Nru a/include/net/ax25.h b/include/net/ax25.h --- a/include/net/ax25.h Tue Aug 12 17:16:52 2003 +++ b/include/net/ax25.h Tue Aug 12 17:16:52 2003 @@ -314,7 +314,7 @@ /* ax25_route.c */ extern void ax25_rt_device_down(struct net_device *); extern int ax25_rt_ioctl(unsigned int, void *); -extern int ax25_rt_get_info(char *, char **, off_t, int); +extern struct file_operations ax25_route_fops; extern int ax25_rt_autobind(ax25_cb *, ax25_address *); extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *, struct net_device *); @@ -373,7 +373,7 @@ extern int ax25_uid_policy; extern ax25_address *ax25_findbyuid(uid_t); extern int ax25_uid_ioctl(int, struct sockaddr_ax25 *); -extern int ax25_uid_get_info(char *, char **, off_t, int); +extern struct file_operations ax25_uid_fops; extern void ax25_uid_free(void); /* sysctl_net_ax25.c */ diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c --- a/net/ax25/af_ax25.c Tue Aug 12 17:16:52 2003 +++ b/net/ax25/af_ax25.c Tue Aug 12 17:16:52 2003 @@ -1844,81 +1844,107 @@ return res; } -static int ax25_get_info(char *buffer, char **start, off_t offset, int length) +#ifdef CONFIG_PROC_FS + +static void *ax25_info_start(struct seq_file *seq, loff_t *pos) { - ax25_cb *ax25; - int k; - int len = 0; - off_t pos = 0; - off_t begin = 0; + struct ax25_cb *ax25; struct hlist_node *node; + int i = 0; spin_lock_bh(&ax25_list_lock); + ax25_for_each(ax25, node, &ax25_list) { + if (i == *pos) + return ax25; + ++i; + } + return NULL; +} + +static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + + return hlist_entry( ((struct ax25_cb *)v)->ax25_node.next, + struct ax25_cb, ax25_node); +} + +static void ax25_info_stop(struct seq_file *seq, void *v) +{ + spin_unlock_bh(&ax25_list_lock); +} + +static int ax25_info_show(struct seq_file *seq, void *v) +{ + ax25_cb *ax25 = v; + int k; + /* * New format: * 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 */ - 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, - ax2asc(&ax25->source_addr), - ax25->iamdigi? "*":""); - - len += sprintf(buffer+len, "%s", ax2asc(&ax25->dest_addr)); - - for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { - len += sprintf(buffer+len, ",%s%s", - ax2asc(&ax25->digipeat->calls[k]), - ax25->digipeat->repeated[k]? "*":""); - } - - len += sprintf(buffer+len, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", - ax25->state, - ax25->vs, ax25->vr, ax25->va, - ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ, - ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ, - ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ, - ax25_display_timer(&ax25->idletimer) / (60 * HZ), - ax25->idle / (60 * HZ), - ax25->n2count, ax25->n2, - ax25->rtt / HZ, - ax25->window, - 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"); - } - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } + seq_printf(seq, "%8.8lx %s %s%s ", + (long) ax25, + ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, + ax2asc(&ax25->source_addr), + ax25->iamdigi? "*":""); + seq_printf(seq, "%s", ax2asc(&ax25->dest_addr)); + + for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { + seq_printf(seq, ",%s%s", + ax2asc(&ax25->digipeat->calls[k]), + ax25->digipeat->repeated[k]? "*":""); + } - if (pos > offset + length) - break; + seq_printf(seq, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", + ax25->state, + ax25->vs, ax25->vr, ax25->va, + ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ, + ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ, + ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ, + ax25_display_timer(&ax25->idletimer) / (60 * HZ), + ax25->idle / (60 * HZ), + ax25->n2count, ax25->n2, + ax25->rtt / HZ, + ax25->window, + ax25->paclen); + + if (ax25->sk != NULL) { + bh_lock_sock(ax25->sk); + seq_printf(seq," %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 { + seq_puts(seq, " * * *\n"); } + return 0; +} - spin_unlock_bh(&ax25_list_lock); +static struct seq_operations ax25_info_seqops = { + .start = ax25_info_start, + .next = ax25_info_next, + .stop = ax25_info_stop, + .show = ax25_info_show, +}; - *start = buffer + (offset - begin); - len -= (offset - begin); +static int ax25_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ax25_info_seqops); +} - if (len > length) len = length; +struct file_operations ax25_info_fops = { + .owner = THIS_MODULE, + .open = ax25_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; - return(len); -} +#endif static struct net_proto_family ax25_family_ops = { .family = PF_AX25, @@ -1988,9 +2014,9 @@ register_netdevice_notifier(&ax25_dev_notifier); ax25_register_sysctl(); - proc_net_create("ax25_route", 0, ax25_rt_get_info); - proc_net_create("ax25", 0, ax25_get_info); - proc_net_create("ax25_calls", 0, ax25_uid_get_info); + proc_net_fops_create("ax25_route", S_IRUGO, &ax25_route_fops); + proc_net_fops_create("ax25", S_IRUGO, &ax25_info_fops); + proc_net_fops_create("ax25_calls", S_IRUGO, &ax25_uid_fops); printk(banner); return 0; diff -Nru a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c --- a/net/ax25/ax25_route.c Tue Aug 12 17:16:52 2003 +++ b/net/ax25/ax25_route.c Tue Aug 12 17:16:52 2003 @@ -34,6 +34,7 @@ #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/seq_file.h> static ax25_route *ax25_route_list; static rwlock_t ax25_route_lock = RW_LOCK_UNLOCKED; @@ -278,66 +279,100 @@ } } -int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length) -{ - ax25_route *ax25_rt; - int len = 0; - off_t pos = 0; - off_t begin = 0; - char *callsign; - int i; +#ifdef CONFIG_PROC_FS - read_lock(&ax25_route_lock); +#define AX25_PROC_START ((void *)1) - len += sprintf(buffer, "callsign dev mode digipeaters\n"); +static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct ax25_route *ax25_rt; + int i = 1; + + read_lock(&ax25_route_lock); + if (*pos == 0) + return AX25_PROC_START; for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { + if (i == *pos) + return ax25_rt; + ++i; + } + + return NULL; +} + +static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return (v == AX25_PROC_START) ? ax25_route_list : + ((struct ax25_route *) v)->next; +} + +static void ax25_rt_seq_stop(struct seq_file *seq, void *v) +{ + read_unlock(&ax25_route_lock); +} + +static int ax25_rt_seq_show(struct seq_file *seq, void *v) +{ + if (v == AX25_PROC_START) + seq_puts(seq, "callsign dev mode digipeaters\n"); + else { + struct ax25_route *ax25_rt = v; + const char *callsign; + int i; + if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0) callsign = "default"; else callsign = ax2asc(&ax25_rt->callsign); - len += sprintf(buffer + len, "%-9s %-4s", + + seq_printf(seq, "%-9s %-4s", callsign, ax25_rt->dev ? ax25_rt->dev->name : "???"); switch (ax25_rt->ip_mode) { case 'V': - len += sprintf(buffer + len, " vc"); + seq_puts(seq, " vc"); break; case 'D': - len += sprintf(buffer + len, " dg"); + seq_puts(seq, " dg"); break; default: - len += sprintf(buffer + len, " *"); + seq_puts(seq, " *"); break; } if (ax25_rt->digipeat != NULL) for (i = 0; i < ax25_rt->digipeat->ndigi; i++) - len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i])); - - len += sprintf(buffer + len, "\n"); + seq_printf(seq, " %s", ax2asc(&ax25_rt->digipeat->calls[i])); - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - break; + seq_puts(seq, "\n"); } - read_unlock(&ax25_route_lock); - - *start = buffer + (offset - begin); - len -= (offset - begin); + return 0; +} - if (len > length) - len = length; +static struct seq_operations ax25_rt_seqops = { + .start = ax25_rt_seq_start, + .next = ax25_rt_seq_next, + .stop = ax25_rt_seq_stop, + .show = ax25_rt_seq_show, +}; - return len; +static int ax25_rt_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ax25_rt_seqops); } + +struct file_operations ax25_route_fops = { + .owner = THIS_MODULE, + .open = ax25_rt_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* * Find AX.25 route diff -Nru a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c --- a/net/ax25/ax25_uid.c Tue Aug 12 17:16:52 2003 +++ b/net/ax25/ax25_uid.c Tue Aug 12 17:16:52 2003 @@ -30,6 +30,7 @@ #include <linux/interrupt.h> #include <linux/notifier.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/stat.h> #include <linux/netfilter.h> #include <linux/sysctl.h> @@ -141,39 +142,73 @@ return -EINVAL; /*NOTREACHED */ } -int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length) +#ifdef CONFIG_PROC_FS + +#define AX25_PROC_START ((void *)1) + +static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) { - ax25_uid_assoc *pt; - int len = 0; - off_t pos = 0; - off_t begin = 0; + struct ax25_uid_assoc *pt; + int i = 1; read_lock(&ax25_uid_lock); - len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy); + if (*pos == 0) + return AX25_PROC_START; for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { - len += sprintf(buffer + len, "%6d %s\n", pt->uid, ax2asc(&pt->call)); - - pos = begin + len; + if (i == *pos) + return pt; + ++i; + } + return NULL; +} - if (pos < offset) { - len = 0; - begin = pos; - } +static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return (v == AX25_PROC_START) ? ax25_uid_list : + ((struct ax25_uid_assoc *) v)->next; +} - if (pos > offset + length) - break; - } +static void ax25_uid_seq_stop(struct seq_file *seq, void *v) +{ read_unlock(&ax25_uid_lock); +} + +static int ax25_uid_seq_show(struct seq_file *seq, void *v) +{ + if (v == AX25_PROC_START) + seq_printf(seq, "Policy: %d\n", ax25_uid_policy); + else { + struct ax25_uid_assoc *pt = v; + - *start = buffer + (offset - begin); - len -= offset - begin; + seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call)); + } + return 0; +} - if (len > length) - len = length; +static struct seq_operations ax25_uid_seqops = { + .start = ax25_uid_seq_start, + .next = ax25_uid_seq_next, + .stop = ax25_uid_seq_stop, + .show = ax25_uid_seq_show, +}; - return len; +static int ax25_uid_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ax25_uid_seqops); } + +struct file_operations ax25_uid_fops = { + .owner = THIS_MODULE, + .open = ax25_uid_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* * Free all memory associated with UID/Callsign structures. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Convert ax25 to seq_file 2003-08-13 0:21 ` [PATCH] Convert ax25 to seq_file Stephen Hemminger @ 2003-08-13 10:11 ` David S. Miller 2003-08-13 15:34 ` Jeroen Vreeken 0 siblings, 1 reply; 23+ messages in thread From: David S. Miller @ 2003-08-13 10:11 UTC (permalink / raw) To: Stephen Hemminger; +Cc: pe1rxq, linux-hams, ralf, netdev On Tue, 12 Aug 2003 17:21:51 -0700 Stephen Hemminger <shemminger@osdl.org> wrote: > This is against 2.6.0-test3 with your rqx4 patch and my earlier > bug fixes. I have a bazillion different ax.25 patches in my inbox now, some should be applied and others not, and this is hard to determine with all the activity. Can someone send me a coherent set of patches to apply once all the issues have been worked out? Thanks. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Convert ax25 to seq_file 2003-08-13 10:11 ` David S. Miller @ 2003-08-13 15:34 ` Jeroen Vreeken 2003-08-13 15:42 ` David S. Miller 0 siblings, 1 reply; 23+ messages in thread From: Jeroen Vreeken @ 2003-08-13 15:34 UTC (permalink / raw) To: David S . Miller; +Cc: Stephen Hemminger, linux-hams, ralf, netdev [-- Attachment #1: Type: text/plain, Size: 565 bytes --] On 2003.08.13 12:11:59 +0200 David S. Miller wrote: > I have a bazillion different ax.25 patches in my inbox now, > some should be applied and others not, and this is hard to > determine with all the activity. > > Can someone send me a coherent set of patches to apply once > all the issues have been worked out? This is my last patch (rxq4) plus Stephen's last three (dev locking, setsockopt, seq_file) Jeroen p.s. Which protocol is a good example of non-linear skb usage? Most still seem to use skb_linearize() and the skb documentation is somewhat outdated. [-- Attachment #2: linux-2.6.0-test3.ax25.diff --] [-- Type: application/octet-stream, Size: 94563 bytes --] Only in linux-2.6.0-test3.rxq/net/ax25: .af_ax25.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25.ko.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25.mod.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_addr.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_dev.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_iface.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_in.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_ip.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_out.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_route.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_std_in.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_std_subr.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_std_timer.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_subr.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_timer.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .ax25_uid.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .built-in.o.cmd Only in linux-2.6.0-test3.rxq/net/ax25: .sysctl_net_ax25.o.cmd diff -ru linux-2.6.0-test3/net/ax25/af_ax25.c linux-2.6.0-test3.rxq/net/ax25/af_ax25.c --- linux-2.6.0-test3/net/ax25/af_ax25.c 2003-08-09 06:41:26.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/af_ax25.c 2003-08-13 00:29:48.000000000 +0200 @@ -51,54 +51,27 @@ -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 @@ { 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 @@ /* * 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 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 *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_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 @@ 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 *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 @@ break; } } + spin_unlock_bh(&ax25_list_lock); return sk; @@ -299,7 +279,16 @@ */ 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 @@ { struct sk_buff *skb; - ax25_remove_socket(ax25); + ax25_cb_del(ax25); ax25_stop_heartbeat(ax25); ax25_stop_t1timer(ax25); @@ -337,22 +326,27 @@ 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 @@ 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 @@ return -EINVAL; } - return 0; + return 0; } /* @@ -507,6 +501,7 @@ 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 @@ (sock->state != SS_UNCONNECTED || sk->sk_state == TCP_LISTEN)) { res = -EADDRNOTAVAIL; + dev_put(dev); break; } @@ -877,7 +873,7 @@ break; default: sk_free(sk); - ax25_free_cb(ax25); + ax25_cb_put(ax25); return NULL; } @@ -937,6 +933,7 @@ if (sk == NULL) return 0; + sock_hold(sk); lock_sock(sk); ax25 = ax25_sk(sk); @@ -944,13 +941,15 @@ 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 @@ 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 @@ ax25_fillin_cb(ax25, ax25_dev); done: - ax25_insert_socket(ax25); + ax25_cb_add(ax25); sk->sk_zapped = 0; out: @@ -1093,7 +1090,7 @@ 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 @@ 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 @@ } 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 @@ 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 @@ sock->state = SS_CONNECTED; + err=0; out: release_sock(sk); - return 0; + return err; } @@ -1331,15 +1332,18 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ * 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 @@ 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"); } Only in linux-2.6.0-test3.rxq/net/ax25: af_ax25.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25.ko Only in linux-2.6.0-test3.rxq/net/ax25: ax25.mod.c Only in linux-2.6.0-test3.rxq/net/ax25: ax25.mod.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25_addr.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25_dev.o diff -ru linux-2.6.0-test3/net/ax25/ax25_ds_in.c linux-2.6.0-test3.rxq/net/ax25/ax25_ds_in.c --- linux-2.6.0-test3/net/ax25/ax25_ds_in.c 2003-08-09 06:38:45.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_ds_in.c 2003-08-12 23:40:35.000000000 +0200 @@ -65,6 +65,7 @@ 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 @@ */ if (!sock_flag(ax25->sk, SOCK_DEAD)) ax25->sk->sk_state_change(ax25->sk); + bh_unlock_sock(ax25->sk); } ax25_dama_on(ax25); diff -ru linux-2.6.0-test3/net/ax25/ax25_ds_subr.c linux-2.6.0-test3.rxq/net/ax25/ax25_ds_subr.c --- linux-2.6.0-test3/net/ax25/ax25_ds_subr.c 2003-08-09 06:41:32.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_ds_subr.c 2003-08-12 23:40:35.000000000 +0200 @@ -40,6 +40,7 @@ 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 @@ 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 @@ { 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; diff -ru linux-2.6.0-test3/net/ax25/ax25_ds_timer.c linux-2.6.0-test3.rxq/net/ax25/ax25_ds_timer.c --- linux-2.6.0-test3/net/ax25/ax25_ds_timer.c 2003-08-09 06:41:26.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_ds_timer.c 2003-08-12 23:40:35.000000000 +0200 @@ -74,6 +74,7 @@ { 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 @@ } 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 @@ 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 @@ /* * 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 @@ break; } + if (sk) + bh_unlock_sock(sk); + ax25_start_heartbeat(ax25); } @@ -157,6 +172,7 @@ 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 @@ ax25->sk->sk_state_change(ax25->sk); sock_set_flag(ax25->sk, SOCK_DEAD); } + bh_lock_sock(ax25->sk); } } diff -ru linux-2.6.0-test3/net/ax25/ax25_iface.c linux-2.6.0-test3.rxq/net/ax25/ax25_iface.c --- linux-2.6.0-test3/net/ax25/ax25_iface.c 2003-08-09 06:42:13.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_iface.c 2003-08-12 23:40:35.000000000 +0200 @@ -33,20 +33,20 @@ struct protocol_struct *next; unsigned int pid; int (*func)(struct sk_buff *, ax25_cb *); -} *protocol_list; +} *protocol_list = NULL; static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED; static struct linkfail_struct { struct linkfail_struct *next; void (*func)(ax25_cb *, int); -} *linkfail_list; +} *linkfail_list = NULL; static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED; static struct listen_struct { struct listen_struct *next; ax25_address callsign; struct net_device *dev; -} *listen_list; +} *listen_list = NULL; static spinlock_t listen_lock = SPIN_LOCK_UNLOCKED; int ax25_protocol_register(unsigned int pid, @@ -129,8 +129,10 @@ spin_lock_bh(&linkfail_lock); linkfail = linkfail_list; - if (linkfail == NULL) + if (linkfail == NULL) { + spin_unlock_bh(&linkfail_lock); return; + } if (linkfail->func == func) { linkfail_list = linkfail->next; @@ -180,8 +182,10 @@ spin_lock_bh(&listen_lock); listen = listen_list; - if (listen == NULL) + if (listen == NULL) { + spin_unlock_bh(&listen_lock); return; + } if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { listen_list = listen->next; @@ -226,8 +230,10 @@ spin_lock_bh(&listen_lock); for (listen = listen_list; listen != NULL; listen = listen->next) - if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) + if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) { + spin_unlock_bh(&listen_lock); return 1; + } spin_unlock_bh(&listen_lock); return 0; Only in linux-2.6.0-test3.rxq/net/ax25: ax25_iface.o diff -ru linux-2.6.0-test3/net/ax25/ax25_in.c linux-2.6.0-test3.rxq/net/ax25/ax25_in.c --- linux-2.6.0-test3/net/ax25/ax25_in.c 2003-08-09 06:32:47.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_in.c 2003-08-12 23:40:35.000000000 +0200 @@ -147,6 +147,7 @@ } 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 @@ else ax25->condition |= AX25_COND_OWN_RX_BUSY; } + bh_unlock_sock(ax25->sk); } return queued; @@ -329,6 +331,7 @@ if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) kfree_skb(skb); + ax25_cb_put(ax25); return 0; } @@ -357,11 +360,14 @@ 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 @@ 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 @@ ax25->state = AX25_STATE_3; - ax25_insert_socket(ax25); + ax25_cb_add(ax25); ax25_start_heartbeat(ax25); ax25_start_t3timer(ax25); Only in linux-2.6.0-test3.rxq/net/ax25: ax25_in.o diff -ru linux-2.6.0-test3/net/ax25/ax25_ip.c linux-2.6.0-test3.rxq/net/ax25/ax25_ip.c --- linux-2.6.0-test3/net/ax25/ax25_ip.c 2003-08-09 06:34:43.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_ip.c 2003-08-12 23:40:35.000000000 +0200 @@ -107,6 +107,7 @@ 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 @@ 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; } } Only in linux-2.6.0-test3.rxq/net/ax25: ax25_ip.o diff -ru linux-2.6.0-test3/net/ax25/ax25_out.c linux-2.6.0-test3.rxq/net/ax25/ax25_out.c --- linux-2.6.0-test3/net/ax25/ax25_out.c 2003-08-09 06:40:10.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_out.c 2003-08-12 23:40:35.000000000 +0200 @@ -71,7 +71,7 @@ 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 @@ #endif } - ax25_insert_socket(ax25); + ax25_cb_add(ax25); ax25->state = AX25_STATE_1; Only in linux-2.6.0-test3.rxq/net/ax25: ax25_out.o diff -ru linux-2.6.0-test3/net/ax25/ax25_route.c linux-2.6.0-test3.rxq/net/ax25/ax25_route.c --- linux-2.6.0-test3/net/ax25/ax25_route.c 2003-08-09 06:38:41.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_route.c 2003-08-12 23:40:35.000000000 +0200 @@ -162,6 +162,7 @@ if (ax25_rt->digipeat != NULL) kfree(ax25_rt->digipeat); kfree(ax25_rt); + return; } /* @@ -434,8 +435,11 @@ 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); Only in linux-2.6.0-test3.rxq/net/ax25: ax25_route.o diff -ru linux-2.6.0-test3/net/ax25/ax25_std_in.c linux-2.6.0-test3.rxq/net/ax25/ax25_std_in.c --- linux-2.6.0-test3/net/ax25/ax25_std_in.c 2003-08-09 06:39:26.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_std_in.c 2003-08-12 23:40:35.000000000 +0200 @@ -73,10 +73,12 @@ 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; Only in linux-2.6.0-test3.rxq/net/ax25: ax25_std_in.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25_std_subr.o diff -ru linux-2.6.0-test3/net/ax25/ax25_std_timer.c linux-2.6.0-test3.rxq/net/ax25/ax25_std_timer.c --- linux-2.6.0-test3/net/ax25/ax25_std_timer.c 2003-08-09 06:34:03.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_std_timer.c 2003-08-12 23:40:35.000000000 +0200 @@ -33,14 +33,25 @@ 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 @@ /* * 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 @@ } } + if (sk) + bh_unlock_sock(sk); + ax25_start_heartbeat(ax25); } @@ -94,6 +108,7 @@ 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 @@ ax25->sk->sk_state_change(ax25->sk); sock_set_flag(ax25->sk, SOCK_DEAD); } + bh_unlock_sock(ax25->sk); } } Only in linux-2.6.0-test3.rxq/net/ax25: ax25_std_timer.o diff -ru linux-2.6.0-test3/net/ax25/ax25_subr.c linux-2.6.0-test3.rxq/net/ax25/ax25_subr.c --- linux-2.6.0-test3/net/ax25/ax25_subr.c 2003-08-09 06:41:35.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_subr.c 2003-08-12 23:40:35.000000000 +0200 @@ -158,10 +158,10 @@ struct sk_buff *skb; unsigned char *dptr; - if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(ax25->ax25_dev->dev->hard_header_len + 2, GFP_ATOMIC)) == NULL) return; - skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat)); + skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len); skb->nh.raw = skb->data; @@ -202,10 +202,10 @@ if (dev == NULL) return; - if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(digi) + 1, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(dev->hard_header_len + 1, GFP_ATOMIC)) == NULL) return; /* Next SABM will get DM'd */ - skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi)); + skb_reserve(skb, dev->hard_header_len); skb->nh.raw = skb->data; ax25_digi_invert(digi, &retdigi); @@ -282,6 +282,7 @@ ax25_link_failed(ax25, reason); if (ax25->sk != NULL) { + bh_lock_sock(ax25->sk); ax25->sk->sk_state = TCP_CLOSE; ax25->sk->sk_err = reason; ax25->sk->sk_shutdown |= SEND_SHUTDOWN; @@ -289,5 +290,6 @@ ax25->sk->sk_state_change(ax25->sk); sock_set_flag(ax25->sk, SOCK_DEAD); } + bh_unlock_sock(ax25->sk); } } Only in linux-2.6.0-test3.rxq/net/ax25: ax25_subr.o diff -ru linux-2.6.0-test3/net/ax25/ax25_timer.c linux-2.6.0-test3.rxq/net/ax25/ax25_timer.c --- linux-2.6.0-test3/net/ax25/ax25_timer.c 2003-08-09 06:38:16.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/ax25_timer.c 2003-08-12 23:40:35.000000000 +0200 @@ -141,13 +141,10 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ break; #endif } - bh_unlock_sock(sk); } Only in linux-2.6.0-test3.rxq/net/ax25: ax25_timer.o Only in linux-2.6.0-test3.rxq/net/ax25: ax25_uid.o Only in linux-2.6.0-test3.rxq/net/ax25: built-in.o diff -ru linux-2.6.0-test3/net/ax25/sysctl_net_ax25.c linux-2.6.0-test3.rxq/net/ax25/sysctl_net_ax25.c --- linux-2.6.0-test3/net/ax25/sysctl_net_ax25.c 2003-08-09 06:41:21.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/ax25/sysctl_net_ax25.c 2003-08-12 23:40:35.000000000 +0200 @@ -12,20 +12,20 @@ #include <linux/spinlock.h> #include <net/ax25.h> -static int min_ipdefmode[1], max_ipdefmode[] = {1}; -static int min_axdefmode[1], max_axdefmode[] = {1}; -static int min_backoff[1], max_backoff[] = {2}; -static int min_conmode[1], max_conmode[] = {2}; +static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1}; +static int min_axdefmode[] = {0}, max_axdefmode[] = {1}; +static int min_backoff[] = {0}, max_backoff[] = {2}; +static int min_conmode[] = {0}, max_conmode[] = {2}; static int min_window[] = {1}, max_window[] = {7}; static int min_ewindow[] = {1}, max_ewindow[] = {63}; static int min_t1[] = {1}, max_t1[] = {30 * HZ}; static int min_t2[] = {1}, max_t2[] = {20 * HZ}; -static int min_t3[1], max_t3[] = {3600 * HZ}; -static int min_idle[1], max_idle[] = {65535 * HZ}; +static int min_t3[] = {0}, max_t3[] = {3600 * HZ}; +static int min_idle[] = {0}, max_idle[] = {65535 * HZ}; static int min_n2[] = {1}, max_n2[] = {31}; static int min_paclen[] = {1}, max_paclen[] = {512}; -static int min_proto[1], max_proto[] = {3}; -static int min_ds_timeout[1], max_ds_timeout[] = {65535 * HZ}; +static int min_proto[] = {0}, max_proto[] = {3}; +static int min_ds_timeout[] = {0}, max_ds_timeout[] = {65535 * HZ}; static struct ctl_table_header *ax25_table_header; @@ -204,8 +204,10 @@ 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); Only in linux-2.6.0-test3.rxq/net/ax25: sysctl_net_ax25.o Only in linux-2.6.0-test3.rxq/net/netrom: .af_netrom.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .built-in.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .netrom.ko.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .netrom.mod.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .netrom.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_dev.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_in.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_loopback.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_out.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_route.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_subr.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .nr_timer.o.cmd Only in linux-2.6.0-test3.rxq/net/netrom: .sysctl_net_netrom.o.cmd diff -ru linux-2.6.0-test3/net/netrom/af_netrom.c linux-2.6.0-test3.rxq/net/netrom/af_netrom.c --- linux-2.6.0-test3/net/netrom/af_netrom.c 2003-08-09 06:36:46.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/af_netrom.c 2003-08-12 23:40:35.000000000 +0200 @@ -147,8 +147,10 @@ spin_lock_bh(&nr_list_lock); sk_for_each(s, node, &nr_list) if (!ax25cmp(&nr_sk(s)->source_addr, addr) && - s->sk_state == TCP_LISTEN) + s->sk_state == TCP_LISTEN) { + bh_lock_sock(s); goto found; + } s = NULL; found: spin_unlock_bh(&nr_list_lock); @@ -167,8 +169,10 @@ sk_for_each(s, node, &nr_list) { nr_cb *nr = nr_sk(s); - if (nr->my_index == index && nr->my_id == id) + if (nr->my_index == index && nr->my_id == id) { + bh_lock_sock(s); goto found; + } } s = NULL; found: @@ -190,8 +194,10 @@ nr_cb *nr = nr_sk(s); if (nr->your_index == index && nr->your_id == id && - !ax25cmp(&nr->dest_addr, dest)) + !ax25cmp(&nr->dest_addr, dest)) { + bh_lock_sock(s); goto found; + } } s = NULL; found: @@ -206,14 +212,17 @@ { unsigned short id = circuit; unsigned char i, j; + struct sock *sk; for (;;) { i = id / 256; j = id % 256; - if (i != 0 && j != 0) - if (nr_find_socket(i, j) == NULL) + if (i != 0 && j != 0) { + if ((sk=nr_find_socket(i, j)) == NULL) break; + bh_unlock_sock(sk); + } id++; } @@ -231,7 +240,12 @@ */ static void nr_destroy_timer(unsigned long data) { - nr_destroy_socket((struct sock *)data); + struct sock *sk=(struct sock *)data; + bh_lock_sock(sk); + sock_hold(sk); + nr_destroy_socket(sk); + bh_unlock_sock(sk); + sock_put(sk); } /* @@ -264,17 +278,20 @@ kfree_skb(skb); } + while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) { + kfree_skb(skb); + } if (atomic_read(&sk->sk_wmem_alloc) || atomic_read(&sk->sk_rmem_alloc)) { /* Defer: outstanding buffers */ init_timer(&sk->sk_timer); - sk->sk_timer.expires = jiffies + 10 * HZ; + sk->sk_timer.expires = jiffies + 2 * HZ; sk->sk_timer.function = nr_destroy_timer; sk->sk_timer.data = (unsigned long)sk; add_timer(&sk->sk_timer); } else - sk_free(sk); + sock_put(sk); } /* @@ -388,12 +405,15 @@ { struct sock *sk = sock->sk; + lock_sock(sk); if (sk->sk_state != TCP_LISTEN) { memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN); sk->sk_max_ack_backlog = backlog; sk->sk_state = TCP_LISTEN; + release_sock(sk); return 0; } + release_sock(sk); return -EOPNOTSUPP; } @@ -495,6 +515,7 @@ if (sk == NULL) return 0; + lock_sock(sk); nr = nr_sk(sk); switch (nr->state) { @@ -528,6 +549,7 @@ } sock->sk = NULL; + release_sock(sk); return 0; } @@ -540,21 +562,26 @@ struct net_device *dev; ax25_address *user, *source; - if (!sk->sk_zapped) + lock_sock(sk); + if (!sk->sk_zapped) { + release_sock(sk); return -EINVAL; - - if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct -full_sockaddr_ax25)) + } + if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25)) { + release_sock(sk); return -EINVAL; - - if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) + } + if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) { + release_sock(sk); return -EINVAL; - - if (addr->fsa_ax25.sax25_family != AF_NETROM) + } + if (addr->fsa_ax25.sax25_family != AF_NETROM) { + release_sock(sk); return -EINVAL; - + } if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) { SOCK_DEBUG(sk, "NET/ROM: bind failed: invalid node callsign\n"); + release_sock(sk); return -EADDRNOTAVAIL; } @@ -562,16 +589,22 @@ * Only the super user can set an arbitrary user callsign. */ if (addr->fsa_ax25.sax25_ndigis == 1) { - if (!capable(CAP_NET_BIND_SERVICE)) + if (!capable(CAP_NET_BIND_SERVICE)) { + dev_put(dev); + release_sock(sk); return -EACCES; + } nr->user_addr = addr->fsa_digipeater[0]; nr->source_addr = addr->fsa_ax25.sax25_call; } else { source = &addr->fsa_ax25.sax25_call; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) + if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) { + release_sock(sk); + dev_put(dev); return -EPERM; + } user = source; } @@ -583,6 +616,8 @@ nr_insert_socket(sk); sk->sk_zapped = 0; + dev_put(dev); + release_sock(sk); SOCK_DEBUG(sk, "NET/ROM: socket is bound\n"); return 0; } @@ -596,39 +631,50 @@ ax25_address *user, *source = NULL; struct net_device *dev; + lock_sock(sk); if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; + release_sock(sk); return 0; /* Connect completed during a ERESTARTSYS event */ } if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { sock->state = SS_UNCONNECTED; + release_sock(sk); return -ECONNREFUSED; } - if (sk->sk_state == TCP_ESTABLISHED) + if (sk->sk_state == TCP_ESTABLISHED) { + release_sock(sk); return -EISCONN; /* No reconnect on a seqpacket socket */ + } sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; - if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) + if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) { + release_sock(sk); return -EINVAL; - - if (addr->sax25_family != AF_NETROM) + } + if (addr->sax25_family != AF_NETROM) { + release_sock(sk); return -EINVAL; - + } if (sk->sk_zapped) { /* Must bind first - autobinding in this may or may not work */ sk->sk_zapped = 0; - if ((dev = nr_dev_first()) == NULL) + if ((dev = nr_dev_first()) == NULL) { + release_sock(sk); return -ENETUNREACH; - + } source = (ax25_address *)dev->dev_addr; if ((user = ax25_findbyuid(current->euid)) == NULL) { - if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) + if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) { + dev_put(dev); + release_sock(sk); return -EPERM; + } user = source; } @@ -636,12 +682,15 @@ nr->source_addr = *source; nr->device = dev; + dev_put(dev); nr_insert_socket(sk); /* Finish the bind */ } nr->dest_addr = addr->sax25_call; + release_sock(sk); circuit = nr_find_next_circuit(); + lock_sock(sk); nr->my_index = circuit / 256; nr->my_id = circuit % 256; @@ -659,8 +708,10 @@ nr_start_heartbeat(sk); /* Now the loop */ - if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { + release_sock(sk); return -EINPROGRESS; + } /* * A Connect Ack with Choke or timeout or failed routing will go to @@ -675,8 +726,10 @@ set_current_state(TASK_INTERRUPTIBLE); if (sk->sk_state != TCP_SYN_SENT) break; + release_sock(sk); if (!signal_pending(tsk)) { schedule(); + lock_sock(sk); continue; } return -ERESTARTSYS; @@ -687,10 +740,12 @@ if (sk->sk_state != TCP_ESTABLISHED) { sock->state = SS_UNCONNECTED; + release_sock(sk); return sock_error(sk); /* Always set at this point */ } sock->state = SS_CONNECTED; + release_sock(sk); return 0; } @@ -753,6 +808,7 @@ newsock->sk = newsk; out: + release_sock(sk); return err; } @@ -763,9 +819,12 @@ struct sock *sk = sock->sk; nr_cb *nr = nr_sk(sk); + lock_sock(sk); if (peer != 0) { - if (sk->sk_state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) { + release_sock(sk); return -ENOTCONN; + } sax->fsa_ax25.sax25_family = AF_NETROM; sax->fsa_ax25.sax25_ndigis = 1; sax->fsa_ax25.sax25_call = nr->user_addr; @@ -777,6 +836,7 @@ sax->fsa_ax25.sax25_call = nr->source_addr; *uaddr_len = sizeof(struct sockaddr_ax25); } + release_sock(sk); return 0; } @@ -790,6 +850,7 @@ unsigned short circuit_index, circuit_id; unsigned short peer_circuit_index, peer_circuit_id; unsigned short frametype, flags, window, timeout; + int ret; skb->sk = NULL; /* Initially we don't know who it's for */ @@ -847,7 +908,9 @@ else nr_sk(sk)->bpqext = 0; - return nr_process_rx_frame(sk, skb); + ret = nr_process_rx_frame(sk, skb); + bh_unlock_sock(sk); + return ret; } /* @@ -877,6 +940,8 @@ if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog || (make = nr_make_new(sk)) == NULL) { nr_transmit_refusal(skb, 0); + if (sk) + bh_unlock_sock(sk); return 0; } @@ -894,7 +959,9 @@ nr_make->your_index = circuit_index; nr_make->your_id = circuit_id; + bh_unlock_sock(sk); circuit = nr_find_next_circuit(); + bh_lock_sock(sk); nr_make->my_index = circuit / 256; nr_make->my_id = circuit % 256; @@ -936,6 +1003,7 @@ if (!sock_flag(sk, SOCK_DEAD)) sk->sk_data_ready(sk, skb->len); + bh_unlock_sock(sk); return 1; } @@ -954,28 +1022,42 @@ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) return -EINVAL; - if (sk->sk_zapped) - return -EADDRNOTAVAIL; + lock_sock(sk); + if (sk->sk_zapped) { + err = -EADDRNOTAVAIL; + goto out; + } if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); - return -EPIPE; + err = -EPIPE; + goto out; } - if (nr->device == NULL) - return -ENETUNREACH; + if (nr->device == NULL) { + err = -ENETUNREACH; + goto out; + } if (usax) { - if (msg->msg_namelen < sizeof(sax)) - return -EINVAL; + if (msg->msg_namelen < sizeof(sax)) { + err = -EINVAL; + goto out; + } sax = *usax; - if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) - return -EISCONN; - if (sax.sax25_family != AF_NETROM) - return -EINVAL; + if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) { + err = -EISCONN; + goto out; + } + if (sax.sax25_family != AF_NETROM) { + err = -EINVAL; + goto out; + } } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; + if (sk->sk_state != TCP_ESTABLISHED) { + err = -ENOTCONN; + goto out; + } sax.sax25_family = AF_NETROM; sax.sax25_call = nr->dest_addr; } @@ -984,10 +1066,10 @@ /* Build a packet */ SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n"); - size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN; + size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN; if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) - return err; + goto out; skb_reserve(skb, size - len); @@ -1022,12 +1104,16 @@ if (sk->sk_state != TCP_ESTABLISHED) { kfree_skb(skb); - return -ENOTCONN; + err = -ENOTCONN; + goto out; } nr_output(sk, skb); /* Shove it onto the queue */ - return len; + err = len; +out: + release_sock(sk); + return err; } static int nr_recvmsg(struct kiocb *iocb, struct socket *sock, @@ -1044,12 +1130,17 @@ * us! We do one quick check first though */ - if (sk->sk_state != TCP_ESTABLISHED) + lock_sock(sk); + if (sk->sk_state != TCP_ESTABLISHED) { + release_sock(sk); return -ENOTCONN; + } /* Now we can treat all alike */ - if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) + if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) { + release_sock(sk); return er; + } skb->h.raw = skb->data; copied = skb->len; @@ -1070,6 +1161,7 @@ skb_free_datagram(sk, skb); + release_sock(sk); return copied; } @@ -1077,13 +1169,16 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; + int ret; + lock_sock(sk); switch (cmd) { case TIOCOUTQ: { long amount; amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; + release_sock(sk); return put_user(amount, (int *)arg); } @@ -1093,15 +1188,21 @@ /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; + release_sock(sk); return put_user(amount, (int *)arg); } case SIOCGSTAMP: if (sk != NULL) { - if (!sk->sk_stamp.tv_sec) + if (!sk->sk_stamp.tv_sec) { + release_sock(sk); return -ENOENT; - return copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0; + } + ret = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0; + release_sock(sk); + return ret; } + release_sock(sk); return -EINVAL; case SIOCGIFADDR: @@ -1114,17 +1215,21 @@ case SIOCSIFNETMASK: case SIOCGIFMETRIC: case SIOCSIFMETRIC: + release_sock(sk); return -EINVAL; case SIOCADDRT: case SIOCDELRT: case SIOCNRDECOBS: + release_sock(sk); if (!capable(CAP_NET_ADMIN)) return -EPERM; return nr_rt_ioctl(cmd, (void *)arg); default: + release_sock(sk); return dev_ioctl(cmd, (void *)arg); } + release_sock(sk); return 0; } @@ -1144,7 +1249,9 @@ len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n"); sk_for_each(s, node, &nr_list) { - nr_cb *nr = nr_sk(s); + nr_cb *nr; + bh_lock_sock(s); + nr = nr_sk(s); if ((dev = nr->device) == NULL) devname = "???"; @@ -1187,7 +1294,7 @@ len = 0; begin = pos; } - + bh_unlock_sock(s); if (pos > offset + length) break; } @@ -1256,6 +1363,7 @@ for (i = 0; i < nr_ndevs; i++) { sprintf(dev_nr[i].name, "nr%d", i); + dev_nr[i].base_addr = i; dev_nr[i].init = nr_init; register_netdev(&dev_nr[i]); } @@ -1300,23 +1408,23 @@ nr_rt_free(); - ax25_protocol_release(AX25_P_NETROM); +#ifdef CONFIG_SYSCTL + nr_unregister_sysctl(); +#endif + ax25_linkfail_release(nr_link_failed); + ax25_protocol_release(AX25_P_NETROM); unregister_netdevice_notifier(&nr_dev_notifier); -#ifdef CONFIG_SYSCTL - nr_unregister_sysctl(); -#endif sock_unregister(PF_NETROM); for (i = 0; i < nr_ndevs; i++) { if (dev_nr[i].priv != NULL) { + unregister_netdev(&dev_nr[i]); kfree(dev_nr[i].priv); dev_nr[i].priv = NULL; - unregister_netdev(&dev_nr[i]); } - kfree(dev_nr[i].name); } kfree(dev_nr); Only in linux-2.6.0-test3.rxq/net/netrom: af_netrom.o Only in linux-2.6.0-test3.rxq/net/netrom: built-in.o Only in linux-2.6.0-test3.rxq/net/netrom: netrom.ko Only in linux-2.6.0-test3.rxq/net/netrom: netrom.mod.c Only in linux-2.6.0-test3.rxq/net/netrom: netrom.mod.o Only in linux-2.6.0-test3.rxq/net/netrom: netrom.o diff -ru linux-2.6.0-test3/net/netrom/nr_dev.c linux-2.6.0-test3.rxq/net/netrom/nr_dev.c --- linux-2.6.0-test3/net/netrom/nr_dev.c 2003-08-09 06:41:27.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_dev.c 2003-08-12 23:40:35.000000000 +0200 @@ -159,11 +159,13 @@ { struct sockaddr *sa = addr; - ax25_listen_release((ax25_address *)dev->dev_addr, NULL); + if (dev->flags & IFF_UP) + ax25_listen_release((ax25_address *)dev->dev_addr, NULL); memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); - ax25_listen_register((ax25_address *)dev->dev_addr, NULL); + if (dev->flags & IFF_UP) + ax25_listen_register((ax25_address *)dev->dev_addr, NULL); return 0; } @@ -177,8 +179,8 @@ static int nr_close(struct net_device *dev) { - netif_stop_queue(dev); ax25_listen_release((ax25_address *)dev->dev_addr, NULL); + netif_stop_queue(dev); return 0; } @@ -197,16 +199,16 @@ int nr_init(struct net_device *dev) { - SET_MODULE_OWNER(dev); dev->mtu = NR_MAX_PACKET_SIZE; dev->hard_start_xmit = nr_xmit; dev->open = nr_open; dev->stop = nr_close; dev->hard_header = nr_header; - dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN; + dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN; dev->addr_len = AX25_ADDR_LEN; dev->type = ARPHRD_NETROM; + dev->tx_queue_len = 40; dev->rebuild_header = nr_rebuild_header; dev->set_mac_address = nr_set_mac_address; Only in linux-2.6.0-test3.rxq/net/netrom: nr_dev.o diff -ru linux-2.6.0-test3/net/netrom/nr_in.c linux-2.6.0-test3.rxq/net/netrom/nr_in.c --- linux-2.6.0-test3/net/netrom/nr_in.c 2003-08-09 06:34:46.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_in.c 2003-08-12 23:40:35.000000000 +0200 @@ -74,6 +74,7 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) { + bh_lock_sock(sk); switch (frametype) { case NR_CONNACK: { nr_cb *nr = nr_sk(sk); @@ -102,6 +103,7 @@ default: break; } + bh_unlock_sock(sk); return 0; } @@ -114,6 +116,7 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) { + bh_lock_sock(sk); switch (frametype) { case NR_CONNACK | NR_CHOKE_FLAG: nr_disconnect(sk, ECONNRESET); @@ -129,6 +132,7 @@ default: break; } + bh_unlock_sock(sk); return 0; } @@ -150,6 +154,7 @@ nr = skb->data[18]; ns = skb->data[17]; + bh_lock_sock(sk); switch (frametype) { case NR_CONNREQ: nr_write_internal(sk, NR_CONNACK); @@ -260,6 +265,7 @@ default: break; } + bh_unlock_sock(sk); return queued; } Only in linux-2.6.0-test3.rxq/net/netrom: nr_in.o Only in linux-2.6.0-test3.rxq/net/netrom: nr_loopback.o Only in linux-2.6.0-test3.rxq/net/netrom: nr_out.o diff -ru linux-2.6.0-test3/net/netrom/nr_route.c linux-2.6.0-test3.rxq/net/netrom/nr_route.c --- linux-2.6.0-test3/net/netrom/nr_route.c 2003-08-09 06:42:17.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_route.c 2003-08-12 23:40:35.000000000 +0200 @@ -39,10 +39,45 @@ static unsigned int nr_neigh_no = 1; -static struct nr_node *nr_node_list; -static spinlock_t nr_node_lock; -static struct nr_neigh *nr_neigh_list; -static spinlock_t nr_neigh_lock; +HLIST_HEAD(nr_node_list); +spinlock_t nr_node_list_lock = SPIN_LOCK_UNLOCKED; +HLIST_HEAD(nr_neigh_list); +spinlock_t nr_neigh_list_lock = SPIN_LOCK_UNLOCKED; + +struct nr_node *nr_node_get(ax25_address *callsign) +{ + struct nr_node *found = NULL; + struct nr_node *nr_node; + struct hlist_node *node; + + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each(nr_node, node, &nr_node_list) + if (ax25cmp(callsign, &nr_node->callsign) == 0) { + nr_node_hold(nr_node); + found = nr_node; + break; + } + spin_unlock_bh(&nr_node_list_lock); + return found; +} + +struct nr_neigh *nr_neigh_get_dev(ax25_address *callsign, struct net_device *dev) +{ + struct nr_neigh *found = NULL; + struct nr_neigh *nr_neigh; + struct hlist_node *node; + + spin_lock_bh(&nr_neigh_list_lock); + nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) + if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && + nr_neigh->dev == dev) { + nr_neigh_hold(nr_neigh); + found = nr_neigh; + break; + } + spin_unlock_bh(&nr_neigh_list_lock); + return found; +} static void nr_remove_neigh(struct nr_neigh *); @@ -57,17 +92,16 @@ struct nr_neigh *nr_neigh; struct nr_route nr_route; int i, found; + struct net_device *odev; - if (nr_dev_get(nr) != NULL) /* Can't add routes to ourself */ + if ((odev=nr_dev_get(nr)) != NULL) { /* Can't add routes to ourself */ + dev_put(odev); return -EINVAL; + } - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) - if (ax25cmp(nr, &nr_node->callsign) == 0) - break; + nr_node = nr_node_get(nr); - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (ax25cmp(ax25, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) - break; + nr_neigh = nr_neigh_get_dev(ax25, dev); /* * The L2 link to a neighbour has failed in the past @@ -76,24 +110,36 @@ * routes now (and not wait for a node broadcast). */ if (nr_neigh != NULL && nr_neigh->failed != 0 && quality == 0) { - struct nr_node *node; + struct nr_node *nr_nodet; + struct hlist_node *node; - for (node = nr_node_list; node != NULL; node = node->next) - for (i = 0; i < node->count; i++) - if (node->routes[i].neighbour == nr_neigh) - if (i < node->which) - node->which = i; + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each(nr_nodet, node, &nr_node_list) { + nr_node_lock(nr_nodet); + for (i = 0; i < nr_nodet->count; i++) + if (nr_nodet->routes[i].neighbour == nr_neigh) + if (i < nr_nodet->which) + nr_nodet->which = i; + nr_node_unlock(nr_nodet); + } + spin_unlock_bh(&nr_node_list_lock); } if (nr_neigh != NULL) nr_neigh->failed = 0; - if (quality == 0 && nr_neigh != NULL && nr_node != NULL) + if (quality == 0 && nr_neigh != NULL && nr_node != NULL) { + nr_neigh_put(nr_neigh); + nr_node_put(nr_node); return 0; + } if (nr_neigh == NULL) { - if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) + if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) { + if (nr_node) + nr_node_put(nr_node); return -ENOMEM; + } nr_neigh->callsign = *ax25; nr_neigh->digipeat = NULL; @@ -104,48 +150,58 @@ nr_neigh->count = 0; nr_neigh->number = nr_neigh_no++; nr_neigh->failed = 0; + atomic_set(&nr_neigh->refcount, 1); if (ax25_digi != NULL && ax25_digi->ndigi > 0) { if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) { kfree(nr_neigh); + if (nr_node) + nr_node_put(nr_node); return -ENOMEM; } memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi)); } - spin_lock_bh(&nr_neigh_lock); - nr_neigh->next = nr_neigh_list; - nr_neigh_list = nr_neigh; - spin_unlock_bh(&nr_neigh_lock); + spin_lock_bh(&nr_neigh_list_lock); + hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list); + nr_neigh_hold(nr_neigh); + spin_unlock_bh(&nr_neigh_list_lock); } if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked) nr_neigh->quality = quality; if (nr_node == NULL) { - if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) + if ((nr_node = kmalloc(sizeof(*nr_node), GFP_ATOMIC)) == NULL) { + if (nr_neigh) + nr_neigh_put(nr_neigh); return -ENOMEM; + } nr_node->callsign = *nr; strcpy(nr_node->mnemonic, mnemonic); nr_node->which = 0; nr_node->count = 1; + atomic_set(&nr_node->refcount, 1); + nr_node->node_lock = SPIN_LOCK_UNLOCKED; nr_node->routes[0].quality = quality; nr_node->routes[0].obs_count = obs_count; nr_node->routes[0].neighbour = nr_neigh; - spin_lock_bh(&nr_node_lock); - nr_node->next = nr_node_list; - nr_node_list = nr_node; - spin_unlock_bh(&nr_node_lock); - + nr_neigh_hold(nr_neigh); nr_neigh->count++; + spin_lock_bh(&nr_node_list_lock); + hlist_add_head(&nr_node->node_node, &nr_node_list); + /* refcount initialized at 1 */ + spin_unlock_bh(&nr_node_list_lock); + return 0; } + nr_node_lock(nr_node); if (quality != 0) strcpy(nr_node->mnemonic, mnemonic); @@ -171,11 +227,13 @@ nr_node->which++; nr_node->count++; + nr_neigh_hold(nr_neigh); nr_neigh->count++; } else { /* It must be better than the worst */ if (quality > nr_node->routes[2].quality) { nr_node->routes[2].neighbour->count--; + nr_neigh_put(nr_node->routes[2].neighbour); if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked) nr_remove_neigh(nr_node->routes[2].neighbour); @@ -184,6 +242,7 @@ nr_node->routes[2].obs_count = obs_count; nr_node->routes[2].neighbour = nr_neigh; + nr_neigh_hold(nr_neigh); nr_neigh->count++; } } @@ -244,62 +303,42 @@ } } + nr_neigh_put(nr_neigh); + nr_node_unlock(nr_node); + nr_node_put(nr_node); return 0; } -static void nr_remove_node(struct nr_node *nr_node) +static inline void __nr_remove_node(struct nr_node *nr_node) { - struct nr_node *s; - - spin_lock_bh(&nr_node_lock); - if ((s = nr_node_list) == nr_node) { - nr_node_list = nr_node->next; - spin_unlock_bh(&nr_node_lock); - kfree(nr_node); - return; - } - - while (s != NULL && s->next != NULL) { - if (s->next == nr_node) { - s->next = nr_node->next; - spin_unlock_bh(&nr_node_lock); - kfree(nr_node); - return; - } + hlist_del_init(&nr_node->node_node); + nr_node_put(nr_node); +} - s = s->next; - } +#define nr_remove_node_locked(__node) \ + __nr_remove_node(__node) - spin_unlock_bh(&nr_node_lock); +static void nr_remove_node(struct nr_node *nr_node) +{ + spin_lock_bh(&nr_node_list_lock); + __nr_remove_node(nr_node); + spin_unlock_bh(&nr_node_list_lock); } -static void nr_remove_neigh(struct nr_neigh *nr_neigh) +static inline void __nr_remove_neigh(struct nr_neigh *nr_neigh) { - struct nr_neigh *s; + hlist_del_init(&nr_neigh->neigh_node); + nr_neigh_put(nr_neigh); +} - spin_lock_bh(&nr_neigh_lock); - if ((s = nr_neigh_list) == nr_neigh) { - nr_neigh_list = nr_neigh->next; - spin_unlock_bh(&nr_neigh_lock); - if (nr_neigh->digipeat != NULL) - kfree(nr_neigh->digipeat); - kfree(nr_neigh); - return; - } +#define nr_remove_neigh_locked(__neigh) \ + __nr_remove_neigh(__neigh) - while (s != NULL && s->next != NULL) { - if (s->next == nr_neigh) { - s->next = nr_neigh->next; - spin_unlock_bh(&nr_neigh_lock); - if (nr_neigh->digipeat != NULL) - kfree(nr_neigh->digipeat); - kfree(nr_neigh); - return; - } - - s = s->next; - } - spin_unlock_bh(&nr_neigh_lock); +static void nr_remove_neigh(struct nr_neigh *nr_neigh) +{ + spin_lock_bh(&nr_neigh_list_lock); + __nr_remove_neigh(nr_neigh); + spin_unlock_bh(&nr_neigh_list_lock); } /* @@ -312,26 +351,27 @@ struct nr_neigh *nr_neigh; int i; - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) - if (ax25cmp(callsign, &nr_node->callsign) == 0) - break; + nr_node = nr_node_get(callsign); if (nr_node == NULL) return -EINVAL; - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) - break; + nr_neigh = nr_neigh_get_dev(neighbour, dev); - if (nr_neigh == NULL) + if (nr_neigh == NULL) { + nr_node_put(nr_node); return -EINVAL; + } + nr_node_lock(nr_node); for (i = 0; i < nr_node->count; i++) { if (nr_node->routes[i].neighbour == nr_neigh) { nr_neigh->count--; + nr_neigh_put(nr_neigh); if (nr_neigh->count == 0 && !nr_neigh->locked) nr_remove_neigh(nr_neigh); + nr_neigh_put(nr_neigh); nr_node->count--; @@ -346,11 +386,16 @@ case 2: break; } + nr_node_put(nr_node); } + nr_node_unlock(nr_node); return 0; } } + nr_neigh_put(nr_neigh); + nr_node_unlock(nr_node); + nr_node_put(nr_node); return -EINVAL; } @@ -362,12 +407,12 @@ { struct nr_neigh *nr_neigh; - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) { - if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) { - nr_neigh->quality = quality; - nr_neigh->locked = 1; - return 0; - } + nr_neigh = nr_neigh_get_dev(callsign, dev); + if (nr_neigh) { + nr_neigh->quality = quality; + nr_neigh->locked = 1; + nr_neigh_put(nr_neigh); + return 0; } if ((nr_neigh = kmalloc(sizeof(*nr_neigh), GFP_ATOMIC)) == NULL) @@ -382,6 +427,7 @@ nr_neigh->count = 0; nr_neigh->number = nr_neigh_no++; nr_neigh->failed = 0; + atomic_set(&nr_neigh->refcount, 1); if (ax25_digi != NULL && ax25_digi->ndigi > 0) { if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) { @@ -391,10 +437,10 @@ memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi)); } - spin_lock_bh(&nr_neigh_lock); - nr_neigh->next = nr_neigh_list; - nr_neigh_list = nr_neigh; - spin_unlock_bh(&nr_neigh_lock); + spin_lock_bh(&nr_neigh_list_lock); + hlist_add_head(&nr_neigh->neigh_node, &nr_neigh_list); + /* refcount is initialized at 1 */ + spin_unlock_bh(&nr_neigh_list_lock); return 0; } @@ -407,9 +453,7 @@ { struct nr_neigh *nr_neigh; - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) - break; + nr_neigh = nr_neigh_get_dev(callsign, dev); if (nr_neigh == NULL) return -EINVAL; @@ -418,6 +462,7 @@ if (nr_neigh->count == 0) nr_remove_neigh(nr_neigh); + nr_neigh_put(nr_neigh); return 0; } @@ -430,15 +475,13 @@ static int nr_dec_obs(void) { struct nr_neigh *nr_neigh; - struct nr_node *s, *nr_node; + struct nr_node *s; + struct hlist_node *node, *nodet; int i; - nr_node = nr_node_list; - - while (nr_node != NULL) { - s = nr_node; - nr_node = nr_node->next; - + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each_safe(s, node, nodet, &nr_node_list) { + nr_node_lock(s); for (i = 0; i < s->count; i++) { switch (s->routes[i].obs_count) { case 0: /* A locked entry */ @@ -448,6 +491,7 @@ nr_neigh = s->routes[i].neighbour; nr_neigh->count--; + nr_neigh_put(nr_neigh); if (nr_neigh->count == 0 && !nr_neigh->locked) nr_remove_neigh(nr_neigh); @@ -472,8 +516,10 @@ } if (s->count <= 0) - nr_remove_node(s); + nr_remove_node_locked(s); + nr_node_unlock(s); } + spin_unlock_bh(&nr_node_list_lock); return 0; } @@ -483,21 +529,17 @@ */ void nr_rt_device_down(struct net_device *dev) { - struct nr_neigh *s, *nr_neigh = nr_neigh_list; - struct nr_node *t, *nr_node; + struct nr_neigh *s; + struct hlist_node *node, *nodet, *node2, *node2t; + struct nr_node *t; int i; - while (nr_neigh != NULL) { - s = nr_neigh; - nr_neigh = nr_neigh->next; - + spin_lock_bh(&nr_neigh_list_lock); + nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) { if (s->dev == dev) { - nr_node = nr_node_list; - - while (nr_node != NULL) { - t = nr_node; - nr_node = nr_node->next; - + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each_safe(t, node2, node2t, &nr_node_list) { + nr_node_lock(t); for (i = 0; i < t->count; i++) { if (t->routes[i].neighbour == s) { t->count--; @@ -514,12 +556,15 @@ } if (t->count <= 0) - nr_remove_node(t); + nr_remove_node_locked(t); + nr_node_unlock(t); } + spin_unlock_bh(&nr_node_list_lock); - nr_remove_neigh(s); + nr_remove_neigh_locked(s); } } + spin_unlock_bh(&nr_neigh_list_lock); } /* @@ -553,6 +598,8 @@ if (first == NULL || strncmp(dev->name, first->name, 3) < 0) first = dev; } + if (first) + dev_hold(first); read_unlock(&dev_base_lock); return first; @@ -603,6 +650,7 @@ { struct nr_route_struct nr_route; struct net_device *dev; + int ret; switch (cmd) { case SIOCADDRT: @@ -610,23 +658,29 @@ return -EFAULT; if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL) return -EINVAL; - if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) + if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS) { + dev_put(dev); return -EINVAL; + } switch (nr_route.type) { case NETROM_NODE: - return nr_add_node(&nr_route.callsign, + ret = nr_add_node(&nr_route.callsign, nr_route.mnemonic, &nr_route.neighbour, nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), dev, nr_route.quality, nr_route.obs_count); + break; case NETROM_NEIGH: - return nr_add_neigh(&nr_route.callsign, + ret = nr_add_neigh(&nr_route.callsign, nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters), dev, nr_route.quality); + break; default: - return -EINVAL; + ret = -EINVAL; } + dev_put(dev); + return ret; case SIOCDELRT: if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct))) @@ -635,14 +689,18 @@ return -EINVAL; switch (nr_route.type) { case NETROM_NODE: - return nr_del_node(&nr_route.callsign, + ret = nr_del_node(&nr_route.callsign, &nr_route.neighbour, dev); + break; case NETROM_NEIGH: - return nr_del_neigh(&nr_route.callsign, + ret = nr_del_neigh(&nr_route.callsign, dev, nr_route.quality); + break; default: - return -EINVAL; + ret = -EINVAL; } + dev_put(dev); + return ret; case SIOCNRDECOBS: return nr_dec_obs(); @@ -660,22 +718,36 @@ */ void nr_link_failed(ax25_cb *ax25, int reason) { - struct nr_neigh *nr_neigh; - struct nr_node *nr_node; - - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (nr_neigh->ax25 == ax25) + struct nr_neigh *s, *nr_neigh = NULL; + struct hlist_node *node; + struct nr_node *nr_node = NULL; + + spin_lock_bh(&nr_neigh_list_lock); + nr_neigh_for_each(s, node, &nr_neigh_list) + if (s->ax25 == ax25) { + nr_neigh_hold(s); + nr_neigh = s; break; + } + spin_unlock_bh(&nr_neigh_list_lock); if (nr_neigh == NULL) return; nr_neigh->ax25 = NULL; + ax25_cb_put(ax25); - if (++nr_neigh->failed < sysctl_netrom_link_fails_count) return; - - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) + if (++nr_neigh->failed < sysctl_netrom_link_fails_count) { + nr_neigh_put(nr_neigh); + return; + } + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each(nr_node, node, &nr_node_list) + nr_node_lock(nr_node); if (nr_node->which < nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh) nr_node->which++; + nr_node_unlock(nr_node); + spin_unlock_bh(&nr_node_list_lock); + nr_neigh_put(nr_neigh); } /* @@ -689,6 +761,9 @@ struct nr_node *nr_node; struct net_device *dev; unsigned char *dptr; + ax25_cb *ax25s; + int ret; + struct sk_buff *skbn; nr_src = (ax25_address *)(skb->data + 0); @@ -700,50 +775,84 @@ if ((dev = nr_dev_get(nr_dest)) != NULL) { /* Its for me */ if (ax25 == NULL) /* Its from me */ - return nr_loopback_queue(skb); + ret = nr_loopback_queue(skb); else - return nr_rx_frame(skb, dev); + ret = nr_rx_frame(skb, dev); + dev_put(dev); + return ret; } if (!sysctl_netrom_routing_control && ax25 != NULL) return 0; /* Its Time-To-Live has expired */ - if (--skb->data[14] == 0) + if (skb->data[14] == 1) { return 0; + } - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) - if (ax25cmp(nr_dest, &nr_node->callsign) == 0) - break; + nr_node = nr_node_get(nr_dest); + if (nr_node == NULL) + return 0; + nr_node_lock(nr_node); - if (nr_node == NULL || nr_node->which >= nr_node->count) + if (nr_node->which >= nr_node->count) { + nr_node_unlock(nr_node); + nr_node_put(nr_node); return 0; + } nr_neigh = nr_node->routes[nr_node->which].neighbour; - if ((dev = nr_dev_first()) == NULL) + if ((dev = nr_dev_first()) == NULL) { + nr_node_unlock(nr_node); + nr_node_put(nr_node); + return 0; + } + + /* We are going to change the netrom headers so we should get our + own skb, we also did not know until now how much header space + we had to reserve... - RXQ */ + if ((skbn=skb_copy_expand(skb, dev->hard_header_len, 0, GFP_ATOMIC)) == NULL) { + nr_node_unlock(nr_node); + nr_node_put(nr_node); + dev_put(dev); return 0; + } + kfree_skb(skb); + skb=skbn; + skb->data[14]--; dptr = skb_push(skb, 1); *dptr = AX25_P_NETROM; - nr_neigh->ax25 = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); + ax25s = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); + if (nr_neigh->ax25 && ax25s) { + /* We were already holding this ax25_cb */ + ax25_cb_put(ax25s); + } + nr_neigh->ax25 = ax25s; - return (nr_neigh->ax25 != NULL); + dev_put(dev); + ret = (nr_neigh->ax25 != NULL); + nr_node_unlock(nr_node); + nr_node_put(nr_node); + return ret; } int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length) { struct nr_node *nr_node; + struct hlist_node *node; int len = 0; off_t pos = 0; off_t begin = 0; int i; - spin_lock_bh(&nr_node_lock); + spin_lock_bh(&nr_node_list_lock); len += sprintf(buffer, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n"); - for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) { + nr_node_for_each(nr_node, node, &nr_node_list) { + nr_node_lock(nr_node); len += sprintf(buffer + len, "%-9s %-7s %d %d", ax2asc(&nr_node->callsign), (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic, @@ -756,6 +865,7 @@ nr_node->routes[i].obs_count, nr_node->routes[i].neighbour->number); } + nr_node_unlock(nr_node); len += sprintf(buffer + len, "\n"); @@ -769,7 +879,7 @@ if (pos > offset + length) break; } - spin_unlock_bh(&nr_node_lock); + spin_unlock_bh(&nr_node_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -782,15 +892,16 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length) { struct nr_neigh *nr_neigh; + struct hlist_node *node; int len = 0; off_t pos = 0; off_t begin = 0; int i; - spin_lock_bh(&nr_neigh_lock); + spin_lock_bh(&nr_neigh_list_lock); len += sprintf(buffer, "addr callsign dev qual lock count failed digipeaters\n"); - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) { + nr_neigh_for_each(nr_neigh, node, &nr_neigh_list) { len += sprintf(buffer + len, "%05d %-9s %-4s %3d %d %3d %3d", nr_neigh->number, ax2asc(&nr_neigh->callsign), @@ -818,7 +929,7 @@ break; } - spin_unlock_bh(&nr_neigh_lock); + spin_unlock_bh(&nr_neigh_list_lock); *start = buffer + (offset - begin); len -= (offset - begin); @@ -833,20 +944,24 @@ */ void __exit nr_rt_free(void) { - struct nr_neigh *s, *nr_neigh = nr_neigh_list; - struct nr_node *t, *nr_node = nr_node_list; - - while (nr_node != NULL) { - t = nr_node; - nr_node = nr_node->next; - - nr_remove_node(t); - } - - while (nr_neigh != NULL) { - s = nr_neigh; - nr_neigh = nr_neigh->next; - - nr_remove_neigh(s); + struct nr_neigh *s = NULL; + struct nr_node *t = NULL; + struct hlist_node *node, *nodet; + + spin_lock_bh(&nr_neigh_list_lock); + spin_lock_bh(&nr_node_list_lock); + nr_node_for_each_safe(t, node, nodet, &nr_node_list) { + nr_node_lock(t); + nr_remove_node_locked(t); + nr_node_unlock(t); + } + nr_neigh_for_each_safe(s, node, nodet, &nr_neigh_list) { + while(s->count) { + s->count--; + nr_neigh_put(s); + } + nr_remove_neigh_locked(s); } + spin_unlock_bh(&nr_node_list_lock); + spin_unlock_bh(&nr_neigh_list_lock); } Only in linux-2.6.0-test3.rxq/net/netrom: nr_route.o diff -ru linux-2.6.0-test3/net/netrom/nr_subr.c linux-2.6.0-test3.rxq/net/netrom/nr_subr.c --- linux-2.6.0-test3/net/netrom/nr_subr.c 2003-08-09 06:42:56.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_subr.c 2003-08-12 23:40:35.000000000 +0200 @@ -127,7 +127,7 @@ unsigned char *dptr; int len, timeout; - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN; + len = NR_NETWORK_LEN + NR_TRANSPORT_LEN; switch (frametype & 0x0F) { case NR_CONNREQ: @@ -151,7 +151,7 @@ /* * Space for AX.25 and NET/ROM network header */ - skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN); + skb_reserve(skb, NR_NETWORK_LEN); dptr = skb_put(skb, skb_tailroom(skb)); @@ -219,12 +219,12 @@ unsigned char *dptr; int len; - len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; + len = NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL) return; - skb_reserve(skbn, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN); + skb_reserve(skbn, 0); dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN); Only in linux-2.6.0-test3.rxq/net/netrom: nr_subr.o diff -ru linux-2.6.0-test3/net/netrom/nr_timer.c linux-2.6.0-test3.rxq/net/netrom/nr_timer.c --- linux-2.6.0-test3/net/netrom/nr_timer.c 2003-08-09 06:38:56.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/nr_timer.c 2003-08-12 23:40:35.000000000 +0200 @@ -143,7 +143,10 @@ is accepted() it isn't 'dead' so doesn't get removed. */ if (sock_flag(sk, SOCK_DESTROY) || (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { + sock_hold(sk); nr_destroy_socket(sk); + bh_unlock_sock(sk); + sock_put(sk); return; } break; @@ -227,6 +230,7 @@ case NR_STATE_1: if (nr->n2count == nr->n2) { nr_disconnect(sk, ETIMEDOUT); + bh_unlock_sock(sk); return; } else { nr->n2count++; @@ -237,6 +241,7 @@ case NR_STATE_2: if (nr->n2count == nr->n2) { nr_disconnect(sk, ETIMEDOUT); + bh_unlock_sock(sk); return; } else { nr->n2count++; @@ -247,6 +252,7 @@ case NR_STATE_3: if (nr->n2count == nr->n2) { nr_disconnect(sk, ETIMEDOUT); + bh_unlock_sock(sk); return; } else { nr->n2count++; Only in linux-2.6.0-test3.rxq/net/netrom: nr_timer.o diff -ru linux-2.6.0-test3/net/netrom/sysctl_net_netrom.c linux-2.6.0-test3.rxq/net/netrom/sysctl_net_netrom.c --- linux-2.6.0-test3/net/netrom/sysctl_net_netrom.c 2003-08-09 06:33:21.000000000 +0200 +++ linux-2.6.0-test3.rxq/net/netrom/sysctl_net_netrom.c 2003-08-12 23:40:35.000000000 +0200 @@ -15,9 +15,9 @@ /* * Values taken from NET/ROM documentation. */ -static int min_quality[1], max_quality[] = {255}; -static int min_obs[1], max_obs[] = {255}; -static int min_ttl[1], max_ttl[] = {255}; +static int min_quality[] = {0}, max_quality[] = {255}; +static int min_obs[] = {0}, max_obs[] = {255}; +static int min_ttl[] = {0}, max_ttl[] = {255}; static int min_t1[] = {5 * HZ}; static int max_t1[] = {600 * HZ}; static int min_n2[] = {2}, max_n2[] = {127}; @@ -28,7 +28,7 @@ static int min_window[] = {1}, max_window[] = {127}; static int min_idle[] = {0 * HZ}; static int max_idle[] = {65535 * HZ}; -static int min_route[1], max_route[] = {1}; +static int min_route[] = {0}, max_route[] = {1}; static int min_fails[] = {1}, max_fails[] = {10}; static struct ctl_table_header *nr_table_header; Only in linux-2.6.0-test3.rxq/net/netrom: sysctl_net_netrom.o --- linux-2.6.0-test3/include/net/ax25.h 2003-08-09 06:38:16.000000000 +0200 +++ linux-2.6.0-test3.rxq/include/net/ax25.h 2003-08-12 23:40:35.000000000 +0200 @@ -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 @@ } 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 @@ 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 *); --- linux-2.6.0-test3/include/net/netrom.h 2003-08-09 06:37:18.000000000 +0200 +++ linux-2.6.0-test3.rxq/include/net/netrom.h 2003-08-12 23:40:35.000000000 +0200 @@ -7,6 +7,7 @@ #ifndef _NETROM_H #define _NETROM_H #include <linux/netrom.h> +#include <linux/list.h> #define NR_NETWORK_LEN 15 #define NR_TRANSPORT_LEN 5 @@ -77,16 +78,17 @@ #define nr_sk(__sk) ((nr_cb *)(__sk)->sk_protinfo) struct nr_neigh { - struct nr_neigh *next; - ax25_address callsign; - ax25_digi *digipeat; - ax25_cb *ax25; - struct net_device *dev; - unsigned char quality; - unsigned char locked; - unsigned short count; - unsigned int number; - unsigned char failed; + struct hlist_node neigh_node; + ax25_address callsign; + ax25_digi *digipeat; + ax25_cb *ax25; + struct net_device *dev; + unsigned char quality; + unsigned char locked; + unsigned short count; + unsigned int number; + unsigned char failed; + atomic_t refcount; }; struct nr_route { @@ -96,14 +98,74 @@ }; struct nr_node { - struct nr_node *next; - ax25_address callsign; - char mnemonic[7]; - unsigned char which; - unsigned char count; - struct nr_route routes[3]; + struct hlist_node node_node; + ax25_address callsign; + char mnemonic[7]; + unsigned char which; + unsigned char count; + struct nr_route routes[3]; + atomic_t refcount; + spinlock_t node_lock; }; +/********************************************************************* + * nr_node & nr_neigh lists, refcounting and locking + *********************************************************************/ + +extern struct hlist_head nr_node_list; +extern struct hlist_head nr_neigh_list; + +#define nr_node_hold(__nr_node) \ + atomic_inc(&((__nr_node)->refcount)) + +static __inline__ void nr_node_put(struct nr_node *nr_node) +{ + if (atomic_dec_and_test(&nr_node->refcount)) { + kfree(nr_node); + } +} + +#define nr_neigh_hold(__nr_neigh) \ + atomic_inc(&((__nr_neigh)->refcount)) + +static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh) +{ + if (atomic_dec_and_test(&nr_neigh->refcount)) { + if (nr_neigh->digipeat != NULL) + kfree(nr_neigh->digipeat); + kfree(nr_neigh); + } +} + +/* nr_node_lock and nr_node_unlock also hold/put the node's refcounter. + */ +static __inline__ void nr_node_lock(struct nr_node *nr_node) +{ + nr_node_hold(nr_node); + spin_lock_bh(&nr_node->node_lock); +} + +static __inline__ void nr_node_unlock(struct nr_node *nr_node) +{ + spin_unlock_bh(&nr_node->node_lock); + nr_node_put(nr_node); +} + +#define nr_neigh_for_each(__nr_neigh, node, list) \ + hlist_for_each_entry(__nr_neigh, node, list, neigh_node) + +#define nr_neigh_for_each_safe(__nr_neigh, node, node2, list) \ + hlist_for_each_entry_safe(__nr_neigh, node, node2, list, neigh_node) + +#define nr_node_for_each(__nr_node, node, list) \ + hlist_for_each_entry(__nr_node, node, list, node_node) + +#define nr_node_for_each_safe(__nr_node, node, node2, list) \ + hlist_for_each_entry_safe(__nr_node, node, node2, list, node_node) + + +/*********************************************************************/ + /* af_netrom.c */ extern int sysctl_netrom_default_path_quality; extern int sysctl_netrom_obsolescence_count_initialiser; diff -Nru a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c --- a/net/ax25/ax25_dev.c Tue Aug 12 16:45:51 2003 +++ b/net/ax25/ax25_dev.c Tue Aug 12 16:45:51 2003 @@ -67,6 +67,7 @@ dev->ax25_ptr = ax25_dev; ax25_dev->dev = dev; + dev_hold(dev); ax25_dev->forward = NULL; ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE; @@ -121,6 +122,7 @@ if ((s = ax25_dev_list) == ax25_dev) { ax25_dev_list = s->next; spin_unlock_bh(&ax25_dev_lock); + dev_put(dev); kfree(ax25_dev); ax25_register_sysctl(); return; @@ -131,6 +133,7 @@ s->next = ax25_dev->next; spin_unlock_bh(&ax25_dev_lock); kfree(ax25_dev); + dev_put(dev); ax25_register_sysctl(); return; } --- ax25/net/ax25/af_ax25.c 2003-08-12 17:08:42.025816088 -0700 +++ linux-2.5-net/net/ax25/af_ax25.c 2003-08-12 16:47:07.802057749 -0700 if (optlen > IFNAMSIZ) optlen=IFNAMSIZ; if (copy_from_user(devname, optval, optlen)) { - res = -EFAULT; + res = -EFAULT; break; } @@ -650,12 +650,14 @@ static int ax25_setsockopt(struct socket (sock->state != SS_UNCONNECTED || sk->sk_state == TCP_LISTEN)) { res = -EADDRNOTAVAIL; - dev_put(dev); - break; } - ax25->ax25_dev = ax25_dev_ax25dev(dev); - ax25_fillin_cb(ax25, ax25->ax25_dev); + else if ((ax25->ax25_dev = ax25_dev_ax25dev(dev)) == NULL) + res = -EINVAL; + else + ax25_fillin_cb(ax25, ax25->ax25_dev); + + dev_put(dev); break; default: diff -Nru a/include/net/ax25.h b/include/net/ax25.h --- a/include/net/ax25.h Tue Aug 12 17:16:52 2003 +++ b/include/net/ax25.h Tue Aug 12 17:16:52 2003 @@ -314,7 +314,7 @@ /* ax25_route.c */ extern void ax25_rt_device_down(struct net_device *); extern int ax25_rt_ioctl(unsigned int, void *); -extern int ax25_rt_get_info(char *, char **, off_t, int); +extern struct file_operations ax25_route_fops; extern int ax25_rt_autobind(ax25_cb *, ax25_address *); extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *, struct net_device *); @@ -373,7 +373,7 @@ extern int ax25_uid_policy; extern ax25_address *ax25_findbyuid(uid_t); extern int ax25_uid_ioctl(int, struct sockaddr_ax25 *); -extern int ax25_uid_get_info(char *, char **, off_t, int); +extern struct file_operations ax25_uid_fops; extern void ax25_uid_free(void); /* sysctl_net_ax25.c */ diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c --- a/net/ax25/af_ax25.c Tue Aug 12 17:16:52 2003 +++ b/net/ax25/af_ax25.c Tue Aug 12 17:16:52 2003 @@ -1844,81 +1844,107 @@ return res; } -static int ax25_get_info(char *buffer, char **start, off_t offset, int length) +#ifdef CONFIG_PROC_FS + +static void *ax25_info_start(struct seq_file *seq, loff_t *pos) { - ax25_cb *ax25; - int k; - int len = 0; - off_t pos = 0; - off_t begin = 0; + struct ax25_cb *ax25; struct hlist_node *node; + int i = 0; spin_lock_bh(&ax25_list_lock); + ax25_for_each(ax25, node, &ax25_list) { + if (i == *pos) + return ax25; + ++i; + } + return NULL; +} + +static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + + return hlist_entry( ((struct ax25_cb *)v)->ax25_node.next, + struct ax25_cb, ax25_node); +} + +static void ax25_info_stop(struct seq_file *seq, void *v) +{ + spin_unlock_bh(&ax25_list_lock); +} + +static int ax25_info_show(struct seq_file *seq, void *v) +{ + ax25_cb *ax25 = v; + int k; + /* * New format: * 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 */ - 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, - ax2asc(&ax25->source_addr), - ax25->iamdigi? "*":""); - - len += sprintf(buffer+len, "%s", ax2asc(&ax25->dest_addr)); - - for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { - len += sprintf(buffer+len, ",%s%s", - ax2asc(&ax25->digipeat->calls[k]), - ax25->digipeat->repeated[k]? "*":""); - } - - len += sprintf(buffer+len, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", - ax25->state, - ax25->vs, ax25->vr, ax25->va, - ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ, - ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ, - ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ, - ax25_display_timer(&ax25->idletimer) / (60 * HZ), - ax25->idle / (60 * HZ), - ax25->n2count, ax25->n2, - ax25->rtt / HZ, - ax25->window, - 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"); - } - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } + seq_printf(seq, "%8.8lx %s %s%s ", + (long) ax25, + ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, + ax2asc(&ax25->source_addr), + ax25->iamdigi? "*":""); + seq_printf(seq, "%s", ax2asc(&ax25->dest_addr)); + + for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { + seq_printf(seq, ",%s%s", + ax2asc(&ax25->digipeat->calls[k]), + ax25->digipeat->repeated[k]? "*":""); + } - if (pos > offset + length) - break; + seq_printf(seq, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", + ax25->state, + ax25->vs, ax25->vr, ax25->va, + ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ, + ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ, + ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ, + ax25_display_timer(&ax25->idletimer) / (60 * HZ), + ax25->idle / (60 * HZ), + ax25->n2count, ax25->n2, + ax25->rtt / HZ, + ax25->window, + ax25->paclen); + + if (ax25->sk != NULL) { + bh_lock_sock(ax25->sk); + seq_printf(seq," %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 { + seq_puts(seq, " * * *\n"); } + return 0; +} - spin_unlock_bh(&ax25_list_lock); +static struct seq_operations ax25_info_seqops = { + .start = ax25_info_start, + .next = ax25_info_next, + .stop = ax25_info_stop, + .show = ax25_info_show, +}; - *start = buffer + (offset - begin); - len -= (offset - begin); +static int ax25_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ax25_info_seqops); +} - if (len > length) len = length; +struct file_operations ax25_info_fops = { + .owner = THIS_MODULE, + .open = ax25_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; - return(len); -} +#endif static struct net_proto_family ax25_family_ops = { .family = PF_AX25, @@ -1988,9 +2014,9 @@ register_netdevice_notifier(&ax25_dev_notifier); ax25_register_sysctl(); - proc_net_create("ax25_route", 0, ax25_rt_get_info); - proc_net_create("ax25", 0, ax25_get_info); - proc_net_create("ax25_calls", 0, ax25_uid_get_info); + proc_net_fops_create("ax25_route", S_IRUGO, &ax25_route_fops); + proc_net_fops_create("ax25", S_IRUGO, &ax25_info_fops); + proc_net_fops_create("ax25_calls", S_IRUGO, &ax25_uid_fops); printk(banner); return 0; diff -Nru a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c --- a/net/ax25/ax25_route.c Tue Aug 12 17:16:52 2003 +++ b/net/ax25/ax25_route.c Tue Aug 12 17:16:52 2003 @@ -34,6 +34,7 @@ #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/seq_file.h> static ax25_route *ax25_route_list; static rwlock_t ax25_route_lock = RW_LOCK_UNLOCKED; @@ -278,66 +279,100 @@ } } -int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length) -{ - ax25_route *ax25_rt; - int len = 0; - off_t pos = 0; - off_t begin = 0; - char *callsign; - int i; +#ifdef CONFIG_PROC_FS - read_lock(&ax25_route_lock); +#define AX25_PROC_START ((void *)1) - len += sprintf(buffer, "callsign dev mode digipeaters\n"); +static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct ax25_route *ax25_rt; + int i = 1; + + read_lock(&ax25_route_lock); + if (*pos == 0) + return AX25_PROC_START; for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { + if (i == *pos) + return ax25_rt; + ++i; + } + + return NULL; +} + +static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return (v == AX25_PROC_START) ? ax25_route_list : + ((struct ax25_route *) v)->next; +} + +static void ax25_rt_seq_stop(struct seq_file *seq, void *v) +{ + read_unlock(&ax25_route_lock); +} + +static int ax25_rt_seq_show(struct seq_file *seq, void *v) +{ + if (v == AX25_PROC_START) + seq_puts(seq, "callsign dev mode digipeaters\n"); + else { + struct ax25_route *ax25_rt = v; + const char *callsign; + int i; + if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0) callsign = "default"; else callsign = ax2asc(&ax25_rt->callsign); - len += sprintf(buffer + len, "%-9s %-4s", + + seq_printf(seq, "%-9s %-4s", callsign, ax25_rt->dev ? ax25_rt->dev->name : "???"); switch (ax25_rt->ip_mode) { case 'V': - len += sprintf(buffer + len, " vc"); + seq_puts(seq, " vc"); break; case 'D': - len += sprintf(buffer + len, " dg"); + seq_puts(seq, " dg"); break; default: - len += sprintf(buffer + len, " *"); + seq_puts(seq, " *"); break; } if (ax25_rt->digipeat != NULL) for (i = 0; i < ax25_rt->digipeat->ndigi; i++) - len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i])); - - len += sprintf(buffer + len, "\n"); + seq_printf(seq, " %s", ax2asc(&ax25_rt->digipeat->calls[i])); - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - break; + seq_puts(seq, "\n"); } - read_unlock(&ax25_route_lock); - - *start = buffer + (offset - begin); - len -= (offset - begin); + return 0; +} - if (len > length) - len = length; +static struct seq_operations ax25_rt_seqops = { + .start = ax25_rt_seq_start, + .next = ax25_rt_seq_next, + .stop = ax25_rt_seq_stop, + .show = ax25_rt_seq_show, +}; - return len; +static int ax25_rt_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ax25_rt_seqops); } + +struct file_operations ax25_route_fops = { + .owner = THIS_MODULE, + .open = ax25_rt_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* * Find AX.25 route diff -Nru a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c --- a/net/ax25/ax25_uid.c Tue Aug 12 17:16:52 2003 +++ b/net/ax25/ax25_uid.c Tue Aug 12 17:16:52 2003 @@ -30,6 +30,7 @@ #include <linux/interrupt.h> #include <linux/notifier.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/stat.h> #include <linux/netfilter.h> #include <linux/sysctl.h> @@ -141,39 +142,73 @@ return -EINVAL; /*NOTREACHED */ } -int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length) +#ifdef CONFIG_PROC_FS + +#define AX25_PROC_START ((void *)1) + +static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) { - ax25_uid_assoc *pt; - int len = 0; - off_t pos = 0; - off_t begin = 0; + struct ax25_uid_assoc *pt; + int i = 1; read_lock(&ax25_uid_lock); - len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy); + if (*pos == 0) + return AX25_PROC_START; for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { - len += sprintf(buffer + len, "%6d %s\n", pt->uid, ax2asc(&pt->call)); - - pos = begin + len; + if (i == *pos) + return pt; + ++i; + } + return NULL; +} - if (pos < offset) { - len = 0; - begin = pos; - } +static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return (v == AX25_PROC_START) ? ax25_uid_list : + ((struct ax25_uid_assoc *) v)->next; +} - if (pos > offset + length) - break; - } +static void ax25_uid_seq_stop(struct seq_file *seq, void *v) +{ read_unlock(&ax25_uid_lock); +} + +static int ax25_uid_seq_show(struct seq_file *seq, void *v) +{ + if (v == AX25_PROC_START) + seq_printf(seq, "Policy: %d\n", ax25_uid_policy); + else { + struct ax25_uid_assoc *pt = v; + - *start = buffer + (offset - begin); - len -= offset - begin; + seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call)); + } + return 0; +} - if (len > length) - len = length; +static struct seq_operations ax25_uid_seqops = { + .start = ax25_uid_seq_start, + .next = ax25_uid_seq_next, + .stop = ax25_uid_seq_stop, + .show = ax25_uid_seq_show, +}; - return len; +static int ax25_uid_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ax25_uid_seqops); } + +struct file_operations ax25_uid_fops = { + .owner = THIS_MODULE, + .open = ax25_uid_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* * Free all memory associated with UID/Callsign structures. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Convert ax25 to seq_file 2003-08-13 15:34 ` Jeroen Vreeken @ 2003-08-13 15:42 ` David S. Miller 2003-08-13 22:35 ` [PATCH] (0/11) Netrom patches Stephen Hemminger 2003-08-20 18:45 ` [PATCH] ax25 changes Jeroen Vreeken 0 siblings, 2 replies; 23+ messages in thread From: David S. Miller @ 2003-08-13 15:42 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: shemminger, linux-hams, ralf, netdev On Wed, 13 Aug 2003 17:34:46 +0200 Jeroen Vreeken <pe1rxq@amsat.org> wrote: > This is my last patch (rxq4) plus Stephen's last three (dev locking, > setsockopt, seq_file) Please don't combine the patches, I want the each individual patch with the author and his comments for that change. If you combine all the work, this information gets lost. Also, please use something more intelligent to generate these diffs, so that I don't have to sift through all of the lines like "Only in ...". Thanks. > p.s. Which protocol is a good example of non-linear skb usage? Most still > seem to use skb_linearize() and the skb documentation is somewhat outdated. What are you talking about? There are only a handful of skb_linearize() users in the current 2.6.x sources, and those will be eradicated soon. IPV4 is probably the best example. ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH] (0/11) Netrom patches 2003-08-13 15:42 ` David S. Miller @ 2003-08-13 22:35 ` Stephen Hemminger 2003-08-15 4:13 ` David S. Miller 2003-08-20 18:45 ` [PATCH] ax25 changes Jeroen Vreeken 1 sibling, 1 reply; 23+ messages in thread From: Stephen Hemminger @ 2003-08-13 22:35 UTC (permalink / raw) To: David S. Miller; +Cc: Jeroen Vreeken, netdev, linux-hams, ralf, netdev The following set of patches breaks out Jeroen's work (1-7) and adds several updates from me. 1 - sysctl initializers 2 - destroy timeout 3 - write queue cleanup on close 4 - socket header length reservation 5 - lock socket's when using 6 - device management fixes 7 - route table use hlist After these it closely matches the version of NETROM in the rxq3 patch set. 8 - make things static 9 - dynamic net device allocation 10 - convert to seq_file 11 - bug fix for using socket after close ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] (0/11) Netrom patches 2003-08-13 22:35 ` [PATCH] (0/11) Netrom patches Stephen Hemminger @ 2003-08-15 4:13 ` David S. Miller 0 siblings, 0 replies; 23+ messages in thread From: David S. Miller @ 2003-08-15 4:13 UTC (permalink / raw) To: Stephen Hemminger; +Cc: pe1rxq, netdev, linux-hams, ralf On Wed, 13 Aug 2003 15:35:26 -0700 Stephen Hemminger <shemminger@osdl.org> wrote: > The following set of patches breaks out Jeroen's work (1-7) and adds > several updates from me. I've applied all of these NETROM patches, thanks. ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH] ax25 changes 2003-08-13 15:42 ` David S. Miller 2003-08-13 22:35 ` [PATCH] (0/11) Netrom patches Stephen Hemminger @ 2003-08-20 18:45 ` Jeroen Vreeken 2003-08-21 19:18 ` David S. Miller ` (2 more replies) 1 sibling, 3 replies; 23+ messages in thread From: Jeroen Vreeken @ 2003-08-20 18:45 UTC (permalink / raw) To: David S . Miller; +Cc: shemminger, linux-hams, ralf, netdev [-- Attachment #1: Type: text/plain, Size: 1163 bytes --] On 2003.08.13 17:42:52 +0200 David S. Miller wrote: > On Wed, 13 Aug 2003 17:34:46 +0200 > Jeroen Vreeken <pe1rxq@amsat.org> wrote: > > > This is my last patch (rxq4) plus Stephen's last three (dev locking, > > setsockopt, seq_file) > > Please don't combine the patches, I want the each individual > patch with the author and his comments for that change. > > If you combine all the work, this information gets lost. After posting this mega patch I have been away for some days.... Fortunatly Stephen already reduced the amount of work by doing the netrom stuff. The next four patches are the remaining ax25 (and a litle netrom) patches: ax25_cb-lock.diff This is the biggest one: - ax25_cb's use refcounting - the ax25_cb list uses hlists - Lots of socket locking. This patch touches almost everything in the ax25 directory. hard_header.diff Makes ax25_subr.c use the devices hard_header_len instead of some predicted worst case. (also contains a small socket locking patch) iface-lists.diff Fixes the list usage and list locking in ax25_iface.c netrom-refcnt.diff Small changes to netrom as a result of the ax25_cb refcounting. Jeroen [-- Attachment #2: netrom-refcnt.diff --] [-- Type: application/octet-stream, Size: 688 bytes --] --- linux-2.6.0-test3.bk/net/netrom/nr_route.c 2003-08-20 19:17:18.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/netrom/nr_route.c 2003-08-20 19:34:51.000000000 +0200 @@ -735,7 +735,7 @@ if (nr_neigh == NULL) return; nr_neigh->ax25 = NULL; - // ax25_cb_put(ax25); + ax25_cb_put(ax25); if (++nr_neigh->failed < sysctl_netrom_link_fails_count) { nr_neigh_put(nr_neigh); @@ -829,7 +829,7 @@ ax25s = ax25_send_frame(skb, 256, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); if (nr_neigh->ax25 && ax25s) { /* We were already holding this ax25_cb */ - // ax25_cb_put(ax25s); + ax25_cb_put(ax25s); } nr_neigh->ax25 = ax25s; [-- Attachment #3: ax25_cb-lock.diff --] [-- Type: application/octet-stream, Size: 26124 bytes --] diff -ruN linux-2.6.0-test3.bk/net/ax25/af_ax25.c linux-2.6.0-test3.bk.rxq/net/ax25/af_ax25.c --- linux-2.6.0-test3.bk/net/ax25/af_ax25.c 2003-08-20 19:00:29.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/af_ax25.c 2003-08-20 19:58:29.000000000 +0200 @@ -51,54 +51,27 @@ -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 @@ { 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 @@ /* * 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 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 *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_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 @@ 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 *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 @@ break; } } + spin_unlock_bh(&ax25_list_lock); return sk; @@ -299,7 +279,16 @@ */ 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 @@ { struct sk_buff *skb; - ax25_remove_socket(ax25); + ax25_cb_del(ax25); ax25_stop_heartbeat(ax25); ax25_stop_t1timer(ax25); @@ -337,22 +326,27 @@ 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 @@ 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 @@ return -EINVAL; } - return 0; + return 0; } /* @@ -507,6 +501,7 @@ 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 @@ (sock->state != SS_UNCONNECTED || sk->sk_state == TCP_LISTEN)) { res = -EADDRNOTAVAIL; + dev_put(dev); break; } @@ -877,7 +873,7 @@ break; default: sk_free(sk); - ax25_free_cb(ax25); + ax25_cb_put(ax25); return NULL; } @@ -937,6 +933,7 @@ if (sk == NULL) return 0; + sock_hold(sk); lock_sock(sk); ax25 = ax25_sk(sk); @@ -944,13 +941,15 @@ 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 @@ 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 @@ ax25_fillin_cb(ax25, ax25_dev); done: - ax25_insert_socket(ax25); + ax25_cb_add(ax25); sk->sk_zapped = 0; out: @@ -1093,7 +1090,7 @@ 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 @@ 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 @@ } 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 @@ 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 @@ sock->state = SS_CONNECTED; + err=0; out: release_sock(sk); - return 0; + return err; } @@ -1331,15 +1332,18 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ * 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 @@ 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"); } diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_ds_in.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_ds_in.c --- linux-2.6.0-test3.bk/net/ax25/ax25_ds_in.c 2003-08-20 19:00:30.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_ds_in.c 2003-08-20 19:58:29.000000000 +0200 @@ -65,6 +65,7 @@ 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 @@ */ if (!sock_flag(ax25->sk, SOCK_DEAD)) ax25->sk->sk_state_change(ax25->sk); + bh_unlock_sock(ax25->sk); } ax25_dama_on(ax25); diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_ds_subr.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_ds_subr.c --- linux-2.6.0-test3.bk/net/ax25/ax25_ds_subr.c 2003-08-20 19:00:30.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_ds_subr.c 2003-08-20 19:58:29.000000000 +0200 @@ -40,6 +40,7 @@ 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 @@ 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 @@ { 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; diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_ds_timer.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_ds_timer.c --- linux-2.6.0-test3.bk/net/ax25/ax25_ds_timer.c 2003-08-20 19:00:29.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_ds_timer.c 2003-08-20 19:58:29.000000000 +0200 @@ -74,6 +74,7 @@ { 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 @@ } 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 @@ 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 @@ /* * 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 @@ break; } + if (sk) + bh_unlock_sock(sk); + ax25_start_heartbeat(ax25); } @@ -157,6 +172,7 @@ 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 @@ ax25->sk->sk_state_change(ax25->sk); sock_set_flag(ax25->sk, SOCK_DEAD); } + bh_lock_sock(ax25->sk); } } diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_in.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_in.c --- linux-2.6.0-test3.bk/net/ax25/ax25_in.c 2003-08-20 19:00:29.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_in.c 2003-08-20 19:58:29.000000000 +0200 @@ -147,6 +147,7 @@ } 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 @@ else ax25->condition |= AX25_COND_OWN_RX_BUSY; } + bh_unlock_sock(ax25->sk); } return queued; @@ -329,6 +331,7 @@ if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) kfree_skb(skb); + ax25_cb_put(ax25); return 0; } @@ -357,11 +360,14 @@ 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 @@ 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 @@ ax25->state = AX25_STATE_3; - ax25_insert_socket(ax25); + ax25_cb_add(ax25); ax25_start_heartbeat(ax25); ax25_start_t3timer(ax25); diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_ip.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_ip.c --- linux-2.6.0-test3.bk/net/ax25/ax25_ip.c 2003-08-20 19:00:29.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_ip.c 2003-08-20 19:58:29.000000000 +0200 @@ -107,6 +107,7 @@ 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 @@ 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; } } diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_out.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_out.c --- linux-2.6.0-test3.bk/net/ax25/ax25_out.c 2003-08-20 19:00:30.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_out.c 2003-08-20 19:58:29.000000000 +0200 @@ -71,7 +71,7 @@ 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 @@ #endif } - ax25_insert_socket(ax25); + ax25_cb_add(ax25); ax25->state = AX25_STATE_1; diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_route.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_route.c --- linux-2.6.0-test3.bk/net/ax25/ax25_route.c 2003-08-20 19:00:30.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_route.c 2003-08-20 19:58:29.000000000 +0200 @@ -162,6 +162,7 @@ if (ax25_rt->digipeat != NULL) kfree(ax25_rt->digipeat); kfree(ax25_rt); + return; } /* @@ -434,8 +435,11 @@ 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); diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_std_in.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_std_in.c --- linux-2.6.0-test3.bk/net/ax25/ax25_std_in.c 2003-08-20 19:00:29.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_std_in.c 2003-08-20 19:58:29.000000000 +0200 @@ -73,10 +73,12 @@ 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; diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_std_timer.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_std_timer.c --- linux-2.6.0-test3.bk/net/ax25/ax25_std_timer.c 2003-08-20 19:00:29.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_std_timer.c 2003-08-20 19:58:29.000000000 +0200 @@ -33,14 +33,25 @@ 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 @@ /* * 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 @@ } } + if (sk) + bh_unlock_sock(sk); + ax25_start_heartbeat(ax25); } @@ -94,6 +108,7 @@ 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 @@ ax25->sk->sk_state_change(ax25->sk); sock_set_flag(ax25->sk, SOCK_DEAD); } + bh_unlock_sock(ax25->sk); } } diff -ruN linux-2.6.0-test3.bk/net/ax25/ax25_timer.c linux-2.6.0-test3.bk.rxq/net/ax25/ax25_timer.c --- linux-2.6.0-test3.bk/net/ax25/ax25_timer.c 2003-08-20 19:00:30.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_timer.c 2003-08-20 19:58:29.000000000 +0200 @@ -141,13 +141,10 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ break; #endif } - bh_unlock_sock(sk); } diff -ruN linux-2.6.0-test3.bk/net/ax25/sysctl_net_ax25.c linux-2.6.0-test3.bk.rxq/net/ax25/sysctl_net_ax25.c --- linux-2.6.0-test3.bk/net/ax25/sysctl_net_ax25.c 2003-08-20 19:00:29.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/sysctl_net_ax25.c 2003-08-20 19:58:29.000000000 +0200 @@ -204,8 +204,10 @@ 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); --- linux-2.6.0-test3.bk/include/net/ax25.h 2003-08-20 19:05:22.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/include/net/ax25.h 2003-08-20 19:41:56.000000000 +0200 @@ -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 @@ } 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 @@ 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 *); [-- Attachment #4: hard_header.diff --] [-- Type: application/octet-stream, Size: 1406 bytes --] --- linux-2.6.0-test3.bk/net/ax25/ax25_subr.c 2003-08-20 19:00:29.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_subr.c 2003-08-20 19:58:29.000000000 +0200 @@ -158,10 +158,10 @@ struct sk_buff *skb; unsigned char *dptr; - if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat) + 2, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(ax25->ax25_dev->dev->hard_header_len + 2, GFP_ATOMIC)) == NULL) return; - skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(ax25->digipeat)); + skb_reserve(skb, ax25->ax25_dev->dev->hard_header_len); skb->nh.raw = skb->data; @@ -202,10 +202,10 @@ if (dev == NULL) return; - if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + ax25_addr_size(digi) + 1, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(dev->hard_header_len + 1, GFP_ATOMIC)) == NULL) return; /* Next SABM will get DM'd */ - skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi)); + skb_reserve(skb, dev->hard_header_len); skb->nh.raw = skb->data; ax25_digi_invert(digi, &retdigi); @@ -282,6 +282,7 @@ ax25_link_failed(ax25, reason); if (ax25->sk != NULL) { + bh_lock_sock(ax25->sk); ax25->sk->sk_state = TCP_CLOSE; ax25->sk->sk_err = reason; ax25->sk->sk_shutdown |= SEND_SHUTDOWN; @@ -289,5 +290,6 @@ ax25->sk->sk_state_change(ax25->sk); sock_set_flag(ax25->sk, SOCK_DEAD); } + bh_unlock_sock(ax25->sk); } } [-- Attachment #5: iface-lists.diff --] [-- Type: application/octet-stream, Size: 1787 bytes --] --- linux-2.6.0-test3.bk/net/ax25/ax25_iface.c 2003-08-20 19:00:29.000000000 +0200 +++ linux-2.6.0-test3.bk.rxq/net/ax25/ax25_iface.c 2003-08-20 19:58:29.000000000 +0200 @@ -33,20 +33,20 @@ struct protocol_struct *next; unsigned int pid; int (*func)(struct sk_buff *, ax25_cb *); -} *protocol_list; +} *protocol_list = NULL; static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED; static struct linkfail_struct { struct linkfail_struct *next; void (*func)(ax25_cb *, int); -} *linkfail_list; +} *linkfail_list = NULL; static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED; static struct listen_struct { struct listen_struct *next; ax25_address callsign; struct net_device *dev; -} *listen_list; +} *listen_list = NULL; static spinlock_t listen_lock = SPIN_LOCK_UNLOCKED; int ax25_protocol_register(unsigned int pid, @@ -129,8 +129,10 @@ spin_lock_bh(&linkfail_lock); linkfail = linkfail_list; - if (linkfail == NULL) + if (linkfail == NULL) { + spin_unlock_bh(&linkfail_lock); return; + } if (linkfail->func == func) { linkfail_list = linkfail->next; @@ -180,8 +182,10 @@ spin_lock_bh(&listen_lock); listen = listen_list; - if (listen == NULL) + if (listen == NULL) { + spin_unlock_bh(&listen_lock); return; + } if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { listen_list = listen->next; @@ -226,8 +230,10 @@ spin_lock_bh(&listen_lock); for (listen = listen_list; listen != NULL; listen = listen->next) - if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) + if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) { + spin_unlock_bh(&listen_lock); return 1; + } spin_unlock_bh(&listen_lock); return 0; ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ax25 changes 2003-08-20 18:45 ` [PATCH] ax25 changes Jeroen Vreeken @ 2003-08-21 19:18 ` David S. Miller 2003-08-22 20:13 ` [PATCH] ax25 - make sure and hold ref to dev Stephen Hemminger 2003-08-22 20:15 ` [RFT][PATCH] ax25 using seq_file Stephen Hemminger 2 siblings, 0 replies; 23+ messages in thread From: David S. Miller @ 2003-08-21 19:18 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: shemminger, linux-hams, ralf, netdev On Wed, 20 Aug 2003 20:45:18 +0200 Jeroen Vreeken <pe1rxq@amsat.org> wrote: > Fortunatly Stephen already reduced the amount of work by doing the netrom > stuff. > The next four patches are the remaining ax25 (and a litle netrom) patches: Applied, thanks Jeroen. ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH] ax25 - make sure and hold ref to dev 2003-08-20 18:45 ` [PATCH] ax25 changes Jeroen Vreeken 2003-08-21 19:18 ` David S. Miller @ 2003-08-22 20:13 ` Stephen Hemminger 2003-08-24 11:28 ` David S. Miller 2003-08-22 20:15 ` [RFT][PATCH] ax25 using seq_file Stephen Hemminger 2 siblings, 1 reply; 23+ messages in thread From: Stephen Hemminger @ 2003-08-22 20:13 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: David S . Miller, linux-hams, ralf, netdev The lower layers of ax25 hold a reference to the underlying device but don't increment the ref count. This is safe because it does the right thing when UNREGISTER notification comes in, but it is better to do the right thing. I tested this by messing with bpqether and ax25 to make sure both can be unloaded correctly. diff -Nru a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c --- a/net/ax25/ax25_dev.c Fri Aug 22 08:20:46 2003 +++ b/net/ax25/ax25_dev.c Fri Aug 22 08:20:46 2003 @@ -67,6 +67,7 @@ dev->ax25_ptr = ax25_dev; ax25_dev->dev = dev; + dev_hold(dev); ax25_dev->forward = NULL; ax25_dev->values[AX25_VALUES_IPDEFMODE] = AX25_DEF_IPDEFMODE; @@ -121,6 +122,7 @@ if ((s = ax25_dev_list) == ax25_dev) { ax25_dev_list = s->next; spin_unlock_bh(&ax25_dev_lock); + dev_put(dev); kfree(ax25_dev); ax25_register_sysctl(); return; @@ -130,6 +132,7 @@ if (s->next == ax25_dev) { s->next = ax25_dev->next; spin_unlock_bh(&ax25_dev_lock); + dev_put(dev); kfree(ax25_dev); ax25_register_sysctl(); return; @@ -196,8 +199,8 @@ ax25_dev = ax25_dev_list; while (ax25_dev != NULL) { s = ax25_dev; + dev_put(ax25_dev->dev); ax25_dev = ax25_dev->next; - kfree(s); } ax25_dev_list = NULL; ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ax25 - make sure and hold ref to dev 2003-08-22 20:13 ` [PATCH] ax25 - make sure and hold ref to dev Stephen Hemminger @ 2003-08-24 11:28 ` David S. Miller 0 siblings, 0 replies; 23+ messages in thread From: David S. Miller @ 2003-08-24 11:28 UTC (permalink / raw) To: Stephen Hemminger; +Cc: pe1rxq, linux-hams, ralf, netdev On Fri, 22 Aug 2003 13:13:28 -0700 Stephen Hemminger <shemminger@osdl.org> wrote: > The lower layers of ax25 hold a reference to the underlying device > but don't increment the ref count. This is safe because it does the > right thing when UNREGISTER notification comes in, but it is better > to do the right thing. Applied, thanks Stephen. ^ permalink raw reply [flat|nested] 23+ messages in thread
* [RFT][PATCH] ax25 using seq_file 2003-08-20 18:45 ` [PATCH] ax25 changes Jeroen Vreeken 2003-08-21 19:18 ` David S. Miller 2003-08-22 20:13 ` [PATCH] ax25 - make sure and hold ref to dev Stephen Hemminger @ 2003-08-22 20:15 ` Stephen Hemminger 2003-08-24 11:29 ` David S. Miller 2 siblings, 1 reply; 23+ messages in thread From: Stephen Hemminger @ 2003-08-22 20:15 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: David S . Miller, linux-hams, ralf, netdev Convert AX25 to use the seq_file interface for it's /proc hook. Jeroen could you test this with real hardware, since without hardware the table always comes up empty which is not a good enough test. diff -Nru a/include/net/ax25.h b/include/net/ax25.h --- a/include/net/ax25.h Fri Aug 22 08:21:10 2003 +++ b/include/net/ax25.h Fri Aug 22 08:21:10 2003 @@ -314,7 +314,7 @@ /* ax25_route.c */ extern void ax25_rt_device_down(struct net_device *); extern int ax25_rt_ioctl(unsigned int, void *); -extern int ax25_rt_get_info(char *, char **, off_t, int); +extern struct file_operations ax25_route_fops; extern int ax25_rt_autobind(ax25_cb *, ax25_address *); extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *, struct net_device *); @@ -373,7 +373,7 @@ extern int ax25_uid_policy; extern ax25_address *ax25_findbyuid(uid_t); extern int ax25_uid_ioctl(int, struct sockaddr_ax25 *); -extern int ax25_uid_get_info(char *, char **, off_t, int); +extern struct file_operations ax25_uid_fops; extern void ax25_uid_free(void); /* sysctl_net_ax25.c */ diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c --- a/net/ax25/af_ax25.c Fri Aug 22 08:21:10 2003 +++ b/net/ax25/af_ax25.c Fri Aug 22 08:21:10 2003 @@ -1842,81 +1842,107 @@ return res; } -static int ax25_get_info(char *buffer, char **start, off_t offset, int length) +#ifdef CONFIG_PROC_FS + +static void *ax25_info_start(struct seq_file *seq, loff_t *pos) { - ax25_cb *ax25; - int k; - int len = 0; - off_t pos = 0; - off_t begin = 0; + struct ax25_cb *ax25; struct hlist_node *node; + int i = 0; spin_lock_bh(&ax25_list_lock); + ax25_for_each(ax25, node, &ax25_list) { + if (i == *pos) + return ax25; + ++i; + } + return NULL; +} + +static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + + return hlist_entry( ((struct ax25_cb *)v)->ax25_node.next, + struct ax25_cb, ax25_node); +} + +static void ax25_info_stop(struct seq_file *seq, void *v) +{ + spin_unlock_bh(&ax25_list_lock); +} + +static int ax25_info_show(struct seq_file *seq, void *v) +{ + ax25_cb *ax25 = v; + int k; + /* * New format: * 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 */ - 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, - ax2asc(&ax25->source_addr), - ax25->iamdigi? "*":""); - - len += sprintf(buffer+len, "%s", ax2asc(&ax25->dest_addr)); - - for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { - len += sprintf(buffer+len, ",%s%s", - ax2asc(&ax25->digipeat->calls[k]), - ax25->digipeat->repeated[k]? "*":""); - } - - len += sprintf(buffer+len, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", - ax25->state, - ax25->vs, ax25->vr, ax25->va, - ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ, - ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ, - ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ, - ax25_display_timer(&ax25->idletimer) / (60 * HZ), - ax25->idle / (60 * HZ), - ax25->n2count, ax25->n2, - ax25->rtt / HZ, - ax25->window, - 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"); - } - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } + seq_printf(seq, "%8.8lx %s %s%s ", + (long) ax25, + ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name, + ax2asc(&ax25->source_addr), + ax25->iamdigi? "*":""); + seq_printf(seq, "%s", ax2asc(&ax25->dest_addr)); + + for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) { + seq_printf(seq, ",%s%s", + ax2asc(&ax25->digipeat->calls[k]), + ax25->digipeat->repeated[k]? "*":""); + } - if (pos > offset + length) - break; + seq_printf(seq, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d", + ax25->state, + ax25->vs, ax25->vr, ax25->va, + ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ, + ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ, + ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ, + ax25_display_timer(&ax25->idletimer) / (60 * HZ), + ax25->idle / (60 * HZ), + ax25->n2count, ax25->n2, + ax25->rtt / HZ, + ax25->window, + ax25->paclen); + + if (ax25->sk != NULL) { + bh_lock_sock(ax25->sk); + seq_printf(seq," %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 { + seq_puts(seq, " * * *\n"); } + return 0; +} - spin_unlock_bh(&ax25_list_lock); +static struct seq_operations ax25_info_seqops = { + .start = ax25_info_start, + .next = ax25_info_next, + .stop = ax25_info_stop, + .show = ax25_info_show, +}; - *start = buffer + (offset - begin); - len -= (offset - begin); +static int ax25_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ax25_info_seqops); +} - if (len > length) len = length; +static struct file_operations ax25_info_fops = { + .owner = THIS_MODULE, + .open = ax25_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; - return(len); -} +#endif static struct net_proto_family ax25_family_ops = { .family = PF_AX25, @@ -1986,9 +2012,9 @@ register_netdevice_notifier(&ax25_dev_notifier); ax25_register_sysctl(); - proc_net_create("ax25_route", 0, ax25_rt_get_info); - proc_net_create("ax25", 0, ax25_get_info); - proc_net_create("ax25_calls", 0, ax25_uid_get_info); + proc_net_fops_create("ax25_route", S_IRUGO, &ax25_route_fops); + proc_net_fops_create("ax25", S_IRUGO, &ax25_info_fops); + proc_net_fops_create("ax25_calls", S_IRUGO, &ax25_uid_fops); printk(banner); return 0; diff -Nru a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c --- a/net/ax25/ax25_route.c Fri Aug 22 08:21:10 2003 +++ b/net/ax25/ax25_route.c Fri Aug 22 08:21:10 2003 @@ -34,6 +34,7 @@ #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/seq_file.h> static ax25_route *ax25_route_list; static rwlock_t ax25_route_lock = RW_LOCK_UNLOCKED; @@ -278,66 +279,100 @@ } } -int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length) -{ - ax25_route *ax25_rt; - int len = 0; - off_t pos = 0; - off_t begin = 0; - char *callsign; - int i; +#ifdef CONFIG_PROC_FS - read_lock(&ax25_route_lock); +#define AX25_PROC_START ((void *)1) - len += sprintf(buffer, "callsign dev mode digipeaters\n"); +static void *ax25_rt_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct ax25_route *ax25_rt; + int i = 1; + + read_lock(&ax25_route_lock); + if (*pos == 0) + return AX25_PROC_START; for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { + if (i == *pos) + return ax25_rt; + ++i; + } + + return NULL; +} + +static void *ax25_rt_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return (v == AX25_PROC_START) ? ax25_route_list : + ((struct ax25_route *) v)->next; +} + +static void ax25_rt_seq_stop(struct seq_file *seq, void *v) +{ + read_unlock(&ax25_route_lock); +} + +static int ax25_rt_seq_show(struct seq_file *seq, void *v) +{ + if (v == AX25_PROC_START) + seq_puts(seq, "callsign dev mode digipeaters\n"); + else { + struct ax25_route *ax25_rt = v; + const char *callsign; + int i; + if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0) callsign = "default"; else callsign = ax2asc(&ax25_rt->callsign); - len += sprintf(buffer + len, "%-9s %-4s", + + seq_printf(seq, "%-9s %-4s", callsign, ax25_rt->dev ? ax25_rt->dev->name : "???"); switch (ax25_rt->ip_mode) { case 'V': - len += sprintf(buffer + len, " vc"); + seq_puts(seq, " vc"); break; case 'D': - len += sprintf(buffer + len, " dg"); + seq_puts(seq, " dg"); break; default: - len += sprintf(buffer + len, " *"); + seq_puts(seq, " *"); break; } if (ax25_rt->digipeat != NULL) for (i = 0; i < ax25_rt->digipeat->ndigi; i++) - len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i])); - - len += sprintf(buffer + len, "\n"); + seq_printf(seq, " %s", ax2asc(&ax25_rt->digipeat->calls[i])); - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - - if (pos > offset + length) - break; + seq_puts(seq, "\n"); } - read_unlock(&ax25_route_lock); - - *start = buffer + (offset - begin); - len -= (offset - begin); + return 0; +} - if (len > length) - len = length; +static struct seq_operations ax25_rt_seqops = { + .start = ax25_rt_seq_start, + .next = ax25_rt_seq_next, + .stop = ax25_rt_seq_stop, + .show = ax25_rt_seq_show, +}; - return len; +static int ax25_rt_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ax25_rt_seqops); } + +struct file_operations ax25_route_fops = { + .owner = THIS_MODULE, + .open = ax25_rt_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* * Find AX.25 route diff -Nru a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c --- a/net/ax25/ax25_uid.c Fri Aug 22 08:21:10 2003 +++ b/net/ax25/ax25_uid.c Fri Aug 22 08:21:10 2003 @@ -30,6 +30,7 @@ #include <linux/interrupt.h> #include <linux/notifier.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/stat.h> #include <linux/netfilter.h> #include <linux/sysctl.h> @@ -141,39 +142,73 @@ return -EINVAL; /*NOTREACHED */ } -int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length) +#ifdef CONFIG_PROC_FS + +#define AX25_PROC_START ((void *)1) + +static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos) { - ax25_uid_assoc *pt; - int len = 0; - off_t pos = 0; - off_t begin = 0; + struct ax25_uid_assoc *pt; + int i = 1; read_lock(&ax25_uid_lock); - len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy); + if (*pos == 0) + return AX25_PROC_START; for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { - len += sprintf(buffer + len, "%6d %s\n", pt->uid, ax2asc(&pt->call)); - - pos = begin + len; + if (i == *pos) + return pt; + ++i; + } + return NULL; +} - if (pos < offset) { - len = 0; - begin = pos; - } +static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + ++*pos; + return (v == AX25_PROC_START) ? ax25_uid_list : + ((struct ax25_uid_assoc *) v)->next; +} - if (pos > offset + length) - break; - } +static void ax25_uid_seq_stop(struct seq_file *seq, void *v) +{ read_unlock(&ax25_uid_lock); +} + +static int ax25_uid_seq_show(struct seq_file *seq, void *v) +{ + if (v == AX25_PROC_START) + seq_printf(seq, "Policy: %d\n", ax25_uid_policy); + else { + struct ax25_uid_assoc *pt = v; + - *start = buffer + (offset - begin); - len -= offset - begin; + seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(&pt->call)); + } + return 0; +} - if (len > length) - len = length; +static struct seq_operations ax25_uid_seqops = { + .start = ax25_uid_seq_start, + .next = ax25_uid_seq_next, + .stop = ax25_uid_seq_stop, + .show = ax25_uid_seq_show, +}; - return len; +static int ax25_uid_info_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &ax25_uid_seqops); } + +struct file_operations ax25_uid_fops = { + .owner = THIS_MODULE, + .open = ax25_uid_info_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +#endif /* * Free all memory associated with UID/Callsign structures. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFT][PATCH] ax25 using seq_file 2003-08-22 20:15 ` [RFT][PATCH] ax25 using seq_file Stephen Hemminger @ 2003-08-24 11:29 ` David S. Miller 2003-08-24 22:35 ` Jeroen Vreeken 0 siblings, 1 reply; 23+ messages in thread From: David S. Miller @ 2003-08-24 11:29 UTC (permalink / raw) To: Stephen Hemminger; +Cc: pe1rxq, linux-hams, ralf, netdev On Fri, 22 Aug 2003 13:15:47 -0700 Stephen Hemminger <shemminger@osdl.org> wrote: > Convert AX25 to use the seq_file interface for it's /proc hook. > > Jeroen could you test this with real hardware, since without hardware > the table always comes up empty which is not a good enough test. Meanwhile I've applied this. If problems are found you can send me fixes. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [RFT][PATCH] ax25 using seq_file 2003-08-24 11:29 ` David S. Miller @ 2003-08-24 22:35 ` Jeroen Vreeken 0 siblings, 0 replies; 23+ messages in thread From: Jeroen Vreeken @ 2003-08-24 22:35 UTC (permalink / raw) To: David S . Miller; +Cc: Stephen Hemminger, linux-hams, ralf, netdev On 2003.08.24 13:29:11 +0200 David S. Miller wrote: > On Fri, 22 Aug 2003 13:15:47 -0700 > Stephen Hemminger <shemminger@osdl.org> wrote: > > > Convert AX25 to use the seq_file interface for it's /proc hook. > > > > Jeroen could you test this with real hardware, since without hardware > > the table always comes up empty which is not a good enough test. > > Meanwhile I've applied this. If problems are found you can > send me fixes. > No problems so far.... I gave it a try this evening and until now it keeps running fine with the seq_file patches. I can read the /proc files as much as I like with varying connections going on. Jeroen ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ax25 & netrom fixes for 2.6 2003-08-12 21:09 ` Jeroen Vreeken 2003-08-12 22:39 ` [PATCH] ax25 fix for premature free Stephen Hemminger @ 2003-08-13 10:10 ` David S. Miller 1 sibling, 0 replies; 23+ messages in thread From: David S. Miller @ 2003-08-13 10:10 UTC (permalink / raw) To: Jeroen Vreeken; +Cc: shemminger, pe1rxq, linux-hams, ralf, netdev On Tue, 12 Aug 2003 23:09:51 +0200 Jeroen Vreeken <pe1rxq@amsat.org> wrote: > Since at the moment the only zero-copy path I can imagine is from packets > over a bpq ethernet device wouldn't it be the easiest to just check at > ax25_rcv() for non-linear packets and call skb_linearize() for them? skb_linearize() is a deprecated interface, no new pieces of code should use it. If you want to mark the protocol as a new one you must do the non-linear handling properly just like every other protocol. Please, if you're going to be working in this area, fix this up properly and don't paper around the problems Stephen is showing to you. ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2003-08-24 22:35 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2003-08-12 17:46 [PATCH] ax25 & netrom fixes for 2.6 Jeroen Vreeken 2003-08-12 19:48 ` Stephen Hemminger 2003-08-12 20:59 ` Jeroen Vreeken 2003-08-12 20:56 ` Stephen Hemminger 2003-08-12 21:09 ` Jeroen Vreeken 2003-08-12 22:39 ` [PATCH] ax25 fix for premature free Stephen Hemminger 2003-08-12 23:03 ` Jeroen Vreeken 2003-08-12 23:49 ` [PATCH] ax25 use dev_hold/dev_put as required for net_devices Stephen Hemminger 2003-08-13 0:19 ` [PATCH] ax25 setsockopt(SO_BINDTODEVICE) bug fix Stephen Hemminger 2003-08-13 0:21 ` [PATCH] Convert ax25 to seq_file Stephen Hemminger 2003-08-13 10:11 ` David S. Miller 2003-08-13 15:34 ` Jeroen Vreeken 2003-08-13 15:42 ` David S. Miller 2003-08-13 22:35 ` [PATCH] (0/11) Netrom patches Stephen Hemminger 2003-08-15 4:13 ` David S. Miller 2003-08-20 18:45 ` [PATCH] ax25 changes Jeroen Vreeken 2003-08-21 19:18 ` David S. Miller 2003-08-22 20:13 ` [PATCH] ax25 - make sure and hold ref to dev Stephen Hemminger 2003-08-24 11:28 ` David S. Miller 2003-08-22 20:15 ` [RFT][PATCH] ax25 using seq_file Stephen Hemminger 2003-08-24 11:29 ` David S. Miller 2003-08-24 22:35 ` Jeroen Vreeken 2003-08-13 10:10 ` [PATCH] ax25 & netrom fixes for 2.6 David S. Miller
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).