Commit e2021e76 authored by Ralf Bächle's avatar Ralf Bächle

Merge dea.linux-mips.net:/usr/src/bk/linux-2.5

into dea.linux-mips.net:/home/ralf/src/ax25/linux-2.5
parents 12ebbff8 5003f54a
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
* *
* 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>
#define AX25_T1CLAMPLO 1 #define AX25_T1CLAMPLO 1
#define AX25_T1CLAMPHI (30 * HZ) #define AX25_T1CLAMPHI (30 * HZ)
...@@ -197,7 +198,8 @@ typedef struct ax25_cb { ...@@ -197,7 +198,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 +226,7 @@ extern void ax25_digi_invert(ax25_digi *, ax25_digi *); ...@@ -224,6 +226,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 *);
......
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?
...@@ -114,6 +114,7 @@ ...@@ -114,6 +114,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/net.h> #include <linux/net.h>
#include <net/ax25.h> #include <net/ax25.h>
...@@ -134,13 +135,15 @@ ...@@ -134,13 +135,15 @@
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/arp.h> #include <net/arp.h>
ax25_cb *volatile ax25_list; ax25_cb *ax25_list;
spinlock_t ax25_list_lock = SPIN_LOCK_UNLOCKED;
static struct proto_ops ax25_proto_ops; static struct proto_ops ax25_proto_ops;
...@@ -173,25 +176,25 @@ static void ax25_remove_socket(ax25_cb *ax25) ...@@ -173,25 +176,25 @@ static void ax25_remove_socket(ax25_cb *ax25)
ax25_cb *s; ax25_cb *s;
unsigned long flags; unsigned long flags;
save_flags(flags); cli(); spin_lock_irqsave(&ax25_list_lock, flags);
if ((s = ax25_list) == ax25) { if ((s = ax25_list) == ax25) {
ax25_list = s->next; ax25_list = s->next;
restore_flags(flags); spin_unlock_irqrestore(&ax25_list_lock, flags);
return; return;
} }
while (s != NULL && s->next != NULL) { while (s != NULL && s->next != NULL) {
if (s->next == ax25) { if (s->next == ax25) {
s->next = ax25->next; s->next = ax25->next;
restore_flags(flags); spin_unlock_irqrestore(&ax25_list_lock, flags);
return; return;
} }
s = s->next; s = s->next;
} }
restore_flags(flags); spin_unlock_irqrestore(&ax25_list_lock, flags);
} }
/* /*
...@@ -199,18 +202,21 @@ static void ax25_remove_socket(ax25_cb *ax25) ...@@ -199,18 +202,21 @@ static void ax25_remove_socket(ax25_cb *ax25)
*/ */
static void ax25_kill_by_device(struct net_device *dev) static void ax25_kill_by_device(struct net_device *dev)
{ {
unsigned long flags;
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
ax25_cb *s; ax25_cb *s;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return; return;
spin_lock_irqsave(&ax25_list_lock, flags);
for (s = ax25_list; s != NULL; s = s->next) { for (s = ax25_list; s != NULL; s = s->next) {
if (s->ax25_dev == ax25_dev) { if (s->ax25_dev == ax25_dev) {
s->ax25_dev = NULL; s->ax25_dev = NULL;
ax25_disconnect(s, ENETUNREACH); ax25_disconnect(s, ENETUNREACH);
} }
} }
spin_unlock_irqrestore(&ax25_list_lock, flags);
} }
/* /*
...@@ -247,13 +253,10 @@ void ax25_insert_socket(ax25_cb *ax25) ...@@ -247,13 +253,10 @@ void ax25_insert_socket(ax25_cb *ax25)
{ {
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&ax25_list_lock, flags);
cli();
ax25->next = ax25_list; ax25->next = ax25_list;
ax25_list = ax25; ax25_list = ax25;
spin_unlock_irqrestore(&ax25_list_lock, flags);
restore_flags(flags);
} }
/* /*
...@@ -265,22 +268,21 @@ struct sock *ax25_find_listener(ax25_address *addr, int digi, struct net_device ...@@ -265,22 +268,21 @@ struct sock *ax25_find_listener(ax25_address *addr, int digi, struct net_device
unsigned long flags; unsigned long flags;
ax25_cb *s; ax25_cb *s;
save_flags(flags); spin_lock_irqsave(&ax25_list_lock, flags);
cli();
for (s = ax25_list; s != NULL; s = s->next) { for (s = ax25_list; s != NULL; s = s->next) {
if ((s->iamdigi && !digi) || (!s->iamdigi && digi)) if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
continue; continue;
if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) { if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) {
/* If device is null we match any device */ /* If device is null we match any device */
if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) { if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) {
restore_flags(flags); spin_unlock_irqrestore(&ax25_list_lock, flags);
return s->sk; return s->sk;
} }
} }
} }
spin_unlock_irqrestore(&ax25_list_lock, flags);
restore_flags(flags);
return NULL; return NULL;
} }
...@@ -292,17 +294,15 @@ struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, in ...@@ -292,17 +294,15 @@ struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, in
ax25_cb *s; ax25_cb *s;
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&ax25_list_lock, flags);
cli();
for (s = ax25_list; s != NULL; s = s->next) { for (s = ax25_list; s != NULL; s = s->next) {
if (s->sk != NULL && ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->sk->type == type) { if (s->sk != NULL && ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->sk->type == type) {
restore_flags(flags); spin_unlock_irqrestore(&ax25_list_lock, flags);
return s->sk; return s->sk;
} }
} }
spin_unlock_irqrestore(&ax25_list_lock, flags);
restore_flags(flags);
return NULL; return NULL;
} }
...@@ -316,9 +316,7 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi ...@@ -316,9 +316,7 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi
ax25_cb *s; ax25_cb *s;
unsigned long flags; unsigned long flags;
save_flags(flags); spin_lock_irqsave(&ax25_list_lock, flags);
cli();
for (s = ax25_list; s != NULL; s = s->next) { for (s = ax25_list; s != NULL; s = s->next) {
if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET) if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET)
continue; continue;
...@@ -334,12 +332,12 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi ...@@ -334,12 +332,12 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi
if (s->digipeat != NULL && s->digipeat->ndigi != 0) if (s->digipeat != NULL && s->digipeat->ndigi != 0)
continue; continue;
} }
restore_flags(flags); spin_unlock_irqrestore(&ax25_list_lock, flags);
return s; return s;
} }
} }
spin_unlock_irqrestore(&ax25_list_lock, flags);
restore_flags(flags);
return NULL; return NULL;
} }
...@@ -352,17 +350,14 @@ struct sock *ax25_addr_match(ax25_address *addr) ...@@ -352,17 +350,14 @@ struct sock *ax25_addr_match(ax25_address *addr)
unsigned long flags; unsigned long flags;
ax25_cb *s; ax25_cb *s;
save_flags(flags); spin_lock_irqsave(&ax25_list_lock, flags);
cli();
for (s = ax25_list; s != NULL; s = s->next) { for (s = ax25_list; s != NULL; s = s->next) {
if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == SOCK_RAW) { if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == SOCK_RAW) {
restore_flags(flags); spin_unlock_irqrestore(&ax25_list_lock, flags);
return s->sk; return s->sk;
} }
} }
spin_unlock_irqrestore(&ax25_list_lock, flags);
restore_flags(flags);
return NULL; return NULL;
} }
...@@ -634,10 +629,10 @@ ax25_cb *ax25_create_cb(void) ...@@ -634,10 +629,10 @@ ax25_cb *ax25_create_cb(void)
static int ax25_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) static int ax25_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
ax25_cb *ax25 = ax25_sk(sk); ax25_cb *ax25;
struct net_device *dev; struct net_device *dev;
char devname[IFNAMSIZ]; char devname[IFNAMSIZ];
int opt; int opt, res = 0;
if (level != SOL_AX25) if (level != SOL_AX25)
return -ENOPROTOOPT; return -ENOPROTOOPT;
...@@ -648,98 +643,130 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op ...@@ -648,98 +643,130 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
if (get_user(opt, (int *)optval)) if (get_user(opt, (int *)optval))
return -EFAULT; return -EFAULT;
lock_kernel();
ax25 = ax25_sk(sk);
switch (optname) { switch (optname) {
case AX25_WINDOW: case AX25_WINDOW:
if (ax25->modulus == AX25_MODULUS) { if (ax25->modulus == AX25_MODULUS) {
if (opt < 1 || opt > 7) if (opt < 1 || opt > 7) {
return -EINVAL; res = -EINVAL;
break;
}
} else { } else {
if (opt < 1 || opt > 63) if (opt < 1 || opt > 63) {
return -EINVAL; res = -EINVAL;
break;
}
} }
ax25->window = opt; ax25->window = opt;
return 0; break;
case AX25_T1: case AX25_T1:
if (opt < 1) if (opt < 1) {
return -EINVAL; res = -EINVAL;
break;
}
ax25->rtt = (opt * HZ) / 2; ax25->rtt = (opt * HZ) / 2;
ax25->t1 = opt * HZ; ax25->t1 = opt * HZ;
return 0; break;
case AX25_T2: case AX25_T2:
if (opt < 1) if (opt < 1) {
return -EINVAL; res = -EINVAL;
break;
}
ax25->t2 = opt * HZ; ax25->t2 = opt * HZ;
return 0; break;
case AX25_N2: case AX25_N2:
if (opt < 1 || opt > 31) if (opt < 1 || opt > 31) {
return -EINVAL; res = -EINVAL;
break;
}
ax25->n2 = opt; ax25->n2 = opt;
return 0; break;
case AX25_T3: case AX25_T3:
if (opt < 1) if (opt < 1) {
return -EINVAL; res = -EINVAL;
break;
}
ax25->t3 = opt * HZ; ax25->t3 = opt * HZ;
return 0; break;
case AX25_IDLE: case AX25_IDLE:
if (opt < 0) if (opt < 0) {
return -EINVAL; res = -EINVAL;
break;
}
ax25->idle = opt * 60 * HZ; ax25->idle = opt * 60 * HZ;
return 0; break;
case AX25_BACKOFF: case AX25_BACKOFF:
if (opt < 0 || opt > 2) if (opt < 0 || opt > 2) {
return -EINVAL; res = -EINVAL;
break;
}
ax25->backoff = opt; ax25->backoff = opt;
return 0; break;
case AX25_EXTSEQ: case AX25_EXTSEQ:
ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS; ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
return 0; break;
case AX25_PIDINCL: case AX25_PIDINCL:
ax25->pidincl = opt ? 1 : 0; ax25->pidincl = opt ? 1 : 0;
return 0; break;
case AX25_IAMDIGI: case AX25_IAMDIGI:
ax25->iamdigi = opt ? 1 : 0; ax25->iamdigi = opt ? 1 : 0;
return 0; break;
case AX25_PACLEN: case AX25_PACLEN:
if (opt < 16 || opt > 65535) if (opt < 16 || opt > 65535) {
return -EINVAL; res = -EINVAL;
break;
}
ax25->paclen = opt; ax25->paclen = opt;
return 0; break;
case SO_BINDTODEVICE: case SO_BINDTODEVICE:
if (optlen > IFNAMSIZ) optlen=IFNAMSIZ; if (optlen > IFNAMSIZ)
if (copy_from_user(devname, optval, optlen)) optlen=IFNAMSIZ;
return -EFAULT; if (copy_from_user(devname, optval, optlen)) {
res = -EFAULT;
break;
}
dev = dev_get_by_name(devname); dev = dev_get_by_name(devname);
if (dev == NULL) return -ENODEV; if (dev == NULL) {
res = -ENODEV;
break;
}
if (sk->type == SOCK_SEQPACKET && if (sk->type == SOCK_SEQPACKET &&
(sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) {
return -EADDRNOTAVAIL; res = -EADDRNOTAVAIL;
break;
}
ax25->ax25_dev = ax25_dev_ax25dev(dev); ax25->ax25_dev = ax25_dev_ax25dev(dev);
ax25_fillin_cb(ax25, ax25->ax25_dev); ax25_fillin_cb(ax25, ax25->ax25_dev);
return 0; break;
default: default:
return -ENOPROTOOPT; res = -ENOPROTOOPT;
} }
unlock_kernel();
return res;
} }
static int ax25_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) static int ax25_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
ax25_cb *ax25 = ax25_sk(sk); ax25_cb *ax25;
struct ax25_dev *ax25_dev; struct ax25_dev *ax25_dev;
char devname[IFNAMSIZ]; char devname[IFNAMSIZ];
void *valptr; void *valptr;
...@@ -758,6 +785,9 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op ...@@ -758,6 +785,9 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
valptr = (void *) &val; valptr = (void *) &val;
length = min_t(unsigned int, maxlen, sizeof(int)); length = min_t(unsigned int, maxlen, sizeof(int));
lock_kernel();
ax25 = ax25_sk(sk);
switch (optname) { switch (optname) {
case AX25_WINDOW: case AX25_WINDOW:
val = ax25->window; val = ax25->window;
...@@ -819,8 +849,10 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op ...@@ -819,8 +849,10 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
break; break;
default: default:
unlock_kernel();
return -ENOPROTOOPT; return -ENOPROTOOPT;
} }
unlock_kernel();
if (put_user(length, optlen)) if (put_user(length, optlen))
return -EFAULT; return -EFAULT;
...@@ -832,11 +864,14 @@ static int ax25_listen(struct socket *sock, int backlog) ...@@ -832,11 +864,14 @@ static int ax25_listen(struct socket *sock, int backlog)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
lock_kernel();
if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) { if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) {
sk->max_ack_backlog = backlog; sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN; sk->state = TCP_LISTEN;
unlock_kernel();
return 0; return 0;
} }
unlock_kernel();
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -851,6 +886,7 @@ int ax25_create(struct socket *sock, int protocol) ...@@ -851,6 +886,7 @@ int ax25_create(struct socket *sock, int protocol)
if (protocol == 0 || protocol == PF_AX25) if (protocol == 0 || protocol == PF_AX25)
protocol = AX25_P_TEXT; protocol = AX25_P_TEXT;
break; break;
case SOCK_SEQPACKET: case SOCK_SEQPACKET:
switch (protocol) { switch (protocol) {
case 0: case 0:
...@@ -883,6 +919,7 @@ int ax25_create(struct socket *sock, int protocol) ...@@ -883,6 +919,7 @@ int ax25_create(struct socket *sock, int protocol)
break; break;
} }
break; break;
case SOCK_RAW: case SOCK_RAW:
break; break;
default: default:
...@@ -985,7 +1022,11 @@ static int ax25_release(struct socket *sock) ...@@ -985,7 +1022,11 @@ static int ax25_release(struct socket *sock)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
ax25_cb *ax25; ax25_cb *ax25;
if (sk == NULL) return 0; lock_kernel();
if (sk == NULL) {
unlock_kernel();
return 0;
}
ax25 = ax25_sk(sk); ax25 = ax25_sk(sk);
...@@ -1048,6 +1089,7 @@ static int ax25_release(struct socket *sock) ...@@ -1048,6 +1089,7 @@ static int ax25_release(struct socket *sock)
sock->sk = NULL; sock->sk = NULL;
sk->socket = NULL; /* Not used, but we should do this */ sk->socket = NULL; /* Not used, but we should do this */
unlock_kernel();
return 0; return 0;
} }
...@@ -1066,26 +1108,35 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -1066,26 +1108,35 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
ax25_address *call; ax25_address *call;
ax25_dev *ax25_dev = NULL; ax25_dev *ax25_dev = NULL;
if (sk->zapped == 0) lock_kernel();
if (sk->zapped == 0) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
if (addr_len != sizeof(struct sockaddr_ax25) && if (addr_len != sizeof(struct sockaddr_ax25) &&
addr_len != sizeof(struct full_sockaddr_ax25)) { addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */ /* support for old structure may go away some time */
if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
(addr_len > sizeof(struct full_sockaddr_ax25))) (addr_len > sizeof(struct full_sockaddr_ax25))) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n", printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n",
current->comm); current->comm);
} }
if (addr->fsa_ax25.sax25_family != AF_AX25) if (addr->fsa_ax25.sax25_family != AF_AX25) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
call = ax25_findbyuid(current->euid); call = ax25_findbyuid(current->euid);
if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
unlock_kernel();
return -EACCES; return -EACCES;
}
if (call == NULL) if (call == NULL)
ax25->source_addr = addr->fsa_ax25.sax25_call; ax25->source_addr = addr->fsa_ax25.sax25_call;
...@@ -1101,12 +1152,16 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -1101,12 +1152,16 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) { if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) {
if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 && if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 &&
(ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) {
unlock_kernel();
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
}
} else { } else {
if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) {
unlock_kernel();
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
} }
}
if (ax25_dev != NULL) if (ax25_dev != NULL)
ax25_fillin_cb(ax25, ax25_dev); ax25_fillin_cb(ax25, ax25_dev);
...@@ -1114,6 +1169,8 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) ...@@ -1114,6 +1169,8 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
done: done:
ax25_insert_socket(ax25); ax25_insert_socket(ax25);
sk->zapped = 0; sk->zapped = 0;
unlock_kernel();
return 0; return 0;
} }
...@@ -1128,24 +1185,30 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le ...@@ -1128,24 +1185,30 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
ax25_digi *digi = NULL; ax25_digi *digi = NULL;
int ct = 0, err; int ct = 0, err;
lock_kernel();
/* deal with restarts */ /* deal with restarts */
if (sock->state == SS_CONNECTING) { if (sock->state == SS_CONNECTING) {
switch (sk->state) { switch (sk->state) {
case TCP_SYN_SENT: /* still trying */ case TCP_SYN_SENT: /* still trying */
unlock_kernel();
return -EINPROGRESS; return -EINPROGRESS;
case TCP_ESTABLISHED: /* connection established */ case TCP_ESTABLISHED: /* connection established */
unlock_kernel();
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
return 0; return 0;
case TCP_CLOSE: /* connection refused */ case TCP_CLOSE: /* connection refused */
unlock_kernel();
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
return -ECONNREFUSED; return -ECONNREFUSED;
} }
} }
if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET) if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET) {
unlock_kernel();
return -EISCONN; /* No reconnect on a seqpacket socket */ return -EISCONN; /* No reconnect on a seqpacket socket */
}
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
...@@ -1162,15 +1225,19 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le ...@@ -1162,15 +1225,19 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
else if (addr_len != sizeof(struct full_sockaddr_ax25)) { else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */ /* support for old structure may go away some time */
if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
(addr_len > sizeof(struct full_sockaddr_ax25))) (addr_len > sizeof(struct full_sockaddr_ax25))) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n", printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n",
current->comm); current->comm);
} }
if (fsa->fsa_ax25.sax25_family != AF_AX25) if (fsa->fsa_ax25.sax25_family != AF_AX25) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
if (ax25->digipeat != NULL) { if (ax25->digipeat != NULL) {
kfree(ax25->digipeat); kfree(ax25->digipeat);
...@@ -1182,11 +1249,15 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le ...@@ -1182,11 +1249,15 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
*/ */
if (addr_len > sizeof(struct sockaddr_ax25) && fsa->fsa_ax25.sax25_ndigis != 0) { if (addr_len > sizeof(struct sockaddr_ax25) && fsa->fsa_ax25.sax25_ndigis != 0) {
/* Valid number of digipeaters ? */ /* Valid number of digipeaters ? */
if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
unlock_kernel();
return -ENOBUFS; return -ENOBUFS;
}
digi->ndigi = fsa->fsa_ax25.sax25_ndigis; digi->ndigi = fsa->fsa_ax25.sax25_ndigis;
digi->lastrepeat = -1; digi->lastrepeat = -1;
...@@ -1218,14 +1289,18 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le ...@@ -1218,14 +1289,18 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
ax25_fillin_cb(ax25, ax25->ax25_dev); ax25_fillin_cb(ax25, ax25->ax25_dev);
ax25_insert_socket(ax25); ax25_insert_socket(ax25);
} else { } else {
if (ax25->ax25_dev == NULL) if (ax25->ax25_dev == NULL) {
unlock_kernel();
return -EHOSTUNREACH; return -EHOSTUNREACH;
} }
}
if (sk->type == SOCK_SEQPACKET && if (sk->type == SOCK_SEQPACKET &&
ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi,
ax25->ax25_dev->dev)) { ax25->ax25_dev->dev)) {
if (digi != NULL) kfree(digi); if (digi != NULL)
kfree(digi);
unlock_kernel();
return -EADDRINUSE; /* Already such a connection */ return -EADDRINUSE; /* Already such a connection */
} }
...@@ -1236,6 +1311,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le ...@@ -1236,6 +1311,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if (sk->type != SOCK_SEQPACKET) { if (sk->type != SOCK_SEQPACKET) {
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED; sk->state = TCP_ESTABLISHED;
unlock_kernel();
return 0; return 0;
} }
...@@ -1252,8 +1328,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le ...@@ -1252,8 +1328,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
ax25->modulus = AX25_MODULUS; ax25->modulus = AX25_MODULUS;
ax25->window = ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25->ax25_dev->values[AX25_VALUES_WINDOW];
if (ax25->ax25_dev->dama.slave) if (ax25->ax25_dev->dama.slave)
ax25_ds_establish_data_link(ax25); ax25_ds_establish_data_link(ax25);
else else
...@@ -1267,30 +1342,38 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le ...@@ -1267,30 +1342,38 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
ax25_start_heartbeat(ax25); ax25_start_heartbeat(ax25);
/* Now the loop */ /* Now the loop */
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
unlock_kernel();
return -EINPROGRESS; return -EINPROGRESS;
}
cli(); /* To avoid races on the sleep */ if (sk->state == TCP_SYN_SENT) {
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);
/* A DM or timeout will go to closed, a UA will go to ABM */ add_wait_queue(sk->sleep, &wait);
while (sk->state == TCP_SYN_SENT) { for (;;) {
interruptible_sleep_on(sk->sleep); set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) { if (sk->state != TCP_SYN_SENT)
sti(); break;
if (!signal_pending(tsk)) {
schedule();
continue;
}
return -ERESTARTSYS; return -ERESTARTSYS;
} }
current->state = TASK_RUNNING;
remove_wait_queue(sk->sleep, &wait);
} }
if (sk->state != TCP_ESTABLISHED) { if (sk->state != TCP_ESTABLISHED) {
/* Not in ABM, not in WAIT_UA -> failed */ /* Not in ABM, not in WAIT_UA -> failed */
sti();
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */ return sock_error(sk); /* Always set at this point */
} }
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
unlock_kernel();
sti();
return 0; return 0;
} }
...@@ -1302,17 +1385,26 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -1302,17 +1385,26 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
struct sock *newsk; struct sock *newsk;
struct sk_buff *skb; struct sk_buff *skb;
if (sock->state != SS_UNCONNECTED) lock_kernel();
if (sock->state != SS_UNCONNECTED) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
if ((sk = sock->sk) == NULL) if ((sk = sock->sk) == NULL) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
if (sk->type != SOCK_SEQPACKET) if (sk->type != SOCK_SEQPACKET) {
unlock_kernel();
return -EOPNOTSUPP; return -EOPNOTSUPP;
}
if (sk->state != TCP_LISTEN) if (sk->state != TCP_LISTEN) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
/* /*
* The read queue this time is holding sockets ready to use * The read queue this time is holding sockets ready to use
...@@ -1320,13 +1412,17 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -1320,13 +1412,17 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
*/ */
do { do {
if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) { if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
if (flags & O_NONBLOCK) if (flags & O_NONBLOCK) {
unlock_kernel();
return -EWOULDBLOCK; return -EWOULDBLOCK;
}
interruptible_sleep_on(sk->sleep); interruptible_sleep_on(sk->sleep);
if (signal_pending(current)) if (signal_pending(current)) {
unlock_kernel();
return -ERESTARTSYS; return -ERESTARTSYS;
} }
}
} while (skb == NULL); } while (skb == NULL);
newsk = skb->sk; newsk = skb->sk;
...@@ -1339,20 +1435,27 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -1339,20 +1435,27 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
sk->ack_backlog--; sk->ack_backlog--;
newsock->sk = newsk; newsock->sk = newsk;
newsock->state = SS_CONNECTED; newsock->state = SS_CONNECTED;
unlock_kernel();
return 0; return 0;
} }
static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
{ {
struct sock *sk = sock->sk; struct sock *sk;
ax25_cb *ax25 = ax25_sk(sk); ax25_cb *ax25;
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr; struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
unsigned char ndigi, i; unsigned char ndigi, i;
lock_kernel();
sk = sock->sk;
ax25 = ax25_sk(sk);
if (peer != 0) { if (peer != 0) {
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED) {
unlock_kernel();
return -ENOTCONN; return -ENOTCONN;
}
fsa->fsa_ax25.sax25_family = AF_AX25; fsa->fsa_ax25.sax25_family = AF_AX25;
fsa->fsa_ax25.sax25_call = ax25->dest_addr; fsa->fsa_ax25.sax25_call = ax25->dest_addr;
...@@ -1377,13 +1480,15 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_ ...@@ -1377,13 +1480,15 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_
} }
} }
*uaddr_len = sizeof (struct full_sockaddr_ax25); *uaddr_len = sizeof (struct full_sockaddr_ax25);
unlock_kernel();
return 0; return 0;
} }
static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
ax25_cb *ax25 = ax25_sk(sk); ax25_cb *ax25;
struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name; struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
int err; int err;
struct sockaddr_ax25 sax; struct sockaddr_ax25 sax;
...@@ -1395,23 +1500,34 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1395,23 +1500,34 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
int lv; int lv;
int addr_len = msg->msg_namelen; int addr_len = msg->msg_namelen;
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) {
return -EINVAL; return -EINVAL;
}
lock_kernel();
ax25 = ax25_sk(sk);
if (sk->zapped) if (sk->zapped) {
unlock_kernel();
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
}
if (sk->shutdown & SEND_SHUTDOWN) { if (sk->shutdown & SEND_SHUTDOWN) {
unlock_kernel();
send_sig(SIGPIPE, current, 0); send_sig(SIGPIPE, current, 0);
return -EPIPE; return -EPIPE;
} }
if (ax25->ax25_dev == NULL) if (ax25->ax25_dev == NULL) {
unlock_kernel();
return -ENETUNREACH; return -ENETUNREACH;
}
if (usax != NULL) { if (usax != NULL) {
if (usax->sax25_family != AF_AX25) if (usax->sax25_family != AF_AX25) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
if (addr_len == sizeof(struct sockaddr_ax25)) { if (addr_len == sizeof(struct sockaddr_ax25)) {
printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n", printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n",
...@@ -1420,8 +1536,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1420,8 +1536,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
else if (addr_len != sizeof(struct full_sockaddr_ax25)) { else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */ /* support for old structure may go away some time */
if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) || if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
(addr_len > sizeof(struct full_sockaddr_ax25))) (addr_len > sizeof(struct full_sockaddr_ax25))) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n", printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n",
current->comm); current->comm);
...@@ -1432,8 +1550,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1432,8 +1550,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax; struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax;
/* Valid number of digipeaters ? */ /* Valid number of digipeaters ? */
if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) {
unlock_kernel();
return -EINVAL; return -EINVAL;
}
dtmp.ndigi = usax->sax25_ndigis; dtmp.ndigi = usax->sax25_ndigis;
...@@ -1447,8 +1567,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1447,8 +1567,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
} }
sax = *usax; sax = *usax;
if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0) if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0) {
unlock_kernel();
return -EISCONN; return -EISCONN;
}
if (usax->sax25_ndigis == 0) if (usax->sax25_ndigis == 0)
dp = NULL; dp = NULL;
else else
...@@ -1474,8 +1596,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1474,8 +1596,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Assume the worst case */ /* Assume the worst case */
size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN; size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN;
if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) {
unlock_kernel();
return err; return err;
}
skb_reserve(skb, size - len); skb_reserve(skb, size - len);
...@@ -1497,11 +1621,13 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1497,11 +1621,13 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Connected mode sockets go via the LAPB machine */ /* Connected mode sockets go via the LAPB machine */
if (sk->state != TCP_ESTABLISHED) { if (sk->state != TCP_ESTABLISHED) {
kfree_skb(skb); kfree_skb(skb);
unlock_kernel();
return -ENOTCONN; return -ENOTCONN;
} }
/* Shove it onto the queue and kick */ /* Shove it onto the queue and kick */
ax25_output(ax25, ax25->paclen, skb); ax25_output(ax25, ax25->paclen, skb);
unlock_kernel();
return len; return len;
} else { } else {
...@@ -1529,6 +1655,7 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1529,6 +1655,7 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
skb->dev = ax25->ax25_dev->dev; skb->dev = ax25->ax25_dev->dev;
ax25_queue_xmit(skb); ax25_queue_xmit(skb);
unlock_kernel();
return len; return len;
} }
...@@ -1536,21 +1663,28 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct ...@@ -1536,21 +1663,28 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm) static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
{ {
struct sock *sk = sock->sk; struct sock *sk;
int copied; int copied;
struct sk_buff *skb; struct sk_buff *skb;
int er; int er;
lock_kernel();
sk = sock->sk;
/* /*
* This works for seqpacket too. The receiver has ordered the * This works for seqpacket too. The receiver has ordered the
* queue for us! We do one quick check first though * queue for us! We do one quick check first though
*/ */
if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED) if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED) {
unlock_kernel();
return -ENOTCONN; return -ENOTCONN;
}
/* Now we can treat all alike */ /* 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) {
unlock_kernel();
return er; return er;
}
if (!ax25_sk(sk)->pidincl) if (!ax25_sk(sk)->pidincl)
skb_pull(skb, 1); /* Remove PID */ skb_pull(skb, 1); /* Remove PID */
...@@ -1590,6 +1724,7 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f ...@@ -1590,6 +1724,7 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f
} }
skb_free_datagram(sk, skb); skb_free_datagram(sk, skb);
unlock_kernel();
return copied; return copied;
} }
...@@ -1603,14 +1738,17 @@ static int ax25_shutdown(struct socket *sk, int how) ...@@ -1603,14 +1738,17 @@ static int ax25_shutdown(struct socket *sk, int how)
static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int res = 0;
lock_kernel();
switch (cmd) { switch (cmd) {
case TIOCOUTQ: { case TIOCOUTQ: {
long amount; long amount;
amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if (amount < 0) if (amount < 0)
amount = 0; amount = 0;
return put_user(amount, (int *)arg); res = put_user(amount, (int *)arg);
break;
} }
case TIOCINQ: { case TIOCINQ: {
...@@ -1619,49 +1757,70 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1619,49 +1757,70 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
/* These two are safe on a single CPU system as only user tasks fiddle here */ /* These two are safe on a single CPU system as only user tasks fiddle here */
if ((skb = skb_peek(&sk->receive_queue)) != NULL) if ((skb = skb_peek(&sk->receive_queue)) != NULL)
amount = skb->len; amount = skb->len;
return put_user(amount, (int *)arg); res = put_user(amount, (int *)arg);
break;
} }
case SIOCGSTAMP: case SIOCGSTAMP:
if (sk != NULL) { if (sk != NULL) {
if (sk->stamp.tv_sec == 0) if (sk->stamp.tv_sec == 0) {
return -ENOENT; res = -ENOENT;
return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; break;
} }
return -EINVAL; res = copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
break;
}
res = -EINVAL;
break;
case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */
case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */ case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
case SIOCAX25GETUID: { case SIOCAX25GETUID: {
struct sockaddr_ax25 sax25; struct sockaddr_ax25 sax25;
if (copy_from_user(&sax25, (void *)arg, sizeof(sax25))) if (copy_from_user(&sax25, (void *)arg, sizeof(sax25))) {
return -EFAULT; res = -EFAULT;
return ax25_uid_ioctl(cmd, &sax25); break;
}
res = ax25_uid_ioctl(cmd, &sax25);
break;
} }
case SIOCAX25NOUID: { /* Set the default policy (default/bar) */ case SIOCAX25NOUID: { /* Set the default policy (default/bar) */
long amount; long amount;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN)) {
return -EPERM; res = -EPERM;
if (get_user(amount, (long *)arg)) break;
return -EFAULT; }
if (amount > AX25_NOUID_BLOCK) if (get_user(amount, (long *)arg)) {
return -EINVAL; res = -EFAULT;
break;
}
if (amount > AX25_NOUID_BLOCK) {
res = -EINVAL;
break;
}
ax25_uid_policy = amount; ax25_uid_policy = amount;
return 0; res = 0;
break;
} }
case SIOCADDRT: case SIOCADDRT:
case SIOCDELRT: case SIOCDELRT:
case SIOCAX25OPTRT: case SIOCAX25OPTRT:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN)) {
return -EPERM; res = -EPERM;
return ax25_rt_ioctl(cmd, (void *)arg); break;
}
res = ax25_rt_ioctl(cmd, (void *)arg);
break;
case SIOCAX25CTLCON: case SIOCAX25CTLCON:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN)) {
return -EPERM; res = -EPERM;
return ax25_ctl_ioctl(cmd, (void *)arg); break;
}
res = ax25_ctl_ioctl(cmd, (void *)arg);
break;
case SIOCAX25GETINFO: case SIOCAX25GETINFO:
case SIOCAX25GETINFOOLD: { case SIOCAX25GETINFOOLD: {
...@@ -1697,23 +1856,33 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1697,23 +1856,33 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
warned=1; warned=1;
} }
if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated))) if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated))) {
return -EFAULT; res = -EFAULT;
break;
}
} else { } else {
if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) {
return -EINVAL; res = -EINVAL;
break;
} }
return 0; }
res = 0;
break;
} }
case SIOCAX25ADDFWD: case SIOCAX25ADDFWD:
case SIOCAX25DELFWD: { case SIOCAX25DELFWD: {
struct ax25_fwd_struct ax25_fwd; struct ax25_fwd_struct ax25_fwd;
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN)) {
return -EPERM; res = -EPERM;
if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) break;
return -EFAULT; }
return ax25_fwd_ioctl(cmd, &ax25_fwd); if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) {
res = -EFAULT;
break;
}
res = ax25_fwd_ioctl(cmd, &ax25_fwd);
break;
} }
case SIOCGIFADDR: case SIOCGIFADDR:
...@@ -1726,25 +1895,28 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1726,25 +1895,28 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCSIFNETMASK: case SIOCSIFNETMASK:
case SIOCGIFMETRIC: case SIOCGIFMETRIC:
case SIOCSIFMETRIC: case SIOCSIFMETRIC:
return -EINVAL; res = -EINVAL;
break;
default: default:
return dev_ioctl(cmd, (void *)arg); res = dev_ioctl(cmd, (void *)arg);
break;
} }
/*NOTREACHED*/ unlock_kernel();
return 0; return res;
} }
static int ax25_get_info(char *buffer, char **start, off_t offset, int length) static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
{ {
unsigned long flags;
ax25_cb *ax25; ax25_cb *ax25;
int k; int k;
int len = 0; int len = 0;
off_t pos = 0; off_t pos = 0;
off_t begin = 0; off_t begin = 0;
cli(); spin_lock_irqsave(&ax25_list_lock, flags);
/* /*
* New format: * New format:
...@@ -1799,7 +1971,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1799,7 +1971,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
break; break;
} }
sti(); spin_unlock_irqrestore(&ax25_list_lock, flags);
*start = buffer + (offset - begin); *start = buffer + (offset - begin);
len -= (offset - begin); len -= (offset - begin);
...@@ -1814,7 +1986,7 @@ static struct net_proto_family ax25_family_ops = { ...@@ -1814,7 +1986,7 @@ static struct net_proto_family ax25_family_ops = {
create: ax25_create, create: ax25_create,
}; };
static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = { static struct proto_ops ax25_proto_ops = {
family: PF_AX25, family: PF_AX25,
release: ax25_release, release: ax25_release,
......
...@@ -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();
} }
...@@ -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);
} }
...@@ -95,11 +95,13 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet ...@@ -95,11 +95,13 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
break; break;
case AX25_DM: case AX25_DM:
if (pf) ax25_disconnect(ax25, ECONNREFUSED); if (pf)
ax25_disconnect(ax25, ECONNREFUSED);
break; break;
default: default:
if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); if (pf)
ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
break; break;
} }
......
...@@ -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>
...@@ -79,6 +80,7 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev) ...@@ -79,6 +80,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 +91,7 @@ static void ax25_ds_timeout(unsigned long arg) ...@@ -89,6 +91,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 +99,7 @@ static void ax25_ds_timeout(unsigned long arg) ...@@ -96,6 +99,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);
} }
...@@ -178,7 +182,6 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25) ...@@ -178,7 +182,6 @@ 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) {
......
...@@ -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,24 @@ static struct protocol_struct { ...@@ -40,22 +41,24 @@ 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 +72,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_ ...@@ -69,31 +72,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 +102,14 @@ void ax25_protocol_release(unsigned int pid) ...@@ -102,15 +102,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 +122,27 @@ int ax25_linkfail_register(void (*func)(ax25_cb *, int)) ...@@ -123,31 +122,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 +151,14 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int)) ...@@ -156,15 +151,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 +175,27 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev) ...@@ -181,31 +175,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 +204,42 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev) ...@@ -214,35 +204,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 +247,26 @@ int ax25_listen_mine(ax25_address *callsign, struct net_device *dev) ...@@ -250,19 +247,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;
} }
...@@ -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;
...@@ -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;
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -65,6 +66,7 @@ ...@@ -65,6 +66,7 @@
#include <linux/init.h> #include <linux/init.h>
static ax25_route *ax25_route_list; static ax25_route *ax25_route_list;
static rwlock_t ax25_route_lock = RW_LOCK_UNLOCKED;
static ax25_route *ax25_find_route(ax25_address *, struct net_device *); static ax25_route *ax25_find_route(ax25_address *, struct net_device *);
...@@ -86,8 +88,10 @@ static inline void ax25_route_invert(ax25_digi *in, ax25_digi *out) ...@@ -86,8 +88,10 @@ static inline void ax25_route_invert(ax25_digi *in, ax25_digi *out)
void ax25_rt_device_down(struct net_device *dev) void ax25_rt_device_down(struct net_device *dev)
{ {
ax25_route *s, *t, *ax25_rt = ax25_route_list; ax25_route *s, *t, *ax25_rt;
write_lock(&ax25_route_lock);
ax25_rt = ax25_route_list;
while (ax25_rt != NULL) { while (ax25_rt != NULL) {
s = ax25_rt; s = ax25_rt;
ax25_rt = ax25_rt->next; ax25_rt = ax25_rt->next;
...@@ -111,11 +115,11 @@ void ax25_rt_device_down(struct net_device *dev) ...@@ -111,11 +115,11 @@ void ax25_rt_device_down(struct net_device *dev)
} }
} }
} }
write_unlock(&ax25_route_lock);
} }
int ax25_rt_ioctl(unsigned int cmd, void *arg) int ax25_rt_ioctl(unsigned int cmd, void *arg)
{ {
unsigned long flags;
ax25_route *s, *t, *ax25_rt; ax25_route *s, *t, *ax25_rt;
struct ax25_routes_struct route; struct ax25_routes_struct route;
struct ax25_route_opt_struct rt_option; struct ax25_route_opt_struct rt_option;
...@@ -130,6 +134,7 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg) ...@@ -130,6 +134,7 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
return -EINVAL; return -EINVAL;
if (route.digi_count > AX25_MAX_DIGIS) if (route.digi_count > AX25_MAX_DIGIS)
return -EINVAL; return -EINVAL;
write_lock(ax25_route_lock);
for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) { if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) {
if (ax25_rt->digipeat != NULL) { if (ax25_rt->digipeat != NULL) {
...@@ -137,8 +142,10 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg) ...@@ -137,8 +142,10 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
ax25_rt->digipeat = NULL; ax25_rt->digipeat = NULL;
} }
if (route.digi_count != 0) { if (route.digi_count != 0) {
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
write_unlock(ax25_route_lock);
return -ENOMEM; return -ENOMEM;
}
ax25_rt->digipeat->lastrepeat = -1; ax25_rt->digipeat->lastrepeat = -1;
ax25_rt->digipeat->ndigi = route.digi_count; ax25_rt->digipeat->ndigi = route.digi_count;
for (i = 0; i < route.digi_count; i++) { for (i = 0; i < route.digi_count; i++) {
...@@ -149,14 +156,17 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg) ...@@ -149,14 +156,17 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
return 0; return 0;
} }
} }
if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
write_unlock(ax25_route_lock);
return -ENOMEM; return -ENOMEM;
}
ax25_rt->callsign = route.dest_addr; ax25_rt->callsign = route.dest_addr;
ax25_rt->dev = ax25_dev->dev; ax25_rt->dev = ax25_dev->dev;
ax25_rt->digipeat = NULL; ax25_rt->digipeat = NULL;
ax25_rt->ip_mode = ' '; ax25_rt->ip_mode = ' ';
if (route.digi_count != 0) { if (route.digi_count != 0) {
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
write_unlock(ax25_route_lock);
kfree(ax25_rt); kfree(ax25_rt);
return -ENOMEM; return -ENOMEM;
} }
...@@ -167,10 +177,10 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg) ...@@ -167,10 +177,10 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
ax25_rt->digipeat->calls[i] = route.digi_addr[i]; ax25_rt->digipeat->calls[i] = route.digi_addr[i];
} }
} }
save_flags(flags); cli();
ax25_rt->next = ax25_route_list; ax25_rt->next = ax25_route_list;
ax25_route_list = ax25_rt; ax25_route_list = ax25_rt;
restore_flags(flags); write_unlock(ax25_route_lock);
break; break;
case SIOCDELRT: case SIOCDELRT:
...@@ -208,6 +218,7 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg) ...@@ -208,6 +218,7 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
return -EFAULT; return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL) if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL)
return -EINVAL; return -EINVAL;
write_lock(ax25_route_lock);
for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) { for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) { if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) {
switch (rt_option.cmd) { switch (rt_option.cmd) {
...@@ -227,6 +238,7 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg) ...@@ -227,6 +238,7 @@ int ax25_rt_ioctl(unsigned int cmd, void *arg)
} }
} }
} }
write_unlock(ax25_route_lock);
break; break;
default: default:
...@@ -245,7 +257,7 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -245,7 +257,7 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
char *callsign; char *callsign;
int i; int i;
cli(); read_lock(&ax25_route_lock);
len += sprintf(buffer, "callsign dev mode digipeaters\n"); len += sprintf(buffer, "callsign dev mode digipeaters\n");
...@@ -286,13 +298,13 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -286,13 +298,13 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length) if (pos > offset + length)
break; break;
} }
read_unlock(&ax25_route_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;
} }
...@@ -306,6 +318,7 @@ static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev) ...@@ -306,6 +318,7 @@ static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
ax25_route *ax25_def_rt = NULL; ax25_route *ax25_def_rt = NULL;
ax25_route *ax25_rt; ax25_route *ax25_rt;
read_lock(&ax25_route_lock);
/* /*
* Bind to the physical interface we heard them on, or the default * Bind to the physical interface we heard them on, or the default
* route if none is found; * route if none is found;
...@@ -323,6 +336,7 @@ static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev) ...@@ -323,6 +336,7 @@ static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
ax25_def_rt = ax25_rt; ax25_def_rt = ax25_rt;
} }
} }
read_unlock(&ax25_route_lock);
if (ax25_spe_rt != NULL) if (ax25_spe_rt != NULL)
return ax25_spe_rt; return ax25_spe_rt;
...@@ -440,6 +454,7 @@ void __exit ax25_rt_free(void) ...@@ -440,6 +454,7 @@ void __exit ax25_rt_free(void)
{ {
ax25_route *s, *ax25_rt = ax25_route_list; ax25_route *s, *ax25_rt = ax25_route_list;
write_unlock(&ax25_route_lock);
while (ax25_rt != NULL) { while (ax25_rt != NULL) {
s = ax25_rt; s = ax25_rt;
ax25_rt = ax25_rt->next; ax25_rt = ax25_rt->next;
...@@ -449,4 +464,5 @@ void __exit ax25_rt_free(void) ...@@ -449,4 +464,5 @@ void __exit ax25_rt_free(void)
kfree(s); kfree(s);
} }
write_unlock(&ax25_route_lock);
} }
...@@ -142,7 +142,8 @@ static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frame ...@@ -142,7 +142,8 @@ static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
case AX25_DM: case AX25_DM:
case AX25_UA: case AX25_UA:
if (pf) ax25_disconnect(ax25, 0); if (pf)
ax25_disconnect(ax25, 0);
break; break;
case AX25_I: case AX25_I:
...@@ -397,7 +398,8 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame ...@@ -397,7 +398,8 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
} }
ax25_frames_acked(ax25, nr); ax25_frames_acked(ax25, nr);
if (ax25->condition & AX25_COND_OWN_RX_BUSY) { if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
if (pf) ax25_std_enquiry_response(ax25); if (pf)
ax25_std_enquiry_response(ax25);
break; break;
} }
if (ns == ax25->vr) { if (ns == ax25->vr) {
......
...@@ -47,7 +47,6 @@ ...@@ -47,7 +47,6 @@
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. */
......
...@@ -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,15 +72,21 @@ ax25_address *ax25_findbyuid(uid_t uid) ...@@ -65,15 +72,21 @@ 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:
res = -ENOENT;
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 (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
return ax25_uid->uid; res = ax25_uid->uid;
break;
} }
return -ENOENT; }
read_unlock(&ax25_uid_lock);
return res;
case SIOCAX25ADDUID: case SIOCAX25ADDUID:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
...@@ -84,40 +97,48 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) ...@@ -84,40 +97,48 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
return -EINVAL; return -EINVAL;
if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
return -ENOMEM; return -ENOMEM;
ax25_uid->uid = sax->sax25_uid; ax25_uid->uid = sax->sax25_uid;
ax25_uid->call = sax->sax25_call; ax25_uid->call = sax->sax25_call;
save_flags(flags); cli();
write_lock(&ax25_uid_lock);
ax25_uid->next = ax25_uid_list; ax25_uid->next = ax25_uid_list;
ax25_uid_list = ax25_uid; ax25_uid_list = ax25_uid;
restore_flags(flags); write_unlock(&ax25_uid_lock);
return 0; return 0;
case SIOCAX25DELUID: case SIOCAX25DELUID:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
write_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 (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
break; break;
} }
if (ax25_uid == NULL) }
if (ax25_uid == NULL) {
write_unlock(&ax25_uid_lock);
return -ENOENT; return -ENOENT;
save_flags(flags); cli(); }
if ((s = ax25_uid_list) == ax25_uid) { if ((s = ax25_uid_list) == ax25_uid) {
ax25_uid_list = s->next; ax25_uid_list = s->next;
restore_flags(flags); write_unlock(&ax25_uid_lock);
kfree(ax25_uid); kfree(ax25_uid);
return 0; return 0;
} }
while (s != NULL && s->next != NULL) { while (s != NULL && s->next != NULL) {
if (s->next == ax25_uid) { if (s->next == ax25_uid) {
s->next = ax25_uid->next; s->next = ax25_uid->next;
restore_flags(flags); write_unlock(&ax25_uid_lock);
kfree(ax25_uid); kfree(ax25_uid);
return 0; return 0;
} }
s = s->next; s = s->next;
} }
restore_flags(flags); write_unlock(&ax25_uid_lock);
return -ENOENT; return -ENOENT;
default: default:
...@@ -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