diff -ru linux-2.6.0-test1/net/ax25/af_ax25.c linux-2.5.74.rxq/net/ax25/af_ax25.c --- linux-2.6.0-test1/net/ax25/af_ax25.c 2003-07-14 05:38:01.000000000 +0200 +++ linux-2.5.74.rxq/net/ax25/af_ax25.c 2003-07-17 19:47:32.000000000 +0200 @@ -51,54 +51,61 @@ -ax25_cb *ax25_list; +HLIST_HEAD(ax25_list); spinlock_t ax25_list_lock = SPIN_LOCK_UNLOCKED; +spinlock_t ax25_cb_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) +/* + * Changed name to include undescores. Nobody should call this without + * going through the ref counter anymore + * - PE1RXQ + */ +void __ax25_free_cb(ax25_cb *ax25) { if (ax25->digipeat != NULL) { kfree(ax25->digipeat); ax25->digipeat = NULL; } - kfree(ax25); } +void ax25_cb_hold(ax25_cb *ax25) +{ + spin_lock_bh(&ax25_cb_lock); + ax25->refcount++; + spin_unlock_bh(&ax25_cb_lock); +} + +void ax25_cb_put(ax25_cb *ax25) +{ + spin_lock_bh(&ax25_cb_lock); + ax25->refcount--; + if (!ax25->refcount) + __ax25_free_cb(ax25); + spin_unlock_bh(&ax25_cb_lock); +} + 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,17 +115,17 @@ { 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); } - } spin_unlock_bh(&ax25_list_lock); } @@ -153,11 +160,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 +176,19 @@ 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 +206,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 +233,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 +251,7 @@ if (s->digipeat != NULL && s->digipeat->ndigi != 0) continue; } + ax25_cb_hold(s); spin_unlock_bh(&ax25_list_lock); return s; @@ -257,16 +269,17 @@ { 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; lock_sock(sk); break; } - } + spin_unlock_bh(&ax25_list_lock); return sk; @@ -299,7 +312,14 @@ */ static void ax25_destroy_timer(unsigned long data) { - ax25_destroy_socket((ax25_cb *)data); + ax25_cb *ax25=(ax25_cb *)data; + struct sock *sk=ax25->sk; + + bh_lock_sock(sk); + sock_hold(sk); + ax25_destroy_socket(ax25); + bh_unlock_sock(sk); + sock_put(sk); } /* @@ -312,7 +332,7 @@ { struct sk_buff *skb; - ax25_remove_socket(ax25); + ax25_cb_del(ax25); ax25_stop_heartbeat(ax25); ax25_stop_t1timer(ax25); @@ -337,22 +357,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 { - sk_free(ax25->sk); + struct sock *sk=ax25->sk; + ax25->sk=NULL; + sock_put(sk); } } else { - ax25_free_cb(ax25); + ax25_cb_put(ax25); } } @@ -507,6 +532,7 @@ return NULL; memset(ax25, 0x00, sizeof(*ax25)); + ax25_cb_hold(ax25); skb_queue_head_init(&ax25->write_queue); skb_queue_head_init(&ax25->frag_queue); @@ -877,7 +903,7 @@ break; default: sk_free(sk); - ax25_free_cb(ax25); + ax25_cb_put(ax25); return NULL; } @@ -1076,7 +1102,7 @@ ax25_fillin_cb(ax25, ax25_dev); done: - ax25_insert_socket(ax25); + ax25_cb_add(ax25); sk->sk_zapped = 0; out: @@ -1092,7 +1118,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; @@ -1198,7 +1224,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; @@ -1207,11 +1233,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; } @@ -1272,6 +1299,8 @@ lock_sock(sk); continue; } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sk_sleep, &wait); return -ERESTARTSYS; } current->state = TASK_RUNNING; @@ -1339,6 +1368,8 @@ lock_sock(sk); continue; } + current->state = TASK_RUNNING; + remove_wait_queue(sk->sk_sleep, &wait); return -ERESTARTSYS; } current->state = TASK_RUNNING; @@ -1518,7 +1549,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) @@ -1844,6 +1875,7 @@ int len = 0; off_t pos = 0; off_t begin = 0; + struct hlist_node *node; spin_lock_bh(&ax25_list_lock); @@ -1852,7 +1884,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, @@ -1955,6 +1987,8 @@ EXPORT_SYMBOL(ax25_rebuild_header); EXPORT_SYMBOL(ax25_findbyuid); EXPORT_SYMBOL(ax25_find_cb); +EXPORT_SYMBOL(ax25_cb_hold); +EXPORT_SYMBOL(ax25_cb_put); EXPORT_SYMBOL(ax25_linkfail_register); EXPORT_SYMBOL(ax25_linkfail_release); EXPORT_SYMBOL(ax25_listen_register); diff -ru linux-2.6.0-test1/net/ax25/ax25_ds_subr.c linux-2.5.74.rxq/net/ax25/ax25_ds_subr.c --- linux-2.6.0-test1/net/ax25/ax25_ds_subr.c 2003-07-14 05:38:05.000000000 +0200 +++ linux-2.5.74.rxq/net/ax25/ax25_ds_subr.c 2003-07-17 19:47:34.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-test1/net/ax25/ax25_ds_timer.c linux-2.5.74.rxq/net/ax25/ax25_ds_timer.c --- linux-2.6.0-test1/net/ax25/ax25_ds_timer.c 2003-07-14 05:38:01.000000000 +0200 +++ linux-2.5.74.rxq/net/ax25/ax25_ds_timer.c 2003-07-17 19:47:32.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); } diff -ru linux-2.6.0-test1/net/ax25/ax25_in.c linux-2.5.74.rxq/net/ax25/ax25_in.c --- linux-2.6.0-test1/net/ax25/ax25_in.c 2003-07-14 05:30:48.000000000 +0200 +++ linux-2.5.74.rxq/net/ax25/ax25_in.c 2003-07-17 19:47:31.000000000 +0200 @@ -329,6 +329,7 @@ if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) kfree_skb(skb); + ax25_cb_put(ax25); return 0; } @@ -357,11 +358,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 +378,8 @@ make->sk_pair = sk; sk->sk_ack_backlog++; + bh_unlock_sock(sk); + sock_put(sk); } else { if (!mine) { kfree_skb(skb); @@ -429,7 +435,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-test1/net/ax25/ax25_ip.c linux-2.5.74.rxq/net/ax25/ax25_ip.c --- linux-2.6.0-test1/net/ax25/ax25_ip.c 2003-07-14 05:32:42.000000000 +0200 +++ linux-2.5.74.rxq/net/ax25/ax25_ip.c 2003-07-17 19:47:31.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-test1/net/ax25/ax25_out.c linux-2.5.74.rxq/net/ax25/ax25_out.c --- linux-2.6.0-test1/net/ax25/ax25_out.c 2003-07-14 05:37:22.000000000 +0200 +++ linux-2.5.74.rxq/net/ax25/ax25_out.c 2003-07-17 19:47:34.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-test1/net/ax25/ax25_route.c linux-2.5.74.rxq/net/ax25/ax25_route.c --- linux-2.6.0-test1/net/ax25/ax25_route.c 2003-07-14 05:36:31.000000000 +0200 +++ linux-2.5.74.rxq/net/ax25/ax25_route.c 2003-07-17 19:47:34.000000000 +0200 @@ -162,6 +162,7 @@ if (ax25_rt->digipeat != NULL) kfree(ax25_rt->digipeat); kfree(ax25_rt); + return; } /* diff -ru linux-2.6.0-test1/net/ax25/ax25_std_timer.c linux-2.5.74.rxq/net/ax25/ax25_std_timer.c --- linux-2.6.0-test1/net/ax25/ax25_std_timer.c 2003-07-14 05:32:29.000000000 +0200 +++ linux-2.5.74.rxq/net/ax25/ax25_std_timer.c 2003-07-17 19:47:33.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); } diff -ru linux-2.6.0-test1/net/ax25/ax25_subr.c linux-2.5.74.rxq/net/ax25/ax25_subr.c --- linux-2.6.0-test1/net/ax25/ax25_subr.c 2003-07-14 05:38:06.000000000 +0200 +++ linux-2.5.74.rxq/net/ax25/ax25_subr.c 2003-07-17 19:47:31.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); --- linux-2.6.0-test1/include/net/ax25.h 2003-07-14 05:35:55.000000000 +0200 +++ linux-2.5.74.rxq/include/net/ax25.h 2003-07-17 20:02:28.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,22 @@ 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 */ + int 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) + /* 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_hold(ax25_cb *); +extern void ax25_cb_put(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 *); diff -ru linux-2.6.0-test1/drivers/net/hamradio/mkiss.c linux-2.5.74.rxq/drivers/net/hamradio/mkiss.c --- linux-2.6.0-test1/drivers/net/hamradio/mkiss.c 2003-07-14 05:38:46.000000000 +0200 +++ linux-2.5.74.rxq/drivers/net/hamradio/mkiss.c 2003-07-17 19:55:27.000000000 +0200 @@ -165,19 +165,20 @@ return NULL; /* If no channels are available, allocate one */ - if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) { + if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) axp = ax25_ctrls[i]; - memset(axp, 0, sizeof(ax25_ctrl_t)); - - /* Initialize channel control data */ - set_bit(AXF_INUSE, &axp->ctrl.flags); - sprintf(axp->dev.name, "ax%d", i++); - axp->ctrl.tty = NULL; - axp->dev.base_addr = i; - axp->dev.priv = (void *)&axp->ctrl; - axp->dev.next = NULL; - axp->dev.init = ax25_init; - } + /* Also initialize an existing channel as register_netdevice doesn't + like already initialized devices... (PE1RXQ) */ + memset(axp, 0, sizeof(ax25_ctrl_t)); + + /* Initialize channel control data */ + set_bit(AXF_INUSE, &axp->ctrl.flags); + sprintf(axp->dev.name, "ax%d", i++); + axp->ctrl.tty = NULL; + axp->dev.base_addr = i; + axp->dev.priv = (void *)&axp->ctrl; + axp->dev.next = NULL; + axp->dev.init = ax25_init; if (axp != NULL) { /*