Commit a4041f6f authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/home/davem/BK/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 046e9c3b 1e96b980
...@@ -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
...@@ -1113,8 +1113,8 @@ L: netfilter-devel@lists.netfilter.org ...@@ -1113,8 +1113,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
...@@ -1363,8 +1363,8 @@ W: http://www.namesys.com ...@@ -1363,8 +1363,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
......
...@@ -2033,57 +2033,103 @@ static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) ...@@ -2033,57 +2033,103 @@ static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
/* This should not be decreased so low that ISNs wrap too fast. */ /* This should not be decreased so low that ISNs wrap too fast. */
#define REKEY_INTERVAL 300 #define REKEY_INTERVAL 300
/*
* Bit layout of the tcp sequence numbers (before adding current time):
* bit 24-31: increased after every key exchange
* bit 0-23: hash(source,dest)
*
* The implementation is similar to the algorithm described
* in the Appendix of RFC 1185, except that
* - it uses a 1 MHz clock instead of a 250 kHz clock
* - it performs a rekey every 5 minutes, which is equivalent
* to a (source,dest) tulple dependent forward jump of the
* clock by 0..2^(HASH_BITS+1)
*
* Thus the average ISN wraparound time is 68 minutes instead of
* 4.55 hours.
*
* SMP cleanup and lock avoidance with poor man's RCU.
* Manfred Spraul <manfred@colorfullife.com>
*
*/
#define COUNT_BITS 8
#define COUNT_MASK ( (1<<COUNT_BITS)-1)
#define HASH_BITS 24 #define HASH_BITS 24
#define HASH_MASK ( (1<<HASH_BITS)-1 )
static struct keydata {
time_t rekey_time;
__u32 count; // already shifted to the final position
__u32 secret[12];
} ____cacheline_aligned ip_keydata[2];
static spinlock_t ip_lock = SPIN_LOCK_UNLOCKED;
static unsigned int ip_cnt;
static struct keydata *__check_and_rekey(time_t time)
{
struct keydata *keyptr;
spin_lock(&ip_lock);
keyptr = &ip_keydata[ip_cnt&1];
if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
keyptr = &ip_keydata[1^(ip_cnt&1)];
keyptr->rekey_time = time;
get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
keyptr->count = (ip_cnt&COUNT_MASK)<<HASH_BITS;
mb();
ip_cnt++;
}
spin_unlock(&ip_lock);
return keyptr;
}
static inline struct keydata *check_and_rekey(time_t time)
{
struct keydata *keyptr = &ip_keydata[ip_cnt&1];
rmb();
if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
keyptr = __check_and_rekey(time);
}
return keyptr;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
__u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
__u16 sport, __u16 dport) __u16 sport, __u16 dport)
{ {
static __u32 rekey_time;
static __u32 count;
static __u32 secret[12];
struct timeval tv; struct timeval tv;
__u32 seq; __u32 seq;
__u32 hash[12];
struct keydata *keyptr;
/* The procedure is the same as for IPv4, but addresses are longer. */ /* The procedure is the same as for IPv4, but addresses are longer.
* Thus we must use twothirdsMD4Transform.
*/
do_gettimeofday(&tv); /* We need the usecs below... */ do_gettimeofday(&tv); /* We need the usecs below... */
keyptr = check_and_rekey(tv.tv_sec);
if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) { memcpy(hash, saddr, 16);
rekey_time = tv.tv_sec; hash[4]=(sport << 16) + dport;
/* First five words are overwritten below. */ memcpy(&hash[5],keyptr->secret,sizeof(__u32)*7);
get_random_bytes(&secret[5], sizeof(secret)-5*4);
count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
}
memcpy(secret, saddr, 16);
secret[4]=(sport << 16) + dport;
seq = (twothirdsMD4Transform(daddr, secret) &
((1<<HASH_BITS)-1)) + count;
seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK;
seq += keyptr->count;
seq += tv.tv_usec + tv.tv_sec*1000000; seq += tv.tv_usec + tv.tv_sec*1000000;
return seq; return seq;
} }
EXPORT_SYMBOL(secure_tcpv6_sequence_number); EXPORT_SYMBOL(secure_tcpv6_sequence_number);
__u32 secure_ipv6_id(__u32 *daddr) __u32 secure_ipv6_id(__u32 *daddr)
{ {
static time_t rekey_time; struct keydata *keyptr;
static __u32 secret[12];
time_t t;
/* keyptr = check_and_rekey(CURRENT_TIME);
* Pick a random secret every REKEY_INTERVAL seconds.
*/
t = CURRENT_TIME;
if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
rekey_time = t;
/* First word is overwritten below. */
get_random_bytes(secret, sizeof(secret));
}
return twothirdsMD4Transform(daddr, secret); return halfMD4Transform(daddr, keyptr->secret);
} }
EXPORT_SYMBOL(secure_ipv6_id); EXPORT_SYMBOL(secure_ipv6_id);
...@@ -2093,40 +2139,30 @@ EXPORT_SYMBOL(secure_ipv6_id); ...@@ -2093,40 +2139,30 @@ EXPORT_SYMBOL(secure_ipv6_id);
__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
__u16 sport, __u16 dport) __u16 sport, __u16 dport)
{ {
static __u32 rekey_time;
static __u32 count;
static __u32 secret[12];
struct timeval tv; struct timeval tv;
__u32 seq; __u32 seq;
__u32 hash[4];
struct keydata *keyptr;
/* /*
* Pick a random secret every REKEY_INTERVAL seconds. * Pick a random secret every REKEY_INTERVAL seconds.
*/ */
do_gettimeofday(&tv); /* We need the usecs below... */ do_gettimeofday(&tv); /* We need the usecs below... */
keyptr = check_and_rekey(tv.tv_sec);
if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
rekey_time = tv.tv_sec;
/* First three words are overwritten below. */
get_random_bytes(&secret[3], sizeof(secret)-12);
count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
}
/* /*
* Pick a unique starting offset for each TCP connection endpoints * Pick a unique starting offset for each TCP connection endpoints
* (saddr, daddr, sport, dport). * (saddr, daddr, sport, dport).
* Note that the words are placed into the first words to be * Note that the words are placed into the starting vector, which is
* mixed in with the halfMD4. This is because the starting * then mixed with a partial MD4 over random data.
* vector is also a random secret (at secret+8), and further
* hashing fixed data into it isn't going to improve anything,
* so we should get started with the variable data.
*/ */
secret[0]=saddr; hash[0]=saddr;
secret[1]=daddr; hash[1]=daddr;
secret[2]=(sport << 16) + dport; hash[2]=(sport << 16) + dport;
hash[3]=keyptr->secret[11];
seq = (halfMD4Transform(secret+8, secret) &
((1<<HASH_BITS)-1)) + count;
seq = halfMD4Transform(hash, keyptr->secret) & HASH_MASK;
seq += keyptr->count;
/* /*
* As close as possible to RFC 793, which * As close as possible to RFC 793, which
* suggests using a 250 kHz clock. * suggests using a 250 kHz clock.
...@@ -2148,31 +2184,22 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, ...@@ -2148,31 +2184,22 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
*/ */
__u32 secure_ip_id(__u32 daddr) __u32 secure_ip_id(__u32 daddr)
{ {
static time_t rekey_time; struct keydata *keyptr;
static __u32 secret[12]; __u32 hash[4];
time_t t;
/* keyptr = check_and_rekey(CURRENT_TIME);
* Pick a random secret every REKEY_INTERVAL seconds.
*/
t = CURRENT_TIME;
if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
rekey_time = t;
/* First word is overwritten below. */
get_random_bytes(secret+1, sizeof(secret)-4);
}
/* /*
* Pick a unique starting offset for each IP destination. * Pick a unique starting offset for each IP destination.
* Note that the words are placed into the first words to be * The dest ip address is placed in the starting vector,
* mixed in with the halfMD4. This is because the starting * which is then hashed with random data.
* vector is also a random secret (at secret+8), and further
* hashing fixed data into it isn't going to improve anything,
* so we should get started with the variable data.
*/ */
secret[0]=daddr; hash[0] = daddr;
hash[1] = keyptr->secret[9];
hash[2] = keyptr->secret[10];
hash[3] = keyptr->secret[11];
return halfMD4Transform(secret+8, secret); return halfMD4Transform(hash, keyptr->secret);
} }
#ifdef CONFIG_SYN_COOKIES #ifdef CONFIG_SYN_COOKIES
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/mii.h> #include <linux/mii.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -49,7 +51,9 @@ ...@@ -49,7 +51,9 @@
#endif #endif
#ifdef NETIF_F_TSO #ifdef NETIF_F_TSO
/* XXX some bug in tso firmware hangs tx cpu, disabled until fixed */ /* XXX Works but still disabled, decreases TCP performance to 7MB/sec even
* XXX over gigabit.
*/
#define TG3_DO_TSO 0 #define TG3_DO_TSO 0
#else #else
#define TG3_DO_TSO 0 #define TG3_DO_TSO 0
...@@ -2390,9 +2394,20 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev) ...@@ -2390,9 +2394,20 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
if (skb->ip_summed == CHECKSUM_HW) if (skb->ip_summed == CHECKSUM_HW)
base_flags |= TXD_FLAG_TCPUDP_CSUM; base_flags |= TXD_FLAG_TCPUDP_CSUM;
#if TG3_DO_TSO != 0 #if TG3_DO_TSO != 0
if ((mss = skb_shinfo(skb)->tso_size) != 0) if ((mss = skb_shinfo(skb)->tso_size) != 0) {
static int times = 0;
mss += ((skb->h.th->doff * 4) - 20);
base_flags |= (TXD_FLAG_CPU_PRE_DMA | base_flags |= (TXD_FLAG_CPU_PRE_DMA |
TXD_FLAG_CPU_POST_DMA); TXD_FLAG_CPU_POST_DMA);
if (times++ < 5) {
printk("tg3_xmit: tso_size[%u] tso_segs[%u] len[%u]\n",
(unsigned int) skb_shinfo(skb)->tso_size,
(unsigned int) skb_shinfo(skb)->tso_segs,
skb->len);
}
}
#else #else
mss = 0; mss = 0;
#endif #endif
...@@ -2443,7 +2458,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev) ...@@ -2443,7 +2458,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
} }
tg3_set_txd(tp, entry, mapping, len, tg3_set_txd(tp, entry, mapping, len,
base_flags, (i == last) | (mss << 1)); base_flags, (i == last));
entry = NEXT_TX(entry); entry = NEXT_TX(entry);
} }
...@@ -2555,9 +2570,24 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2555,9 +2570,24 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->ip_summed == CHECKSUM_HW) if (skb->ip_summed == CHECKSUM_HW)
base_flags |= TXD_FLAG_TCPUDP_CSUM; base_flags |= TXD_FLAG_TCPUDP_CSUM;
#if TG3_DO_TSO != 0 #if TG3_DO_TSO != 0
if ((mss = skb_shinfo(skb)->tso_size) != 0) if ((mss = skb_shinfo(skb)->tso_size) != 0) {
static int times = 0;
/* TSO firmware wants TCP options included in
* tx descriptor MSS value.
*/
mss += ((skb->h.th->doff * 4) - 20);
base_flags |= (TXD_FLAG_CPU_PRE_DMA | base_flags |= (TXD_FLAG_CPU_PRE_DMA |
TXD_FLAG_CPU_POST_DMA); TXD_FLAG_CPU_POST_DMA);
if (times++ < 5) {
printk("tg3_xmit: tso_size[%u] tso_segs[%u] len[%u]\n",
(unsigned int) skb_shinfo(skb)->tso_size,
(unsigned int) skb_shinfo(skb)->tso_segs,
skb->len);
}
}
#else #else
mss = 0; mss = 0;
#endif #endif
...@@ -2597,7 +2627,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2597,7 +2627,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
tg3_set_txd(tp, entry, mapping, len, tg3_set_txd(tp, entry, mapping, len,
base_flags, (i == last) | (mss << 1)); base_flags, (i == last));
entry = NEXT_TX(entry); entry = NEXT_TX(entry);
} }
...@@ -4329,9 +4359,11 @@ static int tg3_reset_hw(struct tg3 *tp) ...@@ -4329,9 +4359,11 @@ static int tg3_reset_hw(struct tg3 *tp)
} }
#if TG3_DO_TSO != 0 #if TG3_DO_TSO != 0
if (tp->dev->features & NETIF_F_TSO) {
err = tg3_load_tso_firmware(tp); err = tg3_load_tso_firmware(tp);
if (err) if (err)
return err; return err;
}
#endif #endif
tp->tx_mode = TX_MODE_ENABLE; tp->tx_mode = TX_MODE_ENABLE;
...@@ -6752,9 +6784,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, ...@@ -6752,9 +6784,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev->vlan_rx_register = tg3_vlan_rx_register; dev->vlan_rx_register = tg3_vlan_rx_register;
dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid; dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid;
#endif #endif
#if TG3_DO_TSO != 0
dev->features |= NETIF_F_TSO;
#endif
tp = dev->priv; tp = dev->priv;
tp->pdev = pdev; tp->pdev = pdev;
...@@ -6855,6 +6884,17 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, ...@@ -6855,6 +6884,17 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
} else } else
tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
#if TG3_DO_TSO != 0
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
tp->pci_chip_rev_id <= CHIPREV_ID_5701_B2)) {
/* Not TSO capable. */
dev->features &= ~NETIF_F_TSO;
} else {
dev->features |= NETIF_F_TSO;
}
#endif
err = register_netdev(dev); err = register_netdev(dev);
if (err) { if (err) {
printk(KERN_ERR PFX "Cannot register net device, " printk(KERN_ERR PFX "Cannot register net device, "
......
...@@ -275,7 +275,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun, ...@@ -275,7 +275,7 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
total += sizeof(pi); total += sizeof(pi);
} }
len = min(skb->len, len); len = min_t(int, skb->len, len);
skb_copy_datagram_iovec(skb, 0, iv, len); skb_copy_datagram_iovec(skb, 0, iv, len);
total += len; total += len;
...@@ -306,6 +306,8 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv, ...@@ -306,6 +306,8 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
return -EFAULT; return -EFAULT;
len += iv[i].iov_len; len += iv[i].iov_len;
} }
if (len < 0)
return -EINVAL;
add_wait_queue(&tun->read_wait, &wait); add_wait_queue(&tun->read_wait, &wait);
while (len) { while (len) {
......
...@@ -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);
......
...@@ -45,4 +45,5 @@ extern int llc_station_ac_report_status(struct llc_station *station, ...@@ -45,4 +45,5 @@ extern int llc_station_ac_report_status(struct llc_station *station,
struct sk_buff *skb); struct sk_buff *skb);
extern int llc_station_ac_report_status(struct llc_station *station, extern int llc_station_ac_report_status(struct llc_station *station,
struct sk_buff *skb); struct sk_buff *skb);
extern void llc_station_ack_tmr_cb(unsigned long timeout_data);
#endif /* LLC_ACTN_H */ #endif /* LLC_ACTN_H */
...@@ -211,4 +211,9 @@ extern int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock* sk, ...@@ -211,4 +211,9 @@ extern int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock* sk,
struct sk_buff *skb); struct sk_buff *skb);
extern int llc_conn_ac_send_i_rsp_as_ack(struct sock* sk, struct sk_buff *skb); extern int llc_conn_ac_send_i_rsp_as_ack(struct sock* sk, struct sk_buff *skb);
extern int llc_conn_ac_send_i_as_ack(struct sock* sk, struct sk_buff *skb); extern int llc_conn_ac_send_i_as_ack(struct sock* sk, struct sk_buff *skb);
extern void llc_conn_busy_tmr_cb(unsigned long timeout_data);
extern void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data);
extern void llc_conn_ack_tmr_cb(unsigned long timeout_data);
extern void llc_conn_rej_tmr_cb(unsigned long timeout_data);
#endif /* LLC_C_AC_H */ #endif /* LLC_C_AC_H */
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
* *
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <net/sock.h>
/* Connection component state transition event qualifiers */ /* Connection component state transition event qualifiers */
/* Types of events (possible values in 'ev->type') */ /* Types of events (possible values in 'ev->type') */
#define LLC_CONN_EV_TYPE_SIMPLE 1 #define LLC_CONN_EV_TYPE_SIMPLE 1
...@@ -293,4 +296,10 @@ extern int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk, ...@@ -293,4 +296,10 @@ extern int llc_conn_ev_qlfy_set_status_conflict(struct sock *sk,
struct sk_buff *skb); struct sk_buff *skb);
extern int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk, extern int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk,
struct sk_buff *skb); struct sk_buff *skb);
static __inline__ int llc_conn_space(struct sock *sk, struct sk_buff *skb)
{
return atomic_read(&sk->rmem_alloc) + skb->truesize <
(unsigned)sk->rcvbuf;
}
#endif /* LLC_C_EV_H */ #endif /* LLC_C_EV_H */
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#define LLC_TYPE_1 1 #define LLC_TYPE_1 1
#define LLC_TYPE_2 2 #define LLC_TYPE_2 2
#define LLC_P_TIME 2 #define LLC_P_TIME 2
#define LLC_ACK_TIME 3 #define LLC_ACK_TIME 1
#define LLC_REJ_TIME 3 #define LLC_REJ_TIME 3
#define LLC_BUSY_TIME 3 #define LLC_BUSY_TIME 3
#define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */ #define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */
......
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>
......
/* /*
* 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();
} }
...@@ -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);
} }
/* /*
* 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_in.c
* Joerg(DL1BKE) Fixed it.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Joerg(DL1BKE) ax25->n2count never got reset
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
...@@ -95,11 +80,13 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet ...@@ -95,11 +80,13 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
break; break;
case AX25_DM: case AX25_DM:
if (pf) ax25_disconnect(ax25, ECONNREFUSED); if (pf)
ax25_disconnect(ax25, ECONNREFUSED);
break; break;
default: default:
if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND); if (pf)
ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
break; break;
} }
......
/* /*
* 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>
...@@ -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)
...@@ -171,12 +159,17 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p ...@@ -171,12 +159,17 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p
static int ax25_check_dama_slave(ax25_dev *ax25_dev) static int ax25_check_dama_slave(ax25_dev *ax25_dev)
{ {
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>
...@@ -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)
...@@ -89,6 +83,7 @@ static void ax25_ds_timeout(unsigned long arg) ...@@ -89,6 +83,7 @@ static void ax25_ds_timeout(unsigned long arg)
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,6 +91,7 @@ static void ax25_ds_timeout(unsigned long arg) ...@@ -96,6 +91,7 @@ static void ax25_ds_timeout(unsigned long arg)
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND); ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT); ax25_disconnect(ax25, ETIMEDOUT);
} }
spin_unlock_bh(&ax25_list_lock);
ax25_dev_dama_off(ax25_dev); ax25_dev_dama_off(ax25_dev);
} }
...@@ -178,7 +174,6 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25) ...@@ -178,7 +174,6 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
void ax25_ds_t1_timeout(ax25_cb *ax25) void ax25_ds_t1_timeout(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_1: case AX25_STATE_1:
if (ax25->n2count == ax25->n2) { if (ax25->n2count == ax25->n2) {
if (ax25->modulus == AX25_MODULUS) { if (ax25->modulus == AX25_MODULUS) {
......
/* /*
* 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>
...@@ -217,19 +187,15 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i ...@@ -217,19 +187,15 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
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);
...@@ -307,7 +275,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d ...@@ -307,7 +275,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
#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 (sk != NULL) {
if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) { if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) {
kfree_skb(skb); kfree_skb(skb);
} else { } else {
...@@ -318,6 +287,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d ...@@ -318,6 +287,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
if (sock_queue_rcv_skb(sk, skb) != 0) if (sock_queue_rcv_skb(sk, skb) != 0)
kfree_skb(skb); kfree_skb(skb);
} }
release_sock(sk);
} else { } else {
kfree_skb(skb); kfree_skb(skb);
} }
...@@ -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>
...@@ -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)
...@@ -170,7 +164,7 @@ int ax25_rebuild_header(struct sk_buff *skb) ...@@ -170,7 +164,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c, ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c,
&dst_c, route->digipeat, dev); &dst_c, route->digipeat, dev);
return 1; goto put;
} }
} }
...@@ -187,7 +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;
...@@ -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,11 +131,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) ...@@ -155,11 +131,9 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
frontlen = skb_headroom(skb); /* Address space + CTRL */ frontlen = skb_headroom(skb); /* Address space + CTRL */
while (skb->len > 0) { while (skb->len > 0) {
save_flags(flags); spin_lock_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;
} }
...@@ -167,7 +141,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) ...@@ -167,7 +141,7 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
if (skb->sk != NULL) if (skb->sk != NULL)
skb_set_owner_w(skbn, skb->sk); skb_set_owner_w(skbn, skb->sk);
restore_flags(flags); spin_unlock_bh(&ax25_frag_lock);
len = (paclen > skb->len) ? skb->len : paclen; len = (paclen > skb->len) ? skb->len : paclen;
......
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) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
* *
* This module: * Most of this code is based on the SDL diagrams published in the 7th ARRL
* This module is free software; you can redistribute it and/or * Computer Networking Conference papers. The diagrams have mistakes in them,
* modify it under the terms of the GNU General Public License * but are mostly correct. Before you modify the code could you read the SDL
* as published by the Free Software Foundation; either version * diagrams as the code is not obvious and probably very easy to break.
* 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) Cloned from ax25_in.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>
...@@ -142,7 +119,8 @@ static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frame ...@@ -142,7 +119,8 @@ static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
case AX25_DM: case AX25_DM:
case AX25_UA: case AX25_UA:
if (pf) ax25_disconnect(ax25, 0); if (pf)
ax25_disconnect(ax25, 0);
break; break;
case AX25_I: case AX25_I:
...@@ -397,7 +375,8 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame ...@@ -397,7 +375,8 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
} }
ax25_frames_acked(ax25, nr); ax25_frames_acked(ax25, nr);
if (ax25->condition & AX25_COND_OWN_RX_BUSY) { if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
if (pf) ax25_std_enquiry_response(ax25); if (pf)
ax25_std_enquiry_response(ax25);
break; break;
} }
if (ns == ax25->vr) { if (ns == ax25->vr) {
......
/* /*
* 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>
......
/* /*
* 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,7 +34,6 @@ ...@@ -47,7 +34,6 @@
void ax25_std_heartbeat_expiry(ax25_cb *ax25) void ax25_std_heartbeat_expiry(ax25_cb *ax25)
{ {
switch (ax25->state) { switch (ax25->state) {
case AX25_STATE_0: case AX25_STATE_0:
/* Magic here: If we listen() and a new link dies before it /* Magic here: If we listen() and a new link dies before it
is accepted() it isn't 'dead' so doesn't get removed. */ is accepted() it isn't 'dead' so doesn't get removed. */
......
/* /*
* 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.
*
* 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 029 Alan(GW4PTS) Switched to KA9Q constant names. Removed
* old BSD code.
* AX.25 030 Jonathan(G4KLX) Added support for extended AX.25.
* Added fragmentation support.
* Darryl(G7LED) Added function ax25_requeue_frames() to split
* it up from ax25_frames_acked().
* AX.25 031 Joerg(DL1BKE) DAMA needs KISS Fullduplex ON/OFF.
* Thus we have ax25_kiss_cmd() now... ;-)
* Dave Brown(N2RJT)
* Killed a silly bug in the DAMA code.
* Joerg(DL1BKE) Found the real bug in ax25.h, sri.
* AX.25 032 Joerg(DL1BKE) Added ax25_queue_length to count the number of
* enqueued buffers of a socket..
* AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
* 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>
......
/* /*
* 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) Tomi Manninen OH2BNS (oh2bns@sral.fi)
* This module is free software; you can redistribute it and/or * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
* modify it under the terms of the GNU General Public License * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
* as published by the Free Software Foundation; either version * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
* 2 of the License, or (at your option) any later version. * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
*
* 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 Standard and DAMA code into separate files.
* Joerg(DL1BKE) Fixed DAMA Slave. We are *required* to start with
* standard AX.25 mode.
* AX.25 037 Jonathan(G4KLX) New timer architecture.
* Tomi(OH2BNS) Fixed heartbeat expiry (check ax25_dev).
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -152,12 +139,15 @@ unsigned long ax25_display_timer(struct timer_list *timer) ...@@ -152,12 +139,15 @@ unsigned long ax25_display_timer(struct timer_list *timer)
static void ax25_heartbeat_expiry(unsigned long param) static void ax25_heartbeat_expiry(unsigned long param)
{ {
ax25_cb *ax25 = (ax25_cb *)param;
int proto = AX25_PROTO_STD_SIMPLEX; int proto = AX25_PROTO_STD_SIMPLEX;
ax25_cb *ax25 = (ax25_cb *)param;
struct sock *sk = ax25->sk;
if (ax25->ax25_dev) if (ax25->ax25_dev)
proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]; proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL];
bh_lock_sock(sk);
switch (proto) { switch (proto) {
case AX25_PROTO_STD_SIMPLEX: case AX25_PROTO_STD_SIMPLEX:
case AX25_PROTO_STD_DUPLEX: case AX25_PROTO_STD_DUPLEX:
...@@ -173,12 +163,15 @@ static void ax25_heartbeat_expiry(unsigned long param) ...@@ -173,12 +163,15 @@ static void ax25_heartbeat_expiry(unsigned long param)
break; break;
#endif #endif
} }
bh_unlock_sock(sk);
} }
static void ax25_t1timer_expiry(unsigned long param) static void ax25_t1timer_expiry(unsigned long param)
{ {
ax25_cb *ax25 = (ax25_cb *)param; ax25_cb *ax25 = (ax25_cb *)param;
struct sock *sk = ax25->sk;
bh_lock_sock(sk);
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:
...@@ -192,12 +185,15 @@ static void ax25_t1timer_expiry(unsigned long param) ...@@ -192,12 +185,15 @@ static void ax25_t1timer_expiry(unsigned long param)
break; break;
#endif #endif
} }
bh_unlock_sock(sk);
} }
static void ax25_t2timer_expiry(unsigned long param) static void ax25_t2timer_expiry(unsigned long param)
{ {
ax25_cb *ax25 = (ax25_cb *)param; ax25_cb *ax25 = (ax25_cb *)param;
struct sock *sk = ax25->sk;
bh_lock_sock(sk);
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:
...@@ -211,12 +207,15 @@ static void ax25_t2timer_expiry(unsigned long param) ...@@ -211,12 +207,15 @@ static void ax25_t2timer_expiry(unsigned long param)
break; break;
#endif #endif
} }
bh_unlock_sock(sk);
} }
static void ax25_t3timer_expiry(unsigned long param) static void ax25_t3timer_expiry(unsigned long param)
{ {
ax25_cb *ax25 = (ax25_cb *)param; ax25_cb *ax25 = (ax25_cb *)param;
struct sock *sk = ax25->sk;
bh_lock_sock(sk);
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:
...@@ -232,12 +231,15 @@ static void ax25_t3timer_expiry(unsigned long param) ...@@ -232,12 +231,15 @@ static void ax25_t3timer_expiry(unsigned long param)
break; break;
#endif #endif
} }
bh_unlock_sock(sk);
} }
static void ax25_idletimer_expiry(unsigned long param) static void ax25_idletimer_expiry(unsigned long param)
{ {
ax25_cb *ax25 = (ax25_cb *)param; ax25_cb *ax25 = (ax25_cb *)param;
struct sock *sk = ax25->sk;
bh_lock_sock(sk);
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:
...@@ -253,4 +255,5 @@ static void ax25_idletimer_expiry(unsigned long param) ...@@ -253,4 +255,5 @@ static void ax25_idletimer_expiry(unsigned long param)
break; break;
#endif #endif
} }
bh_unlock_sock(sk);
} }
/* /*
* 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/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/socket.h> #include <linux/socket.h>
...@@ -23,6 +16,7 @@ ...@@ -23,6 +16,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/net.h> #include <linux/net.h>
#include <linux/spinlock.h>
#include <net/ax25.h> #include <net/ax25.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -47,17 +41,23 @@ ...@@ -47,17 +41,23 @@
*/ */
static ax25_uid_assoc *ax25_uid_list; static ax25_uid_assoc *ax25_uid_list;
static rwlock_t ax25_uid_lock = RW_LOCK_UNLOCKED;
int ax25_uid_policy = 0; int ax25_uid_policy = 0;
ax25_address *ax25_findbyuid(uid_t uid) ax25_address *ax25_findbyuid(uid_t uid)
{ {
ax25_uid_assoc *ax25_uid; ax25_uid_assoc *ax25_uid;
ax25_address *res = NULL;
read_lock(&ax25_uid_lock);
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
if (ax25_uid->uid == uid) if (ax25_uid->uid == uid) {
return &ax25_uid->call; res = &ax25_uid->call;
break;
}
} }
read_unlock(&ax25_uid_lock);
return NULL; return NULL;
} }
...@@ -65,15 +65,21 @@ ax25_address *ax25_findbyuid(uid_t uid) ...@@ -65,15 +65,21 @@ ax25_address *ax25_findbyuid(uid_t uid)
int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
{ {
ax25_uid_assoc *s, *ax25_uid; ax25_uid_assoc *s, *ax25_uid;
unsigned long flags; unsigned long res;
switch (cmd) { switch (cmd) {
case SIOCAX25GETUID: case SIOCAX25GETUID:
res = -ENOENT;
read_lock(&ax25_uid_lock);
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
return ax25_uid->uid; res = ax25_uid->uid;
break;
} }
return -ENOENT; }
read_unlock(&ax25_uid_lock);
return res;
case SIOCAX25ADDUID: case SIOCAX25ADDUID:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
...@@ -84,40 +90,48 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax) ...@@ -84,40 +90,48 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
return -EINVAL; return -EINVAL;
if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL) if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
return -ENOMEM; return -ENOMEM;
ax25_uid->uid = sax->sax25_uid; ax25_uid->uid = sax->sax25_uid;
ax25_uid->call = sax->sax25_call; ax25_uid->call = sax->sax25_call;
save_flags(flags); cli();
write_lock(&ax25_uid_lock);
ax25_uid->next = ax25_uid_list; ax25_uid->next = ax25_uid_list;
ax25_uid_list = ax25_uid; ax25_uid_list = ax25_uid;
restore_flags(flags); write_unlock(&ax25_uid_lock);
return 0; return 0;
case SIOCAX25DELUID: case SIOCAX25DELUID:
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
write_lock(&ax25_uid_lock);
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) { for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
break; break;
} }
if (ax25_uid == NULL) }
if (ax25_uid == NULL) {
write_unlock(&ax25_uid_lock);
return -ENOENT; return -ENOENT;
save_flags(flags); cli(); }
if ((s = ax25_uid_list) == ax25_uid) { if ((s = ax25_uid_list) == ax25_uid) {
ax25_uid_list = s->next; ax25_uid_list = s->next;
restore_flags(flags); write_unlock(&ax25_uid_lock);
kfree(ax25_uid); kfree(ax25_uid);
return 0; return 0;
} }
while (s != NULL && s->next != NULL) { while (s != NULL && s->next != NULL) {
if (s->next == ax25_uid) { if (s->next == ax25_uid) {
s->next = ax25_uid->next; s->next = ax25_uid->next;
restore_flags(flags); write_unlock(&ax25_uid_lock);
kfree(ax25_uid); kfree(ax25_uid);
return 0; return 0;
} }
s = s->next; s = s->next;
} }
restore_flags(flags); write_unlock(&ax25_uid_lock);
return -ENOENT; return -ENOENT;
default: default:
...@@ -134,8 +148,7 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -134,8 +148,7 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0; off_t pos = 0;
off_t begin = 0; off_t begin = 0;
cli(); read_lock(&ax25_uid_lock);
len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy); len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy);
for (pt = ax25_uid_list; pt != NULL; pt = pt->next) { for (pt = ax25_uid_list; pt != NULL; pt = pt->next) {
...@@ -151,13 +164,13 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -151,13 +164,13 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length) if (pos > offset + length)
break; break;
} }
read_unlock(&ax25_uid_lock);
sti();
*start = buffer + (offset - begin); *start = buffer + (offset - begin);
len -= offset - begin; len -= offset - begin;
if (len > length) len = length; if (len > length)
len = length;
return len; return len;
} }
...@@ -167,12 +180,16 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -167,12 +180,16 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
*/ */
void __exit ax25_uid_free(void) void __exit ax25_uid_free(void)
{ {
ax25_uid_assoc *s, *ax25_uid = ax25_uid_list; ax25_uid_assoc *s, *ax25_uid;
write_lock(&ax25_uid_lock);
ax25_uid = ax25_uid_list;
while (ax25_uid != NULL) { while (ax25_uid != NULL) {
s = ax25_uid; s = ax25_uid;
ax25_uid = ax25_uid->next; ax25_uid = ax25_uid->next;
kfree(s); kfree(s);
} }
ax25_uid_list = NULL;
write_unlock(&ax25_uid_lock);
} }
/* -*- linux-c -*- /*
* sysctl_net_ax25.c: sysctl interface to net AX.25 subsystem. * 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.
* *
* Begun April 1, 1996, Mike Shaver. * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
* Added /proc/sys/net/ax25 directory entry (empty =) ). [MS]
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/spinlock.h>
#include <net/ax25.h> #include <net/ax25.h>
static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1}; static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1};
...@@ -105,6 +107,7 @@ void ax25_register_sysctl(void) ...@@ -105,6 +107,7 @@ void ax25_register_sysctl(void)
ax25_dev *ax25_dev; ax25_dev *ax25_dev;
int n, k; int n, k;
spin_lock_bh(&ax25_dev_lock);
for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
ax25_table_size += sizeof(ctl_table); ax25_table_size += sizeof(ctl_table);
...@@ -119,6 +122,7 @@ void ax25_register_sysctl(void) ...@@ -119,6 +122,7 @@ void ax25_register_sysctl(void)
while (n--) while (n--)
kfree(ax25_table[n].child); kfree(ax25_table[n].child);
kfree(ax25_table); kfree(ax25_table);
spin_unlock_bh(&ax25_dev_lock);
return; return;
} }
memcpy(child, ax25_param_table, sizeof(ax25_param_table)); memcpy(child, ax25_param_table, sizeof(ax25_param_table));
...@@ -144,6 +148,7 @@ void ax25_register_sysctl(void) ...@@ -144,6 +148,7 @@ void ax25_register_sysctl(void)
n++; n++;
} }
spin_unlock_bh(&ax25_dev_lock);
ax25_dir_table[0].child = ax25_table; ax25_dir_table[0].child = ax25_table;
......
...@@ -24,16 +24,10 @@ ...@@ -24,16 +24,10 @@
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <net/llc_mac.h> #include <net/llc_mac.h>
static void llc_station_ack_tmr_callback(unsigned long timeout_data);
int llc_station_ac_start_ack_timer(struct llc_station *station, int llc_station_ac_start_ack_timer(struct llc_station *station,
struct sk_buff *skb) struct sk_buff *skb)
{ {
del_timer(&station->ack_timer); mod_timer(&station->ack_timer, jiffies + LLC_ACK_TIME * HZ);
station->ack_timer.expires = jiffies + LLC_ACK_TIME * HZ;
station->ack_timer.data = (unsigned long)station;
station->ack_timer.function = llc_station_ack_tmr_callback;
add_timer(&station->ack_timer);
return 0; return 0;
} }
...@@ -130,7 +124,7 @@ int llc_station_ac_report_status(struct llc_station *station, ...@@ -130,7 +124,7 @@ int llc_station_ac_report_status(struct llc_station *station,
return 0; return 0;
} }
static void llc_station_ack_tmr_callback(unsigned long timeout_data) void llc_station_ack_tmr_cb(unsigned long timeout_data)
{ {
struct llc_station *station = (struct llc_station *)timeout_data; struct llc_station *station = (struct llc_station *)timeout_data;
struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
......
...@@ -28,10 +28,6 @@ ...@@ -28,10 +28,6 @@
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <net/llc_mac.h> #include <net/llc_mac.h>
static void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data);
static void llc_conn_ack_tmr_cb(unsigned long timeout_data);
static void llc_conn_rej_tmr_cb(unsigned long timeout_data);
static void llc_conn_busy_tmr_cb(unsigned long timeout_data);
static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb); static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb);
static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb); static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb);
static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *ev); static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *ev);
...@@ -664,11 +660,8 @@ int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb) ...@@ -664,11 +660,8 @@ int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
if (!llc->remote_busy_flag) { if (!llc->remote_busy_flag) {
llc->remote_busy_flag = 1; llc->remote_busy_flag = 1;
llc->busy_state_timer.timer.expires = jiffies + mod_timer(&llc->busy_state_timer.timer,
llc->busy_state_timer.expire * HZ; jiffies + llc->busy_state_timer.expire * HZ);
llc->busy_state_timer.timer.data = (unsigned long)sk;
llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;
add_timer(&llc->busy_state_timer.timer);
} }
return 0; return 0;
} }
...@@ -905,12 +898,8 @@ int llc_conn_ac_start_p_timer(struct sock *sk, struct sk_buff *skb) ...@@ -905,12 +898,8 @@ int llc_conn_ac_start_p_timer(struct sock *sk, struct sk_buff *skb)
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
llc->p_flag = 1; llc->p_flag = 1;
del_timer(&llc->pf_cycle_timer.timer); mod_timer(&llc->pf_cycle_timer.timer,
llc->pf_cycle_timer.timer.expires = jiffies + jiffies + llc->pf_cycle_timer.expire * HZ);
llc->pf_cycle_timer.expire * HZ;
llc->pf_cycle_timer.timer.data = (unsigned long)sk;
llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb;
add_timer(&llc->pf_cycle_timer.timer);
return 0; return 0;
} }
...@@ -1181,11 +1170,7 @@ int llc_conn_ac_start_ack_timer(struct sock *sk, struct sk_buff *skb) ...@@ -1181,11 +1170,7 @@ int llc_conn_ac_start_ack_timer(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
del_timer(&llc->ack_timer.timer); mod_timer(&llc->ack_timer.timer, jiffies + llc->ack_timer.expire * HZ);
llc->ack_timer.timer.expires = jiffies + llc->ack_timer.expire * HZ;
llc->ack_timer.timer.data = (unsigned long)sk;
llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
add_timer(&llc->ack_timer.timer);
return 0; return 0;
} }
...@@ -1193,12 +1178,8 @@ int llc_conn_ac_start_rej_timer(struct sock *sk, struct sk_buff *skb) ...@@ -1193,12 +1178,8 @@ int llc_conn_ac_start_rej_timer(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
del_timer(&llc->rej_sent_timer.timer); mod_timer(&llc->rej_sent_timer.timer,
llc->rej_sent_timer.timer.expires = jiffies + jiffies + llc->rej_sent_timer.expire * HZ);
llc->rej_sent_timer.expire * HZ;
llc->rej_sent_timer.timer.data = (unsigned long)sk;
llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb;
add_timer(&llc->rej_sent_timer.timer);
return 0; return 0;
} }
...@@ -1207,13 +1188,9 @@ int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk, ...@@ -1207,13 +1188,9 @@ int llc_conn_ac_start_ack_tmr_if_not_running(struct sock *sk,
{ {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
if (!timer_pending(&llc->ack_timer.timer)) { if (!timer_pending(&llc->ack_timer.timer))
llc->ack_timer.timer.expires = jiffies + mod_timer(&llc->ack_timer.timer,
llc->ack_timer.expire * HZ; jiffies + llc->ack_timer.expire * HZ);
llc->ack_timer.timer.data = (unsigned long)sk;
llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
add_timer(&llc->ack_timer.timer);
}
return 0; return 0;
} }
...@@ -1260,13 +1237,9 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb) ...@@ -1260,13 +1237,9 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
llc->failed_data_req = 0; llc->failed_data_req = 0;
llc_conn_ac_data_confirm(sk, skb); llc_conn_ac_data_confirm(sk, skb);
} }
if (unacked) { if (unacked)
llc->ack_timer.timer.expires = jiffies + mod_timer(&llc->ack_timer.timer,
llc->ack_timer.expire * HZ; jiffies + llc->ack_timer.expire * HZ);
llc->ack_timer.timer.data = (unsigned long)sk;
llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
add_timer(&llc->ack_timer.timer);
}
} else if (llc->failed_data_req) { } else if (llc->failed_data_req) {
llc_pdu_decode_pf_bit(skb, &fbit); llc_pdu_decode_pf_bit(skb, &fbit);
if (fbit == 1) { if (fbit == 1) {
...@@ -1413,7 +1386,7 @@ void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data) ...@@ -1413,7 +1386,7 @@ void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
bh_unlock_sock(sk); bh_unlock_sock(sk);
} }
static void llc_conn_busy_tmr_cb(unsigned long timeout_data) void llc_conn_busy_tmr_cb(unsigned long timeout_data)
{ {
struct sock *sk = (struct sock *)timeout_data; struct sock *sk = (struct sock *)timeout_data;
struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
...@@ -1445,7 +1418,7 @@ void llc_conn_ack_tmr_cb(unsigned long timeout_data) ...@@ -1445,7 +1418,7 @@ void llc_conn_ack_tmr_cb(unsigned long timeout_data)
bh_unlock_sock(sk); bh_unlock_sock(sk);
} }
static void llc_conn_rej_tmr_cb(unsigned long timeout_data) void llc_conn_rej_tmr_cb(unsigned long timeout_data)
{ {
struct sock *sk = (struct sock *)timeout_data; struct sock *sk = (struct sock *)timeout_data;
struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
......
...@@ -194,7 +194,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb) ...@@ -194,7 +194,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_0(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && return llc_conn_space(sk, skb) &&
!LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
!LLC_I_PF_IS_0(pdu) && !LLC_I_PF_IS_0(pdu) &&
LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
} }
...@@ -203,7 +204,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb) ...@@ -203,7 +204,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_1(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && return llc_conn_space(sk, skb) &&
!LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
!LLC_I_PF_IS_1(pdu) && !LLC_I_PF_IS_1(pdu) &&
LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
} }
...@@ -250,7 +252,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) ...@@ -250,7 +252,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && return llc_conn_space(sk, skb) &&
!LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
!LLC_I_PF_IS_0(pdu) && !LLC_I_PF_IS_0(pdu) &&
LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
} }
...@@ -268,7 +271,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb) ...@@ -268,7 +271,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && return llc_conn_space(sk, skb) &&
!LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1; LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
} }
...@@ -423,7 +427,8 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb) ...@@ -423,7 +427,8 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_0(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && return llc_conn_space(sk, skb) &&
!LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
!LLC_S_PF_IS_0(pdu) && !LLC_S_PF_IS_0(pdu) &&
LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1;
} }
...@@ -432,7 +437,8 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb) ...@@ -432,7 +437,8 @@ int llc_conn_ev_rx_rr_rsp_fbit_set_1(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) && return llc_conn_space(sk, skb) &&
!LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
!LLC_S_PF_IS_1(pdu) && !LLC_S_PF_IS_1(pdu) &&
LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1; LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1;
} }
......
...@@ -184,19 +184,32 @@ int llc_sk_init(struct sock* sk) ...@@ -184,19 +184,32 @@ int llc_sk_init(struct sock* sk)
goto out; goto out;
memset(llc, 0, sizeof(*llc)); memset(llc, 0, sizeof(*llc));
rc = 0; rc = 0;
llc->sk = sk; llc->sk = sk;
llc->state = LLC_CONN_STATE_ADM; llc->state = LLC_CONN_STATE_ADM;
llc->inc_cntr = llc->dec_cntr = 2; llc->inc_cntr = llc->dec_cntr = 2;
llc->dec_step = llc->connect_step = 1; llc->dec_step = llc->connect_step = 1;
llc->ack_timer.expire = LLC_ACK_TIME; llc->ack_timer.expire = LLC_ACK_TIME;
llc->ack_timer.timer.data = (unsigned long)sk;
llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
llc->pf_cycle_timer.expire = LLC_P_TIME; llc->pf_cycle_timer.expire = LLC_P_TIME;
llc->pf_cycle_timer.timer.data = (unsigned long)sk;
llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb;
llc->rej_sent_timer.expire = LLC_REJ_TIME; llc->rej_sent_timer.expire = LLC_REJ_TIME;
llc->rej_sent_timer.timer.data = (unsigned long)sk;
llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb;
llc->busy_state_timer.expire = LLC_BUSY_TIME; llc->busy_state_timer.expire = LLC_BUSY_TIME;
llc->busy_state_timer.timer.data = (unsigned long)sk;
llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;
llc->n2 = 2; /* max retransmit */ llc->n2 = 2; /* max retransmit */
llc->k = 2; /* tx win size, will adjust dynam */ llc->k = 2; /* tx win size, will adjust dynam */
llc->rw = 128; /* rx win size (opt and equal to llc->rw = 128; /* rx win size (opt and equal to
* tx_win of remote LLC) * tx_win of remote LLC) */
*/
skb_queue_head_init(&llc->pdu_unack_q); skb_queue_head_init(&llc->pdu_unack_q);
sk->backlog_rcv = llc_backlog_rcv; sk->backlog_rcv = llc_backlog_rcv;
llc_sk(sk) = llc; llc_sk(sk) = llc;
...@@ -534,6 +547,21 @@ struct sk_buff *llc_alloc_frame(void) ...@@ -534,6 +547,21 @@ struct sk_buff *llc_alloc_frame(void)
return skb; return skb;
} }
static char *llc_conn_state_names[] = {
[LLC_CONN_STATE_ADM] = "adm",
[LLC_CONN_STATE_SETUP] = "setup",
[LLC_CONN_STATE_NORMAL] = "normal",
[LLC_CONN_STATE_BUSY] = "busy",
[LLC_CONN_STATE_REJ] = "rej",
[LLC_CONN_STATE_AWAIT] = "await",
[LLC_CONN_STATE_AWAIT_BUSY] = "await_busy",
[LLC_CONN_STATE_AWAIT_REJ] = "await_rej",
[LLC_CONN_STATE_D_CONN] = "d_conn",
[LLC_CONN_STATE_RESET] = "reset",
[LLC_CONN_STATE_ERROR] = "error",
[LLC_CONN_STATE_TEMP] = "temp",
};
static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
{ {
struct llc_opt *llc; struct llc_opt *llc;
...@@ -546,19 +574,34 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) ...@@ -546,19 +574,34 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
struct llc_sap *sap = list_entry(sap_entry, struct llc_sap, struct llc_sap *sap = list_entry(sap_entry, struct llc_sap,
node); node);
len += sprintf(bf + len, "lsap=%d\n", sap->laddr.lsap); len += sprintf(bf + len, "lsap=%02X\n", sap->laddr.lsap);
spin_lock_bh(&sap->sk_list.lock); spin_lock_bh(&sap->sk_list.lock);
if (list_empty(&sap->sk_list.list)) { if (list_empty(&sap->sk_list.list)) {
len += sprintf(bf + len, "no connections\n"); len += sprintf(bf + len, "no connections\n");
goto unlock; goto unlock;
} }
len += sprintf(bf + len, len += sprintf(bf + len, "connection list:\n"
"connection list:\nstate retr txwin rxwin\n"); "dsap state retr txw rxw "
"pf ff sf df rs cs "
"tack tpfc trs tbs blog busr\n");
list_for_each(llc_entry, &sap->sk_list.list) { list_for_each(llc_entry, &sap->sk_list.list) {
llc = list_entry(llc_entry, struct llc_opt, node); llc = list_entry(llc_entry, struct llc_opt, node);
len += sprintf(bf + len, " %-5d%-5d%-6d%-5d\n", len += sprintf(bf + len, " %02X %-10s %3d %3d %3d "
llc->state, llc->retry_count, llc->k, "%2d %2d %2d "
llc->rw); "%2d %2d %2d "
"%4d %4d %3d %3d %4d %4d\n",
llc->daddr.lsap,
llc_conn_state_names[llc->state],
llc->retry_count, llc->k, llc->rw,
llc->p_flag, llc->f_flag, llc->s_flag,
llc->data_flag, llc->remote_busy_flag,
llc->cause_flag,
timer_pending(&llc->ack_timer.timer),
timer_pending(&llc->pf_cycle_timer.timer),
timer_pending(&llc->rej_sent_timer.timer),
timer_pending(&llc->busy_state_timer.timer),
!!llc->sk->backlog.tail,
llc->sk->lock.users);
} }
unlock: unlock:
spin_unlock_bh(&sap->sk_list.lock); spin_unlock_bh(&sap->sk_list.lock);
...@@ -608,6 +651,9 @@ static int __init llc_init(void) ...@@ -608,6 +651,9 @@ static int __init llc_init(void)
skb_queue_head_init(&llc_main_station.mac_pdu_q); skb_queue_head_init(&llc_main_station.mac_pdu_q);
skb_queue_head_init(&llc_main_station.ev_q.list); skb_queue_head_init(&llc_main_station.ev_q.list);
spin_lock_init(&llc_main_station.ev_q.lock); spin_lock_init(&llc_main_station.ev_q.lock);
llc_main_station.ack_timer.data = (unsigned long)&llc_main_station;
llc_main_station.ack_timer.function = llc_station_ack_tmr_cb;
skb = alloc_skb(0, GFP_ATOMIC); skb = alloc_skb(0, GFP_ATOMIC);
if (!skb) if (!skb)
goto err; goto err;
......
...@@ -360,11 +360,11 @@ static int llc_ui_release(struct socket *sock) ...@@ -360,11 +360,11 @@ static int llc_ui_release(struct socket *sock)
llc->laddr.lsap, llc->daddr.lsap); llc->laddr.lsap, llc->daddr.lsap);
if (!llc_send_disc(sk)) if (!llc_send_disc(sk))
llc_ui_wait_for_disc(sk, sk->rcvtimeo); llc_ui_wait_for_disc(sk, sk->rcvtimeo);
release_sock(sk);
if (!sk->zapped) { if (!sk->zapped) {
llc_sap_unassign_sock(llc->sap, sk); llc_sap_unassign_sock(llc->sap, sk);
llc_ui_remove_socket(sk); llc_ui_remove_socket(sk);
} }
release_sock(sk);
if (llc->sap && list_empty(&llc->sap->sk_list.list)) if (llc->sap && list_empty(&llc->sap->sk_list.list))
llc_sap_close(llc->sap); llc_sap_close(llc->sap);
sock_put(sk); sock_put(sk);
...@@ -484,10 +484,10 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) ...@@ -484,10 +484,10 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
llc->daddr.lsap = addr->sllc_dsap; llc->daddr.lsap = addr->sllc_dsap;
memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN); memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
memcpy(&llc->addr, addr, sizeof(llc->addr)); memcpy(&llc->addr, addr, sizeof(llc->addr));
rc = sk->zapped = 0;
llc_ui_insert_socket(sk); llc_ui_insert_socket(sk);
/* assign new connection to it's SAP */ /* assign new connection to it's SAP */
llc_sap_assign_sock(sap, sk); llc_sap_assign_sock(sap, sk);
rc = sk->zapped = 0;
out: out:
return rc; return rc;
} }
...@@ -952,7 +952,9 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, ...@@ -952,7 +952,9 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if (size > dev->mtu) if (size > dev->mtu)
size = dev->mtu; size = dev->mtu;
copied = size - hdrlen; copied = size - hdrlen;
release_sock(sk);
skb = sock_alloc_send_skb(sk, size, noblock, &rc); skb = sock_alloc_send_skb(sk, size, noblock, &rc);
lock_sock(sk);
if (!skb) if (!skb)
goto release; goto release;
skb->sk = sk; skb->sk = sk;
......
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
* 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 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
* NET/ROM 001 Jonathan(G4KLX) Cloned from loopback.c
* NET/ROM 002 Steve Whitehouse(GW7RRM) fixed the set_mac_address
* NET/ROM 003 Jonathan(G4KLX) Put nr_rebuild_header into line with
* ax25_rebuild_header
* NET/ROM 004 Jonathan(G4KLX) Callsign registration with AX.25.
* NET/ROM 006 Hans(PE1AYX) Fixed interface to IP layer.
*/ */
#include <linux/config.h> #include <linux/config.h>
#define __NO_VERSION__ #define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
......
/* /*
* 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
* 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 Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* * Copyright Darryl Miles G7LED (dlm@g7led.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
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_in.c
* NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragment reception.
* Darryl(G7LED) Added missing INFO with NAK case, optimized
* INFOACK handling, removed reconnect on error.
* NET/ROM 006 Jonathan(G4KLX) Hdrincl removal changes.
* NET/ROM 007 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>
...@@ -88,10 +71,10 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more) ...@@ -88,10 +71,10 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
* The handling of the timer(s) is in file nr_timer.c. * The handling of the timer(s) is in file nr_timer.c.
* Handling of state 0 and connection release is in netrom.c. * Handling of state 0 and connection release is in netrom.c.
*/ */
static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
int frametype)
{ {
switch (frametype) { switch (frametype) {
case NR_CONNACK: { case NR_CONNACK: {
nr_cb *nr = nr_sk(sk); nr_cb *nr = nr_sk(sk);
...@@ -128,10 +111,10 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype ...@@ -128,10 +111,10 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype
* The handling of the timer(s) is in file nr_timer.c * The handling of the timer(s) is in file nr_timer.c
* Handling of state 0 and connection release is in netrom.c. * Handling of state 0 and connection release is in netrom.c.
*/ */
static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
int frametype)
{ {
switch (frametype) { switch (frametype) {
case NR_CONNACK | NR_CHOKE_FLAG: case NR_CONNACK | NR_CHOKE_FLAG:
nr_disconnect(sk, ECONNRESET); nr_disconnect(sk, ECONNRESET);
break; break;
...@@ -168,7 +151,6 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype ...@@ -168,7 +151,6 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
ns = skb->data[17]; ns = skb->data[17];
switch (frametype) { switch (frametype) {
case NR_CONNREQ: case NR_CONNREQ:
nr_write_internal(sk, NR_CONNACK); nr_write_internal(sk, NR_CONNACK);
break; break;
......
/* /*
* 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>
......
/* /*
* 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
* 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 Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
* * Copyright Darryl Miles G7LED (dlm@g7led.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
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_out.c
* NET/ROM 003 Jonathan(G4KLX) Added NET/ROM fragmentation.
* Darryl(G7LED) Fixed NAK, to give out correct reponse.
* NET/ROM 007 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>
...@@ -196,7 +187,7 @@ void nr_kick(struct sock *sk) ...@@ -196,7 +187,7 @@ void nr_kick(struct sock *sk)
void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb) void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
{ {
nr_cb *nr = nr; nr_cb *nr = nr_sk(sk);
unsigned char *dptr; unsigned char *dptr;
/* /*
......
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
* 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 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
* NET/ROM 001 Jonathan(G4KLX) Cloned from ax25_subr.c
* NET/ROM 003 Jonathan(G4KLX) Added G8BPQ NET/ROM extensions.
* NET/ROM 007 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>
...@@ -165,7 +156,6 @@ void nr_write_internal(struct sock *sk, int frametype) ...@@ -165,7 +156,6 @@ void nr_write_internal(struct sock *sk, int frametype)
dptr = skb_put(skb, skb_tailroom(skb)); dptr = skb_put(skb, skb_tailroom(skb));
switch (frametype & 0x0F) { switch (frametype & 0x0F) {
case NR_CONNREQ: case NR_CONNREQ:
timeout = nr->t1 / HZ; timeout = nr->t1 / HZ;
*dptr++ = nr->my_index; *dptr++ = nr->my_index;
......
This diff is collapsed.
/* -*- linux-c -*- /*
* sysctl_net_netrom.c: sysctl interface to net NET/ROM subsystem. * 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.
* *
* Begun April 1, 1996, Mike Shaver. * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
* Added /proc/sys/net/netrom directory entry (empty =) ). [MS]
*/ */
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/init.h> #include <linux/init.h>
......
This diff is collapsed.
/* /*
* ROSE release 003 * 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
* ROSE 001 Jonathan(G4KLX) Cloned from nr_dev.c.
* Hans(PE1AYX) Fixed interface to IP layer.
*/ */
#include <linux/config.h> #include <linux/config.h>
#define __NO_VERSION__ #define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
...@@ -29,7 +21,7 @@ ...@@ -29,7 +21,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/if_ether.h> /* For the statistics structure. */ #include <linux/if_ether.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/io.h> #include <asm/io.h>
......
This diff is collapsed.
/* /*
* ROSE release 003 * 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
* ROSE 001 Jonathan(G4KLX) Cloned from rose_timer.c
* ROSE 003 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>
......
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