Commit b331768e authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/home/davem/src/BK/ham-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents e65ca57c c2edf826
...@@ -240,8 +240,8 @@ L: linux-net@vger.kernel.org ...@@ -240,8 +240,8 @@ L: linux-net@vger.kernel.org
S: Maintained S: Maintained
AX.25 NETWORK LAYER AX.25 NETWORK LAYER
P: Matthias Welwarsky P: Ralf Baechle
M: dg2fef@afthd.tu-darmstadt.de M: ralf@linux-mips.org
L: linux-hams@vger.kernel.org L: linux-hams@vger.kernel.org
S: Maintained S: Maintained
...@@ -1121,8 +1121,8 @@ L: netfilter-devel@lists.netfilter.org ...@@ -1121,8 +1121,8 @@ L: netfilter-devel@lists.netfilter.org
S: Supported S: Supported
NETROM NETWORK LAYER NETROM NETWORK LAYER
P: Tomi Manninen P: Ralf Baechle
M: Tomi.Manninen@hut.fi M: ralf@linux-mips.org
L: linux-hams@vger.kernel.org L: linux-hams@vger.kernel.org
S: Maintained S: Maintained
...@@ -1371,8 +1371,8 @@ W: http://www.namesys.com ...@@ -1371,8 +1371,8 @@ W: http://www.namesys.com
S: Supported S: Supported
ROSE NETWORK LAYER ROSE NETWORK LAYER
P: Jean-Paul Roubelat P: Ralf Baechle
M: jpr@f6fbb.org M: ralf@linux-mips.org
L: linux-hams@vger.kernel.org L: linux-hams@vger.kernel.org
S: Maintained S: Maintained
......
...@@ -3,11 +3,14 @@ ...@@ -3,11 +3,14 @@
* *
* Alan Cox (GW4PTS) 10/11/93 * Alan Cox (GW4PTS) 10/11/93
*/ */
#ifndef _AX25_H #ifndef _AX25_H
#define _AX25_H #define _AX25_H
#include <linux/config.h> #include <linux/config.h>
#include <linux/ax25.h> #include <linux/ax25.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <asm/atomic.h>
#define AX25_T1CLAMPLO 1 #define AX25_T1CLAMPLO 1
#define AX25_T1CLAMPHI (30 * HZ) #define AX25_T1CLAMPHI (30 * HZ)
...@@ -66,6 +69,8 @@ ...@@ -66,6 +69,8 @@
#define AX25_UA 0x63 /* Unnumbered acknowledge */ #define AX25_UA 0x63 /* Unnumbered acknowledge */
#define AX25_FRMR 0x87 /* Frame reject */ #define AX25_FRMR 0x87 /* Frame reject */
#define AX25_UI 0x03 /* Unnumbered information */ #define AX25_UI 0x03 /* Unnumbered information */
#define AX25_XID 0xaf /* Exchange information */
#define AX25_TEST 0xe3 /* Test */
#define AX25_PF 0x10 /* Poll/final bit for standard AX.25 */ #define AX25_PF 0x10 /* Poll/final bit for standard AX.25 */
#define AX25_EPF 0x01 /* Poll/final bit for extended AX.25 */ #define AX25_EPF 0x01 /* Poll/final bit for extended AX.25 */
...@@ -147,10 +152,12 @@ typedef struct { ...@@ -147,10 +152,12 @@ typedef struct {
typedef struct ax25_route { typedef struct ax25_route {
struct ax25_route *next; struct ax25_route *next;
atomic_t ref;
ax25_address callsign; ax25_address callsign;
struct net_device *dev; struct net_device *dev;
ax25_digi *digipeat; ax25_digi *digipeat;
char ip_mode; char ip_mode;
struct timer_list timer;
} ax25_route; } ax25_route;
typedef struct { typedef struct {
...@@ -197,11 +204,12 @@ typedef struct ax25_cb { ...@@ -197,11 +204,12 @@ typedef struct ax25_cb {
#define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo) #define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo)
/* af_ax25.c */ /* af_ax25.c */
extern ax25_cb *volatile ax25_list; extern ax25_cb *ax25_list;
extern spinlock_t ax25_list_lock;
extern void ax25_free_cb(ax25_cb *); extern void ax25_free_cb(ax25_cb *);
extern void ax25_insert_socket(ax25_cb *); extern void ax25_insert_socket(ax25_cb *);
struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int); struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int);
struct sock *ax25_find_socket(ax25_address *, ax25_address *, int); struct sock *ax25_get_socket(ax25_address *, ax25_address *, int);
extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct net_device *); extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct net_device *);
extern struct sock *ax25_addr_match(ax25_address *); extern struct sock *ax25_addr_match(ax25_address *);
extern void ax25_send_to_raw(struct sock *, struct sk_buff *, int); extern void ax25_send_to_raw(struct sock *, struct sk_buff *, int);
...@@ -224,6 +232,7 @@ extern void ax25_digi_invert(ax25_digi *, ax25_digi *); ...@@ -224,6 +232,7 @@ extern void ax25_digi_invert(ax25_digi *, ax25_digi *);
/* ax25_dev.c */ /* ax25_dev.c */
extern ax25_dev *ax25_dev_list; extern ax25_dev *ax25_dev_list;
extern spinlock_t ax25_dev_lock;
extern ax25_dev *ax25_dev_ax25dev(struct net_device *); extern ax25_dev *ax25_dev_ax25dev(struct net_device *);
extern ax25_dev *ax25_addr_ax25dev(ax25_address *); extern ax25_dev *ax25_addr_ax25dev(ax25_address *);
extern void ax25_dev_device_up(struct net_device *); extern void ax25_dev_device_up(struct net_device *);
...@@ -286,10 +295,16 @@ extern void ax25_rt_device_down(struct net_device *); ...@@ -286,10 +295,16 @@ extern void ax25_rt_device_down(struct net_device *);
extern int ax25_rt_ioctl(unsigned int, void *); extern int ax25_rt_ioctl(unsigned int, void *);
extern int ax25_rt_get_info(char *, char **, off_t, int); extern int ax25_rt_get_info(char *, char **, off_t, int);
extern int ax25_rt_autobind(ax25_cb *, ax25_address *); extern int ax25_rt_autobind(ax25_cb *, ax25_address *);
extern ax25_route *ax25_rt_find_route(ax25_address *, struct net_device *); extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *,
struct net_device *);
extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *); extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *);
extern void ax25_rt_free(void); extern void ax25_rt_free(void);
static inline void ax25_put_route(ax25_route *ax25_rt)
{
atomic_dec(&ax25_rt->ref);
}
/* ax25_std_in.c */ /* ax25_std_in.c */
extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int); extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int);
......
# #
# Amateur Radio protocols and AX.25 device configuration # Amateur Radio protocols and AX.25 device configuration
# #
# 19971130 Now in an own category to make correct compilation of the # 19971130 Now in an own category to make correct compilation of the
# AX.25 stuff easier... # AX.25 stuff easier...
# Joerg Reuter DL1BKE <jreuter@yaina.de> # Joerg Reuter DL1BKE <jreuter@yaina.de>
# 19980129 Moved to net/ax25/Config.in, sourcing device drivers. # 19980129 Moved to net/ax25/Config.in, sourcing device drivers.
......
Do the ax25_list_lock, ax25_dev_lock, linkfail_lockreally, ax25_frag_lock and
listen_lock have to be bh-safe?
Do the netrom and rose locks have to be bh-safe?
A device might be deleted after lookup in the SIOCADDRT ioctl but before it's
being used.
Routes to a device being taken down might be deleted by ax25_rt_device_down
but added by somebody else before the device has been deleted fully.
Massive amounts of lock_kernel / unlock_kernel are just a temporary solution to
get around the removal of SOCKOPS_WRAP. A serious locking strategy has to be
implemented.
The ax25_rt_find_route synopsys is pervert but I somehow had to deal with
the race caused by the static variable in it's previous implementation.
Implement proper socket locking in netrom and rose.
Check socket locking when ax25_rcv is sending to raw sockets. In particular
ax25_send_to_raw() seems fishy. Heck - ax25_rcv is fishy.
Handle XID and TEST frames properly.
This diff is collapsed.
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_subr.c.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
...@@ -165,14 +152,14 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a ...@@ -165,14 +152,14 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
if (flags != NULL) { if (flags != NULL) {
*flags = 0; *flags = 0;
if (buf[6] & AX25_CBIT) if (buf[6] & AX25_CBIT)
*flags = AX25_COMMAND; *flags = AX25_COMMAND;
if (buf[13] & AX25_CBIT) if (buf[13] & AX25_CBIT)
*flags = AX25_RESPONSE; *flags = AX25_RESPONSE;
} }
if (dama != NULL) if (dama != NULL)
*dama = ~buf[13] & AX25_DAMA_FLAG; *dama = ~buf[13] & AX25_DAMA_FLAG;
/* Copy to, from */ /* Copy to, from */
...@@ -243,7 +230,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a ...@@ -243,7 +230,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a
if (d == NULL || d->ndigi == 0) { if (d == NULL || d->ndigi == 0) {
buf[6] |= AX25_EBIT; buf[6] |= AX25_EBIT;
return 2 * AX25_ADDR_LEN; return 2 * AX25_ADDR_LEN;
} }
buf += AX25_ADDR_LEN; buf += AX25_ADDR_LEN;
len += AX25_ADDR_LEN; len += AX25_ADDR_LEN;
...@@ -277,7 +264,7 @@ int ax25_addr_size(ax25_digi *dp) ...@@ -277,7 +264,7 @@ int ax25_addr_size(ax25_digi *dp)
return AX25_ADDR_LEN * (2 + dp->ndigi); return AX25_ADDR_LEN * (2 + dp->ndigi);
} }
/* /*
* Reverse Digipeat List. May not pass both parameters as same struct * Reverse Digipeat List. May not pass both parameters as same struct
*/ */
void ax25_digi_invert(ax25_digi *in, ax25_digi *out) void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
......
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Other kernels modules in this kit are generally BSD derived. See the copyright headers.
*
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_route.c.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -27,6 +17,7 @@ ...@@ -27,6 +17,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h> #include <net/ax25.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -41,27 +32,35 @@ ...@@ -41,27 +32,35 @@
#include <linux/init.h> #include <linux/init.h>
ax25_dev *ax25_dev_list; ax25_dev *ax25_dev_list;
spinlock_t ax25_dev_lock = SPIN_LOCK_UNLOCKED;
ax25_dev *ax25_dev_ax25dev(struct net_device *dev) ax25_dev *ax25_dev_ax25dev(struct net_device *dev)
{ {
ax25_dev *ax25_dev; ax25_dev *ax25_dev, *res = NULL;
spin_lock_bh(&ax25_dev_lock);
for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
if (ax25_dev->dev == dev) if (ax25_dev->dev == dev) {
return ax25_dev; res = ax25_dev;
break;
}
spin_unlock_bh(&ax25_dev_lock);
return NULL; return res;
} }
ax25_dev *ax25_addr_ax25dev(ax25_address *addr) ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
{ {
ax25_dev *ax25_dev; ax25_dev *ax25_dev, *res = NULL;
spin_lock_bh(&ax25_dev_lock);
for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) {
return ax25_dev; res = ax25_dev;
}
spin_unlock_bh(&ax25_dev_lock);
return NULL; return res;
} }
/* /*
...@@ -71,7 +70,6 @@ ax25_dev *ax25_addr_ax25dev(ax25_address *addr) ...@@ -71,7 +70,6 @@ ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
void ax25_dev_device_up(struct net_device *dev) void ax25_dev_device_up(struct net_device *dev)
{ {
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
unsigned long flags;
if ((ax25_dev = kmalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) { if ((ax25_dev = kmalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) {
printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n"); printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n");
...@@ -100,10 +98,10 @@ void ax25_dev_device_up(struct net_device *dev) ...@@ -100,10 +98,10 @@ void ax25_dev_device_up(struct net_device *dev)
ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL; ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL;
ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT; ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT;
save_flags(flags); cli(); spin_lock_bh(&ax25_dev_lock);
ax25_dev->next = ax25_dev_list; ax25_dev->next = ax25_dev_list;
ax25_dev_list = ax25_dev; ax25_dev_list = ax25_dev;
restore_flags(flags); spin_unlock_bh(&ax25_dev_lock);
ax25_register_sysctl(); ax25_register_sysctl();
} }
...@@ -111,14 +109,13 @@ void ax25_dev_device_up(struct net_device *dev) ...@@ -111,14 +109,13 @@ void ax25_dev_device_up(struct net_device *dev)
void ax25_dev_device_down(struct net_device *dev) void ax25_dev_device_down(struct net_device *dev)
{ {
ax25_dev *s, *ax25_dev; ax25_dev *s, *ax25_dev;
unsigned long flags;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return; return;
ax25_unregister_sysctl(); ax25_unregister_sysctl();
save_flags(flags); cli(); spin_lock_bh(&ax25_dev_lock);
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
ax25_ds_del_timer(ax25_dev); ax25_ds_del_timer(ax25_dev);
...@@ -133,7 +130,7 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -133,7 +130,7 @@ void ax25_dev_device_down(struct net_device *dev)
if ((s = ax25_dev_list) == ax25_dev) { if ((s = ax25_dev_list) == ax25_dev) {
ax25_dev_list = s->next; ax25_dev_list = s->next;
restore_flags(flags); spin_unlock_bh(&ax25_dev_lock);
kfree(ax25_dev); kfree(ax25_dev);
ax25_register_sysctl(); ax25_register_sysctl();
return; return;
...@@ -142,7 +139,7 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -142,7 +139,7 @@ void ax25_dev_device_down(struct net_device *dev)
while (s != NULL && s->next != NULL) { while (s != NULL && s->next != NULL) {
if (s->next == ax25_dev) { if (s->next == ax25_dev) {
s->next = ax25_dev->next; s->next = ax25_dev->next;
restore_flags(flags); spin_unlock_bh(&ax25_dev_lock);
kfree(ax25_dev); kfree(ax25_dev);
ax25_register_sysctl(); ax25_register_sysctl();
return; return;
...@@ -150,8 +147,8 @@ void ax25_dev_device_down(struct net_device *dev) ...@@ -150,8 +147,8 @@ void ax25_dev_device_down(struct net_device *dev)
s = s->next; s = s->next;
} }
spin_unlock_bh(&ax25_dev_lock);
restore_flags(flags);
ax25_register_sysctl(); ax25_register_sysctl();
} }
...@@ -163,22 +160,22 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd) ...@@ -163,22 +160,22 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
return -EINVAL; return -EINVAL;
switch (cmd) { switch (cmd) {
case SIOCAX25ADDFWD: case SIOCAX25ADDFWD:
if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL) if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
return -EINVAL; return -EINVAL;
if (ax25_dev->forward != NULL) if (ax25_dev->forward != NULL)
return -EINVAL; return -EINVAL;
ax25_dev->forward = fwd_dev->dev; ax25_dev->forward = fwd_dev->dev;
break; break;
case SIOCAX25DELFWD:
if (ax25_dev->forward == NULL)
return -EINVAL;
ax25_dev->forward = NULL;
break;
default: case SIOCAX25DELFWD:
if (ax25_dev->forward == NULL)
return -EINVAL; return -EINVAL;
ax25_dev->forward = NULL;
break;
default:
return -EINVAL;
} }
return 0; return 0;
...@@ -202,12 +199,16 @@ struct net_device *ax25_fwd_dev(struct net_device *dev) ...@@ -202,12 +199,16 @@ struct net_device *ax25_fwd_dev(struct net_device *dev)
*/ */
void __exit ax25_dev_free(void) void __exit ax25_dev_free(void)
{ {
ax25_dev *s, *ax25_dev = ax25_dev_list; ax25_dev *s, *ax25_dev;
spin_lock_bh(&ax25_dev_lock);
ax25_dev = ax25_dev_list;
while (ax25_dev != NULL) { while (ax25_dev != NULL) {
s = ax25_dev; s = ax25_dev;
ax25_dev = ax25_dev->next; ax25_dev = ax25_dev->next;
kfree(s); kfree(s);
} }
ax25_dev_list = NULL;
spin_unlock_bh(&ax25_dev_lock);
} }
This diff is collapsed.
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_out.c and ax25_subr.c.
* Joerg(DL1BKE) Changed ax25_ds_enquiry_response(),
* fixed ax25_dama_on() and ax25_dama_off().
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
...@@ -31,6 +16,7 @@ ...@@ -31,6 +16,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h> #include <linux/net.h>
#include <net/ax25.h> #include <net/ax25.h>
#include <linux/inet.h> #include <linux/inet.h>
...@@ -73,7 +59,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25) ...@@ -73,7 +59,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
* DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5> * DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5>
* *
* Flexnet refuses to send us *any* I frame if we send * Flexnet refuses to send us *any* I frame if we send
* a REJ in case AX25_COND_REJECT is set. It is superfluous in * a REJ in case AX25_COND_REJECT is set. It is superfluous in
* this mode anyway (a RR or RNR invokes the retransmission). * this mode anyway (a RR or RNR invokes the retransmission).
* Is this a Flexnet bug? * Is this a Flexnet bug?
*/ */
...@@ -93,6 +79,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25) ...@@ -93,6 +79,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
ax25_start_t3timer(ax25); ax25_start_t3timer(ax25);
ax25_ds_set_timer(ax25->ax25_dev); ax25_ds_set_timer(ax25->ax25_dev);
spin_lock_bh(&ax25_list_lock);
for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) { for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
if (ax25o == ax25) if (ax25o == ax25)
continue; continue;
...@@ -118,6 +105,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25) ...@@ -118,6 +105,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
if (ax25o->state != AX25_STATE_0) if (ax25o->state != AX25_STATE_0)
ax25_start_t3timer(ax25o); ax25_start_t3timer(ax25o);
} }
spin_unlock_bh(&ax25_list_lock);
} }
void ax25_ds_establish_data_link(ax25_cb *ax25) void ax25_ds_establish_data_link(ax25_cb *ax25)
...@@ -132,8 +120,8 @@ void ax25_ds_establish_data_link(ax25_cb *ax25) ...@@ -132,8 +120,8 @@ void ax25_ds_establish_data_link(ax25_cb *ax25)
/* /*
* :::FIXME::: * :::FIXME:::
* This is a kludge. Not all drivers recognize kiss commands. * This is a kludge. Not all drivers recognize kiss commands.
* We need a driver level request to switch duplex mode, that does * We need a driver level request to switch duplex mode, that does
* either SCC changing, PI config or KISS as required. Currently * either SCC changing, PI config or KISS as required. Currently
* this request isn't reliable. * this request isn't reliable.
*/ */
...@@ -164,19 +152,24 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p ...@@ -164,19 +152,24 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p
* A nasty problem arises if we count the number of DAMA connections * A nasty problem arises if we count the number of DAMA connections
* wrong, especially when connections on the device already existed * wrong, especially when connections on the device already existed
* and our network node (or the sysop) decides to turn on DAMA Master * and our network node (or the sysop) decides to turn on DAMA Master
* mode. We thus flag the 'real' slave connections with * mode. We thus flag the 'real' slave connections with
* ax25->dama_slave=1 and look on every disconnect if still slave * ax25->dama_slave=1 and look on every disconnect if still slave
* connections exist. * connections exist.
*/ */
static int ax25_check_dama_slave(ax25_dev *ax25_dev) static int ax25_check_dama_slave(ax25_dev *ax25_dev)
{ {
ax25_cb *ax25; ax25_cb *ax25;
int res = 0;
spin_lock_bh(&ax25_list_lock);
for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next) for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next)
if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) {
return 1; res = 1;
break;
}
spin_unlock_bh(&ax25_list_lock);
return 0; return res;
} }
void ax25_dev_dama_on(ax25_dev *ax25_dev) void ax25_dev_dama_on(ax25_dev *ax25_dev)
......
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Cloned from ax25_timer.c.
* Joerg(DL1BKE) Added DAMA Slave Timeout timer
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/spinlock.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
...@@ -41,7 +34,7 @@ static void ax25_ds_timeout(unsigned long); ...@@ -41,7 +34,7 @@ static void ax25_ds_timeout(unsigned long);
/* /*
* Add DAMA slave timeout timer to timer list. * Add DAMA slave timeout timer to timer list.
* Unlike the connection based timers the timeout function gets * Unlike the connection based timers the timeout function gets
* triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT * triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT
* (aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in * (aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in
* 1/10th of a second. * 1/10th of a second.
...@@ -58,7 +51,8 @@ static void ax25_ds_add_timer(ax25_dev *ax25_dev) ...@@ -58,7 +51,8 @@ static void ax25_ds_add_timer(ax25_dev *ax25_dev)
void ax25_ds_del_timer(ax25_dev *ax25_dev) void ax25_ds_del_timer(ax25_dev *ax25_dev)
{ {
if (ax25_dev) del_timer(&ax25_dev->dama.slave_timer); if (ax25_dev)
del_timer(&ax25_dev->dama.slave_timer);
} }
void ax25_ds_set_timer(ax25_dev *ax25_dev) void ax25_ds_set_timer(ax25_dev *ax25_dev)
...@@ -80,15 +74,16 @@ static void ax25_ds_timeout(unsigned long arg) ...@@ -80,15 +74,16 @@ static void ax25_ds_timeout(unsigned long arg)
{ {
ax25_dev *ax25_dev = (struct ax25_dev *) arg; ax25_dev *ax25_dev = (struct ax25_dev *) arg;
ax25_cb *ax25; ax25_cb *ax25;
if (ax25_dev == NULL || !ax25_dev->dama.slave) if (ax25_dev == NULL || !ax25_dev->dama.slave)
return; /* Yikes! */ return; /* Yikes! */
if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) { if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) {
ax25_ds_set_timer(ax25_dev); ax25_ds_set_timer(ax25_dev);
return; return;
} }
spin_lock_bh(&ax25_list_lock);
for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) { for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) {
if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE)) if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
continue; continue;
...@@ -96,7 +91,8 @@ static void ax25_ds_timeout(unsigned long arg) ...@@ -96,7 +91,8 @@ static void ax25_ds_timeout(unsigned long arg)
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT); ax25_disconnect(ax25, ETIMEDOUT);
} }
spin_unlock_bh(&ax25_list_lock);
ax25_dev_dama_off(ax25_dev); ax25_dev_dama_off(ax25_dev);
} }
...@@ -104,33 +100,33 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25) ...@@ -104,33 +100,33 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_0: case AX25_STATE_0:
/* Magic here: If we listen() and a new link dies before it /* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */ is accepted() it isn't 'dead' so doesn't get removed. */
if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
ax25_destroy_socket(ax25); ax25_destroy_socket(ax25);
return; return;
}
break;
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;
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;
} }
ax25_start_heartbeat(ax25); ax25_start_heartbeat(ax25);
} }
/* dl1bke 960114: T3 works much like the IDLE timeout, but /* dl1bke 960114: T3 works much like the IDLE timeout, but
* gets reloaded with every frame for this * gets reloaded with every frame for this
* connection. * connection.
...@@ -168,7 +164,7 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25) ...@@ -168,7 +164,7 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
} }
/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC /* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
* within the poll of any connected channel. Remember * within the poll of any connected channel. Remember
* that we are not allowed to send anything unless we * that we are not allowed to send anything unless we
* get polled by the Master. * get polled by the Master.
* *
...@@ -176,48 +172,47 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25) ...@@ -176,48 +172,47 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
* ax25_enquiry_response(). * ax25_enquiry_response().
*/ */
void ax25_ds_t1_timeout(ax25_cb *ax25) void ax25_ds_t1_timeout(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_1:
case AX25_STATE_1: if (ax25->n2count == ax25->n2) {
if (ax25->n2count == ax25->n2) { if (ax25->modulus == AX25_MODULUS) {
if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25->n2count = 0;
ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
}
} else {
ax25->n2count++;
if (ax25->modulus == AX25_MODULUS)
ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
else
ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
}
break;
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
}
break;
case AX25_STATE_3:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
ax25_disconnect(ax25, ETIMEDOUT); ax25_disconnect(ax25, ETIMEDOUT);
return; return;
} else { } else {
ax25->n2count++; ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25->n2count = 0;
ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
} }
break; } else {
ax25->n2count++;
if (ax25->modulus == AX25_MODULUS)
ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
else
ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
}
break;
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
}
break;
case AX25_STATE_3:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
}
break;
} }
ax25_calculate_t1(ax25); ax25_calculate_t1(ax25);
......
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -20,6 +13,7 @@ ...@@ -20,6 +13,7 @@
#include <linux/in.h> #include <linux/in.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
...@@ -40,22 +34,25 @@ static struct protocol_struct { ...@@ -40,22 +34,25 @@ static struct protocol_struct {
unsigned int pid; unsigned int pid;
int (*func)(struct sk_buff *, ax25_cb *); int (*func)(struct sk_buff *, ax25_cb *);
} *protocol_list; } *protocol_list;
static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED;
static struct linkfail_struct { static struct linkfail_struct {
struct linkfail_struct *next; struct linkfail_struct *next;
void (*func)(ax25_cb *, int); void (*func)(ax25_cb *, int);
} *linkfail_list; } *linkfail_list;
static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED;
static struct listen_struct { static struct listen_struct {
struct listen_struct *next; struct listen_struct *next;
ax25_address callsign; ax25_address callsign;
struct net_device *dev; struct net_device *dev;
} *listen_list; } *listen_list;
static spinlock_t listen_lock = SPIN_LOCK_UNLOCKED;
int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_cb *)) int ax25_protocol_register(unsigned int pid,
int (*func)(struct sk_buff *, ax25_cb *))
{ {
struct protocol_struct *protocol; struct protocol_struct *protocol;
unsigned long flags;
if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT) if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT)
return 0; return 0;
...@@ -69,31 +66,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_ ...@@ -69,31 +66,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_
protocol->pid = pid; protocol->pid = pid;
protocol->func = func; protocol->func = func;
save_flags(flags); write_lock(&protocol_list_lock);
cli();
protocol->next = protocol_list; protocol->next = protocol_list;
protocol_list = protocol; protocol_list = protocol;
write_unlock(&protocol_list_lock);
restore_flags(flags);
return 1; return 1;
} }
void ax25_protocol_release(unsigned int pid) void ax25_protocol_release(unsigned int pid)
{ {
struct protocol_struct *s, *protocol = protocol_list; struct protocol_struct *s, *protocol;
unsigned long flags;
if (protocol == NULL) write_lock(&protocol_list_lock);
protocol = protocol_list;
if (protocol == NULL) {
write_unlock(&protocol_list_lock);
return; return;
}
save_flags(flags);
cli();
if (protocol->pid == pid) { if (protocol->pid == pid) {
protocol_list = protocol->next; protocol_list = protocol->next;
restore_flags(flags); write_unlock(&protocol_list_lock);
kfree(protocol); kfree(protocol);
return; return;
} }
...@@ -102,52 +96,45 @@ void ax25_protocol_release(unsigned int pid) ...@@ -102,52 +96,45 @@ void ax25_protocol_release(unsigned int pid)
if (protocol->next->pid == pid) { if (protocol->next->pid == pid) {
s = protocol->next; s = protocol->next;
protocol->next = protocol->next->next; protocol->next = protocol->next->next;
restore_flags(flags); write_unlock(&protocol_list_lock);
kfree(s); kfree(s);
return; return;
} }
protocol = protocol->next; protocol = protocol->next;
} }
write_unlock(&protocol_list_lock);
restore_flags(flags);
} }
int ax25_linkfail_register(void (*func)(ax25_cb *, int)) int ax25_linkfail_register(void (*func)(ax25_cb *, int))
{ {
struct linkfail_struct *linkfail; struct linkfail_struct *linkfail;
unsigned long flags;
if ((linkfail = kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL) if ((linkfail = kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL)
return 0; return 0;
linkfail->func = func; linkfail->func = func;
save_flags(flags); spin_lock_bh(&linkfail_lock);
cli();
linkfail->next = linkfail_list; linkfail->next = linkfail_list;
linkfail_list = linkfail; linkfail_list = linkfail;
spin_unlock_bh(&linkfail_lock);
restore_flags(flags);
return 1; return 1;
} }
void ax25_linkfail_release(void (*func)(ax25_cb *, int)) void ax25_linkfail_release(void (*func)(ax25_cb *, int))
{ {
struct linkfail_struct *s, *linkfail = linkfail_list; struct linkfail_struct *s, *linkfail;
unsigned long flags;
spin_lock_bh(&linkfail_lock);
linkfail = linkfail_list;
if (linkfail == NULL) if (linkfail == NULL)
return; return;
save_flags(flags);
cli();
if (linkfail->func == func) { if (linkfail->func == func) {
linkfail_list = linkfail->next; linkfail_list = linkfail->next;
restore_flags(flags); spin_unlock_bh(&linkfail_lock);
kfree(linkfail); kfree(linkfail);
return; return;
} }
...@@ -156,21 +143,19 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int)) ...@@ -156,21 +143,19 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int))
if (linkfail->next->func == func) { if (linkfail->next->func == func) {
s = linkfail->next; s = linkfail->next;
linkfail->next = linkfail->next->next; linkfail->next = linkfail->next->next;
restore_flags(flags); spin_unlock_bh(&linkfail_lock);
kfree(s); kfree(s);
return; return;
} }
linkfail = linkfail->next; linkfail = linkfail->next;
} }
spin_unlock_bh(&linkfail_lock);
restore_flags(flags);
} }
int ax25_listen_register(ax25_address *callsign, struct net_device *dev) int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
{ {
struct listen_struct *listen; struct listen_struct *listen;
unsigned long flags;
if (ax25_listen_mine(callsign, dev)) if (ax25_listen_mine(callsign, dev))
return 0; return 0;
...@@ -181,31 +166,26 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev) ...@@ -181,31 +166,26 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
listen->callsign = *callsign; listen->callsign = *callsign;
listen->dev = dev; listen->dev = dev;
save_flags(flags); spin_lock_bh(&listen_lock);
cli();
listen->next = listen_list; listen->next = listen_list;
listen_list = listen; listen_list = listen;
spin_unlock_bh(&listen_lock);
restore_flags(flags);
return 1; return 1;
} }
void ax25_listen_release(ax25_address *callsign, struct net_device *dev) void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
{ {
struct listen_struct *s, *listen = listen_list; struct listen_struct *s, *listen;
unsigned long flags;
spin_lock_bh(&listen_lock);
listen = listen_list;
if (listen == NULL) if (listen == NULL)
return; return;
save_flags(flags);
cli();
if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) { if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
listen_list = listen->next; listen_list = listen->next;
restore_flags(flags); spin_unlock_bh(&listen_lock);
kfree(listen); kfree(listen);
return; return;
} }
...@@ -214,35 +194,41 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev) ...@@ -214,35 +194,41 @@ void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) { if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) {
s = listen->next; s = listen->next;
listen->next = listen->next->next; listen->next = listen->next->next;
restore_flags(flags); spin_unlock_bh(&listen_lock);
kfree(s); kfree(s);
return; return;
} }
listen = listen->next; listen = listen->next;
} }
spin_unlock_bh(&listen_lock);
restore_flags(flags);
} }
int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *) int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
{ {
int (*res)(struct sk_buff *, ax25_cb *) = NULL;
struct protocol_struct *protocol; struct protocol_struct *protocol;
read_lock(&protocol_list_lock);
for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
if (protocol->pid == pid) if (protocol->pid == pid) {
return protocol->func; res = protocol->func;
break;
}
read_unlock(&protocol_list_lock);
return NULL; return res;
} }
int ax25_listen_mine(ax25_address *callsign, struct net_device *dev) int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
{ {
struct listen_struct *listen; struct listen_struct *listen;
spin_lock_bh(&listen_lock);
for (listen = listen_list; listen != NULL; listen = listen->next) for (listen = listen_list; listen != NULL; listen = listen->next)
if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL)) if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL))
return 1; return 1;
spin_unlock_bh(&listen_lock);
return 0; return 0;
} }
...@@ -251,18 +237,24 @@ void ax25_link_failed(ax25_cb *ax25, int reason) ...@@ -251,18 +237,24 @@ void ax25_link_failed(ax25_cb *ax25, int reason)
{ {
struct linkfail_struct *linkfail; struct linkfail_struct *linkfail;
spin_lock_bh(&linkfail_lock);
for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next) for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
(linkfail->func)(ax25, reason); (linkfail->func)(ax25, reason);
spin_unlock_bh(&linkfail_lock);
} }
int ax25_protocol_is_registered(unsigned int pid) int ax25_protocol_is_registered(unsigned int pid)
{ {
struct protocol_struct *protocol; struct protocol_struct *protocol;
int res = 0;
read_lock(&protocol_list_lock);
for (protocol = protocol_list; protocol != NULL; protocol = protocol->next) for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
if (protocol->pid == pid) if (protocol->pid == pid) {
return 1; res = 1;
break;
}
read_unlock(&protocol_list_lock);
return 0; return res;
} }
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* This module: * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* This module is free software; you can redistribute it and/or * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from
* the sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Added IP mode registration.
* AX.25 030 Jonathan(G4KLX) Added AX.25 fragment reception.
* Upgraded state machine for SABME.
* Added arbitrary protocol id support.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* HaJo(DD8NE) Added Idle Disc Timer T5
* Joerg(DL1BKE) Renamed it to "IDLE" with a slightly
* different behaviour. Fixed defrag
* routine (I hope)
* AX.25 032 Darryl(G7LED) AX.25 segmentation fixed.
* AX.25 033 Jonathan(G4KLX) Remove auto-router.
* Modularisation changes.
* AX.25 035 Hans(PE1AYX) Fixed interface to IP layer.
* AX.25 036 Jonathan(G4KLX) Move DAMA code into own file.
* Joerg(DL1BKE) Fixed DAMA Slave.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Thomas(DL9SAU) Fixed missing initialization of skb->protocol.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -146,7 +116,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) ...@@ -146,7 +116,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
#ifdef CONFIG_INET #ifdef CONFIG_INET
if (pid == AX25_P_IP) { if (pid == AX25_P_IP) {
/* working around a TCP bug to keep additional listeners /* working around a TCP bug to keep additional listeners
* happy. TCP re-uses the buffer and destroys the original * happy. TCP re-uses the buffer and destroys the original
* content. * content.
*/ */
...@@ -199,37 +169,33 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i ...@@ -199,37 +169,33 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
return 0; return 0;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
queued = ax25_std_frame_in(ax25, skb, type); queued = ax25_std_frame_in(ax25, skb, type);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (dama || ax25->ax25_dev->dama.slave) if (dama || ax25->ax25_dev->dama.slave)
queued = ax25_ds_frame_in(ax25, skb, type); queued = ax25_ds_frame_in(ax25, skb, type);
else else
queued = ax25_std_frame_in(ax25, skb, type); queued = ax25_std_frame_in(ax25, skb, type);
break; break;
#endif #endif
} }
return queued; return queued;
} }
static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *dev_addr, struct packet_type *ptype) static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
ax25_address *dev_addr, struct packet_type *ptype)
{ {
struct sock *make; ax25_address src, dest, *next_digi = NULL;
struct sock *sk; int type = 0, mine = 0, dama;
int type = 0; struct sock *make, *sk, *raw;
ax25_digi dp, reverse_dp; ax25_digi dp, reverse_dp;
ax25_cb *ax25; ax25_cb *ax25;
ax25_address src, dest;
ax25_address *next_digi = NULL;
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
struct sock *raw;
int mine = 0;
int dama;
/* /*
* Process the AX.25/LAPB frame. * Process the AX.25/LAPB frame.
...@@ -274,8 +240,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d ...@@ -274,8 +240,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) { if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
skb->h.raw = skb->data + 2; /* skip control and pid */ skb->h.raw = skb->data + 2; /* skip control and pid */
if ((raw = ax25_addr_match(&dest)) != NULL) if ((raw = ax25_addr_match(&dest)) != NULL) {
ax25_send_to_raw(raw, skb, skb->data[1]); ax25_send_to_raw(raw, skb, skb->data[1]);
release_sock(raw);
}
if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) {
kfree_skb(skb); kfree_skb(skb);
...@@ -285,47 +253,49 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d ...@@ -285,47 +253,49 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
/* Now we are pointing at the pid byte */ /* Now we are pointing at the pid byte */
switch (skb->data[1]) { switch (skb->data[1]) {
#ifdef CONFIG_INET #ifdef CONFIG_INET
case AX25_P_IP: case AX25_P_IP:
skb_pull(skb,2); /* drop PID/CTRL */ skb_pull(skb,2); /* drop PID/CTRL */
skb->h.raw = skb->data; skb->h.raw = skb->data;
skb->nh.raw = skb->data; skb->nh.raw = skb->data;
skb->dev = dev; skb->dev = dev;
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
skb->protocol = htons(ETH_P_IP); skb->protocol = htons(ETH_P_IP);
ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */
break; break;
case AX25_P_ARP: case AX25_P_ARP:
skb_pull(skb,2); skb_pull(skb,2);
skb->h.raw = skb->data; skb->h.raw = skb->data;
skb->nh.raw = skb->data; skb->nh.raw = skb->data;
skb->dev = dev; skb->dev = dev;
skb->pkt_type = PACKET_HOST; skb->pkt_type = PACKET_HOST;
skb->protocol = htons(ETH_P_ARP); skb->protocol = htons(ETH_P_ARP);
arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */
break; break;
#endif #endif
case AX25_P_TEXT: case AX25_P_TEXT:
/* Now find a suitable dgram socket */ /* Now find a suitable dgram socket */
if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) { sk = ax25_get_socket(&dest, &src, SOCK_DGRAM);
if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) { if (sk != NULL) {
kfree_skb(skb); if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) {
} else {
/*
* Remove the control and PID.
*/
skb_pull(skb, 2);
if (sock_queue_rcv_skb(sk, skb) != 0)
kfree_skb(skb);
}
} else {
kfree_skb(skb); kfree_skb(skb);
} else {
/*
* Remove the control and PID.
*/
skb_pull(skb, 2);
if (sock_queue_rcv_skb(sk, skb) != 0)
kfree_skb(skb);
} }
break; release_sock(sk);
} else {
kfree_skb(skb);
}
break;
default: default:
kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */ kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */
break; break;
} }
return 0; return 0;
...@@ -349,9 +319,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d ...@@ -349,9 +319,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) { if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) {
/* /*
* Process the frame. If it is queued up internally it returns one otherwise we * Process the frame. If it is queued up internally it
* free it immediately. This routine itself wakes the user context layers so we * returns one otherwise we free it immediately. This
* do no further work * routine itself wakes the user context layers so we do
* no further work
*/ */
if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
kfree_skb(skb); kfree_skb(skb);
...@@ -363,7 +334,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d ...@@ -363,7 +334,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
/* a) received not a SABM(E) */ /* a) received not a SABM(E) */
if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) { if ((*skb->data & ~AX25_PF) != AX25_SABM &&
(*skb->data & ~AX25_PF) != AX25_SABME) {
/* /*
* Never reply to a DM. Also ignore any connects for * Never reply to a DM. Also ignore any connects for
* addresses that are not our interfaces and not a socket. * addresses that are not our interfaces and not a socket.
...@@ -383,9 +355,12 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d ...@@ -383,9 +355,12 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET); sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);
if (sk != NULL) { if (sk != NULL) {
if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, ax25_dev)) == NULL) { if (sk->ack_backlog == sk->max_ack_backlog ||
if (mine) ax25_return_dm(dev, &src, &dest, &dp); (make = ax25_make_new(sk, ax25_dev)) == NULL) {
if (mine)
ax25_return_dm(dev, &src, &dest, &dp);
kfree_skb(skb); kfree_skb(skb);
return 0; return 0;
} }
...@@ -486,4 +461,3 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -486,4 +461,3 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev,
return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype); return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype);
} }
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 036 Jonathan(G4KLX) Split from af_ax25.c.
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -88,16 +81,16 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short ...@@ -88,16 +81,16 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short
/* Append a suitable AX.25 PID */ /* Append a suitable AX.25 PID */
switch (type) { switch (type) {
case ETH_P_IP: case ETH_P_IP:
*buff++ = AX25_P_IP; *buff++ = AX25_P_IP;
break; break;
case ETH_P_ARP: case ETH_P_ARP:
*buff++ = AX25_P_ARP; *buff++ = AX25_P_ARP;
break; break;
default: default:
printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type); printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
*buff++ = 0; *buff++ = 0;
break; break;
} }
if (daddr != NULL) if (daddr != NULL)
...@@ -112,8 +105,8 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -112,8 +105,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
unsigned char *bp = skb->data; unsigned char *bp = skb->data;
struct net_device *dev; struct net_device *dev;
ax25_address *src, *dst; ax25_address *src, *dst;
ax25_route *route;
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
ax25_route _route, *route = &_route;
dst = (ax25_address *)(bp + 1); dst = (ax25_address *)(bp + 1);
src = (ax25_address *)(bp + 8); src = (ax25_address *)(bp + 8);
...@@ -121,14 +114,15 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -121,14 +114,15 @@ int ax25_rebuild_header(struct sk_buff *skb)
if (arp_find(bp + 1, skb)) if (arp_find(bp + 1, skb))
return 1; return 1;
route = ax25_rt_find_route(dst, NULL); route = ax25_rt_find_route(route, dst, NULL);
dev = route->dev; dev = route->dev;
if (dev == NULL) if (dev == NULL)
dev = skb->dev; dev = skb->dev;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
return 1; goto put;
}
if (bp[16] == AX25_P_IP) { if (bp[16] == AX25_P_IP) {
if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) { if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
...@@ -153,7 +147,7 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -153,7 +147,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) { if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
kfree_skb(skb); kfree_skb(skb);
return 1; goto put;
} }
if (skb->sk != NULL) if (skb->sk != NULL)
...@@ -167,10 +161,10 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -167,10 +161,10 @@ int ax25_rebuild_header(struct sk_buff *skb)
skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */
ourskb->nh.raw = ourskb->data; ourskb->nh.raw = ourskb->data;
ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c, ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c,
&dst_c, route->digipeat, dev); &dst_c, route->digipeat, dev);
return 1; goto put;
} }
} }
...@@ -187,7 +181,7 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -187,7 +181,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if (route->digipeat != NULL) { if (route->digipeat != NULL) {
if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) { if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
kfree_skb(skb); kfree_skb(skb);
return 1; goto put;
} }
skb = ourskb; skb = ourskb;
...@@ -197,6 +191,9 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -197,6 +191,9 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_queue_xmit(skb); ax25_queue_xmit(skb);
put:
ax25_put_route(route);
return 1; return 1;
} }
......
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* This module: * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* Jonathan(G4KLX) Only poll when window is full.
* AX.25 030 Jonathan(G4KLX) Added fragmentation to ax25_output.
* Added support for extended AX.25.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* Joerg(DL1BKE) Modified fragmenter to fragment vanilla
* AX.25 I-Frames. Added PACLEN parameter.
* Joerg(DL1BKE) Fixed a problem with buffer allocation
* for fragments.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Joerg(DL1BKE) Fixed DAMA Slave mode: will work
* on non-DAMA interfaces like AX25L2V2
* again (this behaviour is _required_).
* Joerg(DL1BKE) ax25_check_iframes_acked() returns a
* value now (for DAMA n2count handling)
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -44,6 +18,7 @@ ...@@ -44,6 +18,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/spinlock.h>
#include <linux/net.h> #include <linux/net.h>
#include <net/ax25.h> #include <net/ax25.h>
#include <linux/inet.h> #include <linux/inet.h>
...@@ -57,6 +32,8 @@ ...@@ -57,6 +32,8 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
static spinlock_t ax25_frag_lock = SPIN_LOCK_UNLOCKED;
ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev) ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev)
{ {
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
...@@ -101,18 +78,18 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2 ...@@ -101,18 +78,18 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
} }
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_std_establish_data_link(ax25); ax25_std_establish_data_link(ax25);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (ax25_dev->dama.slave) if (ax25_dev->dama.slave)
ax25_ds_establish_data_link(ax25); ax25_ds_establish_data_link(ax25);
else else
ax25_std_establish_data_link(ax25); ax25_std_establish_data_link(ax25);
break; break;
#endif #endif
} }
...@@ -138,7 +115,6 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) ...@@ -138,7 +115,6 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
struct sk_buff *skbn; struct sk_buff *skbn;
unsigned char *p; unsigned char *p;
int frontlen, len, fragno, ka9qfrag, first = 1; int frontlen, len, fragno, ka9qfrag, first = 1;
long flags;
if ((skb->len - 1) > paclen) { if ((skb->len - 1) > paclen) {
if (*skb->data == AX25_P_TEXT) { if (*skb->data == AX25_P_TEXT) {
...@@ -155,20 +131,18 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) ...@@ -155,20 +131,18 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
frontlen = skb_headroom(skb); /* Address space + CTRL */ frontlen = skb_headroom(skb); /* Address space + CTRL */
while (skb->len > 0) { while (skb->len > 0) {
save_flags(flags); spin_lock_bh(&ax25_frag_lock);
cli();
if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) { if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) {
restore_flags(flags); spin_unlock_bh(&ax25_frag_lock);
printk(KERN_CRIT "AX.25: ax25_output - out of memory\n"); printk(KERN_CRIT "AX.25: ax25_output - out of memory\n");
return; return;
} }
if (skb->sk != NULL) if (skb->sk != NULL)
skb_set_owner_w(skbn, skb->sk); skb_set_owner_w(skbn, skb->sk);
restore_flags(flags); spin_unlock_bh(&ax25_frag_lock);
len = (paclen > skb->len) ? skb->len : paclen; len = (paclen > skb->len) ? skb->len : paclen;
if (ka9qfrag == 1) { if (ka9qfrag == 1) {
...@@ -202,24 +176,24 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) ...@@ -202,24 +176,24 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
} }
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_kick(ax25); ax25_kick(ax25);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
/* /*
* A DAMA slave is _required_ to work as normal AX.25L2V2 * A DAMA slave is _required_ to work as normal AX.25L2V2
* if no DAMA master is available. * if no DAMA master is available.
*/ */
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25); if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25);
break; break;
#endif #endif
} }
} }
/* /*
* This procedure is passed a buffer descriptor for an iframe. It builds * This procedure is passed a buffer descriptor for an iframe. It builds
* the rest of the control part of the frame and then writes it out. * the rest of the control part of the frame and then writes it out.
*/ */
...@@ -305,15 +279,15 @@ void ax25_kick(ax25_cb *ax25) ...@@ -305,15 +279,15 @@ void ax25_kick(ax25_cb *ax25)
* in DAMA mode. * in DAMA mode.
*/ */
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF); ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
break; break;
#ifdef CONFIG_AX25_DAMA_SLAVE #ifdef CONFIG_AX25_DAMA_SLAVE
case AX25_PROTO_DAMA_SLAVE: case AX25_PROTO_DAMA_SLAVE:
ax25_send_iframe(ax25, skbn, AX25_POLLOFF); ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
break; break;
#endif #endif
} }
......
This diff is collapsed.
This diff is collapsed.
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Most of this code is based on the SDL diagrams published in the 7th
* ARRL Computer Networking Conference papers. The diagrams have mistakes
* in them, but are mostly correct. Before you modify the code could you
* read the SDL diagrams as the code is not obvious and probably very
* easy to break;
*
* History
* AX.25 036 Jonathan(G4KLX) Split from ax25_out.c.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
...@@ -80,7 +66,7 @@ void ax25_std_transmit_enquiry(ax25_cb *ax25) ...@@ -80,7 +66,7 @@ void ax25_std_transmit_enquiry(ax25_cb *ax25)
ax25_calculate_t1(ax25); ax25_calculate_t1(ax25);
ax25_start_t1timer(ax25); ax25_start_t1timer(ax25);
} }
void ax25_std_enquiry_response(ax25_cb *ax25) void ax25_std_enquiry_response(ax25_cb *ax25)
{ {
if (ax25->condition & AX25_COND_OWN_RX_BUSY) if (ax25->condition & AX25_COND_OWN_RX_BUSY)
......
/* /*
* AX.25 release 037 * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
* This code REQUIRES 2.1.15 or higher/ NET3.038 * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* This module: * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* This module is free software; you can redistribute it and/or * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* AX.25 028a Jonathan(G4KLX) New state machine based on SDL diagrams.
* AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the
* sock structure.
* AX.25 029 Alan(GW4PTS) Switched to KA9Q constant names.
* AX.25 031 Joerg(DL1BKE) Added DAMA support
* AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout bug
* AX.25 033 Jonathan(G4KLX) Modularisation functions.
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* AX.25 036 Jonathan(G4KLX) Split from ax25_timer.c.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
...@@ -47,30 +34,29 @@ ...@@ -47,30 +34,29 @@
void ax25_std_heartbeat_expiry(ax25_cb *ax25) void ax25_std_heartbeat_expiry(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_0:
case AX25_STATE_0: /* Magic here: If we listen() and a new link dies before it
/* Magic here: If we listen() and a new link dies before it is accepted() it isn't 'dead' so doesn't get removed. */
is accepted() it isn't 'dead' so doesn't get removed. */ if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) { ax25_destroy_socket(ax25);
ax25_destroy_socket(ax25); return;
return; }
} break;
break;
case AX25_STATE_3:
case AX25_STATE_3: case AX25_STATE_4:
case AX25_STATE_4: /*
/* * Check the state of the receive buffer.
* Check the state of the receive buffer. */
*/ if (ax25->sk != NULL) {
if (ax25->sk != NULL) { if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
(ax25->condition & AX25_COND_OWN_RX_BUSY)) { ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
ax25->condition &= ~AX25_COND_OWN_RX_BUSY; ax25->condition &= ~AX25_COND_ACK_PENDING;
ax25->condition &= ~AX25_COND_ACK_PENDING; ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE); break;
break;
}
} }
}
} }
ax25_start_heartbeat(ax25); ax25_start_heartbeat(ax25);
...@@ -117,53 +103,53 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25) ...@@ -117,53 +103,53 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25)
void ax25_std_t1timer_expiry(ax25_cb *ax25) void ax25_std_t1timer_expiry(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_1: case AX25_STATE_1:
if (ax25->n2count == ax25->n2) { if (ax25->n2count == ax25->n2) {
if (ax25->modulus == AX25_MODULUS) { if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->modulus = AX25_MODULUS;
ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25->n2count = 0;
ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
}
} else {
ax25->n2count++;
if (ax25->modulus == AX25_MODULUS)
ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
else
ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
}
break;
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT); ax25_disconnect(ax25, ETIMEDOUT);
return; return;
} else { } else {
ax25->n2count++; ax25->modulus = AX25_MODULUS;
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
ax25->n2count = 0;
ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
} }
break; } else {
ax25->n2count++;
case AX25_STATE_3: if (ax25->modulus == AX25_MODULUS)
ax25->n2count = 1; ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
else
ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
}
break;
case AX25_STATE_2:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
}
break;
case AX25_STATE_3:
ax25->n2count = 1;
ax25_std_transmit_enquiry(ax25);
ax25->state = AX25_STATE_4;
break;
case AX25_STATE_4:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
ax25_std_transmit_enquiry(ax25); ax25_std_transmit_enquiry(ax25);
ax25->state = AX25_STATE_4; }
break; break;
case AX25_STATE_4:
if (ax25->n2count == ax25->n2) {
ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
ax25->n2count++;
ax25_std_transmit_enquiry(ax25);
}
break;
} }
ax25_calculate_t1(ax25); ax25_calculate_t1(ax25);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/* /*
* NET/ROM release 007 * This program is free software; you can redistribute it and/or modify
* * it under the terms of the GNU General Public License as published by
* This code REQUIRES 2.1.15 or higher/ NET3.038 * the Free Software Foundation; either version 2 of the License, or
* * (at your option) any later version.
* This module:
* This module is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* History
* NET/ROM 007 Tomi(OH2BNS) Created this file.
* Small change in nr_loopback_queue().
* *
* Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/timer.h> #include <linux/timer.h>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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