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 #include -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 #include #include +#include #include #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 +#include #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;