Commit 0dfe6e55 authored by Ralf Bächle's avatar Ralf Bächle

Resolve merge conflicts.

parents 35aa61ec e39aa73c
...@@ -3,11 +3,14 @@ ...@@ -3,11 +3,14 @@
* *
* Alan Cox (GW4PTS) 10/11/93 * Alan Cox (GW4PTS) 10/11/93
*/ */
#ifndef _AX25_H #ifndef _AX25_H
#define _AX25_H #define _AX25_H
#include <linux/config.h> #include <linux/config.h>
#include <linux/ax25.h> #include <linux/ax25.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <asm/atomic.h>
#define AX25_T1CLAMPLO 1 #define AX25_T1CLAMPLO 1
#define AX25_T1CLAMPHI (30 * HZ) #define AX25_T1CLAMPHI (30 * HZ)
...@@ -147,10 +150,12 @@ typedef struct { ...@@ -147,10 +150,12 @@ typedef struct {
typedef struct ax25_route { typedef struct ax25_route {
struct ax25_route *next; struct ax25_route *next;
atomic_t ref;
ax25_address callsign; ax25_address callsign;
struct net_device *dev; struct net_device *dev;
ax25_digi *digipeat; ax25_digi *digipeat;
char ip_mode; char ip_mode;
struct timer_list timer;
} ax25_route; } ax25_route;
typedef struct { typedef struct {
...@@ -197,7 +202,8 @@ typedef struct ax25_cb { ...@@ -197,7 +202,8 @@ typedef struct ax25_cb {
#define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo) #define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo)
/* af_ax25.c */ /* af_ax25.c */
extern ax25_cb *volatile ax25_list; extern ax25_cb *ax25_list;
extern spinlock_t ax25_list_lock;
extern void ax25_free_cb(ax25_cb *); extern void ax25_free_cb(ax25_cb *);
extern void ax25_insert_socket(ax25_cb *); extern void ax25_insert_socket(ax25_cb *);
struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int); struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int);
...@@ -224,6 +230,7 @@ extern void ax25_digi_invert(ax25_digi *, ax25_digi *); ...@@ -224,6 +230,7 @@ extern void ax25_digi_invert(ax25_digi *, ax25_digi *);
/* ax25_dev.c */ /* ax25_dev.c */
extern ax25_dev *ax25_dev_list; extern ax25_dev *ax25_dev_list;
extern spinlock_t ax25_dev_lock;
extern ax25_dev *ax25_dev_ax25dev(struct net_device *); extern ax25_dev *ax25_dev_ax25dev(struct net_device *);
extern ax25_dev *ax25_addr_ax25dev(ax25_address *); extern ax25_dev *ax25_addr_ax25dev(ax25_address *);
extern void ax25_dev_device_up(struct net_device *); extern void ax25_dev_device_up(struct net_device *);
...@@ -286,7 +293,8 @@ extern void ax25_rt_device_down(struct net_device *); ...@@ -286,7 +293,8 @@ extern void ax25_rt_device_down(struct net_device *);
extern int ax25_rt_ioctl(unsigned int, void *); extern int ax25_rt_ioctl(unsigned int, void *);
extern int ax25_rt_get_info(char *, char **, off_t, int); extern int ax25_rt_get_info(char *, char **, off_t, int);
extern int ax25_rt_autobind(ax25_cb *, ax25_address *); extern int ax25_rt_autobind(ax25_cb *, ax25_address *);
extern ax25_route *ax25_rt_find_route(ax25_address *, struct net_device *); extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *,
struct net_device *);
extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *); extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *);
extern void ax25_rt_free(void); extern void ax25_rt_free(void);
......
af_ax25.c:ax25_connect:
There is a race with changing the socket state here which should be
fixed by introduction of proper socket locking:
if (sk->state != TCP_ESTABLISHED) {
/* Not in ABM, not in WAIT_UA -> failed */
sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */
}
Do the ax25_list_lock, ax25_uid_lock, ax25_route_lock, protocol_list_lock,
ax25_dev_lock, linkfail_lockreally, ax25_frag_lock and listen_lock have to
be interrupt safe?
This diff is collapsed.
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h> #include <net/ax25.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -41,27 +42,37 @@ ...@@ -41,27 +42,37 @@
#include <linux/init.h> #include <linux/init.h>
ax25_dev *ax25_dev_list; ax25_dev *ax25_dev_list;
spinlock_t ax25_dev_lock = SPIN_LOCK_UNLOCKED;
ax25_dev *ax25_dev_ax25dev(struct net_device *dev) ax25_dev *ax25_dev_ax25dev(struct net_device *dev)
{ {
ax25_dev *ax25_dev; ax25_dev *ax25_dev, *res = NULL;
unsigned long flags;
spin_lock_irqsave(&ax25_dev_lock, flags);
for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
if (ax25_dev->dev == dev) if (ax25_dev->dev == dev) {
return ax25_dev; res = ax25_dev;
break;
}
spin_unlock_irqrestore(&ax25_dev_lock, flags);
return NULL; return res;
} }
ax25_dev *ax25_addr_ax25dev(ax25_address *addr) ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
{ {
ax25_dev *ax25_dev; ax25_dev *ax25_dev, *res = NULL;
unsigned long flags;
spin_lock_irqsave(&ax25_dev_lock, flags);
for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) {
return ax25_dev; res = ax25_dev;
}
spin_unlock_irqrestore(&ax25_dev_lock, flags);
return NULL; return res;
} }
/* /*
...@@ -100,10 +111,10 @@ void ax25_dev_device_up(struct net_device *dev) ...@@ -100,10 +111,10 @@ void ax25_dev_device_up(struct net_device *dev)
ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL; ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL;
ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT; ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT;
save_flags(flags); cli(); spin_lock_irqsave(&ax25_dev_lock, flags);
ax25_dev->next = ax25_dev_list; ax25_dev->next = ax25_dev_list;
ax25_dev_list = ax25_dev; ax25_dev_list = ax25_dev;
restore_flags(flags); spin_unlock_irqrestore(&ax25_dev_lock, flags);
ax25_register_sysctl(); ax25_register_sysctl();
} }
...@@ -118,7 +129,7 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -118,7 +129,7 @@ void ax25_dev_device_down(struct net_device *dev)
ax25_unregister_sysctl(); ax25_unregister_sysctl();
save_flags(flags); cli(); spin_lock_irqsave(&ax25_dev_lock, flags);
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
ax25_ds_del_timer(ax25_dev); ax25_ds_del_timer(ax25_dev);
...@@ -133,7 +144,7 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -133,7 +144,7 @@ void ax25_dev_device_down(struct net_device *dev)
if ((s = ax25_dev_list) == ax25_dev) { if ((s = ax25_dev_list) == ax25_dev) {
ax25_dev_list = s->next; ax25_dev_list = s->next;
restore_flags(flags); spin_unlock_irqrestore(&ax25_dev_lock, flags);
kfree(ax25_dev); kfree(ax25_dev);
ax25_register_sysctl(); ax25_register_sysctl();
return; return;
...@@ -142,7 +153,7 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -142,7 +153,7 @@ void ax25_dev_device_down(struct net_device *dev)
while (s != NULL && s->next != NULL) { while (s != NULL && s->next != NULL) {
if (s->next == ax25_dev) { if (s->next == ax25_dev) {
s->next = ax25_dev->next; s->next = ax25_dev->next;
restore_flags(flags); spin_unlock_irqrestore(&ax25_dev_lock, flags);
kfree(ax25_dev); kfree(ax25_dev);
ax25_register_sysctl(); ax25_register_sysctl();
return; return;
...@@ -150,8 +161,8 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -150,8 +161,8 @@ void ax25_dev_device_down(struct net_device *dev)
s = s->next; s = s->next;
} }
spin_unlock_irqrestore(&ax25_dev_lock, flags);
restore_flags(flags);
ax25_register_sysctl(); ax25_register_sysctl();
} }
...@@ -163,22 +174,22 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd) ...@@ -163,22 +174,22 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
return -EINVAL; return -EINVAL;
switch (cmd) { switch (cmd) {
case SIOCAX25ADDFWD: case SIOCAX25ADDFWD:
if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL) if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
return -EINVAL; return -EINVAL;
if (ax25_dev->forward != NULL) if (ax25_dev->forward != NULL)
return -EINVAL; return -EINVAL;
ax25_dev->forward = fwd_dev->dev; ax25_dev->forward = fwd_dev->dev;
break; break;
case SIOCAX25DELFWD:
if (ax25_dev->forward == NULL)
return -EINVAL;
ax25_dev->forward = NULL;
break;
default: case SIOCAX25DELFWD:
if (ax25_dev->forward == NULL)
return -EINVAL; return -EINVAL;
ax25_dev->forward = NULL;
break;
default:
return -EINVAL;
} }
return 0; return 0;
...@@ -202,12 +213,17 @@ struct net_device *ax25_fwd_dev(struct net_device *dev) ...@@ -202,12 +213,17 @@ struct net_device *ax25_fwd_dev(struct net_device *dev)
*/ */
void __exit ax25_dev_free(void) void __exit ax25_dev_free(void)
{ {
ax25_dev *s, *ax25_dev = ax25_dev_list; ax25_dev *s, *ax25_dev;
unsigned long flags;
spin_lock_irqsave(&ax25_dev_lock, flags);
ax25_dev = ax25_dev_list;
while (ax25_dev != NULL) { while (ax25_dev != NULL) {
s = ax25_dev; s = ax25_dev;
ax25_dev = ax25_dev->next; ax25_dev = ax25_dev->next;
kfree(s); kfree(s);
} }
ax25_dev_list = NULL;
spin_unlock_irqrestore(&ax25_dev_lock, flags);
} }
This diff is collapsed.
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h> #include <linux/net.h>
#include <net/ax25.h> #include <net/ax25.h>
#include <linux/inet.h> #include <linux/inet.h>
...@@ -53,6 +54,7 @@ void ax25_ds_nr_error_recovery(ax25_cb *ax25) ...@@ -53,6 +54,7 @@ void ax25_ds_nr_error_recovery(ax25_cb *ax25)
*/ */
void ax25_ds_enquiry_response(ax25_cb *ax25) void ax25_ds_enquiry_response(ax25_cb *ax25)
{ {
unsigned long flags;
ax25_cb *ax25o; ax25_cb *ax25o;
/* Please note that neither DK4EGs nor DG2FEFs /* Please note that neither DK4EGs nor DG2FEFs
...@@ -93,6 +95,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25) ...@@ -93,6 +95,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
ax25_start_t3timer(ax25); ax25_start_t3timer(ax25);
ax25_ds_set_timer(ax25->ax25_dev); ax25_ds_set_timer(ax25->ax25_dev);
spin_lock_irqsave(&ax25_list_lock, flags);
for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) { for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
if (ax25o == ax25) if (ax25o == ax25)
continue; continue;
...@@ -118,6 +121,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25) ...@@ -118,6 +121,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
if (ax25o->state != AX25_STATE_0) if (ax25o->state != AX25_STATE_0)
ax25_start_t3timer(ax25o); ax25_start_t3timer(ax25o);
} }
spin_unlock_irqrestore(&ax25_list_lock, flags);
} }
void ax25_ds_establish_data_link(ax25_cb *ax25) void ax25_ds_establish_data_link(ax25_cb *ax25)
...@@ -170,13 +174,19 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p ...@@ -170,13 +174,19 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p
*/ */
static int ax25_check_dama_slave(ax25_dev *ax25_dev) static int ax25_check_dama_slave(ax25_dev *ax25_dev)
{ {
unsigned long flags;
ax25_cb *ax25; ax25_cb *ax25;
int res = 0;
spin_lock_irqsave(&ax25_list_lock, flags);
for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next) for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next)
if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) {
return 1; res = 1;
break;
}
spin_unlock_irqrestore(&ax25_list_lock, flags);
return 0; return res;
} }
void ax25_dev_dama_on(ax25_dev *ax25_dev) void ax25_dev_dama_on(ax25_dev *ax25_dev)
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/spinlock.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
...@@ -58,7 +59,8 @@ static void ax25_ds_add_timer(ax25_dev *ax25_dev) ...@@ -58,7 +59,8 @@ static void ax25_ds_add_timer(ax25_dev *ax25_dev)
void ax25_ds_del_timer(ax25_dev *ax25_dev) void ax25_ds_del_timer(ax25_dev *ax25_dev)
{ {
if (ax25_dev) del_timer(&ax25_dev->dama.slave_timer); if (ax25_dev)
del_timer(&ax25_dev->dama.slave_timer);
} }
void ax25_ds_set_timer(ax25_dev *ax25_dev) void ax25_ds_set_timer(ax25_dev *ax25_dev)
...@@ -79,6 +81,7 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev) ...@@ -79,6 +81,7 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev)
static void ax25_ds_timeout(unsigned long arg) static void ax25_ds_timeout(unsigned long arg)
{ {
ax25_dev *ax25_dev = (struct ax25_dev *) arg; ax25_dev *ax25_dev = (struct ax25_dev *) arg;
unsigned long flags;
ax25_cb *ax25; ax25_cb *ax25;
if (ax25_dev == NULL || !ax25_dev->dama.slave) if (ax25_dev == NULL || !ax25_dev->dama.slave)
...@@ -89,6 +92,7 @@ static void ax25_ds_timeout(unsigned long arg) ...@@ -89,6 +92,7 @@ static void ax25_ds_timeout(unsigned long arg)
return; return;
} }
spin_lock_irqsave(&ax25_list_lock, flags);
for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) { for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) {
if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE)) if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
continue; continue;
...@@ -96,6 +100,7 @@ static void ax25_ds_timeout(unsigned long arg) ...@@ -96,6 +100,7 @@ static void ax25_ds_timeout(unsigned long arg)
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT); ax25_disconnect(ax25, ETIMEDOUT);
} }
spin_unlock_irqrestore(&ax25_list_lock, flags);
ax25_dev_dama_off(ax25_dev); ax25_dev_dama_off(ax25_dev);
} }
...@@ -104,28 +109,28 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25) ...@@ -104,28 +109,28 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_0: case AX25_STATE_0:
/* Magic here: If we listen() and a new link dies before it /* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */ is accepted() it isn't 'dead' so doesn't get removed. */
if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
ax25_destroy_socket(ax25); ax25_destroy_socket(ax25);
return; return;
} }
break; break;
case AX25_STATE_3: case AX25_STATE_3:
/* /*
* Check the state of the receive buffer. * Check the state of the receive buffer.
*/ */
if (ax25->sk != NULL) { if (ax25->sk != NULL) {
if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
(ax25->condition & AX25_COND_OWN_RX_BUSY)) { (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
ax25->condition &= ~AX25_COND_OWN_RX_BUSY; ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
ax25->condition &= ~AX25_COND_ACK_PENDING; ax25->condition &= ~AX25_COND_ACK_PENDING;
break; break;
}
} }
break; }
break;
} }
ax25_start_heartbeat(ax25); ax25_start_heartbeat(ax25);
...@@ -178,46 +183,45 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25) ...@@ -178,46 +183,45 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
void ax25_ds_t1_timeout(ax25_cb *ax25) void ax25_ds_t1_timeout(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_1:
case AX25_STATE_1: if (ax25->n2count == ax25->n2) {
if (ax25->n2count == ax25->n2) { if (ax25->modulus == AX25_MODULUS) {
if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25->n2count = 0;
ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
}
} else {
ax25->n2count++;
if (ax25->modulus == AX25_MODULUS)
ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
else
ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
}
break;
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
}
break;
case AX25_STATE_3:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
ax25_disconnect(ax25, ETIMEDOUT); ax25_disconnect(ax25, ETIMEDOUT);
return; return;
} else { } else {
ax25->n2count++; ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25->n2count = 0;
ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
} }
break; } else {
ax25->n2count++;
if (ax25->modulus == AX25_MODULUS)
ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
else
ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
}
break;
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
}
break;
case AX25_STATE_3:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
}
break;
} }
ax25_calculate_t1(ax25); ax25_calculate_t1(ax25);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/in.h> #include <linux/in.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
...@@ -40,22 +41,25 @@ static struct protocol_struct { ...@@ -40,22 +41,25 @@ static struct protocol_struct {
unsigned int pid; unsigned int pid;
int (*func)(struct sk_buff *, ax25_cb *); int (*func)(struct sk_buff *, ax25_cb *);
} *protocol_list; } *protocol_list;
static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED;
static struct linkfail_struct { static struct linkfail_struct {
struct linkfail_struct *next; struct linkfail_struct *next;
void (*func)(ax25_cb *, int); void (*func)(ax25_cb *, int);
} *linkfail_list; } *linkfail_list;
static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED;
static struct listen_struct { static struct listen_struct {
struct listen_struct *next; struct listen_struct *next;
ax25_address callsign; ax25_address callsign;
struct net_device *dev; struct net_device *dev;
} *listen_list; } *listen_list;
static spinlock_t listen_lock = SPIN_LOCK_UNLOCKED;
int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_cb *)) int ax25_protocol_register(unsigned int pid,
int (*func)(struct sk_buff *, ax25_cb *))
{ {
struct protocol_struct *protocol; struct protocol_struct *protocol;
unsigned long flags;
if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT) if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT)
return 0; return 0;
...@@ -69,31 +73,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_ ...@@ -69,31 +73,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_
protocol->pid = pid; protocol->pid = pid;
protocol->func = func; protocol->func = func;
save_flags(flags); write_lock(&protocol_list_lock);
cli();
protocol->next = protocol_list; protocol->next = protocol_list;
protocol_list = protocol; protocol_list = protocol;
write_unlock(&protocol_list_lock);
restore_flags(flags);
return 1; return 1;
} }
void ax25_protocol_release(unsigned int pid) void ax25_protocol_release(unsigned int pid)
{ {
struct protocol_struct *s, *protocol = protocol_list; struct protocol_struct *s, *protocol;
unsigned long flags;
if (protocol == NULL) write_lock(&protocol_list_lock);
protocol = protocol_list;
if (protocol == NULL) {
write_unlock(&protocol_list_lock);
return; return;
}
save_flags(flags);
cli();
if (protocol->pid == pid) { if (protocol->pid == pid) {
protocol_list = protocol->next; protocol_list = protocol->next;
restore_flags(flags); write_unlock(&protocol_list_lock);
kfree(protocol); kfree(protocol);
return; return;
} }
...@@ -102,15 +103,14 @@ void ax25_protocol_release(unsigned int pid) ...@@ -102,15 +103,14 @@ void ax25_protocol_release(unsigned int pid)
if (protocol->next->pid == pid) { if (protocol->next->pid == pid) {
s = protocol->next; s = protocol->next;
protocol->next = protocol->next->next; protocol->next = protocol->next->next;
restore_flags(flags); write_unlock(&protocol_list_lock);
kfree(s); kfree(s);
return; return;
} }
protocol = protocol->next; protocol = protocol->next;
} }
write_unlock(&protocol_list_lock);
restore_flags(flags);
} }
int ax25_linkfail_register(void (*func)(ax25_cb *, int)) int ax25_linkfail_register(void (*func)(ax25_cb *, int))
...@@ -123,31 +123,27 @@ int ax25_linkfail_register(void (*func)(ax25_cb *, int)) ...@@ -123,31 +123,27 @@ int ax25_linkfail_register(void (*func)(ax25_cb *, int))
linkfail->func = func; linkfail->func = func;
save_flags(flags); spin_lock_irqsave(&linkfail_lock, flags);
cli();
linkfail->next = linkfail_list; linkfail->next = linkfail_list;
linkfail_list = linkfail; linkfail_list = linkfail;
spin_unlock_irqrestore(&linkfail_lock, flags);
restore_flags(flags);
return 1; return 1;
} }
void ax25_linkfail_release(void (*func)(ax25_cb *, int)) void ax25_linkfail_release(void (*func)(ax25_cb *, int))
{ {
struct linkfail_struct *s, *linkfail = linkfail_list; struct linkfail_struct *s, *linkfail;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&linkfail_lock, flags);
linkfail = linkfail_list;
if (linkfail == NULL) if (linkfail == NULL)
return; return;
save_flags(flags);
cli();
if (linkfail->func == func) { if (linkfail->func == func) {
linkfail_list = linkfail->next; linkfail_list = linkfail->next;
restore_flags(flags); spin_unlock_irqrestore(&linkfail_lock, flags);
kfree(linkfail); kfree(linkfail);
return; return;
} }
...@@ -156,15 +152,14 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int)) ...@@ -156,15 +152,14 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int))
if (linkfail->next->func == func) { if (linkfail->next->func == func) {
s = linkfail->next; s = linkfail->next;
linkfail->next = linkfail->next->next; linkfail->next = linkfail->next->next;
restore_flags(flags); spin_unlock_irqrestore(&linkfail_lock, flags);
kfree(s); kfree(s);
return; return;
} }
linkfail = linkfail->next; linkfail = linkfail->next;
} }
spin_unlock_irqrestore(&linkfail_lock, flags);
restore_flags(flags);
} }
int ax25_listen_register(ax25_address *callsign, struct net_device *dev) int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
...@@ -181,31 +176,27 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev) ...@@ -181,31 +176,27 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
listen->callsign = *callsign; listen->callsign = *callsign;
listen->dev = dev; listen->dev = dev;
save_flags(flags); spin_lock_irqsave(&listen_lock, flags);
cli();
listen->next = listen_list; listen->next = listen_list;
listen_list = listen; listen_list = listen;
spin_unlock_irqrestore(&listen_lock, flags);
restore_flags(flags);
return 1; return 1;
} }
void ax25_listen_release(ax25_address *callsign, struct net_device *dev) void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
{ {
struct listen_struct *s, *listen = listen_list; struct listen_struct *s, *listen;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&listen_lock, flags);
listen = listen_list;
if (listen == NULL) if (listen == NULL)
return; return;
save_flags(flags);
cli();
if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
listen_list = listen->next; listen_list = listen->next;
restore_flags(flags); spin_unlock_irqrestore(&listen_lock, flags);
kfree(listen); kfree(listen);
return; return;
} }
...@@ -214,35 +205,42 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev) ...@@ -214,35 +205,42 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) { if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) {
s = listen->next; s = listen->next;
listen->next = listen->next->next; listen->next = listen->next->next;
restore_flags(flags); spin_unlock_irqrestore(&listen_lock, flags);
kfree(s); kfree(s);
return; return;
} }
listen = listen->next; listen = listen->next;
} }
spin_unlock_irqrestore(&listen_lock, flags);
restore_flags(flags);
} }
int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
{ {
int (*res)(struct sk_buff *, ax25_cb *) = NULL;
struct protocol_struct *protocol; struct protocol_struct *protocol;
read_lock(&protocol_list_lock);
for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
if (protocol->pid == pid) if (protocol->pid == pid) {
return protocol->func; res = protocol->func;
break;
}
read_unlock(&protocol_list_lock);
return NULL; return res;
} }
int ax25_listen_mine(ax25_address *callsign, struct net_device *dev) int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
{ {
struct listen_struct *listen; struct listen_struct *listen;
unsigned long flags;
spin_lock_irqsave(&listen_lock, flags);
for (listen = listen_list; listen != NULL; listen = listen->next) 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))
return 1; return 1;
spin_unlock_irqrestore(&listen_lock, flags);
return 0; return 0;
} }
...@@ -250,19 +248,26 @@ int ax25_listen_mine(ax25_address *callsign, struct net_device *dev) ...@@ -250,19 +248,26 @@ int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
void ax25_link_failed(ax25_cb *ax25, int reason) void ax25_link_failed(ax25_cb *ax25, int reason)
{ {
struct linkfail_struct *linkfail; struct linkfail_struct *linkfail;
unsigned long flags;
spin_lock_irqsave(&linkfail_lock, flags);
for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next) for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
(linkfail->func)(ax25, reason); (linkfail->func)(ax25, reason);
spin_unlock_irqrestore(&linkfail_lock, flags);
} }
int ax25_protocol_is_registered(unsigned int pid) int ax25_protocol_is_registered(unsigned int pid)
{ {
struct protocol_struct *protocol; struct protocol_struct *protocol;
int res = 0;
read_lock(&protocol_list_lock);
for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
if (protocol->pid == pid) if (protocol->pid == pid) {
return 1; res = 1;
break;
}
read_unlock(&protocol_list_lock);
return 0; return res;
} }
...@@ -199,25 +199,26 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i ...@@ -199,25 +199,26 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
return 0; return 0;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
queued = ax25_std_frame_in(ax25, skb, type); queued = ax25_std_frame_in(ax25, skb, type);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (dama || ax25->ax25_dev->dama.slave) if (dama || ax25->ax25_dev->dama.slave)
queued = ax25_ds_frame_in(ax25, skb, type); queued = ax25_ds_frame_in(ax25, skb, type);
else else
queued = ax25_std_frame_in(ax25, skb, type); queued = ax25_std_frame_in(ax25, skb, type);
break; break;
#endif #endif
} }
return queued; return queued;
} }
static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *dev_addr, struct packet_type *ptype) static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
ax25_address *dev_addr, struct packet_type *ptype)
{ {
struct sock *make; struct sock *make;
struct sock *sk; struct sock *sk;
...@@ -285,47 +286,47 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d ...@@ -285,47 +286,47 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
/* Now we are pointing at the pid byte */ /* Now we are pointing at the pid byte */
switch (skb->data[1]) { switch (skb->data[1]) {
#ifdef CONFIG_INET #ifdef CONFIG_INET
case AX25_P_IP: case AX25_P_IP:
skb_pull(skb,2); /* drop PID/CTRL */ skb_pull(skb,2); /* drop PID/CTRL */
skb->h.raw = skb->data; skb->h.raw = skb->data;
skb->nh.raw = skb->data; skb->nh.raw = skb->data;
skb->dev = dev; skb->dev = dev;
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */
break; break;
case AX25_P_ARP: case AX25_P_ARP:
skb_pull(skb,2); skb_pull(skb,2);
skb->h.raw = skb->data; skb->h.raw = skb->data;
skb->nh.raw = skb->data; skb->nh.raw = skb->data;
skb->dev = dev; skb->dev = dev;
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
skb->protocol = htons(ETH_P_ARP); skb->protocol = htons(ETH_P_ARP);
arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */
break; break;
#endif #endif
case AX25_P_TEXT: case AX25_P_TEXT:
/* Now find a suitable dgram socket */ /* Now find a suitable dgram socket */
if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) { if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) {
if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) { if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) {
kfree_skb(skb);
} else {
/*
* Remove the control and PID.
*/
skb_pull(skb, 2);
if (sock_queue_rcv_skb(sk, skb) != 0)
kfree_skb(skb);
}
} else {
kfree_skb(skb); kfree_skb(skb);
} else {
/*
* Remove the control and PID.
*/
skb_pull(skb, 2);
if (sock_queue_rcv_skb(sk, skb) != 0)
kfree_skb(skb);
} }
break; } else {
kfree_skb(skb);
}
break;
default: default:
kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */ kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */
break; break;
} }
return 0; return 0;
...@@ -486,4 +487,3 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -486,4 +487,3 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev,
return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype); return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype);
} }
...@@ -88,16 +88,16 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short ...@@ -88,16 +88,16 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short
/* Append a suitable AX.25 PID */ /* Append a suitable AX.25 PID */
switch (type) { switch (type) {
case ETH_P_IP: case ETH_P_IP:
*buff++ = AX25_P_IP; *buff++ = AX25_P_IP;
break; break;
case ETH_P_ARP: case ETH_P_ARP:
*buff++ = AX25_P_ARP; *buff++ = AX25_P_ARP;
break; break;
default: default:
printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type); printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
*buff++ = 0; *buff++ = 0;
break; break;
} }
if (daddr != NULL) if (daddr != NULL)
...@@ -112,8 +112,8 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -112,8 +112,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
unsigned char *bp = skb->data; unsigned char *bp = skb->data;
struct net_device *dev; struct net_device *dev;
ax25_address *src, *dst; ax25_address *src, *dst;
ax25_route *route;
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
ax25_route _route, *route = &_route;
dst = (ax25_address *)(bp + 1); dst = (ax25_address *)(bp + 1);
src = (ax25_address *)(bp + 8); src = (ax25_address *)(bp + 8);
...@@ -121,14 +121,15 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -121,14 +121,15 @@ int ax25_rebuild_header(struct sk_buff *skb)
if (arp_find(bp + 1, skb)) if (arp_find(bp + 1, skb))
return 1; return 1;
route = ax25_rt_find_route(dst, NULL); route = ax25_rt_find_route(route, dst, NULL);
dev = route->dev; dev = route->dev;
if (dev == NULL) if (dev == NULL)
dev = skb->dev; dev = skb->dev;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
return 1; goto put;
}
if (bp[16] == AX25_P_IP) { if (bp[16] == AX25_P_IP) {
if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
...@@ -153,7 +154,7 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -153,7 +154,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) { if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
kfree_skb(skb); kfree_skb(skb);
return 1; goto put;
} }
if (skb->sk != NULL) if (skb->sk != NULL)
...@@ -170,7 +171,7 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -170,7 +171,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c, ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c,
&dst_c, route->digipeat, dev); &dst_c, route->digipeat, dev);
return 1; goto put;
} }
} }
...@@ -187,7 +188,7 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -187,7 +188,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if (route->digipeat != NULL) { if (route->digipeat != NULL) {
if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) { if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
kfree_skb(skb); kfree_skb(skb);
return 1; goto put;
} }
skb = ourskb; skb = ourskb;
...@@ -197,6 +198,9 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -197,6 +198,9 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_queue_xmit(skb); ax25_queue_xmit(skb);
put:
ax25_put_route(route);
return 1; return 1;
} }
......
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h> #include <linux/net.h>
#include <net/ax25.h> #include <net/ax25.h>
#include <linux/inet.h> #include <linux/inet.h>
...@@ -57,6 +58,8 @@ ...@@ -57,6 +58,8 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
static spinlock_t ax25_frag_lock = SPIN_LOCK_UNLOCKED;
ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev) ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev)
{ {
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
...@@ -101,18 +104,18 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2 ...@@ -101,18 +104,18 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
} }
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_std_establish_data_link(ax25); ax25_std_establish_data_link(ax25);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (ax25_dev->dama.slave) if (ax25_dev->dama.slave)
ax25_ds_establish_data_link(ax25); ax25_ds_establish_data_link(ax25);
else else
ax25_std_establish_data_link(ax25); ax25_std_establish_data_link(ax25);
break; break;
#endif #endif
} }
...@@ -155,11 +158,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) ...@@ -155,11 +158,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
frontlen = skb_headroom(skb); /* Address space + CTRL */ frontlen = skb_headroom(skb); /* Address space + CTRL */
while (skb->len > 0) { while (skb->len > 0) {
save_flags(flags); spin_lock_irqsave(&ax25_frag_lock, flags);
cli();
if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) { if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) {
restore_flags(flags); spin_unlock_irqrestore(&ax25_frag_lock, flags);
printk(KERN_CRIT "AX.25: ax25_output - out of memory\n"); printk(KERN_CRIT "AX.25: ax25_output - out of memory\n");
return; return;
} }
...@@ -167,7 +168,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) ...@@ -167,7 +168,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
if (skb->sk != NULL) if (skb->sk != NULL)
skb_set_owner_w(skbn, skb->sk); skb_set_owner_w(skbn, skb->sk);
restore_flags(flags); spin_unlock_irqrestore(&ax25_frag_lock, flags);
len = (paclen > skb->len) ? skb->len : paclen; len = (paclen > skb->len) ? skb->len : paclen;
...@@ -202,19 +203,19 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) ...@@ -202,19 +203,19 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
} }
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_kick(ax25); ax25_kick(ax25);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
/* /*
* A DAMA slave is _required_ to work as normal AX.25L2V2 * A DAMA slave is _required_ to work as normal AX.25L2V2
* if no DAMA master is available. * if no DAMA master is available.
*/ */
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25); if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25);
break; break;
#endif #endif
} }
} }
...@@ -305,15 +306,15 @@ void ax25_kick(ax25_cb *ax25) ...@@ -305,15 +306,15 @@ void ax25_kick(ax25_cb *ax25)
* in DAMA mode. * in DAMA mode.
*/ */
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF); ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
ax25_send_iframe(ax25, skbn, AX25_POLLOFF); ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
break; break;
#endif #endif
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -47,30 +47,29 @@ ...@@ -47,30 +47,29 @@
void ax25_std_heartbeat_expiry(ax25_cb *ax25) void ax25_std_heartbeat_expiry(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_0:
case AX25_STATE_0: /* Magic here: If we listen() and a new link dies before it
/* Magic here: If we listen() and a new link dies before it is accepted() it isn't 'dead' so doesn't get removed. */
is accepted() it isn't 'dead' so doesn't get removed. */ if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { ax25_destroy_socket(ax25);
ax25_destroy_socket(ax25); return;
return; }
} break;
break;
case AX25_STATE_3:
case AX25_STATE_3: case AX25_STATE_4:
case AX25_STATE_4: /*
/* * Check the state of the receive buffer.
* Check the state of the receive buffer. */
*/ if (ax25->sk != NULL) {
if (ax25->sk != NULL) { if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
(ax25->condition & AX25_COND_OWN_RX_BUSY)) { ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
ax25->condition &= ~AX25_COND_OWN_RX_BUSY; ax25->condition &= ~AX25_COND_ACK_PENDING;
ax25->condition &= ~AX25_COND_ACK_PENDING; ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); break;
break;
}
} }
}
} }
ax25_start_heartbeat(ax25); ax25_start_heartbeat(ax25);
...@@ -117,53 +116,53 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25) ...@@ -117,53 +116,53 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25)
void ax25_std_t1timer_expiry(ax25_cb *ax25) void ax25_std_t1timer_expiry(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_1: case AX25_STATE_1:
if (ax25->n2count == ax25->n2) { if (ax25->n2count == ax25->n2) {
if (ax25->modulus == AX25_MODULUS) { if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25->n2count = 0;
ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
}
} else {
ax25->n2count++;
if (ax25->modulus == AX25_MODULUS)
ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
else
ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
}
break;
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT); ax25_disconnect(ax25, ETIMEDOUT);
return; return;
} else { } else {
ax25->n2count++; ax25->modulus = AX25_MODULUS;
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25->n2count = 0;
ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
} }
break; } else {
ax25->n2count++;
case AX25_STATE_3: if (ax25->modulus == AX25_MODULUS)
ax25->n2count = 1; ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
else
ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
}
break;
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
}
break;
case AX25_STATE_3:
ax25->n2count = 1;
ax25_std_transmit_enquiry(ax25);
ax25->state = AX25_STATE_4;
break;
case AX25_STATE_4:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
ax25_std_transmit_enquiry(ax25); ax25_std_transmit_enquiry(ax25);
ax25->state = AX25_STATE_4; }
break; break;
case AX25_STATE_4:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
ax25_std_transmit_enquiry(ax25);
}
break;
} }
ax25_calculate_t1(ax25); ax25_calculate_t1(ax25);
......
...@@ -257,18 +257,18 @@ void ax25_calculate_t1(ax25_cb *ax25) ...@@ -257,18 +257,18 @@ void ax25_calculate_t1(ax25_cb *ax25)
int n, t = 2; int n, t = 2;
switch (ax25->backoff) { switch (ax25->backoff) {
case 0: case 0:
break; break;
case 1: case 1:
t += 2 * ax25->n2count; t += 2 * ax25->n2count;
break; break;
case 2: case 2:
for (n = 0; n < ax25->n2count; n++) for (n = 0; n < ax25->n2count; n++)
t *= 2; t *= 2;
if (t > 8) t = 8; if (t > 8) t = 8;
break; break;
} }
ax25->t1 = t * ax25->rtt; ax25->t1 = t * ax25->rtt;
......
...@@ -159,18 +159,18 @@ static void ax25_heartbeat_expiry(unsigned long param) ...@@ -159,18 +159,18 @@ static void ax25_heartbeat_expiry(unsigned long param)
proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]; proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL];
switch (proto) { switch (proto) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_std_heartbeat_expiry(ax25); ax25_std_heartbeat_expiry(ax25);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave) if (ax25->ax25_dev->dama.slave)
ax25_ds_heartbeat_expiry(ax25); ax25_ds_heartbeat_expiry(ax25);
else else
ax25_std_heartbeat_expiry(ax25); ax25_std_heartbeat_expiry(ax25);
break; break;
#endif #endif
} }
} }
...@@ -180,16 +180,16 @@ static void ax25_t1timer_expiry(unsigned long param) ...@@ -180,16 +180,16 @@ static void ax25_t1timer_expiry(unsigned long param)
ax25_cb *ax25 = (ax25_cb *)param; ax25_cb *ax25 = (ax25_cb *)param;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_std_t1timer_expiry(ax25); ax25_std_t1timer_expiry(ax25);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave) if (!ax25->ax25_dev->dama.slave)
ax25_std_t1timer_expiry(ax25); ax25_std_t1timer_expiry(ax25);
break; break;
#endif #endif
} }
} }
...@@ -199,16 +199,16 @@ static void ax25_t2timer_expiry(unsigned long param) ...@@ -199,16 +199,16 @@ static void ax25_t2timer_expiry(unsigned long param)
ax25_cb *ax25 = (ax25_cb *)param; ax25_cb *ax25 = (ax25_cb *)param;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_std_t2timer_expiry(ax25); ax25_std_t2timer_expiry(ax25);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave) if (!ax25->ax25_dev->dama.slave)
ax25_std_t2timer_expiry(ax25); ax25_std_t2timer_expiry(ax25);
break; break;
#endif #endif
} }
} }
...@@ -218,18 +218,18 @@ static void ax25_t3timer_expiry(unsigned long param) ...@@ -218,18 +218,18 @@ static void ax25_t3timer_expiry(unsigned long param)
ax25_cb *ax25 = (ax25_cb *)param; ax25_cb *ax25 = (ax25_cb *)param;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_std_t3timer_expiry(ax25); ax25_std_t3timer_expiry(ax25);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave) if (ax25->ax25_dev->dama.slave)
ax25_ds_t3timer_expiry(ax25); ax25_ds_t3timer_expiry(ax25);
else else
ax25_std_t3timer_expiry(ax25); ax25_std_t3timer_expiry(ax25);
break; break;
#endif #endif
} }
} }
...@@ -239,18 +239,18 @@ static void ax25_idletimer_expiry(unsigned long param) ...@@ -239,18 +239,18 @@ static void ax25_idletimer_expiry(unsigned long param)
ax25_cb *ax25 = (ax25_cb *)param; ax25_cb *ax25 = (ax25_cb *)param;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_std_idletimer_expiry(ax25); ax25_std_idletimer_expiry(ax25);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave) if (ax25->ax25_dev->dama.slave)
ax25_ds_idletimer_expiry(ax25); ax25_ds_idletimer_expiry(ax25);
else else
ax25_std_idletimer_expiry(ax25); ax25_std_idletimer_expiry(ax25);
break; break;
#endif #endif
} }
} }
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h> #include <net/ax25.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -47,17 +48,23 @@ ...@@ -47,17 +48,23 @@
*/ */
static ax25_uid_assoc *ax25_uid_list; static ax25_uid_assoc *ax25_uid_list;
static rwlock_t ax25_uid_lock = RW_LOCK_UNLOCKED;
int ax25_uid_policy = 0; int ax25_uid_policy = 0;
ax25_address *ax25_findbyuid(uid_t uid) ax25_address *ax25_findbyuid(uid_t uid)
{ {
ax25_uid_assoc *ax25_uid; ax25_uid_assoc *ax25_uid;
ax25_address *res = NULL;
read_lock(&ax25_uid_lock);
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
if (ax25_uid->uid == uid) if (ax25_uid->uid == uid) {
return &ax25_uid->call; res = &ax25_uid->call;
break;
}
} }
read_unlock(&ax25_uid_lock);
return NULL; return NULL;
} }
...@@ -65,63 +72,77 @@ ax25_address *ax25_findbyuid(uid_t uid) ...@@ -65,63 +72,77 @@ ax25_address *ax25_findbyuid(uid_t uid)
int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
{ {
ax25_uid_assoc *s, *ax25_uid; ax25_uid_assoc *s, *ax25_uid;
unsigned long flags; unsigned long res;
switch (cmd) { switch (cmd) {
case SIOCAX25GETUID: case SIOCAX25GETUID:
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { res = -ENOENT;
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) read_lock(&ax25_uid_lock);
return ax25_uid->uid; for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
res = ax25_uid->uid;
break;
} }
return -ENOENT; }
read_unlock(&ax25_uid_lock);
case SIOCAX25ADDUID: return res;
if (!capable(CAP_NET_ADMIN))
return -EPERM; case SIOCAX25ADDUID:
if (ax25_findbyuid(sax->sax25_uid)) if (!capable(CAP_NET_ADMIN))
return -EEXIST; return -EPERM;
if (sax->sax25_uid == 0) if (ax25_findbyuid(sax->sax25_uid))
return -EINVAL; return -EEXIST;
if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) if (sax->sax25_uid == 0)
return -ENOMEM; return -EINVAL;
ax25_uid->uid = sax->sax25_uid; if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
ax25_uid->call = sax->sax25_call; return -ENOMEM;
save_flags(flags); cli();
ax25_uid->next = ax25_uid_list; ax25_uid->uid = sax->sax25_uid;
ax25_uid_list = ax25_uid; ax25_uid->call = sax->sax25_call;
restore_flags(flags);
return 0; write_lock(&ax25_uid_lock);
ax25_uid->next = ax25_uid_list;
ax25_uid_list = ax25_uid;
write_unlock(&ax25_uid_lock);
case SIOCAX25DELUID: return 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM; case SIOCAX25DELUID:
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { if (!capable(CAP_NET_ADMIN))
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) return -EPERM;
break;
write_lock(&ax25_uid_lock);
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
break;
} }
if (ax25_uid == NULL) }
return -ENOENT; if (ax25_uid == NULL) {
save_flags(flags); cli(); write_unlock(&ax25_uid_lock);
if ((s = ax25_uid_list) == ax25_uid) { return -ENOENT;
ax25_uid_list = s->next; }
restore_flags(flags); if ((s = ax25_uid_list) == ax25_uid) {
ax25_uid_list = s->next;
write_unlock(&ax25_uid_lock);
kfree(ax25_uid);
return 0;
}
while (s != NULL && s->next != NULL) {
if (s->next == ax25_uid) {
s->next = ax25_uid->next;
write_unlock(&ax25_uid_lock);
kfree(ax25_uid); kfree(ax25_uid);
return 0; return 0;
} }
while (s != NULL && s->next != NULL) { s = s->next;
if (s->next == ax25_uid) { }
s->next = ax25_uid->next; write_unlock(&ax25_uid_lock);
restore_flags(flags);
kfree(ax25_uid);
return 0;
}
s = s->next;
}
restore_flags(flags);
return -ENOENT;
default: return -ENOENT;
return -EINVAL;
default:
return -EINVAL;
} }
return -EINVAL; /*NOTREACHED */ return -EINVAL; /*NOTREACHED */
...@@ -134,8 +155,7 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -134,8 +155,7 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0; off_t pos = 0;
off_t begin = 0; off_t begin = 0;
cli(); read_lock(&ax25_uid_lock);
len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy); len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy);
for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { for (pt = ax25_uid_list; pt != NULL; pt = pt->next) {
...@@ -151,13 +171,13 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -151,13 +171,13 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length) if (pos > offset + length)
break; break;
} }
read_unlock(&ax25_uid_lock);
sti();
*start = buffer + (offset - begin); *start = buffer + (offset - begin);
len -= offset - begin; len -= offset - begin;
if (len > length) len = length; if (len > length)
len = length;
return len; return len;
} }
...@@ -167,12 +187,16 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -167,12 +187,16 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
*/ */
void __exit ax25_uid_free(void) void __exit ax25_uid_free(void)
{ {
ax25_uid_assoc *s, *ax25_uid = ax25_uid_list; ax25_uid_assoc *s, *ax25_uid;
write_lock(&ax25_uid_lock);
ax25_uid = ax25_uid_list;
while (ax25_uid != NULL) { while (ax25_uid != NULL) {
s = ax25_uid; s = ax25_uid;
ax25_uid = ax25_uid->next; ax25_uid = ax25_uid->next;
kfree(s); kfree(s);
} }
ax25_uid_list = NULL;
write_unlock(&ax25_uid_lock);
} }
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/spinlock.h>
#include <net/ax25.h> #include <net/ax25.h>
static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1}; static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1};
...@@ -102,9 +103,11 @@ static const ctl_table ax25_param_table[] = { ...@@ -102,9 +103,11 @@ static const ctl_table ax25_param_table[] = {
void ax25_register_sysctl(void) void ax25_register_sysctl(void)
{ {
unsigned long flags;
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
int n, k; int n, k;
spin_lock_irqsave(&ax25_dev_lock, flags);
for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
ax25_table_size += sizeof(ctl_table); ax25_table_size += sizeof(ctl_table);
...@@ -119,6 +122,7 @@ void ax25_register_sysctl(void) ...@@ -119,6 +122,7 @@ void ax25_register_sysctl(void)
while (n--) while (n--)
kfree(ax25_table[n].child); kfree(ax25_table[n].child);
kfree(ax25_table); kfree(ax25_table);
spin_unlock_irqrestore(&ax25_dev_lock, flags);
return; return;
} }
memcpy(child, ax25_param_table, sizeof(ax25_param_table)); memcpy(child, ax25_param_table, sizeof(ax25_param_table));
...@@ -144,6 +148,7 @@ void ax25_register_sysctl(void) ...@@ -144,6 +148,7 @@ void ax25_register_sysctl(void)
n++; n++;
} }
spin_unlock_irqrestore(&ax25_dev_lock, flags);
ax25_dir_table[0].child = ax25_table; ax25_dir_table[0].child = ax25_table;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment