summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@nuts.ninka.net>2002-09-18 02:14:02 -0700
committerDavid S. Miller <davem@nuts.ninka.net>2002-09-18 02:14:02 -0700
commitc2edf82620682e0384b7d95fea359b082a626f7e (patch)
treed39fcabf56d9cb37c58059f375169c1e4c6875e3
parent5f761bd3d04f12d0cf163544b8ef09677a0b0c2e (diff)
parente5e1cba9ef21644d4f550620717c835b430f2b26 (diff)
Merge http://linux-ham.bkbits.net/linux-2.5
into nuts.ninka.net:/home/davem/src/BK/ham-2.5
-rw-r--r--MAINTAINERS12
-rw-r--r--include/net/ax25.h25
-rw-r--r--net/ax25/Config.in2
-rw-r--r--net/ax25/TODO24
-rw-r--r--net/ax25/af_ax25.c1561
-rw-r--r--net/ax25/ax25_addr.c31
-rw-r--r--net/ax25/ax25_dev.c93
-rw-r--r--net/ax25/ax25_ds_in.c415
-rw-r--r--net/ax25/ax25_ds_subr.c49
-rw-r--r--net/ax25/ax25_ds_timer.c155
-rw-r--r--net/ax25/ax25_iface.c124
-rw-r--r--net/ax25/ax25_in.c180
-rw-r--r--net/ax25/ax25_ip.c57
-rw-r--r--net/ax25/ax25_out.c114
-rw-r--r--net/ax25/ax25_route.c431
-rw-r--r--net/ax25/ax25_std_in.c629
-rw-r--r--net/ax25/ax25_std_subr.c26
-rw-r--r--net/ax25/ax25_std_timer.c158
-rw-r--r--net/ax25/ax25_subr.c70
-rw-r--r--net/ax25/ax25_timer.c145
-rw-r--r--net/ax25/ax25_uid.c151
-rw-r--r--net/ax25/sysctl_net_ax25.c17
-rw-r--r--net/netrom/af_netrom.c483
-rw-r--r--net/netrom/nr_dev.c24
-rw-r--r--net/netrom/nr_in.c302
-rw-r--r--net/netrom/nr_loopback.c19
-rw-r--r--net/netrom/nr_out.c25
-rw-r--r--net/netrom/nr_route.c280
-rw-r--r--net/netrom/nr_subr.c146
-rw-r--r--net/netrom/nr_timer.c133
-rw-r--r--net/netrom/sysctl_net_netrom.c11
-rw-r--r--net/rose/af_rose.c623
-rw-r--r--net/rose/rose_dev.c20
-rw-r--r--net/rose/rose_in.c315
-rw-r--r--net/rose/rose_link.c56
-rw-r--r--net/rose/rose_loopback.c18
-rw-r--r--net/rose/rose_out.c23
-rw-r--r--net/rose/rose_route.c515
-rw-r--r--net/rose/rose_subr.c375
-rw-r--r--net/rose/rose_timer.c110
-rw-r--r--net/rose/sysctl_net_rose.c11
41 files changed, 3971 insertions, 3987 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 46a74039e0e4..d2a92cd31728 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -240,8 +240,8 @@ L: linux-net@vger.kernel.org
S: Maintained
AX.25 NETWORK LAYER
-P: Matthias Welwarsky
-M: dg2fef@afthd.tu-darmstadt.de
+P: Ralf Baechle
+M: ralf@linux-mips.org
L: linux-hams@vger.kernel.org
S: Maintained
@@ -1121,8 +1121,8 @@ L: netfilter-devel@lists.netfilter.org
S: Supported
NETROM NETWORK LAYER
-P: Tomi Manninen
-M: Tomi.Manninen@hut.fi
+P: Ralf Baechle
+M: ralf@linux-mips.org
L: linux-hams@vger.kernel.org
S: Maintained
@@ -1371,8 +1371,8 @@ W: http://www.namesys.com
S: Supported
ROSE NETWORK LAYER
-P: Jean-Paul Roubelat
-M: jpr@f6fbb.org
+P: Ralf Baechle
+M: ralf@linux-mips.org
L: linux-hams@vger.kernel.org
S: Maintained
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 334127932384..c34da24f1902 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -3,11 +3,14 @@
*
* Alan Cox (GW4PTS) 10/11/93
*/
-
#ifndef _AX25_H
#define _AX25_H
+
#include <linux/config.h>
#include <linux/ax25.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <asm/atomic.h>
#define AX25_T1CLAMPLO 1
#define AX25_T1CLAMPHI (30 * HZ)
@@ -66,6 +69,8 @@
#define AX25_UA 0x63 /* Unnumbered acknowledge */
#define AX25_FRMR 0x87 /* Frame reject */
#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_EPF 0x01 /* Poll/final bit for extended AX.25 */
@@ -147,10 +152,12 @@ typedef struct {
typedef struct ax25_route {
struct ax25_route *next;
+ atomic_t ref;
ax25_address callsign;
- struct net_device *dev;
+ struct net_device *dev;
ax25_digi *digipeat;
char ip_mode;
+ struct timer_list timer;
} ax25_route;
typedef struct {
@@ -197,11 +204,12 @@ typedef struct ax25_cb {
#define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo)
/* af_ax25.c */
-extern ax25_cb *volatile ax25_list;
+extern ax25_cb *ax25_list;
+extern spinlock_t ax25_list_lock;
extern void ax25_free_cb(ax25_cb *);
extern void ax25_insert_socket(ax25_cb *);
struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int);
-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 struct sock *ax25_addr_match(ax25_address *);
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 *);
/* ax25_dev.c */
extern ax25_dev *ax25_dev_list;
+extern spinlock_t ax25_dev_lock;
extern ax25_dev *ax25_dev_ax25dev(struct net_device *);
extern ax25_dev *ax25_addr_ax25dev(ax25_address *);
extern void ax25_dev_device_up(struct net_device *);
@@ -286,10 +295,16 @@ extern void ax25_rt_device_down(struct net_device *);
extern int ax25_rt_ioctl(unsigned int, void *);
extern int ax25_rt_get_info(char *, char **, off_t, int);
extern int ax25_rt_autobind(ax25_cb *, ax25_address *);
-extern ax25_route *ax25_rt_find_route(ax25_address *, struct net_device *);
+extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *,
+ struct net_device *);
extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *);
extern void ax25_rt_free(void);
+static inline void ax25_put_route(ax25_route *ax25_rt)
+{
+ atomic_dec(&ax25_rt->ref);
+}
+
/* ax25_std_in.c */
extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int);
diff --git a/net/ax25/Config.in b/net/ax25/Config.in
index b8e5d7333052..783d86605e77 100644
--- a/net/ax25/Config.in
+++ b/net/ax25/Config.in
@@ -1,7 +1,7 @@
#
# Amateur Radio protocols and AX.25 device configuration
#
-# 19971130 Now in an own category to make correct compilation of the
+# 19971130 Now in an own category to make correct compilation of the
# AX.25 stuff easier...
# Joerg Reuter DL1BKE <jreuter@yaina.de>
# 19980129 Moved to net/ax25/Config.in, sourcing device drivers.
diff --git a/net/ax25/TODO b/net/ax25/TODO
new file mode 100644
index 000000000000..4089c49e45cc
--- /dev/null
+++ b/net/ax25/TODO
@@ -0,0 +1,24 @@
+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.
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 661335502baf..9b250f0da085 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1,109 +1,18 @@
/*
- * AX.25 release 038
+ * 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
- *
- * 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 006 Alan(GW4PTS) Nearly died of shock - it's working 8-)
- * AX.25 007 Alan(GW4PTS) Removed the silliest bugs
- * AX.25 008 Alan(GW4PTS) Cleaned up, fixed a few state machine problems, added callbacks
- * AX.25 009 Alan(GW4PTS) Emergency patch kit to fix memory corruption
- * AX.25 010 Alan(GW4PTS) Added RAW sockets/Digipeat.
- * AX.25 011 Alan(GW4PTS) RAW socket and datagram fixes (thanks) - Raw sendto now gets PID right
- * datagram sendto uses correct target address.
- * AX.25 012 Alan(GW4PTS) Correct incoming connection handling, send DM to failed connects.
- * Use skb->data not skb+1. Support sk->priority correctly.
- * Correct receive on SOCK_DGRAM.
- * AX.25 013 Alan(GW4PTS) Send DM to all unknown frames, missing initialiser fixed
- * Leave spare SSID bits set (DAMA etc) - thanks for bug report,
- * removed device registration (it's not used or needed). Clean up for
- * gcc 2.5.8. PID to AX25_P_
- * AX.25 014 Alan(GW4PTS) Cleanup and NET3 merge
- * AX.25 015 Alan(GW4PTS) Internal test version.
- * AX.25 016 Alan(GW4PTS) Semi Internal version for PI card
- * work.
- * AX.25 017 Alan(GW4PTS) Fixed some small bugs reported by
- * G4KLX
- * AX.25 018 Alan(GW4PTS) Fixed a small error in SOCK_DGRAM
- * AX.25 019 Alan(GW4PTS) Clean ups for the non INET kernel and device ioctls in AX.25
- * AX.25 020 Jonathan(G4KLX) /proc support and other changes.
- * AX.25 021 Alan(GW4PTS) Added AX25_T1, AX25_N2, AX25_T3 as requested.
- * AX.25 022 Jonathan(G4KLX) More work on the ax25 auto router and /proc improved (again)!
- * Alan(GW4PTS) Added TIOCINQ/OUTQ
- * AX.25 023 Alan(GW4PTS) Fixed shutdown bug
- * AX.25 023 Alan(GW4PTS) Linus changed timers
- * AX.25 024 Alan(GW4PTS) Small bug fixes
- * AX.25 025 Alan(GW4PTS) More fixes, Linux 1.1.51 compatibility stuff, timers again!
- * AX.25 026 Alan(GW4PTS) Small state fix.
- * AX.25 027 Alan(GW4PTS) Socket close crash fixes.
- * AX.25 028 Alan(GW4PTS) Callsign control including settings per uid.
- * Small bug fixes.
- * Protocol set by sockets only.
- * Small changes to allow for start of NET/ROM layer.
- * AX.25 028a Jonathan(G4KLX) Changes to state machine.
- * AX.25 028b Jonathan(G4KLX) Extracted ax25 control block
- * from sock structure.
- * AX.25 029 Alan(GW4PTS) Combined 028b and some KA9Q code
- * Jonathan(G4KLX) and removed all the old Berkeley, added IP mode registration.
- * Darryl(G7LED) stuff. Cross-port digipeating. Minor fixes and enhancements.
- * Alan(GW4PTS) Missed suser() on axassociate checks
- * AX.25 030 Alan(GW4PTS) Added variable length headers.
- * Jonathan(G4KLX) Added BPQ Ethernet interface.
- * Steven(GW7RRM) Added digi-peating control ioctl.
- * Added extended AX.25 support.
- * Added AX.25 frame segmentation.
- * Darryl(G7LED) Changed connect(), recvfrom(), sendto() sockaddr/addrlen to
- * fall inline with bind() and new policy.
- * Moved digipeating ctl to new ax25_dev structs.
- * Fixed ax25_release(), set TCP_CLOSE, wakeup app
- * context, THEN make the sock dead.
- * Alan(GW4PTS) Cleaned up for single recvmsg methods.
- * Alan(GW4PTS) Fixed not clearing error on connect failure.
- * AX.25 031 Jonathan(G4KLX) Added binding to any device.
- * Joerg(DL1BKE) Added DAMA support, fixed (?) digipeating, fixed buffer locking
- * for "virtual connect" mode... Result: Probably the
- * "Most Buggiest Code You've Ever Seen" (TM)
- * HaJo(DD8NE) Implementation of a T5 (idle) timer
- * Joerg(DL1BKE) Renamed T5 to IDLE and changed behaviour:
- * the timer gets reloaded on every received or transmitted
- * I frame for IP or NETROM. The idle timer is not active
- * on "vanilla AX.25" connections. Furthermore added PACLEN
- * to provide AX.25-layer based fragmentation (like WAMPES)
- * AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout error.
- * ax25_send_frame() limits the number of enqueued
- * datagrams per socket.
- * AX.25 033 Jonathan(G4KLX) Removed auto-router.
- * Hans(PE1AYX) Converted to Module.
- * Joerg(DL1BKE) Moved BPQ Ethernet to separate driver.
- * AX.25 034 Jonathan(G4KLX) 2.1 changes
- * Alan(GW4PTS) Small POSIXisations
- * AX.25 035 Alan(GW4PTS) Started fixing to the new
- * format.
- * Hans(PE1AYX) Fixed interface to IP layer.
- * Alan(GW4PTS) Added asynchronous support.
- * Frederic(F1OAT) Support for pseudo-digipeating.
- * Jonathan(G4KLX) Support for packet forwarding.
- * AX.25 036 Jonathan(G4KLX) Major restructuring.
- * Joerg(DL1BKE) Fixed DAMA Slave.
- * Jonathan(G4KLX) Fix wildcard listen parameter setting.
- * AX.25 037 Jonathan(G4KLX) New timer architecture.
- * AX.25 038 Matthias(DG2FEF) Small fixes to the syscall interface to make kernel
- * independent of AX25_MAX_DIGIS used by applications.
- * Tomi(OH2BNS) Fixed ax25_getname().
- * Joerg(DL1BKE) Starting to phase out the support for full_sockaddr_ax25
- * with only 6 digipeaters and sockaddr_ax25 in ax25_bind(),
- * ax25_connect() and ax25_sendmsg()
- * Joerg(DL1BKE) Added support for SO_BINDTODEVICE
- * Arnaldo C. Melo s/suser/capable(CAP_NET_ADMIN)/, some more cleanups
- * Michal Ostrowski Module initialization cleanup.
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
+ * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
+ * Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl)
+ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
-
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -114,6 +23,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
+#include <linux/smp_lock.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <net/ax25.h>
@@ -134,13 +44,15 @@
#include <linux/netfilter.h>
#include <linux/sysctl.h>
#include <linux/init.h>
+#include <linux/spinlock.h>
#include <net/tcp.h>
#include <net/ip.h>
#include <net/arp.h>
-ax25_cb *volatile ax25_list;
+ax25_cb *ax25_list;
+spinlock_t ax25_list_lock = SPIN_LOCK_UNLOCKED;
static struct proto_ops ax25_proto_ops;
@@ -171,27 +83,24 @@ static void ax25_free_sock(struct sock *sk)
static void ax25_remove_socket(ax25_cb *ax25)
{
ax25_cb *s;
- unsigned long flags;
-
- save_flags(flags); cli();
+ spin_lock_bh(&ax25_list_lock);
if ((s = ax25_list) == ax25) {
ax25_list = s->next;
- restore_flags(flags);
+ spin_unlock_bh(&ax25_list_lock);
return;
}
while (s != NULL && s->next != NULL) {
if (s->next == ax25) {
s->next = ax25->next;
- restore_flags(flags);
+ spin_unlock_bh(&ax25_list_lock);
return;
}
s = s->next;
}
-
- restore_flags(flags);
+ spin_unlock_bh(&ax25_list_lock);
}
/*
@@ -205,18 +114,21 @@ static void ax25_kill_by_device(struct net_device *dev)
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return;
+ spin_lock_bh(&ax25_list_lock);
for (s = ax25_list; s != NULL; s = s->next) {
if (s->ax25_dev == ax25_dev) {
s->ax25_dev = NULL;
ax25_disconnect(s, ENETUNREACH);
}
}
+ spin_unlock_bh(&ax25_list_lock);
}
/*
* Handle device status changes.
*/
-static int ax25_device_event(struct notifier_block *this,unsigned long event, void *ptr)
+static int ax25_device_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
@@ -225,16 +137,16 @@ static int ax25_device_event(struct notifier_block *this,unsigned long event, vo
return NOTIFY_DONE;
switch (event) {
- case NETDEV_UP:
- ax25_dev_device_up(dev);
- break;
- case NETDEV_DOWN:
- ax25_kill_by_device(dev);
- ax25_rt_device_down(dev);
- ax25_dev_device_down(dev);
- break;
- default:
- break;
+ case NETDEV_UP:
+ ax25_dev_device_up(dev);
+ break;
+ case NETDEV_DOWN:
+ ax25_kill_by_device(dev);
+ ax25_rt_device_down(dev);
+ ax25_dev_device_down(dev);
+ break;
+ default:
+ break;
}
return NOTIFY_DONE;
@@ -245,64 +157,59 @@ static int ax25_device_event(struct notifier_block *this,unsigned long event, vo
*/
void ax25_insert_socket(ax25_cb *ax25)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&ax25_list_lock);
ax25->next = ax25_list;
ax25_list = ax25;
-
- restore_flags(flags);
+ spin_unlock_bh(&ax25_list_lock);
}
/*
* Find a socket that wants to accept the SABM we have just
* received.
*/
-struct sock *ax25_find_listener(ax25_address *addr, int digi, struct net_device *dev, int type)
+struct sock *ax25_find_listener(ax25_address *addr, int digi,
+ struct net_device *dev, int type)
{
- unsigned long flags;
ax25_cb *s;
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&ax25_list_lock);
for (s = ax25_list; s != NULL; s = s->next) {
if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
continue;
if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) {
/* If device is null we match any device */
if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) {
- restore_flags(flags);
+ spin_unlock_bh(&ax25_list_lock);
+
return s->sk;
}
}
}
+ spin_unlock_bh(&ax25_list_lock);
- restore_flags(flags);
return NULL;
}
/*
* Find an AX.25 socket given both ends.
*/
-struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, int type)
+struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr,
+ int type)
{
+ struct sock *sk = NULL;
ax25_cb *s;
- unsigned long flags;
-
- save_flags(flags);
- cli();
+ spin_lock_bh(&ax25_list_lock);
for (s = ax25_list; s != NULL; s = s->next) {
if (s->sk != NULL && ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->sk->type == type) {
- restore_flags(flags);
- return s->sk;
+ sk = s->sk;
+ lock_sock(sk);
+ break;
}
}
- restore_flags(flags);
+out:
+ spin_unlock_bh(&ax25_list_lock);
return NULL;
}
@@ -311,14 +218,12 @@ struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, in
* Find an AX.25 control block given both ends. It will only pick up
* floating AX.25 control blocks or non Raw socket bound control blocks.
*/
-ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi *digi, struct net_device *dev)
+ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
+ ax25_digi *digi, struct net_device *dev)
{
ax25_cb *s;
- unsigned long flags;
-
- save_flags(flags);
- cli();
+ spin_lock_bh(&ax25_list_lock);
for (s = ax25_list; s != NULL; s = s->next) {
if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET)
continue;
@@ -334,12 +239,12 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi
if (s->digipeat != NULL && s->digipeat->ndigi != 0)
continue;
}
- restore_flags(flags);
+ spin_unlock_bh(&ax25_list_lock);
+
return s;
}
}
-
- restore_flags(flags);
+ spin_unlock_bh(&ax25_list_lock);
return NULL;
}
@@ -349,22 +254,21 @@ ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi
*/
struct sock *ax25_addr_match(ax25_address *addr)
{
- unsigned long flags;
+ struct sock *sk = NULL;
ax25_cb *s;
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&ax25_list_lock);
for (s = ax25_list; s != NULL; s = s->next) {
- if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == SOCK_RAW) {
- restore_flags(flags);
- return s->sk;
+ if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 &&
+ s->sk->type == SOCK_RAW) {
+ sk = s->sk;
+ lock_sock(sk);
+ break;
}
}
+ spin_unlock_bh(&ax25_list_lock);
- restore_flags(flags);
-
- return NULL;
+ return sk;
}
void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto)
@@ -400,17 +304,16 @@ static void ax25_destroy_timer(unsigned long data)
}
/*
- * This is called from user mode and the timers. Thus it protects itself against
- * interrupt users but doesn't worry about being called during work.
- * Once it is removed from the queue no interrupt or bottom half will
- * touch it and we are (fairly 8-) ) safe.
+ * This is called from user mode and the timers. Thus it protects itself
+ * against interrupt users but doesn't worry about being called during
+ * work. Once it is removed from the queue no interrupt or bottom half
+ * will touch it and we are (fairly 8-) ) safe.
*/
-void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer */
+void ax25_destroy_socket(ax25_cb *ax25)
{
struct sk_buff *skb;
- unsigned long flags;
- save_flags(flags); cli();
+ ax25_remove_socket(ax25);
ax25_stop_heartbeat(ax25);
ax25_stop_t1timer(ax25);
@@ -418,15 +321,17 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer
ax25_stop_t3timer(ax25);
ax25_stop_idletimer(ax25);
- ax25_remove_socket(ax25);
ax25_clear_queues(ax25); /* Flush the queues */
if (ax25->sk != NULL) {
while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) {
- if (skb->sk != ax25->sk) { /* A pending connection */
+ if (skb->sk != ax25->sk) {
+ /* A pending connection */
ax25_cb *sax25 = ax25_sk(skb->sk);
- skb->sk->dead = 1; /* Queue the unaccepted socket for death */
+ /* Queue the unaccepted socket for death */
+ skb->sk->dead = 1;
+
ax25_start_heartbeat(sax25);
sax25->state = AX25_STATE_0;
}
@@ -450,8 +355,6 @@ void ax25_destroy_socket(ax25_cb *ax25) /* Not static as it's used by the timer
} else {
ax25_free_cb(ax25);
}
-
- restore_flags(flags);
}
/*
@@ -484,66 +387,66 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg)
return -ENOTCONN;
switch (ax25_ctl.cmd) {
- case AX25_KILL:
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ case AX25_KILL:
+ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
#ifdef CONFIG_AX25_DAMA_SLAVE
- if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
- ax25_dama_off(ax25);
+ if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
+ ax25_dama_off(ax25);
#endif
- ax25_disconnect(ax25, ENETRESET);
- break;
+ ax25_disconnect(ax25, ENETRESET);
+ break;
- case AX25_WINDOW:
- if (ax25->modulus == AX25_MODULUS) {
- if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
- return -EINVAL;
- } else {
- if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
- return -EINVAL;
- }
- ax25->window = ax25_ctl.arg;
- break;
-
- case AX25_T1:
- if (ax25_ctl.arg < 1)
+ case AX25_WINDOW:
+ if (ax25->modulus == AX25_MODULUS) {
+ if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
+ return -EINVAL;
+ } else {
+ if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
return -EINVAL;
- ax25->rtt = (ax25_ctl.arg * HZ) / 2;
- ax25->t1 = ax25_ctl.arg * HZ;
- break;
-
- case AX25_T2:
- if (ax25_ctl.arg < 1)
- return -EINVAL;
- ax25->t2 = ax25_ctl.arg * HZ;
- break;
-
- case AX25_N2:
- if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
- return -EINVAL;
- ax25->n2count = 0;
- ax25->n2 = ax25_ctl.arg;
- break;
-
- case AX25_T3:
- if (ax25_ctl.arg < 0)
- return -EINVAL;
- ax25->t3 = ax25_ctl.arg * HZ;
- break;
-
- case AX25_IDLE:
- if (ax25_ctl.arg < 0)
- return -EINVAL;
- ax25->idle = ax25_ctl.arg * 60 * HZ;
- break;
-
- case AX25_PACLEN:
- if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
- return -EINVAL;
- ax25->paclen = ax25_ctl.arg;
- break;
-
- default:
- return -EINVAL;
+ }
+ ax25->window = ax25_ctl.arg;
+ break;
+
+ case AX25_T1:
+ if (ax25_ctl.arg < 1)
+ return -EINVAL;
+ ax25->rtt = (ax25_ctl.arg * HZ) / 2;
+ ax25->t1 = ax25_ctl.arg * HZ;
+ break;
+
+ case AX25_T2:
+ if (ax25_ctl.arg < 1)
+ return -EINVAL;
+ ax25->t2 = ax25_ctl.arg * HZ;
+ break;
+
+ case AX25_N2:
+ if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
+ return -EINVAL;
+ ax25->n2count = 0;
+ ax25->n2 = ax25_ctl.arg;
+ break;
+
+ case AX25_T3:
+ if (ax25_ctl.arg < 0)
+ return -EINVAL;
+ ax25->t3 = ax25_ctl.arg * HZ;
+ break;
+
+ case AX25_IDLE:
+ if (ax25_ctl.arg < 0)
+ return -EINVAL;
+ ax25->idle = ax25_ctl.arg * 60 * HZ;
+ break;
+
+ case AX25_PACLEN:
+ if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
+ return -EINVAL;
+ ax25->paclen = ax25_ctl.arg;
+ break;
+
+ default:
+ return -EINVAL;
}
return 0;
@@ -631,13 +534,14 @@ ax25_cb *ax25_create_cb(void)
* AX25 socket object
*/
-static int ax25_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+static int ax25_setsockopt(struct socket *sock, int level, int optname,
+ char *optval, int optlen)
{
struct sock *sk = sock->sk;
- ax25_cb *ax25 = ax25_sk(sk);
+ ax25_cb *ax25;
struct net_device *dev;
char devname[IFNAMSIZ];
- int opt;
+ int opt, res = 0;
if (level != SOL_AX25)
return -ENOPROTOOPT;
@@ -648,98 +552,131 @@ static int ax25_setsockopt(struct socket *sock, int level, int optname, char *op
if (get_user(opt, (int *)optval))
return -EFAULT;
+ lock_sock(sk);
+ ax25 = ax25_sk(sk);
+
switch (optname) {
- case AX25_WINDOW:
- if (ax25->modulus == AX25_MODULUS) {
- if (opt < 1 || opt > 7)
- return -EINVAL;
- } else {
- if (opt < 1 || opt > 63)
- return -EINVAL;
+ case AX25_WINDOW:
+ if (ax25->modulus == AX25_MODULUS) {
+ if (opt < 1 || opt > 7) {
+ res = -EINVAL;
+ break;
}
- ax25->window = opt;
- return 0;
-
- case AX25_T1:
- if (opt < 1)
- return -EINVAL;
- ax25->rtt = (opt * HZ) / 2;
- ax25->t1 = opt * HZ;
- return 0;
-
- case AX25_T2:
- if (opt < 1)
- return -EINVAL;
- ax25->t2 = opt * HZ;
- return 0;
-
- case AX25_N2:
- if (opt < 1 || opt > 31)
- return -EINVAL;
- ax25->n2 = opt;
- return 0;
-
- case AX25_T3:
- if (opt < 1)
- return -EINVAL;
- ax25->t3 = opt * HZ;
- return 0;
-
- case AX25_IDLE:
- if (opt < 0)
- return -EINVAL;
- ax25->idle = opt * 60 * HZ;
- return 0;
-
- case AX25_BACKOFF:
- if (opt < 0 || opt > 2)
- return -EINVAL;
- ax25->backoff = opt;
- return 0;
-
- case AX25_EXTSEQ:
- ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
- return 0;
-
- case AX25_PIDINCL:
- ax25->pidincl = opt ? 1 : 0;
- return 0;
-
- case AX25_IAMDIGI:
- ax25->iamdigi = opt ? 1 : 0;
- return 0;
-
- case AX25_PACLEN:
- if (opt < 16 || opt > 65535)
- return -EINVAL;
- ax25->paclen = opt;
- return 0;
-
- case SO_BINDTODEVICE:
- if (optlen > IFNAMSIZ) optlen=IFNAMSIZ;
- if (copy_from_user(devname, optval, optlen))
- return -EFAULT;
-
- dev = dev_get_by_name(devname);
- if (dev == NULL) return -ENODEV;
-
- if (sk->type == SOCK_SEQPACKET &&
- (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN))
- return -EADDRNOTAVAIL;
-
- ax25->ax25_dev = ax25_dev_ax25dev(dev);
- ax25_fillin_cb(ax25, ax25->ax25_dev);
- return 0;
+ } else {
+ if (opt < 1 || opt > 63) {
+ res = -EINVAL;
+ break;
+ }
+ }
+ ax25->window = opt;
+ break;
- default:
- return -ENOPROTOOPT;
+ case AX25_T1:
+ if (opt < 1) {
+ res = -EINVAL;
+ break;
+ }
+ ax25->rtt = (opt * HZ) / 2;
+ ax25->t1 = opt * HZ;
+ break;
+
+ case AX25_T2:
+ if (opt < 1) {
+ res = -EINVAL;
+ break;
+ }
+ ax25->t2 = opt * HZ;
+ break;
+
+ case AX25_N2:
+ if (opt < 1 || opt > 31) {
+ res = -EINVAL;
+ break;
+ }
+ ax25->n2 = opt;
+ break;
+
+ case AX25_T3:
+ if (opt < 1) {
+ res = -EINVAL;
+ break;
+ }
+ ax25->t3 = opt * HZ;
+ break;
+
+ case AX25_IDLE:
+ if (opt < 0) {
+ res = -EINVAL;
+ break;
+ }
+ ax25->idle = opt * 60 * HZ;
+ break;
+
+ case AX25_BACKOFF:
+ if (opt < 0 || opt > 2) {
+ res = -EINVAL;
+ break;
+ }
+ ax25->backoff = opt;
+ break;
+
+ case AX25_EXTSEQ:
+ ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
+ break;
+
+ case AX25_PIDINCL:
+ ax25->pidincl = opt ? 1 : 0;
+ break;
+
+ case AX25_IAMDIGI:
+ ax25->iamdigi = opt ? 1 : 0;
+ break;
+
+ case AX25_PACLEN:
+ if (opt < 16 || opt > 65535) {
+ res = -EINVAL;
+ break;
+ }
+ ax25->paclen = opt;
+ break;
+
+ case SO_BINDTODEVICE:
+ if (optlen > IFNAMSIZ)
+ optlen=IFNAMSIZ;
+ if (copy_from_user(devname, optval, optlen)) {
+ res = -EFAULT;
+ break;
+ }
+
+ dev = dev_get_by_name(devname);
+ if (dev == NULL) {
+ res = -ENODEV;
+ break;
+ }
+
+ if (sk->type == SOCK_SEQPACKET &&
+ (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) {
+ res = -EADDRNOTAVAIL;
+ break;
+ }
+
+ ax25->ax25_dev = ax25_dev_ax25dev(dev);
+ ax25_fillin_cb(ax25, ax25->ax25_dev);
+ break;
+
+ default:
+ res = -ENOPROTOOPT;
}
+ release_sock(sk);
+
+ return res;
}
-static int ax25_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+static int ax25_getsockopt(struct socket *sock, int level, int optname,
+ char *optval, int *optlen)
{
struct sock *sk = sock->sk;
- ax25_cb *ax25 = ax25_sk(sk);
+ ax25_cb *ax25;
struct ax25_dev *ax25_dev;
char devname[IFNAMSIZ];
void *valptr;
@@ -751,76 +688,81 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
if (get_user(maxlen, optlen))
return -EFAULT;
-
+
if (maxlen < 1)
return -EFAULT;
valptr = (void *) &val;
length = min_t(unsigned int, maxlen, sizeof(int));
+ lock_sock(sk);
+ ax25 = ax25_sk(sk);
+
switch (optname) {
- case AX25_WINDOW:
- val = ax25->window;
- break;
+ case AX25_WINDOW:
+ val = ax25->window;
+ break;
- case AX25_T1:
- val = ax25->t1 / HZ;
- break;
+ case AX25_T1:
+ val = ax25->t1 / HZ;
+ break;
- case AX25_T2:
- val = ax25->t2 / HZ;
- break;
+ case AX25_T2:
+ val = ax25->t2 / HZ;
+ break;
- case AX25_N2:
- val = ax25->n2;
- break;
+ case AX25_N2:
+ val = ax25->n2;
+ break;
- case AX25_T3:
- val = ax25->t3 / HZ;
- break;
+ case AX25_T3:
+ val = ax25->t3 / HZ;
+ break;
- case AX25_IDLE:
- val = ax25->idle / (60 * HZ);
- break;
+ case AX25_IDLE:
+ val = ax25->idle / (60 * HZ);
+ break;
- case AX25_BACKOFF:
- val = ax25->backoff;
- break;
+ case AX25_BACKOFF:
+ val = ax25->backoff;
+ break;
- case AX25_EXTSEQ:
- val = (ax25->modulus == AX25_EMODULUS);
- break;
+ case AX25_EXTSEQ:
+ val = (ax25->modulus == AX25_EMODULUS);
+ break;
- case AX25_PIDINCL:
- val = ax25->pidincl;
- break;
+ case AX25_PIDINCL:
+ val = ax25->pidincl;
+ break;
- case AX25_IAMDIGI:
- val = ax25->iamdigi;
- break;
+ case AX25_IAMDIGI:
+ val = ax25->iamdigi;
+ break;
- case AX25_PACLEN:
- val = ax25->paclen;
- break;
-
- case SO_BINDTODEVICE:
- ax25_dev = ax25->ax25_dev;
-
- if (ax25_dev != NULL && ax25_dev->dev != NULL) {
- strncpy(devname, ax25_dev->dev->name, IFNAMSIZ);
- length = min_t(unsigned int, strlen(ax25_dev->dev->name)+1, maxlen);
- devname[length-1] = '\0';
- } else {
- *devname = '\0';
- length = 1;
- }
+ case AX25_PACLEN:
+ val = ax25->paclen;
+ break;
- valptr = (void *) devname;
- break;
+ case SO_BINDTODEVICE:
+ ax25_dev = ax25->ax25_dev;
- default:
- return -ENOPROTOOPT;
+ if (ax25_dev != NULL && ax25_dev->dev != NULL) {
+ strncpy(devname, ax25_dev->dev->name, IFNAMSIZ);
+ length = min_t(unsigned int, strlen(ax25_dev->dev->name)+1, maxlen);
+ devname[length-1] = '\0';
+ } else {
+ *devname = '\0';
+ length = 1;
+ }
+
+ valptr = (void *) devname;
+ break;
+
+ default:
+ release_sock(sk);
+ return -ENOPROTOOPT;
}
+ release_sock(sk);
if (put_user(length, optlen))
return -EFAULT;
@@ -831,14 +773,20 @@ static int ax25_getsockopt(struct socket *sock, int level, int optname, char *op
static int ax25_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
+ int res = 0;
+ lock_sock(sk);
if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) {
sk->max_ack_backlog = backlog;
sk->state = TCP_LISTEN;
- return 0;
+ goto out;
}
+ res = -EOPNOTSUPP;
- return -EOPNOTSUPP;
+out:
+ release_sock(sk);
+
+ return res;
}
int ax25_create(struct socket *sock, int protocol)
@@ -847,46 +795,48 @@ int ax25_create(struct socket *sock, int protocol)
ax25_cb *ax25;
switch (sock->type) {
- case SOCK_DGRAM:
- if (protocol == 0 || protocol == PF_AX25)
- protocol = AX25_P_TEXT;
+ case SOCK_DGRAM:
+ if (protocol == 0 || protocol == PF_AX25)
+ protocol = AX25_P_TEXT;
+ break;
+
+ case SOCK_SEQPACKET:
+ switch (protocol) {
+ case 0:
+ case PF_AX25: /* For CLX */
+ protocol = AX25_P_TEXT;
break;
- case SOCK_SEQPACKET:
- switch (protocol) {
- case 0:
- case PF_AX25: /* For CLX */
- protocol = AX25_P_TEXT;
- break;
- case AX25_P_SEGMENT:
+ case AX25_P_SEGMENT:
#ifdef CONFIG_INET
- case AX25_P_ARP:
- case AX25_P_IP:
+ case AX25_P_ARP:
+ case AX25_P_IP:
#endif
#ifdef CONFIG_NETROM
- case AX25_P_NETROM:
+ case AX25_P_NETROM:
#endif
#ifdef CONFIG_ROSE
- case AX25_P_ROSE:
+ case AX25_P_ROSE:
#endif
- return -ESOCKTNOSUPPORT;
+ return -ESOCKTNOSUPPORT;
#ifdef CONFIG_NETROM_MODULE
- case AX25_P_NETROM:
- if (ax25_protocol_is_registered(AX25_P_NETROM))
- return -ESOCKTNOSUPPORT;
+ case AX25_P_NETROM:
+ if (ax25_protocol_is_registered(AX25_P_NETROM))
+ return -ESOCKTNOSUPPORT;
#endif
#ifdef CONFIG_ROSE_MODULE
- case AX25_P_ROSE:
- if (ax25_protocol_is_registered(AX25_P_ROSE))
- return -ESOCKTNOSUPPORT;
+ case AX25_P_ROSE:
+ if (ax25_protocol_is_registered(AX25_P_ROSE))
+ return -ESOCKTNOSUPPORT;
#endif
- default:
- break;
- }
- break;
- case SOCK_RAW:
- break;
default:
- return -ESOCKTNOSUPPORT;
+ break;
+ }
+ break;
+
+ case SOCK_RAW:
+ break;
+ default:
+ return -ESOCKTNOSUPPORT;
}
if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1, NULL)) == NULL)
@@ -923,14 +873,14 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev)
}
switch (osk->type) {
- case SOCK_DGRAM:
- break;
- case SOCK_SEQPACKET:
- break;
- default:
- sk_free(sk);
- ax25_free_cb(ax25);
- return NULL;
+ case SOCK_DGRAM:
+ break;
+ case SOCK_SEQPACKET:
+ break;
+ default:
+ sk_free(sk);
+ ax25_free_cb(ax25);
+ return NULL;
}
sock_init_data(NULL, sk);
@@ -985,58 +935,61 @@ static int ax25_release(struct socket *sock)
struct sock *sk = sock->sk;
ax25_cb *ax25;
- if (sk == NULL) return 0;
+ if (sk == NULL)
+ return 0;
+ lock_sock(sk);
ax25 = ax25_sk(sk);
if (sk->type == SOCK_SEQPACKET) {
switch (ax25->state) {
- case AX25_STATE_0:
- ax25_disconnect(ax25, 0);
- ax25_destroy_socket(ax25);
- break;
+ case AX25_STATE_0:
+ ax25_disconnect(ax25, 0);
+ ax25_destroy_socket(ax25);
+ break;
- case AX25_STATE_1:
- case AX25_STATE_2:
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25_disconnect(ax25, 0);
- ax25_destroy_socket(ax25);
- break;
+ case AX25_STATE_1:
+ case AX25_STATE_2:
+ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ ax25_disconnect(ax25, 0);
+ ax25_destroy_socket(ax25);
+ break;
- case AX25_STATE_3:
- case AX25_STATE_4:
- ax25_clear_queues(ax25);
- ax25->n2count = 0;
- switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_send_control(ax25,
- AX25_DISC,
- AX25_POLLON,
- AX25_COMMAND);
- ax25_stop_t2timer(ax25);
- ax25_stop_t3timer(ax25);
- ax25_stop_idletimer(ax25);
- break;
+ case AX25_STATE_3:
+ case AX25_STATE_4:
+ ax25_clear_queues(ax25);
+ ax25->n2count = 0;
+
+ switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_send_control(ax25,
+ AX25_DISC,
+ AX25_POLLON,
+ AX25_COMMAND);
+ ax25_stop_t2timer(ax25);
+ ax25_stop_t3timer(ax25);
+ ax25_stop_idletimer(ax25);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- ax25_stop_t3timer(ax25);
- ax25_stop_idletimer(ax25);
- break;
-#endif
- }
- ax25_calculate_t1(ax25);
- ax25_start_t1timer(ax25);
- ax25->state = AX25_STATE_2;
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
- sk->destroy = 1;
+ case AX25_PROTO_DAMA_SLAVE:
+ ax25_stop_t3timer(ax25);
+ ax25_stop_idletimer(ax25);
break;
+#endif
+ }
+ ax25_calculate_t1(ax25);
+ ax25_start_t1timer(ax25);
+ ax25->state = AX25_STATE_2;
+ sk->state = TCP_CLOSE;
+ sk->shutdown |= SEND_SHUTDOWN;
+ sk->state_change(sk);
+ sk->dead = 1;
+ sk->destroy = 1;
+ break;
- default:
- break;
+ default:
+ break;
}
} else {
sk->state = TCP_CLOSE;
@@ -1046,8 +999,9 @@ static int ax25_release(struct socket *sock)
ax25_destroy_socket(ax25);
}
- sock->sk = NULL;
+ sock->sk = NULL;
sk->socket = NULL; /* Not used, but we should do this */
+ release_sock(sk);
return 0;
}
@@ -1055,26 +1009,25 @@ static int ax25_release(struct socket *sock)
/*
* We support a funny extension here so you can (as root) give any callsign
* digipeated via a local address as source. This hack is obsolete now
- * that we've implemented support for SO_BINDTODEVICE. It is however small
+ * that we've implemented support for SO_BINDTODEVICE. It is however small
* and trivially backward compatible.
*/
static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sock *sk = sock->sk;
- ax25_cb *ax25 = ax25_sk(sk);
struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
- ax25_address *call;
ax25_dev *ax25_dev = NULL;
+ ax25_address *call;
+ ax25_cb *ax25;
+ int err = 0;
- if (sk->zapped == 0)
- return -EINVAL;
-
- if (addr_len != sizeof(struct sockaddr_ax25) &&
+ if (addr_len != sizeof(struct sockaddr_ax25) &&
addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */
if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
- (addr_len > sizeof(struct full_sockaddr_ax25)))
+ (addr_len > sizeof(struct full_sockaddr_ax25))) {
return -EINVAL;
+ }
printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n",
current->comm);
@@ -1084,8 +1037,17 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return -EINVAL;
call = ax25_findbyuid(current->euid);
- if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN))
+ if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
return -EACCES;
+ }
+
+ lock_sock(sk);
+
+ ax25 = ax25_sk(sk);
+ if (sk->zapped == 0) {
+ err = -EINVAL;
+ goto out;
+ }
if (call == NULL)
ax25->source_addr = addr->fsa_ax25.sax25_call;
@@ -1095,17 +1057,20 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
/*
* User already set interface with SO_BINDTODEVICE
*/
-
if (ax25->ax25_dev != NULL)
goto done;
if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) {
if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 &&
- (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL)
- return -EADDRNOTAVAIL;
- } else {
- if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL)
- return -EADDRNOTAVAIL;
+ (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) {
+ err = -EADDRNOTAVAIL;
+ goto out;
+ }
+ } else {
+ if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) {
+ err = -EADDRNOTAVAIL;
+ goto out;
+ }
}
if (ax25_dev != NULL)
@@ -1114,41 +1079,24 @@ static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
done:
ax25_insert_socket(ax25);
sk->zapped = 0;
+
+out:
+ release_sock(sk);
+
return 0;
}
/*
* FIXME: nonblock behaviour looks like it may have a bug.
*/
-static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
+static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
+ int addr_len, int flags)
{
struct sock *sk = sock->sk;
ax25_cb *ax25 = ax25_sk(sk);
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
ax25_digi *digi = NULL;
- int ct = 0, err;
-
- /* deal with restarts */
- if (sock->state == SS_CONNECTING) {
- switch (sk->state) {
- case TCP_SYN_SENT: /* still trying */
- return -EINPROGRESS;
-
- case TCP_ESTABLISHED: /* connection established */
- sock->state = SS_CONNECTED;
- return 0;
-
- case TCP_CLOSE: /* connection refused */
- sock->state = SS_UNCONNECTED;
- return -ECONNREFUSED;
- }
- }
-
- if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET)
- return -EISCONN; /* No reconnect on a seqpacket socket */
-
- sk->state = TCP_CLOSE;
- sock->state = SS_UNCONNECTED;
+ int ct = 0, err = 0;
/*
* some sanity checks. code further down depends on this
@@ -1162,8 +1110,9 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */
if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
- (addr_len > sizeof(struct full_sockaddr_ax25)))
+ (addr_len > sizeof(struct full_sockaddr_ax25))) {
return -EINVAL;
+ }
printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n",
current->comm);
@@ -1172,21 +1121,54 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if (fsa->fsa_ax25.sax25_family != AF_AX25)
return -EINVAL;
+ lock_sock(sk);
+
+ /* deal with restarts */
+ if (sock->state == SS_CONNECTING) {
+ switch (sk->state) {
+ case TCP_SYN_SENT: /* still trying */
+ err = -EINPROGRESS;
+ goto out;
+
+ case TCP_ESTABLISHED: /* connection established */
+ sock->state = SS_CONNECTED;
+ goto out;
+
+ case TCP_CLOSE: /* connection refused */
+ sock->state = SS_UNCONNECTED;
+ err = -ECONNREFUSED;
+ goto out;
+ }
+ }
+
+ if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET) {
+ err = -EISCONN; /* No reconnect on a seqpacket socket */
+ goto out;
+ }
+
+ sk->state = TCP_CLOSE;
+ sock->state = SS_UNCONNECTED;
+
if (ax25->digipeat != NULL) {
kfree(ax25->digipeat);
ax25->digipeat = NULL;
}
-
+
/*
* Handle digi-peaters to be used.
*/
- if (addr_len > sizeof(struct sockaddr_ax25) && fsa->fsa_ax25.sax25_ndigis != 0) {
+ if (addr_len > sizeof(struct sockaddr_ax25) &&
+ fsa->fsa_ax25.sax25_ndigis != 0) {
/* Valid number of digipeaters ? */
- if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS)
- return -EINVAL;
+ if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) {
+ err = -EINVAL;
+ goto out;
+ }
- if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL)
- return -ENOBUFS;
+ if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
+ err = -ENOBUFS;
+ goto out;
+ }
digi->ndigi = fsa->fsa_ax25.sax25_ndigis;
digi->lastrepeat = -1;
@@ -1214,19 +1196,24 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n",
current->comm);
if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0)
- return err;
+ goto out;
+
ax25_fillin_cb(ax25, ax25->ax25_dev);
ax25_insert_socket(ax25);
} else {
- if (ax25->ax25_dev == NULL)
- return -EHOSTUNREACH;
+ if (ax25->ax25_dev == NULL) {
+ err = -EHOSTUNREACH;
+ goto out;
+ }
}
if (sk->type == SOCK_SEQPACKET &&
ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi,
ax25->ax25_dev->dev)) {
- if (digi != NULL) kfree(digi);
- return -EADDRINUSE; /* Already such a connection */
+ if (digi != NULL)
+ kfree(digi);
+ err = -EADDRINUSE; /* Already such a connection */
+ goto out;
}
ax25->dest_addr = fsa->fsa_ax25.sax25_call;
@@ -1236,7 +1223,7 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if (sk->type != SOCK_SEQPACKET) {
sock->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED;
- return 0;
+ goto out;
}
/* Move to connecting socket, ax.25 lapb WAIT_UA.. */
@@ -1244,21 +1231,20 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
sk->state = TCP_SYN_SENT;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_std_establish_data_link(ax25);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_establish_data_link(ax25);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- ax25->modulus = AX25_MODULUS;
- ax25->window =
- ax25->ax25_dev->values[AX25_VALUES_WINDOW];
- if (ax25->ax25_dev->dama.slave)
- ax25_ds_establish_data_link(ax25);
- else
- ax25_std_establish_data_link(ax25);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+ if (ax25->ax25_dev->dama.slave)
+ ax25_ds_establish_data_link(ax25);
+ else
+ ax25_std_establish_data_link(ax25);
+ break;
#endif
}
@@ -1267,30 +1253,43 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
ax25_start_heartbeat(ax25);
/* Now the loop */
- if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
- return -EINPROGRESS;
+ if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
+ err = -EINPROGRESS;
+ goto out;
+ }
- cli(); /* To avoid races on the sleep */
+ if (sk->state == TCP_SYN_SENT) {
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
- /* A DM or timeout will go to closed, a UA will go to ABM */
- while (sk->state == TCP_SYN_SENT) {
- interruptible_sleep_on(sk->sleep);
- if (signal_pending(current)) {
- sti();
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ if (sk->state != TCP_SYN_SENT)
+ break;
+ set_current_state(TASK_INTERRUPTIBLE);
+ release_sock(sk);
+ if (!signal_pending(tsk)) {
+ schedule();
+ lock_sock(sk);
+ continue;
+ }
return -ERESTARTSYS;
}
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
}
if (sk->state != TCP_ESTABLISHED) {
/* Not in ABM, not in WAIT_UA -> failed */
- sti();
sock->state = SS_UNCONNECTED;
- return sock_error(sk); /* Always set at this point */
+ err = sock_error(sk); /* Always set at this point */
+ goto out;
}
sock->state = SS_CONNECTED;
- sti();
+out:
+ release_sock(sk);
return 0;
}
@@ -1298,9 +1297,12 @@ static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
{
- struct sock *sk;
- struct sock *newsk;
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
struct sk_buff *skb;
+ struct sock *newsk;
+ struct sock *sk;
+ int err = 0;
if (sock->state != SS_UNCONNECTED)
return -EINVAL;
@@ -1308,26 +1310,40 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
if ((sk = sock->sk) == NULL)
return -EINVAL;
- if (sk->type != SOCK_SEQPACKET)
- return -EOPNOTSUPP;
+ lock_sock(sk);
+ if (sk->type != SOCK_SEQPACKET) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
- if (sk->state != TCP_LISTEN)
- return -EINVAL;
+ if (sk->state != TCP_LISTEN) {
+ err = -EINVAL;
+ goto out;
+ }
/*
* The read queue this time is holding sockets ready to use
* hooked into the SABM we saved
*/
- do {
- if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
- if (flags & O_NONBLOCK)
- return -EWOULDBLOCK;
-
- interruptible_sleep_on(sk->sleep);
- if (signal_pending(current))
- return -ERESTARTSYS;
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ skb = skb_dequeue(&sk->receive_queue);
+ if (skb)
+ break;
+
+ current->state = TASK_INTERRUPTIBLE;
+ release_sock(sk);
+ if (flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ if (!signal_pending(tsk)) {
+ schedule();
+ lock_sock(sk);
+ continue;
}
- } while (skb == NULL);
+ return -ERESTARTSYS;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
newsk = skb->sk;
newsk->pair = NULL;
@@ -1340,19 +1356,29 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
newsock->sk = newsk;
newsock->state = SS_CONNECTED;
- return 0;
+out:
+ release_sock(sk);
+
+ return err;
}
-static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
+static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
+ int *uaddr_len, int peer)
{
- struct sock *sk = sock->sk;
- ax25_cb *ax25 = ax25_sk(sk);
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
+ struct sock *sk = sock->sk;
unsigned char ndigi, i;
+ ax25_cb *ax25;
+ int err = 0;
+
+ lock_sock(sk);
+ ax25 = ax25_sk(sk);
if (peer != 0) {
- if (sk->state != TCP_ESTABLISHED)
- return -ENOTCONN;
+ if (sk->state != TCP_ESTABLISHED) {
+ err = -ENOTCONN;
+ goto out;
+ }
fsa->fsa_ax25.sax25_family = AF_AX25;
fsa->fsa_ax25.sax25_call = ax25->dest_addr;
@@ -1377,41 +1403,53 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_
}
}
*uaddr_len = sizeof (struct full_sockaddr_ax25);
- return 0;
+
+out:
+ release_sock(sk);
+
+ return err;
}
-static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+ struct scm_cookie *scm)
{
- struct sock *sk = sock->sk;
- ax25_cb *ax25 = ax25_sk(sk);
struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
- int err;
+ struct sock *sk = sock->sk;
struct sockaddr_ax25 sax;
struct sk_buff *skb;
+ ax25_digi dtmp, *dp;
unsigned char *asmptr;
- int size;
- ax25_digi *dp;
- ax25_digi dtmp;
- int lv;
- int addr_len = msg->msg_namelen;
+ ax25_cb *ax25;
+ int lv, size, err, addr_len = msg->msg_namelen;
- if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
+ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) {
return -EINVAL;
+ }
+
+ lock_sock(sk);
+ ax25 = ax25_sk(sk);
- if (sk->zapped)
- return -EADDRNOTAVAIL;
+ if (sk->zapped) {
+ err = -EADDRNOTAVAIL;
+ goto out;
+ }
if (sk->shutdown & SEND_SHUTDOWN) {
send_sig(SIGPIPE, current, 0);
- return -EPIPE;
+ err = -EPIPE;
+ goto out;
}
- if (ax25->ax25_dev == NULL)
- return -ENETUNREACH;
+ if (ax25->ax25_dev == NULL) {
+ err = -ENETUNREACH;
+ goto out;
+ }
if (usax != NULL) {
- if (usax->sax25_family != AF_AX25)
- return -EINVAL;
+ if (usax->sax25_family != AF_AX25) {
+ err = -EINVAL;
+ goto out;
+ }
if (addr_len == sizeof(struct sockaddr_ax25)) {
printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n",
@@ -1420,8 +1458,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
/* support for old structure may go away some time */
if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
- (addr_len > sizeof(struct full_sockaddr_ax25)))
- return -EINVAL;
+ (addr_len > sizeof(struct full_sockaddr_ax25))) {
+ err = -EINVAL;
+ goto out;
+ }
printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n",
current->comm);
@@ -1432,8 +1472,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax;
/* Valid number of digipeaters ? */
- if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS)
- return -EINVAL;
+ if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) {
+ err = -EINVAL;
+ goto out;
+ }
dtmp.ndigi = usax->sax25_ndigis;
@@ -1447,8 +1489,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
}
sax = *usax;
- if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0)
- return -EISCONN;
+ if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0) {
+ err = -EISCONN;
+ goto out;
+ }
if (usax->sax25_ndigis == 0)
dp = NULL;
else
@@ -1459,8 +1503,10 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
* it has become closed (not started closed) and is VC
* we ought to SIGPIPE, EPIPE
*/
- if (sk->state != TCP_ESTABLISHED)
- return -ENOTCONN;
+ if (sk->state != TCP_ESTABLISHED) {
+ err = -ENOTCONN;
+ goto out;
+ }
sax.sax25_family = AF_AX25;
sax.sax25_call = ax25->dest_addr;
dp = ax25->digipeat;
@@ -1474,8 +1520,9 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Assume the worst case */
size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN;
- if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
- return err;
+ skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err);
+ if (skb == NULL)
+ goto out;
skb_reserve(skb, size - len);
@@ -1497,60 +1544,73 @@ static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct
/* Connected mode sockets go via the LAPB machine */
if (sk->state != TCP_ESTABLISHED) {
kfree_skb(skb);
- return -ENOTCONN;
+ err = -ENOTCONN;
+ goto out;
}
/* Shove it onto the queue and kick */
ax25_output(ax25, ax25->paclen, skb);
- return len;
- } else {
- asmptr = skb_push(skb, 1 + ax25_addr_size(dp));
+ err = len;
+ goto out;
+ }
- SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);
+ asmptr = skb_push(skb, 1 + ax25_addr_size(dp));
- if (dp != NULL)
- SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);
+ SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);
- /* Build an AX.25 header */
- asmptr += (lv = ax25_addr_build(asmptr, &ax25->source_addr,
- &sax.sax25_call, dp,
- AX25_COMMAND, AX25_MODULUS));
+ if (dp != NULL)
+ SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);
- SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv);
+ /* Build an AX.25 header */
+ asmptr += (lv = ax25_addr_build(asmptr, &ax25->source_addr,
+ &sax.sax25_call, dp,
+ AX25_COMMAND, AX25_MODULUS));
- skb->h.raw = asmptr;
+ SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv);
- SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr);
+ skb->h.raw = asmptr;
- *asmptr = AX25_UI;
+ SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr);
- /* Datagram frames go straight out of the door as UI */
- skb->dev = ax25->ax25_dev->dev;
+ *asmptr = AX25_UI;
- ax25_queue_xmit(skb);
+ /* Datagram frames go straight out of the door as UI */
+ skb->dev = ax25->ax25_dev->dev;
- return len;
- }
+ ax25_queue_xmit(skb);
+
+ err = len;
+
+out:
+ release_sock(sk);
+
+ return err;
}
-static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
+static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+ int flags, struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
- int copied;
struct sk_buff *skb;
- int er;
+ int copied;
+ int err = 0;
+ lock_sock(sk);
/*
* This works for seqpacket too. The receiver has ordered the
* queue for us! We do one quick check first though
*/
- if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED)
- return -ENOTCONN;
+ if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED) {
+ err = -ENOTCONN;
+ goto out;
+ }
/* Now we can treat all alike */
- if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)
- return er;
+ skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+ flags & MSG_DONTWAIT, &err);
+ if (skb == NULL)
+ goto out;
if (!ax25_sk(sk)->pidincl)
skb_pull(skb, 1); /* Remove PID */
@@ -1561,7 +1621,7 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f
if (copied > size) {
copied = size;
msg->msg_flags |= MSG_TRUNC;
- }
+ }
skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
@@ -1590,8 +1650,12 @@ static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int f
}
skb_free_datagram(sk, skb);
+ err = copied;
- return copied;
+out:
+ release_sock(sk);
+
+ return err;
}
static int ax25_shutdown(struct socket *sk, int how)
@@ -1603,137 +1667,173 @@ static int ax25_shutdown(struct socket *sk, int how)
static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk = sock->sk;
+ int res = 0;
+ lock_sock(sk);
switch (cmd) {
- case TIOCOUTQ: {
- long amount;
- amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
- if (amount < 0)
- amount = 0;
- return put_user(amount, (int *)arg);
- }
+ case TIOCOUTQ: {
+ long amount;
+ amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
+ if (amount < 0)
+ amount = 0;
+ res = put_user(amount, (int *)arg);
+ break;
+ }
- case TIOCINQ: {
- struct sk_buff *skb;
- long amount = 0L;
- /* These two are safe on a single CPU system as only user tasks fiddle here */
- if ((skb = skb_peek(&sk->receive_queue)) != NULL)
- amount = skb->len;
- return put_user(amount, (int *)arg);
- }
+ case TIOCINQ: {
+ struct sk_buff *skb;
+ long amount = 0L;
+ /* These two are safe on a single CPU system as only user tasks fiddle here */
+ if ((skb = skb_peek(&sk->receive_queue)) != NULL)
+ amount = skb->len;
+ res = put_user(amount, (int *)arg);
+ break;
+ }
- case SIOCGSTAMP:
- if (sk != NULL) {
- if (sk->stamp.tv_sec == 0)
- return -ENOENT;
- return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
- }
- return -EINVAL;
+ case SIOCGSTAMP:
+ if (sk != NULL) {
+ if (sk->stamp.tv_sec == 0) {
+ res = -ENOENT;
+ break;
+ }
+ res = copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
+ break;
+ }
+ res = -EINVAL;
+ break;
+
+ case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */
+ case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
+ case SIOCAX25GETUID: {
+ struct sockaddr_ax25 sax25;
+ if (copy_from_user(&sax25, (void *)arg, sizeof(sax25))) {
+ res = -EFAULT;
+ break;
+ }
+ res = ax25_uid_ioctl(cmd, &sax25);
+ break;
+ }
- case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */
- case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */
- case SIOCAX25GETUID: {
- struct sockaddr_ax25 sax25;
- if (copy_from_user(&sax25, (void *)arg, sizeof(sax25)))
- return -EFAULT;
- return ax25_uid_ioctl(cmd, &sax25);
+ case SIOCAX25NOUID: { /* Set the default policy (default/bar) */
+ long amount;
+ if (!capable(CAP_NET_ADMIN)) {
+ res = -EPERM;
+ break;
}
+ if (get_user(amount, (long *)arg)) {
+ res = -EFAULT;
+ break;
+ }
+ if (amount > AX25_NOUID_BLOCK) {
+ res = -EINVAL;
+ break;
+ }
+ ax25_uid_policy = amount;
+ res = 0;
+ break;
+ }
- case SIOCAX25NOUID: { /* Set the default policy (default/bar) */
- long amount;
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (get_user(amount, (long *)arg))
- return -EFAULT;
- if (amount > AX25_NOUID_BLOCK)
- return -EINVAL;
- ax25_uid_policy = amount;
- return 0;
+ case SIOCADDRT:
+ case SIOCDELRT:
+ case SIOCAX25OPTRT:
+ if (!capable(CAP_NET_ADMIN)) {
+ res = -EPERM;
+ break;
}
+ res = ax25_rt_ioctl(cmd, (void *)arg);
+ break;
- case SIOCADDRT:
- case SIOCDELRT:
- case SIOCAX25OPTRT:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- return ax25_rt_ioctl(cmd, (void *)arg);
-
- case SIOCAX25CTLCON:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- return ax25_ctl_ioctl(cmd, (void *)arg);
-
- case SIOCAX25GETINFO:
- case SIOCAX25GETINFOOLD: {
- ax25_cb *ax25 = ax25_sk(sk);
- struct ax25_info_struct ax25_info;
-
- ax25_info.t1 = ax25->t1 / HZ;
- ax25_info.t2 = ax25->t2 / HZ;
- ax25_info.t3 = ax25->t3 / HZ;
- ax25_info.idle = ax25->idle / (60 * HZ);
- ax25_info.n2 = ax25->n2;
- ax25_info.t1timer = ax25_display_timer(&ax25->t1timer) / HZ;
- ax25_info.t2timer = ax25_display_timer(&ax25->t2timer) / HZ;
- ax25_info.t3timer = ax25_display_timer(&ax25->t3timer) / HZ;
- ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ);
- ax25_info.n2count = ax25->n2count;
- ax25_info.state = ax25->state;
- ax25_info.rcv_q = atomic_read(&sk->rmem_alloc);
- ax25_info.snd_q = atomic_read(&sk->wmem_alloc);
- ax25_info.vs = ax25->vs;
- ax25_info.vr = ax25->vr;
- ax25_info.va = ax25->va;
- ax25_info.vs_max = ax25->vs; /* reserved */
- ax25_info.paclen = ax25->paclen;
- ax25_info.window = ax25->window;
-
- /* old structure? */
- if (cmd == SIOCAX25GETINFOOLD) {
- static int warned = 0;
- if (!warned) {
- printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",
- current->comm);
- warned=1;
- }
-
- if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated)))
- return -EFAULT;
- } else {
- if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct)))
- return -EINVAL;
- }
- return 0;
+ case SIOCAX25CTLCON:
+ if (!capable(CAP_NET_ADMIN)) {
+ res = -EPERM;
+ break;
}
+ res = ax25_ctl_ioctl(cmd, (void *)arg);
+ break;
+
+ case SIOCAX25GETINFO:
+ case SIOCAX25GETINFOOLD: {
+ ax25_cb *ax25 = ax25_sk(sk);
+ struct ax25_info_struct ax25_info;
+
+ ax25_info.t1 = ax25->t1 / HZ;
+ ax25_info.t2 = ax25->t2 / HZ;
+ ax25_info.t3 = ax25->t3 / HZ;
+ ax25_info.idle = ax25->idle / (60 * HZ);
+ ax25_info.n2 = ax25->n2;
+ ax25_info.t1timer = ax25_display_timer(&ax25->t1timer) / HZ;
+ ax25_info.t2timer = ax25_display_timer(&ax25->t2timer) / HZ;
+ ax25_info.t3timer = ax25_display_timer(&ax25->t3timer) / HZ;
+ ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ);
+ ax25_info.n2count = ax25->n2count;
+ ax25_info.state = ax25->state;
+ ax25_info.rcv_q = atomic_read(&sk->rmem_alloc);
+ ax25_info.snd_q = atomic_read(&sk->wmem_alloc);
+ ax25_info.vs = ax25->vs;
+ ax25_info.vr = ax25->vr;
+ ax25_info.va = ax25->va;
+ ax25_info.vs_max = ax25->vs; /* reserved */
+ ax25_info.paclen = ax25->paclen;
+ ax25_info.window = ax25->window;
+
+ /* old structure? */
+ if (cmd == SIOCAX25GETINFOOLD) {
+ static int warned = 0;
+ if (!warned) {
+ printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",
+ current->comm);
+ warned=1;
+ }
- case SIOCAX25ADDFWD:
- case SIOCAX25DELFWD: {
- struct ax25_fwd_struct ax25_fwd;
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd)))
- return -EFAULT;
- return ax25_fwd_ioctl(cmd, &ax25_fwd);
+ if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated))) {
+ res = -EFAULT;
+ break;
+ }
+ } else {
+ if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) {
+ res = -EINVAL;
+ break;
+ }
}
+ res = 0;
+ break;
+ }
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- case SIOCGIFMETRIC:
- case SIOCSIFMETRIC:
- return -EINVAL;
+ case SIOCAX25ADDFWD:
+ case SIOCAX25DELFWD: {
+ struct ax25_fwd_struct ax25_fwd;
+ if (!capable(CAP_NET_ADMIN)) {
+ res = -EPERM;
+ break;
+ }
+ if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) {
+ res = -EFAULT;
+ break;
+ }
+ res = ax25_fwd_ioctl(cmd, &ax25_fwd);
+ break;
+ }
- default:
- return dev_ioctl(cmd, (void *)arg);
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFMETRIC:
+ case SIOCSIFMETRIC:
+ res = -EINVAL;
+ break;
+
+ default:
+ res = dev_ioctl(cmd, (void *)arg);
+ break;
}
+ release_sock(sk);
- /*NOTREACHED*/
- return 0;
+ return res;
}
static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
@@ -1744,28 +1844,28 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
off_t begin = 0;
- cli();
+ spin_lock_bh(&ax25_list_lock);
/*
* New format:
- * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode
+ * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode
*/
-
+
for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {
- len += sprintf(buffer+len, "%8.8lx %s %s%s ",
- (long) ax25,
+ len += sprintf(buffer+len, "%8.8lx %s %s%s ",
+ (long) ax25,
ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,
ax2asc(&ax25->source_addr),
ax25->iamdigi? "*":"");
len += sprintf(buffer+len, "%s", ax2asc(&ax25->dest_addr));
-
+
for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) {
len += sprintf(buffer+len, ",%s%s",
ax2asc(&ax25->digipeat->calls[k]),
ax25->digipeat->repeated[k]? "*":"");
}
-
+
len += sprintf(buffer+len, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d",
ax25->state,
ax25->vs, ax25->vr, ax25->va,
@@ -1799,7 +1899,7 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
break;
}
- sti();
+ spin_unlock_bh(&ax25_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
@@ -1814,7 +1914,7 @@ static struct net_proto_family ax25_family_ops = {
.create = ax25_create,
};
-static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {
+static struct proto_ops ax25_proto_ops = {
.family = PF_AX25,
.release = ax25_release,
@@ -1835,15 +1935,14 @@ static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {
.sendpage = sock_no_sendpage,
};
-#include <linux/smp_lock.h>
-SOCKOPS_WRAP(ax25_proto, PF_AX25);
-
/*
* Called by socket.c on kernel start up
*/
static struct packet_type ax25_packet_type = {
- .type = __constant_htons(ETH_P_AX25),
- .func = ax25_kiss_rcv,
+ .type = __constant_htons(ETH_P_AX25),
+ .dev = NULL, /* All devices */
+ .func = ax25_kiss_rcv,
+ .data = (void *) 1
};
static struct notifier_block ax25_dev_notifier = {
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
index f96c65586c04..f4fa6dfb846e 100644
--- a/net/ax25/ax25_addr.c
+++ b/net/ax25/ax25_addr.c
@@ -1,24 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -165,14 +152,14 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
if (flags != NULL) {
*flags = 0;
-
+
if (buf[6] & AX25_CBIT)
*flags = AX25_COMMAND;
if (buf[13] & AX25_CBIT)
*flags = AX25_RESPONSE;
}
- if (dama != NULL)
+ if (dama != NULL)
*dama = ~buf[13] & AX25_DAMA_FLAG;
/* Copy to, from */
@@ -243,7 +230,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a
if (d == NULL || d->ndigi == 0) {
buf[6] |= AX25_EBIT;
return 2 * AX25_ADDR_LEN;
- }
+ }
buf += AX25_ADDR_LEN;
len += AX25_ADDR_LEN;
@@ -277,7 +264,7 @@ int ax25_addr_size(ax25_digi *dp)
return AX25_ADDR_LEN * (2 + dp->ndigi);
}
-/*
+/*
* Reverse Digipeat List. May not pass both parameters as same struct
*/
void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c
index efeec64e03ec..e26110d6c0ca 100644
--- a/net/ax25/ax25_dev.c
+++ b/net/ax25/ax25_dev.c
@@ -1,21 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -27,6 +17,7 @@
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
+#include <linux/spinlock.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
@@ -41,27 +32,35 @@
#include <linux/init.h>
ax25_dev *ax25_dev_list;
+spinlock_t ax25_dev_lock = SPIN_LOCK_UNLOCKED;
ax25_dev *ax25_dev_ax25dev(struct net_device *dev)
{
- ax25_dev *ax25_dev;
+ ax25_dev *ax25_dev, *res = NULL;
+ spin_lock_bh(&ax25_dev_lock);
for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
- if (ax25_dev->dev == dev)
- return ax25_dev;
+ if (ax25_dev->dev == dev) {
+ res = ax25_dev;
+ break;
+ }
+ spin_unlock_bh(&ax25_dev_lock);
- return NULL;
+ return res;
}
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)
- if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0)
- return ax25_dev;
+ if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) {
+ res = ax25_dev;
+ }
+ spin_unlock_bh(&ax25_dev_lock);
- return NULL;
+ return res;
}
/*
@@ -71,7 +70,6 @@ ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
void ax25_dev_device_up(struct net_device *dev)
{
ax25_dev *ax25_dev;
- unsigned long flags;
if ((ax25_dev = kmalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) {
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)
ax25_dev->values[AX25_VALUES_PROTOCOL] = AX25_DEF_PROTOCOL;
ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT;
- save_flags(flags); cli();
+ spin_lock_bh(&ax25_dev_lock);
ax25_dev->next = ax25_dev_list;
ax25_dev_list = ax25_dev;
- restore_flags(flags);
+ spin_unlock_bh(&ax25_dev_lock);
ax25_register_sysctl();
}
@@ -111,14 +109,13 @@ void ax25_dev_device_up(struct net_device *dev)
void ax25_dev_device_down(struct net_device *dev)
{
ax25_dev *s, *ax25_dev;
- unsigned long flags;
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return;
ax25_unregister_sysctl();
- save_flags(flags); cli();
+ spin_lock_bh(&ax25_dev_lock);
#ifdef CONFIG_AX25_DAMA_SLAVE
ax25_ds_del_timer(ax25_dev);
@@ -133,7 +130,7 @@ void ax25_dev_device_down(struct net_device *dev)
if ((s = ax25_dev_list) == ax25_dev) {
ax25_dev_list = s->next;
- restore_flags(flags);
+ spin_unlock_bh(&ax25_dev_lock);
kfree(ax25_dev);
ax25_register_sysctl();
return;
@@ -142,7 +139,7 @@ void ax25_dev_device_down(struct net_device *dev)
while (s != NULL && s->next != NULL) {
if (s->next == ax25_dev) {
s->next = ax25_dev->next;
- restore_flags(flags);
+ spin_unlock_bh(&ax25_dev_lock);
kfree(ax25_dev);
ax25_register_sysctl();
return;
@@ -150,8 +147,8 @@ void ax25_dev_device_down(struct net_device *dev)
s = s->next;
}
+ spin_unlock_bh(&ax25_dev_lock);
- restore_flags(flags);
ax25_register_sysctl();
}
@@ -163,22 +160,22 @@ int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
return -EINVAL;
switch (cmd) {
- case SIOCAX25ADDFWD:
- if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
- return -EINVAL;
- if (ax25_dev->forward != NULL)
- return -EINVAL;
- ax25_dev->forward = fwd_dev->dev;
- break;
-
- case SIOCAX25DELFWD:
- if (ax25_dev->forward == NULL)
- return -EINVAL;
- ax25_dev->forward = NULL;
- break;
+ case SIOCAX25ADDFWD:
+ if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
+ return -EINVAL;
+ if (ax25_dev->forward != NULL)
+ return -EINVAL;
+ ax25_dev->forward = fwd_dev->dev;
+ break;
- default:
+ case SIOCAX25DELFWD:
+ if (ax25_dev->forward == NULL)
return -EINVAL;
+ ax25_dev->forward = NULL;
+ break;
+
+ default:
+ return -EINVAL;
}
return 0;
@@ -202,12 +199,16 @@ struct net_device *ax25_fwd_dev(struct net_device *dev)
*/
void __exit ax25_dev_free(void)
{
- ax25_dev *s, *ax25_dev = ax25_dev_list;
+ ax25_dev *s, *ax25_dev;
+ spin_lock_bh(&ax25_dev_lock);
+ ax25_dev = ax25_dev_list;
while (ax25_dev != NULL) {
s = ax25_dev;
ax25_dev = ax25_dev->next;
kfree(s);
}
+ ax25_dev_list = NULL;
+ spin_unlock_bh(&ax25_dev_lock);
}
diff --git a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c
index 2ae715ec3911..387e1a63bc7d 100644
--- a/net/ax25/ax25_ds_in.c
+++ b/net/ax25/ax25_ds_in.c
@@ -1,27 +1,12 @@
/*
- * 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
- *
- * 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
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -53,54 +38,56 @@
static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
switch (frametype) {
- case AX25_SABM:
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- break;
-
- case AX25_SABME:
- ax25->modulus = AX25_EMODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- break;
-
- case AX25_DISC:
- ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
- break;
-
- case AX25_UA:
- ax25_calculate_rtt(ax25);
- ax25_stop_t1timer(ax25);
- ax25_start_t3timer(ax25);
- ax25_start_idletimer(ax25);
- ax25->vs = 0;
- ax25->va = 0;
- ax25->vr = 0;
- ax25->state = AX25_STATE_3;
- ax25->n2count = 0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_ESTABLISHED;
- /* For WAIT_SABM connections we will produce an accept ready socket here */
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- }
- ax25_dama_on(ax25);
-
- /* according to DK4EG´s spec we are required to
- * send a RR RESPONSE FINAL NR=0.
- */
-
- ax25_std_enquiry_response(ax25);
- break;
-
- case AX25_DM:
- if (pf) ax25_disconnect(ax25, ECONNREFUSED);
- break;
-
- default:
- if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
- break;
+ case AX25_SABM:
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ break;
+
+ case AX25_SABME:
+ ax25->modulus = AX25_EMODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ break;
+
+ case AX25_DISC:
+ ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
+ break;
+
+ case AX25_UA:
+ ax25_calculate_rtt(ax25);
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
+ ax25->vs = 0;
+ ax25->va = 0;
+ ax25->vr = 0;
+ ax25->state = AX25_STATE_3;
+ ax25->n2count = 0;
+ if (ax25->sk != NULL) {
+ ax25->sk->state = TCP_ESTABLISHED;
+ /* For WAIT_SABM connections we will produce an accept ready socket here */
+ if (!ax25->sk->dead)
+ ax25->sk->state_change(ax25->sk);
+ }
+ ax25_dama_on(ax25);
+
+ /* according to DK4EG´s spec we are required to
+ * send a RR RESPONSE FINAL NR=0.
+ */
+
+ ax25_std_enquiry_response(ax25);
+ break;
+
+ case AX25_DM:
+ if (pf)
+ ax25_disconnect(ax25, ECONNREFUSED);
+ break;
+
+ default:
+ if (pf)
+ ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
+ break;
}
return 0;
@@ -114,38 +101,38 @@ static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
static int ax25_ds_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
switch (frametype) {
- case AX25_SABM:
- case AX25_SABME:
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25_dama_off(ax25);
- break;
-
- case AX25_DISC:
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ case AX25_SABM:
+ case AX25_SABME:
+ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ ax25_dama_off(ax25);
+ break;
+
+ case AX25_DISC:
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_dama_off(ax25);
+ ax25_disconnect(ax25, 0);
+ break;
+
+ case AX25_DM:
+ case AX25_UA:
+ if (pf) {
ax25_dama_off(ax25);
ax25_disconnect(ax25, 0);
- break;
-
- case AX25_DM:
- case AX25_UA:
- if (pf) {
- ax25_dama_off(ax25);
- ax25_disconnect(ax25, 0);
- }
- break;
-
- case AX25_I:
- case AX25_REJ:
- case AX25_RNR:
- case AX25_RR:
- if (pf) {
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25_dama_off(ax25);
- }
- break;
+ }
+ break;
+
+ case AX25_I:
+ case AX25_REJ:
+ case AX25_RNR:
+ case AX25_RR:
+ if (pf) {
+ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ ax25_dama_off(ax25);
+ }
+ break;
- default:
- break;
+ default:
+ break;
}
return 0;
@@ -161,127 +148,127 @@ static int ax25_ds_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int framet
int queued = 0;
switch (frametype) {
- case AX25_SABM:
- case AX25_SABME:
- if (frametype == AX25_SABM) {
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
- } else {
- ax25->modulus = AX25_EMODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
- }
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- ax25_stop_t1timer(ax25);
- ax25_start_t3timer(ax25);
- ax25_start_idletimer(ax25);
- ax25->condition = 0x00;
- ax25->vs = 0;
- ax25->va = 0;
- ax25->vr = 0;
- ax25_requeue_frames(ax25);
- ax25_dama_on(ax25);
- break;
-
- case AX25_DISC:
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- ax25_dama_off(ax25);
- ax25_disconnect(ax25, 0);
- break;
-
- case AX25_DM:
- ax25_dama_off(ax25);
- ax25_disconnect(ax25, ECONNRESET);
- break;
+ case AX25_SABM:
+ case AX25_SABME:
+ if (frametype == AX25_SABM) {
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+ } else {
+ ax25->modulus = AX25_EMODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+ }
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
+ ax25->condition = 0x00;
+ ax25->vs = 0;
+ ax25->va = 0;
+ ax25->vr = 0;
+ ax25_requeue_frames(ax25);
+ ax25_dama_on(ax25);
+ break;
+
+ case AX25_DISC:
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_dama_off(ax25);
+ ax25_disconnect(ax25, 0);
+ break;
+
+ case AX25_DM:
+ ax25_dama_off(ax25);
+ ax25_disconnect(ax25, ECONNRESET);
+ break;
+
+ case AX25_RR:
+ case AX25_RNR:
+ if (frametype == AX25_RR)
+ ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+ else
+ ax25->condition |= AX25_COND_PEER_RX_BUSY;
+
+ if (ax25_validate_nr(ax25, nr)) {
+ if (ax25_check_iframes_acked(ax25, nr))
+ ax25->n2count=0;
+ if (type == AX25_COMMAND && pf)
+ ax25_ds_enquiry_response(ax25);
+ } else {
+ ax25_ds_nr_error_recovery(ax25);
+ ax25->state = AX25_STATE_1;
+ }
+ break;
- case AX25_RR:
- case AX25_RNR:
- if (frametype == AX25_RR)
- ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
- else
- ax25->condition |= AX25_COND_PEER_RX_BUSY;
-
- if (ax25_validate_nr(ax25, nr)) {
- if (ax25_check_iframes_acked(ax25, nr))
- ax25->n2count=0;
- if (type == AX25_COMMAND && pf)
- ax25_ds_enquiry_response(ax25);
- } else {
- ax25_ds_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- }
- break;
+ case AX25_REJ:
+ ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
- case AX25_REJ:
- ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+ if (ax25_validate_nr(ax25, nr)) {
+ if (ax25->va != nr)
+ ax25->n2count=0;
- if (ax25_validate_nr(ax25, nr)) {
- if (ax25->va != nr)
- ax25->n2count=0;
+ ax25_frames_acked(ax25, nr);
+ ax25_calculate_rtt(ax25);
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_requeue_frames(ax25);
- ax25_frames_acked(ax25, nr);
- ax25_calculate_rtt(ax25);
- ax25_stop_t1timer(ax25);
- ax25_start_t3timer(ax25);
- ax25_requeue_frames(ax25);
+ if (type == AX25_COMMAND && pf)
+ ax25_ds_enquiry_response(ax25);
+ } else {
+ ax25_ds_nr_error_recovery(ax25);
+ ax25->state = AX25_STATE_1;
+ }
+ break;
- if (type == AX25_COMMAND && pf)
- ax25_ds_enquiry_response(ax25);
- } else {
- ax25_ds_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- }
+ case AX25_I:
+ if (!ax25_validate_nr(ax25, nr)) {
+ ax25_ds_nr_error_recovery(ax25);
+ ax25->state = AX25_STATE_1;
break;
-
- case AX25_I:
- if (!ax25_validate_nr(ax25, nr)) {
- ax25_ds_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- break;
- }
- if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
- ax25_frames_acked(ax25, nr);
+ }
+ if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
+ ax25_frames_acked(ax25, nr);
+ ax25->n2count = 0;
+ } else {
+ if (ax25_check_iframes_acked(ax25, nr))
ax25->n2count = 0;
+ }
+ if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+ if (pf) ax25_ds_enquiry_response(ax25);
+ break;
+ }
+ if (ns == ax25->vr) {
+ ax25->vr = (ax25->vr + 1) % ax25->modulus;
+ queued = ax25_rx_iframe(ax25, skb);
+ if (ax25->condition & AX25_COND_OWN_RX_BUSY)
+ ax25->vr = ns; /* ax25->vr - 1 */
+ ax25->condition &= ~AX25_COND_REJECT;
+ if (pf) {
+ ax25_ds_enquiry_response(ax25);
} else {
- if (ax25_check_iframes_acked(ax25, nr))
- ax25->n2count = 0;
+ if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
+ ax25->condition |= AX25_COND_ACK_PENDING;
+ ax25_start_t2timer(ax25);
+ }
}
- if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+ } else {
+ if (ax25->condition & AX25_COND_REJECT) {
if (pf) ax25_ds_enquiry_response(ax25);
- break;
- }
- if (ns == ax25->vr) {
- ax25->vr = (ax25->vr + 1) % ax25->modulus;
- queued = ax25_rx_iframe(ax25, skb);
- if (ax25->condition & AX25_COND_OWN_RX_BUSY)
- ax25->vr = ns; /* ax25->vr - 1 */
- ax25->condition &= ~AX25_COND_REJECT;
- if (pf) {
- ax25_ds_enquiry_response(ax25);
- } else {
- if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
- ax25->condition |= AX25_COND_ACK_PENDING;
- ax25_start_t2timer(ax25);
- }
- }
} else {
- if (ax25->condition & AX25_COND_REJECT) {
- if (pf) ax25_ds_enquiry_response(ax25);
- } else {
- ax25->condition |= AX25_COND_REJECT;
- ax25_ds_enquiry_response(ax25);
- ax25->condition &= ~AX25_COND_ACK_PENDING;
- }
+ ax25->condition |= AX25_COND_REJECT;
+ ax25_ds_enquiry_response(ax25);
+ ax25->condition &= ~AX25_COND_ACK_PENDING;
}
- break;
+ }
+ break;
- case AX25_FRMR:
- case AX25_ILLEGAL:
- ax25_ds_establish_data_link(ax25);
- ax25->state = AX25_STATE_1;
- break;
+ case AX25_FRMR:
+ case AX25_ILLEGAL:
+ ax25_ds_establish_data_link(ax25);
+ ax25->state = AX25_STATE_1;
+ break;
- default:
- break;
+ default:
+ break;
}
return queued;
@@ -297,15 +284,15 @@ int ax25_ds_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
switch (ax25->state) {
- case AX25_STATE_1:
- queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type);
- break;
- case AX25_STATE_2:
- queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type);
- break;
- case AX25_STATE_3:
- queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
- break;
+ case AX25_STATE_1:
+ queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type);
+ break;
+ case AX25_STATE_2:
+ queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type);
+ break;
+ case AX25_STATE_3:
+ queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
+ break;
}
return queued;
diff --git a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c
index e3e88d7710af..d42b8f22823f 100644
--- a/net/ax25/ax25_ds_subr.c
+++ b/net/ax25/ax25_ds_subr.c
@@ -1,27 +1,12 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -31,6 +16,7 @@
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
+#include <linux/spinlock.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <linux/inet.h>
@@ -73,7 +59,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
* DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5>
*
* Flexnet refuses to send us *any* I frame if we send
- * a REJ in case AX25_COND_REJECT is set. It is superfluous in
+ * a REJ in case AX25_COND_REJECT is set. It is superfluous in
* this mode anyway (a RR or RNR invokes the retransmission).
* Is this a Flexnet bug?
*/
@@ -93,6 +79,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
ax25_start_t3timer(ax25);
ax25_ds_set_timer(ax25->ax25_dev);
+ spin_lock_bh(&ax25_list_lock);
for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
if (ax25o == ax25)
continue;
@@ -118,6 +105,7 @@ void ax25_ds_enquiry_response(ax25_cb *ax25)
if (ax25o->state != AX25_STATE_0)
ax25_start_t3timer(ax25o);
}
+ spin_unlock_bh(&ax25_list_lock);
}
void ax25_ds_establish_data_link(ax25_cb *ax25)
@@ -132,8 +120,8 @@ void ax25_ds_establish_data_link(ax25_cb *ax25)
/*
* :::FIXME:::
- * This is a kludge. Not all drivers recognize kiss commands.
- * We need a driver level request to switch duplex mode, that does
+ * This is a kludge. Not all drivers recognize kiss commands.
+ * We need a driver level request to switch duplex mode, that does
* either SCC changing, PI config or KISS as required. Currently
* this request isn't reliable.
*/
@@ -164,19 +152,24 @@ static void ax25_kiss_cmd(ax25_dev *ax25_dev, unsigned char cmd, unsigned char p
* A nasty problem arises if we count the number of DAMA connections
* wrong, especially when connections on the device already existed
* and our network node (or the sysop) decides to turn on DAMA Master
- * mode. We thus flag the 'real' slave connections with
+ * mode. We thus flag the 'real' slave connections with
* ax25->dama_slave=1 and look on every disconnect if still slave
* connections exist.
*/
static int ax25_check_dama_slave(ax25_dev *ax25_dev)
{
ax25_cb *ax25;
+ int res = 0;
+ spin_lock_bh(&ax25_list_lock);
for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next)
- if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1)
- return 1;
+ if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) {
+ res = 1;
+ break;
+ }
+ spin_unlock_bh(&ax25_list_lock);
- return 0;
+ return res;
}
void ax25_dev_dama_on(ax25_dev *ax25_dev)
diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c
index 02c189e4cb11..ca0309376293 100644
--- a/net/ax25/ax25_ds_timer.c
+++ b/net/ax25/ax25_ds_timer.c
@@ -1,23 +1,16 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
+#include <linux/spinlock.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
@@ -41,7 +34,7 @@ static void ax25_ds_timeout(unsigned long);
/*
* Add DAMA slave timeout timer to timer list.
- * Unlike the connection based timers the timeout function gets
+ * Unlike the connection based timers the timeout function gets
* triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT
* (aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in
* 1/10th of a second.
@@ -58,7 +51,8 @@ static void ax25_ds_add_timer(ax25_dev *ax25_dev)
void ax25_ds_del_timer(ax25_dev *ax25_dev)
{
- if (ax25_dev) del_timer(&ax25_dev->dama.slave_timer);
+ if (ax25_dev)
+ del_timer(&ax25_dev->dama.slave_timer);
}
void ax25_ds_set_timer(ax25_dev *ax25_dev)
@@ -80,15 +74,16 @@ static void ax25_ds_timeout(unsigned long arg)
{
ax25_dev *ax25_dev = (struct ax25_dev *) arg;
ax25_cb *ax25;
-
+
if (ax25_dev == NULL || !ax25_dev->dama.slave)
return; /* Yikes! */
-
+
if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) {
ax25_ds_set_timer(ax25_dev);
return;
}
-
+
+ spin_lock_bh(&ax25_list_lock);
for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) {
if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
continue;
@@ -96,7 +91,8 @@ static void ax25_ds_timeout(unsigned long arg)
ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
ax25_disconnect(ax25, ETIMEDOUT);
}
-
+ spin_unlock_bh(&ax25_list_lock);
+
ax25_dev_dama_off(ax25_dev);
}
@@ -104,33 +100,33 @@ void ax25_ds_heartbeat_expiry(ax25_cb *ax25)
{
switch (ax25->state) {
- case AX25_STATE_0:
- /* Magic here: If we listen() and a new link dies before it
- is accepted() it isn't 'dead' so doesn't get removed. */
- if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
- ax25_destroy_socket(ax25);
- return;
+ case AX25_STATE_0:
+ /* Magic here: If we listen() and a new link dies before it
+ is accepted() it isn't 'dead' so doesn't get removed. */
+ if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
+ ax25_destroy_socket(ax25);
+ return;
+ }
+ break;
+
+ case AX25_STATE_3:
+ /*
+ * Check the state of the receive buffer.
+ */
+ if (ax25->sk != NULL) {
+ if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
+ (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
+ ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
+ ax25->condition &= ~AX25_COND_ACK_PENDING;
+ break;
}
- break;
-
- case AX25_STATE_3:
- /*
- * Check the state of the receive buffer.
- */
- if (ax25->sk != NULL) {
- if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
- (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
- ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
- ax25->condition &= ~AX25_COND_ACK_PENDING;
- break;
- }
- }
- break;
+ }
+ break;
}
ax25_start_heartbeat(ax25);
}
-
+
/* dl1bke 960114: T3 works much like the IDLE timeout, but
* gets reloaded with every frame for this
* connection.
@@ -168,7 +164,7 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
}
/* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
- * within the poll of any connected channel. Remember
+ * within the poll of any connected channel. Remember
* that we are not allowed to send anything unless we
* get polled by the Master.
*
@@ -176,48 +172,47 @@ void ax25_ds_idletimer_expiry(ax25_cb *ax25)
* ax25_enquiry_response().
*/
void ax25_ds_t1_timeout(ax25_cb *ax25)
-{
+{
switch (ax25->state) {
-
- case AX25_STATE_1:
- if (ax25->n2count == ax25->n2) {
- if (ax25->modulus == AX25_MODULUS) {
- ax25_disconnect(ax25, ETIMEDOUT);
- return;
- } else {
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
- ax25->n2count = 0;
- ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
- }
- } else {
- ax25->n2count++;
- if (ax25->modulus == AX25_MODULUS)
- ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
- else
- ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
- }
- break;
-
- case AX25_STATE_2:
- if (ax25->n2count == ax25->n2) {
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
- ax25_disconnect(ax25, ETIMEDOUT);
- return;
- } else {
- ax25->n2count++;
- }
- break;
-
- case AX25_STATE_3:
- if (ax25->n2count == ax25->n2) {
- ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
+ case AX25_STATE_1:
+ if (ax25->n2count == ax25->n2) {
+ if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
- ax25->n2count++;
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+ ax25->n2count = 0;
+ ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
}
- break;
+ } else {
+ ax25->n2count++;
+ if (ax25->modulus == AX25_MODULUS)
+ ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
+ else
+ ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
+ }
+ break;
+
+ case AX25_STATE_2:
+ if (ax25->n2count == ax25->n2) {
+ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
+ } else {
+ ax25->n2count++;
+ }
+ break;
+
+ case AX25_STATE_3:
+ if (ax25->n2count == ax25->n2) {
+ ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
+ } else {
+ ax25->n2count++;
+ }
+ break;
}
ax25_calculate_t1(ax25);
diff --git a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c
index 15ca9c45304e..403624e592ff 100644
--- a/net/ax25/ax25_iface.c
+++ b/net/ax25/ax25_iface.c
@@ -1,18 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -20,6 +13,7 @@
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
@@ -40,22 +34,25 @@ static struct protocol_struct {
unsigned int pid;
int (*func)(struct sk_buff *, ax25_cb *);
} *protocol_list;
+static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED;
static struct linkfail_struct {
struct linkfail_struct *next;
void (*func)(ax25_cb *, int);
} *linkfail_list;
+static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED;
static struct listen_struct {
struct listen_struct *next;
ax25_address callsign;
struct net_device *dev;
} *listen_list;
+static spinlock_t listen_lock = SPIN_LOCK_UNLOCKED;
-int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_cb *))
+int ax25_protocol_register(unsigned int pid,
+ int (*func)(struct sk_buff *, ax25_cb *))
{
struct protocol_struct *protocol;
- unsigned long flags;
if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT)
return 0;
@@ -69,31 +66,28 @@ int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_
protocol->pid = pid;
protocol->func = func;
- save_flags(flags);
- cli();
-
+ write_lock(&protocol_list_lock);
protocol->next = protocol_list;
protocol_list = protocol;
-
- restore_flags(flags);
+ write_unlock(&protocol_list_lock);
return 1;
}
void ax25_protocol_release(unsigned int pid)
{
- struct protocol_struct *s, *protocol = protocol_list;
- unsigned long flags;
+ struct protocol_struct *s, *protocol;
- if (protocol == NULL)
+ write_lock(&protocol_list_lock);
+ protocol = protocol_list;
+ if (protocol == NULL) {
+ write_unlock(&protocol_list_lock);
return;
-
- save_flags(flags);
- cli();
+ }
if (protocol->pid == pid) {
protocol_list = protocol->next;
- restore_flags(flags);
+ write_unlock(&protocol_list_lock);
kfree(protocol);
return;
}
@@ -102,52 +96,45 @@ void ax25_protocol_release(unsigned int pid)
if (protocol->next->pid == pid) {
s = protocol->next;
protocol->next = protocol->next->next;
- restore_flags(flags);
+ write_unlock(&protocol_list_lock);
kfree(s);
return;
}
protocol = protocol->next;
}
-
- restore_flags(flags);
+ write_unlock(&protocol_list_lock);
}
int ax25_linkfail_register(void (*func)(ax25_cb *, int))
{
struct linkfail_struct *linkfail;
- unsigned long flags;
if ((linkfail = kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL)
return 0;
linkfail->func = func;
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&linkfail_lock);
linkfail->next = linkfail_list;
linkfail_list = linkfail;
-
- restore_flags(flags);
+ spin_unlock_bh(&linkfail_lock);
return 1;
}
void ax25_linkfail_release(void (*func)(ax25_cb *, int))
{
- struct linkfail_struct *s, *linkfail = linkfail_list;
- unsigned long flags;
+ struct linkfail_struct *s, *linkfail;
+ spin_lock_bh(&linkfail_lock);
+ linkfail = linkfail_list;
if (linkfail == NULL)
return;
- save_flags(flags);
- cli();
-
if (linkfail->func == func) {
linkfail_list = linkfail->next;
- restore_flags(flags);
+ spin_unlock_bh(&linkfail_lock);
kfree(linkfail);
return;
}
@@ -156,21 +143,19 @@ void ax25_linkfail_release(void (*func)(ax25_cb *, int))
if (linkfail->next->func == func) {
s = linkfail->next;
linkfail->next = linkfail->next->next;
- restore_flags(flags);
+ spin_unlock_bh(&linkfail_lock);
kfree(s);
return;
}
linkfail = linkfail->next;
}
-
- restore_flags(flags);
+ spin_unlock_bh(&linkfail_lock);
}
int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
{
struct listen_struct *listen;
- unsigned long flags;
if (ax25_listen_mine(callsign, dev))
return 0;
@@ -181,31 +166,26 @@ int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
listen->callsign = *callsign;
listen->dev = dev;
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&listen_lock);
listen->next = listen_list;
listen_list = listen;
-
- restore_flags(flags);
+ spin_unlock_bh(&listen_lock);
return 1;
}
void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
{
- struct listen_struct *s, *listen = listen_list;
- unsigned long flags;
+ struct listen_struct *s, *listen;
+ spin_lock_bh(&listen_lock);
+ listen = listen_list;
if (listen == NULL)
return;
- save_flags(flags);
- cli();
-
if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
listen_list = listen->next;
- restore_flags(flags);
+ spin_unlock_bh(&listen_lock);
kfree(listen);
return;
}
@@ -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) {
s = listen->next;
listen->next = listen->next->next;
- restore_flags(flags);
+ spin_unlock_bh(&listen_lock);
kfree(s);
return;
}
listen = listen->next;
}
-
- restore_flags(flags);
+ spin_unlock_bh(&listen_lock);
}
int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
{
+ int (*res)(struct sk_buff *, ax25_cb *) = NULL;
struct protocol_struct *protocol;
+ read_lock(&protocol_list_lock);
for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
- if (protocol->pid == pid)
- return protocol->func;
+ if (protocol->pid == pid) {
+ res = protocol->func;
+ break;
+ }
+ read_unlock(&protocol_list_lock);
- return NULL;
+ return res;
}
int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
{
struct listen_struct *listen;
+ spin_lock_bh(&listen_lock);
for (listen = listen_list; listen != NULL; listen = listen->next)
if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL))
return 1;
+ spin_unlock_bh(&listen_lock);
return 0;
}
@@ -251,18 +237,24 @@ void ax25_link_failed(ax25_cb *ax25, int reason)
{
struct linkfail_struct *linkfail;
+ spin_lock_bh(&linkfail_lock);
for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
(linkfail->func)(ax25, reason);
+ spin_unlock_bh(&linkfail_lock);
}
int ax25_protocol_is_registered(unsigned int pid)
{
struct protocol_struct *protocol;
+ int res = 0;
+ read_lock(&protocol_list_lock);
for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
- if (protocol->pid == pid)
- return 1;
+ if (protocol->pid == pid) {
+ res = 1;
+ break;
+ }
+ read_unlock(&protocol_list_lock);
- return 0;
+ return res;
}
-
diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
index 2abbd886c26f..a886b03e9c2f 100644
--- a/net/ax25/ax25_in.c
+++ b/net/ax25/ax25_in.c
@@ -1,44 +1,14 @@
/*
- * 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
- *
- * 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 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.
+ * 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)
*/
-
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -146,7 +116,7 @@ int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb)
#ifdef CONFIG_INET
if (pid == AX25_P_IP) {
- /* working around a TCP bug to keep additional listeners
+ /* working around a TCP bug to keep additional listeners
* happy. TCP re-uses the buffer and destroys the original
* content.
*/
@@ -199,37 +169,33 @@ static int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type, i
return 0;
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- queued = ax25_std_frame_in(ax25, skb, type);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ queued = ax25_std_frame_in(ax25, skb, type);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- if (dama || ax25->ax25_dev->dama.slave)
- queued = ax25_ds_frame_in(ax25, skb, type);
- else
- queued = ax25_std_frame_in(ax25, skb, type);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ if (dama || ax25->ax25_dev->dama.slave)
+ queued = ax25_ds_frame_in(ax25, skb, type);
+ else
+ queued = ax25_std_frame_in(ax25, skb, type);
+ break;
#endif
}
return queued;
}
-static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *dev_addr, struct packet_type *ptype)
+static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
+ ax25_address *dev_addr, struct packet_type *ptype)
{
- struct sock *make;
- struct sock *sk;
- int type = 0;
+ ax25_address src, dest, *next_digi = NULL;
+ int type = 0, mine = 0, dama;
+ struct sock *make, *sk, *raw;
ax25_digi dp, reverse_dp;
ax25_cb *ax25;
- ax25_address src, dest;
- ax25_address *next_digi = NULL;
ax25_dev *ax25_dev;
- struct sock *raw;
- int mine = 0;
- int dama;
/*
* 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
if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
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]);
+ release_sock(raw);
+ }
if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) {
kfree_skb(skb);
@@ -285,47 +253,49 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *d
/* Now we are pointing at the pid byte */
switch (skb->data[1]) {
#ifdef CONFIG_INET
- case AX25_P_IP:
- skb_pull(skb,2); /* drop PID/CTRL */
- skb->h.raw = skb->data;
- skb->nh.raw = skb->data;
- skb->dev = dev;
- skb->pkt_type = PACKET_HOST;
- skb->protocol = htons(ETH_P_IP);
- ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */
- break;
-
- case AX25_P_ARP:
- skb_pull(skb,2);
- skb->h.raw = skb->data;
- skb->nh.raw = skb->data;
- skb->dev = dev;
- skb->pkt_type = PACKET_HOST;
- skb->protocol = htons(ETH_P_ARP);
- arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */
- break;
+ case AX25_P_IP:
+ skb_pull(skb,2); /* drop PID/CTRL */
+ skb->h.raw = skb->data;
+ skb->nh.raw = skb->data;
+ skb->dev = dev;
+ skb->pkt_type = PACKET_HOST;
+ skb->protocol = htons(ETH_P_IP);
+ ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */
+ break;
+
+ case AX25_P_ARP:
+ skb_pull(skb,2);
+ skb->h.raw = skb->data;
+ skb->nh.raw = skb->data;
+ skb->dev = dev;
+ skb->pkt_type = PACKET_HOST;
+ skb->protocol = htons(ETH_P_ARP);
+ arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */
+ break;
#endif
- case AX25_P_TEXT:
- /* Now find a suitable dgram socket */
- if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) {
- if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) {
- kfree_skb(skb);
- } else {
- /*
- * Remove the control and PID.
- */
- skb_pull(skb, 2);
- if (sock_queue_rcv_skb(sk, skb) != 0)
- kfree_skb(skb);
- }
- } else {
+ case AX25_P_TEXT:
+ /* Now find a suitable dgram socket */
+ sk = ax25_get_socket(&dest, &src, SOCK_DGRAM);
+ if (sk != NULL) {
+ if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) {
kfree_skb(skb);
+ } else {
+ /*
+ * Remove the control and PID.
+ */
+ skb_pull(skb, 2);
+ if (sock_queue_rcv_skb(sk, skb) != 0)
+ kfree_skb(skb);
}
- break;
+ release_sock(sk);
+ } else {
+ kfree_skb(skb);
+ }
+ break;
- default:
- kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */
- break;
+ default:
+ kfree_skb(skb); /* Will scan SOCK_AX25 RAW sockets */
+ break;
}
return 0;
@@ -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) {
/*
- * Process the frame. If it is queued up internally it returns one otherwise we
- * free it immediately. This routine itself wakes the user context layers so we
- * do no further work
+ * Process the frame. If it is queued up internally it
+ * returns one otherwise we free it immediately. This
+ * routine itself wakes the user context layers so we do
+ * no further work
*/
if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
kfree_skb(skb);
@@ -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) */
- 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
* 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
sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);
if (sk != NULL) {
- if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, ax25_dev)) == NULL) {
- if (mine) ax25_return_dm(dev, &src, &dest, &dp);
+ if (sk->ack_backlog == sk->max_ack_backlog ||
+ (make = ax25_make_new(sk, ax25_dev)) == NULL) {
+ if (mine)
+ ax25_return_dm(dev, &src, &dest, &dp);
kfree_skb(skb);
+
return 0;
}
@@ -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);
}
-
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index 80fe26de8181..6ea092dedab0 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -1,18 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -88,16 +81,16 @@ int ax25_encapsulate(struct sk_buff *skb, struct net_device *dev, unsigned short
/* Append a suitable AX.25 PID */
switch (type) {
- case ETH_P_IP:
- *buff++ = AX25_P_IP;
- break;
- case ETH_P_ARP:
- *buff++ = AX25_P_ARP;
- break;
- default:
- printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
- *buff++ = 0;
- break;
+ case ETH_P_IP:
+ *buff++ = AX25_P_IP;
+ break;
+ case ETH_P_ARP:
+ *buff++ = AX25_P_ARP;
+ break;
+ default:
+ printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
+ *buff++ = 0;
+ break;
}
if (daddr != NULL)
@@ -112,8 +105,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
unsigned char *bp = skb->data;
struct net_device *dev;
ax25_address *src, *dst;
- ax25_route *route;
ax25_dev *ax25_dev;
+ ax25_route _route, *route = &_route;
dst = (ax25_address *)(bp + 1);
src = (ax25_address *)(bp + 8);
@@ -121,14 +114,15 @@ int ax25_rebuild_header(struct sk_buff *skb)
if (arp_find(bp + 1, skb))
return 1;
- route = ax25_rt_find_route(dst, NULL);
+ route = ax25_rt_find_route(route, dst, NULL);
dev = route->dev;
if (dev == NULL)
dev = skb->dev;
- if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
- return 1;
+ if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
+ goto put;
+ }
if (bp[16] == AX25_P_IP) {
if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
@@ -153,7 +147,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
kfree_skb(skb);
- return 1;
+ goto put;
}
if (skb->sk != NULL)
@@ -167,10 +161,10 @@ int ax25_rebuild_header(struct sk_buff *skb)
skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */
ourskb->nh.raw = ourskb->data;
- ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c,
+ ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c,
&dst_c, route->digipeat, dev);
- return 1;
+ goto put;
}
}
@@ -187,7 +181,7 @@ int ax25_rebuild_header(struct sk_buff *skb)
if (route->digipeat != NULL) {
if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
kfree_skb(skb);
- return 1;
+ goto put;
}
skb = ourskb;
@@ -197,6 +191,9 @@ int ax25_rebuild_header(struct sk_buff *skb)
ax25_queue_xmit(skb);
+put:
+ ax25_put_route(route);
+
return 1;
}
diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
index 231c170e7a0b..e6d25e22d3ac 100644
--- a/net/ax25/ax25_out.c
+++ b/net/ax25/ax25_out.c
@@ -1,39 +1,13 @@
/*
- * 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
- *
- * 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 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)
+ * 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)
*/
-
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -44,6 +18,7 @@
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
+#include <linux/spinlock.h>
#include <linux/net.h>
#include <net/ax25.h>
#include <linux/inet.h>
@@ -57,6 +32,8 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
+static spinlock_t ax25_frag_lock = SPIN_LOCK_UNLOCKED;
+
ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev)
{
ax25_dev *ax25_dev;
@@ -101,18 +78,18 @@ ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax2
}
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_std_establish_data_link(ax25);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_establish_data_link(ax25);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- if (ax25_dev->dama.slave)
- ax25_ds_establish_data_link(ax25);
- else
- ax25_std_establish_data_link(ax25);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ if (ax25_dev->dama.slave)
+ ax25_ds_establish_data_link(ax25);
+ else
+ ax25_std_establish_data_link(ax25);
+ break;
#endif
}
@@ -138,7 +115,6 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
struct sk_buff *skbn;
unsigned char *p;
int frontlen, len, fragno, ka9qfrag, first = 1;
- long flags;
if ((skb->len - 1) > paclen) {
if (*skb->data == AX25_P_TEXT) {
@@ -155,20 +131,18 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
frontlen = skb_headroom(skb); /* Address space + CTRL */
while (skb->len > 0) {
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&ax25_frag_lock);
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");
return;
}
if (skb->sk != NULL)
skb_set_owner_w(skbn, skb->sk);
-
- restore_flags(flags);
-
+
+ spin_unlock_bh(&ax25_frag_lock);
+
len = (paclen > skb->len) ? skb->len : paclen;
if (ka9qfrag == 1) {
@@ -202,24 +176,24 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb)
}
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_kick(ax25);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_kick(ax25);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- /*
- * A DAMA slave is _required_ to work as normal AX.25L2V2
- * if no DAMA master is available.
- */
- case AX25_PROTO_DAMA_SLAVE:
- if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25);
- break;
+ /*
+ * A DAMA slave is _required_ to work as normal AX.25L2V2
+ * if no DAMA master is available.
+ */
+ case AX25_PROTO_DAMA_SLAVE:
+ if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25);
+ break;
#endif
}
}
-/*
+/*
* This procedure is passed a buffer descriptor for an iframe. It builds
* the rest of the control part of the frame and then writes it out.
*/
@@ -305,15 +279,15 @@ void ax25_kick(ax25_cb *ax25)
* in DAMA mode.
*/
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
+ break;
#endif
}
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 254ff36fb669..21a05044cfe0 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -1,49 +1,20 @@
/*
- * 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
- *
- * 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 020 Jonathan(G4KLX) First go.
- * AX.25 022 Jonathan(G4KLX) Added the actual meat to this - we now have a nice heard list.
- * AX.25 025 Alan(GW4PTS) First cut at autobinding by route scan.
- * AX.25 028b Jonathan(G4KLX) Extracted AX25 control block from the
- * sock structure. Device removal now
- * removes the heard structure.
- * AX.25 029 Steven(GW7RRM) Added /proc information for uid/callsign mapping.
- * Jonathan(G4KLX) Handling of IP mode in the routing list and /proc entry.
- * AX.25 030 Jonathan(G4KLX) Added digi-peaters to routing table, and
- * ioctls to manipulate them. Added port
- * configuration.
- * AX.25 031 Jonathan(G4KLX) Added concept of default route.
- * Joerg(DL1BKE) ax25_rt_build_path() find digipeater list and device by
- * destination call. Needed for IP routing via digipeater
- * Jonathan(G4KLX) Added routing for IP datagram packets.
- * Joerg(DL1BKE) Changed routing for IP datagram and VC to use a default
- * route if available. Does not overwrite default routes
- * on route-table overflow anymore.
- * Joerg(DL1BKE) Fixed AX.25 routing of IP datagram and VC, new ioctl()
- * "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag
- * on routes.
- * AX.25 033 Jonathan(G4KLX) Remove auto-router.
- * Joerg(DL1BKE) Moved BPQ Ethernet driver to separate device.
- * AX.25 035 Frederic(F1OAT) Support for pseudo-digipeating.
- * Jonathan(G4KLX) Support for packet forwarding.
- * Arnaldo C. Melo s/suser/capable/
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
+ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
+#include <linux/timer.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -56,6 +27,7 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
+#include <linux/spinlock.h>
#include <net/sock.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -65,8 +37,9 @@
#include <linux/init.h>
static ax25_route *ax25_route_list;
+static rwlock_t ax25_route_lock = RW_LOCK_UNLOCKED;
-static ax25_route *ax25_find_route(ax25_address *, struct net_device *);
+static ax25_route *ax25_get_route(ax25_address *, struct net_device *);
/*
* small macro to drop non-digipeated digipeaters and reverse path
@@ -86,8 +59,10 @@ static inline void ax25_route_invert(ax25_digi *in, ax25_digi *out)
void ax25_rt_device_down(struct net_device *dev)
{
- ax25_route *s, *t, *ax25_rt = ax25_route_list;
-
+ ax25_route *s, *t, *ax25_rt;
+
+ write_lock(&ax25_route_lock);
+ ax25_rt = ax25_route_list;
while (ax25_rt != NULL) {
s = ax25_rt;
ax25_rt = ax25_rt->next;
@@ -111,129 +86,196 @@ void ax25_rt_device_down(struct net_device *dev)
}
}
}
+ write_unlock(&ax25_route_lock);
}
-int ax25_rt_ioctl(unsigned int cmd, void *arg)
+static int ax25_rt_add(struct ax25_routes_struct *route)
{
- unsigned long flags;
- ax25_route *s, *t, *ax25_rt;
- struct ax25_routes_struct route;
- struct ax25_route_opt_struct rt_option;
+ ax25_route *ax25_rt;
ax25_dev *ax25_dev;
int i;
- switch (cmd) {
- case SIOCADDRT:
- if (copy_from_user(&route, arg, sizeof(route)))
- return -EFAULT;
- if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
- return -EINVAL;
- if (route.digi_count > AX25_MAX_DIGIS)
- return -EINVAL;
- for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
- if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) {
- if (ax25_rt->digipeat != NULL) {
- kfree(ax25_rt->digipeat);
- ax25_rt->digipeat = NULL;
- }
- if (route.digi_count != 0) {
- if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
- ax25_rt->digipeat->lastrepeat = -1;
- ax25_rt->digipeat->ndigi = route.digi_count;
- for (i = 0; i < route.digi_count; i++) {
- ax25_rt->digipeat->repeated[i] = 0;
- ax25_rt->digipeat->calls[i] = route.digi_addr[i];
- }
- }
- return 0;
- }
+ if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
+ return -EINVAL;
+ if (route->digi_count > AX25_MAX_DIGIS)
+ return -EINVAL;
+
+ write_lock(&ax25_route_lock);
+
+ ax25_rt = ax25_route_list;
+ while (ax25_rt != NULL) {
+ if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
+ ax25_rt->dev == ax25_dev->dev) {
+ if (ax25_rt->digipeat != NULL) {
+ kfree(ax25_rt->digipeat);
+ ax25_rt->digipeat = NULL;
}
- if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
- ax25_rt->callsign = route.dest_addr;
- ax25_rt->dev = ax25_dev->dev;
- ax25_rt->digipeat = NULL;
- ax25_rt->ip_mode = ' ';
- if (route.digi_count != 0) {
+ if (route->digi_count != 0) {
if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
- kfree(ax25_rt);
+ write_unlock(&ax25_route_lock);
return -ENOMEM;
}
ax25_rt->digipeat->lastrepeat = -1;
- ax25_rt->digipeat->ndigi = route.digi_count;
- for (i = 0; i < route.digi_count; i++) {
+ ax25_rt->digipeat->ndigi = route->digi_count;
+ for (i = 0; i < route->digi_count; i++) {
ax25_rt->digipeat->repeated[i] = 0;
- ax25_rt->digipeat->calls[i] = route.digi_addr[i];
+ ax25_rt->digipeat->calls[i] = route->digi_addr[i];
}
}
- save_flags(flags); cli();
- ax25_rt->next = ax25_route_list;
- ax25_route_list = ax25_rt;
- restore_flags(flags);
- break;
+ return 0;
+ }
+ ax25_rt = ax25_rt->next;
+ }
- case SIOCDELRT:
- if (copy_from_user(&route, arg, sizeof(route)))
- return -EFAULT;
- if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
- return -EINVAL;
- ax25_rt = ax25_route_list;
- while (ax25_rt != NULL) {
- s = ax25_rt;
- ax25_rt = ax25_rt->next;
- if (s->dev == ax25_dev->dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) {
- if (ax25_route_list == s) {
- ax25_route_list = s->next;
- if (s->digipeat != NULL)
- kfree(s->digipeat);
- kfree(s);
- } else {
- for (t = ax25_route_list; t != NULL; t = t->next) {
- if (t->next == s) {
- t->next = s->next;
- if (s->digipeat != NULL)
- kfree(s->digipeat);
- kfree(s);
- break;
- }
- }
+ if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
+ write_unlock(&ax25_route_lock);
+ return -ENOMEM;
+ }
+
+ atomic_set(&ax25_rt->ref, 0);
+ ax25_rt->callsign = route->dest_addr;
+ ax25_rt->dev = ax25_dev->dev;
+ ax25_rt->digipeat = NULL;
+ ax25_rt->ip_mode = ' ';
+ if (route->digi_count != 0) {
+ if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
+ write_unlock(&ax25_route_lock);
+ kfree(ax25_rt);
+ return -ENOMEM;
+ }
+ ax25_rt->digipeat->lastrepeat = -1;
+ ax25_rt->digipeat->ndigi = route->digi_count;
+ for (i = 0; i < route->digi_count; i++) {
+ ax25_rt->digipeat->repeated[i] = 0;
+ ax25_rt->digipeat->calls[i] = route->digi_addr[i];
+ }
+ }
+ ax25_rt->next = ax25_route_list;
+ ax25_route_list = ax25_rt;
+ write_unlock(&ax25_route_lock);
+
+ return 0;
+}
+
+static int ax25_rt_destroy(ax25_route *ax25_rt)
+{
+ if (atomic_read(&ax25_rt->ref) == 0) {
+ if (ax25_rt->digipeat != NULL)
+ kfree(ax25_rt->digipeat);
+ kfree(ax25_rt);
+ }
+
+ /*
+ * Uh... Route is still in use; we can't yet destroy it. Retry later.
+ */
+ init_timer(&ax25_rt->timer);
+ ax25_rt->timer.data = (unsigned long) ax25_rt;
+ ax25_rt->timer.function = (void *) ax25_rt_destroy;
+ ax25_rt->timer.expires = jiffies + 5 * HZ;
+
+ add_timer(&ax25_rt->timer);
+}
+
+static int ax25_rt_del(struct ax25_routes_struct *route)
+{
+ ax25_route *s, *t, *ax25_rt;
+ ax25_dev *ax25_dev;
+
+ if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
+ return -EINVAL;
+
+ write_lock(&ax25_route_lock);
+
+ ax25_rt = ax25_route_list;
+ while (ax25_rt != NULL) {
+ s = ax25_rt;
+ ax25_rt = ax25_rt->next;
+ if (s->dev == ax25_dev->dev &&
+ ax25cmp(&route->dest_addr, &s->callsign) == 0) {
+ if (ax25_route_list == s) {
+ ax25_route_list = s->next;
+ ax25_rt_destroy(s);
+ } else {
+ for (t = ax25_route_list; t != NULL; t = t->next) {
+ if (t->next == s) {
+ t->next = s->next;
+ ax25_rt_destroy(s);
+ break;
}
}
}
- break;
+ }
+ }
+ write_unlock(&ax25_route_lock);
- case SIOCAX25OPTRT:
- if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
- return -EFAULT;
- if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL)
- return -EINVAL;
- for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
- if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) {
- switch (rt_option.cmd) {
- case AX25_SET_RT_IPMODE:
- switch (rt_option.arg) {
- case ' ':
- case 'D':
- case 'V':
- ax25_rt->ip_mode = rt_option.arg;
- break;
- default:
- return -EINVAL;
- }
- break;
- default:
- return -EINVAL;
- }
+ return 0;
+}
+
+static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
+{
+ ax25_route *ax25_rt;
+ ax25_dev *ax25_dev;
+ int err = 0;
+
+ if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
+ return -EINVAL;
+
+ write_lock(&ax25_route_lock);
+
+ ax25_rt = ax25_route_list;
+ while (ax25_rt != NULL) {
+ if (ax25_rt->dev == ax25_dev->dev &&
+ ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) {
+ switch (rt_option->cmd) {
+ case AX25_SET_RT_IPMODE:
+ switch (rt_option->arg) {
+ case ' ':
+ case 'D':
+ case 'V':
+ ax25_rt->ip_mode = rt_option->arg;
+ break;
+ default:
+ err = -EINVAL;
+ goto out;
}
+ break;
+ default:
+ err = -EINVAL;
+ goto out;
}
- break;
-
- default:
- return -EINVAL;
+ }
+ ax25_rt = ax25_rt->next;
}
- return 0;
+out:
+ write_unlock(&ax25_route_lock);
+ return err;
+}
+
+int ax25_rt_ioctl(unsigned int cmd, void *arg)
+{
+ struct ax25_route_opt_struct rt_option;
+ struct ax25_routes_struct route;
+
+ switch (cmd) {
+ case SIOCADDRT:
+ if (copy_from_user(&route, arg, sizeof(route)))
+ return -EFAULT;
+ return ax25_rt_add(&route);
+
+ case SIOCDELRT:
+ if (copy_from_user(&route, arg, sizeof(route)))
+ return -EFAULT;
+ return ax25_rt_del(&route);
+
+ case SIOCAX25OPTRT:
+ if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
+ return -EFAULT;
+ return ax25_rt_opt(&rt_option);
+
+ default:
+ return -EINVAL;
+ }
}
int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
@@ -244,8 +286,8 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
off_t begin = 0;
char *callsign;
int i;
-
- cli();
+
+ read_lock(&ax25_route_lock);
len += sprintf(buffer, "callsign dev mode digipeaters\n");
@@ -259,15 +301,15 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
ax25_rt->dev ? ax25_rt->dev->name : "???");
switch (ax25_rt->ip_mode) {
- case 'V':
- len += sprintf(buffer + len, " vc");
- break;
- case 'D':
- len += sprintf(buffer + len, " dg");
- break;
- default:
- len += sprintf(buffer + len, " *");
- break;
+ case 'V':
+ len += sprintf(buffer + len, " vc");
+ break;
+ case 'D':
+ len += sprintf(buffer + len, " dg");
+ break;
+ default:
+ len += sprintf(buffer + len, " *");
+ break;
}
if (ax25_rt->digipeat != NULL)
@@ -286,26 +328,29 @@ int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length)
break;
}
-
- sti();
+ read_unlock(&ax25_route_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
- if (len > length) len = length;
+ if (len > length)
+ len = length;
return len;
-}
+}
/*
* Find AX.25 route
+ *
+ * Only routes with a refernce rout of zero can be destroyed.
*/
-static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
+static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
{
ax25_route *ax25_spe_rt = NULL;
ax25_route *ax25_def_rt = NULL;
ax25_route *ax25_rt;
+ read_lock(&ax25_route_lock);
/*
* Bind to the physical interface we heard them on, or the default
* route if none is found;
@@ -324,10 +369,16 @@ static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
}
}
+ ax25_rt = ax25_def_rt;
if (ax25_spe_rt != NULL)
- return ax25_spe_rt;
+ ax25_rt = ax25_spe_rt;
- return ax25_def_rt;
+ if (ax25_rt != NULL)
+ atomic_inc(&ax25_rt->ref);
+
+ read_unlock(&ax25_route_lock);
+
+ return ax25_rt;
}
/*
@@ -346,7 +397,7 @@ static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat)
digipeat->ndigi = k;
}
-
+
/*
* Find which interface to use.
@@ -355,24 +406,31 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
{
ax25_route *ax25_rt;
ax25_address *call;
+ int err;
- if ((ax25_rt = ax25_find_route(addr, NULL)) == NULL)
+ if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL)
return -EHOSTUNREACH;
- if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL)
- return -EHOSTUNREACH;
+ if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
+ err = -EHOSTUNREACH;
+ goto put;
+ }
if ((call = ax25_findbyuid(current->euid)) == NULL) {
- if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
- return -EPERM;
+ if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
+ err = -EPERM;
+ goto put;
+ }
call = (ax25_address *)ax25->ax25_dev->dev->dev_addr;
}
ax25->source_addr = *call;
if (ax25_rt->digipeat != NULL) {
- if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
+ if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
+ err = -ENOMEM;
+ goto put;
+ }
memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi));
ax25_adjust_path(addr, ax25->digipeat);
}
@@ -380,31 +438,32 @@ int ax25_rt_autobind(ax25_cb *ax25, ax25_address *addr)
if (ax25->sk != NULL)
ax25->sk->zapped = 0;
+put:
+ ax25_put_route(ax25_rt);
+
return 0;
}
-/*
- * dl1bke 960117: build digipeater path
- * dl1bke 960301: use the default route if it exists
- */
-ax25_route *ax25_rt_find_route(ax25_address *addr, struct net_device *dev)
+ax25_route *ax25_rt_find_route(ax25_route * route, ax25_address *addr,
+ struct net_device *dev)
{
- static ax25_route route;
ax25_route *ax25_rt;
- if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) {
- route.next = NULL;
- route.callsign = *addr;
- route.dev = dev;
- route.digipeat = NULL;
- route.ip_mode = ' ';
- return &route;
- }
+ if ((ax25_rt = ax25_get_route(addr, dev)))
+ return ax25_rt;
- return ax25_rt;
+ route->next = NULL;
+ atomic_set(&route->ref, 1);
+ route->callsign = *addr;
+ route->dev = dev;
+ route->digipeat = NULL;
+ route->ip_mode = ' ';
+
+ return route;
}
-struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_address *dest, ax25_digi *digi)
+struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
+ ax25_address *dest, ax25_digi *digi)
{
struct sk_buff *skbn;
unsigned char *bp;
@@ -440,6 +499,7 @@ void __exit ax25_rt_free(void)
{
ax25_route *s, *ax25_rt = ax25_route_list;
+ write_unlock(&ax25_route_lock);
while (ax25_rt != NULL) {
s = ax25_rt;
ax25_rt = ax25_rt->next;
@@ -449,4 +509,5 @@ void __exit ax25_rt_free(void)
kfree(s);
}
+ write_unlock(&ax25_route_lock);
}
diff --git a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c
index b68155f38a45..70470dc75ab0 100644
--- a/net/ax25/ax25_std_in.c
+++ b/net/ax25/ax25_std_in.c
@@ -1,42 +1,19 @@
/*
- * 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:
- * 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 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.
+ * 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.
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -68,55 +45,55 @@
static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
switch (frametype) {
- case AX25_SABM:
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- break;
-
- case AX25_SABME:
- ax25->modulus = AX25_EMODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- break;
-
- case AX25_DISC:
- ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
- break;
-
- case AX25_UA:
- if (pf) {
- ax25_calculate_rtt(ax25);
- ax25_stop_t1timer(ax25);
- ax25_start_t3timer(ax25);
- ax25_start_idletimer(ax25);
- ax25->vs = 0;
- ax25->va = 0;
- ax25->vr = 0;
- ax25->state = AX25_STATE_3;
- ax25->n2count = 0;
- if (ax25->sk != NULL) {
- ax25->sk->state = TCP_ESTABLISHED;
- /* For WAIT_SABM connections we will produce an accept ready socket here */
- if (!ax25->sk->dead)
- ax25->sk->state_change(ax25->sk);
- }
+ case AX25_SABM:
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ break;
+
+ case AX25_SABME:
+ ax25->modulus = AX25_EMODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ break;
+
+ case AX25_DISC:
+ ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
+ break;
+
+ case AX25_UA:
+ if (pf) {
+ ax25_calculate_rtt(ax25);
+ ax25_stop_t1timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
+ ax25->vs = 0;
+ ax25->va = 0;
+ ax25->vr = 0;
+ ax25->state = AX25_STATE_3;
+ ax25->n2count = 0;
+ if (ax25->sk != NULL) {
+ ax25->sk->state = TCP_ESTABLISHED;
+ /* For WAIT_SABM connections we will produce an accept ready socket here */
+ if (!ax25->sk->dead)
+ ax25->sk->state_change(ax25->sk);
}
- break;
+ }
+ break;
- case AX25_DM:
- if (pf) {
- if (ax25->modulus == AX25_MODULUS) {
- ax25_disconnect(ax25, ECONNREFUSED);
- } else {
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
- }
+ case AX25_DM:
+ if (pf) {
+ if (ax25->modulus == AX25_MODULUS) {
+ ax25_disconnect(ax25, ECONNREFUSED);
+ } else {
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
}
- break;
+ }
+ break;
- default:
- break;
+ default:
+ break;
}
return 0;
@@ -130,30 +107,31 @@ static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
{
switch (frametype) {
- case AX25_SABM:
- case AX25_SABME:
- ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
- break;
-
- case AX25_DISC:
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ case AX25_SABM:
+ case AX25_SABME:
+ ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
+ break;
+
+ case AX25_DISC:
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_disconnect(ax25, 0);
+ break;
+
+ case AX25_DM:
+ case AX25_UA:
+ if (pf)
ax25_disconnect(ax25, 0);
- break;
+ break;
- case AX25_DM:
- case AX25_UA:
- if (pf) ax25_disconnect(ax25, 0);
- break;
-
- case AX25_I:
- case AX25_REJ:
- case AX25_RNR:
- case AX25_RR:
- if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
- break;
+ case AX25_I:
+ case AX25_REJ:
+ case AX25_RNR:
+ case AX25_RR:
+ if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
+ break;
- default:
- break;
+ default:
+ break;
}
return 0;
@@ -169,116 +147,116 @@ static int ax25_std_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
int queued = 0;
switch (frametype) {
- case AX25_SABM:
- case AX25_SABME:
- if (frametype == AX25_SABM) {
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
- } else {
- ax25->modulus = AX25_EMODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
- }
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ case AX25_SABM:
+ case AX25_SABME:
+ if (frametype == AX25_SABM) {
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+ } else {
+ ax25->modulus = AX25_EMODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+ }
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_stop_t1timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
+ ax25->condition = 0x00;
+ ax25->vs = 0;
+ ax25->va = 0;
+ ax25->vr = 0;
+ ax25_requeue_frames(ax25);
+ break;
+
+ case AX25_DISC:
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_disconnect(ax25, 0);
+ break;
+
+ case AX25_DM:
+ ax25_disconnect(ax25, ECONNRESET);
+ break;
+
+ case AX25_RR:
+ case AX25_RNR:
+ if (frametype == AX25_RR)
+ ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+ else
+ ax25->condition |= AX25_COND_PEER_RX_BUSY;
+ if (type == AX25_COMMAND && pf)
+ ax25_std_enquiry_response(ax25);
+ if (ax25_validate_nr(ax25, nr)) {
+ ax25_check_iframes_acked(ax25, nr);
+ } else {
+ ax25_std_nr_error_recovery(ax25);
+ ax25->state = AX25_STATE_1;
+ }
+ break;
+
+ case AX25_REJ:
+ ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+ if (type == AX25_COMMAND && pf)
+ ax25_std_enquiry_response(ax25);
+ if (ax25_validate_nr(ax25, nr)) {
+ ax25_frames_acked(ax25, nr);
+ ax25_calculate_rtt(ax25);
ax25_stop_t1timer(ax25);
- ax25_stop_t2timer(ax25);
ax25_start_t3timer(ax25);
- ax25_start_idletimer(ax25);
- ax25->condition = 0x00;
- ax25->vs = 0;
- ax25->va = 0;
- ax25->vr = 0;
ax25_requeue_frames(ax25);
- break;
-
- case AX25_DISC:
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- ax25_disconnect(ax25, 0);
- break;
+ } else {
+ ax25_std_nr_error_recovery(ax25);
+ ax25->state = AX25_STATE_1;
+ }
+ break;
- case AX25_DM:
- ax25_disconnect(ax25, ECONNRESET);
+ case AX25_I:
+ if (!ax25_validate_nr(ax25, nr)) {
+ ax25_std_nr_error_recovery(ax25);
+ ax25->state = AX25_STATE_1;
break;
-
- case AX25_RR:
- case AX25_RNR:
- if (frametype == AX25_RR)
- ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
- else
- ax25->condition |= AX25_COND_PEER_RX_BUSY;
- if (type == AX25_COMMAND && pf)
- ax25_std_enquiry_response(ax25);
- if (ax25_validate_nr(ax25, nr)) {
- ax25_check_iframes_acked(ax25, nr);
- } else {
- ax25_std_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- }
+ }
+ if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
+ ax25_frames_acked(ax25, nr);
+ } else {
+ ax25_check_iframes_acked(ax25, nr);
+ }
+ if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+ if (pf) ax25_std_enquiry_response(ax25);
break;
-
- case AX25_REJ:
- ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
- if (type == AX25_COMMAND && pf)
+ }
+ if (ns == ax25->vr) {
+ ax25->vr = (ax25->vr + 1) % ax25->modulus;
+ queued = ax25_rx_iframe(ax25, skb);
+ if (ax25->condition & AX25_COND_OWN_RX_BUSY)
+ ax25->vr = ns; /* ax25->vr - 1 */
+ ax25->condition &= ~AX25_COND_REJECT;
+ if (pf) {
ax25_std_enquiry_response(ax25);
- if (ax25_validate_nr(ax25, nr)) {
- ax25_frames_acked(ax25, nr);
- ax25_calculate_rtt(ax25);
- ax25_stop_t1timer(ax25);
- ax25_start_t3timer(ax25);
- ax25_requeue_frames(ax25);
} else {
- ax25_std_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- }
- break;
-
- case AX25_I:
- if (!ax25_validate_nr(ax25, nr)) {
- ax25_std_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- break;
- }
- if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
- ax25_frames_acked(ax25, nr);
- } else {
- ax25_check_iframes_acked(ax25, nr);
+ if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
+ ax25->condition |= AX25_COND_ACK_PENDING;
+ ax25_start_t2timer(ax25);
+ }
}
- if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+ } else {
+ if (ax25->condition & AX25_COND_REJECT) {
if (pf) ax25_std_enquiry_response(ax25);
- break;
- }
- if (ns == ax25->vr) {
- ax25->vr = (ax25->vr + 1) % ax25->modulus;
- queued = ax25_rx_iframe(ax25, skb);
- if (ax25->condition & AX25_COND_OWN_RX_BUSY)
- ax25->vr = ns; /* ax25->vr - 1 */
- ax25->condition &= ~AX25_COND_REJECT;
- if (pf) {
- ax25_std_enquiry_response(ax25);
- } else {
- if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
- ax25->condition |= AX25_COND_ACK_PENDING;
- ax25_start_t2timer(ax25);
- }
- }
} else {
- if (ax25->condition & AX25_COND_REJECT) {
- if (pf) ax25_std_enquiry_response(ax25);
- } else {
- ax25->condition |= AX25_COND_REJECT;
- ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
- ax25->condition &= ~AX25_COND_ACK_PENDING;
- }
+ ax25->condition |= AX25_COND_REJECT;
+ ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
+ ax25->condition &= ~AX25_COND_ACK_PENDING;
}
- break;
+ }
+ break;
- case AX25_FRMR:
- case AX25_ILLEGAL:
- ax25_std_establish_data_link(ax25);
- ax25->state = AX25_STATE_1;
- break;
+ case AX25_FRMR:
+ case AX25_ILLEGAL:
+ ax25_std_establish_data_link(ax25);
+ ax25->state = AX25_STATE_1;
+ break;
- default:
- break;
+ default:
+ break;
}
return queued;
@@ -294,145 +272,146 @@ static int ax25_std_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frame
int queued = 0;
switch (frametype) {
- case AX25_SABM:
- case AX25_SABME:
- if (frametype == AX25_SABM) {
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
- } else {
- ax25->modulus = AX25_EMODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
- }
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ case AX25_SABM:
+ case AX25_SABME:
+ if (frametype == AX25_SABM) {
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+ } else {
+ ax25->modulus = AX25_EMODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+ }
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_stop_t1timer(ax25);
+ ax25_stop_t2timer(ax25);
+ ax25_start_t3timer(ax25);
+ ax25_start_idletimer(ax25);
+ ax25->condition = 0x00;
+ ax25->vs = 0;
+ ax25->va = 0;
+ ax25->vr = 0;
+ ax25->state = AX25_STATE_3;
+ ax25->n2count = 0;
+ ax25_requeue_frames(ax25);
+ break;
+
+ case AX25_DISC:
+ ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+ ax25_disconnect(ax25, 0);
+ break;
+
+ case AX25_DM:
+ ax25_disconnect(ax25, ECONNRESET);
+ break;
+
+ case AX25_RR:
+ case AX25_RNR:
+ if (frametype == AX25_RR)
+ ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+ else
+ ax25->condition |= AX25_COND_PEER_RX_BUSY;
+ if (type == AX25_RESPONSE && pf) {
ax25_stop_t1timer(ax25);
- ax25_stop_t2timer(ax25);
- ax25_start_t3timer(ax25);
- ax25_start_idletimer(ax25);
- ax25->condition = 0x00;
- ax25->vs = 0;
- ax25->va = 0;
- ax25->vr = 0;
- ax25->state = AX25_STATE_3;
- ax25->n2count = 0;
- ax25_requeue_frames(ax25);
- break;
-
- case AX25_DISC:
- ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
- ax25_disconnect(ax25, 0);
- break;
-
- case AX25_DM:
- ax25_disconnect(ax25, ECONNRESET);
- break;
-
- case AX25_RR:
- case AX25_RNR:
- if (frametype == AX25_RR)
- ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
- else
- ax25->condition |= AX25_COND_PEER_RX_BUSY;
- if (type == AX25_RESPONSE && pf) {
- ax25_stop_t1timer(ax25);
- ax25->n2count = 0;
- if (ax25_validate_nr(ax25, nr)) {
- ax25_frames_acked(ax25, nr);
- if (ax25->vs == ax25->va) {
- ax25_start_t3timer(ax25);
- ax25->state = AX25_STATE_3;
- } else {
- ax25_requeue_frames(ax25);
- }
- } else {
- ax25_std_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- }
- break;
- }
- if (type == AX25_COMMAND && pf)
- ax25_std_enquiry_response(ax25);
+ ax25->n2count = 0;
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
+ if (ax25->vs == ax25->va) {
+ ax25_start_t3timer(ax25);
+ ax25->state = AX25_STATE_3;
+ } else {
+ ax25_requeue_frames(ax25);
+ }
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
+ }
+ if (type == AX25_COMMAND && pf)
+ ax25_std_enquiry_response(ax25);
+ if (ax25_validate_nr(ax25, nr)) {
+ ax25_frames_acked(ax25, nr);
+ } else {
+ ax25_std_nr_error_recovery(ax25);
+ ax25->state = AX25_STATE_1;
+ }
+ break;
- case AX25_REJ:
- ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
- if (pf && type == AX25_RESPONSE) {
- ax25_stop_t1timer(ax25);
- ax25->n2count = 0;
- if (ax25_validate_nr(ax25, nr)) {
- ax25_frames_acked(ax25, nr);
- if (ax25->vs == ax25->va) {
- ax25_start_t3timer(ax25);
- ax25->state = AX25_STATE_3;
- } else {
- ax25_requeue_frames(ax25);
- }
- } else {
- ax25_std_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- }
- break;
- }
- if (type == AX25_COMMAND && pf)
- ax25_std_enquiry_response(ax25);
+ case AX25_REJ:
+ ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+ if (pf && type == AX25_RESPONSE) {
+ ax25_stop_t1timer(ax25);
+ ax25->n2count = 0;
if (ax25_validate_nr(ax25, nr)) {
ax25_frames_acked(ax25, nr);
- ax25_requeue_frames(ax25);
+ if (ax25->vs == ax25->va) {
+ ax25_start_t3timer(ax25);
+ ax25->state = AX25_STATE_3;
+ } else {
+ ax25_requeue_frames(ax25);
+ }
} else {
ax25_std_nr_error_recovery(ax25);
ax25->state = AX25_STATE_1;
}
break;
+ }
+ if (type == AX25_COMMAND && pf)
+ ax25_std_enquiry_response(ax25);
+ if (ax25_validate_nr(ax25, nr)) {
+ ax25_frames_acked(ax25, nr);
+ ax25_requeue_frames(ax25);
+ } else {
+ ax25_std_nr_error_recovery(ax25);
+ ax25->state = AX25_STATE_1;
+ }
+ break;
- case AX25_I:
- if (!ax25_validate_nr(ax25, nr)) {
- ax25_std_nr_error_recovery(ax25);
- ax25->state = AX25_STATE_1;
- break;
+ case AX25_I:
+ if (!ax25_validate_nr(ax25, nr)) {
+ ax25_std_nr_error_recovery(ax25);
+ ax25->state = AX25_STATE_1;
+ break;
+ }
+ ax25_frames_acked(ax25, nr);
+ if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+ if (pf)
+ ax25_std_enquiry_response(ax25);
+ break;
+ }
+ if (ns == ax25->vr) {
+ ax25->vr = (ax25->vr + 1) % ax25->modulus;
+ queued = ax25_rx_iframe(ax25, skb);
+ if (ax25->condition & AX25_COND_OWN_RX_BUSY)
+ ax25->vr = ns; /* ax25->vr - 1 */
+ ax25->condition &= ~AX25_COND_REJECT;
+ if (pf) {
+ ax25_std_enquiry_response(ax25);
+ } else {
+ if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
+ ax25->condition |= AX25_COND_ACK_PENDING;
+ ax25_start_t2timer(ax25);
+ }
}
- ax25_frames_acked(ax25, nr);
- if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+ } else {
+ if (ax25->condition & AX25_COND_REJECT) {
if (pf) ax25_std_enquiry_response(ax25);
- break;
- }
- if (ns == ax25->vr) {
- ax25->vr = (ax25->vr + 1) % ax25->modulus;
- queued = ax25_rx_iframe(ax25, skb);
- if (ax25->condition & AX25_COND_OWN_RX_BUSY)
- ax25->vr = ns; /* ax25->vr - 1 */
- ax25->condition &= ~AX25_COND_REJECT;
- if (pf) {
- ax25_std_enquiry_response(ax25);
- } else {
- if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
- ax25->condition |= AX25_COND_ACK_PENDING;
- ax25_start_t2timer(ax25);
- }
- }
} else {
- if (ax25->condition & AX25_COND_REJECT) {
- if (pf) ax25_std_enquiry_response(ax25);
- } else {
- ax25->condition |= AX25_COND_REJECT;
- ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
- ax25->condition &= ~AX25_COND_ACK_PENDING;
- }
+ ax25->condition |= AX25_COND_REJECT;
+ ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
+ ax25->condition &= ~AX25_COND_ACK_PENDING;
}
- break;
+ }
+ break;
- case AX25_FRMR:
- case AX25_ILLEGAL:
- ax25_std_establish_data_link(ax25);
- ax25->state = AX25_STATE_1;
- break;
+ case AX25_FRMR:
+ case AX25_ILLEGAL:
+ ax25_std_establish_data_link(ax25);
+ ax25->state = AX25_STATE_1;
+ break;
- default:
- break;
+ default:
+ break;
}
return queued;
@@ -448,18 +427,18 @@ int ax25_std_frame_in(ax25_cb *ax25, struct sk_buff *skb, int type)
frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
switch (ax25->state) {
- case AX25_STATE_1:
- queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type);
- break;
- case AX25_STATE_2:
- queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type);
- break;
- case AX25_STATE_3:
- queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
- break;
- case AX25_STATE_4:
- queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type);
- break;
+ case AX25_STATE_1:
+ queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type);
+ break;
+ case AX25_STATE_2:
+ queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type);
+ break;
+ case AX25_STATE_3:
+ queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
+ break;
+ case AX25_STATE_4:
+ queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type);
+ break;
}
ax25_kick(ax25);
diff --git a/net/ax25/ax25_std_subr.c b/net/ax25/ax25_std_subr.c
index c868e0507952..2b3c801ae486 100644
--- a/net/ax25/ax25_std_subr.c
+++ b/net/ax25/ax25_std_subr.c
@@ -1,25 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -80,7 +66,7 @@ void ax25_std_transmit_enquiry(ax25_cb *ax25)
ax25_calculate_t1(ax25);
ax25_start_t1timer(ax25);
}
-
+
void ax25_std_enquiry_response(ax25_cb *ax25)
{
if (ax25->condition & AX25_COND_OWN_RX_BUSY)
diff --git a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c
index 741e08d231cc..957f5e5fec81 100644
--- a/net/ax25/ax25_std_timer.c
+++ b/net/ax25/ax25_std_timer.c
@@ -1,27 +1,14 @@
/*
- * 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
- *
- * 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 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.
+ * 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) Frederic Rible F1OAT (frible@teaser.fr)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -47,30 +34,29 @@
void ax25_std_heartbeat_expiry(ax25_cb *ax25)
{
switch (ax25->state) {
-
- case AX25_STATE_0:
- /* Magic here: If we listen() and a new link dies before it
- is accepted() it isn't 'dead' so doesn't get removed. */
- if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
- ax25_destroy_socket(ax25);
- return;
- }
- break;
-
- case AX25_STATE_3:
- case AX25_STATE_4:
- /*
- * Check the state of the receive buffer.
- */
- if (ax25->sk != NULL) {
- if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
- (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
- ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
- ax25->condition &= ~AX25_COND_ACK_PENDING;
- ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
- break;
- }
+ case AX25_STATE_0:
+ /* Magic here: If we listen() and a new link dies before it
+ is accepted() it isn't 'dead' so doesn't get removed. */
+ if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
+ ax25_destroy_socket(ax25);
+ return;
+ }
+ break;
+
+ case AX25_STATE_3:
+ case AX25_STATE_4:
+ /*
+ * Check the state of the receive buffer.
+ */
+ if (ax25->sk != NULL) {
+ if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
+ (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
+ ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
+ ax25->condition &= ~AX25_COND_ACK_PENDING;
+ ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
+ break;
}
+ }
}
ax25_start_heartbeat(ax25);
@@ -117,53 +103,53 @@ void ax25_std_idletimer_expiry(ax25_cb *ax25)
void ax25_std_t1timer_expiry(ax25_cb *ax25)
{
switch (ax25->state) {
- case AX25_STATE_1:
- if (ax25->n2count == ax25->n2) {
- if (ax25->modulus == AX25_MODULUS) {
- ax25_disconnect(ax25, ETIMEDOUT);
- return;
- } else {
- ax25->modulus = AX25_MODULUS;
- ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
- ax25->n2count = 0;
- ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
- }
- } else {
- ax25->n2count++;
- if (ax25->modulus == AX25_MODULUS)
- ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
- else
- ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
- }
- break;
-
- case AX25_STATE_2:
- if (ax25->n2count == ax25->n2) {
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ case AX25_STATE_1:
+ if (ax25->n2count == ax25->n2) {
+ if (ax25->modulus == AX25_MODULUS) {
ax25_disconnect(ax25, ETIMEDOUT);
return;
} else {
- ax25->n2count++;
- ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ ax25->modulus = AX25_MODULUS;
+ ax25->window = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+ ax25->n2count = 0;
+ ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
}
- break;
-
- case AX25_STATE_3:
- ax25->n2count = 1;
+ } else {
+ ax25->n2count++;
+ if (ax25->modulus == AX25_MODULUS)
+ ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
+ else
+ ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
+ }
+ break;
+
+ case AX25_STATE_2:
+ if (ax25->n2count == ax25->n2) {
+ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
+ } else {
+ ax25->n2count++;
+ ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+ }
+ break;
+
+ case AX25_STATE_3:
+ ax25->n2count = 1;
+ ax25_std_transmit_enquiry(ax25);
+ ax25->state = AX25_STATE_4;
+ break;
+
+ case AX25_STATE_4:
+ if (ax25->n2count == ax25->n2) {
+ ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
+ ax25_disconnect(ax25, ETIMEDOUT);
+ return;
+ } else {
+ ax25->n2count++;
ax25_std_transmit_enquiry(ax25);
- ax25->state = AX25_STATE_4;
- break;
-
- case AX25_STATE_4:
- if (ax25->n2count == ax25->n2) {
- ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
- ax25_disconnect(ax25, ETIMEDOUT);
- return;
- } else {
- ax25->n2count++;
- ax25_std_transmit_enquiry(ax25);
- }
- break;
+ }
+ break;
}
ax25_calculate_t1(ax25);
diff --git a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
index c49892720fab..54db70c15b4a 100644
--- a/net/ax25/ax25_subr.c
+++ b/net/ax25/ax25_subr.c
@@ -1,38 +1,14 @@
/*
- * 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
- *
- * 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 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.
+ * 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) Frederic Rible F1OAT (frible@teaser.fr)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -172,9 +148,9 @@ int ax25_decode(ax25_cb *ax25, struct sk_buff *skb, int *ns, int *nr, int *pf)
return frametype;
}
-/*
+/*
* This routine is called when the HDLC layer internally generates a
- * command or response for the remote machine ( eg. RR, UA etc. ).
+ * command or response for the remote machine ( eg. RR, UA etc. ).
* Only supervisory or unnumbered frames are processed.
*/
void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type)
@@ -231,7 +207,7 @@ void ax25_return_dm(struct net_device *dev, ax25_address *src, ax25_address *des
skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi));
skb->nh.raw = skb->data;
-
+
ax25_digi_invert(digi, &retdigi);
dptr = skb_put(skb, 1);
@@ -257,18 +233,18 @@ void ax25_calculate_t1(ax25_cb *ax25)
int n, t = 2;
switch (ax25->backoff) {
- case 0:
- break;
-
- case 1:
- t += 2 * ax25->n2count;
- break;
-
- case 2:
- for (n = 0; n < ax25->n2count; n++)
- t *= 2;
- if (t > 8) t = 8;
- break;
+ case 0:
+ break;
+
+ case 1:
+ t += 2 * ax25->n2count;
+ break;
+
+ case 2:
+ for (n = 0; n < ax25->n2count; n++)
+ t *= 2;
+ if (t > 8) t = 8;
+ break;
}
ax25->t1 = t * ax25->rtt;
diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c
index 8ea87b01df41..7ef07596932f 100644
--- a/net/ax25/ax25_timer.c
+++ b/net/ax25/ax25_timer.c
@@ -1,30 +1,17 @@
/*
- * 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
- *
- * 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 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).
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
+ * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
+ * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
*/
-
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -152,105 +139,121 @@ unsigned long ax25_display_timer(struct timer_list *timer)
static void ax25_heartbeat_expiry(unsigned long param)
{
- ax25_cb *ax25 = (ax25_cb *)param;
int proto = AX25_PROTO_STD_SIMPLEX;
+ ax25_cb *ax25 = (ax25_cb *)param;
+ struct sock *sk = ax25->sk;
if (ax25->ax25_dev)
proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL];
+ bh_lock_sock(sk);
+
switch (proto) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_std_heartbeat_expiry(ax25);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_heartbeat_expiry(ax25);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- if (ax25->ax25_dev->dama.slave)
- ax25_ds_heartbeat_expiry(ax25);
- else
- ax25_std_heartbeat_expiry(ax25);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ if (ax25->ax25_dev->dama.slave)
+ ax25_ds_heartbeat_expiry(ax25);
+ else
+ ax25_std_heartbeat_expiry(ax25);
+ break;
#endif
}
+ bh_unlock_sock(sk);
}
static void ax25_t1timer_expiry(unsigned long param)
{
ax25_cb *ax25 = (ax25_cb *)param;
+ struct sock *sk = ax25->sk;
+ bh_lock_sock(sk);
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_std_t1timer_expiry(ax25);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_t1timer_expiry(ax25);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- if (!ax25->ax25_dev->dama.slave)
- ax25_std_t1timer_expiry(ax25);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ if (!ax25->ax25_dev->dama.slave)
+ ax25_std_t1timer_expiry(ax25);
+ break;
#endif
}
+ bh_unlock_sock(sk);
}
static void ax25_t2timer_expiry(unsigned long param)
{
ax25_cb *ax25 = (ax25_cb *)param;
+ struct sock *sk = ax25->sk;
+ bh_lock_sock(sk);
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_std_t2timer_expiry(ax25);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_t2timer_expiry(ax25);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- if (!ax25->ax25_dev->dama.slave)
- ax25_std_t2timer_expiry(ax25);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ if (!ax25->ax25_dev->dama.slave)
+ ax25_std_t2timer_expiry(ax25);
+ break;
#endif
}
+ bh_unlock_sock(sk);
}
static void ax25_t3timer_expiry(unsigned long param)
{
ax25_cb *ax25 = (ax25_cb *)param;
+ struct sock *sk = ax25->sk;
+ bh_lock_sock(sk);
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_std_t3timer_expiry(ax25);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_t3timer_expiry(ax25);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- if (ax25->ax25_dev->dama.slave)
- ax25_ds_t3timer_expiry(ax25);
- else
- ax25_std_t3timer_expiry(ax25);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ if (ax25->ax25_dev->dama.slave)
+ ax25_ds_t3timer_expiry(ax25);
+ else
+ ax25_std_t3timer_expiry(ax25);
+ break;
#endif
}
+ bh_unlock_sock(sk);
}
static void ax25_idletimer_expiry(unsigned long param)
{
ax25_cb *ax25 = (ax25_cb *)param;
+ struct sock *sk = ax25->sk;
+ bh_lock_sock(sk);
switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
- case AX25_PROTO_STD_SIMPLEX:
- case AX25_PROTO_STD_DUPLEX:
- ax25_std_idletimer_expiry(ax25);
- break;
+ case AX25_PROTO_STD_SIMPLEX:
+ case AX25_PROTO_STD_DUPLEX:
+ ax25_std_idletimer_expiry(ax25);
+ break;
#ifdef CONFIG_AX25_DAMA_SLAVE
- case AX25_PROTO_DAMA_SLAVE:
- if (ax25->ax25_dev->dama.slave)
- ax25_ds_idletimer_expiry(ax25);
- else
- ax25_std_idletimer_expiry(ax25);
- break;
+ case AX25_PROTO_DAMA_SLAVE:
+ if (ax25->ax25_dev->dama.slave)
+ ax25_ds_idletimer_expiry(ax25);
+ else
+ ax25_std_idletimer_expiry(ax25);
+ break;
#endif
}
+ bh_unlock_sock(sk);
}
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
index 603d8b8cc864..c5b473dc711b 100644
--- a/net/ax25/ax25_uid.c
+++ b/net/ax25/ax25_uid.c
@@ -1,18 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -23,6 +16,7 @@
#include <linux/string.h>
#include <linux/sockios.h>
#include <linux/net.h>
+#include <linux/spinlock.h>
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
@@ -47,17 +41,23 @@
*/
static ax25_uid_assoc *ax25_uid_list;
+static rwlock_t ax25_uid_lock = RW_LOCK_UNLOCKED;
int ax25_uid_policy = 0;
ax25_address *ax25_findbyuid(uid_t uid)
{
ax25_uid_assoc *ax25_uid;
+ ax25_address *res = NULL;
+ read_lock(&ax25_uid_lock);
for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
- if (ax25_uid->uid == uid)
- return &ax25_uid->call;
+ if (ax25_uid->uid == uid) {
+ res = &ax25_uid->call;
+ break;
+ }
}
+ read_unlock(&ax25_uid_lock);
return NULL;
}
@@ -65,63 +65,77 @@ ax25_address *ax25_findbyuid(uid_t uid)
int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
{
ax25_uid_assoc *s, *ax25_uid;
- unsigned long flags;
+ unsigned long res;
switch (cmd) {
- case SIOCAX25GETUID:
- for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
- if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
- return ax25_uid->uid;
+ case SIOCAX25GETUID:
+ res = -ENOENT;
+ read_lock(&ax25_uid_lock);
+ for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
+ if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
+ res = ax25_uid->uid;
+ break;
}
- return -ENOENT;
+ }
+ read_unlock(&ax25_uid_lock);
- case SIOCAX25ADDUID:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (ax25_findbyuid(sax->sax25_uid))
- return -EEXIST;
- if (sax->sax25_uid == 0)
- return -EINVAL;
- if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- ax25_uid->uid = sax->sax25_uid;
- ax25_uid->call = sax->sax25_call;
- save_flags(flags); cli();
- ax25_uid->next = ax25_uid_list;
- ax25_uid_list = ax25_uid;
- restore_flags(flags);
- return 0;
+ return res;
+
+ case SIOCAX25ADDUID:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (ax25_findbyuid(sax->sax25_uid))
+ return -EEXIST;
+ if (sax->sax25_uid == 0)
+ return -EINVAL;
+ if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
+ return -ENOMEM;
+
+ ax25_uid->uid = sax->sax25_uid;
+ ax25_uid->call = sax->sax25_call;
+
+ write_lock(&ax25_uid_lock);
+ ax25_uid->next = ax25_uid_list;
+ ax25_uid_list = ax25_uid;
+ write_unlock(&ax25_uid_lock);
+
+ return 0;
+
+ case SIOCAX25DELUID:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
- case SIOCAX25DELUID:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
- if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
- break;
+ write_lock(&ax25_uid_lock);
+ for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
+ if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
+ break;
}
- if (ax25_uid == NULL)
- return -ENOENT;
- save_flags(flags); cli();
- if ((s = ax25_uid_list) == ax25_uid) {
- ax25_uid_list = s->next;
- restore_flags(flags);
+ }
+ if (ax25_uid == NULL) {
+ write_unlock(&ax25_uid_lock);
+ return -ENOENT;
+ }
+ if ((s = ax25_uid_list) == ax25_uid) {
+ ax25_uid_list = s->next;
+ write_unlock(&ax25_uid_lock);
+ kfree(ax25_uid);
+ return 0;
+ }
+ while (s != NULL && s->next != NULL) {
+ if (s->next == ax25_uid) {
+ s->next = ax25_uid->next;
+ write_unlock(&ax25_uid_lock);
kfree(ax25_uid);
return 0;
}
- while (s != NULL && s->next != NULL) {
- if (s->next == ax25_uid) {
- s->next = ax25_uid->next;
- restore_flags(flags);
- kfree(ax25_uid);
- return 0;
- }
- s = s->next;
- }
- restore_flags(flags);
- return -ENOENT;
+ s = s->next;
+ }
+ write_unlock(&ax25_uid_lock);
- default:
- return -EINVAL;
+ return -ENOENT;
+
+ default:
+ return -EINVAL;
}
return -EINVAL; /*NOTREACHED */
@@ -134,8 +148,7 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
off_t begin = 0;
- cli();
-
+ read_lock(&ax25_uid_lock);
len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy);
for (pt = ax25_uid_list; pt != NULL; pt = pt->next) {
@@ -151,13 +164,13 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length)
break;
}
-
- sti();
+ read_unlock(&ax25_uid_lock);
*start = buffer + (offset - begin);
len -= offset - begin;
- if (len > length) len = length;
+ if (len > length)
+ len = length;
return len;
}
@@ -167,12 +180,16 @@ int ax25_uid_get_info(char *buffer, char **start, off_t offset, int length)
*/
void __exit ax25_uid_free(void)
{
- ax25_uid_assoc *s, *ax25_uid = ax25_uid_list;
+ ax25_uid_assoc *s, *ax25_uid;
+ write_lock(&ax25_uid_lock);
+ ax25_uid = ax25_uid_list;
while (ax25_uid != NULL) {
s = ax25_uid;
ax25_uid = ax25_uid->next;
kfree(s);
}
+ ax25_uid_list = NULL;
+ write_unlock(&ax25_uid_lock);
}
diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
index e6016f93de43..09641dc6580a 100644
--- a/net/ax25/sysctl_net_ax25.c
+++ b/net/ax25/sysctl_net_ax25.c
@@ -1,13 +1,15 @@
-/* -*- 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.
- * Added /proc/sys/net/ax25 directory entry (empty =) ). [MS]
+ * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
*/
-
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/sysctl.h>
+#include <linux/spinlock.h>
#include <net/ax25.h>
static int min_ipdefmode[] = {0}, max_ipdefmode[] = {1};
@@ -105,6 +107,7 @@ void ax25_register_sysctl(void)
ax25_dev *ax25_dev;
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)
ax25_table_size += sizeof(ctl_table);
@@ -119,6 +122,7 @@ void ax25_register_sysctl(void)
while (n--)
kfree(ax25_table[n].child);
kfree(ax25_table);
+ spin_unlock_bh(&ax25_dev_lock);
return;
}
memcpy(child, ax25_param_table, sizeof(ax25_param_table));
@@ -128,7 +132,7 @@ void ax25_register_sysctl(void)
ax25_table[n].mode = 0555;
#ifndef CONFIG_AX25_DAMA_SLAVE
- /*
+ /*
* We do not wish to have a representation of this parameter
* in /proc/sys/ when configured *not* to include the
* AX.25 DAMA slave code, do we?
@@ -144,6 +148,7 @@ void ax25_register_sysctl(void)
n++;
}
+ spin_unlock_bh(&ax25_dev_lock);
ax25_dir_table[0].child = ax25_table;
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index f1dddc7be67b..055053e507fb 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -1,38 +1,13 @@
/*
- * 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
- *
- * 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 the AX25 code.
- * NET/ROM 002 Darryl(G7LED) Fixes and address enhancement.
- * Jonathan(G4KLX) Complete bind re-think.
- * Alan(GW4PTS) Trivial tweaks into new format.
- * NET/ROM 003 Jonathan(G4KLX) Added G8BPQ extensions.
- * Added NET/ROM routing ioctl.
- * Darryl(G7LED) Fix autobinding (on connect).
- * Fixed nr_release(), set TCP_CLOSE, wakeup app
- * context, THEN make the sock dead.
- * Circuit ID check before allocating it on
- * a connection.
- * Alan(GW4PTS) sendmsg/recvmsg only. Fixed connect clear bug
- * inherited from AX.25
- * NET/ROM 004 Jonathan(G4KLX) Converted to module.
- * NET/ROM 005 Jonathan(G4KLX) Linux 2.1
- * Alan(GW4PTS) Started POSIXisms
- * NET/ROM 006 Alan(GW4PTS) Brought in line with the ANK changes
- * Jonathan(G4KLX) Removed hdrincl.
- * NET/ROM 007 Jonathan(G4KLX) New timer architecture.
- * Implemented Idle timer.
- * Arnaldo C. Melo s/suser/capable/, micro cleanups
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
*/
-
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -82,7 +57,8 @@ int sysctl_netrom_link_fails_count = NR_DEFAULT_FAILS;
static unsigned short circuit = 0x101;
-static struct sock *volatile nr_list;
+static struct sock *nr_list;
+static spinlock_t nr_list_lock;
static struct proto_ops nr_proto_ops;
@@ -123,27 +99,26 @@ decmod: MOD_DEC_USE_COUNT;
static void nr_remove_socket(struct sock *sk)
{
struct sock *s;
- unsigned long flags;
- save_flags(flags); cli();
+ spin_lock_bh(&nr_list_lock);
if ((s = nr_list) == sk) {
nr_list = s->next;
- restore_flags(flags);
+ spin_unlock_bh(&nr_list_lock);
return;
}
while (s != NULL && s->next != NULL) {
if (s->next == sk) {
s->next = sk->next;
- restore_flags(flags);
+ spin_unlock_bh(&nr_list_lock);
return;
}
s = s->next;
}
- restore_flags(flags);
+ spin_unlock_bh(&nr_list_lock);
}
/*
@@ -153,10 +128,12 @@ static void nr_kill_by_device(struct net_device *dev)
{
struct sock *s;
+ spin_lock_bh(&nr_list_lock);
for (s = nr_list; s != NULL; s = s->next) {
if (nr_sk(s)->device == dev)
nr_disconnect(s, ENETUNREACH);
}
+ spin_unlock_bh(&nr_list_lock);
}
/*
@@ -180,14 +157,10 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi
*/
static void nr_insert_socket(struct sock *sk)
{
- unsigned long flags;
-
- save_flags(flags); cli();
-
+ spin_lock_bh(&nr_list_lock);
sk->next = nr_list;
nr_list = sk;
-
- restore_flags(flags);
+ spin_unlock_bh(&nr_list_lock);
}
/*
@@ -196,21 +169,18 @@ static void nr_insert_socket(struct sock *sk)
*/
static struct sock *nr_find_listener(ax25_address *addr)
{
- unsigned long flags;
struct sock *s;
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&nr_list_lock);
for (s = nr_list; s != NULL; s = s->next) {
if (!ax25cmp(&nr_sk(s)->source_addr, addr) &&
s->state == TCP_LISTEN) {
- restore_flags(flags);
+ spin_unlock_bh(&nr_list_lock);
return s;
}
}
+ spin_unlock_bh(&nr_list_lock);
- restore_flags(flags);
return NULL;
}
@@ -220,21 +190,17 @@ static struct sock *nr_find_listener(ax25_address *addr)
static struct sock *nr_find_socket(unsigned char index, unsigned char id)
{
struct sock *s;
- unsigned long flags;
-
- save_flags(flags);
- cli();
+ spin_lock_bh(&nr_list_lock);
for (s = nr_list; s != NULL; s = s->next) {
nr_cb *nr = nr_sk(s);
if (nr->my_index == index && nr->my_id == id) {
- restore_flags(flags);
+ spin_unlock_bh(&nr_list_lock);
return s;
}
}
-
- restore_flags(flags);
+ spin_unlock_bh(&nr_list_lock);
return NULL;
}
@@ -242,25 +208,22 @@ static struct sock *nr_find_socket(unsigned char index, unsigned char id)
/*
* Find a connected NET/ROM socket given their circuit IDs.
*/
-static struct sock *nr_find_peer(unsigned char index, unsigned char id, ax25_address *dest)
+static struct sock *nr_find_peer(unsigned char index, unsigned char id,
+ ax25_address *dest)
{
struct sock *s;
- unsigned long flags;
-
- save_flags(flags);
- cli();
+ spin_lock_bh(&nr_list_lock);
for (s = nr_list; s != NULL; s = s->next) {
nr_cb *nr = nr_sk(s);
if (nr->your_index == index && nr->your_id == id &&
!ax25cmp(&nr->dest_addr, dest)) {
- restore_flags(flags);
+ spin_unlock_bh(&nr_list_lock);
return s;
}
}
-
- restore_flags(flags);
+ spin_unlock_bh(&nr_list_lock);
return NULL;
}
@@ -301,17 +264,16 @@ static void nr_destroy_timer(unsigned long data)
}
/*
- * This is called from user mode and the timers. Thus it protects itself against
- * interrupt users but doesn't worry about being called during work.
- * Once it is removed from the queue no interrupt or bottom half will
- * touch it and we are (fairly 8-) ) safe.
+ * This is called from user mode and the timers. Thus it protects itself
+ * against interrupt users but doesn't worry about being called during
+ * work. Once it is removed from the queue no interrupt or bottom half
+ * will touch it and we are (fairly 8-) ) safe.
*/
-void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */
+void nr_destroy_socket(struct sock *sk)
{
struct sk_buff *skb;
- unsigned long flags;
- save_flags(flags); cli();
+ nr_remove_socket(sk);
nr_stop_heartbeat(sk);
nr_stop_t1timer(sk);
@@ -319,7 +281,6 @@ void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
nr_stop_t4timer(sk);
nr_stop_idletimer(sk);
- nr_remove_socket(sk);
nr_clear_queues(sk); /* Flush the queues */
while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
@@ -342,8 +303,6 @@ void nr_destroy_socket(struct sock *sk) /* Not static as it's used by the timer
} else {
nr_free_sock(sk);
}
-
- restore_flags(flags);
}
/*
@@ -368,38 +327,38 @@ static int nr_setsockopt(struct socket *sock, int level, int optname,
return -EFAULT;
switch (optname) {
- case NETROM_T1:
- if (opt < 1)
- return -EINVAL;
- nr->t1 = opt * HZ;
- return 0;
-
- case NETROM_T2:
- if (opt < 1)
- return -EINVAL;
- nr->t2 = opt * HZ;
- return 0;
-
- case NETROM_N2:
- if (opt < 1 || opt > 31)
- return -EINVAL;
- nr->n2 = opt;
- return 0;
-
- case NETROM_T4:
- if (opt < 1)
- return -EINVAL;
- nr->t4 = opt * HZ;
- return 0;
-
- case NETROM_IDLE:
- if (opt < 0)
- return -EINVAL;
- nr->idle = opt * 60 * HZ;
- return 0;
-
- default:
- return -ENOPROTOOPT;
+ case NETROM_T1:
+ if (opt < 1)
+ return -EINVAL;
+ nr->t1 = opt * HZ;
+ return 0;
+
+ case NETROM_T2:
+ if (opt < 1)
+ return -EINVAL;
+ nr->t2 = opt * HZ;
+ return 0;
+
+ case NETROM_N2:
+ if (opt < 1 || opt > 31)
+ return -EINVAL;
+ nr->n2 = opt;
+ return 0;
+
+ case NETROM_T4:
+ if (opt < 1)
+ return -EINVAL;
+ nr->t4 = opt * HZ;
+ return 0;
+
+ case NETROM_IDLE:
+ if (opt < 0)
+ return -EINVAL;
+ nr->idle = opt * 60 * HZ;
+ return 0;
+
+ default:
+ return -ENOPROTOOPT;
}
}
@@ -421,28 +380,28 @@ static int nr_getsockopt(struct socket *sock, int level, int optname,
return -EINVAL;
switch (optname) {
- case NETROM_T1:
- val = nr->t1 / HZ;
- break;
+ case NETROM_T1:
+ val = nr->t1 / HZ;
+ break;
- case NETROM_T2:
- val = nr->t2 / HZ;
- break;
+ case NETROM_T2:
+ val = nr->t2 / HZ;
+ break;
- case NETROM_N2:
- val = nr->n2;
- break;
+ case NETROM_N2:
+ val = nr->n2;
+ break;
- case NETROM_T4:
- val = nr->t4 / HZ;
- break;
+ case NETROM_T4:
+ val = nr->t4 / HZ;
+ break;
- case NETROM_IDLE:
- val = nr->idle / (60 * HZ);
- break;
+ case NETROM_IDLE:
+ val = nr->idle / (60 * HZ);
+ break;
- default:
- return -ENOPROTOOPT;
+ default:
+ return -ENOPROTOOPT;
}
len = min_t(unsigned int, len, sizeof(int));
@@ -567,34 +526,33 @@ static int nr_release(struct socket *sock)
nr = nr_sk(sk);
switch (nr->state) {
-
- case NR_STATE_0:
- case NR_STATE_1:
- case NR_STATE_2:
- nr_disconnect(sk, 0);
- nr_destroy_socket(sk);
- break;
-
- case NR_STATE_3:
- nr_clear_queues(sk);
- nr->n2count = 0;
- nr_write_internal(sk, NR_DISCREQ);
- nr_start_t1timer(sk);
- nr_stop_t2timer(sk);
- nr_stop_t4timer(sk);
- nr_stop_idletimer(sk);
- nr->state = NR_STATE_2;
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
- sk->destroy = 1;
- sk->socket = NULL;
- break;
-
- default:
- sk->socket = NULL;
- break;
+ case NR_STATE_0:
+ case NR_STATE_1:
+ case NR_STATE_2:
+ nr_disconnect(sk, 0);
+ nr_destroy_socket(sk);
+ break;
+
+ case NR_STATE_3:
+ nr_clear_queues(sk);
+ nr->n2count = 0;
+ nr_write_internal(sk, NR_DISCREQ);
+ nr_start_t1timer(sk);
+ nr_stop_t2timer(sk);
+ nr_stop_t4timer(sk);
+ nr_stop_idletimer(sk);
+ nr->state = NR_STATE_2;
+ sk->state = TCP_CLOSE;
+ sk->shutdown |= SEND_SHUTDOWN;
+ sk->state_change(sk);
+ sk->dead = 1;
+ sk->destroy = 1;
+ sk->socket = NULL;
+ break;
+
+ default:
+ sk->socket = NULL;
+ break;
}
sock->sk = NULL;
@@ -732,78 +690,98 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
return -EINPROGRESS;
- cli(); /* To avoid races on the sleep */
-
/*
- * A Connect Ack with Choke or timeout or failed routing will go to closed.
+ * A Connect Ack with Choke or timeout or failed routing will go to
+ * closed.
*/
- while (sk->state == TCP_SYN_SENT) {
- interruptible_sleep_on(sk->sleep);
- if (signal_pending(current)) {
- sti();
+ if (sk->state == TCP_SYN_SENT) {
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (sk->state != TCP_SYN_SENT)
+ break;
+ if (!signal_pending(tsk)) {
+ schedule();
+ continue;
+ }
return -ERESTARTSYS;
}
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
}
if (sk->state != TCP_ESTABLISHED) {
- sti();
sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */
}
sock->state = SS_CONNECTED;
- sti();
-
return 0;
}
static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
{
- struct sock *sk;
- struct sock *newsk;
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
struct sk_buff *skb;
+ struct sock *newsk;
+ struct sock *sk;
+ int err = 0;
if ((sk = sock->sk) == NULL)
return -EINVAL;
- if (sk->type != SOCK_SEQPACKET)
- return -EOPNOTSUPP;
+ lock_sock(sk);
+ if (sk->type != SOCK_SEQPACKET) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
- if (sk->state != TCP_LISTEN)
- return -EINVAL;
+ if (sk->state != TCP_LISTEN) {
+ err = -EINVAL;
+ goto out;
+ }
/*
* The write queue this time is holding sockets ready to use
* hooked into the SABM we saved
*/
- do {
- cli();
- if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
- if (flags & O_NONBLOCK) {
- sti();
- return -EWOULDBLOCK;
- }
- interruptible_sleep_on(sk->sleep);
- if (signal_pending(current)) {
- sti();
- return -ERESTARTSYS;
- }
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ skb = skb_dequeue(&sk->receive_queue);
+ if (skb)
+ break;
+
+ current->state = TASK_INTERRUPTIBLE;
+ release_sock(sk);
+ if (flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ if (!signal_pending(tsk)) {
+ schedule();
+ lock_sock(sk);
+ continue;
}
- } while (skb == NULL);
+ return -ERESTARTSYS;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
newsk = skb->sk;
newsk->pair = NULL;
newsk->socket = newsock;
newsk->sleep = &newsock->wait;
- sti();
/* Now attach up the new socket */
kfree_skb(skb);
sk->ack_backlog--;
newsock->sk = newsk;
- return 0;
+out:
+ return err;
}
static int nr_getname(struct socket *sock, struct sockaddr *uaddr,
@@ -1127,54 +1105,53 @@ static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
struct sock *sk = sock->sk;
switch (cmd) {
- case TIOCOUTQ: {
- long amount;
- amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
- if (amount < 0)
- amount = 0;
- return put_user(amount, (int *)arg);
- }
+ case TIOCOUTQ: {
+ long amount;
+ amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
+ if (amount < 0)
+ amount = 0;
+ return put_user(amount, (int *)arg);
+ }
- case TIOCINQ: {
- struct sk_buff *skb;
- long amount = 0L;
- /* These two are safe on a single CPU system as only user tasks fiddle here */
- if ((skb = skb_peek(&sk->receive_queue)) != NULL)
- amount = skb->len;
- return put_user(amount, (int *)arg);
- }
+ case TIOCINQ: {
+ struct sk_buff *skb;
+ long amount = 0L;
+ /* These two are safe on a single CPU system as only user tasks fiddle here */
+ if ((skb = skb_peek(&sk->receive_queue)) != NULL)
+ amount = skb->len;
+ return put_user(amount, (int *)arg);
+ }
- case SIOCGSTAMP:
- if (sk != NULL) {
- if (sk->stamp.tv_sec == 0)
- return -ENOENT;
- return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
- }
- return -EINVAL;
+ case SIOCGSTAMP:
+ if (sk != NULL) {
+ if (sk->stamp.tv_sec == 0)
+ return -ENOENT;
+ return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
+ }
+ return -EINVAL;
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- case SIOCGIFMETRIC:
- case SIOCSIFMETRIC:
- return -EINVAL;
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFMETRIC:
+ case SIOCSIFMETRIC:
+ return -EINVAL;
- case SIOCADDRT:
- case SIOCDELRT:
- case SIOCNRDECOBS:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return nr_rt_ioctl(cmd, (void *)arg);
+ case SIOCADDRT:
+ case SIOCDELRT:
+ case SIOCNRDECOBS:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ return nr_rt_ioctl(cmd, (void *)arg);
- default:
- return dev_ioctl(cmd, (void *)arg);
+ default:
+ return dev_ioctl(cmd, (void *)arg);
}
- /*NOTREACHED*/
return 0;
}
@@ -1187,7 +1164,7 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
off_t begin = 0;
- cli();
+ spin_lock_bh(&nr_list_lock);
len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n");
@@ -1240,47 +1217,45 @@ static int nr_get_info(char *buffer, char **start, off_t offset, int length)
break;
}
- sti();
+ spin_unlock_bh(&nr_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
- if (len > length) len = length;
+ if (len > length)
+ len = length;
- return(len);
-}
+ return len;
+}
static struct net_proto_family nr_family_ops = {
- .family = PF_NETROM,
- .create = nr_create,
+ .family = PF_NETROM,
+ .create = nr_create,
};
-static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = {
- .family = PF_NETROM,
-
- .release = nr_release,
- .bind = nr_bind,
- .connect = nr_connect,
- .socketpair = sock_no_socketpair,
- .accept = nr_accept,
- .getname = nr_getname,
- .poll = datagram_poll,
- .ioctl = nr_ioctl,
- .listen = nr_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = nr_setsockopt,
- .getsockopt = nr_getsockopt,
- .sendmsg = nr_sendmsg,
- .recvmsg = nr_recvmsg,
- .mmap = sock_no_mmap,
- .sendpage = sock_no_sendpage,
+static struct proto_ops nr_proto_ops = {
+ .family = PF_NETROM,
+
+ .release = nr_release,
+ .bind = nr_bind,
+ .connect = nr_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = nr_accept,
+ .getname = nr_getname,
+ .poll = datagram_poll,
+ .ioctl = nr_ioctl,
+ .listen = nr_listen,
+ .shutdown = sock_no_shutdown,
+ .setsockopt = nr_setsockopt,
+ .getsockopt = nr_getsockopt,
+ .sendmsg = nr_sendmsg,
+ .recvmsg = nr_recvmsg,
+ .mmap = sock_no_mmap,
+ .sendpage = sock_no_sendpage,
};
-#include <linux/smp_lock.h>
-SOCKOPS_WRAP(nr_proto, PF_NETROM);
-
static struct notifier_block nr_dev_notifier = {
- .notifier_call =nr_device_event,
+ .notifier_call = nr_device_event,
};
static struct net_device *dev_nr;
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index d6d5cbd641b5..67308a60d2dc 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -1,23 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
@@ -115,7 +103,7 @@ static int nr_rebuild_header(struct sk_buff *skb)
kfree_skb(skb);
len = skbn->len;
-
+
if (!nr_route_frame(skbn, NULL)) {
kfree_skb(skbn);
stats->tx_errors++;
diff --git a/net/netrom/nr_in.c b/net/netrom/nr_in.c
index 5e28d34eeb23..a5457a1d9cfc 100644
--- a/net/netrom/nr_in.c
+++ b/net/netrom/nr_in.c
@@ -1,29 +1,12 @@
/*
- * 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
- *
- * 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.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -77,7 +60,7 @@ static int nr_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
kfree_skb(skbo);
}
- nr->fraglen = 0;
+ nr->fraglen = 0;
}
return sock_queue_rcv_skb(sk, skbn);
@@ -88,36 +71,36 @@ 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.
* 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) {
+ case NR_CONNACK: {
+ nr_cb *nr = nr_sk(sk);
+
+ nr_stop_t1timer(sk);
+ nr_start_idletimer(sk);
+ nr->your_index = skb->data[17];
+ nr->your_id = skb->data[18];
+ nr->vs = 0;
+ nr->va = 0;
+ nr->vr = 0;
+ nr->vl = 0;
+ nr->state = NR_STATE_3;
+ nr->n2count = 0;
+ nr->window = skb->data[20];
+ sk->state = TCP_ESTABLISHED;
+ if (!sk->dead)
+ sk->state_change(sk);
+ break;
+ }
- case NR_CONNACK: {
- nr_cb *nr = nr_sk(sk);
-
- nr_stop_t1timer(sk);
- nr_start_idletimer(sk);
- nr->your_index = skb->data[17];
- nr->your_id = skb->data[18];
- nr->vs = 0;
- nr->va = 0;
- nr->vr = 0;
- nr->vl = 0;
- nr->state = NR_STATE_3;
- nr->n2count = 0;
- nr->window = skb->data[20];
- sk->state = TCP_ESTABLISHED;
- if (!sk->dead)
- sk->state_change(sk);
- break;
- }
-
- case NR_CONNACK | NR_CHOKE_FLAG:
- nr_disconnect(sk, ECONNREFUSED);
- break;
+ case NR_CONNACK | NR_CHOKE_FLAG:
+ nr_disconnect(sk, ECONNREFUSED);
+ break;
- default:
- break;
+ default:
+ break;
}
return 0;
@@ -128,23 +111,23 @@ 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
* 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) {
+ case NR_CONNACK | NR_CHOKE_FLAG:
+ nr_disconnect(sk, ECONNRESET);
+ break;
- case NR_CONNACK | NR_CHOKE_FLAG:
- nr_disconnect(sk, ECONNRESET);
- break;
-
- case NR_DISCREQ:
- nr_write_internal(sk, NR_DISCACK);
+ case NR_DISCREQ:
+ nr_write_internal(sk, NR_DISCACK);
- case NR_DISCACK:
- nr_disconnect(sk, 0);
- break;
+ case NR_DISCACK:
+ nr_disconnect(sk, 0);
+ break;
- default:
- break;
+ default:
+ break;
}
return 0;
@@ -168,35 +151,62 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
ns = skb->data[17];
switch (frametype) {
-
- case NR_CONNREQ:
- nr_write_internal(sk, NR_CONNACK);
- break;
-
- case NR_DISCREQ:
- nr_write_internal(sk, NR_DISCACK);
- nr_disconnect(sk, 0);
- break;
-
- case NR_CONNACK | NR_CHOKE_FLAG:
- case NR_DISCACK:
- nr_disconnect(sk, ECONNRESET);
+ case NR_CONNREQ:
+ nr_write_internal(sk, NR_CONNACK);
+ break;
+
+ case NR_DISCREQ:
+ nr_write_internal(sk, NR_DISCACK);
+ nr_disconnect(sk, 0);
+ break;
+
+ case NR_CONNACK | NR_CHOKE_FLAG:
+ case NR_DISCACK:
+ nr_disconnect(sk, ECONNRESET);
+ break;
+
+ case NR_INFOACK:
+ case NR_INFOACK | NR_CHOKE_FLAG:
+ case NR_INFOACK | NR_NAK_FLAG:
+ case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
+ if (frametype & NR_CHOKE_FLAG) {
+ nrom->condition |= NR_COND_PEER_RX_BUSY;
+ nr_start_t4timer(sk);
+ } else {
+ nrom->condition &= ~NR_COND_PEER_RX_BUSY;
+ nr_stop_t4timer(sk);
+ }
+ if (!nr_validate_nr(sk, nr)) {
break;
-
- case NR_INFOACK:
- case NR_INFOACK | NR_CHOKE_FLAG:
- case NR_INFOACK | NR_NAK_FLAG:
- case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
- if (frametype & NR_CHOKE_FLAG) {
- nrom->condition |= NR_COND_PEER_RX_BUSY;
- nr_start_t4timer(sk);
+ }
+ if (frametype & NR_NAK_FLAG) {
+ nr_frames_acked(sk, nr);
+ nr_send_nak_frame(sk);
+ } else {
+ if (nrom->condition & NR_COND_PEER_RX_BUSY) {
+ nr_frames_acked(sk, nr);
} else {
- nrom->condition &= ~NR_COND_PEER_RX_BUSY;
- nr_stop_t4timer(sk);
- }
- if (!nr_validate_nr(sk, nr)) {
- break;
+ nr_check_iframes_acked(sk, nr);
}
+ }
+ break;
+
+ case NR_INFO:
+ case NR_INFO | NR_NAK_FLAG:
+ case NR_INFO | NR_CHOKE_FLAG:
+ case NR_INFO | NR_MORE_FLAG:
+ case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG:
+ case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
+ case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
+ case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
+ if (frametype & NR_CHOKE_FLAG) {
+ nrom->condition |= NR_COND_PEER_RX_BUSY;
+ nr_start_t4timer(sk);
+ } else {
+ nrom->condition &= ~NR_COND_PEER_RX_BUSY;
+ nr_stop_t4timer(sk);
+ }
+ if (nr_validate_nr(sk, nr)) {
if (frametype & NR_NAK_FLAG) {
nr_frames_acked(sk, nr);
nr_send_nak_frame(sk);
@@ -207,76 +217,48 @@ static int nr_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype
nr_check_iframes_acked(sk, nr);
}
}
+ }
+ queued = 1;
+ skb_queue_head(&nrom->reseq_queue, skb);
+ if (nrom->condition & NR_COND_OWN_RX_BUSY)
break;
-
- case NR_INFO:
- case NR_INFO | NR_NAK_FLAG:
- case NR_INFO | NR_CHOKE_FLAG:
- case NR_INFO | NR_MORE_FLAG:
- case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG:
- case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
- case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
- case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
- if (frametype & NR_CHOKE_FLAG) {
- nrom->condition |= NR_COND_PEER_RX_BUSY;
- nr_start_t4timer(sk);
- } else {
- nrom->condition &= ~NR_COND_PEER_RX_BUSY;
- nr_stop_t4timer(sk);
- }
- if (nr_validate_nr(sk, nr)) {
- if (frametype & NR_NAK_FLAG) {
- nr_frames_acked(sk, nr);
- nr_send_nak_frame(sk);
- } else {
- if (nrom->condition & NR_COND_PEER_RX_BUSY) {
- nr_frames_acked(sk, nr);
+ skb_queue_head_init(&temp_queue);
+ do {
+ save_vr = nrom->vr;
+ while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) {
+ ns = skbn->data[17];
+ if (ns == nrom->vr) {
+ if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
+ nrom->vr = (nrom->vr + 1) % NR_MODULUS;
} else {
- nr_check_iframes_acked(sk, nr);
- }
- }
- }
- queued = 1;
- skb_queue_head(&nrom->reseq_queue, skb);
- if (nrom->condition & NR_COND_OWN_RX_BUSY)
- break;
- skb_queue_head_init(&temp_queue);
- do {
- save_vr = nrom->vr;
- while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) {
- ns = skbn->data[17];
- if (ns == nrom->vr) {
- if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
- nrom->vr = (nrom->vr + 1) % NR_MODULUS;
- } else {
- nrom->condition |= NR_COND_OWN_RX_BUSY;
- skb_queue_tail(&temp_queue, skbn);
- }
- } else if (nr_in_rx_window(sk, ns)) {
+ nrom->condition |= NR_COND_OWN_RX_BUSY;
skb_queue_tail(&temp_queue, skbn);
- } else {
- kfree_skb(skbn);
}
- }
- while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
- skb_queue_tail(&nrom->reseq_queue, skbn);
- }
- } while (save_vr != nrom->vr);
- /*
- * Window is full, ack it immediately.
- */
- if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) {
- nr_enquiry_response(sk);
- } else {
- if (!(nrom->condition & NR_COND_ACK_PENDING)) {
- nrom->condition |= NR_COND_ACK_PENDING;
- nr_start_t2timer(sk);
+ } else if (nr_in_rx_window(sk, ns)) {
+ skb_queue_tail(&temp_queue, skbn);
+ } else {
+ kfree_skb(skbn);
}
}
- break;
+ while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
+ skb_queue_tail(&nrom->reseq_queue, skbn);
+ }
+ } while (save_vr != nrom->vr);
+ /*
+ * Window is full, ack it immediately.
+ */
+ if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) {
+ nr_enquiry_response(sk);
+ } else {
+ if (!(nrom->condition & NR_COND_ACK_PENDING)) {
+ nrom->condition |= NR_COND_ACK_PENDING;
+ nr_start_t2timer(sk);
+ }
+ }
+ break;
- default:
- break;
+ default:
+ break;
}
return queued;
@@ -294,15 +276,15 @@ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb)
frametype = skb->data[19];
switch (nr->state) {
- case NR_STATE_1:
- queued = nr_state1_machine(sk, skb, frametype);
- break;
- case NR_STATE_2:
- queued = nr_state2_machine(sk, skb, frametype);
- break;
- case NR_STATE_3:
- queued = nr_state3_machine(sk, skb, frametype);
- break;
+ case NR_STATE_1:
+ queued = nr_state1_machine(sk, skb, frametype);
+ break;
+ case NR_STATE_2:
+ queued = nr_state2_machine(sk, skb, frametype);
+ break;
+ case NR_STATE_3:
+ queued = nr_state3_machine(sk, skb, frametype);
+ break;
}
nr_kick(sk);
diff --git a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c
index c943c09646bb..1d0f987529bc 100644
--- a/net/netrom/nr_loopback.c
+++ b/net/netrom/nr_loopback.c
@@ -1,20 +1,11 @@
/*
- * NET/ROM release 007
- *
- * This code REQUIRES 2.1.15 or higher/ NET3.038
- *
- * 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().
+ * 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.
*
+ * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
-
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
diff --git a/net/netrom/nr_out.c b/net/netrom/nr_out.c
index 10996ba5ecdd..3e71bbeba389 100644
--- a/net/netrom/nr_out.c
+++ b/net/netrom/nr_out.c
@@ -1,21 +1,12 @@
/*
- * 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
- *
- * 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.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -85,7 +76,7 @@ void nr_output(struct sock *sk, struct sk_buff *skb)
nr_kick(sk);
}
-/*
+/*
* This procedure is passed a buffer descriptor for an iframe. It builds
* the rest of the control part of the frame and then writes it out.
*/
@@ -104,7 +95,7 @@ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb)
nr_start_idletimer(sk);
- nr_transmit_buffer(sk, skb);
+ nr_transmit_buffer(sk, skb);
}
void nr_send_nak_frame(struct sock *sk)
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index ec0578b51316..fa85cae733f4 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -1,26 +1,13 @@
/*
- * 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
- *
- * 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) First attempt.
- * NET/ROM 003 Jonathan(G4KLX) Use SIOCADDRT/SIOCDELRT ioctl values
- * for NET/ROM routes.
- * Use '*' for a blank mnemonic in /proc/net/nr_nodes.
- * Change default quality for new neighbour when same
- * as node callsign.
- * Alan Cox(GW4PTS) Added the firewall hooks.
- * NET/ROM 006 Jonathan(G4KLX) Added the setting of digipeated neighbours.
- * Tomi(OH2BNS) Routing quality and link failure changes.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -47,12 +34,15 @@
#include <linux/notifier.h>
#include <linux/netfilter.h>
#include <linux/init.h>
+#include <linux/spinlock.h>
#include <net/netrom.h>
static unsigned int nr_neigh_no = 1;
static struct nr_node *nr_node_list;
+static spinlock_t nr_node_lock;
static struct nr_neigh *nr_neigh_list;
+static spinlock_t nr_neigh_lock;
static void nr_remove_neigh(struct nr_neigh *);
@@ -66,7 +56,6 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
struct nr_node *nr_node;
struct nr_neigh *nr_neigh;
struct nr_route nr_route;
- unsigned long flags;
int i, found;
if (nr_dev_get(nr) != NULL) /* Can't add routes to ourself */
@@ -124,13 +113,10 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
}
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&nr_neigh_lock);
nr_neigh->next = nr_neigh_list;
nr_neigh_list = nr_neigh;
-
- restore_flags(flags);
+ spin_unlock_bh(&nr_neigh_lock);
}
if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
@@ -150,13 +136,10 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
nr_node->routes[0].obs_count = obs_count;
nr_node->routes[0].neighbour = nr_neigh;
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&nr_node_lock);
nr_node->next = nr_node_list;
nr_node_list = nr_node;
-
- restore_flags(flags);
+ spin_unlock_bh(&nr_node_lock);
nr_neigh->count++;
@@ -207,40 +190,49 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
/* Now re-sort the routes in quality order */
switch (nr_node->count) {
- case 3:
- if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
- switch (nr_node->which) {
- case 0: nr_node->which = 1; break;
- case 1: nr_node->which = 0; break;
- default: break;
- }
- nr_route = nr_node->routes[0];
- nr_node->routes[0] = nr_node->routes[1];
- nr_node->routes[1] = nr_route;
+ case 3:
+ if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
+ switch (nr_node->which) {
+ case 0: nr_node->which = 1; break;
+ case 1: nr_node->which = 0; break;
+ default: break;
}
- if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
- switch (nr_node->which) {
- case 1: nr_node->which = 2; break;
- case 2: nr_node->which = 1; break;
- default: break;
- }
- nr_route = nr_node->routes[1];
- nr_node->routes[1] = nr_node->routes[2];
- nr_node->routes[2] = nr_route;
+ nr_route = nr_node->routes[0];
+ nr_node->routes[0] = nr_node->routes[1];
+ nr_node->routes[1] = nr_route;
+ }
+ if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
+ switch (nr_node->which) {
+ case 1: nr_node->which = 2;
+ break;
+
+ case 2: nr_node->which = 1;
+ break;
+
+ default:
+ break;
}
- case 2:
- if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
- switch (nr_node->which) {
- case 0: nr_node->which = 1; break;
- case 1: nr_node->which = 0; break;
- default: break;
- }
- nr_route = nr_node->routes[0];
- nr_node->routes[0] = nr_node->routes[1];
- nr_node->routes[1] = nr_route;
+ nr_route = nr_node->routes[1];
+ nr_node->routes[1] = nr_node->routes[2];
+ nr_node->routes[2] = nr_route;
+ }
+ case 2:
+ if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
+ switch (nr_node->which) {
+ case 0: nr_node->which = 1;
+ break;
+
+ case 1: nr_node->which = 0;
+ break;
+
+ default: break;
}
- case 1:
- break;
+ nr_route = nr_node->routes[0];
+ nr_node->routes[0] = nr_node->routes[1];
+ nr_node->routes[1] = nr_route;
+ }
+ case 1:
+ break;
}
for (i = 0; i < nr_node->count; i++) {
@@ -257,14 +249,11 @@ static int nr_add_node(ax25_address *nr, const char *mnemonic, ax25_address *ax2
static void nr_remove_node(struct nr_node *nr_node)
{
struct nr_node *s;
- unsigned long flags;
-
- save_flags(flags);
- cli();
+ spin_lock_bh(&nr_node_lock);
if ((s = nr_node_list) == nr_node) {
nr_node_list = nr_node->next;
- restore_flags(flags);
+ spin_unlock_bh(&nr_node_lock);
kfree(nr_node);
return;
}
@@ -272,7 +261,7 @@ static void nr_remove_node(struct nr_node *nr_node)
while (s != NULL && s->next != NULL) {
if (s->next == nr_node) {
s->next = nr_node->next;
- restore_flags(flags);
+ spin_unlock_bh(&nr_node_lock);
kfree(nr_node);
return;
}
@@ -280,20 +269,17 @@ static void nr_remove_node(struct nr_node *nr_node)
s = s->next;
}
- restore_flags(flags);
+ spin_unlock_bh(&nr_node_lock);
}
static void nr_remove_neigh(struct nr_neigh *nr_neigh)
{
struct nr_neigh *s;
- unsigned long flags;
-
- save_flags(flags);
- cli();
+ spin_lock_bh(&nr_neigh_lock);
if ((s = nr_neigh_list) == nr_neigh) {
nr_neigh_list = nr_neigh->next;
- restore_flags(flags);
+ spin_unlock_bh(&nr_neigh_lock);
if (nr_neigh->digipeat != NULL)
kfree(nr_neigh->digipeat);
kfree(nr_neigh);
@@ -303,7 +289,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
while (s != NULL && s->next != NULL) {
if (s->next == nr_neigh) {
s->next = nr_neigh->next;
- restore_flags(flags);
+ spin_unlock_bh(&nr_neigh_lock);
if (nr_neigh->digipeat != NULL)
kfree(nr_neigh->digipeat);
kfree(nr_neigh);
@@ -312,8 +298,7 @@ static void nr_remove_neigh(struct nr_neigh *nr_neigh)
s = s->next;
}
-
- restore_flags(flags);
+ spin_unlock_bh(&nr_neigh_lock);
}
/*
@@ -330,13 +315,15 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
if (ax25cmp(callsign, &nr_node->callsign) == 0)
break;
- if (nr_node == NULL) return -EINVAL;
+ if (nr_node == NULL)
+ return -EINVAL;
for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
break;
- if (nr_neigh == NULL) return -EINVAL;
+ if (nr_neigh == NULL)
+ return -EINVAL;
for (i = 0; i < nr_node->count; i++) {
if (nr_node->routes[i].neighbour == nr_neigh) {
@@ -351,12 +338,12 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
nr_remove_node(nr_node);
} else {
switch (i) {
- case 0:
- nr_node->routes[0] = nr_node->routes[1];
- case 1:
- nr_node->routes[1] = nr_node->routes[2];
- case 2:
- break;
+ case 0:
+ nr_node->routes[0] = nr_node->routes[1];
+ case 1:
+ nr_node->routes[1] = nr_node->routes[2];
+ case 2:
+ break;
}
}
@@ -373,7 +360,6 @@ static int nr_del_node(ax25_address *callsign, ax25_address *neighbour, struct n
static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
{
struct nr_neigh *nr_neigh;
- unsigned long flags;
for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) {
@@ -404,15 +390,12 @@ static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net
memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
}
- save_flags(flags);
- cli();
-
+ spin_lock_bh(&nr_neigh_lock);
nr_neigh->next = nr_neigh_list;
nr_neigh_list = nr_neigh;
+ spin_unlock_bh(&nr_neigh_lock);
- restore_flags(flags);
-
- return 0;
+ return 0;
}
/*
@@ -457,7 +440,6 @@ static int nr_dec_obs(void)
for (i = 0; i < s->count; i++) {
switch (s->routes[i].obs_count) {
-
case 0: /* A locked entry */
break;
@@ -520,12 +502,12 @@ void nr_rt_device_down(struct net_device *dev)
t->count--;
switch (i) {
- case 0:
- t->routes[0] = t->routes[1];
- case 1:
- t->routes[1] = t->routes[2];
- case 2:
- break;
+ case 0:
+ t->routes[0] = t->routes[1];
+ case 1:
+ t->routes[1] = t->routes[2];
+ case 2:
+ break;
}
}
}
@@ -622,51 +604,50 @@ int nr_rt_ioctl(unsigned int cmd, void *arg)
struct net_device *dev;
switch (cmd) {
+ case SIOCADDRT:
+ if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
+ return -EFAULT;
+ if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
+ return -EINVAL;
+ if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS)
+ return -EINVAL;
+ switch (nr_route.type) {
+ case NETROM_NODE:
+ return nr_add_node(&nr_route.callsign,
+ nr_route.mnemonic,
+ &nr_route.neighbour,
+ nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
+ dev, nr_route.quality,
+ nr_route.obs_count);
+ case NETROM_NEIGH:
+ return nr_add_neigh(&nr_route.callsign,
+ nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
+ dev, nr_route.quality);
+ default:
+ return -EINVAL;
+ }
- case SIOCADDRT:
- if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
- return -EFAULT;
- if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
- return -EINVAL;
- if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS)
- return -EINVAL;
- switch (nr_route.type) {
- case NETROM_NODE:
- return nr_add_node(&nr_route.callsign,
- nr_route.mnemonic,
- &nr_route.neighbour,
- nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
- dev, nr_route.quality,
- nr_route.obs_count);
- case NETROM_NEIGH:
- return nr_add_neigh(&nr_route.callsign,
- nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
- dev, nr_route.quality);
- default:
- return -EINVAL;
- }
-
- case SIOCDELRT:
- if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
- return -EFAULT;
- if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
- return -EINVAL;
- switch (nr_route.type) {
- case NETROM_NODE:
- return nr_del_node(&nr_route.callsign,
- &nr_route.neighbour, dev);
- case NETROM_NEIGH:
- return nr_del_neigh(&nr_route.callsign,
- dev, nr_route.quality);
- default:
- return -EINVAL;
- }
-
- case SIOCNRDECOBS:
- return nr_dec_obs();
-
+ case SIOCDELRT:
+ if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
+ return -EFAULT;
+ if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
+ return -EINVAL;
+ switch (nr_route.type) {
+ case NETROM_NODE:
+ return nr_del_node(&nr_route.callsign,
+ &nr_route.neighbour, dev);
+ case NETROM_NEIGH:
+ return nr_del_neigh(&nr_route.callsign,
+ dev, nr_route.quality);
default:
return -EINVAL;
+ }
+
+ case SIOCNRDECOBS:
+ return nr_dec_obs();
+
+ default:
+ return -EINVAL;
}
return 0;
@@ -758,8 +739,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
off_t begin = 0;
int i;
- cli();
-
+ spin_lock_bh(&nr_node_lock);
len += sprintf(buffer, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
@@ -767,7 +747,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
ax2asc(&nr_node->callsign),
(nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
nr_node->which + 1,
- nr_node->count);
+ nr_node->count);
for (i = 0; i < nr_node->count; i++) {
len += sprintf(buffer + len, " %3d %d %05d",
@@ -788,8 +768,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length)
break;
}
-
- sti();
+ spin_unlock_bh(&nr_node_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
@@ -797,7 +776,7 @@ int nr_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if (len > length) len = length;
return len;
-}
+}
int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
{
@@ -807,8 +786,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
off_t begin = 0;
int i;
- cli();
-
+ spin_lock_bh(&nr_neigh_lock);
len += sprintf(buffer, "addr callsign dev qual lock count failed digipeaters\n");
for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
@@ -839,7 +817,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
break;
}
- sti();
+ spin_unlock_bh(&nr_neigh_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
@@ -847,7 +825,7 @@ int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
if (len > length) len = length;
return len;
-}
+}
/*
* Free all memory associated with the nodes and routes lists.
diff --git a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c
index f9c4fba77c04..f1d7aef4b811 100644
--- a/net/netrom/nr_subr.c
+++ b/net/netrom/nr_subr.c
@@ -1,20 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -125,7 +116,7 @@ int nr_in_rx_window(struct sock *sk, unsigned short ns)
return 0;
}
-/*
+/*
* This routine is called when the HDLC layer internally generates a
* control frame.
*/
@@ -139,19 +130,19 @@ void nr_write_internal(struct sock *sk, int frametype)
len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
switch (frametype & 0x0F) {
- case NR_CONNREQ:
- len += 17;
- break;
- case NR_CONNACK:
- len += (nr->bpqext) ? 2 : 1;
- break;
- case NR_DISCREQ:
- case NR_DISCACK:
- case NR_INFOACK:
- break;
- default:
- printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype);
- return;
+ case NR_CONNREQ:
+ len += 17;
+ break;
+ case NR_CONNACK:
+ len += (nr->bpqext) ? 2 : 1;
+ break;
+ case NR_DISCREQ:
+ case NR_DISCACK:
+ case NR_INFOACK:
+ break;
+ default:
+ printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype);
+ return;
}
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -161,59 +152,58 @@ void nr_write_internal(struct sock *sk, int frametype)
* Space for AX.25 and NET/ROM network header
*/
skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN);
-
+
dptr = skb_put(skb, skb_tailroom(skb));
switch (frametype & 0x0F) {
+ case NR_CONNREQ:
+ timeout = nr->t1 / HZ;
+ *dptr++ = nr->my_index;
+ *dptr++ = nr->my_id;
+ *dptr++ = 0;
+ *dptr++ = 0;
+ *dptr++ = frametype;
+ *dptr++ = nr->window;
+ memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN);
+ dptr[6] &= ~AX25_CBIT;
+ dptr[6] &= ~AX25_EBIT;
+ dptr[6] |= AX25_SSSID_SPARE;
+ dptr += AX25_ADDR_LEN;
+ memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN);
+ dptr[6] &= ~AX25_CBIT;
+ dptr[6] &= ~AX25_EBIT;
+ dptr[6] |= AX25_SSSID_SPARE;
+ dptr += AX25_ADDR_LEN;
+ *dptr++ = timeout % 256;
+ *dptr++ = timeout / 256;
+ break;
+
+ case NR_CONNACK:
+ *dptr++ = nr->your_index;
+ *dptr++ = nr->your_id;
+ *dptr++ = nr->my_index;
+ *dptr++ = nr->my_id;
+ *dptr++ = frametype;
+ *dptr++ = nr->window;
+ if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser;
+ break;
+
+ case NR_DISCREQ:
+ case NR_DISCACK:
+ *dptr++ = nr->your_index;
+ *dptr++ = nr->your_id;
+ *dptr++ = 0;
+ *dptr++ = 0;
+ *dptr++ = frametype;
+ break;
- case NR_CONNREQ:
- timeout = nr->t1 / HZ;
- *dptr++ = nr->my_index;
- *dptr++ = nr->my_id;
- *dptr++ = 0;
- *dptr++ = 0;
- *dptr++ = frametype;
- *dptr++ = nr->window;
- memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN);
- dptr[6] &= ~AX25_CBIT;
- dptr[6] &= ~AX25_EBIT;
- dptr[6] |= AX25_SSSID_SPARE;
- dptr += AX25_ADDR_LEN;
- memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN);
- dptr[6] &= ~AX25_CBIT;
- dptr[6] &= ~AX25_EBIT;
- dptr[6] |= AX25_SSSID_SPARE;
- dptr += AX25_ADDR_LEN;
- *dptr++ = timeout % 256;
- *dptr++ = timeout / 256;
- break;
-
- case NR_CONNACK:
- *dptr++ = nr->your_index;
- *dptr++ = nr->your_id;
- *dptr++ = nr->my_index;
- *dptr++ = nr->my_id;
- *dptr++ = frametype;
- *dptr++ = nr->window;
- if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser;
- break;
-
- case NR_DISCREQ:
- case NR_DISCACK:
- *dptr++ = nr->your_index;
- *dptr++ = nr->your_id;
- *dptr++ = 0;
- *dptr++ = 0;
- *dptr++ = frametype;
- break;
-
- case NR_INFOACK:
- *dptr++ = nr->your_index;
- *dptr++ = nr->your_id;
- *dptr++ = 0;
- *dptr++ = nr->vr;
- *dptr++ = frametype;
- break;
+ case NR_INFOACK:
+ *dptr++ = nr->your_index;
+ *dptr++ = nr->your_id;
+ *dptr++ = 0;
+ *dptr++ = nr->vr;
+ *dptr++ = frametype;
+ break;
}
nr_transmit_buffer(sk, skb);
@@ -243,7 +233,7 @@ void nr_transmit_refusal(struct sk_buff *skb, int mine)
dptr[6] &= ~AX25_EBIT;
dptr[6] |= AX25_SSSID_SPARE;
dptr += AX25_ADDR_LEN;
-
+
memcpy(dptr, skb->data + 0, AX25_ADDR_LEN);
dptr[6] &= ~AX25_CBIT;
dptr[6] |= AX25_EBIT;
diff --git a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c
index cdeab2e21f55..388105d711b0 100644
--- a/net/netrom/nr_timer.c
+++ b/net/netrom/nr_timer.c
@@ -1,20 +1,12 @@
/*
- * 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
- *
- * 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_timer.c
- * NET/ROM 007 Jonathan(G4KLX) New timer architecture.
- * Implemented idle timer.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -144,33 +136,34 @@ static void nr_heartbeat_expiry(unsigned long param)
struct sock *sk = (struct sock *)param;
nr_cb *nr = nr_sk(sk);
+ bh_lock_sock(sk);
switch (nr->state) {
-
- case NR_STATE_0:
- /* Magic here: If we listen() and a new link dies before it
- is accepted() it isn't 'dead' so doesn't get removed. */
- if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
- nr_destroy_socket(sk);
- return;
- }
- break;
-
- case NR_STATE_3:
- /*
- * Check for the state of the receive buffer.
- */
- if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
- (nr->condition & NR_COND_OWN_RX_BUSY)) {
- nr->condition &= ~NR_COND_OWN_RX_BUSY;
- nr->condition &= ~NR_COND_ACK_PENDING;
- nr->vl = nr->vr;
- nr_write_internal(sk, NR_INFOACK);
- break;
- }
+ case NR_STATE_0:
+ /* Magic here: If we listen() and a new link dies before it
+ is accepted() it isn't 'dead' so doesn't get removed. */
+ if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
+ nr_destroy_socket(sk);
+ return;
+ }
+ break;
+
+ case NR_STATE_3:
+ /*
+ * Check for the state of the receive buffer.
+ */
+ if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
+ (nr->condition & NR_COND_OWN_RX_BUSY)) {
+ nr->condition &= ~NR_COND_OWN_RX_BUSY;
+ nr->condition &= ~NR_COND_ACK_PENDING;
+ nr->vl = nr->vr;
+ nr_write_internal(sk, NR_INFOACK);
break;
+ }
+ break;
}
nr_start_heartbeat(sk);
+ bh_unlock_sock(sk);
}
static void nr_t2timer_expiry(unsigned long param)
@@ -178,17 +171,21 @@ static void nr_t2timer_expiry(unsigned long param)
struct sock *sk = (struct sock *)param;
nr_cb *nr = nr_sk(sk);
+ bh_lock_sock(sk);
if (nr->condition & NR_COND_ACK_PENDING) {
nr->condition &= ~NR_COND_ACK_PENDING;
nr_enquiry_response(sk);
}
+ bh_unlock_sock(sk);
}
static void nr_t4timer_expiry(unsigned long param)
{
struct sock *sk = (struct sock *)param;
+ bh_lock_sock(sk);
nr_sk(sk)->condition &= ~NR_COND_PEER_RX_BUSY;
+ bh_unlock_sock(sk);
}
static void nr_idletimer_expiry(unsigned long param)
@@ -196,6 +193,8 @@ static void nr_idletimer_expiry(unsigned long param)
struct sock *sk = (struct sock *)param;
nr_cb *nr = nr_sk(sk);
+ bh_lock_sock(sk);
+
nr_clear_queues(sk);
nr->n2count = 0;
@@ -214,6 +213,7 @@ static void nr_idletimer_expiry(unsigned long param)
sk->state_change(sk);
sk->dead = 1;
+ bh_unlock_sock(sk);
}
static void nr_t1timer_expiry(unsigned long param)
@@ -221,38 +221,39 @@ static void nr_t1timer_expiry(unsigned long param)
struct sock *sk = (struct sock *)param;
nr_cb *nr = nr_sk(sk);
+ bh_lock_sock(sk);
switch (nr->state) {
-
- case NR_STATE_1:
- if (nr->n2count == nr->n2) {
- nr_disconnect(sk, ETIMEDOUT);
- return;
- } else {
- nr->n2count++;
- nr_write_internal(sk, NR_CONNREQ);
- }
- break;
-
- case NR_STATE_2:
- if (nr->n2count == nr->n2) {
- nr_disconnect(sk, ETIMEDOUT);
- return;
- } else {
- nr->n2count++;
- nr_write_internal(sk, NR_DISCREQ);
- }
- break;
-
- case NR_STATE_3:
- if (nr->n2count == nr->n2) {
- nr_disconnect(sk, ETIMEDOUT);
- return;
- } else {
- nr->n2count++;
- nr_requeue_frames(sk);
- }
- break;
+ case NR_STATE_1:
+ if (nr->n2count == nr->n2) {
+ nr_disconnect(sk, ETIMEDOUT);
+ return;
+ } else {
+ nr->n2count++;
+ nr_write_internal(sk, NR_CONNREQ);
+ }
+ break;
+
+ case NR_STATE_2:
+ if (nr->n2count == nr->n2) {
+ nr_disconnect(sk, ETIMEDOUT);
+ return;
+ } else {
+ nr->n2count++;
+ nr_write_internal(sk, NR_DISCREQ);
+ }
+ break;
+
+ case NR_STATE_3:
+ if (nr->n2count == nr->n2) {
+ nr_disconnect(sk, ETIMEDOUT);
+ return;
+ } else {
+ nr->n2count++;
+ nr_requeue_frames(sk);
+ }
+ break;
}
nr_start_t1timer(sk);
+ bh_unlock_sock(sk);
}
diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c
index bf8006236bdc..1e92edceb7bd 100644
--- a/net/netrom/sysctl_net_netrom.c
+++ b/net/netrom/sysctl_net_netrom.c
@@ -1,10 +1,11 @@
-/* -*- 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.
- * Added /proc/sys/net/netrom directory entry (empty =) ). [MS]
+ * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
*/
-
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/init.h>
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index f9ccd78a8c0f..b672f85c9a49 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1,29 +1,14 @@
/*
- * 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
- *
- * 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 af_netrom.c.
- * Alan(GW4PTS) Hacked up for newer API stuff
- * Terry (VK2KTJ) Added support for variable length
- * address masks.
- * ROSE 002 Jonathan(G4KLX) Changed hdrincl to qbitincl.
- * Added random number facilities entry.
- * Variable number of ROSE devices.
- * ROSE 003 Jonathan(G4KLX) New timer architecture.
- * Implemented idle timer.
- * Added use count to neighbour.
- * Tomi(OH2BNS) Fixed rose_getname().
- * Arnaldo C. Melo s/suser/capable/ + micro cleanups
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
+ * Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
*/
-
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -33,6 +18,7 @@
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/sockios.h>
@@ -47,7 +33,7 @@
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/fcntl.h>
-#include <linux/termios.h> /* For TIOCINQ/OUTQ */
+#include <linux/termios.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
@@ -71,6 +57,7 @@ int sysctl_rose_maximum_vcs = ROSE_DEFAULT_MAXVC;
int sysctl_rose_window_size = ROSE_DEFAULT_WINDOW_SIZE;
static struct sock *rose_list;
+static spinlock_t rose_list_lock = SPIN_LOCK_UNLOCKED;
static struct proto_ops rose_proto_ops;
@@ -173,27 +160,24 @@ decmod: MOD_DEC_USE_COUNT;
static void rose_remove_socket(struct sock *sk)
{
struct sock *s;
- unsigned long flags;
-
- save_flags(flags); cli();
+ spin_lock_bh(&rose_list_lock);
if ((s = rose_list) == sk) {
rose_list = s->next;
- restore_flags(flags);
+ spin_unlock_bh(&rose_list_lock);
return;
}
while (s != NULL && s->next != NULL) {
if (s->next == sk) {
s->next = sk->next;
- restore_flags(flags);
+ spin_unlock_bh(&rose_list_lock);
return;
}
s = s->next;
}
-
- restore_flags(flags);
+ spin_unlock_bh(&rose_list_lock);
}
/*
@@ -204,6 +188,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
{
struct sock *s;
+ spin_lock_bh(&rose_list_lock);
for (s = rose_list; s != NULL; s = s->next) {
rose_cb *rose = rose_sk(s);
@@ -213,6 +198,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
rose->neighbour = NULL;
}
}
+ spin_unlock_bh(&rose_list_lock);
}
/*
@@ -221,7 +207,8 @@ void rose_kill_by_neigh(struct rose_neigh *neigh)
static void rose_kill_by_device(struct net_device *dev)
{
struct sock *s;
-
+
+ spin_lock_bh(&rose_list_lock);
for (s = rose_list; s != NULL; s = s->next) {
rose_cb *rose = rose_sk(s);
@@ -231,12 +218,14 @@ static void rose_kill_by_device(struct net_device *dev)
rose->device = NULL;
}
}
+ spin_unlock_bh(&rose_list_lock);
}
/*
* Handle device status changes.
*/
-static int rose_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+static int rose_device_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
{
struct net_device *dev = (struct net_device *)ptr;
@@ -244,13 +233,13 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, v
return NOTIFY_DONE;
switch (dev->type) {
- case ARPHRD_ROSE:
- rose_kill_by_device(dev);
- break;
- case ARPHRD_AX25:
- rose_link_device_down(dev);
- rose_rt_device_down(dev);
- break;
+ case ARPHRD_ROSE:
+ rose_kill_by_device(dev);
+ break;
+ case ARPHRD_AX25:
+ rose_link_device_down(dev);
+ rose_rt_device_down(dev);
+ break;
}
return NOTIFY_DONE;
@@ -261,14 +250,11 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, v
*/
static void rose_insert_socket(struct sock *sk)
{
- unsigned long flags;
-
- save_flags(flags); cli();
+ spin_lock_bh(&rose_list_lock);
sk->next = rose_list;
rose_list = sk;
-
- restore_flags(flags);
+ spin_unlock_bh(&rose_list_lock);
}
/*
@@ -277,18 +263,16 @@ static void rose_insert_socket(struct sock *sk)
*/
static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
{
- unsigned long flags;
struct sock *s;
- save_flags(flags); cli();
-
+ spin_lock_bh(&rose_list_lock);
for (s = rose_list; s != NULL; s = s->next) {
rose_cb *rose = rose_sk(s);
if (!rosecmp(&rose->source_addr, addr) &&
!ax25cmp(&rose->source_call, call) &&
!rose->source_ndigis && s->state == TCP_LISTEN) {
- restore_flags(flags);
+ spin_unlock_bh(&rose_list_lock);
return s;
}
}
@@ -299,12 +283,12 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
if (!rosecmp(&rose->source_addr, addr) &&
!ax25cmp(&rose->source_call, &null_ax25_address) &&
s->state == TCP_LISTEN) {
- restore_flags(flags);
+ spin_unlock_bh(&rose_list_lock);
return s;
}
}
+ spin_unlock_bh(&rose_list_lock);
- restore_flags(flags);
return NULL;
}
@@ -314,20 +298,17 @@ static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh)
{
struct sock *s;
- unsigned long flags;
-
- save_flags(flags); cli();
+ spin_lock_bh(&rose_list_lock);
for (s = rose_list; s != NULL; s = s->next) {
rose_cb *rose = rose_sk(s);
if (rose->lci == lci && rose->neighbour == neigh) {
- restore_flags(flags);
+ spin_unlock_bh(&rose_list_lock);
return s;
}
}
-
- restore_flags(flags);
+ spin_unlock_bh(&rose_list_lock);
return NULL;
}
@@ -366,23 +347,20 @@ static void rose_destroy_timer(unsigned long data)
}
/*
- * This is called from user mode and the timers. Thus it protects itself against
- * interrupt users but doesn't worry about being called during work.
- * Once it is removed from the queue no interrupt or bottom half will
- * touch it and we are (fairly 8-) ) safe.
+ * This is called from user mode and the timers. Thus it protects itself
+ * against interrupt users but doesn't worry about being called during
+ * work. Once it is removed from the queue no interrupt or bottom half
+ * will touch it and we are (fairly 8-) ) safe.
*/
-void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the timer */
+void rose_destroy_socket(struct sock *sk)
{
struct sk_buff *skb;
- unsigned long flags;
-
- save_flags(flags); cli();
+ rose_remove_socket(sk);
rose_stop_heartbeat(sk);
rose_stop_idletimer(sk);
rose_stop_timer(sk);
- rose_remove_socket(sk);
rose_clear_queues(sk); /* Flush the queues */
while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
@@ -405,8 +383,6 @@ void rose_destroy_socket(struct sock *sk) /* Not static as it's used by the time
} else {
rose_free_sock(sk);
}
-
- restore_flags(flags);
}
/*
@@ -431,46 +407,46 @@ static int rose_setsockopt(struct socket *sock, int level, int optname,
return -EFAULT;
switch (optname) {
- case ROSE_DEFER:
- rose->defer = opt ? 1 : 0;
- return 0;
-
- case ROSE_T1:
- if (opt < 1)
- return -EINVAL;
- rose->t1 = opt * HZ;
- return 0;
-
- case ROSE_T2:
- if (opt < 1)
- return -EINVAL;
- rose->t2 = opt * HZ;
- return 0;
-
- case ROSE_T3:
- if (opt < 1)
- return -EINVAL;
- rose->t3 = opt * HZ;
- return 0;
-
- case ROSE_HOLDBACK:
- if (opt < 1)
- return -EINVAL;
- rose->hb = opt * HZ;
- return 0;
-
- case ROSE_IDLE:
- if (opt < 0)
- return -EINVAL;
- rose->idle = opt * 60 * HZ;
- return 0;
-
- case ROSE_QBITINCL:
- rose->qbitincl = opt ? 1 : 0;
- return 0;
-
- default:
- return -ENOPROTOOPT;
+ case ROSE_DEFER:
+ rose->defer = opt ? 1 : 0;
+ return 0;
+
+ case ROSE_T1:
+ if (opt < 1)
+ return -EINVAL;
+ rose->t1 = opt * HZ;
+ return 0;
+
+ case ROSE_T2:
+ if (opt < 1)
+ return -EINVAL;
+ rose->t2 = opt * HZ;
+ return 0;
+
+ case ROSE_T3:
+ if (opt < 1)
+ return -EINVAL;
+ rose->t3 = opt * HZ;
+ return 0;
+
+ case ROSE_HOLDBACK:
+ if (opt < 1)
+ return -EINVAL;
+ rose->hb = opt * HZ;
+ return 0;
+
+ case ROSE_IDLE:
+ if (opt < 0)
+ return -EINVAL;
+ rose->idle = opt * 60 * HZ;
+ return 0;
+
+ case ROSE_QBITINCL:
+ rose->qbitincl = opt ? 1 : 0;
+ return 0;
+
+ default:
+ return -ENOPROTOOPT;
}
}
@@ -484,44 +460,44 @@ static int rose_getsockopt(struct socket *sock, int level, int optname,
if (level != SOL_ROSE)
return -ENOPROTOOPT;
-
+
if (get_user(len, optlen))
return -EFAULT;
if (len < 0)
return -EINVAL;
-
+
switch (optname) {
- case ROSE_DEFER:
- val = rose->defer;
- break;
+ case ROSE_DEFER:
+ val = rose->defer;
+ break;
- case ROSE_T1:
- val = rose->t1 / HZ;
- break;
+ case ROSE_T1:
+ val = rose->t1 / HZ;
+ break;
- case ROSE_T2:
- val = rose->t2 / HZ;
- break;
+ case ROSE_T2:
+ val = rose->t2 / HZ;
+ break;
- case ROSE_T3:
- val = rose->t3 / HZ;
- break;
+ case ROSE_T3:
+ val = rose->t3 / HZ;
+ break;
- case ROSE_HOLDBACK:
- val = rose->hb / HZ;
- break;
+ case ROSE_HOLDBACK:
+ val = rose->hb / HZ;
+ break;
- case ROSE_IDLE:
- val = rose->idle / (60 * HZ);
- break;
+ case ROSE_IDLE:
+ val = rose->idle / (60 * HZ);
+ break;
- case ROSE_QBITINCL:
- val = rose->qbitincl;
- break;
+ case ROSE_QBITINCL:
+ val = rose->qbitincl;
+ break;
- default:
- return -ENOPROTOOPT;
+ default:
+ return -ENOPROTOOPT;
}
len = min_t(unsigned int, len, sizeof(int));
@@ -565,7 +541,7 @@ static int rose_create(struct socket *sock, int protocol)
rose = rose_sk(sk);
sock_init_data(sock, sk);
-
+
skb_queue_head_init(&rose->ack_queue);
#ifdef M_BIT
skb_queue_head_init(&rose->frag_queue);
@@ -647,39 +623,38 @@ static int rose_release(struct socket *sock)
rose = rose_sk(sk);
switch (rose->state) {
-
- case ROSE_STATE_0:
- rose_disconnect(sk, 0, -1, -1);
- rose_destroy_socket(sk);
- break;
-
- case ROSE_STATE_2:
- rose->neighbour->use--;
- rose_disconnect(sk, 0, -1, -1);
- rose_destroy_socket(sk);
- break;
-
- case ROSE_STATE_1:
- case ROSE_STATE_3:
- case ROSE_STATE_4:
- case ROSE_STATE_5:
- rose_clear_queues(sk);
- rose_stop_idletimer(sk);
- rose_write_internal(sk, ROSE_CLEAR_REQUEST);
- rose_start_t3timer(sk);
- rose->state = ROSE_STATE_2;
- sk->state = TCP_CLOSE;
- sk->shutdown |= SEND_SHUTDOWN;
- sk->state_change(sk);
- sk->dead = 1;
- sk->destroy = 1;
- break;
-
- default:
- break;
+ case ROSE_STATE_0:
+ rose_disconnect(sk, 0, -1, -1);
+ rose_destroy_socket(sk);
+ break;
+
+ case ROSE_STATE_2:
+ rose->neighbour->use--;
+ rose_disconnect(sk, 0, -1, -1);
+ rose_destroy_socket(sk);
+ break;
+
+ case ROSE_STATE_1:
+ case ROSE_STATE_3:
+ case ROSE_STATE_4:
+ case ROSE_STATE_5:
+ rose_clear_queues(sk);
+ rose_stop_idletimer(sk);
+ rose_write_internal(sk, ROSE_CLEAR_REQUEST);
+ rose_start_t3timer(sk);
+ rose->state = ROSE_STATE_2;
+ sk->state = TCP_CLOSE;
+ sk->shutdown |= SEND_SHUTDOWN;
+ sk->state_change(sk);
+ sk->dead = 1;
+ sk->destroy = 1;
+ break;
+
+ default:
+ break;
}
- sock->sk = NULL;
+ sock->sk = NULL;
sk->socket = NULL; /* Not used, but we should do this. **/
return 0;
@@ -842,71 +817,90 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le
if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
return -EINPROGRESS;
- cli(); /* To avoid races on the sleep */
-
/*
- * A Connect Ack with Choke or timeout or failed routing will go to closed.
+ * A Connect Ack with Choke or timeout or failed routing will go to
+ * closed.
*/
- while (sk->state == TCP_SYN_SENT) {
- interruptible_sleep_on(sk->sleep);
- if (signal_pending(current)) {
- sti();
+ if (sk->state == TCP_SYN_SENT) {
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (sk->state != TCP_SYN_SENT)
+ break;
+ if (!signal_pending(tsk)) {
+ schedule();
+ continue;
+ }
return -ERESTARTSYS;
}
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
}
if (sk->state != TCP_ESTABLISHED) {
- sti();
sock->state = SS_UNCONNECTED;
return sock_error(sk); /* Always set at this point */
}
sock->state = SS_CONNECTED;
- sti();
-
return 0;
}
static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
{
- struct sock *sk;
- struct sock *newsk;
+ struct task_struct *tsk = current;
+ DECLARE_WAITQUEUE(wait, tsk);
struct sk_buff *skb;
+ struct sock *newsk;
+ struct sock *sk;
+ int err = 0;
if ((sk = sock->sk) == NULL)
return -EINVAL;
- if (sk->type != SOCK_SEQPACKET)
- return -EOPNOTSUPP;
+ lock_sock(sk);
+ if (sk->type != SOCK_SEQPACKET) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
- if (sk->state != TCP_LISTEN)
- return -EINVAL;
+ if (sk->state != TCP_LISTEN) {
+ err = -EINVAL;
+ goto out;
+ }
/*
* The write queue this time is holding sockets ready to use
* hooked into the SABM we saved
*/
- do {
- cli();
- if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
- if (flags & O_NONBLOCK) {
- sti();
- return -EWOULDBLOCK;
- }
- interruptible_sleep_on(sk->sleep);
- if (signal_pending(current)) {
- sti();
- return -ERESTARTSYS;
- }
+ add_wait_queue(sk->sleep, &wait);
+ for (;;) {
+ skb = skb_dequeue(&sk->receive_queue);
+ if (skb)
+ break;
+
+ current->state = TASK_INTERRUPTIBLE;
+ release_sock(sk);
+ if (flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ if (!signal_pending(tsk)) {
+ schedule();
+ lock_sock(sk);
+ continue;
}
- } while (skb == NULL);
+ return -ERESTARTSYS;
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &wait);
newsk = skb->sk;
newsk->pair = NULL;
newsk->socket = newsock;
newsk->sleep = &newsock->wait;
- sti();
/* Now attach up the new socket */
skb->sk = NULL;
@@ -914,7 +908,10 @@ static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
sk->ack_backlog--;
newsock->sk = newsk;
- return 0;
+out:
+ release_sock(sk);
+
+ return err;
}
static int rose_getname(struct socket *sock, struct sockaddr *uaddr,
@@ -961,7 +958,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
* skb->data points to the rose frame start
*/
memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
-
+
len = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
@@ -1028,7 +1025,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros
return 1;
}
-static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
@@ -1131,7 +1128,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
SOCK_DEBUG(sk, "ROSE: Built header.\n");
SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n");
-
+
if (sk->state != TCP_ESTABLISHED) {
kfree_skb(skb);
return -ENOTCONN;
@@ -1144,7 +1141,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct sk_buff *skbn;
int frontlen;
int lg;
-
+
/* Save a copy of the Header */
memcpy(header, skb->data, ROSE_MIN_LEN);
skb_pull(skb, ROSE_MIN_LEN);
@@ -1173,10 +1170,10 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if (skb->len > 0)
skbn->data[2] |= M_BIT;
-
+
skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
}
-
+
skb->free = 1;
kfree_skb(skb, FREE_WRITE);
} else {
@@ -1192,7 +1189,7 @@ static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
}
-static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size,
int flags, struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
@@ -1264,96 +1261,96 @@ static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
rose_cb *rose = rose_sk(sk);
switch (cmd) {
- case TIOCOUTQ: {
- long amount;
- amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
- if (amount < 0)
- amount = 0;
- return put_user(amount, (unsigned int *)arg);
- }
+ case TIOCOUTQ: {
+ long amount;
+ amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
+ if (amount < 0)
+ amount = 0;
+ return put_user(amount, (unsigned int *)arg);
+ }
- case TIOCINQ: {
- struct sk_buff *skb;
- long amount = 0L;
- /* These two are safe on a single CPU system as only user tasks fiddle here */
- if ((skb = skb_peek(&sk->receive_queue)) != NULL)
- amount = skb->len;
- return put_user(amount, (unsigned int *)arg);
+ case TIOCINQ: {
+ struct sk_buff *skb;
+ long amount = 0L;
+ /* These two are safe on a single CPU system as only user tasks fiddle here */
+ if ((skb = skb_peek(&sk->receive_queue)) != NULL)
+ amount = skb->len;
+ return put_user(amount, (unsigned int *)arg);
+ }
+
+ case SIOCGSTAMP:
+ if (sk != NULL) {
+ if (sk->stamp.tv_sec == 0)
+ return -ENOENT;
+ return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
}
+ return -EINVAL;
- case SIOCGSTAMP:
- if (sk != NULL) {
- if (sk->stamp.tv_sec == 0)
- return -ENOENT;
- return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
- }
- return -EINVAL;
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ case SIOCGIFMETRIC:
+ case SIOCSIFMETRIC:
+ return -EINVAL;
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- case SIOCGIFMETRIC:
- case SIOCSIFMETRIC:
- return -EINVAL;
+ case SIOCADDRT:
+ case SIOCDELRT:
+ case SIOCRSCLRRT:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ return rose_rt_ioctl(cmd, (void *)arg);
+
+ case SIOCRSGCAUSE: {
+ struct rose_cause_struct rose_cause;
+ rose_cause.cause = rose->cause;
+ rose_cause.diagnostic = rose->diagnostic;
+ return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0;
+ }
- case SIOCADDRT:
- case SIOCDELRT:
- case SIOCRSCLRRT:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return rose_rt_ioctl(cmd, (void *)arg);
-
- case SIOCRSGCAUSE: {
- struct rose_cause_struct rose_cause;
- rose_cause.cause = rose->cause;
- rose_cause.diagnostic = rose->diagnostic;
- return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0;
- }
+ case SIOCRSSCAUSE: {
+ struct rose_cause_struct rose_cause;
+ if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct)))
+ return -EFAULT;
+ rose->cause = rose_cause.cause;
+ rose->diagnostic = rose_cause.diagnostic;
+ return 0;
+ }
- case SIOCRSSCAUSE: {
- struct rose_cause_struct rose_cause;
- if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct)))
- return -EFAULT;
- rose->cause = rose_cause.cause;
- rose->diagnostic = rose_cause.diagnostic;
- return 0;
- }
+ case SIOCRSSL2CALL:
+ if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
+ ax25_listen_release(&rose_callsign, NULL);
+ if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address)))
+ return -EFAULT;
+ if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
+ ax25_listen_register(&rose_callsign, NULL);
+ return 0;
- case SIOCRSSL2CALL:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
- ax25_listen_release(&rose_callsign, NULL);
- if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address)))
- return -EFAULT;
- if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
- ax25_listen_register(&rose_callsign, NULL);
- return 0;
-
- case SIOCRSGL2CALL:
- return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0;
-
- case SIOCRSACCEPT:
- if (rose->state == ROSE_STATE_5) {
- rose_write_internal(sk, ROSE_CALL_ACCEPTED);
- rose_start_idletimer(sk);
- rose->condition = 0x00;
- rose->vs = 0;
- rose->va = 0;
- rose->vr = 0;
- rose->vl = 0;
- rose->state = ROSE_STATE_3;
- }
- return 0;
+ case SIOCRSGL2CALL:
+ return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0;
+
+ case SIOCRSACCEPT:
+ if (rose->state == ROSE_STATE_5) {
+ rose_write_internal(sk, ROSE_CALL_ACCEPTED);
+ rose_start_idletimer(sk);
+ rose->condition = 0x00;
+ rose->vs = 0;
+ rose->va = 0;
+ rose->vr = 0;
+ rose->vl = 0;
+ rose->state = ROSE_STATE_3;
+ }
+ return 0;
- default:
- return dev_ioctl(cmd, (void *)arg);
+ default:
+ return dev_ioctl(cmd, (void *)arg);
}
- /*NOTREACHED*/
return 0;
}
@@ -1366,7 +1363,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
off_t begin = 0;
- cli();
+ spin_lock_bh(&rose_list_lock);
len += sprintf(buffer, "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n");
@@ -1390,7 +1387,7 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %05d %d %d %d %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
rose2asc(&rose->source_addr),
callsign,
- devname,
+ devname,
rose->lci & 0x0FFF,
(rose->neighbour) ? rose->neighbour->number : 0,
rose->state,
@@ -1418,48 +1415,44 @@ static int rose_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length)
break;
}
-
- sti();
+ spin_unlock_bh(&rose_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
if (len > length) len = length;
- return(len);
-}
+ return len;
+}
static struct net_proto_family rose_family_ops = {
- .family = PF_ROSE,
- .create = rose_create,
+ .family = PF_ROSE,
+ .create = rose_create,
};
-static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = {
- .family = PF_ROSE,
-
- .release = rose_release,
- .bind = rose_bind,
- .connect = rose_connect,
- .socketpair = sock_no_socketpair,
- .accept = rose_accept,
- .getname = rose_getname,
- .poll = datagram_poll,
- .ioctl = rose_ioctl,
- .listen = rose_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = rose_setsockopt,
- .getsockopt = rose_getsockopt,
- .sendmsg = rose_sendmsg,
- .recvmsg = rose_recvmsg,
- .mmap = sock_no_mmap,
- .sendpage = sock_no_sendpage,
+static struct proto_ops rose_proto_ops = {
+ .family = PF_ROSE,
+
+ .release = rose_release,
+ .bind = rose_bind,
+ .connect = rose_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = rose_accept,
+ .getname = rose_getname,
+ .poll = datagram_poll,
+ .ioctl = rose_ioctl,
+ .listen = rose_listen,
+ .shutdown = sock_no_shutdown,
+ .setsockopt = rose_setsockopt,
+ .getsockopt = rose_getsockopt,
+ .sendmsg = rose_sendmsg,
+ .recvmsg = rose_recvmsg,
+ .mmap = sock_no_mmap,
+ .sendpage = sock_no_sendpage,
};
-#include <linux/smp_lock.h>
-SOCKOPS_WRAP(rose_proto, PF_ROSE);
-
static struct notifier_block rose_dev_notifier = {
- .notifier_call =rose_device_event,
+ .notifier_call = rose_device_event,
};
static struct net_device *dev_rose;
@@ -1555,5 +1548,5 @@ static void __exit rose_exit(void)
kfree(dev_rose);
}
-module_exit(rose_exit);
+module_exit(rose_exit);
diff --git a/net/rose/rose_dev.c b/net/rose/rose_dev.c
index e50bda038c3b..befeaac63937 100644
--- a/net/rose/rose_dev.c
+++ b/net/rose/rose_dev.c
@@ -1,19 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
@@ -29,7 +21,7 @@
#include <linux/errno.h>
#include <linux/fcntl.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/io.h>
diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c
index 4c5bbb54d534..48e09cded78e 100644
--- a/net/rose/rose_in.c
+++ b/net/rose/rose_in.c
@@ -1,27 +1,16 @@
/*
- * 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.
- *
- * 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
- * ROSE 001 Jonathan(G4KLX) Cloned from nr_in.c
- * ROSE 002 Jonathan(G4KLX) Return cause and diagnostic codes from Clear Requests.
- * ROSE 003 Jonathan(G4KLX) New timer architecture.
- * Removed M bit processing.
+ * 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.
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -55,29 +44,28 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_cb *rose = rose_sk(sk);
switch (frametype) {
+ case ROSE_CALL_ACCEPTED:
+ rose_stop_timer(sk);
+ rose_start_idletimer(sk);
+ rose->condition = 0x00;
+ rose->vs = 0;
+ rose->va = 0;
+ rose->vr = 0;
+ rose->vl = 0;
+ rose->state = ROSE_STATE_3;
+ sk->state = TCP_ESTABLISHED;
+ if (!sk->dead)
+ sk->state_change(sk);
+ break;
+
+ case ROSE_CLEAR_REQUEST:
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
+ rose->neighbour->use--;
+ break;
- case ROSE_CALL_ACCEPTED:
- rose_stop_timer(sk);
- rose_start_idletimer(sk);
- rose->condition = 0x00;
- rose->vs = 0;
- rose->va = 0;
- rose->vr = 0;
- rose->vl = 0;
- rose->state = ROSE_STATE_3;
- sk->state = TCP_ESTABLISHED;
- if (!sk->dead)
- sk->state_change(sk);
- break;
-
- case ROSE_CLEAR_REQUEST:
- rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
- rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
- rose->neighbour->use--;
- break;
-
- default:
- break;
+ default:
+ break;
}
return 0;
@@ -93,20 +81,19 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_cb *rose = rose_sk(sk);
switch (frametype) {
+ case ROSE_CLEAR_REQUEST:
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ rose->neighbour->use--;
+ break;
- case ROSE_CLEAR_REQUEST:
- rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
- rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
- rose->neighbour->use--;
- break;
-
- case ROSE_CLEAR_CONFIRMATION:
- rose_disconnect(sk, 0, -1, -1);
- rose->neighbour->use--;
- break;
+ case ROSE_CLEAR_CONFIRMATION:
+ rose_disconnect(sk, 0, -1, -1);
+ rose->neighbour->use--;
+ break;
- default:
- break;
+ default:
+ break;
}
return 0;
@@ -123,50 +110,68 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
int queued = 0;
switch (frametype) {
+ case ROSE_RESET_REQUEST:
+ rose_stop_timer(sk);
+ rose_start_idletimer(sk);
+ rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
+ rose->condition = 0x00;
+ rose->vs = 0;
+ rose->vr = 0;
+ rose->va = 0;
+ rose->vl = 0;
+ rose_requeue_frames(sk);
+ break;
+
+ case ROSE_CLEAR_REQUEST:
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ rose->neighbour->use--;
+ break;
- case ROSE_RESET_REQUEST:
- rose_stop_timer(sk);
- rose_start_idletimer(sk);
- rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
+ case ROSE_RR:
+ case ROSE_RNR:
+ if (!rose_validate_nr(sk, nr)) {
+ rose_write_internal(sk, ROSE_RESET_REQUEST);
rose->condition = 0x00;
rose->vs = 0;
rose->vr = 0;
rose->va = 0;
rose->vl = 0;
- rose_requeue_frames(sk);
- break;
-
- case ROSE_CLEAR_REQUEST:
- rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
- rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
- rose->neighbour->use--;
- break;
-
- case ROSE_RR:
- case ROSE_RNR:
- if (!rose_validate_nr(sk, nr)) {
- rose_write_internal(sk, ROSE_RESET_REQUEST);
- rose->condition = 0x00;
- rose->vs = 0;
- rose->vr = 0;
- rose->va = 0;
- rose->vl = 0;
- rose->state = ROSE_STATE_4;
- rose_start_t2timer(sk);
- rose_stop_idletimer(sk);
+ rose->state = ROSE_STATE_4;
+ rose_start_t2timer(sk);
+ rose_stop_idletimer(sk);
+ } else {
+ rose_frames_acked(sk, nr);
+ if (frametype == ROSE_RNR) {
+ rose->condition |= ROSE_COND_PEER_RX_BUSY;
} else {
- rose_frames_acked(sk, nr);
- if (frametype == ROSE_RNR) {
- rose->condition |= ROSE_COND_PEER_RX_BUSY;
- } else {
- rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
- }
+ rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
}
- break;
+ }
+ break;
- case ROSE_DATA: /* XXX */
- rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
- if (!rose_validate_nr(sk, nr)) {
+ case ROSE_DATA: /* XXX */
+ rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
+ if (!rose_validate_nr(sk, nr)) {
+ rose_write_internal(sk, ROSE_RESET_REQUEST);
+ rose->condition = 0x00;
+ rose->vs = 0;
+ rose->vr = 0;
+ rose->va = 0;
+ rose->vl = 0;
+ rose->state = ROSE_STATE_4;
+ rose_start_t2timer(sk);
+ rose_stop_idletimer(sk);
+ break;
+ }
+ rose_frames_acked(sk, nr);
+ if (ns == rose->vr) {
+ rose_start_idletimer(sk);
+ if (sock_queue_rcv_skb(sk, skb) == 0) {
+ rose->vr = (rose->vr + 1) % ROSE_MODULUS;
+ queued = 1;
+ } else {
+ /* Should never happen ! */
rose_write_internal(sk, ROSE_RESET_REQUEST);
rose->condition = 0x00;
rose->vs = 0;
@@ -178,45 +183,26 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_stop_idletimer(sk);
break;
}
- rose_frames_acked(sk, nr);
- if (ns == rose->vr) {
- rose_start_idletimer(sk);
- if (sock_queue_rcv_skb(sk, skb) == 0) {
- rose->vr = (rose->vr + 1) % ROSE_MODULUS;
- queued = 1;
- } else {
- /* Should never happen ! */
- rose_write_internal(sk, ROSE_RESET_REQUEST);
- rose->condition = 0x00;
- rose->vs = 0;
- rose->vr = 0;
- rose->va = 0;
- rose->vl = 0;
- rose->state = ROSE_STATE_4;
- rose_start_t2timer(sk);
- rose_stop_idletimer(sk);
- break;
- }
- if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2))
- rose->condition |= ROSE_COND_OWN_RX_BUSY;
- }
- /*
- * If the window is full, ack the frame, else start the
- * acknowledge hold back timer.
- */
- if (((rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == rose->vr) {
- rose->condition &= ~ROSE_COND_ACK_PENDING;
- rose_stop_timer(sk);
- rose_enquiry_response(sk);
- } else {
- rose->condition |= ROSE_COND_ACK_PENDING;
- rose_start_hbtimer(sk);
- }
- break;
-
- default:
- printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype);
- break;
+ if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2))
+ rose->condition |= ROSE_COND_OWN_RX_BUSY;
+ }
+ /*
+ * If the window is full, ack the frame, else start the
+ * acknowledge hold back timer.
+ */
+ if (((rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == rose->vr) {
+ rose->condition &= ~ROSE_COND_ACK_PENDING;
+ rose_stop_timer(sk);
+ rose_enquiry_response(sk);
+ } else {
+ rose->condition |= ROSE_COND_ACK_PENDING;
+ rose_start_hbtimer(sk);
+ }
+ break;
+
+ default:
+ printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype);
+ break;
}
return queued;
@@ -232,29 +218,28 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety
rose_cb *rose = rose_sk(sk);
switch (frametype) {
+ case ROSE_RESET_REQUEST:
+ rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
+ case ROSE_RESET_CONFIRMATION:
+ rose_stop_timer(sk);
+ rose_start_idletimer(sk);
+ rose->condition = 0x00;
+ rose->va = 0;
+ rose->vr = 0;
+ rose->vs = 0;
+ rose->vl = 0;
+ rose->state = ROSE_STATE_3;
+ rose_requeue_frames(sk);
+ break;
+
+ case ROSE_CLEAR_REQUEST:
+ rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+ rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+ rose->neighbour->use--;
+ break;
- case ROSE_RESET_REQUEST:
- rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
- case ROSE_RESET_CONFIRMATION:
- rose_stop_timer(sk);
- rose_start_idletimer(sk);
- rose->condition = 0x00;
- rose->va = 0;
- rose->vr = 0;
- rose->vs = 0;
- rose->vl = 0;
- rose->state = ROSE_STATE_3;
- rose_requeue_frames(sk);
- break;
-
- case ROSE_CLEAR_REQUEST:
- rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
- rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
- rose->neighbour->use--;
- break;
-
- default:
- break;
+ default:
+ break;
}
return 0;
@@ -288,21 +273,21 @@ int rose_process_rx_frame(struct sock *sk, struct sk_buff *skb)
frametype = rose_decode(skb, &ns, &nr, &q, &d, &m);
switch (rose->state) {
- case ROSE_STATE_1:
- queued = rose_state1_machine(sk, skb, frametype);
- break;
- case ROSE_STATE_2:
- queued = rose_state2_machine(sk, skb, frametype);
- break;
- case ROSE_STATE_3:
- queued = rose_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
- break;
- case ROSE_STATE_4:
- queued = rose_state4_machine(sk, skb, frametype);
- break;
- case ROSE_STATE_5:
- queued = rose_state5_machine(sk, skb, frametype);
- break;
+ case ROSE_STATE_1:
+ queued = rose_state1_machine(sk, skb, frametype);
+ break;
+ case ROSE_STATE_2:
+ queued = rose_state2_machine(sk, skb, frametype);
+ break;
+ case ROSE_STATE_3:
+ queued = rose_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
+ break;
+ case ROSE_STATE_4:
+ queued = rose_state4_machine(sk, skb, frametype);
+ break;
+ case ROSE_STATE_5:
+ queued = rose_state5_machine(sk, skb, frametype);
+ break;
}
rose_kick(sk);
diff --git a/net/rose/rose_link.c b/net/rose/rose_link.c
index 3935526edc3a..8974778d70d7 100644
--- a/net/rose/rose_link.c
+++ b/net/rose/rose_link.c
@@ -1,19 +1,11 @@
/*
- * 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
- *
- * 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.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -142,25 +134,25 @@ void rose_link_rx_restart(struct sk_buff *skb, struct rose_neigh *neigh, unsigne
struct sk_buff *skbn;
switch (frametype) {
- case ROSE_RESTART_REQUEST:
- rose_stop_t0timer(neigh);
- neigh->restarted = 1;
- neigh->dce_mode = (skb->data[3] == ROSE_DTE_ORIGINATED);
- rose_transmit_restart_confirmation(neigh);
- break;
-
- case ROSE_RESTART_CONFIRMATION:
- rose_stop_t0timer(neigh);
- neigh->restarted = 1;
- break;
-
- case ROSE_DIAGNOSTIC:
- printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
- break;
-
- default:
- printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype);
- break;
+ case ROSE_RESTART_REQUEST:
+ rose_stop_t0timer(neigh);
+ neigh->restarted = 1;
+ neigh->dce_mode = (skb->data[3] == ROSE_DTE_ORIGINATED);
+ rose_transmit_restart_confirmation(neigh);
+ break;
+
+ case ROSE_RESTART_CONFIRMATION:
+ rose_stop_t0timer(neigh);
+ neigh->restarted = 1;
+ break;
+
+ case ROSE_DIAGNOSTIC:
+ printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
+ break;
+
+ default:
+ printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype);
+ break;
}
if (neigh->restarted) {
diff --git a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c
index ad00608a3911..103b4d38f88a 100644
--- a/net/rose/rose_loopback.c
+++ b/net/rose/rose_loopback.c
@@ -1,19 +1,11 @@
/*
- * ROSE release 003
- *
- * This code REQUIRES 2.1.15 or higher/ NET3.038
- *
- * 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 003 Jonathan(G4KLX) Created this file from nr_loopback.c.
+ * 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.
*
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
diff --git a/net/rose/rose_out.c b/net/rose/rose_out.c
index 5f7f7885203a..3583963560ed 100644
--- a/net/rose/rose_out.c
+++ b/net/rose/rose_out.c
@@ -1,20 +1,11 @@
/*
- * 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
- *
- * 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_out.c
- * ROSE 003 Jonathan(G4KLX) New timer architecture.
- * Removed M bit processing.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -36,7 +27,7 @@
#include <linux/interrupt.h>
#include <net/rose.h>
-/*
+/*
* This procedure is passed a buffer descriptor for an iframe. It builds
* the rest of the control part of the frame and then writes it out.
*/
@@ -52,7 +43,7 @@ static void rose_send_iframe(struct sock *sk, struct sk_buff *skb)
rose_start_idletimer(sk);
- rose_transmit_link(skb, rose->neighbour);
+ rose_transmit_link(skb, rose->neighbour);
}
void rose_kick(struct sock *sk)
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index e004ea29a9b7..f96ccecfcd81 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -1,24 +1,12 @@
/*
- * 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
- *
- * 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_route.c.
- * Terry(VK2KTJ) Added support for variable length
- * address masks.
- * ROSE 002 Jonathan(G4KLX) Uprated through routing of packets.
- * Routing loop detection.
- * ROSE 003 Jonathan(G4KLX) New timer architecture.
- * Added use count to neighbours.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -51,8 +39,11 @@
static unsigned int rose_neigh_no = 1;
static struct rose_node *rose_node_list;
+static spinlock_t rose_node_list_lock = SPIN_LOCK_UNLOCKED;
static struct rose_neigh *rose_neigh_list;
+static spinlock_t rose_neigh_list_lock = SPIN_LOCK_UNLOCKED;
static struct rose_route *rose_route_list;
+static spinlock_t rose_route_list_lock = SPIN_LOCK_UNLOCKED;
struct rose_neigh *rose_loopback_neigh;
@@ -62,27 +53,44 @@ static void rose_remove_neigh(struct rose_neigh *);
* Add a new route to a node, and in the process add the node and the
* neighbour if it is new.
*/
-static int rose_add_node(struct rose_route_struct *rose_route, struct net_device *dev)
+static int rose_add_node(struct rose_route_struct *rose_route,
+ struct net_device *dev)
{
struct rose_node *rose_node, *rose_tmpn, *rose_tmpp;
struct rose_neigh *rose_neigh;
- unsigned long flags;
- int i;
+ int i, res = 0;
+
+ spin_lock_bh(&rose_node_list_lock);
+ spin_lock_bh(&rose_neigh_list_lock);
- for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
- if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
+ rose_node = rose_node_list;
+ while (rose_node != NULL) {
+ if ((rose_node->mask == rose_route->mask) &&
+ (rosecmpm(&rose_route->address, &rose_node->address,
+ rose_route->mask) == 0))
break;
+ rose_node = rose_node->next;
+ }
- if (rose_node != NULL && rose_node->loopback)
- return -EINVAL;
+ if (rose_node != NULL && rose_node->loopback) {
+ res = -EINVAL;
+ goto out;
+ }
- for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
- if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
+ rose_neigh = rose_neigh_list;
+ while (rose_neigh != NULL) {
+ if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
+ && rose_neigh->dev == dev)
break;
+ rose_neigh = rose_neigh->next;
+ }
if (rose_neigh == NULL) {
- if ((rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
+ rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC);
+ if (rose_neigh == NULL) {
+ res = -ENOMEM;
+ goto out;
+ }
rose_neigh->callsign = rose_route->neighbour;
rose_neigh->digipeat = NULL;
@@ -103,22 +111,22 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
if (rose_route->ndigis != 0) {
if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
kfree(rose_neigh);
- return -ENOMEM;
+ res = -ENOMEM;
+ goto out;
}
rose_neigh->digipeat->ndigi = rose_route->ndigis;
rose_neigh->digipeat->lastrepeat = -1;
for (i = 0; i < rose_route->ndigis; i++) {
- rose_neigh->digipeat->calls[i] = rose_route->digipeaters[i];
+ rose_neigh->digipeat->calls[i] =
+ rose_route->digipeaters[i];
rose_neigh->digipeat->repeated[i] = 0;
}
}
- save_flags(flags); cli();
rose_neigh->next = rose_neigh_list;
rose_neigh_list = rose_neigh;
- restore_flags(flags);
}
/*
@@ -142,8 +150,11 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
}
/* create new node */
- if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
+ rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC);
+ if (rose_node == NULL) {
+ res = -ENOMEM;
+ goto out;
+ }
rose_node->address = rose_route->address;
rose_node->mask = rose_route->mask;
@@ -151,8 +162,6 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_node->loopback = 0;
rose_node->neighbour[0] = rose_neigh;
- save_flags(flags); cli();
-
if (rose_tmpn == NULL) {
if (rose_tmpp == NULL) { /* Empty list */
rose_node_list = rose_node;
@@ -170,12 +179,9 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_node->next = rose_tmpn;
}
}
-
- restore_flags(flags);
-
rose_neigh->count++;
- return 0;
+ goto out;
}
/* We have space, slot it in */
@@ -185,20 +191,23 @@ static int rose_add_node(struct rose_route_struct *rose_route, struct net_device
rose_neigh->count++;
}
- return 0;
+out:
+ spin_unlock_bh(&rose_neigh_list_lock);
+ spin_unlock_bh(&rose_node_list_lock);
+
+ return res;
}
+/*
+ * Caller is holding rose_node_list_lock.
+ */
static void rose_remove_node(struct rose_node *rose_node)
{
struct rose_node *s;
- unsigned long flags;
-
- save_flags(flags);
- cli();
+ spin_lock_bh(&rose_node_list_lock);
if ((s = rose_node_list) == rose_node) {
rose_node_list = rose_node->next;
- restore_flags(flags);
kfree(rose_node);
return;
}
@@ -206,32 +215,31 @@ static void rose_remove_node(struct rose_node *rose_node)
while (s != NULL && s->next != NULL) {
if (s->next == rose_node) {
s->next = rose_node->next;
- restore_flags(flags);
kfree(rose_node);
return;
}
s = s->next;
}
-
- restore_flags(flags);
}
+/*
+ * Caller is holding rose_neigh_list_lock.
+ */
static void rose_remove_neigh(struct rose_neigh *rose_neigh)
{
struct rose_neigh *s;
- unsigned long flags;
rose_stop_ftimer(rose_neigh);
rose_stop_t0timer(rose_neigh);
skb_queue_purge(&rose_neigh->queue);
- save_flags(flags); cli();
+ spin_lock_bh(&rose_neigh_list_lock);
if ((s = rose_neigh_list) == rose_neigh) {
rose_neigh_list = rose_neigh->next;
- restore_flags(flags);
+ spin_unlock_bh(&rose_neigh_list_lock);
if (rose_neigh->digipeat != NULL)
kfree(rose_neigh->digipeat);
kfree(rose_neigh);
@@ -241,7 +249,7 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
while (s != NULL && s->next != NULL) {
if (s->next == rose_neigh) {
s->next = rose_neigh->next;
- restore_flags(flags);
+ spin_unlock_bh(&rose_neigh_list_lock);
if (rose_neigh->digipeat != NULL)
kfree(rose_neigh->digipeat);
kfree(rose_neigh);
@@ -250,14 +258,15 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
s = s->next;
}
-
- restore_flags(flags);
+ spin_unlock_bh(&rose_neigh_list_lock);
}
+/*
+ * Caller is holding rose_route_list_lock.
+ */
static void rose_remove_route(struct rose_route *rose_route)
{
struct rose_route *s;
- unsigned long flags;
if (rose_route->neigh1 != NULL)
rose_route->neigh1->use--;
@@ -265,11 +274,8 @@ static void rose_remove_route(struct rose_route *rose_route)
if (rose_route->neigh2 != NULL)
rose_route->neigh2->use--;
- save_flags(flags); cli();
-
if ((s = rose_route_list) == rose_route) {
rose_route_list = rose_route->next;
- restore_flags(flags);
kfree(rose_route);
return;
}
@@ -277,40 +283,54 @@ static void rose_remove_route(struct rose_route *rose_route)
while (s != NULL && s->next != NULL) {
if (s->next == rose_route) {
s->next = rose_route->next;
- restore_flags(flags);
kfree(rose_route);
return;
}
s = s->next;
}
-
- restore_flags(flags);
}
/*
* "Delete" a node. Strictly speaking remove a route to a node. The node
* is only deleted if no routes are left to it.
*/
-static int rose_del_node(struct rose_route_struct *rose_route, struct net_device *dev)
+static int rose_del_node(struct rose_route_struct *rose_route,
+ struct net_device *dev)
{
struct rose_node *rose_node;
struct rose_neigh *rose_neigh;
- int i;
+ int i, err = 0;
- for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
- if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
- break;
+ spin_lock_bh(&rose_node_list_lock);
+ spin_lock_bh(&rose_neigh_list_lock);
- if (rose_node == NULL) return -EINVAL;
+ rose_node = rose_node_list;
+ while (rose_node != NULL) {
+ if ((rose_node->mask == rose_route->mask) &&
+ (rosecmpm(&rose_route->address, &rose_node->address,
+ rose_route->mask) == 0))
+ break;
+ rose_node = rose_node->next;
+ }
- if (rose_node->loopback) return -EINVAL;
+ if (rose_node == NULL || rose_node->loopback) {
+ err = -EINVAL;
+ goto out;
+ }
- for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
- if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
+ rose_neigh = rose_neigh_list;
+ while (rose_neigh != NULL) {
+ if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
+ && rose_neigh->dev == dev)
break;
+ rose_neigh = rose_neigh->next;
+ }
- if (rose_neigh == NULL) return -EINVAL;
+ if (rose_neigh == NULL) {
+ err = -EINVAL;
+ goto out;
+ }
for (i = 0; i < rose_node->count; i++) {
if (rose_node->neighbour[i] == rose_neigh) {
@@ -325,20 +345,26 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
rose_remove_node(rose_node);
} else {
switch (i) {
- case 0:
- rose_node->neighbour[0] = rose_node->neighbour[1];
- case 1:
- rose_node->neighbour[1] = rose_node->neighbour[2];
- case 2:
- break;
+ case 0:
+ rose_node->neighbour[0] =
+ rose_node->neighbour[1];
+ case 1:
+ rose_node->neighbour[1] =
+ rose_node->neighbour[2];
+ case 2:
+ break;
}
}
-
- return 0;
+ goto out;
}
}
+ err = -EINVAL;
+
+out:
+ spin_unlock_bh(&rose_neigh_list_lock);
+ spin_unlock_bh(&rose_node_list_lock);
- return -EINVAL;
+ return err;
}
/*
@@ -346,8 +372,6 @@ static int rose_del_node(struct rose_route_struct *rose_route, struct net_device
*/
int rose_add_loopback_neigh(void)
{
- unsigned long flags;
-
if ((rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_ATOMIC)) == NULL)
return -ENOMEM;
@@ -367,10 +391,10 @@ int rose_add_loopback_neigh(void)
init_timer(&rose_loopback_neigh->ftimer);
init_timer(&rose_loopback_neigh->t0timer);
- save_flags(flags); cli();
+ spin_lock_bh(&rose_neigh_list_lock);
rose_loopback_neigh->next = rose_neigh_list;
rose_neigh_list = rose_loopback_neigh;
- restore_flags(flags);
+ spin_unlock_bh(&rose_neigh_list_lock);
return 0;
}
@@ -381,16 +405,26 @@ int rose_add_loopback_neigh(void)
int rose_add_loopback_node(rose_address *address)
{
struct rose_node *rose_node;
- unsigned long flags;
+ unsigned int err = 0;
- for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
- if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
+ spin_lock_bh(&rose_node_list_lock);
+
+ rose_node = rose_node_list;
+ while (rose_node != NULL) {
+ if ((rose_node->mask == 10) &&
+ (rosecmpm(address, &rose_node->address, 10) == 0) &&
+ rose_node->loopback)
break;
+ rose_node = rose_node->next;
+ }
- if (rose_node != NULL) return 0;
-
- if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
+ if (rose_node != NULL)
+ goto out;
+
+ if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
rose_node->address = *address;
rose_node->mask = 10;
@@ -399,13 +433,14 @@ int rose_add_loopback_node(rose_address *address)
rose_node->neighbour[0] = rose_loopback_neigh;
/* Insert at the head of list. Address is always mask=10 */
- save_flags(flags); cli();
rose_node->next = rose_node_list;
rose_node_list = rose_node;
- restore_flags(flags);
rose_loopback_neigh->count++;
+out:
+ spin_unlock_bh(&rose_node_list_lock);
+
return 0;
}
@@ -416,15 +451,26 @@ void rose_del_loopback_node(rose_address *address)
{
struct rose_node *rose_node;
- for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
- if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
+ spin_lock_bh(&rose_node_list_lock);
+
+ rose_node = rose_node_list;
+ while (rose_node != NULL) {
+ if ((rose_node->mask == 10) &&
+ (rosecmpm(address, &rose_node->address, 10) == 0) &&
+ rose_node->loopback)
break;
+ rose_node = rose_node->next;
+ }
- if (rose_node == NULL) return;
+ if (rose_node == NULL)
+ goto out;
rose_remove_node(rose_node);
rose_loopback_neigh->count--;
+
+out:
+ spin_unlock_bh(&rose_node_list_lock);
}
/*
@@ -432,52 +478,62 @@ void rose_del_loopback_node(rose_address *address)
*/
void rose_rt_device_down(struct net_device *dev)
{
- struct rose_neigh *s, *rose_neigh = rose_neigh_list;
+ struct rose_neigh *s, *rose_neigh;
struct rose_node *t, *rose_node;
int i;
+ spin_lock_bh(&rose_node_list_lock);
+ spin_lock_bh(&rose_neigh_list_lock);
+ rose_neigh = rose_neigh_list;
while (rose_neigh != NULL) {
s = rose_neigh;
rose_neigh = rose_neigh->next;
- if (s->dev == dev) {
- rose_node = rose_node_list;
-
- while (rose_node != NULL) {
- t = rose_node;
- rose_node = rose_node->next;
-
- for (i = 0; i < t->count; i++) {
- if (t->neighbour[i] == s) {
- t->count--;
-
- switch (i) {
- case 0:
- t->neighbour[0] = t->neighbour[1];
- case 1:
- t->neighbour[1] = t->neighbour[2];
- case 2:
- break;
- }
- }
- }
+ if (s->dev != dev)
+ continue;
+
+ rose_node = rose_node_list;
+
+ while (rose_node != NULL) {
+ t = rose_node;
+ rose_node = rose_node->next;
+
+ for (i = 0; i < t->count; i++) {
+ if (t->neighbour[i] != s)
+ continue;
+
+ t->count--;
- if (t->count <= 0)
- rose_remove_node(t);
+ switch (i) {
+ case 0:
+ t->neighbour[0] = t->neighbour[1];
+ case 1:
+ t->neighbour[1] = t->neighbour[2];
+ case 2:
+ break;
+ }
}
- rose_remove_neigh(s);
+ if (t->count <= 0)
+ rose_remove_node(t);
}
+
+ rose_remove_neigh(s);
}
+ spin_unlock_bh(&rose_neigh_list_lock);
+ spin_unlock_bh(&rose_node_list_lock);
}
+#if 0 /* Currently unused */
/*
* A device has been removed. Remove its links.
*/
void rose_route_device_down(struct net_device *dev)
{
- struct rose_route *s, *rose_route = rose_route_list;
+ struct rose_route *s, *rose_route;
+ spin_lock_bh(&rose_route_list_lock);
+ rose_route = rose_route_list;
while (rose_route != NULL) {
s = rose_route;
rose_route = rose_route->next;
@@ -485,7 +541,9 @@ void rose_route_device_down(struct net_device *dev)
if (s->neigh1->dev == dev || s->neigh2->dev == dev)
rose_remove_route(s);
}
+ spin_unlock_bh(&rose_route_list_lock);
}
+#endif
/*
* Clear all nodes and neighbours out, except for neighbours with
@@ -494,8 +552,14 @@ void rose_route_device_down(struct net_device *dev)
*/
static int rose_clear_routes(void)
{
- struct rose_neigh *s, *rose_neigh = rose_neigh_list;
- struct rose_node *t, *rose_node = rose_node_list;
+ struct rose_neigh *s, *rose_neigh;
+ struct rose_node *t, *rose_node;
+
+ spin_lock_bh(&rose_node_list_lock);
+ spin_lock_bh(&rose_neigh_list_lock);
+
+ rose_neigh = rose_neigh_list;
+ rose_node = rose_node_list;
while (rose_node != NULL) {
t = rose_node;
@@ -514,6 +578,9 @@ static int rose_clear_routes(void)
}
}
+ spin_unlock_bh(&rose_neigh_list_lock);
+ spin_unlock_bh(&rose_node_list_lock);
+
return 0;
}
@@ -603,18 +670,22 @@ struct rose_route *rose_route_free_lci(unsigned int lci, struct rose_neigh *neig
/*
* Find a neighbour given a ROSE address.
*/
-struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsigned char *diagnostic)
+struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
+ unsigned char *diagnostic)
{
+ struct rose_neigh *res = NULL;
struct rose_node *node;
int failed = 0;
int i;
+ spin_lock_bh(&rose_node_list_lock);
for (node = rose_node_list; node != NULL; node = node->next) {
if (rosecmpm(addr, &node->address, node->mask) == 0) {
for (i = 0; i < node->count; i++) {
if (!rose_ftimer_running(node->neighbour[i])) {
- return node->neighbour[i]; }
- else
+ res = node->neighbour[i];
+ goto out;
+ } else
failed = 1;
}
break;
@@ -629,7 +700,10 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsi
*diagnostic = 0;
}
- return NULL;
+out:
+ spin_unlock_bh(&rose_node_list_lock);
+
+ return res;
}
/*
@@ -642,38 +716,36 @@ int rose_rt_ioctl(unsigned int cmd, void *arg)
int err;
switch (cmd) {
-
- case SIOCADDRT:
- if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
- return -EFAULT;
- if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
- return -EINVAL;
- if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */
- dev_put(dev);
- return -EINVAL;
- }
- if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
- return -EINVAL;
-
- err = rose_add_node(&rose_route, dev);
- dev_put(dev);
- return err;
-
- case SIOCDELRT:
- if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
- return -EFAULT;
- if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
- return -EINVAL;
- err = rose_del_node(&rose_route, dev);
+ case SIOCADDRT:
+ if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
+ return -EFAULT;
+ if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
+ return -EINVAL;
+ if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */
dev_put(dev);
- return err;
-
+ return -EINVAL;
+ }
+ if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
+ return -EINVAL;
- case SIOCRSCLRRT:
- return rose_clear_routes();
+ err = rose_add_node(&rose_route, dev);
+ dev_put(dev);
+ return err;
- default:
+ case SIOCDELRT:
+ if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
+ return -EFAULT;
+ if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
return -EINVAL;
+ err = rose_del_node(&rose_route, dev);
+ dev_put(dev);
+ return err;
+
+ case SIOCRSCLRRT:
+ return rose_clear_routes();
+
+ default:
+ return -EINVAL;
}
return 0;
@@ -690,6 +762,8 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
skb_queue_purge(&rose_neigh->queue);
+ spin_lock_bh(&rose_route_list_lock);
+
rose_route = rose_route_list;
while (rose_route != NULL) {
@@ -716,6 +790,7 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh)
rose_route = rose_route->next;
}
+ spin_unlock_bh(&rose_route_list_lock);
}
/*
@@ -727,16 +802,21 @@ void rose_link_failed(ax25_cb *ax25, int reason)
{
struct rose_neigh *rose_neigh;
- for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
+ spin_lock_bh(&rose_neigh_list_lock);
+ rose_neigh = rose_neigh_list;
+ while (rose_neigh != NULL) {
if (rose_neigh->ax25 == ax25)
break;
+ rose_neigh = rose_neigh->next;
+ }
- if (rose_neigh == NULL) return;
-
- rose_neigh->ax25 = NULL;
+ if (rose_neigh != NULL) {
+ rose_neigh->ax25 = NULL;
- rose_del_route_by_neigh(rose_neigh);
- rose_kill_by_neigh(rose_neigh);
+ rose_del_route_by_neigh(rose_neigh);
+ rose_kill_by_neigh(rose_neigh);
+ }
+ spin_unlock_bh(&rose_neigh_list_lock);
}
/*
@@ -769,12 +849,11 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
unsigned int lci, new_lci;
unsigned char cause, diagnostic;
struct net_device *dev;
- unsigned long flags;
- int len;
+ int len, res = 0;
#if 0
if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
- return 0;
+ return res;
#endif
frametype = skb->data[2];
@@ -782,13 +861,22 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
src_addr = (rose_address *)(skb->data + 9);
dest_addr = (rose_address *)(skb->data + 4);
- for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
- if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->ax25_dev->dev == rose_neigh->dev)
+ spin_lock_bh(&rose_node_list_lock);
+ spin_lock_bh(&rose_neigh_list_lock);
+ spin_lock_bh(&rose_route_list_lock);
+
+ rose_neigh = rose_neigh_list;
+ while (rose_neigh != NULL) {
+ if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 &&
+ ax25->ax25_dev->dev == rose_neigh->dev)
break;
+ rose_neigh = rose_neigh->next;
+ }
if (rose_neigh == NULL) {
- printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->dest_addr));
- return 0;
+ printk("rose_route : unknown neighbour or device %s\n",
+ ax2asc(&ax25->dest_addr));
+ goto out;
}
/*
@@ -802,7 +890,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
*/
if (lci == 0) {
rose_link_rx_restart(skb, rose_neigh, frametype);
- return 0;
+ goto out;
}
/*
@@ -828,7 +916,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
}
else {
skb->h.raw = skb->data;
- return rose_process_rx_frame(sk, skb);
+ res = rose_process_rx_frame(sk, skb);
+ goto out;
}
}
@@ -837,21 +926,23 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
*/
if (frametype == ROSE_CALL_REQUEST)
if ((dev = rose_dev_get(dest_addr)) != NULL) {
- int err = rose_rx_call_request(skb, dev, rose_neigh, lci);
+ res = rose_rx_call_request(skb, dev, rose_neigh, lci);
dev_put(dev);
- return err;
+ goto out;
}
if (!sysctl_rose_routing_control) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0);
- return 0;
+ goto out;
}
/*
* Route it to the next in line if we have an entry for it.
*/
- for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
- if (rose_route->lci1 == lci && rose_route->neigh1 == rose_neigh) {
+ rose_route = rose_route_list;
+ while (rose_route != NULL) {
+ if (rose_route->lci1 == lci &&
+ rose_route->neigh1 == rose_neigh) {
if (frametype == ROSE_CALL_REQUEST) {
/* F6FBB - Remove an existing unused route */
rose_remove_route(rose_route);
@@ -863,14 +954,16 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_transmit_link(skb, rose_route->neigh2);
if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route);
- return 1;
+ res = 1;
+ goto out;
} else {
if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route);
- return 0;
+ goto out;
}
}
- if (rose_route->lci2 == lci && rose_route->neigh2 == rose_neigh) {
+ if (rose_route->lci2 == lci &&
+ rose_route->neigh2 == rose_neigh) {
if (frametype == ROSE_CALL_REQUEST) {
/* F6FBB - Remove an existing unused route */
rose_remove_route(rose_route);
@@ -882,13 +975,15 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_transmit_link(skb, rose_route->neigh1);
if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route);
- return 1;
+ res = 1;
+ goto out;
} else {
if (frametype == ROSE_CLEAR_CONFIRMATION)
rose_remove_route(rose_route);
- return 0;
+ goto out;
}
}
+ rose_route = rose_route->next;
}
/*
@@ -903,38 +998,40 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
-
+
if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76);
- return 0;
+ goto out;
}
/*
* Check for routing loops.
*/
- for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
+ rose_route = rose_route_list;
+ while (rose_route != NULL) {
if (rose_route->rand == facilities.rand &&
rosecmp(src_addr, &rose_route->src_addr) == 0 &&
ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 &&
ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120);
- return 0;
+ goto out;
}
+ rose_route = rose_route->next;
}
if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
- return 0;
+ goto out;
}
if ((new_lci = rose_new_lci(new_neigh)) == 0) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71);
- return 0;
+ goto out;
}
if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120);
- return 0;
+ goto out;
}
rose_route->lci1 = lci;
@@ -950,18 +1047,22 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25)
rose_route->neigh1->use++;
rose_route->neigh2->use++;
- save_flags(flags); cli();
rose_route->next = rose_route_list;
rose_route_list = rose_route;
- restore_flags(flags);
skb->data[0] &= 0xF0;
skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F;
skb->data[1] = (rose_route->lci2 >> 0) & 0xFF;
rose_transmit_link(skb, rose_route->neigh2);
+ res = 1;
+
+out:
+ spin_unlock_bh(&rose_route_list_lock);
+ spin_unlock_bh(&rose_neigh_list_lock);
+ spin_unlock_bh(&rose_node_list_lock);
- return 1;
+ return res;
}
int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
@@ -972,7 +1073,7 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
off_t begin = 0;
int i;
- cli();
+ spin_lock_bh(&rose_neigh_list_lock);
len += sprintf(buffer, "address mask n neigh neigh neigh\n");
@@ -1004,16 +1105,16 @@ int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
if (pos > offset + length)
break;
}
-
- sti();
+ spin_unlock_bh(&rose_neigh_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
- if (len > length) len = length;
+ if (len > length)
+ len = length;
return len;
-}
+}
int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
{
@@ -1023,7 +1124,7 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
off_t begin = 0;
int i;
- cli();
+ spin_lock_bh(&rose_neigh_list_lock);
len += sprintf(buffer, "addr callsign dev count use mode restart t0 tf digipeaters\n");
@@ -1059,15 +1160,16 @@ int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
/* } */
}
- sti();
+ spin_unlock_bh(&rose_neigh_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
- if (len > length) len = length;
+ if (len > length)
+ len = length;
return len;
-}
+}
int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
{
@@ -1076,7 +1178,7 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
off_t begin = 0;
- cli();
+ spin_lock_bh(&rose_route_list_lock);
len += sprintf(buffer, "lci address callsign neigh <-> lci address callsign neigh\n");
@@ -1112,15 +1214,16 @@ int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
break;
}
- sti();
+ spin_unlock_bh(&rose_route_list_lock);
*start = buffer + (offset - begin);
len -= (offset - begin);
- if (len > length) len = length;
+ if (len > length)
+ len = length;
return len;
-}
+}
/*
* Release all memory associated with ROSE routing structures.
diff --git a/net/rose/rose_subr.c b/net/rose/rose_subr.c
index 08b21f2fa39e..2653d4899499 100644
--- a/net/rose/rose_subr.c
+++ b/net/rose/rose_subr.c
@@ -1,20 +1,11 @@
/*
- * 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
- *
- * 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_subr.c
- * ROSE 002 Jonathan(G4KLX) Centralised disconnect processing.
- * ROSE 003 Jonathan(G4KLX) Added use count to neighbours.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -103,7 +94,7 @@ int rose_validate_nr(struct sock *sk, unsigned short nr)
return nr == rose->vs;
}
-/*
+/*
* This routine is called when the packet layer internally generates a
* control frame.
*/
@@ -119,16 +110,16 @@ void rose_write_internal(struct sock *sk, int frametype)
len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
switch (frametype) {
- case ROSE_CALL_REQUEST:
- len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
- faclen = rose_create_facilities(buffer, rose);
- len += faclen;
- break;
- case ROSE_CALL_ACCEPTED:
- case ROSE_CLEAR_REQUEST:
- case ROSE_RESET_REQUEST:
- len += 2;
- break;
+ case ROSE_CALL_REQUEST:
+ len += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
+ faclen = rose_create_facilities(buffer, rose);
+ len += faclen;
+ break;
+ case ROSE_CALL_ACCEPTED:
+ case ROSE_CLEAR_REQUEST:
+ case ROSE_RESET_REQUEST:
+ len += 2;
+ break;
}
if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -138,70 +129,69 @@ void rose_write_internal(struct sock *sk, int frametype)
* Space for AX.25 header and PID.
*/
skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1);
-
+
dptr = skb_put(skb, skb_tailroom(skb));
lci1 = (rose->lci >> 8) & 0x0F;
lci2 = (rose->lci >> 0) & 0xFF;
switch (frametype) {
-
- case ROSE_CALL_REQUEST:
- *dptr++ = ROSE_GFI | lci1;
- *dptr++ = lci2;
- *dptr++ = frametype;
- *dptr++ = 0xAA;
- memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN);
- dptr += ROSE_ADDR_LEN;
- memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN);
- dptr += ROSE_ADDR_LEN;
- memcpy(dptr, buffer, faclen);
- dptr += faclen;
- break;
-
- case ROSE_CALL_ACCEPTED:
- *dptr++ = ROSE_GFI | lci1;
- *dptr++ = lci2;
- *dptr++ = frametype;
- *dptr++ = 0x00; /* Address length */
- *dptr++ = 0; /* Facilities length */
- break;
-
- case ROSE_CLEAR_REQUEST:
- *dptr++ = ROSE_GFI | lci1;
- *dptr++ = lci2;
- *dptr++ = frametype;
- *dptr++ = rose->cause;
- *dptr++ = rose->diagnostic;
- break;
-
- case ROSE_RESET_REQUEST:
- *dptr++ = ROSE_GFI | lci1;
- *dptr++ = lci2;
- *dptr++ = frametype;
- *dptr++ = ROSE_DTE_ORIGINATED;
- *dptr++ = 0;
- break;
-
- case ROSE_RR:
- case ROSE_RNR:
- *dptr++ = ROSE_GFI | lci1;
- *dptr++ = lci2;
- *dptr = frametype;
- *dptr++ |= (rose->vr << 5) & 0xE0;
- break;
-
- case ROSE_CLEAR_CONFIRMATION:
- case ROSE_RESET_CONFIRMATION:
- *dptr++ = ROSE_GFI | lci1;
- *dptr++ = lci2;
- *dptr++ = frametype;
- break;
-
- default:
- printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype);
- kfree_skb(skb);
- return;
+ case ROSE_CALL_REQUEST:
+ *dptr++ = ROSE_GFI | lci1;
+ *dptr++ = lci2;
+ *dptr++ = frametype;
+ *dptr++ = 0xAA;
+ memcpy(dptr, &rose->dest_addr, ROSE_ADDR_LEN);
+ dptr += ROSE_ADDR_LEN;
+ memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN);
+ dptr += ROSE_ADDR_LEN;
+ memcpy(dptr, buffer, faclen);
+ dptr += faclen;
+ break;
+
+ case ROSE_CALL_ACCEPTED:
+ *dptr++ = ROSE_GFI | lci1;
+ *dptr++ = lci2;
+ *dptr++ = frametype;
+ *dptr++ = 0x00; /* Address length */
+ *dptr++ = 0; /* Facilities length */
+ break;
+
+ case ROSE_CLEAR_REQUEST:
+ *dptr++ = ROSE_GFI | lci1;
+ *dptr++ = lci2;
+ *dptr++ = frametype;
+ *dptr++ = rose->cause;
+ *dptr++ = rose->diagnostic;
+ break;
+
+ case ROSE_RESET_REQUEST:
+ *dptr++ = ROSE_GFI | lci1;
+ *dptr++ = lci2;
+ *dptr++ = frametype;
+ *dptr++ = ROSE_DTE_ORIGINATED;
+ *dptr++ = 0;
+ break;
+
+ case ROSE_RR:
+ case ROSE_RNR:
+ *dptr++ = ROSE_GFI | lci1;
+ *dptr++ = lci2;
+ *dptr = frametype;
+ *dptr++ |= (rose->vr << 5) & 0xE0;
+ break;
+
+ case ROSE_CLEAR_CONFIRMATION:
+ case ROSE_RESET_CONFIRMATION:
+ *dptr++ = ROSE_GFI | lci1;
+ *dptr++ = lci2;
+ *dptr++ = frametype;
+ break;
+
+ default:
+ printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype);
+ kfree_skb(skb);
+ return;
}
rose_transmit_link(skb, rose->neighbour);
@@ -216,15 +206,15 @@ int rose_decode(struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
*ns = *nr = *q = *d = *m = 0;
switch (frame[2]) {
- case ROSE_CALL_REQUEST:
- case ROSE_CALL_ACCEPTED:
- case ROSE_CLEAR_REQUEST:
- case ROSE_CLEAR_CONFIRMATION:
- case ROSE_RESET_REQUEST:
- case ROSE_RESET_CONFIRMATION:
- return frame[2];
- default:
- break;
+ case ROSE_CALL_REQUEST:
+ case ROSE_CALL_ACCEPTED:
+ case ROSE_CLEAR_REQUEST:
+ case ROSE_CLEAR_CONFIRMATION:
+ case ROSE_RESET_REQUEST:
+ case ROSE_RESET_CONFIRMATION:
+ return frame[2];
+ default:
+ break;
}
if ((frame[2] & 0x1F) == ROSE_RR ||
@@ -253,61 +243,61 @@ static int rose_parse_national(unsigned char *p, struct rose_facilities_struct *
do {
switch (*p & 0xC0) {
- case 0x00:
- p += 2;
- n += 2;
- len -= 2;
- break;
+ case 0x00:
+ p += 2;
+ n += 2;
+ len -= 2;
+ break;
- case 0x40:
- if (*p == FAC_NATIONAL_RAND)
- facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
- p += 3;
- n += 3;
- len -= 3;
- break;
+ case 0x40:
+ if (*p == FAC_NATIONAL_RAND)
+ facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
+ p += 3;
+ n += 3;
+ len -= 3;
+ break;
- case 0x80:
- p += 4;
- n += 4;
- len -= 4;
- break;
+ case 0x80:
+ p += 4;
+ n += 4;
+ len -= 4;
+ break;
- case 0xC0:
- l = p[1];
- if (*p == FAC_NATIONAL_DEST_DIGI) {
- if (!fac_national_digis_received) {
- memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
- facilities->source_ndigis = 1;
- }
+ case 0xC0:
+ l = p[1];
+ if (*p == FAC_NATIONAL_DEST_DIGI) {
+ if (!fac_national_digis_received) {
+ memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
+ facilities->source_ndigis = 1;
}
- else if (*p == FAC_NATIONAL_SRC_DIGI) {
- if (!fac_national_digis_received) {
- memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
- facilities->dest_ndigis = 1;
- }
- }
- else if (*p == FAC_NATIONAL_FAIL_CALL) {
- memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
- }
- else if (*p == FAC_NATIONAL_FAIL_ADD) {
- memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
+ }
+ else if (*p == FAC_NATIONAL_SRC_DIGI) {
+ if (!fac_national_digis_received) {
+ memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
+ facilities->dest_ndigis = 1;
}
- else if (*p == FAC_NATIONAL_DIGIS) {
- fac_national_digis_received = 1;
- facilities->source_ndigis = 0;
- facilities->dest_ndigis = 0;
- for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) {
- if (pt[6] & AX25_HBIT)
- memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
- else
- memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
- }
+ }
+ else if (*p == FAC_NATIONAL_FAIL_CALL) {
+ memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
+ }
+ else if (*p == FAC_NATIONAL_FAIL_ADD) {
+ memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
+ }
+ else if (*p == FAC_NATIONAL_DIGIS) {
+ fac_national_digis_received = 1;
+ facilities->source_ndigis = 0;
+ facilities->dest_ndigis = 0;
+ for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) {
+ if (pt[6] & AX25_HBIT)
+ memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
+ else
+ memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
}
- p += l + 2;
- n += l + 2;
- len -= l + 2;
- break;
+ }
+ p += l + 2;
+ n += l + 2;
+ len -= l + 2;
+ break;
}
} while (*p != 0x00 && len > 0);
@@ -321,49 +311,50 @@ static int rose_parse_ccitt(unsigned char *p, struct rose_facilities_struct *fac
do {
switch (*p & 0xC0) {
- case 0x00:
- p += 2;
- n += 2;
- len -= 2;
- break;
+ case 0x00:
+ p += 2;
+ n += 2;
+ len -= 2;
+ break;
- case 0x40:
- p += 3;
- n += 3;
- len -= 3;
- break;
+ case 0x40:
+ p += 3;
+ n += 3;
+ len -= 3;
+ break;
- case 0x80:
- p += 4;
- n += 4;
- len -= 4;
- break;
+ case 0x80:
+ p += 4;
+ n += 4;
+ len -= 4;
+ break;
- case 0xC0:
- l = p[1];
- if (*p == FAC_CCITT_DEST_NSAP) {
- memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN);
- memcpy(callsign, p + 12, l - 10);
- callsign[l - 10] = '\0';
- facilities->source_call = *asc2ax(callsign);
- }
- if (*p == FAC_CCITT_SRC_NSAP) {
- memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
- memcpy(callsign, p + 12, l - 10);
- callsign[l - 10] = '\0';
- facilities->dest_call = *asc2ax(callsign);
- }
- p += l + 2;
- n += l + 2;
- len -= l + 2;
- break;
+ case 0xC0:
+ l = p[1];
+ if (*p == FAC_CCITT_DEST_NSAP) {
+ memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN);
+ memcpy(callsign, p + 12, l - 10);
+ callsign[l - 10] = '\0';
+ facilities->source_call = *asc2ax(callsign);
+ }
+ if (*p == FAC_CCITT_SRC_NSAP) {
+ memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
+ memcpy(callsign, p + 12, l - 10);
+ callsign[l - 10] = '\0';
+ facilities->dest_call = *asc2ax(callsign);
+ }
+ p += l + 2;
+ n += l + 2;
+ len -= l + 2;
+ break;
}
} while (*p != 0x00 && len > 0);
return n;
}
-int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facilities)
+int rose_parse_facilities(unsigned char *p,
+ struct rose_facilities_struct *facilities)
{
int facilities_len, len;
@@ -378,26 +369,26 @@ int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facil
p++;
switch (*p) {
- case FAC_NATIONAL: /* National */
- len = rose_parse_national(p + 1, facilities, facilities_len - 1);
- facilities_len -= len + 1;
- p += len + 1;
- break;
+ case FAC_NATIONAL: /* National */
+ len = rose_parse_national(p + 1, facilities, facilities_len - 1);
+ facilities_len -= len + 1;
+ p += len + 1;
+ break;
- case FAC_CCITT: /* CCITT */
- len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
- facilities_len -= len + 1;
- p += len + 1;
- break;
+ case FAC_CCITT: /* CCITT */
+ len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
+ facilities_len -= len + 1;
+ p += len + 1;
+ break;
- default:
- printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
- facilities_len--;
- p++;
- break;
+ default:
+ printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
+ facilities_len--;
+ p++;
+ break;
}
- }
- else break; /* Error in facilities format */
+ } else
+ break; /* Error in facilities format */
}
return 1;
diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c
index 4f66adbaf8a7..5af130c74541 100644
--- a/net/rose/rose_timer.c
+++ b/net/rose/rose_timer.c
@@ -1,20 +1,12 @@
/*
- * 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
- *
- * 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_timer.c
- * ROSE 003 Jonathan(G4KLX) New timer architecture.
- * Implemented idle timer.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
*/
-
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -139,34 +131,35 @@ static void rose_heartbeat_expiry(unsigned long param)
struct sock *sk = (struct sock *)param;
rose_cb *rose = rose_sk(sk);
+ bh_lock_sock(sk);
switch (rose->state) {
-
- case ROSE_STATE_0:
- /* Magic here: If we listen() and a new link dies before it
- is accepted() it isn't 'dead' so doesn't get removed. */
- if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
- rose_destroy_socket(sk);
- return;
- }
- break;
-
- case ROSE_STATE_3:
- /*
- * Check for the state of the receive buffer.
- */
- if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
- (rose->condition & ROSE_COND_OWN_RX_BUSY)) {
- rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
- rose->condition &= ~ROSE_COND_ACK_PENDING;
- rose->vl = rose->vr;
- rose_write_internal(sk, ROSE_RR);
- rose_stop_timer(sk); /* HB */
- break;
- }
+ case ROSE_STATE_0:
+ /* Magic here: If we listen() and a new link dies before it
+ is accepted() it isn't 'dead' so doesn't get removed. */
+ if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
+ rose_destroy_socket(sk);
+ return;
+ }
+ break;
+
+ case ROSE_STATE_3:
+ /*
+ * Check for the state of the receive buffer.
+ */
+ if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
+ (rose->condition & ROSE_COND_OWN_RX_BUSY)) {
+ rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
+ rose->condition &= ~ROSE_COND_ACK_PENDING;
+ rose->vl = rose->vr;
+ rose_write_internal(sk, ROSE_RR);
+ rose_stop_timer(sk); /* HB */
break;
+ }
+ break;
}
rose_start_heartbeat(sk);
+ bh_unlock_sock(sk);
}
static void rose_timer_expiry(unsigned long param)
@@ -174,33 +167,35 @@ static void rose_timer_expiry(unsigned long param)
struct sock *sk = (struct sock *)param;
rose_cb *rose = rose_sk(sk);
+ bh_lock_sock(sk);
switch (rose->state) {
-
- case ROSE_STATE_1: /* T1 */
- case ROSE_STATE_4: /* T2 */
- rose_write_internal(sk, ROSE_CLEAR_REQUEST);
- rose->state = ROSE_STATE_2;
- rose_start_t3timer(sk);
- break;
-
- case ROSE_STATE_2: /* T3 */
- rose->neighbour->use--;
- rose_disconnect(sk, ETIMEDOUT, -1, -1);
- break;
-
- case ROSE_STATE_3: /* HB */
- if (rose->condition & ROSE_COND_ACK_PENDING) {
- rose->condition &= ~ROSE_COND_ACK_PENDING;
- rose_enquiry_response(sk);
- }
- break;
+ case ROSE_STATE_1: /* T1 */
+ case ROSE_STATE_4: /* T2 */
+ rose_write_internal(sk, ROSE_CLEAR_REQUEST);
+ rose->state = ROSE_STATE_2;
+ rose_start_t3timer(sk);
+ break;
+
+ case ROSE_STATE_2: /* T3 */
+ rose->neighbour->use--;
+ rose_disconnect(sk, ETIMEDOUT, -1, -1);
+ break;
+
+ case ROSE_STATE_3: /* HB */
+ if (rose->condition & ROSE_COND_ACK_PENDING) {
+ rose->condition &= ~ROSE_COND_ACK_PENDING;
+ rose_enquiry_response(sk);
+ }
+ break;
}
+ bh_unlock_sock(sk);
}
static void rose_idletimer_expiry(unsigned long param)
{
struct sock *sk = (struct sock *)param;
+ bh_lock_sock(sk);
rose_clear_queues(sk);
rose_write_internal(sk, ROSE_CLEAR_REQUEST);
@@ -210,10 +205,11 @@ static void rose_idletimer_expiry(unsigned long param)
sk->state = TCP_CLOSE;
sk->err = 0;
- sk->shutdown |= SEND_SHUTDOWN;
+ sk->shutdown |= SEND_SHUTDOWN;
if (!sk->dead)
sk->state_change(sk);
sk->dead = 1;
+ bh_unlock_sock(sk);
}
diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c
index 8b5c89f83be2..7c309c10d49c 100644
--- a/net/rose/sysctl_net_rose.c
+++ b/net/rose/sysctl_net_rose.c
@@ -1,10 +1,11 @@
-/* -*- linux-c -*-
- * sysctl_net_rose.c: sysctl interface to net ROSE 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.
- * Added /proc/sys/net/rose directory entry (empty =) ). [MS]
+ * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
*/
-
#include <linux/mm.h>
#include <linux/sysctl.h>
#include <linux/init.h>