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

Resolve merge conflicts.

parents 35aa61ec e39aa73c
......@@ -3,11 +3,14 @@
*
* Alan Cox (GW4PTS) 10/11/93
*/
#ifndef _AX25_H
#define _AX25_H
#include <linux/config.h>
#include <linux/ax25.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <asm/atomic.h>
#define AX25_T1CLAMPLO 1
#define AX25_T1CLAMPHI (30 * HZ)
......@@ -147,10 +150,12 @@ typedef struct {
typedef struct ax25_route {
struct ax25_route *next;
atomic_t ref;
ax25_address callsign;
struct net_device *dev;
struct net_device *dev;
ax25_digi *digipeat;
char ip_mode;
struct timer_list timer;
} ax25_route;
typedef struct {
......@@ -197,7 +202,8 @@ typedef struct ax25_cb {
#define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo)
/* 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_insert_socket(ax25_cb *);
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 *);
/* ax25_dev.c */
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_addr_ax25dev(ax25_address *);
extern void ax25_dev_device_up(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_get_info(char *, char **, off_t, int);
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 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?
......@@ -114,6 +114,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <net/ax25.h>
......@@ -134,13 +135,15 @@
#include <linux/netfilter.h>
#include <linux/sysctl.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <net/tcp.h>
#include <net/ip.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;
......@@ -173,25 +176,25 @@ static void ax25_remove_socket(ax25_cb *ax25)
ax25_cb *s;
unsigned long flags;
save_flags(flags); cli();
spin_lock_irqsave(&ax25_list_lock, flags);
if ((s = ax25_list) == ax25) {
ax25_list = s->next;
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
return;
}
while (s != NULL && s->next != NULL) {
if (s->next == ax25) {
s->next = ax25->next;
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
return;
}
s = s->next;
}
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
}
/*
......@@ -199,24 +202,28 @@ static void ax25_remove_socket(ax25_cb *ax25)
*/
static void ax25_kill_by_device(struct net_device *dev)
{
unsigned long flags;
ax25_dev *ax25_dev;
ax25_cb *s;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return;
spin_lock_irqsave(&ax25_list_lock, flags);
for (s = ax25_list; s != NULL; s = s->next) {
if (s->ax25_dev == ax25_dev) {
s->ax25_dev = NULL;
ax25_disconnect(s, ENETUNREACH);
}
}
spin_unlock_irqrestore(&ax25_list_lock, flags);
}
/*
* Handle device status changes.
*/
static int ax25_device_event(struct notifier_block *this,unsigned long event, void *ptr)
static int ax25_device_event(struct notifier_block *this,unsigned long event,
void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
......@@ -225,16 +232,16 @@ static int ax25_device_event(struct notifier_block *this,unsigned long event, vo
return NOTIFY_DONE;
switch (event) {
case NETDEV_UP:
ax25_dev_device_up(dev);
break;
case NETDEV_DOWN:
ax25_kill_by_device(dev);
ax25_rt_device_down(dev);
ax25_dev_device_down(dev);
break;
default:
break;
case NETDEV_UP:
ax25_dev_device_up(dev);
break;
case NETDEV_DOWN:
ax25_kill_by_device(dev);
ax25_rt_device_down(dev);
ax25_dev_device_down(dev);
break;
default:
break;
}
return NOTIFY_DONE;
......@@ -247,62 +254,58 @@ void ax25_insert_socket(ax25_cb *ax25)
{
unsigned long flags;
save_flags(flags);
cli();
spin_lock_irqsave(&ax25_list_lock, flags);
ax25->next = ax25_list;
ax25_list = ax25;
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
}
/*
* Find a socket that wants to accept the SABM we have just
* received.
*/
struct sock *ax25_find_listener(ax25_address *addr, int digi, struct net_device *dev, int type)
struct sock *ax25_find_listener(ax25_address *addr, int digi,
struct net_device *dev, int type)
{
unsigned long flags;
ax25_cb *s;
save_flags(flags);
cli();
spin_lock_irqsave(&ax25_list_lock, flags);
for (s = ax25_list; s != NULL; s = s->next) {
if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
continue;
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 (s->ax25_dev == NULL || s->ax25_dev->dev == dev) {
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
return s->sk;
}
}
}
spin_unlock_irqrestore(&ax25_list_lock, flags);
restore_flags(flags);
return NULL;
}
/*
* Find an AX.25 socket given both ends.
*/
struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, int type)
struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr,
int type)
{
ax25_cb *s;
unsigned long flags;
save_flags(flags);
cli();
spin_lock_irqsave(&ax25_list_lock, flags);
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) {
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
return s->sk;
}
}
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
return NULL;
}
......@@ -311,14 +314,13 @@ struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, in
* Find an AX.25 control block given both ends. It will only pick up
* floating AX.25 control blocks or non Raw socket bound control blocks.
*/
ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi *digi, struct net_device *dev)
ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
ax25_digi *digi, struct net_device *dev)
{
ax25_cb *s;
unsigned long flags;
save_flags(flags);
cli();
spin_lock_irqsave(&ax25_list_lock, flags);
for (s = ax25_list; s != NULL; s = s->next) {
if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET)
continue;
......@@ -334,12 +336,12 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi
if (s->digipeat != NULL && s->digipeat->ndigi != 0)
continue;
}
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
return s;
}
}
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
return NULL;
}
......@@ -352,17 +354,14 @@ struct sock *ax25_addr_match(ax25_address *addr)
unsigned long flags;
ax25_cb *s;
save_flags(flags);
cli();
spin_lock_irqsave(&ax25_list_lock, flags);
for (s = ax25_list; s != NULL; s = s->next) {
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;
}
}
restore_flags(flags);
spin_unlock_irqrestore(&ax25_list_lock, flags);
return NULL;
}
......@@ -400,12 +399,12 @@ static void ax25_destroy_timer(unsigned long data)
}
/*
* This is called from user mode and the timers. Thus it protects itself against
* interrupt users but doesn't worry about being called during work.
* Once it is removed from the queue no interrupt or bottom half will
* touch it and we are (fairly 8-) ) safe.
* This is called from user mode and the timers. Thus it protects itself
* against interrupt users but doesn't worry about being called during
* work. Once it is removed from the queue no interrupt or bottom half
* will touch it and we are (fairly 8-) ) safe.
*/
void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer */
void ax25_destroy_socket(ax25_cb *ax25)
{
struct sk_buff *skb;
unsigned long flags;
......@@ -484,66 +483,66 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
return -ENOTCONN;
switch (ax25_ctl.cmd) {
case AX25_KILL:
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
case AX25_KILL:
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
#ifdef CONFIG_AX25_DAMA_SLAVE
if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
ax25_dama_off(ax25);
if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
ax25_dama_off(ax25);
#endif
ax25_disconnect(ax25, ENETRESET);
break;
ax25_disconnect(ax25, ENETRESET);
break;
case AX25_WINDOW:
if (ax25->modulus == AX25_MODULUS) {
if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
return -EINVAL;
} else {
if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
return -EINVAL;
}
ax25->window = ax25_ctl.arg;
break;
case AX25_T1:
if (ax25_ctl.arg < 1)
case AX25_WINDOW:
if (ax25->modulus == AX25_MODULUS) {
if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
return -EINVAL;
ax25->rtt = (ax25_ctl.arg * HZ) / 2;
ax25->t1 = ax25_ctl.arg * HZ;
break;
case AX25_T2:
if (ax25_ctl.arg < 1)
return -EINVAL;
ax25->t2 = ax25_ctl.arg * HZ;
break;
case AX25_N2:
if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
return -EINVAL;
ax25->n2count = 0;
ax25->n2 = ax25_ctl.arg;
break;
case AX25_T3:
if (ax25_ctl.arg < 0)
return -EINVAL;
ax25->t3 = ax25_ctl.arg * HZ;
break;
case AX25_IDLE:
if (ax25_ctl.arg < 0)
return -EINVAL;
ax25->idle = ax25_ctl.arg * 60 * HZ;
break;
case AX25_PACLEN:
if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
return -EINVAL;
ax25->paclen = ax25_ctl.arg;
break;
default:
return -EINVAL;
} else {
if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
return -EINVAL;
}
ax25->window = ax25_ctl.arg;
break;
case AX25_T1:
if (ax25_ctl.arg < 1)
return -EINVAL;
ax25->rtt = (ax25_ctl.arg * HZ) / 2;
ax25->t1 = ax25_ctl.arg * HZ;
break;
case AX25_T2:
if (ax25_ctl.arg < 1)
return -EINVAL;
ax25->t2 = ax25_ctl.arg * HZ;
break;
case AX25_N2:
if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
return -EINVAL;
ax25->n2count = 0;
ax25->n2 = ax25_ctl.arg;
break;
case AX25_T3:
if (ax25_ctl.arg < 0)
return -EINVAL;
ax25->t3 = ax25_ctl.arg * HZ;
break;
case AX25_IDLE:
if (ax25_ctl.arg < 0)
return -EINVAL;
ax25->idle = ax25_ctl.arg * 60 * HZ;
break;
case AX25_PACLEN:
if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
return -EINVAL;
ax25->paclen = ax25_ctl.arg;
break;
default:
return -EINVAL;
}
return 0;
......@@ -631,13 +630,14 @@ ax25_cb *ax25_create_cb(void)
* AX25 socket object
*/
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;
ax25_cb *ax25 = ax25_sk(sk);
ax25_cb *ax25;
struct net_device *dev;
char devname[IFNAMSIZ];
int opt;
int opt, res = 0;
if (level != SOL_AX25)
return -ENOPROTOOPT;
......@@ -648,98 +648,131 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
if (get_user(opt, (int *)optval))
return -EFAULT;
lock_kernel();
ax25 = ax25_sk(sk);
switch (optname) {
case AX25_WINDOW:
if (ax25->modulus == AX25_MODULUS) {
if (opt < 1 || opt > 7)
return -EINVAL;
} else {
if (opt < 1 || opt > 63)
return -EINVAL;
case AX25_WINDOW:
if (ax25->modulus == AX25_MODULUS) {
if (opt < 1 || opt > 7) {
res = -EINVAL;
break;
}
ax25->window = opt;
return 0;
case AX25_T1:
if (opt < 1)
return -EINVAL;
ax25->rtt = (opt * HZ) / 2;
ax25->t1 = opt * HZ;
return 0;
} else {
if (opt < 1 || opt > 63) {
res = -EINVAL;
break;
}
}
ax25->window = opt;
break;
case AX25_T2:
if (opt < 1)
return -EINVAL;
ax25->t2 = opt * HZ;
return 0;
case AX25_T1:
if (opt < 1) {
res = -EINVAL;
break;
}
ax25->rtt = (opt * HZ) / 2;
ax25->t1 = opt * HZ;
break;
case AX25_N2:
if (opt < 1 || opt > 31)
return -EINVAL;
ax25->n2 = opt;
return 0;
case AX25_T2:
if (opt < 1) {
res = -EINVAL;
break;
}
ax25->t2 = opt * HZ;
break;
case AX25_T3:
if (opt < 1)
return -EINVAL;
ax25->t3 = opt * HZ;
return 0;
case AX25_N2:
if (opt < 1 || opt > 31) {
res = -EINVAL;
break;
}
ax25->n2 = opt;
break;
case AX25_IDLE:
if (opt < 0)
return -EINVAL;
ax25->idle = opt * 60 * HZ;
return 0;
case AX25_T3:
if (opt < 1) {
res = -EINVAL;
break;
}
ax25->t3 = opt * HZ;
break;
case AX25_BACKOFF:
if (opt < 0 || opt > 2)
return -EINVAL;
ax25->backoff = opt;
return 0;
case AX25_IDLE:
if (opt < 0) {
res = -EINVAL;
break;
}
ax25->idle = opt * 60 * HZ;
break;
case AX25_EXTSEQ:
ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
return 0;
case AX25_BACKOFF:
if (opt < 0 || opt > 2) {
res = -EINVAL;
break;
}
ax25->backoff = opt;
break;
case AX25_PIDINCL:
ax25->pidincl = opt ? 1 : 0;
return 0;
case AX25_EXTSEQ:
ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
break;
case AX25_IAMDIGI:
ax25->iamdigi = opt ? 1 : 0;
return 0;
case AX25_PIDINCL:
ax25->pidincl = opt ? 1 : 0;
break;
case AX25_PACLEN:
if (opt < 16 || opt > 65535)
return -EINVAL;
ax25->paclen = opt;
return 0;
case AX25_IAMDIGI:
ax25->iamdigi = opt ? 1 : 0;
break;
case SO_BINDTODEVICE:
if (optlen > IFNAMSIZ) optlen=IFNAMSIZ;
if (copy_from_user(devname, optval, optlen))
return -EFAULT;
case AX25_PACLEN:
if (opt < 16 || opt > 65535) {
res = -EINVAL;
break;
}
ax25->paclen = opt;
break;
case SO_BINDTODEVICE:
if (optlen > IFNAMSIZ)
optlen=IFNAMSIZ;
if (copy_from_user(devname, optval, optlen)) {
res = -EFAULT;
break;
}
dev = dev_get_by_name(devname);
if (dev == NULL) return -ENODEV;
dev = dev_get_by_name(devname);
if (dev == NULL) {
res = -ENODEV;
break;
}
if (sk->type == SOCK_SEQPACKET &&
(sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN))
return -EADDRNOTAVAIL;
if (sk->type == SOCK_SEQPACKET &&
(sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) {
res = -EADDRNOTAVAIL;
break;
}
ax25->ax25_dev = ax25_dev_ax25dev(dev);
ax25_fillin_cb(ax25, ax25->ax25_dev);
return 0;
ax25->ax25_dev = ax25_dev_ax25dev(dev);
ax25_fillin_cb(ax25, ax25->ax25_dev);
break;
default:
return -ENOPROTOOPT;
default:
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;
ax25_cb *ax25 = ax25_sk(sk);
ax25_cb *ax25;
struct ax25_dev *ax25_dev;
char devname[IFNAMSIZ];
void *valptr;
......@@ -758,69 +791,74 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
valptr = (void *) &val;
length = min_t(unsigned int, maxlen, sizeof(int));
lock_kernel();
ax25 = ax25_sk(sk);
switch (optname) {
case AX25_WINDOW:
val = ax25->window;
break;
case AX25_WINDOW:
val = ax25->window;
break;
case AX25_T1:
val = ax25->t1 / HZ;
break;
case AX25_T1:
val = ax25->t1 / HZ;
break;
case AX25_T2:
val = ax25->t2 / HZ;
break;
case AX25_T2:
val = ax25->t2 / HZ;
break;
case AX25_N2:
val = ax25->n2;
break;
case AX25_N2:
val = ax25->n2;
break;
case AX25_T3:
val = ax25->t3 / HZ;
break;
case AX25_T3:
val = ax25->t3 / HZ;
break;
case AX25_IDLE:
val = ax25->idle / (60 * HZ);
break;
case AX25_IDLE:
val = ax25->idle / (60 * HZ);
break;
case AX25_BACKOFF:
val = ax25->backoff;
break;
case AX25_BACKOFF:
val = ax25->backoff;
break;
case AX25_EXTSEQ:
val = (ax25->modulus == AX25_EMODULUS);
break;
case AX25_EXTSEQ:
val = (ax25->modulus == AX25_EMODULUS);
break;
case AX25_PIDINCL:
val = ax25->pidincl;
break;
case AX25_PIDINCL:
val = ax25->pidincl;
break;
case AX25_IAMDIGI:
val = ax25->iamdigi;
break;
case AX25_IAMDIGI:
val = ax25->iamdigi;
break;
case AX25_PACLEN:
val = ax25->paclen;
break;
case SO_BINDTODEVICE:
ax25_dev = ax25->ax25_dev;
if (ax25_dev != NULL && ax25_dev->dev != NULL) {
strncpy(devname, ax25_dev->dev->name, IFNAMSIZ);
length = min_t(unsigned int, strlen(ax25_dev->dev->name)+1, maxlen);
devname[length-1] = '\0';
} else {
*devname = '\0';
length = 1;
}
case AX25_PACLEN:
val = ax25->paclen;
break;
valptr = (void *) devname;
break;
case SO_BINDTODEVICE:
ax25_dev = ax25->ax25_dev;
default:
return -ENOPROTOOPT;
if (ax25_dev != NULL && ax25_dev->dev != NULL) {
strncpy(devname, ax25_dev->dev->name, IFNAMSIZ);
length = min_t(unsigned int, strlen(ax25_dev->dev->name)+1, maxlen);
devname[length-1] = '\0';
} else {
*devname = '\0';
length = 1;
}
valptr = (void *) devname;
break;
default:
unlock_kernel();
return -ENOPROTOOPT;
}
unlock_kernel();
if (put_user(length, optlen))
return -EFAULT;
......@@ -832,11 +870,14 @@ static int ax25_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
lock_kernel();
if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) {
sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN;
unlock_kernel();
return 0;
}
unlock_kernel();
return -EOPNOTSUPP;
}
......@@ -847,46 +888,48 @@ int ax25_create(struct socket *sock, int protocol)
ax25_cb *ax25;
switch (sock->type) {
case SOCK_DGRAM:
if (protocol == 0 || protocol == PF_AX25)
protocol = AX25_P_TEXT;
case SOCK_DGRAM:
if (protocol == 0 || protocol == PF_AX25)
protocol = AX25_P_TEXT;
break;
case SOCK_SEQPACKET:
switch (protocol) {
case 0:
case PF_AX25: /* For CLX */
protocol = AX25_P_TEXT;
break;
case SOCK_SEQPACKET:
switch (protocol) {
case 0:
case PF_AX25: /* For CLX */
protocol = AX25_P_TEXT;
break;
case AX25_P_SEGMENT:
case AX25_P_SEGMENT:
#ifdef CONFIG_INET
case AX25_P_ARP:
case AX25_P_IP:
case AX25_P_ARP:
case AX25_P_IP:
#endif
#ifdef CONFIG_NETROM
case AX25_P_NETROM:
case AX25_P_NETROM:
#endif
#ifdef CONFIG_ROSE
case AX25_P_ROSE:
case AX25_P_ROSE:
#endif
return -ESOCKTNOSUPPORT;
return -ESOCKTNOSUPPORT;
#ifdef CONFIG_NETROM_MODULE
case AX25_P_NETROM:
if (ax25_protocol_is_registered(AX25_P_NETROM))
return -ESOCKTNOSUPPORT;
case AX25_P_NETROM:
if (ax25_protocol_is_registered(AX25_P_NETROM))
return -ESOCKTNOSUPPORT;
#endif
#ifdef CONFIG_ROSE_MODULE
case AX25_P_ROSE:
if (ax25_protocol_is_registered(AX25_P_ROSE))
return -ESOCKTNOSUPPORT;
case AX25_P_ROSE:
if (ax25_protocol_is_registered(AX25_P_ROSE))
return -ESOCKTNOSUPPORT;
#endif
default:
break;
}
break;
case SOCK_RAW:
break;
default:
return -ESOCKTNOSUPPORT;
break;
}
break;
case SOCK_RAW:
break;
default:
return -ESOCKTNOSUPPORT;
}
if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1, NULL)) == NULL)
......@@ -923,14 +966,14 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
}
switch (osk->type) {
case SOCK_DGRAM:
break;
case SOCK_SEQPACKET:
break;
default:
sk_free(sk);
ax25_free_cb(ax25);
return NULL;
case SOCK_DGRAM:
break;
case SOCK_SEQPACKET:
break;
default:
sk_free(sk);
ax25_free_cb(ax25);
return NULL;
}
sock_init_data(NULL, sk);
......@@ -985,58 +1028,62 @@ static int ax25_release(struct socket *sock)
struct sock *sk = sock->sk;
ax25_cb *ax25;
if (sk == NULL) return 0;
lock_kernel();
if (sk == NULL) {
unlock_kernel();
return 0;
}
ax25 = ax25_sk(sk);
if (sk->type == SOCK_SEQPACKET) {
switch (ax25->state) {
case AX25_STATE_0:
ax25_disconnect(ax25, 0);
ax25_destroy_socket(ax25);
break;
case AX25_STATE_0:
ax25_disconnect(ax25, 0);
ax25_destroy_socket(ax25);
break;
case AX25_STATE_1:
case AX25_STATE_2:
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, 0);
ax25_destroy_socket(ax25);
break;
case AX25_STATE_1:
case AX25_STATE_2:
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, 0);
ax25_destroy_socket(ax25);
break;
case AX25_STATE_3:
case AX25_STATE_4:
ax25_clear_queues(ax25);
ax25->n2count = 0;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_send_control(ax25,
AX25_DISC,
AX25_POLLON,
AX25_COMMAND);
ax25_stop_t2timer(ax25);
ax25_stop_t3timer(ax25);
ax25_stop_idletimer(ax25);
break;
case AX25_STATE_3:
case AX25_STATE_4:
ax25_clear_queues(ax25);
ax25->n2count = 0;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_send_control(ax25,
AX25_DISC,
AX25_POLLON,
AX25_COMMAND);
ax25_stop_t2timer(ax25);
ax25_stop_t3timer(ax25);
ax25_stop_idletimer(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
ax25_stop_t3timer(ax25);
ax25_stop_idletimer(ax25);
break;
#endif
}
ax25_calculate_t1(ax25);
ax25_start_t1timer(ax25);
ax25->state = AX25_STATE_2;
sk->state = TCP_CLOSE;
sk->shutdown |= SEND_SHUTDOWN;
sk->state_change(sk);
sk->dead = 1;
sk->destroy = 1;
case AX25_PROTO_DAMA_SLAVE:
ax25_stop_t3timer(ax25);
ax25_stop_idletimer(ax25);
break;
#endif
}
ax25_calculate_t1(ax25);
ax25_start_t1timer(ax25);
ax25->state = AX25_STATE_2;
sk->state = TCP_CLOSE;
sk->shutdown |= SEND_SHUTDOWN;
sk->state_change(sk);
sk->dead = 1;
sk->destroy = 1;
break;
default:
break;
default:
break;
}
} else {
sk->state = TCP_CLOSE;
......@@ -1048,6 +1095,7 @@ static int ax25_release(struct socket *sock)
sock->sk = NULL;
sk->socket = NULL; /* Not used, but we should do this */
unlock_kernel();
return 0;
}
......@@ -1066,26 +1114,35 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
ax25_address *call;
ax25_dev *ax25_dev = NULL;
if (sk->zapped == 0)
lock_kernel();
if (sk->zapped == 0) {
unlock_kernel();
return -EINVAL;
}
if (addr_len != sizeof(struct sockaddr_ax25) &&
addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */
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;
}
printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n",
current->comm);
}
if (addr->fsa_ax25.sax25_family != AF_AX25)
if (addr->fsa_ax25.sax25_family != AF_AX25) {
unlock_kernel();
return -EINVAL;
}
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;
}
if (call == NULL)
ax25->source_addr = addr->fsa_ax25.sax25_call;
......@@ -1101,11 +1158,15 @@ 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 (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;
}
} 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;
}
}
if (ax25_dev != NULL)
......@@ -1114,13 +1175,16 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
done:
ax25_insert_socket(ax25);
sk->zapped = 0;
unlock_kernel();
return 0;
}
/*
* FIXME: nonblock behaviour looks like it may have a bug.
*/
static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
{
struct sock *sk = sock->sk;
ax25_cb *ax25 = ax25_sk(sk);
......@@ -1128,24 +1192,30 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
ax25_digi *digi = NULL;
int ct = 0, err;
lock_kernel();
/* deal with restarts */
if (sock->state == SS_CONNECTING) {
switch (sk->state) {
case TCP_SYN_SENT: /* still trying */
unlock_kernel();
return -EINPROGRESS;
case TCP_ESTABLISHED: /* connection established */
unlock_kernel();
sock->state = SS_CONNECTED;
return 0;
case TCP_CLOSE: /* connection refused */
unlock_kernel();
sock->state = SS_UNCONNECTED;
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 */
}
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
......@@ -1162,15 +1232,19 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */
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;
}
printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n",
current->comm);
}
if (fsa->fsa_ax25.sax25_family != AF_AX25)
if (fsa->fsa_ax25.sax25_family != AF_AX25) {
unlock_kernel();
return -EINVAL;
}
if (ax25->digipeat != NULL) {
kfree(ax25->digipeat);
......@@ -1182,11 +1256,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) {
/* 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;
}
if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL)
if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
unlock_kernel();
return -ENOBUFS;
}
digi->ndigi = fsa->fsa_ax25.sax25_ndigis;
digi->lastrepeat = -1;
......@@ -1218,14 +1296,18 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
ax25_fillin_cb(ax25, ax25->ax25_dev);
ax25_insert_socket(ax25);
} else {
if (ax25->ax25_dev == NULL)
if (ax25->ax25_dev == NULL) {
unlock_kernel();
return -EHOSTUNREACH;
}
}
if (sk->type == SOCK_SEQPACKET &&
ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi,
ax25->ax25_dev->dev)) {
if (digi != NULL) kfree(digi);
if (digi != NULL)
kfree(digi);
unlock_kernel();
return -EADDRINUSE; /* Already such a connection */
}
......@@ -1236,6 +1318,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if (sk->type != SOCK_SEQPACKET) {
sock->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED;
unlock_kernel();
return 0;
}
......@@ -1244,21 +1327,20 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
sk->state = TCP_SYN_SENT;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_establish_data_link(ax25);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_establish_data_link(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
ax25->modulus = AX25_MODULUS;
ax25->window =
ax25->ax25_dev->values[AX25_VALUES_WINDOW];
if (ax25->ax25_dev->dama.slave)
ax25_ds_establish_data_link(ax25);
else
ax25_std_establish_data_link(ax25);
break;
case AX25_PROTO_DAMA_SLAVE:
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
if (ax25->ax25_dev->dama.slave)
ax25_ds_establish_data_link(ax25);
else
ax25_std_establish_data_link(ax25);
break;
#endif
}
......@@ -1267,30 +1349,38 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
ax25_start_heartbeat(ax25);
/* Now the loop */
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
unlock_kernel();
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 */
while (sk->state == TCP_SYN_SENT) {
interruptible_sleep_on(sk->sleep);
if (signal_pending(current)) {
sti();
add_wait_queue(sk->sleep, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (sk->state != TCP_SYN_SENT)
break;
if (!signal_pending(tsk)) {
schedule();
continue;
}
return -ERESTARTSYS;
}
current->state = TASK_RUNNING;
remove_wait_queue(sk->sleep, &wait);
}
if (sk->state != TCP_ESTABLISHED) {
/* Not in ABM, not in WAIT_UA -> failed */
sti();
sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */
}
sock->state = SS_CONNECTED;
sti();
unlock_kernel();
return 0;
}
......@@ -1302,17 +1392,26 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
struct sock *newsk;
struct sk_buff *skb;
if (sock->state != SS_UNCONNECTED)
lock_kernel();
if (sock->state != SS_UNCONNECTED) {
unlock_kernel();
return -EINVAL;
}
if ((sk = sock->sk) == NULL)
if ((sk = sock->sk) == NULL) {
unlock_kernel();
return -EINVAL;
}
if (sk->type != SOCK_SEQPACKET)
if (sk->type != SOCK_SEQPACKET) {
unlock_kernel();
return -EOPNOTSUPP;
}
if (sk->state != TCP_LISTEN)
if (sk->state != TCP_LISTEN) {
unlock_kernel();
return -EINVAL;
}
/*
* The read queue this time is holding sockets ready to use
......@@ -1320,12 +1419,16 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
*/
do {
if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
if (flags & O_NONBLOCK)
if (flags & O_NONBLOCK) {
unlock_kernel();
return -EWOULDBLOCK;
}
interruptible_sleep_on(sk->sleep);
if (signal_pending(current))
if (signal_pending(current)) {
unlock_kernel();
return -ERESTARTSYS;
}
}
} while (skb == NULL);
......@@ -1339,20 +1442,28 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
sk->ack_backlog--;
newsock->sk = newsk;
newsock->state = SS_CONNECTED;
unlock_kernel();
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;
ax25_cb *ax25 = ax25_sk(sk);
struct sock *sk;
ax25_cb *ax25;
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
unsigned char ndigi, i;
lock_kernel();
sk = sock->sk;
ax25 = ax25_sk(sk);
if (peer != 0) {
if (sk->state != TCP_ESTABLISHED)
if (sk->state != TCP_ESTABLISHED) {
unlock_kernel();
return -ENOTCONN;
}
fsa->fsa_ax25.sax25_family = AF_AX25;
fsa->fsa_ax25.sax25_call = ax25->dest_addr;
......@@ -1377,13 +1488,16 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_
}
}
*uaddr_len = sizeof (struct full_sockaddr_ax25);
unlock_kernel();
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;
ax25_cb *ax25 = ax25_sk(sk);
ax25_cb *ax25;
struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
int err;
struct sockaddr_ax25 sax;
......@@ -1395,23 +1509,34 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
int lv;
int addr_len = msg->msg_namelen;
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) {
return -EINVAL;
}
lock_kernel();
ax25 = ax25_sk(sk);
if (sk->zapped)
if (sk->zapped) {
unlock_kernel();
return -EADDRNOTAVAIL;
}
if (sk->shutdown & SEND_SHUTDOWN) {
unlock_kernel();
send_sig(SIGPIPE, current, 0);
return -EPIPE;
}
if (ax25->ax25_dev == NULL)
if (ax25->ax25_dev == NULL) {
unlock_kernel();
return -ENETUNREACH;
}
if (usax != NULL) {
if (usax->sax25_family != AF_AX25)
if (usax->sax25_family != AF_AX25) {
unlock_kernel();
return -EINVAL;
}
if (addr_len == sizeof(struct sockaddr_ax25)) {
printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n",
......@@ -1420,8 +1545,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */
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;
}
printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n",
current->comm);
......@@ -1432,8 +1559,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax;
/* 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;
}
dtmp.ndigi = usax->sax25_ndigis;
......@@ -1447,8 +1576,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
}
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;
}
if (usax->sax25_ndigis == 0)
dp = NULL;
else
......@@ -1474,8 +1605,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Assume the worst case */
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;
}
skb_reserve(skb, size - len);
......@@ -1497,11 +1630,13 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Connected mode sockets go via the LAPB machine */
if (sk->state != TCP_ESTABLISHED) {
kfree_skb(skb);
unlock_kernel();
return -ENOTCONN;
}
/* Shove it onto the queue and kick */
ax25_output(ax25, ax25->paclen, skb);
unlock_kernel();
return len;
} else {
......@@ -1529,28 +1664,37 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
skb->dev = ax25->ax25_dev->dev;
ax25_queue_xmit(skb);
unlock_kernel();
return len;
}
}
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;
struct sk_buff *skb;
int er;
lock_kernel();
sk = sock->sk;
/*
* This works for seqpacket too. The receiver has ordered the
* 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;
}
/* 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;
}
if (!ax25_sk(sk)->pidincl)
skb_pull(skb, 1); /* Remove PID */
......@@ -1590,6 +1734,7 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f
}
skb_free_datagram(sk, skb);
unlock_kernel();
return copied;
}
......@@ -1603,148 +1748,185 @@ static int ax25_shutdown(struct socket *sk, int how)
static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
int res = 0;
lock_kernel();
switch (cmd) {
case TIOCOUTQ: {
long amount;
amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if (amount < 0)
amount = 0;
return put_user(amount, (int *)arg);
}
case TIOCINQ: {
struct sk_buff *skb;
long amount = 0L;
/* These two are safe on a single CPU system as only user tasks fiddle here */
if ((skb = skb_peek(&sk->receive_queue)) != NULL)
amount = skb->len;
return put_user(amount, (int *)arg);
}
case TIOCOUTQ: {
long amount;
amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
if (amount < 0)
amount = 0;
res = put_user(amount, (int *)arg);
break;
}
case SIOCGSTAMP:
if (sk != NULL) {
if (sk->stamp.tv_sec == 0)
return -ENOENT;
return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
}
return -EINVAL;
case TIOCINQ: {
struct sk_buff *skb;
long amount = 0L;
/* These two are safe on a single CPU system as only user tasks fiddle here */
if ((skb = skb_peek(&sk->receive_queue)) != NULL)
amount = skb->len;
res = put_user(amount, (int *)arg);
break;
}
case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */
case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
case SIOCAX25GETUID: {
struct sockaddr_ax25 sax25;
if (copy_from_user(&sax25, (void *)arg, sizeof(sax25)))
return -EFAULT;
return ax25_uid_ioctl(cmd, &sax25);
case SIOCGSTAMP:
if (sk != NULL) {
if (sk->stamp.tv_sec == 0) {
res = -ENOENT;
break;
}
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 SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
case SIOCAX25GETUID: {
struct sockaddr_ax25 sax25;
if (copy_from_user(&sax25, (void *)arg, sizeof(sax25))) {
res = -EFAULT;
break;
}
res = ax25_uid_ioctl(cmd, &sax25);
break;
}
case SIOCAX25NOUID: { /* Set the default policy (default/bar) */
long amount;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (get_user(amount, (long *)arg))
return -EFAULT;
if (amount > AX25_NOUID_BLOCK)
return -EINVAL;
ax25_uid_policy = amount;
return 0;
case SIOCAX25NOUID: { /* Set the default policy (default/bar) */
long amount;
if (!capable(CAP_NET_ADMIN)) {
res = -EPERM;
break;
}
if (get_user(amount, (long *)arg)) {
res = -EFAULT;
break;
}
if (amount > AX25_NOUID_BLOCK) {
res = -EINVAL;
break;
}
ax25_uid_policy = amount;
res = 0;
break;
}
case SIOCADDRT:
case SIOCDELRT:
case SIOCAX25OPTRT:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
return ax25_rt_ioctl(cmd, (void *)arg);
case SIOCAX25CTLCON:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
return ax25_ctl_ioctl(cmd, (void *)arg);
case SIOCAX25GETINFO:
case SIOCAX25GETINFOOLD: {
ax25_cb *ax25 = ax25_sk(sk);
struct ax25_info_struct ax25_info;
ax25_info.t1 = ax25->t1 / HZ;
ax25_info.t2 = ax25->t2 / HZ;
ax25_info.t3 = ax25->t3 / HZ;
ax25_info.idle = ax25->idle / (60 * HZ);
ax25_info.n2 = ax25->n2;
ax25_info.t1timer = ax25_display_timer(&ax25->t1timer) / HZ;
ax25_info.t2timer = ax25_display_timer(&ax25->t2timer) / HZ;
ax25_info.t3timer = ax25_display_timer(&ax25->t3timer) / HZ;
ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ);
ax25_info.n2count = ax25->n2count;
ax25_info.state = ax25->state;
ax25_info.rcv_q = atomic_read(&sk->rmem_alloc);
ax25_info.snd_q = atomic_read(&sk->wmem_alloc);
ax25_info.vs = ax25->vs;
ax25_info.vr = ax25->vr;
ax25_info.va = ax25->va;
ax25_info.vs_max = ax25->vs; /* reserved */
ax25_info.paclen = ax25->paclen;
ax25_info.window = ax25->window;
/* old structure? */
if (cmd == SIOCAX25GETINFOOLD) {
static int warned = 0;
if (!warned) {
printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",
current->comm);
warned=1;
}
if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated)))
return -EFAULT;
} else {
if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct)))
return -EINVAL;
}
return 0;
case SIOCADDRT:
case SIOCDELRT:
case SIOCAX25OPTRT:
if (!capable(CAP_NET_ADMIN)) {
res = -EPERM;
break;
}
res = ax25_rt_ioctl(cmd, (void *)arg);
break;
case SIOCAX25ADDFWD:
case SIOCAX25DELFWD: {
struct ax25_fwd_struct ax25_fwd;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd)))
return -EFAULT;
return ax25_fwd_ioctl(cmd, &ax25_fwd);
case SIOCAX25CTLCON:
if (!capable(CAP_NET_ADMIN)) {
res = -EPERM;
break;
}
res = ax25_ctl_ioctl(cmd, (void *)arg);
break;
case SIOCAX25GETINFO:
case SIOCAX25GETINFOOLD: {
ax25_cb *ax25 = ax25_sk(sk);
struct ax25_info_struct ax25_info;
ax25_info.t1 = ax25->t1 / HZ;
ax25_info.t2 = ax25->t2 / HZ;
ax25_info.t3 = ax25->t3 / HZ;
ax25_info.idle = ax25->idle / (60 * HZ);
ax25_info.n2 = ax25->n2;
ax25_info.t1timer = ax25_display_timer(&ax25->t1timer) / HZ;
ax25_info.t2timer = ax25_display_timer(&ax25->t2timer) / HZ;
ax25_info.t3timer = ax25_display_timer(&ax25->t3timer) / HZ;
ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ);
ax25_info.n2count = ax25->n2count;
ax25_info.state = ax25->state;
ax25_info.rcv_q = atomic_read(&sk->rmem_alloc);
ax25_info.snd_q = atomic_read(&sk->wmem_alloc);
ax25_info.vs = ax25->vs;
ax25_info.vr = ax25->vr;
ax25_info.va = ax25->va;
ax25_info.vs_max = ax25->vs; /* reserved */
ax25_info.paclen = ax25->paclen;
ax25_info.window = ax25->window;
/* old structure? */
if (cmd == SIOCAX25GETINFOOLD) {
static int warned = 0;
if (!warned) {
printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",
current->comm);
warned=1;
}
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
case SIOCSIFDSTADDR:
case SIOCGIFBRDADDR:
case SIOCSIFBRDADDR:
case SIOCGIFNETMASK:
case SIOCSIFNETMASK:
case SIOCGIFMETRIC:
case SIOCSIFMETRIC:
return -EINVAL;
if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated))) {
res = -EFAULT;
break;
}
} else {
if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) {
res = -EINVAL;
break;
}
}
res = 0;
break;
}
default:
return dev_ioctl(cmd, (void *)arg);
case SIOCAX25ADDFWD:
case SIOCAX25DELFWD: {
struct ax25_fwd_struct ax25_fwd;
if (!capable(CAP_NET_ADMIN)) {
res = -EPERM;
break;
}
if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) {
res = -EFAULT;
break;
}
res = ax25_fwd_ioctl(cmd, &ax25_fwd);
break;
}
/*NOTREACHED*/
return 0;
case SIOCGIFADDR:
case SIOCSIFADDR:
case SIOCGIFDSTADDR:
case SIOCSIFDSTADDR:
case SIOCGIFBRDADDR:
case SIOCSIFBRDADDR:
case SIOCGIFNETMASK:
case SIOCSIFNETMASK:
case SIOCGIFMETRIC:
case SIOCSIFMETRIC:
res = -EINVAL;
break;
default:
res = dev_ioctl(cmd, (void *)arg);
break;
}
unlock_kernel();
return res;
}
static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
{
unsigned long flags;
ax25_cb *ax25;
int k;
int len = 0;
off_t pos = 0;
off_t begin = 0;
cli();
spin_lock_irqsave(&ax25_list_lock, flags);
/*
* New format:
......@@ -1799,7 +1981,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
break;
}
sti();
spin_unlock_irqrestore(&ax25_list_lock, flags);
*start = buffer + (offset - begin);
len -= (offset - begin);
......@@ -1814,7 +1996,6 @@ static struct net_proto_family ax25_family_ops = {
.create = ax25_create,
};
static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {
.family = PF_AX25,
.release = ax25_release,
......@@ -1835,15 +2016,14 @@ static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {
.sendpage = sock_no_sendpage,
};
#include <linux/smp_lock.h>
SOCKOPS_WRAP(ax25_proto, PF_AX25);
/*
* Called by socket.c on kernel start up
*/
static struct packet_type ax25_packet_type = {
.type = __constant_htons(ETH_P_AX25),
.func = ax25_kiss_rcv,
.type = __constant_htons(ETH_P_AX25),
.dev = NULL, /* All devices */
.func = ax25_kiss_rcv,
.data = (void *) 1
};
static struct notifier_block ax25_dev_notifier = {
......
......@@ -27,6 +27,7 @@
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
......@@ -41,27 +42,37 @@
#include <linux/init.h>
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;
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)
if (ax25_dev->dev == dev)
return ax25_dev;
if (ax25_dev->dev == 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_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)
if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0)
return ax25_dev;
if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) {
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)
ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL;
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_list = ax25_dev;
restore_flags(flags);
spin_unlock_irqrestore(&ax25_dev_lock, flags);
ax25_register_sysctl();
}
......@@ -118,7 +129,7 @@ void ax25_dev_device_down(struct net_device *dev)
ax25_unregister_sysctl();
save_flags(flags); cli();
spin_lock_irqsave(&ax25_dev_lock, flags);
#ifdef CONFIG_AX25_DAMA_SLAVE
ax25_ds_del_timer(ax25_dev);
......@@ -133,7 +144,7 @@ void ax25_dev_device_down(struct net_device *dev)
if ((s = ax25_dev_list) == ax25_dev) {
ax25_dev_list = s->next;
restore_flags(flags);
spin_unlock_irqrestore(&ax25_dev_lock, flags);
kfree(ax25_dev);
ax25_register_sysctl();
return;
......@@ -142,7 +153,7 @@ void ax25_dev_device_down(struct net_device *dev)
while (s != NULL && s->next != NULL) {
if (s->next == ax25_dev) {
s->next = ax25_dev->next;
restore_flags(flags);
spin_unlock_irqrestore(&ax25_dev_lock, flags);
kfree(ax25_dev);
ax25_register_sysctl();
return;
......@@ -150,8 +161,8 @@ void ax25_dev_device_down(struct net_device *dev)
s = s->next;
}
spin_unlock_irqrestore(&ax25_dev_lock, flags);
restore_flags(flags);
ax25_register_sysctl();
}
......@@ -163,22 +174,22 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
return -EINVAL;
switch (cmd) {
case SIOCAX25ADDFWD:
if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
return -EINVAL;
if (ax25_dev->forward != NULL)
return -EINVAL;
ax25_dev->forward = fwd_dev->dev;
break;
case SIOCAX25DELFWD:
if (ax25_dev->forward == NULL)
return -EINVAL;
ax25_dev->forward = NULL;
break;
case SIOCAX25ADDFWD:
if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
return -EINVAL;
if (ax25_dev->forward != NULL)
return -EINVAL;
ax25_dev->forward = fwd_dev->dev;
break;
default:
case SIOCAX25DELFWD:
if (ax25_dev->forward == NULL)
return -EINVAL;
ax25_dev->forward = NULL;
break;
default:
return -EINVAL;
}
return 0;
......@@ -202,12 +213,17 @@ struct net_device *ax25_fwd_dev(struct net_device *dev)
*/
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) {
s = ax25_dev;
ax25_dev = ax25_dev->next;
kfree(s);
}
ax25_dev_list = NULL;
spin_unlock_irqrestore(&ax25_dev_lock, flags);
}
......@@ -53,54 +53,56 @@
static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
switch (frametype) {
case AX25_SABM:
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
break;
case AX25_SABM:
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
break;
case AX25_SABME:
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
break;
case AX25_UA:
ax25_calculate_rtt(ax25);
ax25_stop_t1timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25->state = AX25_STATE_3;
ax25->n2count = 0;
if (ax25->sk != NULL) {
ax25->sk->state = TCP_ESTABLISHED;
/* For WAIT_SABM connections we will produce an accept ready socket here */
if (!ax25->sk->dead)
ax25->sk->state_change(ax25->sk);
}
ax25_dama_on(ax25);
/* according to DK4EGs spec we are required to
* send a RR RESPONSE FINAL NR=0.
*/
ax25_std_enquiry_response(ax25);
break;
case AX25_DM:
if (pf) ax25_disconnect(ax25, ECONNREFUSED);
break;
default:
if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
break;
case AX25_SABME:
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
break;
case AX25_UA:
ax25_calculate_rtt(ax25);
ax25_stop_t1timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25->state = AX25_STATE_3;
ax25->n2count = 0;
if (ax25->sk != NULL) {
ax25->sk->state = TCP_ESTABLISHED;
/* For WAIT_SABM connections we will produce an accept ready socket here */
if (!ax25->sk->dead)
ax25->sk->state_change(ax25->sk);
}
ax25_dama_on(ax25);
/* according to DK4EGs spec we are required to
* send a RR RESPONSE FINAL NR=0.
*/
ax25_std_enquiry_response(ax25);
break;
case AX25_DM:
if (pf)
ax25_disconnect(ax25, ECONNREFUSED);
break;
default:
if (pf)
ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
break;
}
return 0;
......@@ -114,38 +116,38 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
static int ax25_ds_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
switch (frametype) {
case AX25_SABM:
case AX25_SABME:
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_dama_off(ax25);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
case AX25_SABM:
case AX25_SABME:
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_dama_off(ax25);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_dama_off(ax25);
ax25_disconnect(ax25, 0);
break;
case AX25_DM:
case AX25_UA:
if (pf) {
ax25_dama_off(ax25);
ax25_disconnect(ax25, 0);
break;
case AX25_DM:
case AX25_UA:
if (pf) {
ax25_dama_off(ax25);
ax25_disconnect(ax25, 0);
}
break;
case AX25_I:
case AX25_REJ:
case AX25_RNR:
case AX25_RR:
if (pf) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_dama_off(ax25);
}
break;
}
break;
case AX25_I:
case AX25_REJ:
case AX25_RNR:
case AX25_RR:
if (pf) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_dama_off(ax25);
}
break;
default:
break;
default:
break;
}
return 0;
......@@ -161,127 +163,127 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
int queued = 0;
switch (frametype) {
case AX25_SABM:
case AX25_SABME:
if (frametype == AX25_SABM) {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
} else {
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
}
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_stop_t1timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->condition = 0x00;
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25_requeue_frames(ax25);
ax25_dama_on(ax25);
break;
case AX25_SABM:
case AX25_SABME:
if (frametype == AX25_SABM) {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
} else {
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
}
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_stop_t1timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->condition = 0x00;
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25_requeue_frames(ax25);
ax25_dama_on(ax25);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_dama_off(ax25);
ax25_disconnect(ax25, 0);
break;
case AX25_DM:
ax25_dama_off(ax25);
ax25_disconnect(ax25, ECONNRESET);
break;
case AX25_RR:
case AX25_RNR:
if (frametype == AX25_RR)
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
else
ax25->condition |= AX25_COND_PEER_RX_BUSY;
if (ax25_validate_nr(ax25, nr)) {
if (ax25_check_iframes_acked(ax25, nr))
ax25->n2count=0;
if (type == AX25_COMMAND && pf)
ax25_ds_enquiry_response(ax25);
} else {
ax25_ds_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_dama_off(ax25);
ax25_disconnect(ax25, 0);
break;
case AX25_REJ:
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
case AX25_DM:
ax25_dama_off(ax25);
ax25_disconnect(ax25, ECONNRESET);
break;
if (ax25_validate_nr(ax25, nr)) {
if (ax25->va != nr)
ax25->n2count=0;
case AX25_RR:
case AX25_RNR:
if (frametype == AX25_RR)
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
else
ax25->condition |= AX25_COND_PEER_RX_BUSY;
if (ax25_validate_nr(ax25, nr)) {
if (ax25_check_iframes_acked(ax25, nr))
ax25->n2count=0;
if (type == AX25_COMMAND && pf)
ax25_ds_enquiry_response(ax25);
} else {
ax25_ds_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
case AX25_REJ:
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
if (ax25_validate_nr(ax25, nr)) {
if (ax25->va != nr)
ax25->n2count=0;
ax25_frames_acked(ax25, nr);
ax25_calculate_rtt(ax25);
ax25_stop_t1timer(ax25);
ax25_start_t3timer(ax25);
ax25_requeue_frames(ax25);
ax25_frames_acked(ax25, nr);
ax25_calculate_rtt(ax25);
ax25_stop_t1timer(ax25);
ax25_start_t3timer(ax25);
ax25_requeue_frames(ax25);
if (type == AX25_COMMAND && pf)
ax25_ds_enquiry_response(ax25);
} else {
ax25_ds_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
if (type == AX25_COMMAND && pf)
ax25_ds_enquiry_response(ax25);
} else {
ax25_ds_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
case AX25_I:
if (!ax25_validate_nr(ax25, nr)) {
ax25_ds_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
break;
case AX25_I:
if (!ax25_validate_nr(ax25, nr)) {
ax25_ds_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
break;
}
if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
ax25_frames_acked(ax25, nr);
}
if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
ax25_frames_acked(ax25, nr);
ax25->n2count = 0;
} else {
if (ax25_check_iframes_acked(ax25, nr))
ax25->n2count = 0;
}
if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
if (pf) ax25_ds_enquiry_response(ax25);
break;
}
if (ns == ax25->vr) {
ax25->vr = (ax25->vr + 1) % ax25->modulus;
queued = ax25_rx_iframe(ax25, skb);
if (ax25->condition & AX25_COND_OWN_RX_BUSY)
ax25->vr = ns; /* ax25->vr - 1 */
ax25->condition &= ~AX25_COND_REJECT;
if (pf) {
ax25_ds_enquiry_response(ax25);
} else {
if (ax25_check_iframes_acked(ax25, nr))
ax25->n2count = 0;
if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
ax25->condition |= AX25_COND_ACK_PENDING;
ax25_start_t2timer(ax25);
}
}
if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
} else {
if (ax25->condition & AX25_COND_REJECT) {
if (pf) ax25_ds_enquiry_response(ax25);
break;
}
if (ns == ax25->vr) {
ax25->vr = (ax25->vr + 1) % ax25->modulus;
queued = ax25_rx_iframe(ax25, skb);
if (ax25->condition & AX25_COND_OWN_RX_BUSY)
ax25->vr = ns; /* ax25->vr - 1 */
ax25->condition &= ~AX25_COND_REJECT;
if (pf) {
ax25_ds_enquiry_response(ax25);
} else {
if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
ax25->condition |= AX25_COND_ACK_PENDING;
ax25_start_t2timer(ax25);
}
}
} else {
if (ax25->condition & AX25_COND_REJECT) {
if (pf) ax25_ds_enquiry_response(ax25);
} else {
ax25->condition |= AX25_COND_REJECT;
ax25_ds_enquiry_response(ax25);
ax25->condition &= ~AX25_COND_ACK_PENDING;
}
ax25->condition |= AX25_COND_REJECT;
ax25_ds_enquiry_response(ax25);
ax25->condition &= ~AX25_COND_ACK_PENDING;
}
break;
}
break;
case AX25_FRMR:
case AX25_ILLEGAL:
ax25_ds_establish_data_link(ax25);
ax25->state = AX25_STATE_1;
break;
case AX25_FRMR:
case AX25_ILLEGAL:
ax25_ds_establish_data_link(ax25);
ax25->state = AX25_STATE_1;
break;
default:
break;
default:
break;
}
return queued;
......@@ -297,15 +299,15 @@ int ax25_ds_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
switch (ax25->state) {
case AX25_STATE_1:
queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_2:
queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_3:
queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
break;
case AX25_STATE_1:
queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_2:
queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_3:
queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
break;
}
return queued;
......
......@@ -31,6 +31,7 @@
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <linux/inet.h>
......@@ -53,6 +54,7 @@ void ax25_ds_nr_error_recovery(ax25_cb *ax25)
*/
void ax25_ds_enquiry_response(ax25_cb *ax25)
{
unsigned long flags;
ax25_cb *ax25o;
/* Please note that neither DK4EGs nor DG2FEFs
......@@ -93,6 +95,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
ax25_start_t3timer(ax25);
ax25_ds_set_timer(ax25->ax25_dev);
spin_lock_irqsave(&ax25_list_lock, flags);
for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
if (ax25o == ax25)
continue;
......@@ -118,6 +121,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
if (ax25o->state != AX25_STATE_0)
ax25_start_t3timer(ax25o);
}
spin_unlock_irqrestore(&ax25_list_lock, flags);
}
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
*/
static int ax25_check_dama_slave(ax25_dev *ax25_dev)
{
unsigned long flags;
ax25_cb *ax25;
int res = 0;
spin_lock_irqsave(&ax25_list_lock, flags);
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)
return 1;
if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) {
res = 1;
break;
}
spin_unlock_irqrestore(&ax25_list_lock, flags);
return 0;
return res;
}
void ax25_dev_dama_on(ax25_dev *ax25_dev)
......
......@@ -18,6 +18,7 @@
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/spinlock.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
......@@ -58,7 +59,8 @@ static void ax25_ds_add_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)
......@@ -79,6 +81,7 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev)
static void ax25_ds_timeout(unsigned long arg)
{
ax25_dev *ax25_dev = (struct ax25_dev *) arg;
unsigned long flags;
ax25_cb *ax25;
if (ax25_dev == NULL || !ax25_dev->dama.slave)
......@@ -89,6 +92,7 @@ static void ax25_ds_timeout(unsigned long arg)
return;
}
spin_lock_irqsave(&ax25_list_lock, flags);
for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) {
if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
continue;
......@@ -96,6 +100,7 @@ static void ax25_ds_timeout(unsigned long arg)
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT);
}
spin_unlock_irqrestore(&ax25_list_lock, flags);
ax25_dev_dama_off(ax25_dev);
}
......@@ -104,28 +109,28 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
{
switch (ax25->state) {
case AX25_STATE_0:
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
ax25_destroy_socket(ax25);
return;
}
break;
case AX25_STATE_3:
/*
* Check the state of the receive buffer.
*/
if (ax25->sk != NULL) {
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_ACK_PENDING;
break;
}
case AX25_STATE_0:
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
ax25_destroy_socket(ax25);
return;
}
break;
case AX25_STATE_3:
/*
* Check the state of the receive buffer.
*/
if (ax25->sk != NULL) {
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_ACK_PENDING;
break;
}
break;
}
break;
}
ax25_start_heartbeat(ax25);
......@@ -178,46 +183,45 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
void ax25_ds_t1_timeout(ax25_cb *ax25)
{
switch (ax25->state) {
case AX25_STATE_1:
if (ax25->n2count == ax25->n2) {
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);
case AX25_STATE_1:
if (ax25->n2count == ax25->n2) {
if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
return;
} 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);
......
......@@ -20,6 +20,7 @@
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
......@@ -40,22 +41,25 @@ static struct protocol_struct {
unsigned int pid;
int (*func)(struct sk_buff *, ax25_cb *);
} *protocol_list;
static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED;
static struct linkfail_struct {
struct linkfail_struct *next;
void (*func)(ax25_cb *, int);
} *linkfail_list;
static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED;
static struct listen_struct {
struct listen_struct *next;
ax25_address callsign;
struct net_device *dev;
} *listen_list;
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;
unsigned long flags;
if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT)
return 0;
......@@ -69,31 +73,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_
protocol->pid = pid;
protocol->func = func;
save_flags(flags);
cli();
write_lock(&protocol_list_lock);
protocol->next = protocol_list;
protocol_list = protocol;
restore_flags(flags);
write_unlock(&protocol_list_lock);
return 1;
}
void ax25_protocol_release(unsigned int pid)
{
struct protocol_struct *s, *protocol = protocol_list;
unsigned long flags;
struct protocol_struct *s, *protocol;
if (protocol == NULL)
write_lock(&protocol_list_lock);
protocol = protocol_list;
if (protocol == NULL) {
write_unlock(&protocol_list_lock);
return;
save_flags(flags);
cli();
}
if (protocol->pid == pid) {
protocol_list = protocol->next;
restore_flags(flags);
write_unlock(&protocol_list_lock);
kfree(protocol);
return;
}
......@@ -102,15 +103,14 @@ void ax25_protocol_release(unsigned int pid)
if (protocol->next->pid == pid) {
s = protocol->next;
protocol->next = protocol->next->next;
restore_flags(flags);
write_unlock(&protocol_list_lock);
kfree(s);
return;
}
protocol = protocol->next;
}
restore_flags(flags);
write_unlock(&protocol_list_lock);
}
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;
save_flags(flags);
cli();
spin_lock_irqsave(&linkfail_lock, flags);
linkfail->next = linkfail_list;
linkfail_list = linkfail;
restore_flags(flags);
spin_unlock_irqrestore(&linkfail_lock, flags);
return 1;
}
void ax25_linkfail_release(void (*func)(ax25_cb *, int))
{
struct linkfail_struct *s, *linkfail = linkfail_list;
struct linkfail_struct *s, *linkfail;
unsigned long flags;
spin_lock_irqsave(&linkfail_lock, flags);
linkfail = linkfail_list;
if (linkfail == NULL)
return;
save_flags(flags);
cli();
if (linkfail->func == func) {
linkfail_list = linkfail->next;
restore_flags(flags);
spin_unlock_irqrestore(&linkfail_lock, flags);
kfree(linkfail);
return;
}
......@@ -156,15 +152,14 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int))
if (linkfail->next->func == func) {
s = linkfail->next;
linkfail->next = linkfail->next->next;
restore_flags(flags);
spin_unlock_irqrestore(&linkfail_lock, flags);
kfree(s);
return;
}
linkfail = linkfail->next;
}
restore_flags(flags);
spin_unlock_irqrestore(&linkfail_lock, flags);
}
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->dev = dev;
save_flags(flags);
cli();
spin_lock_irqsave(&listen_lock, flags);
listen->next = listen_list;
listen_list = listen;
restore_flags(flags);
spin_unlock_irqrestore(&listen_lock, flags);
return 1;
}
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;
spin_lock_irqsave(&listen_lock, flags);
listen = listen_list;
if (listen == NULL)
return;
save_flags(flags);
cli();
if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
listen_list = listen->next;
restore_flags(flags);
spin_unlock_irqrestore(&listen_lock, flags);
kfree(listen);
return;
}
......@@ -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) {
s = listen->next;
listen->next = listen->next->next;
restore_flags(flags);
spin_unlock_irqrestore(&listen_lock, flags);
kfree(s);
return;
}
listen = listen->next;
}
restore_flags(flags);
spin_unlock_irqrestore(&listen_lock, flags);
}
int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
{
int (*res)(struct sk_buff *, ax25_cb *) = NULL;
struct protocol_struct *protocol;
read_lock(&protocol_list_lock);
for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
if (protocol->pid == pid)
return protocol->func;
if (protocol->pid == pid) {
res = protocol->func;
break;
}
read_unlock(&protocol_list_lock);
return NULL;
return res;
}
int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
{
struct listen_struct *listen;
unsigned long flags;
spin_lock_irqsave(&listen_lock, flags);
for (listen = listen_list; listen != NULL; listen = listen->next)
if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL))
return 1;
spin_unlock_irqrestore(&listen_lock, flags);
return 0;
}
......@@ -250,19 +248,26 @@ int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
void ax25_link_failed(ax25_cb *ax25, int reason)
{
struct linkfail_struct *linkfail;
unsigned long flags;
spin_lock_irqsave(&linkfail_lock, flags);
for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
(linkfail->func)(ax25, reason);
spin_unlock_irqrestore(&linkfail_lock, flags);
}
int ax25_protocol_is_registered(unsigned int pid)
{
struct protocol_struct *protocol;
int res = 0;
read_lock(&protocol_list_lock);
for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
if (protocol->pid == pid)
return 1;
if (protocol->pid == pid) {
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
return 0;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
queued = ax25_std_frame_in(ax25, skb, type);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
queued = ax25_std_frame_in(ax25, skb, type);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
if (dama || ax25->ax25_dev->dama.slave)
queued = ax25_ds_frame_in(ax25, skb, type);
else
queued = ax25_std_frame_in(ax25, skb, type);
break;
case AX25_PROTO_DAMA_SLAVE:
if (dama || ax25->ax25_dev->dama.slave)
queued = ax25_ds_frame_in(ax25, skb, type);
else
queued = ax25_std_frame_in(ax25, skb, type);
break;
#endif
}
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 *sk;
......@@ -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 */
switch (skb->data[1]) {
#ifdef CONFIG_INET
case AX25_P_IP:
skb_pull(skb,2); /* drop PID/CTRL */
skb->h.raw = skb->data;
skb->nh.raw = skb->data;
skb->dev = dev;
skb->pkt_type = PACKET_HOST;
skb->protocol = htons(ETH_P_IP);
ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */
break;
case AX25_P_ARP:
skb_pull(skb,2);
skb->h.raw = skb->data;
skb->nh.raw = skb->data;
skb->dev = dev;
skb->pkt_type = PACKET_HOST;
skb->protocol = htons(ETH_P_ARP);
arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */
break;
case AX25_P_IP:
skb_pull(skb,2); /* drop PID/CTRL */
skb->h.raw = skb->data;
skb->nh.raw = skb->data;
skb->dev = dev;
skb->pkt_type = PACKET_HOST;
skb->protocol = htons(ETH_P_IP);
ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */
break;
case AX25_P_ARP:
skb_pull(skb,2);
skb->h.raw = skb->data;
skb->nh.raw = skb->data;
skb->dev = dev;
skb->pkt_type = PACKET_HOST;
skb->protocol = htons(ETH_P_ARP);
arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */
break;
#endif
case AX25_P_TEXT:
/* Now find a suitable dgram socket */
if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) {
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 {
case AX25_P_TEXT:
/* Now find a suitable dgram socket */
if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) {
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);
}
break;
} else {
kfree_skb(skb);
}
break;
default:
kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */
break;
default:
kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */
break;
}
return 0;
......@@ -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);
}
......@@ -88,16 +88,16 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short
/* Append a suitable AX.25 PID */
switch (type) {
case ETH_P_IP:
*buff++ = AX25_P_IP;
break;
case ETH_P_ARP:
*buff++ = AX25_P_ARP;
break;
default:
printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
*buff++ = 0;
break;
case ETH_P_IP:
*buff++ = AX25_P_IP;
break;
case ETH_P_ARP:
*buff++ = AX25_P_ARP;
break;
default:
printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
*buff++ = 0;
break;
}
if (daddr != NULL)
......@@ -112,8 +112,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
unsigned char *bp = skb->data;
struct net_device *dev;
ax25_address *src, *dst;
ax25_route *route;
ax25_dev *ax25_dev;
ax25_route _route, *route = &_route;
dst = (ax25_address *)(bp + 1);
src = (ax25_address *)(bp + 8);
......@@ -121,14 +121,15 @@ int ax25_rebuild_header(struct sk_buff *skb)
if (arp_find(bp + 1, skb))
return 1;
route = ax25_rt_find_route(dst, NULL);
route = ax25_rt_find_route(route, dst, NULL);
dev = route->dev;
if (dev == NULL)
dev = skb->dev;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return 1;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
goto put;
}
if (bp[16] == AX25_P_IP) {
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)
if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
kfree_skb(skb);
return 1;
goto put;
}
if (skb->sk != NULL)
......@@ -170,7 +171,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c,
&dst_c, route->digipeat, dev);
return 1;
goto put;
}
}
......@@ -187,7 +188,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if (route->digipeat != NULL) {
if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
kfree_skb(skb);
return 1;
goto put;
}
skb = ourskb;
......@@ -197,6 +198,9 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_queue_xmit(skb);
put:
ax25_put_route(route);
return 1;
}
......
......@@ -44,6 +44,7 @@
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <linux/inet.h>
......@@ -57,6 +58,8 @@
#include <linux/mm.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_dev *ax25_dev;
......@@ -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]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_establish_data_link(ax25);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_establish_data_link(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
if (ax25_dev->dama.slave)
ax25_ds_establish_data_link(ax25);
else
ax25_std_establish_data_link(ax25);
break;
case AX25_PROTO_DAMA_SLAVE:
if (ax25_dev->dama.slave)
ax25_ds_establish_data_link(ax25);
else
ax25_std_establish_data_link(ax25);
break;
#endif
}
......@@ -155,11 +158,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
frontlen = skb_headroom(skb); /* Address space + CTRL */
while (skb->len > 0) {
save_flags(flags);
cli();
spin_lock_irqsave(&ax25_frag_lock, flags);
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");
return;
}
......@@ -167,7 +168,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
if (skb->sk != NULL)
skb_set_owner_w(skbn, skb->sk);
restore_flags(flags);
spin_unlock_irqrestore(&ax25_frag_lock, flags);
len = (paclen > skb->len) ? skb->len : paclen;
......@@ -202,19 +203,19 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
}
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_kick(ax25);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_kick(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
/*
* A DAMA slave is _required_ to work as normal AX.25L2V2
* if no DAMA master is available.
*/
case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25);
break;
/*
* A DAMA slave is _required_ to work as normal AX.25L2V2
* if no DAMA master is available.
*/
case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25);
break;
#endif
}
}
......@@ -305,15 +306,15 @@ void ax25_kick(ax25_cb *ax25)
* in DAMA mode.
*/
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
break;
case AX25_PROTO_DAMA_SLAVE:
ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
break;
#endif
}
......
......@@ -40,10 +40,10 @@
* Jonathan(G4KLX) Support for packet forwarding.
* Arnaldo C. Melo s/suser/capable/
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
......@@ -56,6 +56,7 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <net/sock.h>
#include <asm/uaccess.h>
#include <asm/system.h>
......@@ -65,8 +66,9 @@
#include <linux/init.h>
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_get_route(ax25_address *, struct net_device *);
/*
* small macro to drop non-digipeated digipeaters and reverse path
......@@ -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)
{
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) {
s = ax25_rt;
ax25_rt = ax25_rt->next;
......@@ -111,129 +115,196 @@ void ax25_rt_device_down(struct net_device *dev)
}
}
}
write_unlock(&ax25_route_lock);
}
int ax25_rt_ioctl(unsigned int cmd, void *arg)
static int ax25_rt_add(struct ax25_routes_struct *route)
{
unsigned long flags;
ax25_route *s, *t, *ax25_rt;
struct ax25_routes_struct route;
struct ax25_route_opt_struct rt_option;
ax25_route *ax25_rt;
ax25_dev *ax25_dev;
int i;
switch (cmd) {
case SIOCADDRT:
if (copy_from_user(&route, arg, sizeof(route)))
return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
return -EINVAL;
if (route.digi_count > AX25_MAX_DIGIS)
return -EINVAL;
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 (ax25_rt->digipeat != NULL) {
kfree(ax25_rt->digipeat);
ax25_rt->digipeat = NULL;
}
if (route.digi_count != 0) {
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
return -ENOMEM;
ax25_rt->digipeat->lastrepeat = -1;
ax25_rt->digipeat->ndigi = route.digi_count;
for (i = 0; i < route.digi_count; i++) {
ax25_rt->digipeat->repeated[i] = 0;
ax25_rt->digipeat->calls[i] = route.digi_addr[i];
}
}
return 0;
}
if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
return -EINVAL;
if (route->digi_count > AX25_MAX_DIGIS)
return -EINVAL;
write_lock(&ax25_route_lock);
ax25_rt = ax25_route_list;
while (ax25_rt != NULL) {
if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
ax25_rt->dev == ax25_dev->dev) {
if (ax25_rt->digipeat != NULL) {
kfree(ax25_rt->digipeat);
ax25_rt->digipeat = NULL;
}
if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL)
return -ENOMEM;
ax25_rt->callsign = route.dest_addr;
ax25_rt->dev = ax25_dev->dev;
ax25_rt->digipeat = NULL;
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) {
kfree(ax25_rt);
write_unlock(&ax25_route_lock);
return -ENOMEM;
}
ax25_rt->digipeat->lastrepeat = -1;
ax25_rt->digipeat->ndigi = route.digi_count;
for (i = 0; i < route.digi_count; i++) {
ax25_rt->digipeat->ndigi = route->digi_count;
for (i = 0; i < route->digi_count; i++) {
ax25_rt->digipeat->repeated[i] = 0;
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_route_list = ax25_rt;
restore_flags(flags);
break;
return 0;
}
ax25_rt = ax25_rt->next;
}
case SIOCDELRT:
if (copy_from_user(&route, arg, sizeof(route)))
return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
return -EINVAL;
ax25_rt = ax25_route_list;
while (ax25_rt != NULL) {
s = ax25_rt;
ax25_rt = ax25_rt->next;
if (s->dev == ax25_dev->dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) {
if (ax25_route_list == s) {
ax25_route_list = s->next;
if (s->digipeat != NULL)
kfree(s->digipeat);
kfree(s);
} else {
for (t = ax25_route_list; t != NULL; t = t->next) {
if (t->next == s) {
t->next = s->next;
if (s->digipeat != NULL)
kfree(s->digipeat);
kfree(s);
break;
}
}
if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
write_unlock(&ax25_route_lock);
return -ENOMEM;
}
atomic_set(&ax25_rt->ref, 0);
ax25_rt->callsign = route->dest_addr;
ax25_rt->dev = ax25_dev->dev;
ax25_rt->digipeat = NULL;
ax25_rt->ip_mode = ' ';
if (route->digi_count != 0) {
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
write_unlock(&ax25_route_lock);
kfree(ax25_rt);
return -ENOMEM;
}
ax25_rt->digipeat->lastrepeat = -1;
ax25_rt->digipeat->ndigi = route->digi_count;
for (i = 0; i < route->digi_count; i++) {
ax25_rt->digipeat->repeated[i] = 0;
ax25_rt->digipeat->calls[i] = route->digi_addr[i];
}
}
ax25_rt->next = ax25_route_list;
ax25_route_list = ax25_rt;
write_unlock(&ax25_route_lock);
return 0;
}
static int ax25_rt_destroy(ax25_route *ax25_rt)
{
if (atomic_read(&ax25_rt->ref) == 0) {
if (ax25_rt->digipeat != NULL)
kfree(ax25_rt->digipeat);
kfree(ax25_rt);
}
/*
* Uh... Route is still in use; we can't yet destroy it. Retry later.
*/
init_timer(&ax25_rt->timer);
ax25_rt->timer.data = (unsigned long) ax25_rt;
ax25_rt->timer.function = (void *) ax25_rt_destroy;
ax25_rt->timer.expires = jiffies + 5 * HZ;
add_timer(&ax25_rt->timer);
}
static int ax25_rt_del(struct ax25_routes_struct *route)
{
ax25_route *s, *t, *ax25_rt;
ax25_dev *ax25_dev;
if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
return -EINVAL;
write_lock(&ax25_route_lock);
ax25_rt = ax25_route_list;
while (ax25_rt != NULL) {
s = ax25_rt;
ax25_rt = ax25_rt->next;
if (s->dev == ax25_dev->dev &&
ax25cmp(&route->dest_addr, &s->callsign) == 0) {
if (ax25_route_list == s) {
ax25_route_list = s->next;
ax25_rt_destroy(s);
} else {
for (t = ax25_route_list; t != NULL; t = t->next) {
if (t->next == s) {
t->next = s->next;
ax25_rt_destroy(s);
break;
}
}
}
break;
}
}
write_unlock(&ax25_route_lock);
case SIOCAX25OPTRT:
if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
return -EFAULT;
if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL)
return -EINVAL;
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) {
switch (rt_option.cmd) {
case AX25_SET_RT_IPMODE:
switch (rt_option.arg) {
case ' ':
case 'D':
case 'V':
ax25_rt->ip_mode = rt_option.arg;
break;
default:
return -EINVAL;
}
break;
default:
return -EINVAL;
}
return 0;
}
static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
{
ax25_route *ax25_rt;
ax25_dev *ax25_dev;
int err = 0;
if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
return -EINVAL;
write_lock(&ax25_route_lock);
ax25_rt = ax25_route_list;
while (ax25_rt != NULL) {
if (ax25_rt->dev == ax25_dev->dev &&
ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) {
switch (rt_option->cmd) {
case AX25_SET_RT_IPMODE:
switch (rt_option->arg) {
case ' ':
case 'D':
case 'V':
ax25_rt->ip_mode = rt_option->arg;
break;
default:
err = -EINVAL;
goto out;
}
break;
default:
err = -EINVAL;
goto out;
}
break;
default:
return -EINVAL;
}
ax25_rt = ax25_rt->next;
}
return 0;
out:
write_unlock(&ax25_route_lock);
return err;
}
int ax25_rt_ioctl(unsigned int cmd, void *arg)
{
struct ax25_route_opt_struct rt_option;
struct ax25_routes_struct route;
switch (cmd) {
case SIOCADDRT:
if (copy_from_user(&route, arg, sizeof(route)))
return -EFAULT;
return ax25_rt_add(&route);
case SIOCDELRT:
if (copy_from_user(&route, arg, sizeof(route)))
return -EFAULT;
return ax25_rt_del(&route);
case SIOCAX25OPTRT:
if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
return -EFAULT;
return ax25_rt_opt(&rt_option);
default:
return -EINVAL;
}
}
int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
......@@ -245,7 +316,7 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
char *callsign;
int i;
cli();
read_lock(&ax25_route_lock);
len += sprintf(buffer, "callsign dev mode digipeaters\n");
......@@ -259,15 +330,15 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
ax25_rt->dev ? ax25_rt->dev->name : "???");
switch (ax25_rt->ip_mode) {
case 'V':
len += sprintf(buffer + len, " vc");
break;
case 'D':
len += sprintf(buffer + len, " dg");
break;
default:
len += sprintf(buffer + len, " *");
break;
case 'V':
len += sprintf(buffer + len, " vc");
break;
case 'D':
len += sprintf(buffer + len, " dg");
break;
default:
len += sprintf(buffer + len, " *");
break;
}
if (ax25_rt->digipeat != NULL)
......@@ -286,26 +357,29 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length)
break;
}
sti();
read_unlock(&ax25_route_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
if (len > length) len = length;
if (len > length)
len = length;
return len;
}
/*
* Find AX.25 route
*
* Only routes with a refernce rout of zero can be destroyed.
*/
static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
{
ax25_route *ax25_spe_rt = NULL;
ax25_route *ax25_def_rt = NULL;
ax25_route *ax25_rt;
read_lock(&ax25_route_lock);
/*
* Bind to the physical interface we heard them on, or the default
* route if none is found;
......@@ -324,10 +398,21 @@ static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
}
}
ax25_rt = ax25_def_rt;
if (ax25_spe_rt != NULL)
return ax25_spe_rt;
ax25_rt = ax25_spe_rt;
return ax25_def_rt;
if (ax25_rt != NULL)
atomic_inc(&ax25_rt->ref);
read_unlock(&ax25_route_lock);
return ax25_rt;
}
static inline void ax25_put_route(ax25_route *ax25_rt)
{
atomic_dec(&ax25_rt->ref);
}
/*
......@@ -355,24 +440,31 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
{
ax25_route *ax25_rt;
ax25_address *call;
int err;
if ((ax25_rt = ax25_find_route(addr, NULL)) == NULL)
if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL)
return -EHOSTUNREACH;
if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL)
return -EHOSTUNREACH;
if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
err = -EHOSTUNREACH;
goto put;
}
if ((call = ax25_findbyuid(current->euid)) == NULL) {
if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
return -EPERM;
if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
err = -EPERM;
goto put;
}
call = (ax25_address *)ax25->ax25_dev->dev->dev_addr;
}
ax25->source_addr = *call;
if (ax25_rt->digipeat != NULL) {
if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
return -ENOMEM;
if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
err = -ENOMEM;
goto put;
}
memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi));
ax25_adjust_path(addr, ax25->digipeat);
}
......@@ -380,31 +472,32 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
if (ax25->sk != NULL)
ax25->sk->zapped = 0;
put:
ax25_put_route(ax25_rt);
return 0;
}
/*
* dl1bke 960117: build digipeater path
* dl1bke 960301: use the default route if it exists
*/
ax25_route *ax25_rt_find_route(ax25_address *addr, struct net_device *dev)
ax25_route *ax25_rt_find_route(ax25_route * route, ax25_address *addr,
struct net_device *dev)
{
static ax25_route route;
ax25_route *ax25_rt;
if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) {
route.next = NULL;
route.callsign = *addr;
route.dev = dev;
route.digipeat = NULL;
route.ip_mode = ' ';
return &route;
}
if ((ax25_rt = ax25_get_route(addr, dev)))
return ax25_rt;
return ax25_rt;
route->next = NULL;
atomic_set(&route->ref, 1);
route->callsign = *addr;
route->dev = dev;
route->digipeat = NULL;
route->ip_mode = ' ';
return route;
}
struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_address *dest, ax25_digi *digi)
struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
ax25_address *dest, ax25_digi *digi)
{
struct sk_buff *skbn;
unsigned char *bp;
......@@ -440,6 +533,7 @@ void __exit ax25_rt_free(void)
{
ax25_route *s, *ax25_rt = ax25_route_list;
write_unlock(&ax25_route_lock);
while (ax25_rt != NULL) {
s = ax25_rt;
ax25_rt = ax25_rt->next;
......@@ -449,4 +543,5 @@ void __exit ax25_rt_free(void)
kfree(s);
}
write_unlock(&ax25_route_lock);
}
......@@ -68,55 +68,55 @@
static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
switch (frametype) {
case AX25_SABM:
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
break;
case AX25_SABME:
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
break;
case AX25_UA:
if (pf) {
ax25_calculate_rtt(ax25);
ax25_stop_t1timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25->state = AX25_STATE_3;
ax25->n2count = 0;
if (ax25->sk != NULL) {
ax25->sk->state = TCP_ESTABLISHED;
/* For WAIT_SABM connections we will produce an accept ready socket here */
if (!ax25->sk->dead)
ax25->sk->state_change(ax25->sk);
}
case AX25_SABM:
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
break;
case AX25_SABME:
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
break;
case AX25_UA:
if (pf) {
ax25_calculate_rtt(ax25);
ax25_stop_t1timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25->state = AX25_STATE_3;
ax25->n2count = 0;
if (ax25->sk != NULL) {
ax25->sk->state = TCP_ESTABLISHED;
/* For WAIT_SABM connections we will produce an accept ready socket here */
if (!ax25->sk->dead)
ax25->sk->state_change(ax25->sk);
}
break;
}
break;
case AX25_DM:
if (pf) {
if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ECONNREFUSED);
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
}
case AX25_DM:
if (pf) {
if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ECONNREFUSED);
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
}
break;
}
break;
default:
break;
default:
break;
}
return 0;
......@@ -130,30 +130,31 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
switch (frametype) {
case AX25_SABM:
case AX25_SABME:
ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
case AX25_SABM:
case AX25_SABME:
ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_disconnect(ax25, 0);
break;
case AX25_DM:
case AX25_UA:
if (pf)
ax25_disconnect(ax25, 0);
break;
break;
case AX25_DM:
case AX25_UA:
if (pf) ax25_disconnect(ax25, 0);
break;
case AX25_I:
case AX25_REJ:
case AX25_RNR:
case AX25_RR:
if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
break;
case AX25_I:
case AX25_REJ:
case AX25_RNR:
case AX25_RR:
if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
break;
default:
break;
default:
break;
}
return 0;
......@@ -169,116 +170,116 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
int queued = 0;
switch (frametype) {
case AX25_SABM:
case AX25_SABME:
if (frametype == AX25_SABM) {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
} else {
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
}
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
case AX25_SABM:
case AX25_SABME:
if (frametype == AX25_SABM) {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
} else {
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
}
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_stop_t1timer(ax25);
ax25_stop_t2timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->condition = 0x00;
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25_requeue_frames(ax25);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_disconnect(ax25, 0);
break;
case AX25_DM:
ax25_disconnect(ax25, ECONNRESET);
break;
case AX25_RR:
case AX25_RNR:
if (frametype == AX25_RR)
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
else
ax25->condition |= AX25_COND_PEER_RX_BUSY;
if (type == AX25_COMMAND && pf)
ax25_std_enquiry_response(ax25);
if (ax25_validate_nr(ax25, nr)) {
ax25_check_iframes_acked(ax25, nr);
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
case AX25_REJ:
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
if (type == AX25_COMMAND && pf)
ax25_std_enquiry_response(ax25);
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
ax25_calculate_rtt(ax25);
ax25_stop_t1timer(ax25);
ax25_stop_t2timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->condition = 0x00;
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25_requeue_frames(ax25);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_disconnect(ax25, 0);
break;
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
case AX25_DM:
ax25_disconnect(ax25, ECONNRESET);
case AX25_I:
if (!ax25_validate_nr(ax25, nr)) {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
break;
case AX25_RR:
case AX25_RNR:
if (frametype == AX25_RR)
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
else
ax25->condition |= AX25_COND_PEER_RX_BUSY;
if (type == AX25_COMMAND && pf)
ax25_std_enquiry_response(ax25);
if (ax25_validate_nr(ax25, nr)) {
ax25_check_iframes_acked(ax25, nr);
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
}
if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
ax25_frames_acked(ax25, nr);
} else {
ax25_check_iframes_acked(ax25, nr);
}
if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
if (pf) ax25_std_enquiry_response(ax25);
break;
case AX25_REJ:
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
if (type == AX25_COMMAND && pf)
}
if (ns == ax25->vr) {
ax25->vr = (ax25->vr + 1) % ax25->modulus;
queued = ax25_rx_iframe(ax25, skb);
if (ax25->condition & AX25_COND_OWN_RX_BUSY)
ax25->vr = ns; /* ax25->vr - 1 */
ax25->condition &= ~AX25_COND_REJECT;
if (pf) {
ax25_std_enquiry_response(ax25);
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
ax25_calculate_rtt(ax25);
ax25_stop_t1timer(ax25);
ax25_start_t3timer(ax25);
ax25_requeue_frames(ax25);
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
case AX25_I:
if (!ax25_validate_nr(ax25, nr)) {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
break;
}
if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
ax25_frames_acked(ax25, nr);
} else {
ax25_check_iframes_acked(ax25, nr);
if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
ax25->condition |= AX25_COND_ACK_PENDING;
ax25_start_t2timer(ax25);
}
}
if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
} else {
if (ax25->condition & AX25_COND_REJECT) {
if (pf) ax25_std_enquiry_response(ax25);
break;
}
if (ns == ax25->vr) {
ax25->vr = (ax25->vr + 1) % ax25->modulus;
queued = ax25_rx_iframe(ax25, skb);
if (ax25->condition & AX25_COND_OWN_RX_BUSY)
ax25->vr = ns; /* ax25->vr - 1 */
ax25->condition &= ~AX25_COND_REJECT;
if (pf) {
ax25_std_enquiry_response(ax25);
} else {
if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
ax25->condition |= AX25_COND_ACK_PENDING;
ax25_start_t2timer(ax25);
}
}
} else {
if (ax25->condition & AX25_COND_REJECT) {
if (pf) ax25_std_enquiry_response(ax25);
} else {
ax25->condition |= AX25_COND_REJECT;
ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
ax25->condition &= ~AX25_COND_ACK_PENDING;
}
ax25->condition |= AX25_COND_REJECT;
ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
ax25->condition &= ~AX25_COND_ACK_PENDING;
}
break;
}
break;
case AX25_FRMR:
case AX25_ILLEGAL:
ax25_std_establish_data_link(ax25);
ax25->state = AX25_STATE_1;
break;
case AX25_FRMR:
case AX25_ILLEGAL:
ax25_std_establish_data_link(ax25);
ax25->state = AX25_STATE_1;
break;
default:
break;
default:
break;
}
return queued;
......@@ -294,145 +295,146 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
int queued = 0;
switch (frametype) {
case AX25_SABM:
case AX25_SABME:
if (frametype == AX25_SABM) {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
} else {
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
}
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
case AX25_SABM:
case AX25_SABME:
if (frametype == AX25_SABM) {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
} else {
ax25->modulus = AX25_EMODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
}
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_stop_t1timer(ax25);
ax25_stop_t2timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->condition = 0x00;
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25->state = AX25_STATE_3;
ax25->n2count = 0;
ax25_requeue_frames(ax25);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_disconnect(ax25, 0);
break;
case AX25_DM:
ax25_disconnect(ax25, ECONNRESET);
break;
case AX25_RR:
case AX25_RNR:
if (frametype == AX25_RR)
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
else
ax25->condition |= AX25_COND_PEER_RX_BUSY;
if (type == AX25_RESPONSE && pf) {
ax25_stop_t1timer(ax25);
ax25_stop_t2timer(ax25);
ax25_start_t3timer(ax25);
ax25_start_idletimer(ax25);
ax25->condition = 0x00;
ax25->vs = 0;
ax25->va = 0;
ax25->vr = 0;
ax25->state = AX25_STATE_3;
ax25->n2count = 0;
ax25_requeue_frames(ax25);
break;
case AX25_DISC:
ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
ax25_disconnect(ax25, 0);
break;
case AX25_DM:
ax25_disconnect(ax25, ECONNRESET);
break;
case AX25_RR:
case AX25_RNR:
if (frametype == AX25_RR)
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
else
ax25->condition |= AX25_COND_PEER_RX_BUSY;
if (type == AX25_RESPONSE && pf) {
ax25_stop_t1timer(ax25);
ax25->n2count = 0;
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
if (ax25->vs == ax25->va) {
ax25_start_t3timer(ax25);
ax25->state = AX25_STATE_3;
} else {
ax25_requeue_frames(ax25);
}
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
}
if (type == AX25_COMMAND && pf)
ax25_std_enquiry_response(ax25);
ax25->n2count = 0;
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
if (ax25->vs == ax25->va) {
ax25_start_t3timer(ax25);
ax25->state = AX25_STATE_3;
} else {
ax25_requeue_frames(ax25);
}
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
}
if (type == AX25_COMMAND && pf)
ax25_std_enquiry_response(ax25);
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
case AX25_REJ:
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
if (pf && type == AX25_RESPONSE) {
ax25_stop_t1timer(ax25);
ax25->n2count = 0;
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
if (ax25->vs == ax25->va) {
ax25_start_t3timer(ax25);
ax25->state = AX25_STATE_3;
} else {
ax25_requeue_frames(ax25);
}
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
}
if (type == AX25_COMMAND && pf)
ax25_std_enquiry_response(ax25);
case AX25_REJ:
ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
if (pf && type == AX25_RESPONSE) {
ax25_stop_t1timer(ax25);
ax25->n2count = 0;
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
ax25_requeue_frames(ax25);
if (ax25->vs == ax25->va) {
ax25_start_t3timer(ax25);
ax25->state = AX25_STATE_3;
} else {
ax25_requeue_frames(ax25);
}
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
}
if (type == AX25_COMMAND && pf)
ax25_std_enquiry_response(ax25);
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
ax25_requeue_frames(ax25);
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
case AX25_I:
if (!ax25_validate_nr(ax25, nr)) {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
break;
case AX25_I:
if (!ax25_validate_nr(ax25, nr)) {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
break;
}
ax25_frames_acked(ax25, nr);
if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
if (pf)
ax25_std_enquiry_response(ax25);
break;
}
if (ns == ax25->vr) {
ax25->vr = (ax25->vr + 1) % ax25->modulus;
queued = ax25_rx_iframe(ax25, skb);
if (ax25->condition & AX25_COND_OWN_RX_BUSY)
ax25->vr = ns; /* ax25->vr - 1 */
ax25->condition &= ~AX25_COND_REJECT;
if (pf) {
ax25_std_enquiry_response(ax25);
} else {
if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
ax25->condition |= AX25_COND_ACK_PENDING;
ax25_start_t2timer(ax25);
}
}
ax25_frames_acked(ax25, nr);
if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
} else {
if (ax25->condition & AX25_COND_REJECT) {
if (pf) ax25_std_enquiry_response(ax25);
break;
}
if (ns == ax25->vr) {
ax25->vr = (ax25->vr + 1) % ax25->modulus;
queued = ax25_rx_iframe(ax25, skb);
if (ax25->condition & AX25_COND_OWN_RX_BUSY)
ax25->vr = ns; /* ax25->vr - 1 */
ax25->condition &= ~AX25_COND_REJECT;
if (pf) {
ax25_std_enquiry_response(ax25);
} else {
if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
ax25->condition |= AX25_COND_ACK_PENDING;
ax25_start_t2timer(ax25);
}
}
} else {
if (ax25->condition & AX25_COND_REJECT) {
if (pf) ax25_std_enquiry_response(ax25);
} else {
ax25->condition |= AX25_COND_REJECT;
ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
ax25->condition &= ~AX25_COND_ACK_PENDING;
}
ax25->condition |= AX25_COND_REJECT;
ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
ax25->condition &= ~AX25_COND_ACK_PENDING;
}
break;
}
break;
case AX25_FRMR:
case AX25_ILLEGAL:
ax25_std_establish_data_link(ax25);
ax25->state = AX25_STATE_1;
break;
case AX25_FRMR:
case AX25_ILLEGAL:
ax25_std_establish_data_link(ax25);
ax25->state = AX25_STATE_1;
break;
default:
break;
default:
break;
}
return queued;
......@@ -448,18 +450,18 @@ int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
switch (ax25->state) {
case AX25_STATE_1:
queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_2:
queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_3:
queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
break;
case AX25_STATE_4:
queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type);
break;
case AX25_STATE_1:
queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_2:
queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type);
break;
case AX25_STATE_3:
queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
break;
case AX25_STATE_4:
queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type);
break;
}
ax25_kick(ax25);
......
......@@ -47,30 +47,29 @@
void ax25_std_heartbeat_expiry(ax25_cb *ax25)
{
switch (ax25->state) {
case AX25_STATE_0:
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
ax25_destroy_socket(ax25);
return;
}
break;
case AX25_STATE_3:
case AX25_STATE_4:
/*
* Check the state of the receive buffer.
*/
if (ax25->sk != NULL) {
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_ACK_PENDING;
ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
break;
}
case AX25_STATE_0:
/* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */
if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
ax25_destroy_socket(ax25);
return;
}
break;
case AX25_STATE_3:
case AX25_STATE_4:
/*
* Check the state of the receive buffer.
*/
if (ax25->sk != NULL) {
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_ACK_PENDING;
ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
break;
}
}
}
ax25_start_heartbeat(ax25);
......@@ -117,53 +116,53 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25)
void ax25_std_t1timer_expiry(ax25_cb *ax25)
{
switch (ax25->state) {
case AX25_STATE_1:
if (ax25->n2count == ax25->n2) {
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);
case AX25_STATE_1:
if (ax25->n2count == ax25->n2) {
if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
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);
}
break;
case AX25_STATE_3:
ax25->n2count = 1;
} 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);
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->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);
}
break;
}
break;
}
ax25_calculate_t1(ax25);
......
......@@ -257,18 +257,18 @@ void ax25_calculate_t1(ax25_cb *ax25)
int n, t = 2;
switch (ax25->backoff) {
case 0:
break;
case 1:
t += 2 * ax25->n2count;
break;
case 2:
for (n = 0; n < ax25->n2count; n++)
t *= 2;
if (t > 8) t = 8;
break;
case 0:
break;
case 1:
t += 2 * ax25->n2count;
break;
case 2:
for (n = 0; n < ax25->n2count; n++)
t *= 2;
if (t > 8) t = 8;
break;
}
ax25->t1 = t * ax25->rtt;
......
......@@ -159,18 +159,18 @@ static void ax25_heartbeat_expiry(unsigned long param)
proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL];
switch (proto) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_heartbeat_expiry(ax25);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_heartbeat_expiry(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave)
ax25_ds_heartbeat_expiry(ax25);
else
ax25_std_heartbeat_expiry(ax25);
break;
case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave)
ax25_ds_heartbeat_expiry(ax25);
else
ax25_std_heartbeat_expiry(ax25);
break;
#endif
}
}
......@@ -180,16 +180,16 @@ static void ax25_t1timer_expiry(unsigned long param)
ax25_cb *ax25 = (ax25_cb *)param;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_t1timer_expiry(ax25);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_t1timer_expiry(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave)
ax25_std_t1timer_expiry(ax25);
break;
case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave)
ax25_std_t1timer_expiry(ax25);
break;
#endif
}
}
......@@ -199,16 +199,16 @@ static void ax25_t2timer_expiry(unsigned long param)
ax25_cb *ax25 = (ax25_cb *)param;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_t2timer_expiry(ax25);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_t2timer_expiry(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave)
ax25_std_t2timer_expiry(ax25);
break;
case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave)
ax25_std_t2timer_expiry(ax25);
break;
#endif
}
}
......@@ -218,18 +218,18 @@ static void ax25_t3timer_expiry(unsigned long param)
ax25_cb *ax25 = (ax25_cb *)param;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_t3timer_expiry(ax25);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_t3timer_expiry(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave)
ax25_ds_t3timer_expiry(ax25);
else
ax25_std_t3timer_expiry(ax25);
break;
case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave)
ax25_ds_t3timer_expiry(ax25);
else
ax25_std_t3timer_expiry(ax25);
break;
#endif
}
}
......@@ -239,18 +239,18 @@ static void ax25_idletimer_expiry(unsigned long param)
ax25_cb *ax25 = (ax25_cb *)param;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_idletimer_expiry(ax25);
break;
case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX:
ax25_std_idletimer_expiry(ax25);
break;
#ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave)
ax25_ds_idletimer_expiry(ax25);
else
ax25_std_idletimer_expiry(ax25);
break;
case AX25_PROTO_DAMA_SLAVE:
if (ax25->ax25_dev->dama.slave)
ax25_ds_idletimer_expiry(ax25);
else
ax25_std_idletimer_expiry(ax25);
break;
#endif
}
}
......@@ -23,6 +23,7 @@
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
......@@ -47,17 +48,23 @@
*/
static ax25_uid_assoc *ax25_uid_list;
static rwlock_t ax25_uid_lock = RW_LOCK_UNLOCKED;
int ax25_uid_policy = 0;
ax25_address *ax25_findbyuid(uid_t 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) {
if (ax25_uid->uid == uid)
return &ax25_uid->call;
if (ax25_uid->uid == uid) {
res = &ax25_uid->call;
break;
}
}
read_unlock(&ax25_uid_lock);
return NULL;
}
......@@ -65,63 +72,77 @@ ax25_address *ax25_findbyuid(uid_t uid)
int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
{
ax25_uid_assoc *s, *ax25_uid;
unsigned long flags;
unsigned long res;
switch (cmd) {
case SIOCAX25GETUID:
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
return ax25_uid->uid;
case SIOCAX25GETUID:
res = -ENOENT;
read_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) {
res = ax25_uid->uid;
break;
}
return -ENOENT;
}
read_unlock(&ax25_uid_lock);
case SIOCAX25ADDUID:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (ax25_findbyuid(sax->sax25_uid))
return -EEXIST;
if (sax->sax25_uid == 0)
return -EINVAL;
if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
return -ENOMEM;
ax25_uid->uid = sax->sax25_uid;
ax25_uid->call = sax->sax25_call;
save_flags(flags); cli();
ax25_uid->next = ax25_uid_list;
ax25_uid_list = ax25_uid;
restore_flags(flags);
return 0;
return res;
case SIOCAX25ADDUID:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (ax25_findbyuid(sax->sax25_uid))
return -EEXIST;
if (sax->sax25_uid == 0)
return -EINVAL;
if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
return -ENOMEM;
ax25_uid->uid = sax->sax25_uid;
ax25_uid->call = sax->sax25_call;
write_lock(&ax25_uid_lock);
ax25_uid->next = ax25_uid_list;
ax25_uid_list = ax25_uid;
write_unlock(&ax25_uid_lock);
case SIOCAX25DELUID:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
break;
return 0;
case SIOCAX25DELUID:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
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;
save_flags(flags); cli();
if ((s = ax25_uid_list) == ax25_uid) {
ax25_uid_list = s->next;
restore_flags(flags);
}
if (ax25_uid == NULL) {
write_unlock(&ax25_uid_lock);
return -ENOENT;
}
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);
return 0;
}
while (s != NULL && s->next != NULL) {
if (s->next == ax25_uid) {
s->next = ax25_uid->next;
restore_flags(flags);
kfree(ax25_uid);
return 0;
}
s = s->next;
}
restore_flags(flags);
return -ENOENT;
s = s->next;
}
write_unlock(&ax25_uid_lock);
default:
return -EINVAL;
return -ENOENT;
default:
return -EINVAL;
}
return -EINVAL; /*NOTREACHED */
......@@ -134,8 +155,7 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
off_t begin = 0;
cli();
read_lock(&ax25_uid_lock);
len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy);
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)
if (pos > offset + length)
break;
}
sti();
read_unlock(&ax25_uid_lock);
*start = buffer + (offset - begin);
len -= offset - begin;
if (len > length) len = length;
if (len > length)
len = length;
return len;
}
......@@ -167,12 +187,16 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
*/
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) {
s = ax25_uid;
ax25_uid = ax25_uid->next;
kfree(s);
}
ax25_uid_list = NULL;
write_unlock(&ax25_uid_lock);
}
......@@ -8,6 +8,7 @@
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/spinlock.h>
#include <net/ax25.h>
static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1};
......@@ -102,9 +103,11 @@ static const ctl_table ax25_param_table[] = {
void ax25_register_sysctl(void)
{
unsigned long flags;
ax25_dev *ax25_dev;
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)
ax25_table_size += sizeof(ctl_table);
......@@ -119,6 +122,7 @@ void ax25_register_sysctl(void)
while (n--)
kfree(ax25_table[n].child);
kfree(ax25_table);
spin_unlock_irqrestore(&ax25_dev_lock, flags);
return;
}
memcpy(child, ax25_param_table, sizeof(ax25_param_table));
......@@ -144,6 +148,7 @@ void ax25_register_sysctl(void)
n++;
}
spin_unlock_irqrestore(&ax25_dev_lock, flags);
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